boot/efi/arch/amd64/asm.S

.intel_syntax noprefix
.global trampoline
trampoline:
cli
mov rax, rdi           // New cr3 in rdi

mov rsp, rsi           // New stack in rsi
mov rdi, rdx           // Boot info in rdx

mov cr3, rax           // Switch to new page table

freeze:
hlt
jmp freeze

jmp rcx                // Kernel entry in rcx

.global enable_nxe
enable_nxe:
mov ecx, 0xC0000080    // EFER MSR
rdmsr
bts eax, 11            // Set NXE (bit 11) (No execute enable)
wrmsr
ret
.global disable_interrupts
disable_interrupts:
cli
ret

Bash/make output

root ➜ /workspaces/os0x (main) $ make clean run
cd kernel && make clean
make[1]: Entering directory '/workspaces/os0x/kernel'
rm -f -r obj
rm -f -r bin
make[1]: Leaving directory '/workspaces/os0x/kernel'
cd boot/efi && make clean
make[1]: Entering directory '/workspaces/os0x/boot/efi'
rm -f -r obj
rm -f -r bin
make[1]: Leaving directory '/workspaces/os0x/boot/efi'
rm -f disk.img
rm -f kernel/obj/initrd
cd boot/efi && make
make[1]: Entering directory '/workspaces/os0x/boot/efi'
clang -target x86_64-unknown-linux-gnu -ffreestanding -fno-stack-protector -mno-red-zone -fshort-wchar -nostdlib -fvisibility=hidden -c -MMD -MP -DQUIET -I../../include -I../include -I/usr/local/include/efi -I/usr/local/include/efi/x86_64 -Iinclude -I../../third_party/include main.c -o obj/main.o
clang -target x86_64-unknown-linux-gnu -ffreestanding -fno-stack-protector -mno-red-zone -fshort-wchar -nostdlib -fvisibility=hidden -c -MMD -MP -DQUIET -I../../include -I../include -I/usr/local/include/efi -I/usr/local/include/efi/x86_64 -Iinclude -I../../third_party/include virtual.c -o obj/virtual.o
x86_64-linux-gnu-gcc -ffreestanding -m64 -c -MMD -MP -o obj/asm.o arch/amd64/asm.S
x86_64-linux-gnu-ld \\
-nostdlib -znocombreloc -shared -Bsymbolic \\
-T /usr/local/lib/elf_x86_64_efi.lds \\
-L/usr/local/lib \\
/usr/local/lib/crt0-efi-x86_64.o obj/main.o obj/virtual.o obj/asm.o -lefi -lgnuefi -o obj/main.so
x86_64-linux-gnu-ld: warning: obj/asm.o: missing .note.GNU-stack section implies executable stack
x86_64-linux-gnu-ld: NOTE: This behaviour is deprecated and will be removed in a future version of the linker
x86_64-linux-gnu-objcopy -j .text -j .sdata -j .data \\
-j .dynamic -j .rodata \\
-j .rel* -j .rela* \\
--target=efi-app-x86_64 \\
obj/main.so bin/BOOTX64.EFI
make[1]: Leaving directory '/workspaces/os0x/boot/efi'
cd kernel && make
make[1]: Entering directory '/workspaces/os0x/kernel'
clang -target x86_64-unknown-elf -ffreestanding -nostdlib -fno-builtin -fno-pic -c -MMD -MP  -I../include -I../boot/include -I/usr/local/include/efi -I/usr/local/include/efi/x86_64 -Iinclude uefi.c -o obj/uefi.o
clang -target x86_64-unknown-elf -ffreestanding -nostdlib -fno-builtin -fno-pic -c -MMD -MP  -I../include -I../boot/include -I/usr/local/include/efi -I/usr/local/include/efi/x86_64 -Iinclude main.c -o obj/main.o
x86_64-linux-gnu-gcc -ffreestanding -m64 -c -MMD -MP -o obj/asm.o arch/amd64/asm.S
clang -target x86_64-unknown-elf -ffreestanding -nostdlib -fno-builtin -fno-pic -c -MMD -MP  -I../include -I../boot/include -I/usr/local/include/efi -I/usr/local/include/efi/x86_64 -Iinclude lib/string.c -o obj/lib/string.o
x86_64-linux-gnu-ld -nostdlib -z max-page-size=0x1000 -z noexecstack \\
-T link.ld -o bin/kernel.elf obj/**/*.o
x86_64-linux-gnu-ld: warning: cannot find entry symbol kernel_boot; defaulting to ffffff0000000000
make[1]: Leaving directory '/workspaces/os0x/kernel'
mkdir -p kernel/obj/initrd
rsync -a --delete kernel/bin/kernel.elf kernel/obj/initrd/
cd kernel/obj/initrd && find . | cpio -o --format=newc > ../initrd.img
10 blocks
mv kernel/obj/initrd.img boot/efi/bin/
qemu-img create -f raw disk.img 64M
Formatting 'disk.img', fmt=raw size=67108864
mkfs.fat -F 32 disk.img
mkfs.fat 4.2 (2021-01-31)
mmd -i disk.img ::/EFI
mmd -i disk.img ::/EFI/BOOT
mcopy -i disk.img boot/efi/bin/BOOTX64.EFI ::/EFI/BOOT/
mcopy -i disk.img boot/efi/bin/initrd.img ::/
qemu-system-x86_64 -m 512M -drive if=pflash,format=raw,readonly=on,file=/usr/share/OVMF/OVMF_CODE_4M.fd -drive file=disk.img,format=raw,if=virtio -echr 0x14 -vnc :1,password=off -nographic

