tianole/arch/x86/boot/elf_loader.c
Microindole e3782144b8
refactor(build): split makefiles and normalize internal API names
- align makefile layout with Linux-style directories
2026-05-08 21:00:24 +08:00

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;
}