ProductsLamBoot › Architecture

Architecture

A 10-phase boot flow, core + loadable modules, and the data models that make it auditable

Every module in LamBoot declares its layer. The bootloader is divided into 8 layers, each with a single responsibility. Higher layers build on lower; dependencies never flow the other way. A separate Trust & Audit rail records every decision to a JSON log on disk — append-only, never consulted as control flow.

This discipline is why LamBoot is ~8,300 lines of Rust instead of 40,000+ lines of C, and why every new feature slots cleanly into one existing layer rather than cutting across several.

7
Orchestration
The conductor — composes the rest
main · discovery · boot
6
Presentation
GUI, serial console, input dispatch
gui · console · input
4
Policy & State
Config-driven rules + NVRAM state
policy · health · autodiscovery · preflight
3
Content Parsers
Pure bytes-to-structures, no I/O
bls · uki · policy · pe_loader (v0.9+)
2
Filesystem Abstraction
Uniform read API across FAT, ext4, Btrfs (future)
fs_backend · fat · ext4 (v0.9+)
1
UEFI Firmware Boundary
All UEFI protocol calls live here
fs · partitions · tpm · secure · drivers · initrd
0
Platform Introspection
Read-only discovery of hardware / firmware context
acpi · hypervisor · smbios · fw_cfg
5
Trust &
Audit
append-only rail
trust_log
bootlog
report
telemetry
write-only
from any layer
↓ dependencies flow down · higher layers use lower → writes flow to Trust & Audit · nothing reads from it

Path G (shipped in v0.9.0) added a native read-only ext4 reader on Layer 2 (on top of the ext4-view Rust crate), a native PE loader on Layer 3 (on top of goblin), and a native trust chain. The forward Layer-2 work is native btrfs/xfs read backends. See the roadmap.

PER-LAYER DETAIL

Each layer, in depth

Layer 0 — Platform Introspection

Pure-read discovery of the environment we’re running on. No side effects, no trust decisions, no user interaction. Modules: acpi.rs (ACPI DMAR/IVRS for IOMMU detection), hypervisor.rs (CPUID-based hypervisor detection), smbios.rs (SMBIOS for VM identification and fleet tags), fw_cfg.rs (QEMU fw_cfg device access). Rule: Layer 0 may not import from Layer 1+ — platform introspection must be pure.

Layer 1 — UEFI Firmware Boundary

Everything that touches UEFI protocols directly. Every firmware-facing call belongs here. No policy, no parsing, no UI. Modules: fs.rs (ESP + volume enumeration), partitions.rs (GPT walk, PartitionInfo, XBOOTLDR), tpm.rs (TCG2 protocol), secure.rs (Secure Boot state query), drivers.rs (legacy UEFI FS driver LoadImage path), security_override.rs (Security2Arch/SecurityArch hooks), initrd.rs (LINUX_EFI_INITRD_MEDIA_GUID LoadFile2 provider).

Layer 2 — Block I/O + Filesystem Abstraction (shipped in v0.9.0; native btrfs/xfs are v1.x)

A filesystem-agnostic read API on top of Layer 1. Consumers above this layer don’t know if they’re reading FAT, ext4, Btrfs, or anything else. fs_backend.rs (trait FsBackend { read, exists, read_dir, metadata }), fs_backend_fat.rs (FAT adapter via uefi-rs SimpleFileSystem), fs_backend_ext4.rs (ext4 adapter via the ext4-view crate — read-only by design, backed by language + crate guarantees). fs_backend_btrfs.rs is a v1.1+ community-contribution target.

Layer 3 — Content / Format Parsers

Pure parsers — bytes in, structured data out. No I/O, no firmware calls, no state. Modules: bls.rs (BLS Type 1), uki.rs (UKI PE section parser: .osrel, .cmdline, .linux), policy.rs (TOML parser half), pe_loader.rs (native PE header + section / relocation planning on top of goblin — new in v1.0).

Layer 4 — Policy & State

Config-driven decisions and persistent state. Reads Layer 3 outputs + Layer 0/1 signals to make rules-based decisions. Modules: policy.rs (policy-application half — allowlist/denylist/fallback), health.rs (NVRAM state machine Fresh→Booting→BootedOK/CrashLoop), autodiscovery.rs (entry pipeline config), preflight.rs (validates entries — files present, signatures where applicable).

Layer 5 — Trust & Audit (cross-cutting rail)

Cross-cutting append-only record of decisions. Every layer above can record here; nothing depends on its state. Modules: trust_log.rs (\loader\boot-trust.log), bootlog.rs (\EFI\LamBoot\reports\boot.log), report.rs (\EFI\LamBoot\reports\audit.log), telemetry.rs (per-phase timing). Rule: Layer 5 is written-to from above via &mut TrustLog, never read as control flow.