Qemu/loader output

[W][07736.250876] pw.conf      | [          conf.c: 1031 try_load_conf()] can't load config client.conf: No such file or directory
[E][07736.250888] pw.conf      | [          conf.c: 1060 pw_conf_load_conf_for_context()] can't load config client.conf: No such file or directory
BdsDxe: loading Boot0001 "UEFI Non-Block Boot Device" from PciRoot(0x0)/Pci(0x4,0x0)
BdsDxe: starting Boot0001 "UEFI Non-Block Boot Device" from PciRoot(0x0)/Pci(0x4,0x0)
os0x, an experimental operating system
Copyright (c) 2025 Josh Wyant

Press C-t x in the terminal to exit Qemu monitor.

Loading initrd.img...
Looking for kernel in initrd.img...
Kernel found.
Loading the kernel...
Measuring kernel size...
Section 0xFFFFFF0000000000 has 1 pages.
Total pages: 1
Creating page tables...
Allocating top level page table...
New page table physical address: 0x1DF43000
Cleared the page table.
Mapping the page table into itself...
Mapping page for virtual address 0xFFFFFFFFFFFFF000...
Page table level 4 @ 0x1DF43000, index 0x1FF
Allocated physical page 0x1DE4C000, entry 0x800000001DE4C003
Page table level 3 @ 0x1DE4C000, index 0x1FF
Allocated physical page 0x1DE4B000, entry 0x800000001DE4B003
Page table level 2 @ 0x1DE4B000, index 0x1FF
Allocated physical page 0x1DE4A000, entry 0x800000001DE4A003
Page table level 1, index 0x1FF
New entry: 0x800000001DF43003 P W NX
First bytes: 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0
Page tables created.
Mapping virtual address space...
Mapping in the kernel...
Kernel base:  0xFFFFFF0000000000
Kernel entry: 0xFFFFFF0000000000
Kernel code pages: 1
Section       0xFFFFFF0000000000:
Allocating to 0xFFFFFF0000000000
Creating 1 new pages...
Created 1 new pages at 0x1DE49000. Mapping them in...
Page 1 of 1...
Mapping page for virtual address 0xFFFFFF0000000000...
Page table level 4 @ 0x1DF43000, index 0x1FE
Allocated physical page 0x1DE48000, entry 0x800000001DE48003
Page table level 3 @ 0x1DE48000, index 0x0
Allocated physical page 0x1DE47000, entry 0x800000001DE47003
Page table level 2 @ 0x1DE47000, index 0x0
Allocated physical page 0x1DE46000, entry 0x800000001DE46003
Page table level 1, index 0x0
New entry: 0x1DE49001 P
First bytes: 0xAF 0xAF 0xAF 0xAF 0xAF 0xAF 0xAF 0xAF
Allocated to physical address @ 1 pages: 0x1DE49000
Copied 0x66 bytes
Memsize is 0x66 bytes, clearing 0x0 additional bytes
Entry for kernel (0xFFFFFF0000000000): 0x1DE49001
First bytes: 0x55 0x48 0x89 0xE5 0x48 0x89 0x7D 0xF8
Entry for kernel entry (0xFFFFFF0000000000): 0x1DE49001
First bytes: 0x55 0x48 0x89 0xE5 0x48 0x89 0x7D 0xF8
Mapping in 64kb stacks for 1 CPUs...
Stack pointer: 0xFFFFFF0000012000
Stack 1 ========
(Guard page: 0xFFFFFF0000001000)
Allocating 16 pages for stack at 0xFFFFFF0000002000
Creating 16 new pages...
Created 16 new pages at 0x1DE12000. Mapping them in...
Page 1 of 16...
Mapping page for virtual address 0xFFFFFF0000002000...
Page table level 4 @ 0x1DF43000, index 0x1FE
Page table level 3 @ 0x1DE48000, index 0x0
Page table level 2 @ 0x1DE47000, index 0x0
Page table level 1, index 0x2
New entry: 0x800000001DE12003 P W NX
First bytes: 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0
…
Page 16 of 16...
Mapping page for virtual address 0xFFFFFF0000011000...
Page table level 4 @ 0x1DF43000, index 0x1FE
Page table level 3 @ 0x1DE48000, index 0x0
Page table level 2 @ 0x1DE47000, index 0x0
Page table level 1, index 0x11
New entry: 0x800000001DE21003 P W NX
First bytes: 0xAF 0xAF 0xAF 0xAF 0xAF 0xAF 0xAF 0xAF
Physical address of stack: 0x1DE12000
Entry for (ss:esp - 8) (0xFFFFFF0000011FF8): 0x800000001DE21003
First bytes: 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0
Mapping in 1000 frame buffer pages from 0x80000000 (phys) to 0xFFFFFF0000012000 (virt)...
Mapped in 1000 frame buffer pages from 0x80000000 (phys) to 0xFFFFFF0000012000 (virt).
Entry for frame buffer (0xFFFFFF0000012000): 0x8000000080000003
First bytes: 0x25 0x18 0x18 0x0 0x25 0x18 0x18 0x0
Mapping in initrd.img, 2 pages at 0xFFFFFF00003FA000
Page 1 of 2...
Mapping page for virtual address 0xFFFFFF00003FA000...
Page table level 4 @ 0x1DF43000, index 0x1FE
Page table level 3 @ 0x1DE48000, index 0x0
Page table level 2 @ 0x1DE47000, index 0x1
Page table level 1, index 0x1FA
New entry: 0x800000001DE4D003 P W NX
First bytes: 0x30 0x37 0x30 0x37 0x30 0x31 0x30 0x30
Page 2 of 2...
Mapping page for virtual address 0xFFFFFF00003FB000...
Page table level 4 @ 0x1DF43000, index 0x1FE
Page table level 3 @ 0x1DE48000, index 0x0
Page table level 2 @ 0x1DE47000, index 0x1
Page table level 1, index 0x1FB
New entry: 0x800000001DE4E003 P W NX
First bytes: 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0
Entry for initrd (0xFFFFFF00003FA000): 0x800000001DE4D003
First bytes: 0x30 0x37 0x30 0x37 0x30 0x31 0x30 0x30
Getting temporary memory map...
Memory map size: 0x19E0, descriptor size: 0x30, version: 1
Mapping in loader data section 0x1DE0F000 with 19 pages (identity mapped: 0x0)...
Page 1 of 19...
Mapping page for virtual address 0x1DE0F000...
Page table level 4 @ 0x1DF43000, index 0x0
Allocated physical page 0x1DE0E000, entry 0x800000001DE0E003
Page table level 3 @ 0x1DE0E000, index 0x0
Allocated physical page 0x1DE0D000, entry 0x800000001DE0D003
Page table level 2 @ 0x1DE0D000, index 0xEF
Allocated physical page 0x1DE0C000, entry 0x800000001DE0C003
Page table level 1, index 0xF
New entry: 0x800000001DE0F003 P W NX
First bytes: 0x70 0x68 0x64 0x30 0xAF 0xAF 0xAF 0xAF
…
Page 19 of 19...
Mapping page for virtual address 0x1DE21000...
Page table level 4 @ 0x1DF43000, index 0x0
Page table level 3 @ 0x1DE0E000, index 0x0
Page table level 2 @ 0x1DE0D000, index 0xEF
Page table level 1, index 0x21
New entry: 0x800000001DE21003 P W NX
First bytes: 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0
Mapping in loader code section 0x1DE2A000 with 20 pages (identiy mapped: 0x0)...
Page 1 of 20...
Mapping page for virtual address 0x1DE2A000...
Page table level 4 @ 0x1DF43000, index 0x0
Page table level 3 @ 0x1DE0E000, index 0x0
Page table level 2 @ 0x1DE0D000, index 0xEF
Page table level 1, index 0x2A
New entry: 0x1DE2A001 P
First bytes: 0x4D 0x5A 0x90 0x0 0x3 0x0 0x0 0x0
…
Page 19 of 20...
Mapping page for virtual address 0x1DE3C000...
Page table level 4 @ 0x1DF43000, index 0x0
Page table level 3 @ 0x1DE0E000, index 0x0
Page table level 2 @ 0x1DE0D000, index 0xEF
Page table level 1, index 0x3C
New entry: 0x1DE3C001 P
First bytes: 0x65 0x0 0x20 0x0 0x74 0x0 0x65 0x0
Page 20 of 20...
Mapping page for virtual address 0x1DE3D000...
Page table level 4 @ 0x1DF43000, index 0x0
Page table level 3 @ 0x1DE0E000, index 0x0
Page table level 2 @ 0x1DE0D000, index 0xEF
Page table level 1, index 0x3D
New entry: 0x1DE3D001 P
First bytes: 0x50 0x0 0x61 0x0 0x74 0x0 0x68 0x0
Mapping in loader data section 0x1DE46000 with 9 pages (identity mapped: 0x0)...
Page 1 of 9...
Mapping page for virtual address 0x1DE46000...
Page table level 4 @ 0x1DF43000, index 0x0
Page table level 3 @ 0x1DE0E000, index 0x0
Page table level 2 @ 0x1DE0D000, index 0xEF
Page table level 1, index 0x46
New entry: 0x800000001DE46003 P W NX
First bytes: 0x1 0x90 0xE4 0x1D 0x0 0x0 0x0 0x0
…
Page 9 of 9...
Mapping page for virtual address 0x1DE4E000...
Page table level 4 @ 0x1DF43000, index 0x0
Page table level 3 @ 0x1DE0E000, index 0x0
Page table level 2 @ 0x1DE0D000, index 0xEF
Page table level 1, index 0x4E
New entry: 0x800000001DE4E003 P W NX
First bytes: 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0
Mapping in loader data section 0x1DF43000 with 1 pages (identity mapped: 0x0)...
Page 1 of 1...
Mapping page for virtual address 0x1DF43000...
Page table level 4 @ 0x1DF43000, index 0x0
Page table level 3 @ 0x1DE0E000, index 0x0
Page table level 2 @ 0x1DE0D000, index 0xEF
Page table level 1, index 0x143
New entry: 0x800000001DF43003 P W NX
First bytes: 0x3 0xE0 0xE0 0x1D 0x0 0x0 0x0 0x80
Mapping in loader data section 0x1E0D6000 with 1 pages (identity mapped: 0x0)...
Page 1 of 1...
Mapping page for virtual address 0x1E0D6000...
Page table level 4 @ 0x1DF43000, index 0x0
Page table level 3 @ 0x1DE0E000, index 0x0
Page table level 2 @ 0x1DE0D000, index 0xF0
Allocated physical page 0x1DE0B000, entry 0x800000001DE0B003
Page table level 1, index 0xD6
New entry: 0x800000001E0D6003 P W NX
First bytes: 0x70 0x68 0x64 0x30 0xAF 0xAF 0xAF 0xAF
Freeing temporary memory map...
Entry for loader data (0x1DE0F000): 0x800000001DE0F003
First bytes: 0xAF 0xAF 0xAF 0xAF 0xAF 0xAF 0xAF 0xAF
Entry for loader code (0x1DE2A000): 0x1DE2A001
First bytes: 0x4D 0x5A 0x90 0x0 0x3 0x0 0x0 0x0
End of mapping: 0xFFFFFF00003FC000
Entry for kernel (0xFFFFFF0000000000): 0x1DE49001
First bytes: 0x55 0x48 0x89 0xE5 0x48 0x89 0x7D 0xF8
Entry for kernel entry (0xFFFFFF0000000000): 0x1DE49001
First bytes: 0x55 0x48 0x89 0xE5 0x48 0x89 0x7D 0xF8
Entry for (ss:esp - 8) (0xFFFFFF0000011FF8): 0x800000001DE21003
First bytes: 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0
Entry for frame buffer (0xFFFFFF0000012000): 0x8000000080000003
First bytes: 0x25 0x18 0x18 0x0 0x25 0x18 0x18 0x0
Entry for initrd (0xFFFFFF00003FA000): 0x800000001DE4D003
First bytes: 0x30 0x37 0x30 0x37 0x30 0x31 0x30 0x30
Entry for loader data (0x1DE0F000): 0x800000001DE0F003
First bytes: 0xAF 0xAF 0xAF 0xAF 0xAF 0xAF 0xAF 0xAF
Entry for loader code (0x1DE2A000): 0x1DE2A001
First bytes: 0x4D 0x5A 0x90 0x0 0x3 0x0 0x0 0x0
Entry 0: 0x800000001DE0E003
Entry 1: 0x0
…
Entry 509: 0x0
Entry 510: 0x800000001DE48003
Entry 511: 0x800000001DE4C003
Address of trampoline 0x1DE2FDF0
Enable NXE...
Getting system memory map and calling the kernel...
Memory map size: 0x1A40, descriptor size: 0x30, version: 1

