diff options
| author | salmonik <salmonik@tuta.io> | 2026-07-31 02:55:10 +0200 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-07-31 02:55:10 +0200 |
| commit | 1963a0a6d7398a426d0701f90a5bc796e32899ae (patch) | |
| tree | 8294a30acd2c8bb0d0ff98ebaee14f9667cbcc6d /AGENTS.md | |
| download | rsboot-1963a0a6d7398a426d0701f90a5bc796e32899ae.tar.gz rsboot-1963a0a6d7398a426d0701f90a5bc796e32899ae.zip | |
feat(rsboot): initial commit — UEFI bootloader extracted from RNG
Diffstat (limited to 'AGENTS.md')
| -rw-r--r-- | AGENTS.md | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..a39c192 --- /dev/null +++ b/AGENTS.md | |||
| @@ -0,0 +1,82 @@ | |||
| 1 | # AGENTS.md — rsboot (RaiserSoft Bootloader) | ||
| 2 | |||
| 3 | ## Identity | ||
| 4 | |||
| 5 | rsboot is a custom **UEFI** bootloader (PE32+, x64) that loads a Linux kernel + | ||
| 6 | initramfs from an ext2 partition using UEFI file system protocols, then | ||
| 7 | launches the kernel via `LoadImage`/`StartImage`. Single-stage design — | ||
| 8 | no MBR, no real mode, no stage1/stage2 split. | ||
| 9 | |||
| 10 | This is a standalone submodule of the [RNG](https://git.2137697.xyz/RaiserSoft/rng) project. | ||
| 11 | |||
| 12 | ## Code | ||
| 13 | |||
| 14 | - **Language:** C (freestanding, `-m64`, `-ffreestanding`, `-fPIE`, `-mabi=ms`). | ||
| 15 | - **Assembler:** none currently (no `.asm` files needed). | ||
| 16 | - **Linker:** `ld` with `-Ttext=0x1000 -e efi_main`, producing an ELF64 | ||
| 17 | intermediate (`main.elf`). | ||
| 18 | - **PE conversion:** `objcopy -O pei-x86-64 --subsystem=10` converts the ELF | ||
| 19 | to a PE32+ image, then Python scripts fix up headers and pad for | ||
| 20 | firmware compatibility. | ||
| 21 | - **Dependencies:** none. No libc, no CRT — just raw UEFI protocol calls. | ||
| 22 | - **Debug:** UEFI console output (`con_out->OutputString()` via serial + | ||
| 23 | framebuffer as configured by the firmware). | ||
| 24 | - **UEFI types:** `uefi.h` provides minimal stand-alone type definitions, | ||
| 25 | GUIDs, and protocol structs (system table, boot services, file system | ||
| 26 | protocol, loaded image protocol, etc.). | ||
| 27 | |||
| 28 | ## Source Layout | ||
| 29 | |||
| 30 | ``` | ||
| 31 | main.c — EFI entry point, loads kernel + initrd, starts image | ||
| 32 | uefi.h — UEFI types, GUIDs, protocol structs | ||
| 33 | Makefile — builds BOOTX64.EFI | ||
| 34 | fix_pe_simple.py — PE header fixup (ImageBase, DllChar, strip relocs) | ||
| 35 | pad_for_optiplex.py — PE padding for Optiplex 7010 firmware | ||
| 36 | ``` | ||
| 37 | |||
| 38 | ## Build | ||
| 39 | |||
| 40 | ```sh | ||
| 41 | make # produces ../build/bootloader/BOOTX64.EFI | ||
| 42 | ``` | ||
| 43 | |||
| 44 | The build pipeline: | ||
| 45 | |||
| 46 | 1. **main.o** — compiled with `-fPIE -fshort-wchar -mno-red-zone -mabi=ms` | ||
| 47 | 2. **main.elf** — linked as position-independent ELF64 starting at text 0x1000 | ||
| 48 | 3. **BOOTX64.EFI** — objcopy to `pei-x86-64`, subsystem=10 (EFI application) | ||
| 49 | 4. **fix_pe_simple.py** — sets ImageBase, marks RELOCS_STRIPPED (PIE code | ||
| 50 | uses only PC-relative addressing, so no fixups needed), sets NX | | ||
| 51 | DYNAMIC_BASE | HIGH_ENTROPY_VA, clears .reloc data directory and | ||
| 52 | checksum | ||
| 53 | 5. **pad_for_optiplex.py** — if the PE is smaller than ~160KB, pad to match | ||
| 54 | the size systemd-boot uses (some AMI Aptio firmware versions on | ||
| 55 | Optiplex 7010 reject smaller PE files) | ||
| 56 | |||
| 57 | ## Kernel Loading Flow | ||
| 58 | |||
| 59 | 1. Get our own `LoadedImage` protocol via `handle_protocol` | ||
| 60 | 2. Get `SimpleFileSystem` from the device handle | ||
| 61 | 3. `OpenVolume` → root directory | ||
| 62 | 4. Open `\bzImage`, read into allocated pages | ||
| 63 | 5. Open `\initramfs.cpio.gz`, read into allocated pages | ||
| 64 | 6. `LoadImage` (from memory, not device path) → kernel handle | ||
| 65 | 7. Set kernel's `load_options` (command line) on its `LoadedImage` protocol | ||
| 66 | 8. `StartImage` → kernel takes over | ||
| 67 | |||
| 68 | ## Key Conventions | ||
| 69 | |||
| 70 | - **GUIDs:** EFI_LOADED_IMAGE_GUID, EFI_SIMPLE_FILE_SYSTEM_GUID (defined | ||
| 71 | in `uefi.h` matching the UEFI 2.10 spec). | ||
| 72 | - **Boot device:** The device we were loaded from (our `LoadedImage.device_handle`). | ||
| 73 | - **File paths:** `\bzImage`, `\initramfs.cpio.gz` (backslash prefix for | ||
| 74 | UEFI device paths). | ||
| 75 | - **Cmdline:** `console=ttyS0,115200 console=tty0 earlyprintk=serial,ttyS0,115200 loglevel=3 rng_tty=ttyS0 initrd=\initramfs.cpio.gz` | ||
| 76 | - **Memory allocation:** UEFI boot services `AllocatePages` (type 6 = | ||
| 77 | EfiLoaderData) for kernel/initrd buffers; `AllocatePool` for cmdline copy. | ||
| 78 | - **Compilation quirks:** `-mabi=ms` is required so UEFI calling convention | ||
| 79 | (Microsoft x64 ABI) is used; `-fshort-wchar` makes `wchar_t` 16-bit to | ||
| 80 | match UEFI's CHAR16; `-mno-red-zone` because the red-zone can be clobbered | ||
| 81 | by UEFI firmware handlers. | ||
| 82 | - **Commits:** `feat(rsboot):` prefix. | ||
