multiboot1: Add ahead-of-time info size calculation

This commit is contained in:
mintsuki 2022-06-29 07:26:06 +02:00
parent d7d0a84462
commit a2f7d2d314
1 changed files with 65 additions and 23 deletions

View File

@ -25,6 +25,29 @@ noreturn void multiboot1_spinup_32(uint32_t entry_point, uint32_t multiboot1_inf
static uint32_t kernel_top;
#define LIMINE_BRAND "Limine " LIMINE_VERSION
// Returns the size required to store the multiboot info.
static size_t get_multiboot1_info_size(
char *cmdline,
size_t modules_count, size_t modules_cmdlines_size,
uint32_t section_entry_size, uint32_t section_num
) {
return ALIGN_UP(sizeof(struct multiboot1_info), 16) + // base structure
ALIGN_UP(strlen(cmdline) + 1, 16) + // cmdline
ALIGN_UP(sizeof(LIMINE_BRAND), 16) + // bootloader brand
ALIGN_UP(sizeof(section_entry_size * section_num), 16) + // ELF info
ALIGN_UP(sizeof(struct multiboot1_module) * modules_count, 16) + // modules count
ALIGN_UP(modules_cmdlines_size, 16) + // modules command lines
ALIGN_UP(sizeof(struct multiboot1_mmap_entry) * 256, 16); // memory map
}
static void *mb1_info_alloc(void **mb1_info_raw, size_t size) {
void *ret = *mb1_info_raw;
*mb1_info_raw += ALIGN_UP(size, 16);
return ret;
}
static bool mb1_overlap_check(uint64_t base1, uint64_t top1,
uint64_t base2, uint64_t top2) {
return ((base1 >= base2 && base1 < top2)
@ -183,20 +206,39 @@ retry_raw_load:;
kernel_top = 0x100000;
}
size_t n_modules;
size_t modules_cmdlines_size = 0;
for (n_modules = 0;; n_modules++) {
struct conf_tuple conf_tuple = config_get_tuple(config, n_modules, "MODULE_PATH", "MODULE_STRING");
if (!conf_tuple.value1) break;
char *module_cmdline = conf_tuple.value2;
if (!module_cmdline) module_cmdline = "";
modules_cmdlines_size += ALIGN_UP(strlen(module_cmdline) + 1, 16);
}
size_t mb1_info_size = get_multiboot1_info_size(
cmdline,
n_modules,
modules_cmdlines_size,
section_hdr_info ? section_hdr_info->section_entry_size : 0,
section_hdr_info ? section_hdr_info->num : 0
);
// GRUB allocates boot info at 0x10000, *except* if the kernel happens
// to overlap this region, then it gets moved to right after the
// kernel, or whichever PHDR happens to sit at 0x10000.
// Allocate it wherever, then move it to where GRUB puts it
// afterwards.
size_t mb1_info_size = sizeof(struct multiboot1_info);
struct multiboot1_info *multiboot1_info = ext_mem_alloc(mb1_info_size);
void *mb1_info_raw = ext_mem_alloc(mb1_info_size);
uint64_t mb1_info_final_loc = 0x10000;
retry_mb1_info_reloc:
for (size_t i = 0; i < elf_ranges_count; i++) {
uint64_t mb1_info_top = mb1_info_final_loc + mb1_info_size;
uint64_t base = elf_ranges[i].base - slide;
uint64_t length = elf_ranges[i].length - slide;
uint64_t length = elf_ranges[i].length;
uint64_t top = base + length;
// Do they overlap?
@ -216,18 +258,24 @@ retry_mb1_info_reloc:
}
}
size_t mb1_info_slide = (size_t)mb1_info_raw - mb1_info_final_loc;
if (mb1_info_final_loc + mb1_info_size > kernel_top) {
kernel_top = mb1_info_final_loc + mb1_info_size;
}
struct multiboot1_info *multiboot1_info =
mb1_info_alloc(&mb1_info_raw, sizeof(struct multiboot1_info));
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);
void *sections = mb1_info_alloc(&mb1_info_raw,
section_hdr_info->section_entry_size * section_hdr_info->num);
multiboot1_info->elf_sect.addr = (uintptr_t)sections;
multiboot1_info->elf_sect.addr = (uintptr_t)sections - mb1_info_slide;
memcpy(sections, kernel + section_hdr_info->section_offset, section_hdr_info->section_entry_size * section_hdr_info->num);
@ -247,18 +295,12 @@ retry_mb1_info_reloc:
multiboot1_info->flags |= (1 << 5);
}
uint32_t n_modules;
for (n_modules = 0; ; n_modules++) {
if (config_get_value(config, n_modules, "MODULE_PATH") == NULL)
break;
}
if (n_modules) {
struct multiboot1_module *mods = conv_mem_alloc(sizeof(*mods) * n_modules);
struct multiboot1_module *mods =
mb1_info_alloc(&mb1_info_raw, sizeof(struct multiboot1_module) * n_modules);
multiboot1_info->mods_count = n_modules;
multiboot1_info->mods_addr = (uint32_t)(size_t)mods;
multiboot1_info->mods_addr = (size_t)mods - mb1_info_slide;
for (size_t i = 0; i < n_modules; i++) {
struct multiboot1_module *m = mods + i;
@ -278,7 +320,7 @@ retry_mb1_info_reloc:
if (module_cmdline == NULL) {
module_cmdline = "";
}
char *lowmem_modstr = conv_mem_alloc(strlen(module_cmdline) + 1);
char *lowmem_modstr = mb1_info_alloc(&mb1_info_raw, strlen(module_cmdline) + 1);
strcpy(lowmem_modstr, module_cmdline);
void *module_addr = mb1_alloc(f->size);
@ -287,7 +329,7 @@ retry_mb1_info_reloc:
m->begin = (uint32_t)(size_t)module_addr;
m->end = m->begin + f->size;
m->cmdline = (uint32_t)(size_t)lowmem_modstr;
m->cmdline = (uint32_t)(size_t)lowmem_modstr - mb1_info_slide;
m->pad = 0;
fclose(f);
@ -304,17 +346,17 @@ retry_mb1_info_reloc:
multiboot1_info->flags |= (1 << 3);
}
char *lowmem_cmdline = conv_mem_alloc(strlen(cmdline) + 1);
char *lowmem_cmdline = mb1_info_alloc(&mb1_info_raw, strlen(cmdline) + 1);
strcpy(lowmem_cmdline, cmdline);
multiboot1_info->cmdline = (uint32_t)(size_t)lowmem_cmdline;
multiboot1_info->cmdline = (uint32_t)(size_t)lowmem_cmdline - mb1_info_slide;
if (cmdline)
multiboot1_info->flags |= (1 << 2);
char *bootload_name = "Limine " LIMINE_VERSION;
char *lowmem_bootname = conv_mem_alloc(strlen(bootload_name) + 1);
char *bootload_name = LIMINE_BRAND;
char *lowmem_bootname = mb1_info_alloc(&mb1_info_raw, strlen(bootload_name) + 1);
strcpy(lowmem_bootname, bootload_name);
multiboot1_info->bootloader_name = (uint32_t)(size_t)lowmem_bootname;
multiboot1_info->bootloader_name = (uint32_t)(size_t)lowmem_bootname - mb1_info_slide;
multiboot1_info->flags |= (1 << 9);
term_deinit();
@ -388,7 +430,7 @@ nofb:;
struct e820_entry_t *raw_memmap = get_raw_memmap(&mb_mmap_count);
size_t mb_mmap_len = mb_mmap_count * sizeof(struct multiboot1_mmap_entry);
struct multiboot1_mmap_entry *mmap = conv_mem_alloc(mb_mmap_len);
struct multiboot1_mmap_entry *mmap = mb1_info_alloc(&mb1_info_raw, mb_mmap_len);
// Multiboot is bad and passes raw memmap. We do the same to support it.
for (size_t i = 0; i < mb_mmap_count; i++) {
@ -408,7 +450,7 @@ nofb:;
}
multiboot1_info->mmap_length = mb_mmap_len;
multiboot1_info->mmap_addr = ((uint32_t)(size_t)mmap);
multiboot1_info->mmap_addr = (uint32_t)(size_t)mmap - mb1_info_slide;
multiboot1_info->flags |= (1 << 0) | (1 << 6);
irq_flush_type = IRQ_PIC_ONLY_FLUSH;