boot/efi/virtual.c

load_kernel()

#include "main.h"

EFI_STATUS load_kernel(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable, const void *kernel, size_t kernel_size, boot_info_t *bi)
{
    EFI_STATUS status;
    kernel_image_t kernel_info;
    page_table_physical_ptr_t pageTable;

    TraceLine("Measuring kernel size...");
    TRYWRAPFNS(measure_kernel(kernel, kernel_size, &kernel_info),
               "Failed to measure the kernel size");

    TraceLine("Creating page tables...");
    TRYWRAPFNS(create_page_tables((page_table_physical_address_t *)&pageTable),
               "Failed to create page tables");

    virtual_address_t stack_pointer;
    TraceLine("Mapping virtual address space...");
    TRYWRAPFNS(map_virtual_address_space(SystemTable, kernel, kernel_size, &kernel_info, bi, &stack_pointer, pageTable),
               "Failed to map virtual address space");

    // TraceLine("Mapping the kernel into virtual memory...");
    // TRYWRAPFNS(map_kernel(kernel, kernel_size, &kernel_info, pageTable),
    //            "Failed to map the kernel into virtual memory");

    //__asm__ volatile("mov %0, %%cr3" ::"r"(pageTable) : "memory");

    for (int i = 0; i < 512; i++)
    {
        TraceLine("Entry %d: %llp", i, (*pageTable)[i]);
    }
    TraceLine("Address of trampoline %llp", trampoline);

    TraceLine("Enable NXE...");
    enable_nxe();

    UINTN mapKey;
    TraceLine("Getting system memory map and calling the kernel...");
    TRYWRAPFNS(get_memmap(SystemTable, &bi->memory_map, &mapKey),
               "Failed to get memory map");

    // TraceLine("Calling kernel entry point...");
    // No printing or allocation after getting the memory map
    TRYWRAPFNS(enter_kernel(ImageHandle, SystemTable, &kernel_info, stack_pointer, (page_table_physical_address_t)pageTable, bi, mapKey),
               "Failed to call kernel entry point");

    return EFI_SUCCESS;
}

