Procházet zdrojové kódy

Kernel/x86: Bake the Prekernel and the Kernel into one image

The new baked image is a Prekernel and a Kernel baked together now, so
essentially we no longer need to pass the Prekernel as -kernel and the
actual  kernel image as -initrd to QEMU, leaving the option to pass an
actual initrd or initramfs module later on with multiboot.
Liav A před 2 roky
rodič
revize
897c4e5145

+ 6 - 7
Kernel/Arch/init.cpp

@@ -84,9 +84,6 @@ extern "C" u8 end_of_safemem_atomic_text[];
 
 extern "C" u8 end_of_kernel_image[];
 
-multiboot_module_entry_t multiboot_copy_boot_modules_array[16];
-size_t multiboot_copy_boot_modules_count;
-
 READONLY_AFTER_INIT bool g_in_early_boot;
 
 namespace Kernel {
@@ -137,8 +134,10 @@ READONLY_AFTER_INIT char const* kernel_cmdline;
 READONLY_AFTER_INIT u32 multiboot_flags;
 READONLY_AFTER_INIT multiboot_memory_map_t* multiboot_memory_map;
 READONLY_AFTER_INIT size_t multiboot_memory_map_count;
-READONLY_AFTER_INIT multiboot_module_entry_t* multiboot_modules;
 READONLY_AFTER_INIT size_t multiboot_modules_count;
+READONLY_AFTER_INIT PhysicalAddress multiboot_module_ramdisk_physical_start;
+READONLY_AFTER_INIT PhysicalAddress multiboot_module_ramdisk_physical_end;
+READONLY_AFTER_INIT PhysicalAddress multiboot_module_ramdisk_physical_string_addr;
 READONLY_AFTER_INIT PhysicalAddress multiboot_framebuffer_addr;
 READONLY_AFTER_INIT u32 multiboot_framebuffer_pitch;
 READONLY_AFTER_INIT u32 multiboot_framebuffer_width;
@@ -170,8 +169,10 @@ extern "C" [[noreturn]] UNMAP_AFTER_INIT void init([[maybe_unused]] BootInfo con
     multiboot_flags = boot_info.multiboot_flags;
     multiboot_memory_map = (multiboot_memory_map_t*)boot_info.multiboot_memory_map;
     multiboot_memory_map_count = boot_info.multiboot_memory_map_count;
-    multiboot_modules = (multiboot_module_entry_t*)boot_info.multiboot_modules;
     multiboot_modules_count = boot_info.multiboot_modules_count;
+    multiboot_module_ramdisk_physical_start = PhysicalAddress { boot_info.multiboot_module_ramdisk_physical_start };
+    multiboot_module_ramdisk_physical_end = PhysicalAddress { boot_info.multiboot_module_ramdisk_physical_end };
+    multiboot_module_ramdisk_physical_string_addr = PhysicalAddress { boot_info.multiboot_module_ramdisk_physical_string_addr };
     multiboot_framebuffer_addr = PhysicalAddress { boot_info.multiboot_framebuffer_addr };
     multiboot_framebuffer_pitch = boot_info.multiboot_framebuffer_pitch;
     multiboot_framebuffer_width = boot_info.multiboot_framebuffer_width;
@@ -200,8 +201,6 @@ extern "C" [[noreturn]] UNMAP_AFTER_INIT void init([[maybe_unused]] BootInfo con
     // We need to copy the command line before kmalloc is initialized,
     // as it may overwrite parts of multiboot!
     CommandLine::early_initialize(kernel_cmdline);
-    memcpy(multiboot_copy_boot_modules_array, multiboot_modules, multiboot_modules_count * sizeof(multiboot_module_entry_t));
-    multiboot_copy_boot_modules_count = multiboot_modules_count;
 
     new (&bsp_processor()) Processor();
     bsp_processor().early_initialize(0);

+ 2 - 3
Kernel/Arch/x86_64/linker.ld

@@ -69,6 +69,8 @@ SECTIONS
         start_of_kernel_data = .;
         *(.data*)
         end_of_kernel_data = .;
+        . = ALIGN(4K);
+        *(.heap)
     } :data
 
     .ro_after_init ALIGN(4K) : AT(ADDR(.ro_after_init))
@@ -85,9 +87,6 @@ SECTIONS
         *(COMMON)
         *(.bss*)
         end_of_kernel_bss = .;
-
-        . = ALIGN(4K);
-        *(.heap)
     } :bss
 
     .dynamic ALIGN(4K) : AT (ADDR(.dynamic))

+ 25 - 2
Kernel/CMakeLists.txt

@@ -720,7 +720,25 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang$")
     target_link_libraries(Kernel PRIVATE kernel_heap clang_rt.builtins)
 endif()
 
-add_custom_command(
+if ("${SERENITY_ARCH}" STREQUAL "x86_64")
+    set(KERNEL_ELF_OBJCOPY_TARGET "elf64-x86-64")
+endif()
+
+# In x86_64 the Kernel is linked to the Pre-kernel binary.
+if ("${SERENITY_ARCH}" STREQUAL "x86_64")
+    add_custom_command(
+        TARGET Kernel POST_BUILD
+        COMMAND ${CMAKE_COMMAND} -E env NM=${CMAKE_NM} sh ${CMAKE_CURRENT_SOURCE_DIR}/mkmap.sh
+        COMMAND ${CMAKE_COMMAND} -E env OBJCOPY=${CMAKE_OBJCOPY} sh ${CMAKE_CURRENT_SOURCE_DIR}/embedmap.sh
+        COMMAND ${CMAKE_OBJCOPY} --only-keep-debug Kernel Kernel.debug
+        COMMAND ${CMAKE_OBJCOPY} --strip-debug Kernel
+        COMMAND ${CMAKE_OBJCOPY} --add-gnu-debuglink=Kernel.debug Kernel
+        COMMAND ${CMAKE_OBJCOPY} --set-section-flags .heap=load Kernel Kernel_shared_object
+        COMMAND ${CMAKE_OBJCOPY} -I binary -O ${KERNEL_ELF_OBJCOPY_TARGET} --rename-section .data=.Kernel_image --set-section-alignment .Kernel_image=4096 Kernel_shared_object Kernel.o
+        BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/Kernel.o ${CMAKE_CURRENT_BINARY_DIR}/kernel.map
+    )
+elseif ("${SERENITY_ARCH}" STREQUAL "aarch64")
+    add_custom_command(
         TARGET Kernel POST_BUILD
         COMMAND "${CMAKE_COMMAND}" -E env NM=${CMAKE_NM} sh ${CMAKE_CURRENT_SOURCE_DIR}/mkmap.sh
         COMMAND "${CMAKE_COMMAND}" -E env OBJCOPY=${CMAKE_OBJCOPY} sh ${CMAKE_CURRENT_SOURCE_DIR}/embedmap.sh
@@ -728,9 +746,14 @@ add_custom_command(
         COMMAND ${CMAKE_OBJCOPY} --strip-debug Kernel
         COMMAND ${CMAKE_OBJCOPY} --add-gnu-debuglink=Kernel.debug Kernel
         BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/kernel.map
-)
+    )
+endif()
 
+# Both architectures (x86_64, aarch64) share the same location in their respective architecture build folder.
+# In x86_64 the Kernel is linked to the Pre-kernel binary and then generates the result Kernel binary.
+# In aarch64 there's no Pre-kernel stage yet, so we immediately get a Kernel binary.
 install(FILES "${CMAKE_CURRENT_BINARY_DIR}/Kernel" DESTINATION boot)
+
 install(FILES "${CMAKE_CURRENT_BINARY_DIR}/Kernel.debug" DESTINATION boot)
 install(FILES "${CMAKE_CURRENT_BINARY_DIR}/kernel.map" DESTINATION res)
 

+ 0 - 12
Kernel/Memory/MemoryManager.cpp

@@ -38,9 +38,6 @@ extern u8 end_of_unmap_after_init[];
 extern u8 start_of_kernel_ksyms[];
 extern u8 end_of_kernel_ksyms[];
 
-extern multiboot_module_entry_t multiboot_copy_boot_modules_array[16];
-extern size_t multiboot_copy_boot_modules_count;
-
 namespace Kernel::Memory {
 
 ErrorOr<FlatPtr> page_round_up(FlatPtr x)
@@ -271,15 +268,6 @@ UNMAP_AFTER_INIT void MemoryManager::parse_memory_map()
 #endif
         global_data.used_memory_ranges.append(UsedMemoryRange { UsedMemoryRangeType::Kernel, PhysicalAddress(virtual_to_low_physical((FlatPtr)start_of_kernel_image)), PhysicalAddress(page_round_up(virtual_to_low_physical((FlatPtr)end_of_kernel_image)).release_value_but_fixme_should_propagate_errors()) });
 
-        if (multiboot_flags & 0x4) {
-            auto* bootmods_start = multiboot_copy_boot_modules_array;
-            auto* bootmods_end = bootmods_start + multiboot_copy_boot_modules_count;
-
-            for (auto* bootmod = bootmods_start; bootmod < bootmods_end; bootmod++) {
-                global_data.used_memory_ranges.append(UsedMemoryRange { UsedMemoryRangeType::BootModule, PhysicalAddress(bootmod->start), PhysicalAddress(bootmod->end) });
-            }
-        }
-
         auto* mmap_begin = multiboot_memory_map;
         auto* mmap_end = multiboot_memory_map + multiboot_memory_map_count;
 

+ 18 - 4
Kernel/Prekernel/CMakeLists.txt

@@ -8,14 +8,21 @@ set(SOURCES
     )
 
 if ("${SERENITY_ARCH}" STREQUAL "x86_64")
-    set(PREKERNEL_TARGET Prekernel64)
+    set(PREKERNEL_TARGET kernel_x86-64)
 elseif("${SERENITY_ARCH}" STREQUAL "aarch64")
     message(SEND_ERROR "Prekernel is not needed on aarch64 and should not be compiled!")
 endif()
 
 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static")
 
-add_executable(${PREKERNEL_TARGET} ${SOURCES})
+add_library(KernelObject OBJECT IMPORTED)
+
+set_property(TARGET KernelObject PROPERTY 
+    IMPORTED_OBJECTS ${CMAKE_CURRENT_BINARY_DIR}/../Kernel.o
+)
+
+add_executable(${PREKERNEL_TARGET} ${SOURCES} $<TARGET_OBJECTS:KernelObject>)
+add_dependencies(${PREKERNEL_TARGET} Kernel)
 target_compile_options(${PREKERNEL_TARGET} PRIVATE -no-pie -fno-pic -fno-threadsafe-statics)
 
 target_link_options(${PREKERNEL_TARGET} PRIVATE LINKER:-T ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld -nostdlib LINKER:--no-pie)
@@ -27,13 +34,20 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang$")
     target_link_libraries(${PREKERNEL_TARGET} PRIVATE clang_rt.builtins)
 endif()
 
+if ("${SERENITY_ARCH}" STREQUAL "x86_64")
+    set(ELF_OBJCOPY_TARGET "elf32-i386")
+elseif("${SERENITY_ARCH}" STREQUAL "aarch64")
+    message(SEND_ERROR "Prekernel is not needed on aarch64 and should not be compiled!")
+endif()
+
+
 add_custom_command(
     TARGET ${PREKERNEL_TARGET} POST_BUILD
-    COMMAND ${CMAKE_OBJCOPY} -O elf32-i386 ${CMAKE_CURRENT_BINARY_DIR}/${PREKERNEL_TARGET} ${CMAKE_CURRENT_BINARY_DIR}/Prekernel
+    COMMAND ${CMAKE_OBJCOPY} -O ${ELF_OBJCOPY_TARGET} ${CMAKE_CURRENT_BINARY_DIR}/${PREKERNEL_TARGET} ${CMAKE_CURRENT_BINARY_DIR}/../Kernel
     BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/Prekernel
 )
 
-install(FILES "${CMAKE_CURRENT_BINARY_DIR}/Prekernel" DESTINATION boot)
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/../Kernel" DESTINATION boot)
 
 # Remove options which the Prekernel environment doesn't support.
 get_target_property(PREKERNEL_TARGET_OPTIONS ${PREKERNEL_TARGET} COMPILE_OPTIONS)

+ 4 - 1
Kernel/Prekernel/Prekernel.h

@@ -41,8 +41,11 @@ struct [[gnu::packed]] BootInfo {
     u32 multiboot_flags;
     u64 multiboot_memory_map;
     u32 multiboot_memory_map_count;
-    u64 multiboot_modules;
+    u64 multiboot_modules_physical_ptr;
     u32 multiboot_modules_count;
+    u32 multiboot_module_ramdisk_physical_start;
+    u32 multiboot_module_ramdisk_physical_end;
+    u32 multiboot_module_ramdisk_physical_string_addr;
     u64 multiboot_framebuffer_addr;
     u32 multiboot_framebuffer_pitch;
     u32 multiboot_framebuffer_width;

+ 15 - 12
Kernel/Prekernel/init.cpp

@@ -27,6 +27,9 @@ extern "C" [[noreturn]] void __stack_chk_fail();
 extern "C" u8 start_of_prekernel_image[];
 extern "C" u8 end_of_prekernel_image[];
 
+extern "C" u8 _binary_Kernel_standalone_start[];
+extern "C" u8 end_of_prekernel_image_after_kernel_image[];
+
 extern "C" u8 gdt64ptr[];
 extern "C" u16 code64_sel;
 extern "C" u64 boot_pml4t[512];
@@ -76,12 +79,7 @@ u64 generate_secure_seed();
 
 extern "C" [[noreturn]] void init()
 {
-    if (multiboot_info_ptr->mods_count < 1)
-        halt();
-
-    multiboot_module_entry_t* kernel_module = (multiboot_module_entry_t*)(FlatPtr)multiboot_info_ptr->mods_addr;
-
-    u8* kernel_image = (u8*)(FlatPtr)kernel_module->start;
+    u8* kernel_image = _binary_Kernel_standalone_start;
     // copy the ELF header and program headers because we might end up overwriting them
     ElfW(Ehdr) kernel_elf_header = *(ElfW(Ehdr)*)kernel_image;
     ElfW(Phdr) kernel_program_headers[16];
@@ -89,8 +87,8 @@ 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_physical_base = 0x200000;
-    FlatPtr default_kernel_load_base = KERNEL_MAPPING_BASE + 0x200000;
+    FlatPtr kernel_physical_base = (FlatPtr)kernel_image;
+    FlatPtr default_kernel_load_base = KERNEL_MAPPING_BASE + kernel_physical_base;
 
     FlatPtr kernel_load_base = default_kernel_load_base;
 
@@ -168,9 +166,6 @@ extern "C" [[noreturn]] void init()
         __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_mapping_base = [kernel_mapping_base](auto ptr) {
         return (decltype(ptr))((FlatPtr)ptr + kernel_mapping_base);
     };
@@ -194,8 +189,16 @@ extern "C" [[noreturn]] void init()
     info.multiboot_flags = multiboot_info_ptr->flags;
     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_mapping_base((FlatPtr)multiboot_info_ptr->mods_addr);
+    info.multiboot_modules_physical_ptr = (FlatPtr)multiboot_info_ptr->mods_addr;
     info.multiboot_modules_count = multiboot_info_ptr->mods_count;
+
+    if (info.multiboot_modules_count > 0) {
+        auto* entry = reinterpret_cast<multiboot_module_entry*>(multiboot_info_ptr->mods_addr);
+        info.multiboot_module_ramdisk_physical_start = entry->start;
+        info.multiboot_module_ramdisk_physical_end = entry->end;
+        info.multiboot_module_ramdisk_physical_string_addr = entry->string_addr;
+    }
+
     if ((multiboot_info_ptr->flags & MULTIBOOT_INFO_FRAMEBUFFER_INFO) != 0) {
         info.multiboot_framebuffer_addr = multiboot_info_ptr->framebuffer_addr;
         info.multiboot_framebuffer_pitch = multiboot_info_ptr->framebuffer_pitch;

+ 9 - 0
Kernel/Prekernel/linker.ld

@@ -44,4 +44,13 @@ SECTIONS
     } :bss
 
     end_of_prekernel_image = .;
+
+    .Kernel_image ALIGN(4K) : AT (ADDR(.Kernel_image))
+    {
+        _binary_Kernel_standalone_start = .;
+        KEEP(*(.Kernel_image))
+    }
+
+    end_of_prekernel_image_after_kernel_image = .;
+
 }

+ 1 - 1
Meta/debug-kernel.sh

@@ -60,7 +60,7 @@ exec $SERENITY_KERNEL_DEBUGGER \
     -ex "file $SCRIPT_DIR/../Build/${SERENITY_ARCH:-x86_64}$toolchain_suffix/Kernel/Prekernel/$prekernel_image" \
     -ex "set confirm off" \
     -ex "directory $SCRIPT_DIR/../Build/${SERENITY_ARCH:-x86_64}$toolchain_suffix/" \
-    -ex "add-symbol-file $SCRIPT_DIR/../Build/${SERENITY_ARCH:-x86_64}$toolchain_suffix/Kernel/Kernel -o $kernel_base" \
+    -ex "add-symbol-file $SCRIPT_DIR/../Build/${SERENITY_ARCH:-x86_64}$toolchain_suffix/Kernel/Kernel_shared_object -o $kernel_base" \
     -ex "set confirm on" \
     -ex "set arch $gdb_arch" \
     -ex "set print frame-arguments none" \

+ 1 - 8
Meta/run.sh

@@ -328,16 +328,9 @@ if [ "$NATIVE_WINDOWS_QEMU" -ne "1" ]; then
     -qmp unix:qmp-sock,server,nowait"
 fi
 
-if [ "$SERENITY_ARCH" = "aarch64" ]; then
-    SERENITY_KERNEL_AND_INITRD="
+SERENITY_KERNEL_AND_INITRD="
     -kernel Kernel/Kernel
     "
-else
-    SERENITY_KERNEL_AND_INITRD="
-    -kernel Kernel/Prekernel/Prekernel
-    -initrd Kernel/Kernel
-    "
-fi
 
 
 [ -z "$SERENITY_COMMON_QEMU_ARGS" ] && SERENITY_COMMON_QEMU_ARGS="