From f266dd7c8cdc3099c23cc033bc42834da746189f Mon Sep 17 00:00:00 2001 From: JimmyBinoculars Date: Thu, 26 Feb 2026 17:41:53 +0000 Subject: [PATCH] Loaded a kernel --- Makefile | 16 ++- boot_info.h | 19 ++++ kernel.c | 69 ++++++++++++ kernel.ld | 27 +++++ main.c | 313 +++++++++++++++++++++++++++++++++++++++------------- 5 files changed, 365 insertions(+), 79 deletions(-) create mode 100644 boot_info.h create mode 100644 kernel.c create mode 100644 kernel.ld diff --git a/Makefile b/Makefile index 762fbc5..7492b03 100644 --- a/Makefile +++ b/Makefile @@ -37,6 +37,9 @@ LIBS = -lefi -lgnuefi TARGET = BOOTX64.EFI TARGET_SO = bootx64.so OBJ = $(BUILD_DIR)/main.o +KERNEL_TARGET = kernel.elf +KERNEL_OBJ = $(BUILD_DIR)/kernel.o +KERNEL_LD = kernel.ld # QEMU settings QEMU = qemu-system-x86_64 @@ -79,7 +82,7 @@ QEMU_FLAGS = -machine q35 \ .PHONY: all clean run setup install-deps # Default target -all: setup $(EFI_DIR)/$(TARGET) +all: setup $(EFI_DIR)/$(TARGET) $(BUILD_DIR)/$(KERNEL_TARGET) # Create necessary directories setup: @@ -92,6 +95,17 @@ $(BUILD_DIR)/%.o: $(SRC_DIR)/%.c @echo "Compiling $<..." $(CC) $(CFLAGS) -c $< -o $@ +# Compile kernel source +$(KERNEL_OBJ): $(SRC_DIR)/kernel.c + @echo "Compiling kernel.c..." + $(CC) -ffreestanding -fno-stack-protector -fno-pic -fshort-wchar \ + -mno-red-zone -Wall -Wextra $(EFI_INCLUDES) -c $< -o $@ + +# Link kernel ELF +$(BUILD_DIR)/$(KERNEL_TARGET): $(KERNEL_OBJ) $(KERNEL_LD) + @echo "Linking kernel ELF..." + $(LD) -nostdlib -T $(KERNEL_LD) $(KERNEL_OBJ) -o $@ + # Link to create shared object $(BUILD_DIR)/$(TARGET_SO): $(OBJ) @echo "Linking $@..." diff --git a/boot_info.h b/boot_info.h new file mode 100644 index 0000000..1c44c1f --- /dev/null +++ b/boot_info.h @@ -0,0 +1,19 @@ +#ifndef BOOT_INFO_H +#define BOOT_INFO_H + +#include + +typedef UINTN (*KernelPrintFn)(const CHAR16 *Format, ...); + +typedef struct { + EFI_SYSTEM_TABLE *SystemTable; + KernelPrintFn print; + EFI_STATUS (*clear_screen)(void); + EFI_STATUS (*set_attribute)(UINTN Attribute); + EFI_STATUS (*read_key)(EFI_INPUT_KEY *Key); + void (*shutdown)(void); +} BootInfo; + +typedef void (*KernelEntryFn)(BootInfo *Boot); + +#endif diff --git a/kernel.c b/kernel.c new file mode 100644 index 0000000..bb2cbc3 --- /dev/null +++ b/kernel.c @@ -0,0 +1,69 @@ +#include + +#include "boot_info.h" + +void kmain(BootInfo *Boot) +{ + EFI_INPUT_KEY Key; + + Boot->clear_screen(); + Boot->set_attribute(EFI_TEXT_ATTR(EFI_LIGHTGREEN, EFI_BLACK)); + + Boot->print(L"================================================\n\r"); + Boot->print(L" Welcome to Simple UEFI Operating System!\n\r"); + Boot->print(L"================================================\n\r"); + Boot->print(L"\n\r"); + Boot->print(L"System Information:\n\r"); + Boot->print(L" UEFI Firmware Vendor: %s\n\r", Boot->SystemTable->FirmwareVendor); + Boot->print(L" UEFI Firmware Revision: %d.%d\n\r", + Boot->SystemTable->FirmwareRevision >> 16, + Boot->SystemTable->FirmwareRevision & 0xFFFF); + Boot->print(L"\n\r"); + + Boot->print(L"Available Services:\n\r"); + Boot->print(L" - Console Input/Output: Active\n\r"); + Boot->print(L" - Runtime Services: Active\n\r"); + Boot->print(L" - Boot Services: Active\n\r"); + Boot->print(L"\n\r"); + + Boot->print(L"Commands:\n\r"); + Boot->print(L" 'h' - Display help\n\r"); + Boot->print(L" 'i' - Display system info\n\r"); + Boot->print(L" 'c' - Clear screen\n\r"); + Boot->print(L" 'q' - Shutdown\n\r"); + Boot->print(L"\n\r"); + Boot->print(L"Press a key to start...\n\r"); + + while (TRUE) { + if (EFI_ERROR(Boot->read_key(&Key))) { + continue; + } + + if (Key.UnicodeChar == L'q' || Key.UnicodeChar == L'Q') { + Boot->print(L"\n\rShutting down...\n\r"); + Boot->shutdown(); + } else if (Key.UnicodeChar == L'h' || Key.UnicodeChar == L'H') { + Boot->print(L"\n\r=== Help ===\n\r"); + Boot->print(L"This is a minimal UEFI operating system.\n\r"); + Boot->print(L"It demonstrates basic UEFI functionality.\n\r"); + Boot->print(L"\n\r"); + } else if (Key.UnicodeChar == L'i' || Key.UnicodeChar == L'I') { + Boot->print(L"\n\r=== System Info ===\n\r"); + Boot->print(L"Firmware Vendor: %s\n\r", Boot->SystemTable->FirmwareVendor); + Boot->print(L"Firmware Revision: %d.%d\n\r", + Boot->SystemTable->FirmwareRevision >> 16, + Boot->SystemTable->FirmwareRevision & 0xFFFF); + Boot->print(L"UEFI Specification: %d.%d\n\r", + Boot->SystemTable->Hdr.Revision >> 16, + Boot->SystemTable->Hdr.Revision & 0xFFFF); + Boot->print(L"\n\r"); + } else if (Key.UnicodeChar == L'c' || Key.UnicodeChar == L'C') { + Boot->clear_screen(); + Boot->print(L"Screen cleared. Press 'h' for help.\n\r"); + } else if (Key.UnicodeChar >= 32 && Key.UnicodeChar < 127) { + Boot->print(L"%c", Key.UnicodeChar); + } else if (Key.UnicodeChar == L'\r') { + Boot->print(L"\n\r> "); + } + } +} diff --git a/kernel.ld b/kernel.ld new file mode 100644 index 0000000..66829c4 --- /dev/null +++ b/kernel.ld @@ -0,0 +1,27 @@ +ENTRY(kmain) + +SECTIONS +{ + . = 0x100000; + + .text : ALIGN(0x1000) + { + *(.text*) + } + + .rodata : ALIGN(0x1000) + { + *(.rodata*) + } + + .data : ALIGN(0x1000) + { + *(.data*) + } + + .bss : ALIGN(0x1000) + { + *(COMMON) + *(.bss*) + } +} diff --git a/main.c b/main.c index 46e9d8c..d575ddb 100644 --- a/main.c +++ b/main.c @@ -1,93 +1,250 @@ #include #include +#include "boot_info.h" + +#define ELF_MAGIC 0x464c457f +#define PT_LOAD 1 + +typedef struct { + UINT32 e_magic; + UINT8 e_class; + UINT8 e_data; + UINT8 e_version; + UINT8 e_osabi; + UINT8 e_abiversion; + UINT8 e_pad[7]; + UINT16 e_type; + UINT16 e_machine; + UINT32 e_version2; + UINT64 e_entry; + UINT64 e_phoff; + UINT64 e_shoff; + UINT32 e_flags; + UINT16 e_ehsize; + UINT16 e_phentsize; + UINT16 e_phnum; + UINT16 e_shentsize; + UINT16 e_shnum; + UINT16 e_shstrndx; +} Elf64_Ehdr; + +typedef struct { + UINT32 p_type; + UINT32 p_flags; + UINT64 p_offset; + UINT64 p_vaddr; + UINT64 p_paddr; + UINT64 p_filesz; + UINT64 p_memsz; + UINT64 p_align; +} Elf64_Phdr; + +static EFI_STATUS open_root_volume(EFI_HANDLE ImageHandle, EFI_FILE_PROTOCOL **Root) +{ + EFI_STATUS Status; + EFI_LOADED_IMAGE *LoadedImage = NULL; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileSystem = NULL; + + Status = uefi_call_wrapper(BS->HandleProtocol, 3, ImageHandle, + &gEfiLoadedImageProtocolGuid, (VOID **)&LoadedImage); + if (EFI_ERROR(Status)) { + return Status; + } + + Status = uefi_call_wrapper(BS->HandleProtocol, 3, LoadedImage->DeviceHandle, + &gEfiSimpleFileSystemProtocolGuid, (VOID **)&FileSystem); + if (EFI_ERROR(Status)) { + return Status; + } + + return uefi_call_wrapper(FileSystem->OpenVolume, 2, FileSystem, Root); +} + +static EFI_STATUS read_file_to_buffer(EFI_HANDLE ImageHandle, CHAR16 *Path, + VOID **Buffer, UINTN *Size) +{ + EFI_STATUS Status; + EFI_FILE_PROTOCOL *Root = NULL; + EFI_FILE_PROTOCOL *File = NULL; + EFI_FILE_INFO *Info = NULL; + UINTN InfoSize = 0; + UINTN FileSize = 0; + + Status = open_root_volume(ImageHandle, &Root); + if (EFI_ERROR(Status)) { + return Status; + } + + Status = uefi_call_wrapper(Root->Open, 5, Root, &File, Path, + EFI_FILE_MODE_READ, 0); + if (EFI_ERROR(Status)) { + return Status; + } + + Status = uefi_call_wrapper(File->GetInfo, 4, File, &gEfiFileInfoGuid, + &InfoSize, NULL); + if (Status != EFI_BUFFER_TOO_SMALL) { + uefi_call_wrapper(File->Close, 1, File); + return Status; + } + + Status = uefi_call_wrapper(BS->AllocatePool, 3, EfiLoaderData, + InfoSize, (VOID **)&Info); + if (EFI_ERROR(Status)) { + uefi_call_wrapper(File->Close, 1, File); + return Status; + } + + Status = uefi_call_wrapper(File->GetInfo, 4, File, &gEfiFileInfoGuid, + &InfoSize, Info); + if (EFI_ERROR(Status)) { + uefi_call_wrapper(BS->FreePool, 1, Info); + uefi_call_wrapper(File->Close, 1, File); + return Status; + } + + FileSize = (UINTN)Info->FileSize; + Status = uefi_call_wrapper(BS->AllocatePool, 3, EfiLoaderData, + FileSize, Buffer); + if (EFI_ERROR(Status)) { + uefi_call_wrapper(BS->FreePool, 1, Info); + uefi_call_wrapper(File->Close, 1, File); + return Status; + } + + Status = uefi_call_wrapper(File->Read, 3, File, &FileSize, *Buffer); + if (EFI_ERROR(Status)) { + uefi_call_wrapper(BS->FreePool, 1, Info); + uefi_call_wrapper(File->Close, 1, File); + return Status; + } + + uefi_call_wrapper(BS->FreePool, 1, Info); + uefi_call_wrapper(File->Close, 1, File); + + *Size = FileSize; + return EFI_SUCCESS; +} + +static EFI_STATUS load_elf_kernel(VOID *Image, UINTN Size, UINT64 *EntryOut) +{ + Elf64_Ehdr *Ehdr = (Elf64_Ehdr *)Image; + Elf64_Phdr *Phdr = NULL; + UINT16 Index = 0; + + if (Size < sizeof(Elf64_Ehdr)) { + return EFI_LOAD_ERROR; + } + + if (Ehdr->e_magic != ELF_MAGIC || Ehdr->e_class != 2 || Ehdr->e_data != 1) { + return EFI_LOAD_ERROR; + } + + if ((Ehdr->e_phoff + (UINT64)Ehdr->e_phnum * Ehdr->e_phentsize) > Size) { + return EFI_LOAD_ERROR; + } + + Phdr = (Elf64_Phdr *)((UINT8 *)Image + Ehdr->e_phoff); + + for (Index = 0; Index < Ehdr->e_phnum; Index++) { + Elf64_Phdr *Segment = (Elf64_Phdr *)((UINT8 *)Phdr + (Index * Ehdr->e_phentsize)); + UINT64 SegmentStart = 0; + UINT64 SegmentEnd = 0; + UINT64 SegmentPages = 0; + EFI_PHYSICAL_ADDRESS Address = 0; + + if (Segment->p_type != PT_LOAD || Segment->p_memsz == 0) { + continue; + } + + if ((Segment->p_offset + Segment->p_filesz) > Size) { + return EFI_LOAD_ERROR; + } + + SegmentStart = Segment->p_vaddr & ~0xFFFULL; + SegmentEnd = (Segment->p_vaddr + Segment->p_memsz + 0xFFFULL) & ~0xFFFULL; + SegmentPages = (SegmentEnd - SegmentStart) >> 12; + + Address = (EFI_PHYSICAL_ADDRESS)SegmentStart; + if (EFI_ERROR(uefi_call_wrapper(BS->AllocatePages, 4, AllocateAddress, + EfiLoaderData, SegmentPages, &Address))) { + return EFI_OUT_OF_RESOURCES; + } + + CopyMem((VOID *)(UINTN)Segment->p_vaddr, + (UINT8 *)Image + Segment->p_offset, + (UINTN)Segment->p_filesz); + if (Segment->p_memsz > Segment->p_filesz) { + SetMem((VOID *)(UINTN)(Segment->p_vaddr + Segment->p_filesz), + (UINTN)(Segment->p_memsz - Segment->p_filesz), 0); + } + } + + *EntryOut = Ehdr->e_entry; + return EFI_SUCCESS; +} + +static EFI_STATUS loader_clear_screen(void) +{ + return uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut); +} + +static EFI_STATUS loader_set_attribute(UINTN Attribute) +{ + return uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, Attribute); +} + +static EFI_STATUS loader_read_key(EFI_INPUT_KEY *Key) +{ + UINTN Index = 0; + uefi_call_wrapper(BS->WaitForEvent, 3, 1, &ST->ConIn->WaitForKey, &Index); + return uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2, ST->ConIn, Key); +} + +static void loader_shutdown(void) +{ + uefi_call_wrapper(RT->ResetSystem, 4, EfiResetShutdown, EFI_SUCCESS, 0, NULL); +} + EFI_STATUS EFIAPI efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) { EFI_STATUS Status; - EFI_INPUT_KEY Key; + VOID *KernelImage = NULL; + UINTN KernelSize = 0; + UINT64 KernelEntry = 0; + BootInfo Boot; + KernelEntryFn EntryFn = NULL; // Initialize the GNU-EFI library InitializeLib(ImageHandle, SystemTable); - // Clear the screen - uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut); - - // Set text color to light green - uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, - EFI_TEXT_ATTR(EFI_LIGHTGREEN, EFI_BLACK)); - - // Print welcome messages - Print(L"================================================\n\r"); - Print(L" Welcome to Simple UEFI Operating System!\n\r"); - Print(L"================================================\n\r"); - Print(L"\n\r"); - Print(L"System Information:\n\r"); - Print(L" UEFI Firmware Vendor: %s\n\r", ST->FirmwareVendor); - Print(L" UEFI Firmware Revision: %d.%d\n\r", - ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xFFFF); - Print(L"\n\r"); - - // Display some runtime services info - Print(L"Available Services:\n\r"); - Print(L" - Console Input/Output: Active\n\r"); - Print(L" - Runtime Services: Active\n\r"); - Print(L" - Boot Services: Active\n\r"); - Print(L"\n\r"); - - // Simple command loop - Print(L"Commands:\n\r"); - Print(L" 'h' - Display help\n\r"); - Print(L" 'i' - Display system info\n\r"); - Print(L" 'c' - Clear screen\n\r"); - Print(L" 'q' - Shutdown\n\r"); - Print(L"\n\r"); - Print(L"Press a key to start...\n\r"); - - while (TRUE) { - // Wait for key press - Status = uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2, - ST->ConIn, &Key); - - if (EFI_ERROR(Status)) { - continue; - } - - // Handle commands - if (Key.UnicodeChar == L'q' || Key.UnicodeChar == L'Q') { - Print(L"\n\rShutting down...\n\r"); - // Reset the system - uefi_call_wrapper(RT->ResetSystem, 4, EfiResetShutdown, - EFI_SUCCESS, 0, NULL); - } - else if (Key.UnicodeChar == L'h' || Key.UnicodeChar == L'H') { - Print(L"\n\r=== Help ===\n\r"); - Print(L"This is a minimal UEFI operating system.\n\r"); - Print(L"It demonstrates basic UEFI functionality.\n\r"); - Print(L"\n\r"); - } - else if (Key.UnicodeChar == L'i' || Key.UnicodeChar == L'I') { - Print(L"\n\r=== System Info ===\n\r"); - Print(L"Firmware Vendor: %s\n\r", ST->FirmwareVendor); - Print(L"Firmware Revision: %d.%d\n\r", - ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xFFFF); - Print(L"UEFI Specification: %d.%d\n\r", - ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xFFFF); - Print(L"\n\r"); - } - else if (Key.UnicodeChar == L'c' || Key.UnicodeChar == L'C') { - uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut); - Print(L"Screen cleared. Press 'h' for help.\n\r"); - } - else if (Key.UnicodeChar >= 32 && Key.UnicodeChar < 127) { - // Echo printable characters - Print(L"%c", Key.UnicodeChar); - } - else if (Key.UnicodeChar == L'\r') { - Print(L"\n\r> "); - } + Print(L"Loading kernel...\n\r"); + + Status = read_file_to_buffer(ImageHandle, L"\\kernel.elf", &KernelImage, &KernelSize); + if (EFI_ERROR(Status)) { + Print(L"Failed to read kernel.elf: %r\n\r", Status); + return Status; } - + + Status = load_elf_kernel(KernelImage, KernelSize, &KernelEntry); + if (EFI_ERROR(Status)) { + Print(L"Failed to load kernel.elf: %r\n\r", Status); + return Status; + } + + Boot.SystemTable = ST; + Boot.print = Print; + Boot.clear_screen = loader_clear_screen; + Boot.set_attribute = loader_set_attribute; + Boot.read_key = loader_read_key; + Boot.shutdown = loader_shutdown; + + EntryFn = (KernelEntryFn)(UINTN)KernelEntry; + EntryFn(&Boot); + + Print(L"Kernel returned. Halting.\n\r"); return EFI_SUCCESS; }