Layer 6 — Presentation

Everything the user sees or types. Modules: gui.rs (GOP double-buffered menu, cursor, mouse), console.rs (serial/text-mode fallback), input.rs (keyboard + pointer dispatch).

Layer 7 — Orchestration

The conductor. Assembles the 10-phase boot flow from the layers below. Nothing else depends on Layer 7. It is the top. Modules: main.rs (10-phase orchestration), discovery.rs (aggregates entries across Layer 2 backends + Layer 3 parsers), boot.rs (chainload / UKI / native-PE / legacy-LoadImage dispatch).

Current module counts & LoC totals

LayerModulesLoC (approx)
0 — Platform41,008
1 — UEFI71,573
2 — FS abstraction1 → 4+ planned249 → ~1,200+
3 — Parsers3 → 4 planned~1,114 → ~1,800
4 — Policy41,182
5 — Audit4577
6 — UI31,529
7 — Orchestration3~1,110
Total28 → 36+~8,292 → ~12,000

Medium-sized by bootloader standards: GRUB ~40k LoC of C, systemd-boot ~10k LoC of C, rEFInd ~30k LoC of C++. LamBoot remains smaller than all of them with Path G landed in v0.9.0 — a deliberate property, not an accident.

DEPLOYMENT TOPOLOGY

Where the pieces live at runtime

Distinct axis from the code layers above: this is the physical deployment (host OS → ESP → firmware). The 8-layer code architecture sits inside lambootx64.efi on the ESP.

┌──────────────────────────────────────────────────────────────────┐
│  Host OS — /usr/local/bin/                                       │
│                                                                  │
│    lamboot-diagnose     lamboot-esp         lamboot-backup       │
│    lamboot-repair       lamboot-migrate     lamboot-monitor.py   │
│              (bash CLI toolkit; runs post-boot)                  │
└────────────────────┬─────────────────────────────────────────────┘
                     │  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         │
