# AGENTS.md — rsboot (RaiserSoft Bootloader) ## Identity rsboot is a custom **UEFI** bootloader (PE32+, x64) that loads a Linux kernel + initramfs from an ext2 partition using UEFI file system protocols, then launches the kernel via `LoadImage`/`StartImage`. Single-stage design — no MBR, no real mode, no stage1/stage2 split. This is a standalone submodule of the [RNG](https://git.2137697.xyz/RaiserSoft/rng) project. ## Code - **Language:** C (freestanding, `-m64`, `-ffreestanding`, `-fPIE`, `-mabi=ms`). - **Assembler:** none currently (no `.asm` files needed). - **Linker:** `ld` with `-Ttext=0x1000 -e efi_main`, producing an ELF64 intermediate (`main.elf`). - **PE conversion:** `objcopy -O pei-x86-64 --subsystem=10` converts the ELF to a PE32+ image, then Python scripts fix up headers and pad for firmware compatibility. - **Dependencies:** none. No libc, no CRT — just raw UEFI protocol calls. - **Debug:** UEFI console output (`con_out->OutputString()` via serial + framebuffer as configured by the firmware). - **UEFI types:** `uefi.h` provides minimal stand-alone type definitions, GUIDs, and protocol structs (system table, boot services, file system protocol, loaded image protocol, etc.). ## Source Layout ``` main.c — EFI entry point, loads kernel + initrd, starts image uefi.h — UEFI types, GUIDs, protocol structs Makefile — builds BOOTX64.EFI fix_pe_simple.py — PE header fixup (ImageBase, DllChar, strip relocs) pad_for_optiplex.py — PE padding for Optiplex 7010 firmware ``` ## Build ```sh make # produces ../build/bootloader/BOOTX64.EFI ``` The build pipeline: 1. **main.o** — compiled with `-fPIE -fshort-wchar -mno-red-zone -mabi=ms` 2. **main.elf** — linked as position-independent ELF64 starting at text 0x1000 3. **BOOTX64.EFI** — objcopy to `pei-x86-64`, subsystem=10 (EFI application) 4. **fix_pe_simple.py** — sets ImageBase, marks RELOCS_STRIPPED (PIE code uses only PC-relative addressing, so no fixups needed), sets NX | DYNAMIC_BASE | HIGH_ENTROPY_VA, clears .reloc data directory and checksum 5. **pad_for_optiplex.py** — if the PE is smaller than ~160KB, pad to match the size systemd-boot uses (some AMI Aptio firmware versions on Optiplex 7010 reject smaller PE files) ## Kernel Loading Flow 1. Get our own `LoadedImage` protocol via `handle_protocol` 2. Get `SimpleFileSystem` from the device handle 3. `OpenVolume` → root directory 4. Open `\bzImage`, read into allocated pages 5. Open `\initramfs.cpio.gz`, read into allocated pages 6. `LoadImage` (from memory, not device path) → kernel handle 7. Set kernel's `load_options` (command line) on its `LoadedImage` protocol 8. `StartImage` → kernel takes over ## Key Conventions - **GUIDs:** EFI_LOADED_IMAGE_GUID, EFI_SIMPLE_FILE_SYSTEM_GUID (defined in `uefi.h` matching the UEFI 2.10 spec). - **Boot device:** The device we were loaded from (our `LoadedImage.device_handle`). - **File paths:** `\bzImage`, `\initramfs.cpio.gz` (backslash prefix for UEFI device paths). - **Cmdline:** `console=ttyS0,115200 console=tty0 earlyprintk=serial,ttyS0,115200 loglevel=3 rng_tty=ttyS0 initrd=\initramfs.cpio.gz` - **Memory allocation:** UEFI boot services `AllocatePages` (type 6 = EfiLoaderData) for kernel/initrd buffers; `AllocatePool` for cmdline copy. - **Compilation quirks:** `-mabi=ms` is required so UEFI calling convention (Microsoft x64 ABI) is used; `-fshort-wchar` makes `wchar_t` 16-bit to match UEFI's CHAR16; `-mno-red-zone` because the red-zone can be clobbered by UEFI firmware handlers. - **Commits:** `feat(rsboot):` prefix.