enter_kernel()

EFI_STATUS enter_kernel(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable, kernel_image_t *kernel_info, virtual_address_t stack_pointer, page_table_physical_address_t page_table, boot_info_t *bi, UINTN mapKey)
{
    EFI_STATUS status;

    // TraceLine("Validating kernel entry mapping: %llp", kernel_info->entry);
    // page_table_entry_t *lvl4 = ((page_table_entry_t *)page_table);
    // int l4 = PT_IDX(kernel_info->entry, 4);
    // int l3 = PT_IDX(kernel_info->entry, 3);
    // int l2 = PT_IDX(kernel_info->entry, 2);
    // int l1 = PT_IDX(kernel_info->entry, 1);
    // TraceLine("L4[%d]: %llp", l4, lvl4[l4]);

    // TraceLine("trampoline(page_table: %llp, stack_pointer: %llp, boot_info: %llp, entry: %llp)", page_table, stack_pointer, bi, kernel_info->entry);
    // while (1)
    //     ;

    // DebugLine("Exiting boot services...");
    // No printing or allocation after getting the memory map
    TRYWRAPS((SystemTable->BootServices->ExitBootServices, 2, ImageHandle, mapKey),
             "Could not exit boot services");

    // DebugLine("Kernel loaded. Executing...");
    // No printing after exiting boot services
    trampoline(page_table, stack_pointer, (physical_address_t)bi, (virtual_address_t)kernel_info->entry);

    // Should kernel return
    return EFI_SUCCESS;
}

