diff options
author | Gunnar Beutner <gbeutner@serenityos.org> | 2021-07-26 15:10:51 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-07-27 13:15:16 +0200 |
commit | 57417a3d6efe872d26cc790c5cc009dac3a3c8be (patch) | |
tree | 8ec61e9fcd76db03945c5b413276a920fc422087 /Kernel/Prekernel/init.cpp | |
parent | e3d2ca6bd20257bbb49a8da5e37b8e71dc697333 (diff) | |
download | serenity-57417a3d6efe872d26cc790c5cc009dac3a3c8be.zip |
Kernel: Support loading the kernel at almost arbitrary virtual addresses
This enables further work on implementing KASLR by adding relocation
support to the pre-kernel and updating the kernel to be less dependent
on specific virtual memory layouts.
Diffstat (limited to 'Kernel/Prekernel/init.cpp')
-rw-r--r-- | Kernel/Prekernel/init.cpp | 95 |
1 files changed, 60 insertions, 35 deletions
diff --git a/Kernel/Prekernel/init.cpp b/Kernel/Prekernel/init.cpp index 952461a2f4..a4e9dc7fbc 100644 --- a/Kernel/Prekernel/init.cpp +++ b/Kernel/Prekernel/init.cpp @@ -12,6 +12,7 @@ #include <Kernel/Prekernel/Prekernel.h> #include <Kernel/VirtualAddress.h> #include <LibC/elf.h> +#include <LibELF/Relocation.h> // Defined in the linker script extern size_t __stack_chk_guard; @@ -28,7 +29,8 @@ extern "C" u64 boot_pdpt[512]; extern "C" u64 boot_pd0[512]; extern "C" u64 boot_pd0_pts[512 * (MAX_KERNEL_SIZE >> 21 & 0x1ff)]; extern "C" u64 boot_pd_kernel[512]; -extern "C" u64 boot_pd_kernel_pts[512 * (MAX_KERNEL_SIZE >> 21 & 0x1ff)]; +extern "C" u64 boot_pd_kernel_pt0[512]; +extern "C" u64 boot_pd_kernel_image_pts[512 * (MAX_KERNEL_SIZE >> 21 & 0x1ff)]; extern "C" u64 boot_pd_kernel_pt1023[512]; extern "C" char const kernel_cmdline[4096]; @@ -38,23 +40,28 @@ extern "C" { multiboot_info_t* multiboot_info_ptr; } -void __stack_chk_fail() +[[noreturn]] static void halt() { - asm("ud2"); + asm volatile("hlt"); __builtin_unreachable(); } +void __stack_chk_fail() +{ + halt(); +} + +void __assertion_failed(char const*, char const*, unsigned int, char const*) +{ + halt(); +} + namespace Kernel { // boot.S expects these functions to exactly have the following signatures. // We declare them here to ensure their signatures don't accidentally change. extern "C" [[noreturn]] void init(); -static void halt() -{ - asm volatile("hlt"); -} - // SerenityOS Pre-Kernel Environment C++ entry point :^) // // This is where C++ execution begins, after boot.S transfers control here. @@ -75,50 +82,63 @@ extern "C" [[noreturn]] void init() halt(); __builtin_memcpy(kernel_program_headers, kernel_image + kernel_elf_header.e_phoff, sizeof(ElfW(Phdr)) * kernel_elf_header.e_phnum); - FlatPtr kernel_load_base = 0; + FlatPtr kernel_physical_base = 0x200000; +#if ARCH(I386) + FlatPtr kernel_load_base = 0xc0200000; +#else + FlatPtr kernel_load_base = 0x2000200000; +#endif + FlatPtr kernel_load_end = 0; for (size_t i = 0; i < kernel_elf_header.e_phnum; i++) { auto& kernel_program_header = kernel_program_headers[i]; if (kernel_program_header.p_type != PT_LOAD) continue; - auto start = kernel_program_header.p_vaddr; + auto start = kernel_load_base + kernel_program_header.p_vaddr; auto end = start + kernel_program_header.p_memsz; if (start < (FlatPtr)end_of_prekernel_image) halt(); - if (kernel_program_header.p_paddr < (FlatPtr)end_of_prekernel_image) + if (kernel_physical_base + kernel_program_header.p_paddr < (FlatPtr)end_of_prekernel_image) halt(); - if (kernel_load_base == 0 || start < kernel_load_base) - kernel_load_base = start; if (end > kernel_load_end) kernel_load_end = end; } // align to 1GB - kernel_load_base &= ~(FlatPtr)0x3fffffff; + FlatPtr kernel_mapping_base = kernel_load_base & ~(FlatPtr)0x3fffffff; + + VERIFY(kernel_load_base % 0x1000 == 0); + VERIFY(kernel_load_base >= kernel_mapping_base + 0x200000); #if ARCH(I386) int pdpt_flags = 0x1; #else int pdpt_flags = 0x3; #endif - boot_pdpt[(kernel_load_base >> 30) & 0x1ffu] = (FlatPtr)boot_pd_kernel | pdpt_flags; + boot_pdpt[(kernel_mapping_base >> 30) & 0x1ffu] = (FlatPtr)boot_pd_kernel | pdpt_flags; + + boot_pd_kernel[0] = (FlatPtr)boot_pd_kernel_pt0 | 0x3; + + for (FlatPtr vaddr = kernel_load_base; vaddr <= kernel_load_end; vaddr += PAGE_SIZE * 512) + boot_pd_kernel[(vaddr - kernel_mapping_base) >> 21] = (FlatPtr)(&boot_pd_kernel_image_pts[(vaddr - kernel_load_base) >> 12]) | 0x3; - for (size_t i = 0; i <= (kernel_load_end - kernel_load_base) >> 21; i++) - boot_pd_kernel[i] = (FlatPtr)&boot_pd_kernel_pts[i * 512] | 0x3; + __builtin_memset(boot_pd_kernel_pt0, 0, sizeof(boot_pd_kernel_pt0)); - __builtin_memset(boot_pd_kernel_pts, 0, sizeof(boot_pd_kernel_pts)); + VERIFY((size_t)end_of_prekernel_image < array_size(boot_pd_kernel_pt0) * PAGE_SIZE); /* pseudo-identity map 0M - end_of_prekernel_image */ for (size_t i = 0; i < (FlatPtr)end_of_prekernel_image / PAGE_SIZE; i++) - boot_pd_kernel_pts[i] = i * PAGE_SIZE | 0x3; + boot_pd_kernel_pt0[i] = i * PAGE_SIZE | 0x3; + + __builtin_memset(boot_pd_kernel_image_pts, 0, sizeof(boot_pd_kernel_image_pts)); for (size_t i = 0; i < kernel_elf_header.e_phnum; i++) { auto& kernel_program_header = kernel_program_headers[i]; if (kernel_program_header.p_type != PT_LOAD) continue; for (FlatPtr offset = 0; offset < kernel_program_header.p_memsz; offset += PAGE_SIZE) { - auto pte_index = (kernel_program_header.p_vaddr + offset - kernel_load_base) >> 12; - boot_pd_kernel_pts[pte_index] = (kernel_program_header.p_paddr + offset) | 0x3; + auto pte_index = ((kernel_load_base & 0x1fffff) + kernel_program_header.p_vaddr + offset) >> 12; + boot_pd_kernel_image_pts[pte_index] = (kernel_physical_base + kernel_program_header.p_paddr + offset) | 0x3; } } @@ -130,28 +150,29 @@ extern "C" [[noreturn]] void init() auto& kernel_program_header = kernel_program_headers[i]; if (kernel_program_header.p_type != PT_LOAD) continue; - __builtin_memmove((u8*)kernel_program_header.p_vaddr, kernel_image + kernel_program_header.p_offset, kernel_program_header.p_filesz); + __builtin_memmove((u8*)kernel_load_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--) { auto& kernel_program_header = kernel_program_headers[i]; if (kernel_program_header.p_type != PT_LOAD) continue; - __builtin_memset((u8*)kernel_program_header.p_vaddr + kernel_program_header.p_filesz, 0, kernel_program_header.p_memsz - kernel_program_header.p_filesz); + __builtin_memset((u8*)kernel_load_base + kernel_program_header.p_vaddr + kernel_program_header.p_filesz, 0, kernel_program_header.p_memsz - kernel_program_header.p_filesz); } multiboot_info_ptr->mods_count--; multiboot_info_ptr->mods_addr += sizeof(multiboot_module_entry_t); - auto adjust_by_load_base = [kernel_load_base](auto ptr) { - return (decltype(ptr))((FlatPtr)ptr + kernel_load_base); + auto adjust_by_mapping_base = [kernel_mapping_base](auto ptr) { + return (decltype(ptr))((FlatPtr)ptr + kernel_mapping_base); }; BootInfo info; info.start_of_prekernel_image = (PhysicalPtr)start_of_prekernel_image; info.end_of_prekernel_image = (PhysicalPtr)end_of_prekernel_image; - info.physical_to_virtual_offset = kernel_load_base; - info.kernel_base = kernel_load_base; + info.physical_to_virtual_offset = kernel_load_base - kernel_physical_base; + info.kernel_mapping_base = kernel_mapping_base; + info.kernel_load_base = kernel_load_base; #if ARCH(X86_64) info.gdt64ptr = (PhysicalPtr)gdt64ptr; info.code64_sel = code64_sel; @@ -160,12 +181,12 @@ extern "C" [[noreturn]] void init() info.boot_pdpt = (PhysicalPtr)boot_pdpt; info.boot_pd0 = (PhysicalPtr)boot_pd0; info.boot_pd_kernel = (PhysicalPtr)boot_pd_kernel; - info.boot_pd_kernel_pt1023 = (FlatPtr)adjust_by_load_base(boot_pd_kernel_pt1023); - info.kernel_cmdline = (FlatPtr)adjust_by_load_base(kernel_cmdline); + info.boot_pd_kernel_pt1023 = (FlatPtr)adjust_by_mapping_base(boot_pd_kernel_pt1023); + info.kernel_cmdline = (FlatPtr)adjust_by_mapping_base(kernel_cmdline); info.multiboot_flags = multiboot_info_ptr->flags; - info.multiboot_memory_map = adjust_by_load_base((FlatPtr)multiboot_info_ptr->mmap_addr); + info.multiboot_memory_map = adjust_by_mapping_base((FlatPtr)multiboot_info_ptr->mmap_addr); info.multiboot_memory_map_count = multiboot_info_ptr->mmap_length / sizeof(multiboot_memory_map_t); - info.multiboot_modules = adjust_by_load_base((FlatPtr)multiboot_info_ptr->mods_addr); + info.multiboot_modules = adjust_by_mapping_base((FlatPtr)multiboot_info_ptr->mods_addr); info.multiboot_modules_count = multiboot_info_ptr->mods_count; info.multiboot_framebuffer_addr = multiboot_info_ptr->framebuffer_addr; info.multiboot_framebuffer_pitch = multiboot_info_ptr->framebuffer_pitch; @@ -178,9 +199,11 @@ extern "C" [[noreturn]] void init() #if ARCH(I386) "add %0, %%esp" #else - "add %0, %%rsp" + "movabs %0, %%rax\n" + "add %%rax, %%rsp" #endif - ::"g"(kernel_load_base)); + ::"g"(kernel_mapping_base) + : "ax"); // unmap the 0-1MB region for (size_t i = 0; i < 256; i++) @@ -192,8 +215,10 @@ extern "C" [[noreturn]] void init() reload_cr3(); - void (*entry)(BootInfo const&) = (void (*)(BootInfo const&))kernel_elf_header.e_entry; - entry(*adjust_by_load_base(&info)); + ELF::perform_relative_relocations(kernel_load_base); + + void (*entry)(BootInfo const&) = (void (*)(BootInfo const&))(kernel_load_base + kernel_elf_header.e_entry); + entry(*adjust_by_mapping_base(&info)); __builtin_unreachable(); } |