Better docs and structure
This commit is contained in:
112
main.c
112
main.c
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user