From 3ef8a29933aa1c23b52e32cf2a7a3cd36c069fee Mon Sep 17 00:00:00 2001 From: mintsuki Date: Sun, 19 Jun 2022 01:46:38 +0200 Subject: [PATCH] multiboot1: Add ELF sections load support --- common/protos/multiboot1.c | 62 +++++++++++++++++++++++++++++++++----- 1 file changed, 55 insertions(+), 7 deletions(-) diff --git a/common/protos/multiboot1.c b/common/protos/multiboot1.c index 2d5e0ccb..f94eb620 100644 --- a/common/protos/multiboot1.c +++ b/common/protos/multiboot1.c @@ -21,6 +21,20 @@ noreturn void multiboot1_spinup_32(uint32_t entry_point, uint32_t multiboot1_info); +static uint32_t kernel_top; + +static void *mb1_alloc(size_t size) { + void *ret = (void *)(uintptr_t)ALIGN_UP(kernel_top, 4096); + + while (!memmap_alloc_range((uintptr_t)ret, size, MEMMAP_KERNEL_AND_MODULES, + true, false, false, false)) { + ret += 0x200000; + } + + kernel_top = (uintptr_t)ret + size; + return ret; +} + bool multiboot1_load(char *config, char *cmdline) { struct file_handle *kernel_file; @@ -63,7 +77,8 @@ bool multiboot1_load(char *config, char *cmdline) { panic(true, "multiboot1: Header checksum is invalid"); uint32_t entry_point; - uint32_t kernel_top; + + struct elf_section_hdr_info *section_hdr_info = NULL; if (header.flags & (1 << 16)) { if (header.load_addr > header.header_addr) @@ -99,6 +114,16 @@ bool multiboot1_load(char *config, char *cmdline) { } else { int bits = elf_bits(kernel); + switch (bits) { + case 32: + section_hdr_info = elf32_section_hdr_info(kernel); + break; + case 64: { + section_hdr_info = elf64_section_hdr_info(kernel); + break; + } + } + switch (bits) { case 32: if (elf32_load(kernel, &entry_point, &kernel_top, MEMMAP_KERNEL_AND_MODULES)) @@ -118,6 +143,33 @@ bool multiboot1_load(char *config, char *cmdline) { } } + if (section_hdr_info != NULL) { + multiboot1_info->elf_sect.num = section_hdr_info->num; + multiboot1_info->elf_sect.size = section_hdr_info->section_entry_size; + multiboot1_info->elf_sect.shndx = section_hdr_info->str_section_idx; + + void *sections = conv_mem_alloc(section_hdr_info->section_entry_size * section_hdr_info->num); + + multiboot1_info->elf_sect.addr = (uintptr_t)sections; + + memcpy(sections, kernel + section_hdr_info->section_offset, section_hdr_info->section_entry_size * section_hdr_info->num); + + for (size_t i = 0; i < section_hdr_info->num; i++) { + struct elf64_shdr *shdr = (void *)sections + section_hdr_info->section_offset + i * section_hdr_info->section_entry_size; + + if (shdr->sh_addr != 0 || shdr->sh_size == 0) { + continue; + } + + void *section = mb1_alloc(shdr->sh_size); + memcpy(section, kernel + shdr->sh_offset, shdr->sh_size); + + shdr->sh_addr = (uintptr_t)section; + } + + multiboot1_info->flags |= (1 << 5); + } + uint32_t n_modules; for (n_modules = 0; ; n_modules++) { @@ -152,12 +204,8 @@ bool multiboot1_load(char *config, char *cmdline) { char *lowmem_modstr = conv_mem_alloc(strlen(module_cmdline) + 1); strcpy(lowmem_modstr, module_cmdline); - void *module_addr = (void *)(uintptr_t)ALIGN_UP(kernel_top, 4096); - while (!memmap_alloc_range((uintptr_t)module_addr, f->size, MEMMAP_KERNEL_AND_MODULES, - true, false, false, false)) { - module_addr += 0x200000; - } - kernel_top = (uintptr_t)module_addr + f->size; + void *module_addr = mb1_alloc(f->size); + fread(f, module_addr, 0, f->size); m->begin = (uint32_t)(size_t)module_addr;