Boot Protocol Reference
Canonical reference for the Impossible OS bootloader to kernel handoff ABI. Pairs with:
boot-info-fields.md: per-field ownership matrix (which subsystem reads each field, which consumer validates it).boot-protocol-changelog.md:BOOT_INFO_VERSION-keyed history of every schema change with owning TODO section + commit.include/kernel/boot_info.h: C contract (struct layout + version macro + validator prototypes).src/boot/uefi/boot_info_mirror.h: bootloader mirror of the struct, kept byte-identical with the kernel header.This document describes what the handoff looks like, when each field is valid, and how to populate a minimal supported version. Field-by-field semantics live in
boot-info-fields.md.
1. Layout at a Glance
Physical address 0x10000 ────┐
│
struct boot_info { │ <-- bootloader writes here before jumping
struct boot_info_header header; (offset 0, 8 bytes)
... all ABI fields ... (v24: see boot_info.h sizeof for total)
} │
- Handoff base:
BOOT_INFO_PHYS_ADDR = 0x10000. - Version gate:
BOOT_INFO_VERSION = 24(current; this prose is updated alongside every bump but the authoritative live value lives ininclude/kernel/boot_info.handsrc/boot/uefi/boot_info_mirror.h-- check the changelog for the field-level history). - Magic gate:
BOOT_INFO_MAGIC = 0x49504F53("IPOS", little-endian). - Size gate:
sizeof(struct boot_info)is ABI-pinned via_Static_assert. The kernel refuses any handoff whoseheader.sizedoes not equal this exact value. - Early map bound:
BOOT_INFO_EARLY_MAP_ENDis the bootloader's 4 GiB identity map. The kernel rejects handoff pointers outside[0x1000 .. BOOT_INFO_EARLY_MAP_END).
The mirror in src/boot/uefi/boot_info_mirror.h uses UEFI typedefs (UINT8, UINT64, etc.) while the kernel header uses freestanding kernel/types.h typedefs (uint8_t, uint64_t). The physical byte layout is identical; the _Static_asserts on both sides enforce this, and the Generated ABI Manifest tooling (tools/boot-info-manifest/) emits a canonical SHA-256 fingerprint that must match between the two compilation units.
2. Lifecycle
UEFI firmware
│
▼
[BOOTX64.EFI entry] ─── parse boot.conf, load kernel ELF, populate
g_boot_info at 0x10000, write header magic
+ version + size last
│
▼
[ExitBootServices] ─── UEFI Boot Services protocol handles invalidate;
RuntimeServices and EfiLoaderData regions
survive
│
▼
[Kernel entry (`boot_phase0` in `src/kernel/main/boot_hw.c`)]
│ │
│ ├── boot_info_validate_addr(mbi, size, BOOT_INFO_EARLY_MAP_END)
│ │ reject NULL, misaligned, out-of-map, wrap
│ │
│ ├── boot_version_classify(header, sizeof(struct boot_info), &fault)
│ │ reject magic/version/size drift with a structured
│ │ fault record that feeds boot_version_render_fatal
│ │ (LOG_FATAL on serial + framebuffer). NVRAM
│ │ persistence is NOT attempted here today because
│ │ uefi_runtime_init runs later in Phase 0 -- the
│ │ Phase 3 BlackBox transcription path only emits
│ │ X:\Diag\boot-proto-fault.txt when a FUTURE caller
│ │ with uefi_runtime already live has persisted a
│ │ record (bootloader pre-jump work or section 13
│ │ anti-rollback).
│ │
│ ├── Copy header.size bytes from bootloader's mbi into the
│ │ kernel's own g_boot_info (single-copy, trusted after validation)
│ │
│ ├── boot_payload_validate(&g_boot_info)
│ │ reject overlapping / malformed payload_descriptors[]
│ │
│ ├── (later in phase 0) uefi_runtime_init()
│ │ SetVirtualAddressMap, wire GetVariable/SetVariable
│ │
│ └── pmm_init()
│ walk mmap, mark free, then
│ boot_reserved_populate_from_info(&g_boot_info, &err)
│ boot_reserved_check_payloads_disjoint(...) x4
│ boot_reserved_apply() (apply reservations to bitmap)
│
▼
[Phase 1/2/3 hardware bring-up + subsystem init]
│
└── late Phase 3 in `src/kernel/main/boot_desktop.c`:
hw_dump_write_file() --> X:\Diag\hwdump.txt
boot_reserved_blackbox_dump() --> X:\Diag\boot-reserved.json
boot_version_blackbox_transcribe() --> X:\Diag\boot-proto-fault.txt
(only if a PRIOR caller
with uefi_runtime
already live persisted
a fault record to
NVRAM; today that is
section 13 anti-
rollback when it
ships -- the Phase 0
stale-loader path
does not produce
such a record)
Every validator above is defined in include/kernel/boot_info.h or include/kernel/boot_version.h. The validators run BEFORE any consumer reads g_boot_info fields beyond the header, so downstream code can rely on invariants (no overlap, no range wrap, packed prefix, etc.).
3. Pointer Validity
Pointer fields inside struct boot_info fall into four classes:
| Class | Examples | Validity window |
|---|---|---|
| Bootloader-owned transient | Addresses below 1 MiB, BootServices-era handles |
Dead at ExitBootServices. struct boot_info MUST NOT store any of these. |
| RuntimeServices-survived | uefi_runtime_services, every rt_mmap[].phys_addr |
Valid across EBS. The kernel calls uefi_runtime_init() then SetVirtualAddressMap() to rebind RT pointers to kernel virtual addresses. |
| EfiLoaderData | USB DMA pages, TPM event log copy, typed payload descriptors, scratchpad base | Survives EBS but is reclaimable by PMM unless added to the boot_reserved table (see the Handoff Memory Ownership section). Bootloader sets BOOT_PAYLOAD_FLAG_RESERVED on any descriptor whose bytes must not be reclaimed. |
| Framebuffer MMIO | fb.addr |
Survives EBS. Kernel maps as UC via vmm_map_mmio_uc() after PMM init; bootloader identity map has it as WB. |
The kernel never trusts a pointer until the matching validator has run. boot_info_validate_addr() covers the struct boot_info itself; boot_payload_validate() covers every payload descriptor range; boot_reserved_populate_from_info() covers every retained region (including USB DMA pages, TPM log, framebuffer, runtime memory regions, and payload descriptors with FLAG_RESERVED) -- with one deliberate exception, and it inverts what the flag means to a consumer. Since 2026-08-29 the pass SKIPS pinning a BOOT_PAYLOAD_RANDOM_SEED descriptor whose declared length fails boot_seed_length_reservable(), even though FLAG_RESERVED is set (src/kernel/mm/boot_reserved.c), because reserving an attacker-declared span permanently starves the PMM and kills the boot in heap_init instead of degrading. So FLAG_RESERVED is a PRODUCER's request, not proof the kernel honored it: every consumer of a length-bounded type must apply the same predicate before dereferencing, or it reads memory nothing pinned. Extending that per-type length contract to the other eight payload types is TODO-01 section 28.
4. Minimum Supported Handoff
A third-party bootloader that wants to invoke Impossible OS must populate the fields below at 0x10000 BEFORE jumping to the kernel ELF entry point. Anything not in these tables can be left zero (the kernel's validators accept zero as "absent" and reject only structurally-invalid values), with one important exception below: the capability classification in caps_present / caps_degraded is a Phase 0 hard requirement for v7+ handoffs because boot_caps_validate halts on any known capability bit left unclassified.
Required (kernel halts via Phase 0 validator if wrong)
| Field | Type | Requirement |
|---|---|---|
header.magic |
uint32_t |
Must equal BOOT_INFO_MAGIC = 0x49504F53. |
header.version |
uint16_t |
Must equal the BOOT_INFO_VERSION the kernel was built against. |
header.size |
uint16_t |
Must equal sizeof(struct boot_info) for that version. |
caps_present, caps_degraded (v7+) |
uint64_t each |
Every bit in BOOT_CAP_MASK_KNOWN MUST be classified as present (the loader populated the underlying field) OR degraded (the loader could not populate it and the kernel must use a fallback). A bit set in NEITHER halts via boot_caps_validate. A bit set in BOTH also halts. caps_required may be zero; if non-zero, every required bit must be in caps_present. The native UEFI loader at src/boot/uefi/bootx64.c populates this block explicitly; alternate adapters that leave it zero will halt regardless of the rest of their handoff. |
esp_size_mb, esp_filesystem_type, esp_type_guid_valid (v11+) |
uint32_t, uint8_t, uint8_t |
Bootloader's pre-load ESP integrity attestation. The native UEFI loader populates these via esp_integrity_check() before load_kernel(). The kernel currently logs them but does not halt on zero today; future attestation consumers WILL halt on esp_type_guid_valid=0, so adapters SHOULD populate honestly even if the values are best-effort. |
Required for full UEFI parity (degrades cleanly if absent)
These fields are required by a native UEFI loader that wants every Impossible OS feature (GOP splash, desktop, GetVariable/SetVariable for POST-codes and anti-rollback NVRAM, etc.). A non-UEFI adapter may zero any of them; the kernel degrades each one separately with a klog warning instead of halting.
| Field | Type | Purpose | Degraded behavior when zeroed |
|---|---|---|---|
mmap[] + mmap_count |
struct boot_mmap_entry[] |
Physical memory layout. PMM walks this to find free RAM. | pmm_init logs memory map truncated warning and falls back to whatever is populated; zero entries means no free RAM is recovered and subsequent allocations fail (effectively degraded, not halted). |
fb.addr, fb.pitch, fb.width, fb.height, fb.bpp, fb.pixel_format + fb_available=1 |
struct boot_framebuffer |
Linear GOP framebuffer for the kernel splash and desktop. | fb_available=0 puts the kernel in headless mode: no splash, no desktop, serial still works. Supported path. |
uefi_runtime_services + uefi_rt_available=1 |
uintptr_t/uint8_t |
EFI RuntimeServices table pointer (must point at a RUNTSERV-signature table). Needed for GetVariable / SetVariable / GetTime. |
uefi_runtime_init() returns BOOT_DEGRADED and logs the limitation. POST-code NVRAM writes, anti-rollback reads, and RT time calls become no-ops; kernel boots without them. |
Optional (consumed if populated)
| Field | Purpose | If absent |
|---|---|---|
rt_mmap[] + rt_mmap_count |
UEFI runtime memory regions for SVAM. | Kernel degrades RT services; logs warning. |
tpm_event_log + tpm_event_log_size + tpm_available |
Measured boot event log from EFI_TCG2_PROTOCOL. |
TPM measurement is unavailable. |
usb_controller + usb_devices[] |
xHCI handover state (DCBAA, scratchpad, DMA pages). | Kernel re-enumerates USB with higher latency. |
payload_descriptors[] + payload_count |
Typed payloads (module / initrd / recovery_image; see Module and initrd Handoff Contract). Must pass boot_payload_validate(): packed prefix, no overlap, no range wrap. |
No modules loaded. |
boot_device_*, uefi_boot_* |
Boot device identification and BootOrder inspection. | Kernel uses the default drive search path. |
timing.* |
FPDT and TSC timestamps for boot timeline diagnostics. | Timeline starts at kernel entry. |
config (boot.conf parsed form) |
Runtime configuration knobs: debug, verbose, test_suite, etc. | The kernel has NO fallback for this field today: boot_phase0 consumes whatever bytes were handed off. A zeroed config gives serial_debug=0, splash_timeout=0, deferred=0, utest_isolation=0, etc., which differs from the native UEFI loader's boot_config_defaults() (applied in-loader BEFORE parsing boot.conf). Third-party loaders SHOULD populate config with the same defaults the UEFI loader emits (see src/boot/uefi/bootx64.c::boot_config_defaults) unless they deliberately want the zeroed values. |
Writer contract
The bootloader MUST:
- Allocate
struct boot_infoat physical address0x10000(either a fixed allocation or ensure it lands there via AllocatePages + memmove). efi_memset(g_boot_info_ptr, 0, sizeof(struct boot_info))before populating any field. This guarantees every unused slot is zero (a required precondition forboot_payload_validate()'s NONE-empty-slot invariant, and for every*_countfield that is read without a prior store).- Populate the fields above in any order. The header (
magic,version,size) MUST be written as a block AFTER every validator-relevant field is final. The canonical producer atsrc/boot/uefi/bootx64.caround line 5691 writes the block asheader.magic = BOOT_INFO_MAGIC;thenheader.version = BOOT_INFO_VERSION;thenheader.size = sizeof(struct boot_info);. Post-header telemetry writes are explicitly allowed: the canonical loader then writestiming.kernel_jump = boot_rdtsc();and jumps. The kernel validator (boot_version_classify) reads only the header fields; it never consultstiming.*, so recording jump-timing after the header cannot invalidate the handoff. A third-party loader SHOULD write the header as the last block before any validator-relevant work, but MAY continue to touch telemetry-only fields (timing.*) between the header block andjump_to_kernel. - Call
ExitBootServices()and then jump to the kernel ELF entry point with the handoff pointer inrsiand the magic (UEFI_BOOT_MAGIC) inrdi, matching the Multiboot2-style ABI the kernel's early assembly expects.
Failure modes: magic drift, version drift, and size drift each halt with a dedicated fault-class line via boot_version_render_fatal(). Structural field drift (e.g. rt_mmap entry with wrapping length) halts via the downstream validator with its own class-specific klog. See boot-protocol-changelog.md for which version introduced each field.
5. Example: Native UEFI path
The canonical bootloader is src/boot/uefi/bootx64.c. Follow the flow from efi_main through to jump_to_kernel for a concrete reference implementation. The mirror struct at src/boot/uefi/boot_info_mirror.h is the bootloader-side view; it is regenerated by hand when the kernel header gains a field (the ABI manifest and mirror drift checker tooling catches any drift before build completes).
6. Compatibility Matrix for Alternate Adapters
| Adapter | Required payloads | Required capability flags | Required provenance fields | Supported |
|---|---|---|---|---|
Native UEFI (BOOTX64.EFI) |
All of mmap, fb, uefi_runtime_services |
none (all v6+ features) | boot_device_*, uefi_boot_*, timing.*, config |
✅ Canonical |
| Multiboot2 / GRUB legacy path | (parser deleted) | (parser deleted) | (parser deleted) | ❌ Retired -- policy = unsupported per docs/boot/alt-boot.md. Parser source (src/kernel/multiboot2_parse.c), header (include/kernel/multiboot2.h), 32-bit entry stub (src/boot/entry.asm), Multiboot2 header asm (src/boot/multiboot2_header.asm), and src/boot/grub.cfg were deleted under the Alternate Boot Protocols TODO-08 deprecation gate. Re-opening requires restoring files from git history. |
| PXE / HTTP boot | payload_descriptors[] with BOOT_PAYLOAD_NETWORK_CONFIG |
reserved for Network PXE/HTTP boot | Network provenance section | ⬜ Planned; alternate adapters should target the Alternate Boot Protocols TODO for this path. |
| Secure Launch (TrenchBoot / TXT / SKINIT) | payload_descriptors[] with BOOT_PAYLOAD_TPM_EVENT_LOG |
reserved for drtm_entry_pcr etc. (see Attestation Report Export) |
DRTM measurement metadata | ⬜ Planned; forward-compat fields are reserved in the attestation report. |
| Warm kernel update (KHO-style) | payload_descriptors[] preserving in-memory state |
Warm kernel update handoff ABI slot | KHO state region | ⬜ ABI reserved. |
Every adapter column above references the owning TODO by capability name and anchor link rather than numeric section reference. The matrix is deliberately short. Failure semantics differ by layer:
- Header drift (magic / version / size mismatch): the kernel halts via
boot_version_render_fatalwith a full observed-vs-expected diagnostic. No degraded path. - Payload drift (overlapping / wrapping / unknown-required payload descriptors): the kernel halts via
boot_payload_validatewith a per-descriptor error class. - Optional field absence (framebuffer, runtime services, USB state, TPM log, payloads): the kernel degrades per subsystem with a klog warning. The Multiboot2 row above is retired -- the parser was deleted under the alt-boot
unsupportedpolicy.
An adapter that emits a well-formed header + mmap + classified caps_present/caps_degraded but zeros everything else is a supported degraded boot; the "fail closed" behavior is scoped to the header / capability / payload-integrity validators (header drift, unclassified caps bits, overlapping payloads) and NOT to the full feature surface (framebuffer, runtime services, USB state, TPM log -- each degrades independently with a klog warning when its capability bit is set degraded).
7. See Also
boot-info-fields.md: per-field matrix (ownership, consumer, validator, version-added).boot-protocol-changelog.md: schema changelog keyed byBOOT_INFO_VERSION.- TODO-01 domain index:
todo/01-boot-platform/INDEX.md(implementation-tracking source of truth). tools/boot-info-manifest/: kernel + mirror manifest emitters and drift detector.
This protocol reference is stable: schema-layer changes bump BOOT_INFO_VERSION and get a changelog row; documentation-only edits (new examples, clarified prose) do NOT bump the version.