init.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. /*
  2. * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
  3. * Copyright (c) 2021, Gunnar Beutner <gbeutner@serenityos.org>
  4. * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
  5. *
  6. * SPDX-License-Identifier: BSD-2-Clause
  7. */
  8. #include <AK/Types.h>
  9. #include <Kernel/Multiboot.h>
  10. #include <Kernel/Prekernel/BootInfo.h>
  11. #include <Kernel/Prekernel/Prekernel.h>
  12. #include <Kernel/VirtualAddress.h>
  13. #include <LibC/elf.h>
  14. // Defined in the linker script
  15. extern size_t __stack_chk_guard;
  16. size_t __stack_chk_guard;
  17. extern "C" [[noreturn]] void __stack_chk_fail();
  18. extern "C" u8 start_of_prekernel_image[];
  19. extern "C" u8 end_of_prekernel_image[];
  20. extern "C" u8 gdt64ptr[];
  21. extern "C" u16 code64_sel;
  22. extern "C" u64 boot_pml4t[512];
  23. extern "C" u64 boot_pdpt[512];
  24. extern "C" u64 boot_pd0[512];
  25. extern "C" u64 boot_pd0_pts[512 * (MAX_KERNEL_SIZE >> 21 & 0x1ff)];
  26. extern "C" u64 boot_pd_kernel[512];
  27. extern "C" u64 boot_pd_kernel_pts[512 * (MAX_KERNEL_SIZE >> 21 & 0x1ff)];
  28. extern "C" u64 boot_pd_kernel_pt1023[512];
  29. extern "C" char const kernel_cmdline[4096];
  30. extern "C" void reload_cr3();
  31. extern "C" {
  32. multiboot_info_t* multiboot_info_ptr;
  33. }
  34. void __stack_chk_fail()
  35. {
  36. asm("ud2");
  37. __builtin_unreachable();
  38. }
  39. namespace Kernel {
  40. // boot.S expects these functions to exactly have the following signatures.
  41. // We declare them here to ensure their signatures don't accidentally change.
  42. extern "C" [[noreturn]] void init();
  43. static void halt()
  44. {
  45. asm volatile("hlt");
  46. }
  47. // SerenityOS Pre-Kernel Environment C++ entry point :^)
  48. //
  49. // This is where C++ execution begins, after boot.S transfers control here.
  50. //
  51. extern "C" [[noreturn]] void init()
  52. {
  53. if (multiboot_info_ptr->mods_count < 1)
  54. halt();
  55. multiboot_module_entry_t* kernel_module = (multiboot_module_entry_t*)(FlatPtr)multiboot_info_ptr->mods_addr;
  56. u8* kernel_image = (u8*)(FlatPtr)kernel_module->start;
  57. // copy the ELF header and program headers because we might end up overwriting them
  58. ElfW(Ehdr) kernel_elf_header = *(ElfW(Ehdr)*)kernel_image;
  59. ElfW(Phdr) kernel_program_headers[16];
  60. if (kernel_elf_header.e_phnum > array_size(kernel_program_headers))
  61. halt();
  62. __builtin_memcpy(kernel_program_headers, kernel_image + kernel_elf_header.e_phoff, sizeof(ElfW(Phdr)) * kernel_elf_header.e_phnum);
  63. FlatPtr kernel_load_base = kernel_program_headers[0].p_vaddr;
  64. FlatPtr kernel_load_end = kernel_program_headers[kernel_elf_header.e_phnum - 1].p_vaddr + kernel_program_headers[kernel_elf_header.e_phnum - 1].p_memsz;
  65. // align to 1GB
  66. kernel_load_base &= ~(FlatPtr)0x3fffffff;
  67. if (kernel_program_headers[0].p_vaddr < (FlatPtr)end_of_prekernel_image)
  68. halt();
  69. if (kernel_program_headers[0].p_paddr < (FlatPtr)end_of_prekernel_image)
  70. halt();
  71. #if ARCH(I386)
  72. int pdpt_flags = 0x1;
  73. #else
  74. int pdpt_flags = 0x3;
  75. #endif
  76. boot_pdpt[(kernel_load_base >> 30) & 0x1ffu] = (FlatPtr)boot_pd_kernel | pdpt_flags;
  77. for (size_t i = 0; i <= (kernel_load_end - kernel_load_base) >> 21; i++)
  78. boot_pd_kernel[i] = (FlatPtr)&boot_pd_kernel_pts[i * 512] | 0x3;
  79. __builtin_memset(boot_pd_kernel_pts, 0, sizeof(boot_pd_kernel_pts));
  80. /* pseudo-identity map 0M - end_of_prekernel_image */
  81. for (size_t i = 0; i < (FlatPtr)end_of_prekernel_image / PAGE_SIZE; i++)
  82. boot_pd_kernel_pts[i] = i * PAGE_SIZE | 0x3;
  83. for (size_t i = 0; i < kernel_elf_header.e_phnum; i++) {
  84. auto& kernel_program_header = kernel_program_headers[i];
  85. if (kernel_program_header.p_type != PT_LOAD)
  86. continue;
  87. for (FlatPtr offset = 0; offset < kernel_program_header.p_memsz; offset += PAGE_SIZE) {
  88. auto pte_index = (kernel_program_header.p_vaddr + offset - kernel_load_base) >> 12;
  89. boot_pd_kernel_pts[pte_index] = (kernel_program_header.p_paddr + offset) | 0x3;
  90. }
  91. }
  92. boot_pd_kernel[511] = (FlatPtr)boot_pd_kernel_pt1023 | 0x3;
  93. reload_cr3();
  94. for (ssize_t i = kernel_elf_header.e_phnum - 1; i >= 0; i--) {
  95. auto& kernel_program_header = kernel_program_headers[i];
  96. if (kernel_program_header.p_type != PT_LOAD)
  97. continue;
  98. __builtin_memmove((u8*)kernel_program_header.p_vaddr, kernel_image + kernel_program_header.p_offset, kernel_program_header.p_filesz);
  99. }
  100. for (ssize_t i = kernel_elf_header.e_phnum - 1; i >= 0; i--) {
  101. auto& kernel_program_header = kernel_program_headers[i];
  102. if (kernel_program_header.p_type != PT_LOAD)
  103. continue;
  104. __builtin_memset((u8*)kernel_program_header.p_vaddr + kernel_program_header.p_filesz, 0, kernel_program_header.p_memsz - kernel_program_header.p_filesz);
  105. }
  106. multiboot_info_ptr->mods_count--;
  107. multiboot_info_ptr->mods_addr += sizeof(multiboot_module_entry_t);
  108. auto adjust_by_load_base = [kernel_load_base](auto* ptr) {
  109. return (decltype(ptr))((FlatPtr)ptr + kernel_load_base);
  110. };
  111. BootInfo info;
  112. info.start_of_prekernel_image = adjust_by_load_base(start_of_prekernel_image);
  113. info.end_of_prekernel_image = adjust_by_load_base(end_of_prekernel_image);
  114. info.kernel_base = kernel_load_base;
  115. info.multiboot_info_ptr = adjust_by_load_base(multiboot_info_ptr);
  116. #if ARCH(X86_64)
  117. info.gdt64ptr = (FlatPtr)gdt64ptr;
  118. info.code64_sel = code64_sel;
  119. info.boot_pml4t = (FlatPtr)adjust_by_load_base(boot_pml4t);
  120. #endif
  121. info.boot_pdpt = (FlatPtr)adjust_by_load_base(boot_pdpt);
  122. info.boot_pd0 = (FlatPtr)adjust_by_load_base(boot_pd0);
  123. info.boot_pd_kernel = (FlatPtr)adjust_by_load_base(boot_pd_kernel);
  124. info.boot_pd_kernel_pt1023 = (FlatPtr)adjust_by_load_base(boot_pd_kernel_pt1023);
  125. info.kernel_cmdline = adjust_by_load_base(kernel_cmdline);
  126. asm(
  127. #if ARCH(I386)
  128. "add %0, %%esp"
  129. #else
  130. "add %0, %%rsp"
  131. #endif
  132. ::"g"(kernel_load_base));
  133. // unmap the 0-1MB region
  134. for (size_t i = 0; i < 256; i++)
  135. boot_pd0_pts[i] = 0;
  136. // unmap the end_of_prekernel_image - MAX_KERNEL_SIZE region
  137. for (FlatPtr vaddr = (FlatPtr)end_of_prekernel_image; vaddr < MAX_KERNEL_SIZE; vaddr += PAGE_SIZE)
  138. boot_pd0_pts[vaddr >> 12 & 0x1ff] = 0;
  139. void (*entry)(BootInfo const&) = (void (*)(BootInfo const&))kernel_elf_header.e_entry;
  140. entry(*adjust_by_load_base(&info));
  141. __builtin_unreachable();
  142. }
  143. // Define some Itanium C++ ABI methods to stop the linker from complaining.
  144. // If we actually call these something has gone horribly wrong
  145. void* __dso_handle __attribute__((visibility("hidden")));
  146. }