ProductsLamBoot › Architecture

Architecture

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

LamBoot is organized in three concentric layers: a core bootloader (~215 KB) that holds the essential boot flow, loadable EFI modules for advanced features (diagnostics, network management), and a host-side toolkit for administration. The boundary is explicit: the core ships as a single polished binary, modules are independent EFI applications, and tools live on the host OS alongside the ESP.

This page walks through the architecture top-down: the 10-phase boot flow, the subsystem map, the data protocols between layers, and the memory / security models that underpin the whole thing.

LAYER OVERVIEW

Core + modules + tools

┌──────────────────────────────────────────────────────────────────┐
│  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.8.3 — JSON-lines audit log on ESP
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. Truncated per boot in v0.8.3; append-mode with crypto signatures in v0.9.x (Path G). 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.