Boot Protocol Changelog
History of every
BOOT_INFO_VERSIONbump. Each row links to the owning TODO section and the commit that landed the bump, so anyone diffingstruct boot_infoacross versions can jump straight to the design rationale.Invariant: every version bump MUST land with a changelog row in this file and a TODO section that names the new fields. Adding a field without bumping the version is an ABI-drift bug; bumping without documenting it leaves the next maintainer to guess.
See also:
boot-protocol.md: living contract (layout, lifecycle, pointer validity, minimum handoff).boot-info-fields.md: per-field ownership matrix.
Bump policy
Bump BOOT_INFO_VERSION whenever any of the following happens:
- A field is added, removed, or reordered inside
struct boot_infoor any nested struct. - A field changes type or size (
uint32_ttouint64_t,UINT8[16]toUINT8[32], etc.). - A field's semantics change in a way that a consumer would read the same bytes differently (e.g., reinterpreting a pad as a new flag).
Do NOT bump for:
- Pure documentation edits (comment rewrites, new examples in
boot-protocol.md). - Renaming a field without touching layout (though this is strongly discouraged because it breaks grep).
- Filling a previously-reserved pad slot whose offset and size were already pinned (if the pad was advertised as reserved-for-future, consumers know not to rely on zero).
Both halves of the ABI (the kernel header at include/kernel/boot_info.h and the bootloader mirror at src/boot/uefi/boot_info_mirror.h) update the version macro in the SAME commit as the struct change. The Generated ABI Manifest build step catches mismatches before the image boots.
Versions
v24 (current) -- Loader-owned kernel boot stack
- Commit:
018dc2d1b(Guarded Kernel Stack for Phase 0/1 Execution) - Fields added:
kstack_base(uint64_t),kstack_size(uint32_t),kstack_guard_size(uint32_t), appended at the v23 tail immediately after_gop_handle_pad. Mirror updated atomically;dump-fields.inc+check-doc-coverage.pyallow-list +boot-info-fields.mdupdated together. - Why: before v24 the loader called the kernel entry without ever writing RSP, so Phase 0 and Phase 1 executed on the firmware's own
EfiLoaderDatastack -- whichpmm_initfrees into the allocator, and which nothing reserved.vmm_initandheap_initthen allocated from a pool containing the run the kernel was standing on. It booted on placement luck, not on any enforced property, and no emulator disturbs that luck. The loader now allocates, poisons and publishes a 256 KiB below-4-GiB run and switches RSP to it at the handoff. - Producers / consumers: the bootloader's
bl_kstack_reserve()allocates pre-EBS andjump_to_kernelswitches RSP; the kernel'sboot_stack_init()validates in Phase 0,boot_reserved_populate_from_info()retains the run asBOOT_RESERVED_BOOT_STACK,boot_stack_install_guard()arms the guard page aftervmm_init, andpmm_initrefuses to continue unless every frame of the run is marked used. - Placement contract: publishing well-formed geometry is not sufficient. The run must avoid the low 1 MiB, the kernel-image + max-PMM-bitmap envelope, and the user page-table window, and must be fully poisoned with
BOOT_KSTACK_POISON. See the placement table inboot-info-fields.mdfor each interval, its reason, and the phase that refuses it. - Back-compat: NONE -- requires rebuilding and reflashing BOTH
BOOTX64.EFIandkernel.exetogether (boot_info_validate_header()enforces an exact version +header.sizematch). A v23 loader publisheskstack_base == 0, whichboot_stack_init()halts on by design rather than falling back to the firmware stack: the fallback IS the defect this version removes.
v23 -- Multi-GPU GOP handle enumeration
- Commit: pending (Multi-GPU GOP Handle Enumeration)
- Fields added:
gop_handles[4](each a 32-byteboot_gop_handle:fb_addr/fb_size/width/height/pitch/pixel_format/is_primary/fb_valid),gop_handle_count(uint32_t),_gop_handle_pad(uint32_t), appended at the v22 tail. Struct size 28664. Mirror updated atomically;dump-fields.inc+check-doc-coverage.pyallow-list +boot-info-fields.mdupdated together. - Why:
init_gop()now enumerates every GOP handle viaLocateHandleBuffer(iGPU + dGPU, multiple panels) and publishes per-head geometry so the kernel multi-head driver (04-drivers-hardware/TODO-17 sec6display_register_head()) can register UEFI-discovered heads. The primary (ConsoleOut-attached display) still drivesboot_info.fbunchanged. - Producers / consumers: bootloader's
gop_enumerate_and_select()insrc/boot/uefi/bootx64.cpopulates pre-EBS; the kernel multi-head driver consumesgop_handles[].gop_handle_count==0only on headless / no-display / enumeration-failure; a single-GPU boot publishescount==1. - Back-compat: NONE -- requires rebuilding and reflashing BOTH
BOOTX64.EFIandkernel.exetogether (boot_info_validate_header()enforces an exact version +header.sizematch).
v22 -- A/B-metadata partition range
- Commit: (A/B dual-slot boot)
- Fields added:
ab_meta_lba(uint64_t),ab_meta_block_count(uint32_t),_ab_meta_pad(uint32_t) appended at the v21 tail. Struct size 28528. - Why: lets the kernel A/B-metadata write path locate the reconciled metadata partition WITHOUT re-deriving GPT state via the weaker kernel
gpt_parse(which lacks the bootloader's primary+backup reconciliation). - Producers / consumers: bootloader's
select_active_slot()publishes; kernel A/B-metadata write path consumes. Both 0 when no A/B metadata partition. - Back-compat: NONE -- exact version +
header.sizematch enforced at Phase 0.
v21 -- OS-visible Loader UEFI variables
- Commit: (Boot entry store / menu policy)
- Fields added:
loader_vars_degraded(uint8_t) plusactive_slot+ the A/B slot-status snapshot (ab_select_reason,ab_from_slot,ab_slot_tries[2],ab_slot_flags,ab_status_valid) carved from the reserved_loader_vars_padregion. - Why: systemd-boot Boot Loader Interface compatibility -- the bootloader publishes 11 read-only
Loader*UEFI variables and flags degraded publication; the A/B snapshot surfaces the pre-EBS slot decision to kernel diagnostics. - Producers / consumers: bootloader boot policy publishes; kernel
boot_audit_publish()+ VPD slot diagnostics consume (ab_status_valid == AB_STATUS_VALID_MAGICgates the detailed render). - Back-compat: NONE -- exact version +
header.sizematch enforced at Phase 0.
v20 -- Policy audit surface
- Commit: pending (Policy Audit Trail and Rollback Reason Codes)
- Fields added: ten fields appended after the v19 selection block --
audit_degraded(uint8_t),sticky_present(uint8_t),sticky_recovery_trigger(uint8_t),sticky_watchdog_rollback_request(uint8_t),sticky_last_outcome(uint8_t),sticky_audit_degraded_last_boot(uint8_t),sticky_last_event_code(uint16_t),sticky_last_boot_seq(uint32_t),sticky_consumed_trigger_seq(uint32_t),_audit_pad(uint32_t). Mirror updated atomically; manifest dumper + doc-coverage allow-list updated together. - Why: per-decision boot policy audit needs a way for the bootloader to surface the
ImpossibleOS-BootStickyUEFI variable's cross-boot trigger bits (recovery request, watchdog rollback request) to the kernel-side publisher, plus a flag indicating whether the sticky read itself was trusted. The sticky var is exceptional-only (per-boot NVRAM writes wear flash); per-boot audit history lands in BlackBox JSONL (X:\Boot\history.jsonl) with monotonicboot_seqfrom a BlackBox-side dual-file counter. - Producers / consumers: bootloader's
boot_sticky_read_into_boot_info()insrc/boot/uefi/boot_sticky.cpopulates the surface pre-policy;boot_policy_invoke()consumessticky_recovery_triggerandsticky_watchdog_rollback_requestas ladder inputs. Kernel'sboot_audit_publish()insrc/kernel/main/boot_audit.creads the full surface to compose the JSONL line, then acks consumed triggers viauefi_var_setpost-publish (two-phase ack). - Back-compat: NONE -- v20 requires rebuilding and reflashing BOTH
BOOTX64.EFIandkernel.exetogether. The kernel'sboot_info_validate_header()enforces an exactBOOT_INFO_VERSION+header.sizematch before accepting the handoff; a v19 consumer reading a v20 producer (or vice versa) halts at Phase 0 with "boot_info: bad header". The "zero/absent sticky" defaults only apply once both halves are v20 and the sticky var is missing on first boot.
v19 -- Boot policy selection
- Commit: shipped in boot policy merge order (commit
39b9feee). - Fields added:
selected_entry_id[64],selection_reason(uint32_t),_selection_pad,rejected_entries[64](each carrying 64-byte id + reason u32),rejected_entry_count,rejected_entry_overflow. Documented inboot-info-fields.md"Boot policy selection (v19)". - Why: bootloader's policy ladder needs to record the chosen entry id + reason + per-entry rejects so the kernel can populate registry / loader-variables / audit consumers without re-deriving the decision.
- Producers / consumers: bootloader writes via
boot_policy_invoke(); kernel reads via the v19 Phase-0 ABI validator inboot_decision.c. Forward-compat: rejected_entry_overflow=1 advertises that consumers may have missed entries beyond the 64 cap.
v17, v18 -- intermediate
- v18 added the firmware trust-landscape surface (
sbat_level,dbx_size,degraded_trust_flags); v17 was an interim alignment bump. Both are documented inline inboot_info.hversion-block comments and inboot-info-fields.md"Firmware trust landscape (v18)".
v16 -- Local boot device path detail
- Commit: pending (Local Boot Device Path Detail Capture in
todo/01-boot-platform/TODO-05-boot-device-discovery.md) - Fields added: four fields appended after the v15
boot_descriptiontail --boot_nvme_nsid(uint32_tat offset 23952),boot_nvme_eui64[8](offset 23956),boot_pci_device(offset 23964),boot_pci_function(offset 23965), and_v16_pad[2](offset 23966) for alignment. Per-field_Static_assertoffsets on both kernel header and bootloader mirror. - Why: §4 classifies the boot device by Messaging-node subtype (SATA/NVMe/USB/network) but discards the per-bus identifiers Win11 (
MSFT_Disk.UniqueId/BusType) and Linux (/sys/class/nvme/nvmeX/nsid+ sysfs PCI BDF) both surface. NVMe boots lost NSID + EUI-64; PCI device/function never reachedboot_info; SD / eMMC boots classified asboot_device_type=0. v16 walks the boot device's full UEFI device path for NVMe Messaging nodes (UEFI 2.10 spec 10.3.4.21) and PCI Hardware nodes (UEFI 2.10 spec 10.3.2.1), extends the type enum with5=SD/6=eMMC, and persists the new identifiers inHKLM\SYSTEM\Boot\Device\(NamespaceId,NamespaceEui64,PciDevice,PciFunction). - Producers / consumers: bootloader's existing raw-node walker in
bootx64.c(the same loop that extracts the §7 partition GUID) extracts NVMe NSID / EUI-64 from the NVMe DP node and leaf PCI Device / Function from the LAST PCI Hardware node. Defaults: NSID=0, EUI-64=all-zero, PCI=0xFF/0xFF when not present. Consumer:boot_device_populate_registry()inboot_hw.cwrites the four registry values;NamespaceEui64is a REG_BINARY 8-byte blob that's omitted entirely when all-zero (matches Win11MSFT_Disk.UniqueIdbehavior of skipping absent identifiers). When the raw NVMe node hits but the text classifier missed it (long vendor prefix truncatedboot_device_path[128]), the walker also setsboot_device_type=2from the trusted raw-node evidence. - Back-compat: zero NSID / all-zero EUI-64 / 0xFF PCI fields are the defaults on systems where the boot device is not NVMe / not on PCI; legacy consumers reading those fields see sentinel values and skip the per-bus path. The v16 fields are append-only after v15, so v15 offset pins are unchanged.
v15 -- Extended UEFI boot-variable capability surface
- Commit: pending (Extended Boot Variable Capability Surface in
todo/01-boot-platform/TODO-05-boot-device-discovery.md) - Fields added: four fields appended after the v14 UKI cluster --
boot_current_attrs(uint32_tat offset 23872),boot_option_support(offset 23876),os_indications_supported(uint64_tat offset 23880),boot_description[64](offset 23888). Per-field_Static_assertoffsets on both kernel header and bootloader mirror. - Why: §6 captured
BootCurrent/BootOrder/BootNextand §12 logged the Boot#### description and FilePathList, but the remainingEFI_LOAD_OPTION.Attributesword, two firmware-side capability variables (BootOptionSupport,OsIndicationsSupported), and the Boot#### Description text were still log-only or untouched. Win11 BCDEdit and Linuxefibootmgr -vboth surface these. Read-onlyOsIndicationsSupported(UEFI 2.10 spec 8.5.4) is distinct from theOsIndicationswrite-path capsule trigger banned bytodo/01-boot-platform/TODO-27-uefi-advanced.md-- the read carries no capsule risk. - Producers / consumers: bootloader captures
boot_current_attrsfromEFI_LOAD_OPTIONlo_buf[0..3](little-endian decode) inside the existing §12 decode block; copies the first 63 ASCII chars (bit-7 stripped) of the UCS-2 Description intoboot_descriptionwith NUL terminator; reads the two firmware globals via two newGetVariablecalls inside the existing(rt && rt->GetVariable)scope. Consumer:boot_device_populate_registry()writes 5 new registry values underHKLM\SYSTEM\Boot\Device\--BootCurrentAttributes/BootOptionSupport/OsIndicationsSupportedLo+OsIndicationsSupportedHi(split for REG_DWORD compat) /Description(REG_SZ). - Back-compat: defaults of zero / empty when the firmware variable is absent;
BootCurrent==0xFFFF(the v6 sentinel) gates the description capture, so minimal-NVRAM VMs leave the description empty without misattributing.
v14 -- UKI signed-payload addresses
- Commit: pending (UKI Signed Payload Sections in
todo/01-boot-platform/TODO-02-uefi-hardening-secureboot.md) - Fields added: six
uint64fields appended afterloader_identity--uki_initrd_addr/uki_initrd_size/uki_recovery_addr/uki_recovery_size/uki_modules_addr/uki_modules_size. Per-field_Static_assertoffsets (23824 / 23832 / 23840 / 23848 / 23856 / 23864) on both kernel header and bootloader mirror. - Why: closes the whole-chain Secure Boot signature gap when the UKI ships an
initrd, recovery image, or pinned-module CPIO. Prior to v14 the UKI bundled.osrel+.cmdline+.linuxonly, so any boot path that loaded aninitrd=from disk read those bytes outside the firmware-verified PE signature. v14 publishes kernel-physical pointers to bootloader-allocatedEfiLoaderDatacopies of the new.initrd/.recovery/.modulesPE sections so the kernel consumes signed data, and the bootloader rejects any disk-sideinitrd=/modules=/recovery=cmdline override underBOOT_FLAG_INVOKED_VIA_UKI. - Producers / consumers: bootloader's
detect_uki_sections()walks the LoadedImage PE table for the new section names;uki_copy_payloads_to_loader_data()allocatesEfiLoaderDatapages and copies each payload out of LoadedImage memory before publishing the new physical address intoboot_info. Consumers: kernel-side initrd / recovery / module loaders (when wired). NewBOOT_ERR_UKI_PAYLOADandBOOT_ERR_UKI_DISK_OVERRIDEcodes for fatal-screen attribution.uki_find_disk_override_token()(header-only, shared between bootloader + unit tests) is the canonical scanner. - Back-compat: legacy UKIs without the new sections set the addr fields to zero; the kernel treats zero as "section absent". Builds without
build/uki-payloads/{initrd.img,recovery.img,modules.cpio}ship UKIs unchanged. Split-path boot does not setBOOT_FLAG_INVOKED_VIA_UKI, so the v14 fields stay zero and the cmdline rejection is bypassed.
v13 -- Bootloader build identity
- Commit: pending (Bootloader Build Identity in
todo/01-boot-platform/TODO-01-boot-protocol-abi-handoff.md) - Fields added:
loader_identity(64-byte packedstruct boot_loader_identityat the tail ofstruct boot_info, withgit_sha[20]+build_unix_time+build_label[24]+_pad[12]). - Why: prior to this version the kernel could identify which
.bootprotomanifest it was paired with (via the SHA-256 in the descriptor) but not which BOOTX64.EFI binary produced the handoff bytes. Triage paths -- ABI drift screens, rollback refusals, attestation reports, the BlackBox transcript -- could only blame "the bootloader", not a specific git commit + build time + label. The kernel-side identity is already captured by the.bootprotomanifest hash; bootloader-side parity closes the symmetry. - Producers / consumers: bootloader populates from compile-time constants in
build/boot_loader_identity.h(regenerated bytools/boot-info-manifest/gen-loader-identity.shon every build). Consumers:boot_version_render_fatal+boot_version_blackbox_transcribe(X:\Diag\boot-proto-fault.txt) andHKLM\\SYSTEM\\Boot\\Decision\\Loader{GitSha,BuildTimeLow,BuildTimeHigh,BuildLabel}registry. The persistedboot_version_faultNVRAM record was extended from 48 bytes to 112 bytes (v2) so prior-boot fault attribution captures the failing loader's identity instead of the recovery loader's; old kernels see the size mismatch and clear v2 records (one-way upgrade break, accepted). - Back-compat: a stale bootloader against a fresh kernel leaves
loader_identityzero; renderers detect the all-zerogit_sha[]sentinel (impossible for a real SHA-1) and surface "loader identity unavailable (legacy bootloader)".
v12 -- Boot-decision UNSET sentinel + per-reason policy table
- Commit: pending (re-review of Common Boot-Path Provenance and Decision Record)
- Fields added: none (semantic-only ABI change).
- Why: Codex 2026-04-30 H1 caught a phantom-NORMAL-boot bug -- the v8 layout had
BOOT_PATH_NORMAL = BOOT_REASON_NORMAL = 0, so any producer that did not populate the four boot-decision fields (e.g.multiboot2_parse.cpre-adapter wiring) passed validation as if the firmware reported a real cold boot. Fixed by introducingBOOT_PATH_UNSET = 0andBOOT_REASON_UNSET = 0as sentinels;NORMALshifts to value 1. Other enum values shift up by 1. Validator Rule 1/2 now hard-rejectsUNSETso a BSS-zero record halts instead of certifying. - Why (consistency review): Rule 5/6/7 switches default-allowed any future enum value to bypass classification, and Rule 7 was unidirectional (reason -> flag enforced; flag -> reason not). Replaced with a per-reason policy table (
reason_policy[]inboot_decision.c) indexed byenum boot_reason_code, with_Static_assertpinning length toBOOT_REASON_CODE_MAX + 1. Rule 7b now also enforces the inverse: any trigger flag set inboot_source_flagsMUST match the current reason (a producer settingRECOVERY_TRIGGEREDwhile reportingreason=NORMALis rejected as a provenance contradiction). - Producers / consumers:
bootx64.calready uses enum names so the value shift is implicit;multiboot2_parse.cnow explicitly populates the four fields withBOOT_PATH_NORMAL/BOOT_REASON_NORMAL/0u/0ubefore completing parse.
v11 -- ESP integrity fields
Adds three boot_info fields populated by the UEFI bootloader's pre-load ESP sanity gate so the kernel knows the partition was structurally validated before any code was loaded.
- Commit:
fb0c6520"boot: ESP integrity check (GPT type GUID + FAT32 BPB + required-files batch)" - TODO:
02-uefi-hardening-secureboot.md§13 - Fields added:
esp_size_mb(uint32),esp_filesystem_type(uint8 -- FAT32 / FAT16 / unknown),esp_type_guid_valid(uint8 -- 1 if the ESP partition's GPT type GUID matched the expectedC12A7328-F81F-11D2-BA4B-00A0C93EC93B). - Producer contract: bootloader runs
esp_integrity_check()beforeload_kernel(); halts viaboot_fatal()on GPT type GUID mismatch, FAT32 BPB validation failure, or any required-file (BOOTX64.EFI, kernel.exe, boot.conf) missing. On success the three fields are stamped into boot_info as a structural-validity attestation the kernel can echo into BlackBox. - Consumer contract:
boot_phase0reads the fields after header validation and surfaces them through the[BOOT-INTEGRITY]klog line. A future attestation consumer can chain them into the SRTM PCR replay alongside the v10 UKI flag. - Why: ESP corruption / partition-type drift used to surface as a confusing kernel crash mid-init when a stale BOOTX64.EFI loaded the wrong kernel.exe. Validating at the partition layer + propagating the attestation forward gives operators a definitive "the partition was structurally valid at boot time" signal in BlackBox without re-walking the FAT.
v10 -- Unified Kernel Image (UKI) provenance flag
Adds a single new flag bit to the existing boot_info.flags field. No
struct layout changes; the bump signals that consumers may now observe
BOOT_FLAG_INVOKED_VIA_UKI (1u << 3) in the flag word.
- Owning TODO: Unified Signed Boot Artifact (UKI-style)
- Mask update:
BOOT_FLAG_MASK_KNOWNextends to include the new bit, so the validator does not reject UKI-marked boot info as unknown-flag drift. - Producer contract: bootloader sets the bit when
detect_uki_sections()finds a.linuxPE section in its own LoadedImage andload_kernel()uses the embedded buffer instead of opening\\kernel.exefrom the ESP. Implies the kernel + cmdline + osrel were covered by the firmware-Secure-Boot-verified PE signature as a single signed unit. - Consumer contract: kernel attestation surfaces (
HKLM\SYSTEM\Boot\Decision, future PCR replay) read the bit to report whole-chain signature coverage vs the per-file split path.
v9 -- Anti-rollback binding + warm-kernel-update handoff ABI
Two independent ABI extensions land under v9:
- Commits:
11be3e13"boot: anti-rollback security-version binding via UEFI NVRAM" +975ef6e5"boot: warm-kernel-update handoff ABI fields and descriptor" - TODOs: §13 Anti-Rollback and Security-Version Binding + §14 Warm-Kernel-Update Handoff ABI
- Anti-rollback fields added:
flags,os_loader_security_version,required_security_version,_rollback_pad(fouruint32_tfields appended tostruct boot_infoafterboot_fallback_depth). Alsoanti_rollback_raise(1 byte taken fromboot_config._reserved[10]->_reserved[9]; boot_config total size unchanged). - Warm-update extensions: new enum value
BOOT_PAYLOAD_WARM_UPDATE_STATE=9forenum boot_payload_type, new flag bitBOOT_FLAG_WARM_UPDATEinboot_info.flags, new mmap discriminatorBOOT_MMAP_WARM_UPDATE=15, and a 6-bit continuation flag family (BOOT_WARM_UPDATE_CONT_*) carried inboot_payload_desc.flagsbits 8..13 alongside the standardBOOT_PAYLOAD_FLAG_*family. No struct field changes for the warm-update half -- ABI extension via new enum + flag values. - Anti-rollback why: bind a monotonic counter to UEFI NVRAM variable
IPOSRequiredSecVersionso a stored-but-older signedkernel.execannot boot on a machine whose policy has advanced past that version. Windows 11 shipsOsLoaderSecurityVersionin LPB; Linux uses shim+SBAT revocation. Validator:boot_rollback_validatewired fromboot_hw.cafterboot_decision_validate. Phase-3 raise hook inboot_desktop.cafterPOST16_BOOT_OK, gated onboot_config.anti_rollback_raiseopt-in, usesuefi_set_variableto advance the NVRAM counter. Never decreases. Never writes a redundant same-value. Refusal path is pre-jump bootloader halt with a UEFI fatal screen + serial diagnostic. - Warm-update why: matches the Linux 6.16 Kexec Handover ABI surface so kernel replacement on cloud / server hosts can preserve memory state across kexec. Validator:
boot_warm_update_consumereturnsACCEPTEDorCOLD_FALLBACK(fail-closed on any rejection; partial reattach would leave unreconciled subsystem state). Actual runtime live-update machinery is out-of-scope here; tracked in 03-memory-concurrency/TODO-11 Warm-Kernel-Update Runtime.
v8 -- Boot-path provenance and decision record
- Commit:
12f39619"boot: add common boot decision record" - TODO: Common Boot-Path Provenance and Decision Record
- Fields added:
boot_path,boot_reason,boot_source_flags,boot_fallback_depth(fouruint32_tfields appended tostruct boot_infoaftercaps_degraded). - Manifest: 232 fields,
struct_size = 23736bytes. - Kernel canonical SHA-256:
ec89e4588783...(produced bytools/boot-info-manifest/dump-kernel.c; kernel and mirror must agree). - Why: Give consumers (Registry / BlackBox / recovery orchestrator / attestation) one authoritative answer to "what path did this boot take and why" BEFORE they inspect per-path descriptors. Stable enums + a closed flag mask mean a consumer can trust the record rather than re-deriving it from a dozen provenance fields scattered across
boot_info. Unknownboot_path/boot_reasonhalt (stale-kernel-on-newer-loader gate). Unknown bits inboot_source_flagsalso halt -- the forward-compat tolerance that applies to capability bits does NOT apply here because every flag maps to a kernel-side policy. Validator:boot_decision_validatewired fromboot_hw.cafterboot_caps_validate.
v7 -- Capability negotiation
- Commit:
bed68e53"boot: add boot_info capability negotiation" - TODO: Capability Negotiation and Degraded-Feature Flags
- Fields added:
caps_required,caps_present,caps_degraded(threeuint64_tbitmasks appended tostruct boot_infoafterpayload_total_bytes). - Manifest: 228 fields,
struct_size = 23720bytes. - Kernel canonical SHA-256:
a44cc0c61ce7...(produced bytools/boot-info-manifest/dump-kernel.c; kernel and mirror must agree). - Why: establish a forward-compatible handshake between loader and kernel so the nine optional capabilities (
PAYLOAD_DESCRIPTORS,RUNTIME_SERVICES,SECURE_BOOT_STATE,TPM_EVENT_LOG,USB_HANDOVER,MEDIA_ROLE,NETWORK_PROVENANCE,RESUME_METADATA,ALT_PROTOCOL_ADAPTER) can be independently published OR marked degraded with a safe fallback, without requiring a version bump for every future capability bit. Unknowncaps_requiredbits are rejected (stale-kernel-on-newer-loader gate); unknown bits incaps_present/caps_degradedare tolerated so older kernels can boot against newer loaders that opportunistically populate reserved bits. Validator:boot_caps_validatewired fromboot_hw.cafterboot_payload_validate. Full bit catalog: boot-info-fields.md "Capability negotiation" -> "BOOT_CAP_* bit catalog (v7)".
v6 -- Typed payload descriptor array
- Commit:
01991083"boot: add typed payload descriptors" - TODO: Optional Payload Descriptor Array
- Fields added:
payload_descriptors[32],payload_count,payload_overflow,payload_total_bytes. - Manifest: 225 fields,
struct_size = 23696bytes. - Kernel canonical SHA-256:
eb5f035e21f5...(produced bytools/boot-info-manifest/dump-kernel.c; kernel and mirror must agree). - Why: establish the typed payload ABI that the Module and initrd Handoff Contract fills in (module, initrd, recovery_image) and that the Handoff Memory Ownership section reserves from PMM reclaim. Post-v6 hardening (2026-04-23) tightened the NONE-empty-slot invariant so the validator rejects descriptors with
type=BOOT_PAYLOAD_NONEthat carry non-zero fields; this is a validator tightening, not a layout change, so no version bump.
v5 -- Removable media detection
- Commit:
e4bd76be"boot: detect removable media via EFI_BLOCK_IO_PROTOCOL" - TODO: UEFI Hardening + Secure Boot (boot media classification work).
- Fields added: removable-media / boot partition classification flags in the boot_device area.
- Why: downstream consumers (recovery path, default drive selection) need to distinguish removable from fixed boot media before mounting.
v4 -- Boot partition GUID
- Commit:
d125a47c"boot: extract and validate boot partition GUID from device path" - Fields added:
boot_partition_guid[16],boot_partition_style(GPT vs MBR), plus related metadata. - Why: GPT-style boot media needs explicit partition identification so the kernel can locate diagnostic scratch (X:\Diag) on the correct partition and so recovery can cross-check the partition identity vs
BootOrder.
v3 -- UEFI boot variables
- Commit:
77a4823c"boot: read UEFI boot variables -- BootOrder, BootCurrent, BootNext" - Fields added:
uefi_boot_current,uefi_boot_next,uefi_boot_next_valid,uefi_boot_order[16],uefi_boot_order_count. - Why: the bootloader needs to read
BootOrder+BootCurrent+BootNextbefore ExitBootServices (they come from UEFI variable storage); surfacing them to the kernel lets higher-level boot-device debug code explain the boot entry that fired.
v2 -- Boot device type and path
- Commit:
6c3e723f"boot: pass boot device type and path in boot_info" - Fields added:
boot_device_type(enum: unknown / SATA / NVMe / USB / network),boot_device_path[128](UEFI device path in text form). - Why: the kernel needs to log which device it booted from for diagnostics and to drive the recovery-partition search.
v1 -- Initial ABI
- Commit:
24d7baa2"boot: boot_info ABI header fields and bootloader populate" - Baseline of
struct boot_infowithheader{magic, version, size}, memory map, framebuffer, UEFI config table, runtime services pointer, TPM event log pointer, USB enumeration state, timing TSC timestamps, serial port metadata, last-boot error code, and the parsedboot_configsubset. - Why: first version of the ABI. Everything since is accretion.
Rollback and compatibility
The compatibility policy is strict exact match documented in include/kernel/boot_version.h and enforced by boot_version_classify() in the kernel's Phase 0 validator. There is no downgrade adapter: a v5 bootloader paired with a v6 kernel halts at boot_phase0 with a boot_version_fault record carrying observed_version=5, expected_version=6. The fatal screen + serial log show every observed/expected field; late-boot boot_version_blackbox_transcribe() transcribes a persisted NVRAM record (when present) to X:\Diag\boot-proto-fault.txt.
When the ABI eventually reaches a stable version branch, a compatibility window (min/max version pair) can be added to boot_version_classify without disrupting the fatal-rendering or transcription paths. Until then, rebuilding both halves with bash scripts/build.sh is the canonical response to any version mismatch.
How to add a new version
- Pick the next integer after the current
BOOT_INFO_VERSION. - Update BOTH
include/kernel/boot_info.hANDsrc/boot/uefi/boot_info_mirror.hin the same commit. Both must carry the same new value. - Add or modify fields. Update every
_Static_assertthat pins an offset. Re-runmake boot-info-abito regenerate the manifest. - Open the owning TODO section and list the new fields under a Notes block with the committing hash.
- Add a new
### v<N>heading at the top of this file with the row shape above. Keep the list newest first. - Commit. The next push lands both the code change and the changelog row together; reviewers see one atomic unit of ABI evolution.