check_addr()

void check_addr(const char *name, virtual_address_t vaddr, page_table_entry_physical_ptr_t pageTable)
{
    page_table_entry_t l3 = pageTable[PT_L4_IDX(vaddr)];
    pageTable = (page_table_entry_physical_ptr_t)(l3 & PAGE_ADDR_MASK);

    page_table_entry_t l2 = pageTable[PT_L3_IDX(vaddr)];
    pageTable = (page_table_entry_physical_ptr_t)(l2 & PAGE_ADDR_MASK);

    page_table_entry_t l1 = pageTable[PT_L2_IDX(vaddr)];
    pageTable = (page_table_entry_physical_ptr_t)(l1 & PAGE_ADDR_MASK);

    page_table_entry_t entry = pageTable[PT_L1_IDX(vaddr)];
    physical_address_t paddr = (physical_address_t)(entry & PAGE_ADDR_MASK);

    TraceLine("Entry for %a (%llp): %llp", name, vaddr, entry);

    const unsigned char *bytes = (const unsigned char *)paddr;
    TraceLine("  First bytes: 0x%hhx 0x%hhx 0x%hhx 0x%hhx 0x%hhx 0x%hhx 0x%hhx 0x%hhx", bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7]);
}

map_virtual_address_space()

EFI_STATUS map_virtual_address_space(EFI_SYSTEM_TABLE *SystemTable, const void *kernel, size_t kernel_size, kernel_image_t *kernel_info, boot_info_t *bi, virtual_address_ptr_t stack_pointer_out, page_table_physical_ptr_t pageTable)
{
    EFI_STATUS status;
    UINTN cpuCount;
    page_table_entry_physical_ptr_t pml4 = (page_table_entry_physical_ptr_t)pageTable;

    // Map in the kernel
    TraceLine("Mapping in the kernel...");
    page_virtual_address_t first_page, next_page;
    map_kernel(kernel, kernel_size, kernel_info, &first_page, &next_page, pageTable);

    check_addr("kernel", (virtual_address_t)first_page, pml4);
    check_addr("kernel entry", (virtual_address_t)kernel_info->entry, pml4);

    // for (;;)
    //     ;

    // Map in the stacks
    page_virtual_address_t stack_page = next_page;
    TRYWRAPFNS(get_mp_info(SystemTable, bi, &cpuCount),
               "Failed to get CPU count");
    TraceLine("Mapping in %dkb stacks for %d CPUs...", STACK_SIZE >> 10, cpuCount);
    *stack_pointer_out = (virtual_address_t)(next_page + EFI_PAGE_SIZE // guard page
                                             + STACK_SIZE);            // Top of the stack
    TraceLine("Stack pointer: %llp", *stack_pointer_out);

    int stack_pages = EFI_SIZE_TO_PAGES(STACK_SIZE);
    for (int i = 0; i < cpuCount; i++)
    {
        TraceLine("Stack %d ========", i + 1);
        TraceLine("(Guard page: %llp)", next_page);
        next_page += EFI_PAGE_SIZE; // guard page
        TraceLine("Allocating %d pages for stack at %llp", stack_pages, next_page);
        page_physical_address_t stack_addr;
        TRYWRAPFN(map_new_pages(next_page, &stack_addr, PAGE_PRESENT | PAGE_RW | PAGE_NX, stack_pages, pageTable));
        TraceLine("Physical address of stack: %llp", stack_addr);

        // Zero it out
        memset((void *)stack_addr, 0, STACK_SIZE);
        next_page += STACK_SIZE;
    }

    check_addr("(ss:esp - 8)", *stack_pointer_out - 8, pml4);

    // for (;;)
    //     ;

    // Map in the frame buffer
    page_virtual_address_t framebuf_page = next_page;
    int framebuf_pages = EFI_SIZE_TO_PAGES(bi->graphics_info.framebuffer_size);
    bi->graphics_info.framebuffer_virtual_base = (uint32_t *)next_page;
    TraceLine("Mapping in %d frame buffer pages from %llp (phys) to %llp (virt)...", framebuf_pages, bi->graphics_info.framebuffer_base, bi->graphics_info.framebuffer_virtual_base);
    // Suppress output
    enum BootLogLevel prevLevel = logLevel;
    logLevel = ErrorLevel;
    TRYWRAPFN(map_pages((page_virtual_address_t)bi->graphics_info.framebuffer_virtual_base,
                        (page_physical_address_t)bi->graphics_info.framebuffer_base,
                        PAGE_PRESENT | PAGE_RW | PAGE_NX,
                        framebuf_pages, pageTable));
    next_page += framebuf_pages * EFI_PAGE_SIZE;
    logLevel = prevLevel;
    TraceLine("Mapped in %d frame buffer pages from %llp (phys) to %llp (virt).", framebuf_pages, bi->graphics_info.framebuffer_base, bi->graphics_info.framebuffer_virtual_base);

    check_addr("frame buffer", framebuf_page, pml4);

    // for (;;)
    //     ;

    // Map in initrd image
    page_virtual_address_t initrd_page = next_page;
    int initrd_pages = EFI_SIZE_TO_PAGES(bi->initrd_size);
    TraceLine("Mapping in initrd.img, %d pages at %llp", initrd_pages, next_page);
    TRYWRAPFN(map_pages(next_page, (page_physical_address_t)bi->initrd_base, PAGE_PRESENT | PAGE_RW | PAGE_NX, initrd_pages, pageTable));
    bi->initrd_base = (uint32_t *)next_page; // physical to virtual
    next_page += initrd_pages * EFI_PAGE_SIZE;

    check_addr("initrd", initrd_page, pml4);

    // for (;;)
    //     ;

    // Identity map in our loader code and data
    boot_memmap_t initmm;
    UINTN mapKey;
    page_virtual_address_t loader_page = (uint64_t)-1, loader_code_page;
    TraceLine("Getting temporary memory map...");
    TRYWRAPFNS(get_memmap(SystemTable, &initmm, &mapKey),
               "Failed to get memory map");
    uint8_t *desc = (uint8_t *)initmm.memory_map;
    for (UINTN i = 0; i < initmm.memory_map_size; i += initmm.descriptor_size)
    {
        EFI_MEMORY_DESCRIPTOR *d = (EFI_MEMORY_DESCRIPTOR *)(desc + i);

        switch (d->Type)
        {
        case EfiLoaderCode:
            loader_code_page = d->PhysicalStart;
            TraceLine("Mapping in loader code section %llp with %d pages (identiy mapped: %llp)...", d->PhysicalStart, d->NumberOfPages, d->VirtualStart);
            TRYWRAPFN(map_pages(d->PhysicalStart, d->PhysicalStart, PAGE_PRESENT, d->NumberOfPages, pageTable));
            break;
        case EfiLoaderData:
            if (d->PhysicalStart < loader_page)
                loader_page = d->PhysicalStart;
            TraceLine("Mapping in loader data section %llp with %d pages (identity mapped: %llp)...", d->PhysicalStart, d->NumberOfPages, d->VirtualStart);
            TRYWRAPFN(map_pages(d->PhysicalStart, d->PhysicalStart, PAGE_PRESENT | PAGE_RW | PAGE_NX, d->NumberOfPages, pageTable));
            break;
        }
    }
    TraceLine("Freeing temporary memory map...");
    TRYWRAPS((BS->FreePool, 1, initmm.memory_map), "Failed to free temporary memory map");

    check_addr("loader data", loader_page, pml4);
    check_addr("loader code", loader_code_page, pml4);

    // for (;;)
    //     ;

    TraceLine("End of mapping: %llp", next_page);

    check_addr("kernel", first_page, pml4);
    check_addr("kernel entry", (virtual_address_t)kernel_info->entry, pml4);
    check_addr("(ss:esp - 8)", *stack_pointer_out - 8, pml4);
    check_addr("frame buffer", framebuf_page, pml4);
    check_addr("initrd", initrd_page, pml4);
    check_addr("loader data", loader_page, pml4);
    check_addr("loader code", loader_code_page, pml4);

    // for (;;)
    //     ;

    return EFI_SUCCESS;
}

