ProductsLamBoot › Architecture

Architecture

For readers who want the depth: eight layers, a ten-phase boot flow, and the data models that make it auditable

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.

7
Orchestration
The conductor. Composes the rest.
main · discovery · boot
6
Presentation
Graphical menu, serial console, input.
gui · console
4
Policy and State
Config-driven rules and NVRAM state.
policy · health · partitions · drivers · bls
3
Parsers and Shared Types
Pure bytes to structures, no I/O.
uki · pe_loader · bls_parse · boot_types
2
Storage and Filesystems
Uniform read API across FAT, ext4, and btrfs, including on LVM.
fs_backend · fat · ext4 · btrfs · lvm
1
Firmware Boundary
All UEFI protocol calls live here.
security_override · tpm · firmware_quirks
0
Platform Introspection
Read-only discovery of hardware and firmware context.
acpi · hypervisor · smbios · fw_cfg · secure · input
5
Trust and
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 and Audit. Nothing reads from it.

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.

PER-LAYER DETAIL

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.

DEPLOYMENT TOPOLOGY

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.

CORE / MODULE BOUNDARY

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.

BOOT FLOW

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.
SUBSYSTEM MAP

Representative lamboot-core modules

lamboot-core/src/ (representative)
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.

RUNTIME INTERFACES

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.

ENTRY DISCOVERY

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
1Boot count state: bad entries (tries_left == 0) sort last.
2Sort-key presence: entries with a sort-key sort before entries without.
3Multi-field: sort-key ascending, then machine-id ascending, then version descending (newest first).
4Filename 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.

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 (about 8 MB at 1920×1080).
  • Initrd: Box<[u8]> leaked via Box::into_raw() for stable addresses during the kernel's LoadFile2 callback, then reclaimed by the Drop impl 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 ExitBootServices before 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.