multiboot1: Add ELF sections load support
diff --git a/common/protos/multiboot1.c b/common/protos/multiboot1.c
index 011e01d3..43017b1e 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;
