misc: Bring mb2 up to par to mb1 wrt everywhere ranges and bug fixes

This commit is contained in:
mintsuki 2022-06-29 10:27:04 +02:00
parent 19287d5ca1
commit 215bf87993
13 changed files with 154 additions and 247 deletions

View File

@ -514,7 +514,6 @@ int elf64_load(uint8_t *elf, uint64_t *entry_point, uint64_t *top, uint64_t *_sl
size_t max_simulated_tries = 0x100000;
uint64_t entry = hdr.entry;
bool entry_adjusted = false;
uint64_t max_align = elf64_max_align(elf);
@ -768,7 +767,7 @@ int elf32_load(uint8_t *elf, uint32_t *entry_point, uint32_t *top, uint32_t allo
bool elf32_load_elsewhere(uint8_t *elf, uint64_t *entry_point,
struct elsewhere_range **ranges,
size_t *ranges_count) {
uint64_t *ranges_count) {
struct elf32_hdr *hdr = (void *)elf;
if (strncmp((char *)hdr->ident, "\177ELF", 4)) {
@ -786,7 +785,7 @@ bool elf32_load_elsewhere(uint8_t *elf, uint64_t *entry_point,
return false;
}
*entry_point = hdr.entry;
*entry_point = hdr->entry;
bool entry_adjusted = false;
if (hdr->phdr_size < sizeof(struct elf32_phdr)) {
@ -795,7 +794,7 @@ bool elf32_load_elsewhere(uint8_t *elf, uint64_t *entry_point,
*ranges_count = 0;
for (uint16_t i = 0; i < hdr->ph_num; i++) {
struct elf32_phdr *phdr = (void *)elf + (hdr.phoff + i * hdr.phdr_size);
struct elf32_phdr *phdr = (void *)elf + (hdr->phoff + i * hdr->phdr_size);
if (phdr->p_type != PT_LOAD)
continue;
@ -808,31 +807,31 @@ bool elf32_load_elsewhere(uint8_t *elf, uint64_t *entry_point,
size_t cur_entry = 0;
for (uint16_t i = 0; i < hdr->ph_num; i++) {
struct elf32_phdr *phdr = (void *)elf + (hdr.phoff + i * hdr.phdr_size);
struct elf32_phdr *phdr = (void *)elf + (hdr->phoff + i * hdr->phdr_size);
if (phdr->p_type != PT_LOAD)
continue;
// Sanity checks
if (phdr->p_filesz > phdr.p_memsz) {
if (phdr->p_filesz > phdr->p_memsz) {
panic(true, "elf: p_filesz > p_memsz");
}
void *elsewhere = ext_mem_alloc(phdr.p_memsz);
void *elsewhere = ext_mem_alloc(phdr->p_memsz);
memcpy(elsewhere, elf + phdr.p_offset, phdr.p_filesz);
memcpy(elsewhere, elf + phdr->p_offset, phdr->p_filesz);
if (!entry_adjusted
&& *entry_point >= phdr.p_vaddr
&& *entry_point < (phdr.p_vaddr + phdr.p_memsz)) {
*entry_point -= phdr.p_vaddr;
*entry_point += phdr.p_paddr;
&& *entry_point >= phdr->p_vaddr
&& *entry_point < (phdr->p_vaddr + phdr->p_memsz)) {
*entry_point -= phdr->p_vaddr;
*entry_point += phdr->p_paddr;
entry_adjusted = true;
}
*entry[cur_entry].elsewhere = elsewhere;
*entry[cur_entry].target = phdr.p_paddr;
*entry[cur_entry].length = phdr.p_memsz;
(*ranges[cur_entry]).elsewhere = (uintptr_t)elsewhere;
(*ranges[cur_entry]).target = phdr->p_paddr;
(*ranges[cur_entry]).length = phdr->p_memsz;
cur_entry++;
}
@ -842,7 +841,7 @@ bool elf32_load_elsewhere(uint8_t *elf, uint64_t *entry_point,
bool elf64_load_elsewhere(uint8_t *elf, uint64_t *entry_point,
struct elsewhere_range **ranges,
size_t *ranges_count) {
uint64_t *ranges_count) {
struct elf64_hdr *hdr = (void *)elf;
if (strncmp((char *)hdr->ident, "\177ELF", 4)) {
@ -860,7 +859,7 @@ bool elf64_load_elsewhere(uint8_t *elf, uint64_t *entry_point,
return false;
}
*entry_point = hdr.entry;
*entry_point = hdr->entry;
bool entry_adjusted = false;
if (hdr->phdr_size < sizeof(struct elf64_phdr)) {
@ -869,7 +868,7 @@ bool elf64_load_elsewhere(uint8_t *elf, uint64_t *entry_point,
*ranges_count = 0;
for (uint16_t i = 0; i < hdr->ph_num; i++) {
struct elf64_phdr *phdr = (void *)elf + (hdr.phoff + i * hdr.phdr_size);
struct elf64_phdr *phdr = (void *)elf + (hdr->phoff + i * hdr->phdr_size);
if (phdr->p_type != PT_LOAD)
continue;
@ -882,31 +881,31 @@ bool elf64_load_elsewhere(uint8_t *elf, uint64_t *entry_point,
size_t cur_entry = 0;
for (uint16_t i = 0; i < hdr->ph_num; i++) {
struct elf64_phdr *phdr = (void *)elf + (hdr.phoff + i * hdr.phdr_size);
struct elf64_phdr *phdr = (void *)elf + (hdr->phoff + i * hdr->phdr_size);
if (phdr->p_type != PT_LOAD)
continue;
// Sanity checks
if (phdr->p_filesz > phdr.p_memsz) {
if (phdr->p_filesz > phdr->p_memsz) {
panic(true, "elf: p_filesz > p_memsz");
}
void *elsewhere = ext_mem_alloc(phdr.p_memsz);
void *elsewhere = ext_mem_alloc(phdr->p_memsz);
memcpy(elsewhere, elf + phdr.p_offset, phdr.p_filesz);
memcpy(elsewhere, elf + phdr->p_offset, phdr->p_filesz);
if (!entry_adjusted
&& *entry_point >= phdr.p_vaddr
&& *entry_point < (phdr.p_vaddr + phdr.p_memsz)) {
*entry_point -= phdr.p_vaddr;
*entry_point += phdr.p_paddr;
&& *entry_point >= phdr->p_vaddr
&& *entry_point < (phdr->p_vaddr + phdr->p_memsz)) {
*entry_point -= phdr->p_vaddr;
*entry_point += phdr->p_paddr;
entry_adjusted = true;
}
*entry[cur_entry].elsewhere = elsewhere;
*entry[cur_entry].target = phdr.p_paddr;
*entry[cur_entry].length = phdr.p_memsz;
(*ranges[cur_entry]).elsewhere = (uintptr_t)elsewhere;
(*ranges[cur_entry]).target = phdr->p_paddr;
(*ranges[cur_entry]).length = phdr->p_memsz;
cur_entry++;
}

View File

@ -36,10 +36,10 @@ struct elf_section_hdr_info* elf32_section_hdr_info(uint8_t *elf);
bool elf32_load_elsewhere(uint8_t *elf, uint64_t *entry_point,
struct elsewhere_range **ranges,
size_t *ranges_count);
uint64_t *ranges_count);
bool elf64_load_elsewhere(uint8_t *elf, uint64_t *entry_point,
struct elsewhere_range **ranges,
size_t *ranges_count);
uint64_t *ranges_count);
struct elf64_hdr {
uint8_t ident[16];

View File

@ -3,6 +3,7 @@
#include <stdbool.h>
#include <lib/elsewhere.h>
#include <lib/blib.h>
#include <mm/pmm.h>
static bool elsewhere_overlap_check(uint64_t base1, uint64_t top1,
uint64_t base2, uint64_t top2) {
@ -12,7 +13,7 @@ static bool elsewhere_overlap_check(uint64_t base1, uint64_t top1,
bool elsewhere_append(
bool flexible_target,
struct elsewhere_range *ranges, size_t *ranges_count,
struct elsewhere_range *ranges, uint64_t *ranges_count,
void *elsewhere, uint64_t *target, size_t t_length) {
// original target of -1 means "allocate after top of all ranges"
// flexible target is ignored
@ -80,7 +81,7 @@ retry:
}
// Add the elsewhere range
ranges[*ranges_count].elsewhere = elsewhere;
ranges[*ranges_count].elsewhere = (uintptr_t)elsewhere;
ranges[*ranges_count].target = *target;
ranges[*ranges_count].length = t_length;
*ranges_count += 1;

View File

@ -13,7 +13,7 @@ struct elsewhere_range {
bool elsewhere_append(
bool flexible_target,
struct elsewhere_range *ranges, size_t *ranges_count,
struct elsewhere_range *ranges, uint64_t *ranges_count,
void *elsewhere, uint64_t *target, size_t t_length);
#endif

View File

@ -286,7 +286,7 @@ bool limine_load(char *config, char *cmdline) {
bool is_reloc;
if (elf64_load(kernel, &entry_point, NULL, &slide,
MEMMAP_KERNEL_AND_MODULES, kaslr, false,
MEMMAP_KERNEL_AND_MODULES, kaslr,
&ranges, &ranges_count,
true, &physical_base, &virtual_base, &image_size,
&is_reloc)) {

View File

@ -0,0 +1,36 @@
#include <stdint.h>
#include <stdnoreturn.h>
#if bios == 1
# include <sys/idt.h>
#endif
noreturn void multiboot_spinup_32(
uint32_t reloc_stub,
uint32_t magic, uint32_t protocol_info,
uint32_t entry_point,
uint32_t elf_ranges, uint32_t elf_ranges_count) {
#if bios == 1
struct idtr idtr;
idtr.limit = 0x3ff;
idtr.ptr = 0;
asm volatile (
"lidt %0"
:
: "m" (idtr)
: "memory"
);
#endif
asm volatile (
"jmp *%%ebx"
:
: "b"(reloc_stub), "S"(magic),
"a"(elf_ranges), "d"(elf_ranges_count),
"D"(protocol_info), "c"(entry_point)
: "memory"
);
__builtin_unreachable();
}

View File

@ -2,6 +2,7 @@
#define __PROTOS__MULTIBOOT_H__
#include <stdint.h>
#include <lib/blib.h>
struct mb_reloc_stub {
char jmp[4];
@ -10,4 +11,7 @@ struct mb_reloc_stub {
uint32_t mb_info_target;
};
extern symbol multiboot_spinup_32;
extern symbol multiboot_reloc_stub, multiboot_reloc_stub_end;
#endif

View File

@ -1,45 +0,0 @@
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <stdnoreturn.h>
#include <mm/vmm.h>
#if bios == 1
# include <sys/idt.h>
#endif
#include <protos/multiboot.h>
noreturn void multiboot1_spinup_32(uint32_t entry_point,
uint32_t multiboot1_info, uint32_t mb_info_target,
uint32_t mb_info_size,
uint32_t elf_ranges, uint32_t elf_ranges_count,
uint32_t slide,
struct mb_reloc_stub *reloc_stub) {
#if bios == 1
struct idtr idtr;
idtr.limit = 0x3ff;
idtr.ptr = 0;
asm volatile (
"lidt %0"
:
: "m" (idtr)
: "memory"
);
#endif
reloc_stub->magic = 0x2badb002;
reloc_stub->entry_point = entry_point;
reloc_stub->mb_info_target = mb_info_target;
asm volatile (
"jmp *%%ebx"
:
: "b"(reloc_stub), "S"(multiboot1_info),
"c"(mb_info_size), "a"(elf_ranges), "d"(elf_ranges_count),
"D"(slide)
: "memory"
);
__builtin_unreachable();
}

View File

@ -1,8 +1,8 @@
#include <stdint.h>
#include <stddef.h>
#include <stdnoreturn.h>
#include <config.h>
#include <protos/multiboot1.h>
#include <protos/multiboot.h>
#include <config.h>
#include <lib/libc.h>
#include <lib/elf.h>
#include <lib/blib.h>
@ -20,10 +20,6 @@
#include <mm/pmm.h>
#include <drivers/vga_textmode.h>
extern symbol multiboot_reloc_stub, multiboot_reloc_stub_end;
noreturn void multiboot1_spinup_32(uint32_t entry_point, uint32_t multiboot1_info);
#define LIMINE_BRAND "Limine " LIMINE_VERSION
// Returns the size required to store the multiboot info.
@ -122,7 +118,7 @@ bool multiboot1_load(char *config, char *cmdline) {
ranges_count = 1;
ranges = ext_mem_alloc(sizeof(struct elsewhere_range));
ranges->elsewhere = elsewhere;
ranges->elsewhere = (uintptr_t)elsewhere;
ranges->target = header.load_addr;
ranges->length = full_size;
} else {
@ -171,8 +167,8 @@ bool multiboot1_load(char *config, char *cmdline) {
struct elsewhere_range *new_ranges = ext_mem_alloc(sizeof(struct elsewhere_range) *
(ranges_count
+ 1 /* mb1 info range */
+ n_modules,
+ section_hdr_info ? section_hdr_info->num : 0));
+ n_modules
+ (section_hdr_info ? section_hdr_info->num : 0)));
memcpy(new_ranges, ranges, sizeof(struct elsewhere_range) * ranges_count);
pmm_free(ranges, sizeof(struct elsewhere_range) * ranges_count);
@ -256,7 +252,7 @@ bool multiboot1_load(char *config, char *cmdline) {
char *lowmem_modstr = mb1_info_alloc(&mb1_info_raw, strlen(module_cmdline) + 1);
strcpy(lowmem_modstr, module_cmdline);
void *module_addr = freadall(f);
void *module_addr = freadall(f, MEMMAP_BOOTLOADER_RECLAIMABLE);
uint64_t module_target = (uint64_t)-1; /* no target preference, use top */
elsewhere_append(true /* flexible target */,
@ -390,7 +386,8 @@ nofb:;
irq_flush_type = IRQ_PIC_ONLY_FLUSH;
common_spinup(multiboot_spinup_32, 4,
0x2badb002, entry_point,
common_spinup(multiboot_spinup_32, 6,
(uint32_t)(uintptr_t)reloc_stub, (uint32_t)0x2badb002,
(uint32_t)mb1_info_final_loc, (uint32_t)entry_point,
(uint32_t)(uintptr_t)ranges, (uint32_t)ranges_count);
}

View File

@ -1,45 +0,0 @@
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <stdnoreturn.h>
#include <mm/vmm.h>
#if bios == 1
# include <sys/idt.h>
#endif
#include <protos/multiboot.h>
noreturn void multiboot2_spinup_32(uint32_t entry_point,
uint32_t multiboot2_info, uint32_t mb_info_target,
uint32_t mb_info_size,
uint32_t elf_ranges, uint32_t elf_ranges_count,
uint32_t slide,
struct mb_reloc_stub *reloc_stub) {
#if bios == 1
struct idtr idtr;
idtr.limit = 0x3ff;
idtr.ptr = 0;
asm volatile (
"lidt %0"
:
: "m" (idtr)
: "memory"
);
#endif
reloc_stub->magic = 0x36d76289;
reloc_stub->entry_point = entry_point;
reloc_stub->mb_info_target = mb_info_target;
asm volatile (
"jmp *%%ebx"
:
: "b"(reloc_stub), "S"(multiboot2_info),
"c"(mb_info_size), "a"(elf_ranges), "d"(elf_ranges_count),
"D"(slide)
: "memory"
);
__builtin_unreachable();
}

View File

@ -1,6 +1,7 @@
#include <protos/multiboot2.h>
#include <stdint.h>
#include <stddef.h>
#include <protos/multiboot2.h>
#include <protos/multiboot.h>
#include <config.h>
#include <lib/libc.h>
#include <lib/elf.h>
@ -10,6 +11,7 @@
#include <lib/uri.h>
#include <lib/fb.h>
#include <lib/term.h>
#include <lib/elsewhere.h>
#include <sys/pic.h>
#include <sys/cpu.h>
#include <sys/idt.h>
@ -20,8 +22,6 @@
#include <lib/blib.h>
#include <drivers/vga_textmode.h>
extern symbol multiboot_reloc_stub, multiboot_reloc_stub_end;
#define LIMINE_BRAND "Limine " LIMINE_VERSION
/// Returns the size required to store the multiboot2 info.
@ -57,26 +57,6 @@ static size_t get_multiboot2_info_size(
#define append_tag(P, TAG) ({ (P) += ALIGN_UP((TAG)->size, MULTIBOOT_TAG_ALIGN); })
static uint32_t kernel_top;
static bool mb2_overlap_check(uint64_t base1, uint64_t top1,
uint64_t base2, uint64_t top2) {
return ((base1 >= base2 && base1 < top2)
|| (top1 > base2 && top1 <= top2));
}
static void *mb2_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 multiboot2_load(char *config, char* cmdline) {
struct file_handle *kernel_file;
@ -122,7 +102,7 @@ bool multiboot2_load(char *config, char* cmdline) {
bool is_elf_info_requested = false;
uint32_t entry_point = 0xffffffff;
uint64_t entry_point = 0xffffffff;
// Iterate through the entries...
for (struct multiboot_header_tag *tag = (struct multiboot_header_tag*)(header + 1); // header + 1 to skip the header struct.
@ -197,8 +177,8 @@ bool multiboot2_load(char *config, char* cmdline) {
}
}
struct elf_range *elf_ranges;
uint64_t elf_ranges_count, slide;
struct elsewhere_range *ranges;
uint64_t ranges_count;
if (addresstag != NULL) {
if (addresstag->load_addr > addresstag->header_addr)
@ -217,7 +197,7 @@ bool multiboot2_load(char *config, char* cmdline) {
memcpy((void *)(uintptr_t)addresstag->load_addr, kernel + (header_offset
- (addresstag->header_addr - addresstag->load_addr)), load_size);
kernel_top = addresstag->load_addr + load_size;
//kernel_top = addresstag->load_addr + load_size;
if (addresstag->bss_end_addr) {
uintptr_t bss_addr = addresstag->load_addr + load_size;
@ -229,20 +209,20 @@ bool multiboot2_load(char *config, char* cmdline) {
memmap_alloc_range(bss_addr, bss_size, MEMMAP_KERNEL_AND_MODULES, true, true, false, false);
memset((void *)bss_addr, 0, bss_size);
kernel_top = bss_addr + bss_size;
//kernel_top = bss_addr + bss_size;
}
} else {
uint64_t e;
int bits = elf_bits(kernel);
uint64_t e = 0, t = 0;
switch (bits) {
case 32:
if (elf32_load(kernel, (uint32_t *)&e, (uint32_t *)&t, MEMMAP_BOOTLOADER_RECLAIMABLE, &slide, &elf_ranges, &elf_ranges_count))
if (elf32_load_elsewhere(kernel, &e, &ranges, &ranges_count))
panic(true, "multiboot2: ELF32 load failure");
break;
case 64: {
if (elf64_load(kernel, &e, &t, &slide, MEMMAP_BOOTLOADER_RECLAIMABLE, false, true, &elf_ranges, &elf_ranges_count, false, NULL, NULL, NULL, NULL))
if (elf64_load_elsewhere(kernel, &e, &ranges, &ranges_count))
panic(true, "multiboot2: ELF64 load failure");
break;
@ -251,17 +231,9 @@ bool multiboot2_load(char *config, char* cmdline) {
panic(true, "multiboot2: Invalid ELF file bitness");
}
e -= slide;
if (entry_point == 0xffffffff) {
entry_point = e;
}
t -= slide;
if (t < 0x100000) {
kernel_top = 0x100000;
} else {
kernel_top = t;
}
}
struct elf_section_hdr_info *section_hdr_info = NULL;
@ -311,41 +283,30 @@ bool multiboot2_load(char *config, char* cmdline) {
size_t info_idx = 0;
// Realloc elsewhere ranges to include mb2 info, modules, and elf sections
struct elsewhere_range *new_ranges = ext_mem_alloc(sizeof(struct elsewhere_range) *
(ranges_count
+ 1 /* mb2 info range */
+ n_modules
+ (section_hdr_info ? section_hdr_info->num : 0)));
memcpy(new_ranges, ranges, sizeof(struct elsewhere_range) * ranges_count);
pmm_free(ranges, sizeof(struct elsewhere_range) * ranges_count);
ranges = new_ranges;
// 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.
// Elsewhere append mb2 info *after* kernel but *before* modules.
uint8_t *mb2_info = ext_mem_alloc(mb2_info_size);
uint64_t mb2_info_final_loc = 0x10000;
retry_mb2_info_reloc:
for (size_t i = 0; i < elf_ranges_count; i++) {
uint64_t mb2_info_top = mb2_info_final_loc + mb2_info_size;
uint64_t base = elf_ranges[i].base - slide;
uint64_t length = elf_ranges[i].length - slide;
uint64_t top = base + length;
// Do they overlap?
if (mb2_overlap_check(base, top, mb2_info_final_loc, mb2_info_top)) {
mb2_info_final_loc = top;
goto retry_mb2_info_reloc;
}
// Make sure it is memory that actually exists.
if (!memmap_alloc_range(mb2_info_final_loc, mb2_info_size, MEMMAP_BOOTLOADER_RECLAIMABLE,
MEMMAP_USABLE, false, true, false)) {
if (!memmap_alloc_range(mb2_info_final_loc, mb2_info_size, MEMMAP_BOOTLOADER_RECLAIMABLE,
MEMMAP_BOOTLOADER_RECLAIMABLE, false, true, false)) {
mb2_info_final_loc += 0x1000;
goto retry_mb2_info_reloc;
}
}
}
if (mb2_info_final_loc + mb2_info_size > kernel_top) {
kernel_top = mb2_info_final_loc + mb2_info_size;
}
elsewhere_append(true /* flexible target */,
ranges, &ranges_count,
mb2_info, &mb2_info_final_loc, mb2_info_size);
struct multiboot2_start_tag *mbi_start = (struct multiboot2_start_tag *)mb2_info;
info_idx += sizeof(struct multiboot2_start_tag);
@ -377,10 +338,13 @@ retry_mb2_info_reloc:
continue;
}
void *section = mb2_alloc(shdr->sh_size);
memcpy(section, kernel + shdr->sh_offset, shdr->sh_size);
uint64_t section = (uint64_t)-1; /* no target preference, use top */
shdr->sh_addr = (uintptr_t)section;
elsewhere_append(true /* flexible target */,
ranges, &ranges_count,
kernel + shdr->sh_offset, &section, shdr->sh_size);
shdr->sh_addr = section;
}
append_tag(info_idx, tag);
@ -406,15 +370,18 @@ retry_mb2_info_reloc:
char *module_cmdline = conf_tuple.value2;
if (!module_cmdline) module_cmdline = "";
void *module_addr = mb2_alloc(f->size);
void *module_addr = freadall(f, MEMMAP_BOOTLOADER_RECLAIMABLE);
uint64_t module_target = (uint64_t)-1;
fread(f, module_addr, 0, f->size);
elsewhere_append(true /* flexible target */,
ranges, &ranges_count,
module_addr, &module_target, f->size);
struct multiboot_tag_module *module_tag = (struct multiboot_tag_module *)(mb2_info + info_idx);
module_tag->type = MULTIBOOT_TAG_TYPE_MODULE;
module_tag->size = sizeof(struct multiboot_tag_module) + strlen(module_cmdline) + 1;
module_tag->mod_start = (uint32_t)(size_t)module_addr;
module_tag->mod_start = module_target;
module_tag->mod_end = module_tag->mod_start + f->size;
strcpy(module_tag->cmdline, module_cmdline); // Copy over the command line
@ -645,9 +612,9 @@ retry_mb2_info_reloc:
}
#endif
// Load relocation stub where it won't get overwritten
// Load relocation stub where it won't get overwritten (hopefully)
size_t reloc_stub_size = (size_t)multiboot_reloc_stub_end - (size_t)multiboot_reloc_stub;
void *reloc_stub = mb2_alloc(reloc_stub_size);
void *reloc_stub = ext_mem_alloc(reloc_stub_size);
memcpy(reloc_stub, multiboot_reloc_stub, reloc_stub_size);
#if uefi == 1
@ -743,11 +710,8 @@ retry_mb2_info_reloc:
irq_flush_type = IRQ_PIC_ONLY_FLUSH;
common_spinup(multiboot2_spinup_32, 8,
entry_point,
(uint32_t)(uintptr_t)mb2_info, (uint32_t)mb2_info_final_loc,
(uint32_t)mb2_info_size,
(uint32_t)(uintptr_t)elf_ranges, (uint32_t)elf_ranges_count,
(uint32_t)slide,
(uint32_t)(uintptr_t)reloc_stub);
common_spinup(multiboot_spinup_32, 6,
(uint32_t)(uintptr_t)reloc_stub, (uint32_t)0x36d76289,
(uint32_t)mb2_info_final_loc, (uint32_t)entry_point,
(uint32_t)(uintptr_t)ranges, (uint32_t)ranges_count);
}

View File

@ -24,7 +24,6 @@
#include <stdint.h>
#include <stdbool.h>
#include <stdnoreturn.h>
bool multiboot2_load(char *config, char *cmdline);
@ -416,6 +415,4 @@ struct multiboot_tag_load_base_addr
uint32_t load_base_addr;
};
noreturn void multiboot2_spinup_32(uint32_t entry_point, uint32_t multiboot1_info);
#endif

View File

@ -8,44 +8,43 @@ multiboot_reloc_stub:
times 4-($-multiboot_reloc_stub) db 0
.magic_value: dd 0
.entry_point: dd 0
.mb_info_target: dd 0
; EBX = self
; ESI = multiboot info (original)
; ECX = multiboot info (size)
; EAX = elf ranges
; EDX = elf ranges count
; EDI = slide
; ESI = magic value
; EDI = protocol info
; ECX = entry point
; EAX = ranges
; EDX = ranges count
.code:
mov ebp, edi
mov edi, [ebx + (.mb_info_target - multiboot_reloc_stub)]
push edi
push esi
push ecx
; Copy multiboot info; frees ESI, EDI, and ECX
rep movsb
.ranges_loop:
test edx, edx ; Loop until we're done
jz .ranges_loop_out
.elf_ranges_loop:
mov esi, [eax] ; ESI = elf_range.base
mov edi, esi ; EDI = elf_range.base - slide
sub edi, ebp
mov ecx, [eax+8] ; ECX = elf_range.length
rep movsb ; Copy range to target location
mov esi, [eax] ; ESI = range.elsewhere
mov edi, [eax+8] ; EDI = range.target
mov ecx, [eax+16] ; ECX = range.length
rep movsb ; Copy range to target location
add eax, 24 ; Move to the next elf_range
add eax, 24 ; Move to the next range
dec edx ; Loop until we're done
jnz .elf_ranges_loop
dec edx
jmp .ranges_loop
.ranges_loop_out:
; We're done relocating!
pop ecx
pop esi
pop edi
push dword [ebx + (.entry_point - multiboot_reloc_stub)]
push ecx
mov eax, [ebx + (.magic_value - multiboot_reloc_stub)]
mov ebx, [ebx + (.mb_info_target - multiboot_reloc_stub)]
mov eax, esi ; EAX = magic value
mov ebx, edi ; EBX = protocol info
xor ecx, ecx
xor edx, edx
xor esi, esi