1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
# 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.
|