map_kernel()

EFI_STATUS map_kernel(const void *elf_data, size_t elf_size, kernel_image_t *out, page_virtual_address_ptr_t first_page, page_virtual_address_ptr_t next_page, page_table_physical_ptr_t pageTable)
{
    EFI_STATUS status;

    Elf64_Ehdr *ehdr = (Elf64_Ehdr *)elf_data;
    uint8_t elfmag[] = {ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3};
    if (_memcmp(ehdr->e_ident, elfmag, sizeof(elfmag)))
        return EFI_LOAD_ERROR;

    Elf64_Phdr *phdrs = (Elf64_Phdr *)((uint8_t *)elf_data + ehdr->e_phoff);
    out->kernel_page_count = 0;
    out->kernel_virtual_base = (virtual_address_t)phdrs[0].p_vaddr;
    out->entry = (void *)(uintptr_t)ehdr->e_entry;
    out->kernel_code_pages = EFI_SIZE_TO_PAGES(phdrs[0].p_memsz);
    *first_page = out->kernel_virtual_base;
    *next_page = *first_page;

    TraceLine("  Kernel base:  %llp", out->kernel_virtual_base);
    TraceLine("  Kernel entry: %llp", out->entry);
    TraceLine("  Kernel code pages: %d", out->kernel_code_pages);

    for (int i = 0; i < ehdr->e_phnum; ++i)
    {
        Elf64_Phdr *ph = &phdrs[i];
        if (ph->p_type != PT_LOAD)
            continue;

        TraceLine("  Section       %llp:", ph->p_vaddr);
        TraceLine("  Allocating to %llp", *next_page);

        UINTN pages = EFI_SIZE_TO_PAGES(ph->p_memsz);

        page_physical_address_t physaddr;
        PageAttributes attr = PAGE_PRESENT;
        if (!(ph->p_flags & PF_X))
        {
            TraceLine("    No execute");
            attr |= PAGE_NX;
        }
        if ((ph->p_flags) & PF_W)
        {
            attr |= PAGE_RW;
            TraceLine("    Writeable");
        }
        TRYWRAPFN(map_new_pages(*next_page, &physaddr, attr, pages, pageTable));
        TraceLine("    Allocated to physical address @ %d pages: %llp", pages, physaddr);

        memcpy((void *)physaddr,
               (uint8_t *)elf_data + ph->p_offset,
               ph->p_filesz);
        TraceLine("    Copied 0x%x bytes", ph->p_filesz);

        if (ph->p_memsz > ph->p_filesz)
            memset((uint8_t *)physaddr + ph->p_filesz, 0, ph->p_memsz - ph->p_filesz);
        TraceLine("    Memsize is 0x%x bytes, clearing 0x%x additional bytes", ph->p_memsz, ph->p_memsz - ph->p_filesz);

        out->kernel_page_count += pages;
        *next_page += pages * EFI_PAGE_SIZE;
    }

    return EFI_SUCCESS;
}

measure_kernel()

EFI_STATUS measure_kernel(const void *elf_data, size_t elf_size, kernel_image_t *out)
{
    Elf64_Ehdr *ehdr = (Elf64_Ehdr *)elf_data;
    uint8_t elfmag[] = {ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3};
    if (_memcmp(ehdr->e_ident, elfmag, sizeof(elfmag)))
    {
        ErrorLine("ELF header mismatch!");
        return EFI_LOAD_ERROR;
    }

    Elf64_Phdr *phdrs = (Elf64_Phdr *)((uint8_t *)elf_data + ehdr->e_phoff);
    out->kernel_page_count = 0;
    for (int i = 0; i < ehdr->e_phnum; ++i)
    {
        Elf64_Phdr *ph = &phdrs[i];
        if (ph->p_type != PT_LOAD)
            continue;

        int pages = EFI_SIZE_TO_PAGES(ph->p_memsz);
        TraceLine("    Section %llp has %d pages.", (uint64_t)ph->p_vaddr, pages);
        out->kernel_page_count += pages;
    }
    TraceLine("  Total pages: %d", out->kernel_page_count);

    out->kernel_virtual_base = (virtual_address_t)phdrs[0].p_vaddr;
    return EFI_SUCCESS;
}

get_memmap()