Better docs and structure

This commit is contained in:
2026-02-26 21:33:16 +00:00
parent d449150169
commit 13a281fa4f
18 changed files with 892 additions and 387 deletions

112
main.c
View File

@@ -1,45 +1,70 @@
/*
* main.c UEFI boot loader.
*
* This is the first code that runs. efi_main() is called by UEFI
* firmware via the PE32+ entry point. It:
* 1. Reads kernel.elf from the EFI System Partition
* 2. Parses the ELF64 headers and maps PT_LOAD segments into memory
* 3. Populates a BootInfo struct with UEFI service wrappers
* 4. Jumps to the kernel entry point (kmain)
*/
#include <efi.h>
#include <efilib.h>
#include "boot_info.h"
#define ELF_MAGIC 0x464c457f
#define PT_LOAD 1
/* ================================================================
* ELF64 constants and types
* ================================================================ */
#define ELF_MAGIC 0x464c457f /* "\x7fELF" as a little-endian UINT32 */
#define PT_LOAD 1 /* loadable program segment */
/* Minimal ELF64 file header (enough to locate program headers). */
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_magic; /* must be ELF_MAGIC */
UINT8 e_class; /* 2 = 64-bit */
UINT8 e_data; /* 1 = little-endian */
UINT8 e_version;
UINT8 e_osabi;
UINT8 e_abiversion;
UINT8 e_pad[7];
UINT16 e_type; /* ET_EXEC = 2 */
UINT16 e_machine; /* EM_X86_64 = 62 */
UINT32 e_version2;
UINT64 e_entry;
UINT64 e_phoff;
UINT64 e_entry; /* virtual address of entry point */
UINT64 e_phoff; /* file offset to program header table */
UINT64 e_shoff;
UINT32 e_flags;
UINT16 e_ehsize;
UINT16 e_phentsize;
UINT16 e_phnum;
UINT16 e_phentsize; /* size of one program header entry */
UINT16 e_phnum; /* number of program header entries */
UINT16 e_shentsize;
UINT16 e_shnum;
UINT16 e_shstrndx;
} Elf64_Ehdr;
/* ELF64 program header (describes one segment). */
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;
UINT32 p_type; /* segment type (PT_LOAD, etc.) */
UINT32 p_flags; /* segment flags (R/W/X) */
UINT64 p_offset; /* file offset of segment data */
UINT64 p_vaddr; /* virtual address to map at */
UINT64 p_paddr; /* physical address (usually == vaddr) */
UINT64 p_filesz; /* bytes of segment data in file */
UINT64 p_memsz; /* total bytes in memory (>= filesz) */
UINT64 p_align; /* alignment requirement */
} Elf64_Phdr;
/* ================================================================
* EFI file-system helpers
* ================================================================ */
/*
* Open the root directory of the volume from which this loader was
* loaded (i.e. the EFI System Partition).
*/
static EFI_STATUS open_root_volume(EFI_HANDLE ImageHandle, EFI_FILE_PROTOCOL **Root)
{
EFI_STATUS Status;
@@ -61,6 +86,10 @@ static EFI_STATUS open_root_volume(EFI_HANDLE ImageHandle, EFI_FILE_PROTOCOL **R
return uefi_call_wrapper(FileSystem->OpenVolume, 2, FileSystem, Root);
}
/*
* Read an entire file from the EFI System Partition into a pool buffer.
* Caller must free *Buffer with BS->FreePool() when done.
*/
static EFI_STATUS read_file_to_buffer(EFI_HANDLE ImageHandle, CHAR16 *Path,
VOID **Buffer, UINTN *Size)
{
@@ -127,6 +156,15 @@ static EFI_STATUS read_file_to_buffer(EFI_HANDLE ImageHandle, CHAR16 *Path,
return EFI_SUCCESS;
}
/* ================================================================
* ELF64 kernel loader
* ================================================================ */
/*
* Parse an ELF64 image in memory and load all PT_LOAD segments to
* their specified virtual (== physical) addresses. On success,
* *EntryOut is set to the kernel entry point.
*/
static EFI_STATUS load_elf_kernel(VOID *Image, UINTN Size, UINT64 *EntryOut)
{
Elf64_Ehdr *Ehdr = (Elf64_Ehdr *)Image;
@@ -185,6 +223,10 @@ static EFI_STATUS load_elf_kernel(VOID *Image, UINTN Size, UINT64 *EntryOut)
return EFI_SUCCESS;
}
/* ================================================================
* UEFI service wrappers (passed to the kernel via BootInfo)
* ================================================================ */
static EFI_STATUS loader_clear_screen(void)
{
return uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
@@ -223,6 +265,10 @@ static EFI_STATUS loader_free_pages(EFI_PHYSICAL_ADDRESS addr, UINTN pages)
return uefi_call_wrapper(BS->FreePages, 2, addr, pages);
}
/* ================================================================
* UEFI application entry point
* ================================================================ */
EFI_STATUS
EFIAPI
efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
@@ -233,10 +279,10 @@ efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
UINT64 KernelEntry = 0;
BootInfo Boot;
KernelEntryFn EntryFn = NULL;
// Initialize the GNU-EFI library
/* Initialise the GNU-EFI library */
InitializeLib(ImageHandle, SystemTable);
Print(L"Loading kernel...\n\r");
Status = read_file_to_buffer(ImageHandle, L"\\kernel.elf", &KernelImage, &KernelSize);
@@ -251,16 +297,18 @@ efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
return Status;
}
Boot.SystemTable = ST;
Boot.print = Print;
/* Populate the BootInfo struct with UEFI service wrappers */
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.read_key = loader_read_key;
Boot.try_read_key = loader_try_read_key;
Boot.shutdown = loader_shutdown;
Boot.alloc_pages = loader_alloc_pages;
Boot.free_pages = loader_free_pages;
Boot.shutdown = loader_shutdown;
Boot.alloc_pages = loader_alloc_pages;
Boot.free_pages = loader_free_pages;
/* Jump to the kernel this should not return */
EntryFn = (KernelEntryFn)(UINTN)KernelEntry;
EntryFn(&Boot);