From 6698c4ab3f33b22ac32137e78e8b2e829b7c2bce Mon Sep 17 00:00:00 2001 From: karina Date: Sun, 26 Apr 2026 09:32:07 +0400 Subject: [PATCH] feat: kernel is now elf --- Bootloader/CMakeLists.txt | 4 +- Bootloader/Source/main.c | 98 +++++++++++++++---- Bootloader/Source/modules/elf/elf.h | 32 ++++++ .../Source/{ => modules}/uefi/efi_entry.c | 0 Bootloader/Source/{ => modules}/uefi/uefi.h | 2 + Kernel/CMakeLists.txt | 9 +- Kernel/justfile | 4 +- Kernel/linker.ld | 23 +++-- justfile | 7 +- 9 files changed, 137 insertions(+), 42 deletions(-) create mode 100644 Bootloader/Source/modules/elf/elf.h rename Bootloader/Source/{ => modules}/uefi/efi_entry.c (100%) rename Bootloader/Source/{ => modules}/uefi/uefi.h (99%) diff --git a/Bootloader/CMakeLists.txt b/Bootloader/CMakeLists.txt index d8ee154..2a6c1f0 100644 --- a/Bootloader/CMakeLists.txt +++ b/Bootloader/CMakeLists.txt @@ -9,13 +9,13 @@ set(UEFI_COMPILE_OPTIONS ) add_executable(BOOTAA64 - Source/uefi/efi_entry.c + Source/modules/uefi/efi_entry.c Source/main.c ) target_compile_options(BOOTAA64 PRIVATE ${UEFI_COMPILE_OPTIONS}) target_include_directories(BOOTAA64 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/Source - ${CMAKE_CURRENT_SOURCE_DIR}/Source/uefi + ${CMAKE_CURRENT_SOURCE_DIR}/Source/modules/uefi ) target_link_options(BOOTAA64 PRIVATE diff --git a/Bootloader/Source/main.c b/Bootloader/Source/main.c index 05a954f..edfa06f 100644 --- a/Bootloader/Source/main.c +++ b/Bootloader/Source/main.c @@ -1,10 +1,11 @@ -#include "uefi/uefi.h" +#include "modules/uefi/uefi.h" +#include "modules/elf/elf.h" #include "../../Common/bootinfo.h" #define PAGE_SIZE 0x1000 #define WSTR(str) ((wchar_t*)L##str) -static wchar_t* kernel_path = WSTR("ksOSKernel.bin"); +static wchar_t* kernel_path = WSTR("ksOSKernel.elf"); static efi_guid_t dtb_guid = { 0xb1b621d5, 0xf19c, 0x41a5, {0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0} }; @@ -13,6 +14,14 @@ static void print(const wchar_t* msg) { ST->ConOut->OutputString(ST->ConOut, (wchar_t*)msg); } +void* memset(void* destination, int value, uint64_t count) { + uint8_t* ptr = (uint8_t*)destination; + while (count--) { + *ptr++ = (uint8_t)value; + } + return destination; +} + static efi_status_t die(void) { while (1) { __asm__ volatile("wfi"); @@ -83,33 +92,73 @@ static efi_status_t read_file_info(efi_file_handle_t* file, efi_file_info_t** fi return file->GetInfo(file, &file_info_guid, &file_info_size, *file_info); } -static efi_status_t load_kernel(efi_file_handle_t* root, efi_physical_address_t* kernel_addr, uint64_t* kernel_size) { +static efi_status_t load_kernel(efi_file_handle_t* root, efi_physical_address_t* kernel_addr, uint64_t* kernel_size, efi_file_handle_t** out_handle) { efi_file_handle_t* kernel_file = NULL; - efi_file_info_t* kernel_info = NULL; efi_status_t status = root->Open(root, &kernel_file, kernel_path, EFI_FILE_MODE_READ, 0); - if (EFI_ERROR(status)) { - return status; - } + if (EFI_ERROR(status)) return status; + efi_file_info_t* kernel_info = NULL; status = read_file_info(kernel_file, &kernel_info); - if (EFI_ERROR(status)) { - return status; - } + if (EFI_ERROR(status)) return status; *kernel_size = kernel_info->FileSize; - - uintn_t bytes_to_read = (uintn_t)*kernel_size; uintn_t kernel_pages = (*kernel_size + PAGE_SIZE - 1) / PAGE_SIZE; - *kernel_addr = 0; status = gBS->AllocatePages(AllocateAnyPages, EfiLoaderData, kernel_pages, kernel_addr); - if (EFI_ERROR(status)) { - return status; + if (EFI_ERROR(status)) return status; + + uintn_t bytes_to_read = (uintn_t)*kernel_size; + status = kernel_file->Read(kernel_file, &bytes_to_read, (void*)*kernel_addr); + if (EFI_ERROR(status)) return status; + + *out_handle = kernel_file; + return EFI_SUCCESS; +} + +static efi_status_t parse_elf_headers(efi_physical_address_t kernel_addr) { + Elf64_Ehdr* elf_header = (Elf64_Ehdr*)kernel_addr; + + if (elf_header->e_ident[0] != 0x7f || elf_header->e_ident[1] != 'E' || + elf_header->e_ident[2] != 'L' || elf_header->e_ident[3] != 'F') { + return fail(WSTR("Invalid ELF header\r\n")); + } + if (elf_header->e_machine != 0xB7) { // AArch64 + return fail(WSTR("Invalid ELF machine\r\n")); } - status = kernel_file->Read(kernel_file, &bytes_to_read, (void*)*kernel_addr); - if (EFI_ERROR(status) || bytes_to_read != (uintn_t)*kernel_size) { - return EFI_LOAD_ERROR; + return EFI_SUCCESS; +} + +static efi_status_t load_elf_segments(efi_physical_address_t kernel_addr, efi_file_handle_t* kernel_file) { + Elf64_Ehdr* elf_header = (Elf64_Ehdr*)kernel_addr; + + for (int i = 0; i < elf_header->e_phnum; i++) { + Elf64_Phdr* phdr = (Elf64_Phdr*)(kernel_addr + elf_header->e_phoff + i * elf_header->e_phentsize); + + if (phdr->p_type != PT_LOAD) continue; + if (phdr->p_vaddr < 0x40000000) { + print(WSTR("Skipping low/weird segment\r\n")); + continue; + } + + uintn_t pages = (phdr->p_memsz + 0xFFF) / 0x1000; + efi_physical_address_t segment_addr = phdr->p_vaddr; + + efi_status_t status = gBS->AllocatePages(AllocateAddress, EfiLoaderData, pages, &segment_addr); + if (EFI_ERROR(status)) { + if (status == EFI_NOT_FOUND) print(WSTR(" (Range not in RAM) ")); + if (status == EFI_OUT_OF_RESOURCES) print(WSTR(" (Occupied) ")); + return fail(WSTR("Address conflict!\r\n")); + } + + memset((void*)segment_addr, 0, phdr->p_memsz); + kernel_file->SetPosition(kernel_file, phdr->p_offset); + + uintn_t size_to_read = phdr->p_filesz; + status = kernel_file->Read(kernel_file, &size_to_read, (void*)segment_addr); + if (EFI_ERROR(status) || size_to_read != phdr->p_filesz) { + return fail(WSTR("File read error\r\n")); + } } return EFI_SUCCESS; @@ -175,11 +224,20 @@ efi_status_t bootloader_main(void) { efi_physical_address_t kernel_addr = 0; uint64_t kernel_size = 0; - status = load_kernel(root, &kernel_addr, &kernel_size); + efi_file_handle_t* kernel_file = NULL; + status = load_kernel(root, &kernel_addr, &kernel_size, &kernel_file); if (EFI_ERROR(status)) { return fail(WSTR("Failed to load ksOSKernel.bin\r\n")); } + Elf64_Ehdr* elf_header = (Elf64_Ehdr*)kernel_addr; + + status = parse_elf_headers(kernel_addr); + if (EFI_ERROR(status)) return status; + + status = load_elf_segments(kernel_addr, kernel_file); + if (EFI_ERROR(status)) return status; + Bootinfo* boot_info = NULL; status = gBS->AllocatePool(EfiLoaderData, sizeof(Bootinfo), (void**)&boot_info); if (EFI_ERROR(status) || boot_info == NULL) { @@ -203,7 +261,7 @@ efi_status_t bootloader_main(void) { } typedef void (*kernel_entry_t)(Bootinfo*); - kernel_entry_t kernel_main = (kernel_entry_t)kernel_addr; + kernel_entry_t kernel_main = (kernel_entry_t)elf_header->e_entry; kernel_main(boot_info); return EFI_SUCCESS; diff --git a/Bootloader/Source/modules/elf/elf.h b/Bootloader/Source/modules/elf/elf.h new file mode 100644 index 0000000..2722c79 --- /dev/null +++ b/Bootloader/Source/modules/elf/elf.h @@ -0,0 +1,32 @@ +#pragma once +#include "../../modules/uefi/uefi.h" // IWYU pragma: keep + +typedef struct { + uint8_t e_ident[16]; + uint16_t e_type; + uint16_t e_machine; + uint32_t e_version; + uint64_t e_entry; + uint64_t e_phoff; + uint64_t e_shoff; + uint32_t e_flags; + uint16_t e_ehsize; + uint16_t e_phentsize; + uint16_t e_phnum; + uint16_t e_shentsize; + uint16_t e_shnum; + uint16_t e_shstrndx; +} Elf64_Ehdr; + +typedef struct { + uint32_t p_type; + uint32_t p_flags; + uint64_t p_offset; + uint64_t p_vaddr; + uint64_t p_paddr; + uint64_t p_filesz; + uint64_t p_memsz; + uint64_t p_align; +} Elf64_Phdr; + +#define PT_LOAD 1 \ No newline at end of file diff --git a/Bootloader/Source/uefi/efi_entry.c b/Bootloader/Source/modules/uefi/efi_entry.c similarity index 100% rename from Bootloader/Source/uefi/efi_entry.c rename to Bootloader/Source/modules/uefi/efi_entry.c diff --git a/Bootloader/Source/uefi/uefi.h b/Bootloader/Source/modules/uefi/uefi.h similarity index 99% rename from Bootloader/Source/uefi/uefi.h rename to Bootloader/Source/modules/uefi/uefi.h index f229ba1..8bbf190 100644 --- a/Bootloader/Source/uefi/uefi.h +++ b/Bootloader/Source/modules/uefi/uefi.h @@ -36,6 +36,8 @@ typedef uint16_t wchar_t; #define EFI_LOAD_ERROR EFIERR(1) #define EFI_UNSUPPORTED EFIERR(3) #define EFI_BUFFER_TOO_SMALL EFIERR(5) +#define EFI_OUT_OF_RESOURCES EFIERR(9) +#define EFI_NOT_FOUND EFIERR(14) #define EFI_ABORTED EFIERR(21) #define EFI_OPEN_PROTOCOL_GET_PROTOCOL 0x00000002 diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index caec459..4e24457 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -33,14 +33,11 @@ target_link_options(Kernel PRIVATE -no-pie -T "${CMAKE_CURRENT_SOURCE_DIR}/linker.ld" -z max-page-size=0x1000 + --image-base=0x40100000 + --no-dynamic-linker ) set_target_properties(Kernel PROPERTIES - OUTPUT_NAME "Kernel.elf" + OUTPUT_NAME "ksOSKernel.elf" RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" ) - -add_custom_command(TARGET Kernel POST_BUILD - COMMAND ${LLVM_OBJCOPY} -O binary ${CMAKE_BINARY_DIR}/Kernel.elf ${CMAKE_BINARY_DIR}/Kernel.bin - COMMENT "Generating ksOSKernel.bin from Kernel.elf" -) \ No newline at end of file diff --git a/Kernel/justfile b/Kernel/justfile index f82044a..ae01553 100644 --- a/Kernel/justfile +++ b/Kernel/justfile @@ -7,8 +7,8 @@ build: cmake --build {{TEMP_DIR}}/Kernel - cp {{TEMP_DIR}}/Kernel/Kernel.bin {{BUILD_DIR}}/Kernel/ksOSKernel.bin - @echo "✅ Kernel ready at: {{BUILD_DIR}}/Kernel/ksOSKernel.bin" + cp {{TEMP_DIR}}/Kernel/ksOSKernel.elf {{BUILD_DIR}}/Kernel/ksOSKernel.elf + @echo "✅ Kernel ready at: {{BUILD_DIR}}/Kernel/ksOSKernel.elf" clean: rm -rf {{TEMP_DIR}}/Kernel diff --git a/Kernel/linker.ld b/Kernel/linker.ld index 22e97ea..b793125 100644 --- a/Kernel/linker.ld +++ b/Kernel/linker.ld @@ -1,15 +1,20 @@ -ENTRY(_start) +PHDRS +{ + text PT_LOAD FLAGS(5); /* Read | Execute */ + data PT_LOAD FLAGS(6); /* Read | Write */ +} -SECTIONS { - . = 0; +SECTIONS +{ + . = 0x40100000; .text : { *(.text.boot) *(.text*) - } + } :text - .rodata : { *(.rodata*) } - .data : { *(.data*) } - .bss : { *(.bss*) *(COMMON) } - -} + .rodata : { *(.rodata*) } :text + + .data : { *(.data*) } :data + .bss : { *(.bss*) *(COMMON) } :data +} \ No newline at end of file diff --git a/justfile b/justfile index 91ee8d5..749656d 100644 --- a/justfile +++ b/justfile @@ -28,6 +28,7 @@ DISPLAY_FLAGS := if OS_NAME == "macos" { } ACCEL_INFO := if ACCEL == "" { "none (TCG)" } else { ACCEL } +RAM := "2G" export BUILD_DIR := justfile_directory() + "/.build" export TEMP_DIR := BUILD_DIR + "/temp" @@ -64,14 +65,14 @@ _prep: @mkfs.fat -F 32 {{IMG_FILE}} > /dev/null @mmd -i {{IMG_FILE}} ::/EFI ::/EFI/BOOT @mcopy -i {{IMG_FILE}} {{BOOT_BIN}} ::/EFI/BOOT/BOOTAA64.EFI - @mcopy -i {{IMG_FILE}} {{BUILD_DIR}}/Kernel/ksOSKernel.bin ::/ksOSKernel.bin + @mcopy -i {{IMG_FILE}} {{BUILD_DIR}}/Kernel/ksOSKernel.elf ::/ksOSKernel.elf @run: _image @echo "🚀 Launching (accel: {{ACCEL_INFO}})..." qemu-system-aarch64 {{ACCEL}} \ -machine virt,acpi=off \ -cpu {{CPU}} \ - -m 512M \ + -m {{RAM}} \ -device ramfb \ {{DISPLAY_FLAGS}} \ -drive if=pflash,format=raw,readonly=on,file={{OVMF_ARM}} \ @@ -85,7 +86,7 @@ _prep: qemu-system-aarch64 {{ACCEL}} \ -machine virt,acpi=off \ -cpu {{CPU}} \ - -m 512M \ + -m {{RAM}} \ -device ramfb \ {{DISPLAY_FLAGS}} \ -drive if=pflash,format=raw,readonly=on,file={{OVMF_ARM}} \