LamBoot is about 16,000 lines of Rust across 46 modules, #![no_std], organized into eight layers with one-way dependencies. Every module declares its layer in a source doc comment. Higher layers build on lower, and dependencies never flow the other way. A separate Trust and Audit rail records every decision to a JSON log on disk, append-only, never consulted as control flow.
This is not a convention. A layer-contract checker runs in CI and fails the build if any module mis-declares its layer or a dependency points the wrong way up the stack. The clean architecture is verified on every commit, not asserted. It is also why LamBoot is about 16,000 lines of Rust instead of 40,000 lines of C, and why every new feature slots into one existing layer rather than cutting across several.
Audit
from any layer
Layer 2 reads ext4, btrfs, and FAT natively, including those filesystems on LVM, in memory-safe Rust compiled into the loader. Layer 3 carries a native PE loader, so LamBoot verifies and loads the kernel itself instead of handing off to firmware LoadImage. Together they remove the last firmware dependency in the /boot read path. See the roadmap for the native XFS backend that follows.
Each layer, in depth
Layer 0, Platform Introspection
Pure-read discovery of the environment LamBoot is running on. No side effects, no trust decisions, no user interaction. Modules: acpi (ACPI tables for IOMMU detection), hypervisor (CPUID-based hypervisor detection), smbios (SMBIOS for VM identification and fleet tags), fw_cfg and fw_cfg_config (QEMU fw_cfg device access and the opt/lamboot/config identity channel), secure (Secure Boot state query), input (raw input source). The rule: Layer 0 may not import from Layer 1 and above. Platform introspection stays pure.
Layer 1, Firmware Boundary
Everything that touches UEFI protocols directly. Every firmware-facing call belongs here. No policy, no parsing, no UI. Modules: security_override (the Security2Arch and SecurityArch hooks, Path F), tpm (TCG2 protocol), firmware_quirks (per-firmware workarounds).
Layer 2, Storage and Filesystems (native ext4, btrfs, FAT, including on LVM)
A filesystem-agnostic read API on top of Layer 1. Consumers above this layer do not know whether they are reading FAT, ext4, or btrfs. fs_backend defines the trait; fs_backend_fat, fs_backend_ext4, and fs_backend_btrfs are the native read backends; fs_backend_lvm, fs_backend_lvm_btrfs, and fs_backend_lvm_dispatch read those filesystems in place on LVM. fs handles ESP and volume mounting; initrd is the LoadFile2 provider. Reading is in memory-safe Rust, backed by language and crate guarantees.
Layer 3, Parsers and Shared Types
Pure parsers and shared types: bytes in, structured data out. No I/O, no firmware calls, no state. Modules: bls_parse (BLS Type 1), uki (UKI PE section parser for .osrel, .cmdline, .linux), pe_loader and pe_loader_pure (native PE header, section, and relocation planning), discovery_pure, and boot_types.
Layer 4, Policy and State
Config-driven decisions and persistent state. Reads Layer 3 outputs and Layer 0 and 1 signals to make rules-based decisions. Modules: policy (allowlist, denylist, fallback), health (the NVRAM state machine, Fresh to Booting to BootedOK or CrashLoop), autodiscovery (the entry pipeline), preflight (validates entries: files present, signatures where applicable), partitions (the GPT walk), drivers (legacy UEFI FS driver loading), and bls.
Layer 5, Trust and Audit (cross-cutting rail)
Cross-cutting append-only records of decisions. Every layer above can write here, and nothing depends on its state. The trust-evidence log lives here. Modules: trust_log and trust_log_pure (\loader\boot-trust.log), bootlog and report (boot reports under \EFI\LamBoot\reports\), telemetry (per-phase timing), diag, and version. The rule: Layer 5 is written to from above, never read as control flow.
Layer 6, Presentation
Everything the user sees or types. Modules: gui (the GOP double-buffered menu, cursor, and mouse) and console (the serial and text-mode fallback).
Layer 7, Orchestration
The conductor. It assembles the ten-phase boot flow from the layers below, and nothing else depends on it. Modules: main (the ten-phase orchestration), discovery (aggregates entries across Layer 2 backends and Layer 3 parsers), and boot (chainload, UKI, native-PE, and legacy-LoadImage dispatch).
Size, in context
About 16,000 lines of Rust across 46 modules in eight CI-enforced layers. Medium-sized by bootloader standards: GRUB is about 40,000 lines of C, rEFInd about 30,000 lines of C, and systemd-boot about 10,000 lines of C. LamBoot is smaller than GRUB and rEFInd, in a memory-safe language, and that is a deliberate property rather than an accident.
Where the pieces live at runtime
A distinct axis from the code layers above: this is the physical deployment, from the host OS to the ESP to the firmware. The eight-layer code architecture sits inside lambootx64.efi on the ESP.
┌──────────────────────────────────────────────────────────────────┐
│ Host OS │
│ lamboot-tools (a separate companion project): host-side │
│ boot-health monitoring and ESP tooling, run post-boot. │
│ Reads the ESP, OVMF_VARS, and UEFI variables. │
└────────────────────┬─────────────────────────────────────────────┘
│ reads/writes ESP, OVMF_VARS, UEFI vars
▼
┌──────────────────────────────────────────────────────────────────┐
│ EFI System Partition │
│ \EFI\LamBoot\ │
│ lambootx64.efi ← core bootloader │
│ policy.toml ← measured into PCR 5 │
│ modules\ ← loadable EFI applications │
│ diag-shell.efi interactive diagnostic shell │
│ pci-inventory.efi PCI device inventory │
│ mem-quick.efi quick memory check │
│ drivers\ │
│ btrfs_x64.efi, xfs_x64.efi, ... (legacy FS fallback) │
│ reports\ ← boot report JSONs │
│ boot-trust.log ← trust-evidence log (per boot) │
│ │
│ \loader\entries\ ← BLS Type 1 entries │
│ \EFI\Linux\*.efi ← Unified Kernel Images │
└────────────────────┬─────────────────────────────────────────────┘
│ firmware loads lambootx64.efi
▼
┌──────────────────────────────────────────────────────────────────┐
│ UEFI firmware (EDK II / AMI / Phoenix / Insyde) │
│ Secure Boot (optional), TCG2 protocol, SimpleFileSystem, GOP │
└──────────────────────────────────────────────────────────────────┘
The diagnostic modules working today are diag-shell, pci-inventory, and mem-quick. Native ext4, btrfs, and FAT reading is built into the core, so legacy UEFI filesystem drivers are installed only for a /boot filesystem the core does not natively cover.
Why it matters that the core is separable
Keeping the core small and pushing advanced features into loadable EFI binaries is load-bearing. It produces properties a monolithic design like GRUB cannot.
What the core does
- The ten-phase boot flow.
- BLS Type 1 and UKI discovery.
- Native ext4, btrfs, and FAT reading, including on LVM.
- The native PE loader for the kernel.
- The NVRAM state machine.
- TPM measurements (PCR 4, 5, 12).
- The trust-evidence log writer.
- The graphical menu and serial fallback.
- LoadFile2 initrd delivery and crash-loop fallback selection.
What modules do
- An interactive diagnostic shell (diag-shell).
- PCI device inventory (pci-inventory).
- A quick memory check (mem-quick).
- Any chainloadable EFI application.
No special ABI: just standard UEFI apps. State-sharing is via NVRAM variables or UEFI protocols.
The core has build-time feature gates for tight-binary scenarios. Everything above that is a module, not a compile-time switch.
The ten phases
Ordered. Each phase has a single responsibility, produces structured output, and logs outcomes to the trust-evidence log where applicable.
UEFI firmware → lambootx64.efi entry
1. Health assessment
Read prev BootState from NVRAM; increment crash counter if prev=Booting.
Set state=Booting, timestamp, Boot Loader Interface vars.
2. Security initialization
Read SecureBoot EFI variable; check ShimLock protocol.
Initialize TPM context (TCG2); log Secure Boot state.
3. Mount ESP
LoadedImage → device handle → SimpleFileSystem → volume root.
4. Load policy
Parse \EFI\LamBoot\policy.toml (section-aware TOML).
On failure: defaults (4s timeout, crash threshold 2).
Measure policy bytes into TPM PCR 5.
5. Load filesystem drivers
Scan \EFI\LamBoot\drivers\*.efi for anything the core does not read natively.
LoadImage + StartImage under SecurityOverride (Path F).
ConnectController(recursive=true) on all handles.
6. Enumerate volumes
find_handles::<SimpleFileSystem>() → all FS handles
(ESP + native ext4/btrfs/FAT, including on LVM).
7. Discover boot entries
BLS Type 1 /loader/entries/*.conf, parse each field.
ESP fallback: Windows, UKI (\EFI\Linux\*.efi), GRUB, rEFInd.
Sort: bad-entries-last → sort-key → machine-id → version (UAPI).
Deduplicate by path; BLS takes precedence.
8. Crash-loop check
If crash_counter >= threshold: select fallback entry from policy.
Else: fall through to menu.
9. Interactive menu
GOP: double-buffered graphical menu, mouse + keyboard.
Else: serial/text console menu.
Auto-boot on timeout (disabled in crash-loop).
F2 = Reboot to Firmware, F12 = cold reboot.
10. Boot handoff
Record entry to NVRAM (LamBootLastEntry, LoaderEntrySelected).
Write \EFI\LamBoot\reports\boot.json.
If boot-counted entry: decrement tries_left, rename .conf.
Measure kernel Authenticode hash → PCR 4.
Measure cmdline → PCR 12.
Register initrd via LoadFile2 (LINUX_EFI_INITRD_MEDIA_GUID).
Flush trust-evidence log.
Load and start the kernel via the native PE loader, under SecurityOverride.
If kernel returns: mark_boot_success(), cleanup initrd handle.
Representative lamboot-core modules
main Orchestration: the ten-phase boot flow
boot Chainload, UKI, native-PE, legacy-LoadImage dispatch
discovery BLS-first entry discovery, ESP fallback, UKI detection
security_override Path F: Security and Security2 arch protocol hooks
trust_log JSON-lines trust-evidence log on the ESP
bls / bls_parse BLS Type 1 parsing, UAPI sort, boot counting
uki UKI PE section parser (.osrel, .cmdline, .linux)
pe_loader Native PE header, section, and relocation loader
gui Double-buffered framebuffer, boot menu, mouse
policy Section-aware policy.toml application
health NVRAM state machine, Boot Loader Interface vars
fs / fs_backend_* ESP and volume mounting, native ext4/btrfs/FAT, LVM
initrd LoadFile2 provider (LINUX_EFI_INITRD_MEDIA_GUID)
tpm TPM 2.0 measured boot (TCG2 protocol)
console Serial and text console fallback menu
report Boot reports and audit logging with timestamps
About 16,000 lines across 46 modules. #![no_std], #![no_main]. Explicit unsafe only around UEFI protocol FFI, and every unsafe block carries a SAFETY: comment.
How the layers talk to each other
Instead of private ABIs, LamBoot uses documented standards at every interface. That is what makes the system auditable.
UEFI NVRAM variables (core and host)
LamBoot vendor GUID 4C414D42-4F4F-5400-0000-000000000001. All variables are BOOTSERVICE_ACCESS | RUNTIME_ACCESS, so the running OS, and the Proxmox host for a VM, can read and write them.
- LamBootState (u8): 0=Fresh, 1=Booting, 2=BootedOK, 3=CrashLoop
- LamBootCrashCount (u8)
- LamBootLastEntry (UTF-8 string)
- LamBootTimestamp (8 bytes, packed UTC)
- LamBootVersion (u32, packed major.minor.patch)
Plus the systemd Boot Loader Interface variables (LoaderInfo, LoaderEntrySelected, LoaderBootCountPath, LoaderConfigTimeout) for bootctl and systemd-bless-boot compatibility.
JSON trust-evidence log (core to host)
\loader\boot-trust.log on the ESP, one JSON object per line, with a per-image SHA-256 written for each verified image. See the Security page for the schema.
TPM measurements (core to attestation)
Kernel Authenticode hash into PCR 4 (EFI_BOOT_SERVICES_APPLICATION), policy.toml into PCR 5 (IPL), and the kernel command line into PCR 12 (IPL). It uses hash_log_extend_event for TCG event log entries, and degrades gracefully when no TPM is present.
LoadFile2 initrd protocol (core to kernel)
Kernel 5.7 and newer discovers the initrd via LINUX_EFI_INITRD_MEDIA_GUID on a synthetic device path. LamBoot installs LoadFile2Protocol, the kernel calls it with a NULL buffer to ask for size, then again with an allocated buffer to receive data. RAII cleanup via Rust's Drop trait ensures the protocol is uninstalled even on early returns.
DriverBinding pattern (core to firmware)
Legacy filesystem drivers, for any /boot filesystem the core does not read natively, are loaded via standard UEFI LoadImage and StartImage, and self-register DriverBindingProtocol. LamBoot then calls ConnectController(recursive=true) on every handle, and the firmware matches drivers to devices automatically.
BLS Type 1 and UKI, sorted by the UAPI rules
The sort algorithm implements the full UAPI Group spec. Four tiers, applied in order:
| Tier | Rule |
|---|---|
| 1 | Boot count state: bad entries (tries_left == 0) sort last. |
| 2 | Sort-key presence: entries with a sort-key sort before entries without. |
| 3 | Multi-field: sort-key ascending, then machine-id ascending, then version descending (newest first). |
| 4 | Filename fallback: entry ID descending. |
UAPI version comparison handles pre-release (1.0~rc1 < 1.0), post-release (1.0 < 1.0^post1), numeric segments as integers with stripped leading zeros, alphabetic uppercase sorting lower than lowercase, and skips the _ and + separators.
How allocation works under UEFI
LamBoot uses UEFI Boot Services pool allocation via Rust's alloc crate (enabled by the global_allocator feature of uefi-rs). Specifics:
- Framebuffer:
Vec<BltPixel>sizedwidth * height(about 8 MB at 1920×1080). - Initrd:
Box<[u8]>leaked viaBox::into_raw()for stable addresses during the kernel's LoadFile2 callback, then reclaimed by theDropimpl when the initrd handle is torn down. - Fonts: bitmap fonts compiled into
.rodata. - No heap fragmentation: UEFI apps run single-threaded with a flat memory model. The bootloader calls
ExitBootServicesbefore the kernel, and all UEFI memory is reclaimed.
Read the source
About 16,000 lines across 46 modules. Documented unsafe. Subsystem names are verbs and nouns.