107 lines
2.3 KiB
C
107 lines
2.3 KiB
C
#include "elf_loader.h"
|
|
|
|
#include <tianole/elf.h>
|
|
|
|
static void *mem_copy(void *dst, const void *src, uint64_t size)
|
|
{
|
|
uint8_t *out = (uint8_t *)dst;
|
|
const uint8_t *in = (const uint8_t *)src;
|
|
uint64_t i;
|
|
|
|
for (i = 0; i < size; ++i) {
|
|
out[i] = in[i];
|
|
}
|
|
|
|
return dst;
|
|
}
|
|
|
|
static void mem_zero(void *dst, uint64_t size)
|
|
{
|
|
uint8_t *out = (uint8_t *)dst;
|
|
uint64_t i;
|
|
|
|
for (i = 0; i < size; ++i) {
|
|
out[i] = 0;
|
|
}
|
|
}
|
|
|
|
static efi_status validate_kernel_elf(const elf64_ehdr_t *ehdr)
|
|
{
|
|
if (*(const uint32_t *)ehdr->ident != ELF_MAGIC) {
|
|
return EFI_LOAD_ERROR;
|
|
}
|
|
if (ehdr->ident[4] != ELFCLASS64 || ehdr->ident[5] != ELFDATA2LSB) {
|
|
return EFI_LOAD_ERROR;
|
|
}
|
|
if (ehdr->ident[6] != EV_CURRENT || ehdr->version != EV_CURRENT) {
|
|
return EFI_LOAD_ERROR;
|
|
}
|
|
if (ehdr->type != ET_EXEC || ehdr->machine != EM_X86_64) {
|
|
return EFI_LOAD_ERROR;
|
|
}
|
|
if (ehdr->phentsize != sizeof(elf64_phdr_t)) {
|
|
return EFI_LOAD_ERROR;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
efi_status boot_load_kernel_elf(efi_system_table_t *system_table,
|
|
const void *kernel_image,
|
|
uint64_t kernel_size,
|
|
kernel_entry_fn_t *entry_out)
|
|
{
|
|
const elf64_ehdr_t *ehdr = (const elf64_ehdr_t *)kernel_image;
|
|
const elf64_phdr_t *phdrs;
|
|
uint16_t index;
|
|
efi_status status;
|
|
|
|
if (kernel_size < sizeof(*ehdr)) {
|
|
return EFI_LOAD_ERROR;
|
|
}
|
|
|
|
status = validate_kernel_elf(ehdr);
|
|
if (status != EFI_SUCCESS) {
|
|
return status;
|
|
}
|
|
|
|
phdrs = (const elf64_phdr_t *)((const uint8_t *)kernel_image +
|
|
ehdr->phoff);
|
|
|
|
for (index = 0; index < ehdr->phnum; ++index) {
|
|
const elf64_phdr_t *phdr = &phdrs[index];
|
|
efi_physical_address_t segment_base;
|
|
uint64_t page_count;
|
|
|
|
if (phdr->type != PT_LOAD) {
|
|
continue;
|
|
}
|
|
|
|
if (phdr->memsz < phdr->filesz) {
|
|
return EFI_LOAD_ERROR;
|
|
}
|
|
if (phdr->offset + phdr->filesz > kernel_size) {
|
|
return EFI_LOAD_ERROR;
|
|
}
|
|
|
|
segment_base = phdr->paddr;
|
|
page_count = (phdr->memsz + 0xfffULL) >> 12;
|
|
status = system_table->boot_services->allocate_pages(
|
|
EFI_ALLOCATE_ADDRESS,
|
|
EFI_LOADER_DATA,
|
|
page_count,
|
|
&segment_base);
|
|
if (status != EFI_SUCCESS) {
|
|
return status;
|
|
}
|
|
|
|
mem_zero((void *)(uintptr_t)phdr->paddr, phdr->memsz);
|
|
mem_copy((void *)(uintptr_t)phdr->paddr,
|
|
(const uint8_t *)kernel_image + phdr->offset,
|
|
phdr->filesz);
|
|
}
|
|
|
|
*entry_out = (kernel_entry_fn_t)(uintptr_t)ehdr->entry;
|
|
return EFI_SUCCESS;
|
|
}
|