Prekernel: Support kernel preloaded at high address

Loaders try to put modules as low as reasonable but on
EFI often "reasonable" is much higher than on BIOS. As
a result target can be easily higher than source.

Then we have 2 problems:
* memmove compares virtual address and since target
  is mapped higher it ends up going backwards which
  is wrong if target is physically below source
* order of copying of sections must be inverted if
  target is below source
This commit is contained in:
Vladimir Serbinenko 2023-07-20 08:21:17 +02:00 committed by Andrew Kaster
parent 982ce17927
commit d13609a607
Notes: sideshowbarker 2024-07-17 01:00:06 +09:00

View file

@ -74,6 +74,22 @@ extern "C" [[noreturn]] void init();
u64 generate_secure_seed();
static void memmove_virt(void* dest_virt, FlatPtr dest_phys, void* src, size_t n)
{
if (dest_phys < (FlatPtr)src) {
u8* pd = (u8*)dest_virt;
u8 const* ps = (u8 const*)src;
for (; n--;)
*pd++ = *ps++;
return;
}
u8* pd = (u8*)dest_virt;
u8 const* ps = (u8 const*)src;
for (pd += n, ps += n; n--;)
*--pd = *--ps;
}
extern "C" [[noreturn]] void init()
{
if (multiboot_info_ptr->mods_count < 1)
@ -154,11 +170,15 @@ extern "C" [[noreturn]] void init()
reload_cr3();
for (ssize_t i = kernel_elf_header.e_phnum - 1; i >= 0; i--) {
auto& kernel_program_header = kernel_program_headers[i];
int backwards = kernel_physical_base >= (FlatPtr)kernel_image;
for (ssize_t i = 0; i < kernel_elf_header.e_phnum; i++) {
auto& kernel_program_header = kernel_program_headers[backwards ? kernel_elf_header.e_phnum - 1 - i : i];
if (kernel_program_header.p_type != PT_LOAD)
continue;
__builtin_memmove((u8*)kernel_load_base + kernel_program_header.p_vaddr, kernel_image + kernel_program_header.p_offset, kernel_program_header.p_filesz);
memmove_virt((u8*)kernel_load_base + kernel_program_header.p_vaddr,
kernel_physical_base + kernel_program_header.p_vaddr,
kernel_image + kernel_program_header.p_offset, kernel_program_header.p_filesz);
}
for (ssize_t i = kernel_elf_header.e_phnum - 1; i >= 0; i--) {