│        lamboot-gui.efi           (integrated in core today)      │
│        diag-shell.efi            diagnostic modules              │
│        nvme-diag.efi                                             │
│        mem-test.efi                                              │
│        net-agent.efi             ← network management (roadmap)  │
│      drivers\                                                    │
│        ext4_x64.efi, btrfs_x64.efi, xfs_x64.efi, ...             │
│      reports\                ← boot report JSONs                 │
│      boot-trust.log          ← audit trail (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  │
└──────────────────────────────────────────────────────────────────┘
CORE / MODULE BOUNDARY

Why it matters that the core is separable

The architectural decision to keep the core small and push advanced features into loadable EFI binaries is load-bearing. It produces properties a monolithic design (GRUB) can’t.

What the core does

  • — 10-phase boot flow
  • — BLS Type 1 + UKI discovery
  • — Filesystem driver loading under SecurityOverride
  • — NVRAM state machine
  • — TPM measurements (PCR 4/5/12)
  • — Trust-evidence log writer
  • — GUI + serial fallback menu
  • — LoadFile2 initrd delivery
  • — Crash-loop fallback selection

What modules do

  • — Diagnostic suites (NVMe SMART, memory test, PCI)
  • — Hardware inventory dumping
  • — Network management API (roadmap)
  • — Interactive diagnostic shell
  • — Any chainloadable EFI application

No special ABI — just standard UEFI apps. State-sharing is via NVRAM variables or UEFI protocols.

The core has text-only and no-usb build-time feature gates for tight-binary scenarios (strip GUI → ~50 KB). Everything above that is a module, not a compile-time switch.

BOOT FLOW

The 10 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.
    LoadImage + StartImage under SecurityOverride (Path F).
    ConnectController(recursive=true) on all handles.

 6. Enumerate volumes
    find_handles::() → all FS handles
    (ESP + newly-accessible ext4/btrfs/xfs/zfs/ntfs/f2fs).

 7. Discover boot entries
    BLS Type 1 /loader/entries/*.conf — parse 14 fields each.
    ESP fallback: Windows, UKI (\EFI\Linux\*.efi), GRUB, rEFInd.
    Sort: bad-entries-last → sort-key → machine-id → version (UAPI.10).
    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 UTF-16 → PCR 12.
    Register initrd via LoadFile2 (LINUX_EFI_INITRD_MEDIA_GUID).
    Flush trust-evidence log.
    start_image(kernel) under SecurityOverride.
    If kernel returns: mark_boot_success(), cleanup initrd handle.
SUBSYSTEM MAP

lamboot-core crates

lamboot-core/src/ layout
main.rs                Orchestration — the 10-phase boot flow
security_override.rs   Path F — Security/Security2 arch protocol hooks
trust_log.rs           v0.9.0 — JSON-lines audit log on ESP, append-mode with per-image SHA-256
bls.rs                 BLS Type 1 parser, UAPI.10 sort, boot counting
gui.rs                 Double-buffered framebuffer, VGA font, boot menu, mouse
discovery.rs           BLS-first entry discovery, ESP fallback, UKI detection
policy.rs              Section-aware TOML parser for policy.toml
health.rs              NVRAM state machine, Boot Loader Interface vars
fs.rs                  ESP/volume mounting, file I/O, multi-partition scan
initrd.rs              LoadFile2 provider (LINUX_EFI_INITRD_MEDIA_GUID)
boot.rs                Chainload, UKI, Linux boot under SecurityOverride
input.rs               Keyboard + mouse input dispatch
tpm.rs                 TPM 2.0 measured boot (TCG2 protocol)
console.rs             Serial/text console fallback menu
drivers.rs             EFI filesystem driver loader, records trust events
secure.rs              Secure Boot state detection + shim integration
report.rs              Boot reports and audit logging with timestamps

3,500 lines total. #![no_std], #![no_main]. Explicit unsafe only around UEFI protocol FFI; every unsafe block carries a SAFETY: comment.

DATA PROTOCOLS

How the layers talk to each other

Instead of private ABIs, LamBoot uses boring, documented standards at every interface. That’s what makes the system auditable.

UEFI NVRAM variables (core ↔ host)

LamBoot vendor GUID 4C414D42-4F4F-5400-0000-000000000001. All variables BOOTSERVICE_ACCESS | RUNTIME_ACCESS so the running OS (and the Proxmox host, for a VM) can read/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)
  • ShimRetainProtocol (u8) — asks shim to leave ShimLock installed across kernel boot

Plus the systemd Boot Loader Interface variables (LoaderInfo / LoaderEntrySelected / LoaderBootCountPath / LoaderConfigTimeout) for bootctl and systemd-bless-boot compatibility.

JSON trust-evidence log (core → host)

\loader\boot-trust.log on the ESP. One JSON object per line. Append-mode with per-image SHA-256 in v0.9.0; per-event crypto signing on the v0.9.x polish track. See the security page for the schema.

TPM measurements (core → attestation)

Kernel Authenticode hash → PCR 4 (EFI_BOOT_SERVICES_APPLICATION); policy.toml → PCR 5 (IPL); UTF-16 cmdline → PCR 12 (IPL). Uses hash_log_extend_event for TCG event log entries. Gracefully degrades when TPM is absent.

LoadFile2 initrd protocol (core → kernel)

Kernel 5.7+ discovers initrd via LINUX_EFI_INITRD_MEDIA_GUID on a synthetic device path. LamBoot installs LoadFile2Protocol; the kernel calls it with NULL buffer (asks for size), then again with allocated buffer (receives data). RAII cleanup via Rust Drop trait ensures protocol uninstallation even on early returns.

DriverBinding pattern (core → firmware)

Filesystem drivers loaded via standard UEFI LoadImage + StartImage; drivers self-register DriverBindingProtocol. LamBoot then calls ConnectController(recursive=true) on every handle — the firmware matches drivers to devices automatically. No manual driver-to-device mapping.

ENTRY DISCOVERY

BLS Type 1 + UKI, sorted UAPI.10

The sort algorithm implements the full UAPI Group spec. Four tiers, applied in order:

Tier Rule
1Boot count state: bad entries (tries_left == 0) sort LAST
2Sort-key presence: entries WITH sort-key sort BEFORE entries without
3Multi-field: sort-key asc → machine-id asc → version DESC (UAPI.10 — newest first)
4Filename fallback: entry ID DESC (UAPI.10)

UAPI.10 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 sorts lower than lowercase, and skips _ and + separators.

MEMORY MODEL

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> sized width * height (~8 MB at 1920×1080).
  • Initrd: Box<[u8]> leaked via Box::into_raw() for stable addresses during the kernel’s LoadFile2 callback; reclaimed by the Drop impl when the initrd handle is torn down.
  • Fonts: Terminus Bold 16px (8×16, 4 KB) and 32px (16×32, 16 KB) bitmap fonts compiled into .rodata.
  • No heap fragmentation: UEFI apps run single-threaded with a flat memory model. The bootloader calls ExitBootServices before the kernel; all UEFI memory is reclaimed.

Read the source

3,500 lines. Documented unsafe. Subsystem names are verbs and nouns, not managers and processors.