The EriX bootloader — a minimal, security-focused bootloader that currently targets UEFI on x86_64 and loads/verifies boot.img files.
  • Rust 90.6%
  • Python 5.2%
  • Shell 4.1%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Erik Inkinen d99729f743
All checks were successful
CI / markdown (push) Successful in 14s
CI / test (push) Successful in 1m20s
chore: Merge native CLI development into main
Merge the selected feature/native-cli history with an explicit two-parent commit so main retains the development lineage and the validated source snapshot. The resulting tree is identical to the selected feature commit; no dependency pins or runtime behavior are changed by this merge.

Previous main: 80daeea3a7
Selected feature: 55f2e5295a

Publish this integration point following the requested cross-repository merge. Preserve the feature branch and immutable dependency objects for reproducibility; do not squash, rebase or rewrite existing commits.
2026-09-12 08:28:40 +03:00
.cargo Implement QEMU integration testing and enhance build scripts 2026-02-26 13:36:41 +02:00
.github fix: Pin boot-image fixture tooling to exact source commits 2026-09-12 08:08:32 +03:00
scripts fix: Pin boot-image fixture tooling to exact source commits 2026-09-12 08:08:32 +03:00
src fix: Clear release scanout before framebuffer handoff 2026-09-07 23:43:25 +03:00
tests fix: Pin boot-image fixture tooling to exact source commits 2026-09-12 08:08:32 +03:00
.editorconfig Initial commit 2026-02-26 11:11:41 +01:00
.gitignore Ignore local .ci workspace 2026-04-15 21:52:34 +03:00
.markdownlint-cli2.yaml Tighten CI markdown policy 2026-05-22 15:09:52 +03:00
ARCHITECTURE.md fix: Pin boot-image fixture tooling to exact source commits 2026-09-12 08:08:32 +03:00
Cargo.toml build: Pin dependency and CI helper source commits 2026-09-12 07:35:03 +03:00
CODE_OF_CONDUCT.md docs: Synchronize shared contribution and review policies 2026-09-12 06:38:07 +03:00
CONTRIBUTING.md build: Pin dependency and CI helper source commits 2026-09-12 07:35:03 +03:00
LICENSE Initial commit 2026-02-26 11:11:41 +01:00
Makefile Remove bootloader VM harness 2026-05-22 15:46:05 +03:00
README.md fix: Pin boot-image fixture tooling to exact source commits 2026-09-12 08:08:32 +03:00
ROADMAP.md fix: Pin boot-image fixture tooling to exact source commits 2026-09-12 08:08:32 +03:00
rustfmt.toml bootloader: drop unstable rustfmt options and apply stable formatting 2026-03-23 10:19:50 +02:00
SECURITY.md docs: Synchronize shared contribution and review policies 2026-09-12 06:38:07 +03:00

bootloader

The EriX bootloader is a minimal, security-focused bootloader that currently targets UEFI on x86_64 and loads/verifies boot.img artifacts.

EriX is a clean-room, capability-based microkernel operating system written entirely in Rust.

Technical requirements are tracked in the EriX requirements, conventions, and project documentation.

See:

  • docs for design documents, specifications, and development plans.
  • Related architecture repositories for kernel, services, libraries, drivers, and integration tooling.

Purpose of This Repository

This repository implements the EriX bootloader component. Its purpose in EriX is to verify boot-critical payloads and prepare the initial kernel handoff.

Functionally, it loads the signed boot image, validates payload metadata, prepares memory state, and transfers control to the kernel. The repository keeps the implementation, interface contracts, tests, and documentation for that behavior in one reviewable ownership boundary.

The maintained responsibilities are:

  • load and validate the signed boot image before transferring control to the kernel
  • preserve the boot-time handoff contract expected by the kernel and early services
  • keep platform setup deterministic and limited to boot ownership

Clean-Room Policy

EriX follows a strict clean-room philosophy:

  • No external source code may be copied.
  • No external Rust crates are allowed.
  • No code generation tools that embed third-party code.
  • All code must be authored within the project.

Violations will result in rejection of the contribution.

License

All EriX repositories are licensed under the ISC License.

Development Model

EriX development is modular, deterministic, reproducible, authority-explicit, security-first, and self-hosting oriented.

This repository follows the project roadmap and the validation rules documented in its own roadmap.

Dependencies

  • lib-bootimg for boot.img parsing/verification
  • lib-elf for ELF64 parsing
  • lib-handoff for handoff schema types
  • lib-dynlink for early dynamic-kernel metadata constants and relocation policy alignment
  • lib-sha2 for boot-store object hash verification

No external Rust crates are used.

Build and Test

cargo test --all-features
make build-uefi
BOOTIMG_SIGNING_KEY=/secure/path/signing-key.pem \
BOOTIMG_PUBLIC_KEY_HEX_FILE=/secure/path/signing-key.pub.hex \
BOOTIMG_KEY_ID=7 \
  make package-esp

make package-esp expects a signed boot.img fixture at out/fixtures/minimal-boot.img. If it is missing, scripts/package-esp.sh invokes scripts/build-bootimg-fixture.sh, which expects a kernel ELF fixture at out/fixtures/kernel.elf or the KERNEL_ELF path supplied by the caller. The fixture builder also requires the caller to select an Ed25519 private key, the matching raw public-key hex file, and its u32 key ID through the three BOOTIMG_* variables above. Relative key paths are resolved from this repository root. The script never discovers or chooses signing authority; it authenticates the completed image with the supplied public key before returning. The keys under tests/keys are test fixtures and are not production trust roots.

Fixture tooling requires Python 3 and Git. scripts/prepare-boot-tool.py records the default full boot-tool commit; BOOT_TOOL_REVISION may select another reviewed full 40-character lowercase commit. A sibling repository supplies only original Git objects, never its current branch or worktree bytes. The builder uses a clean detached .ci/boot-tool/<revision> checkout and private Cargo output. BOOT_TOOL_SOURCE may select an explicit Git transport source without changing the required identity. Dirty private checkouts are rejected, not reset. The private Cargo home excludes path patches so tracked lockfiles retain their exact Git identities. BOOT_TOOL_GIT_CONFIG_GLOBAL, or git-url-rewrites.conf under an explicit BOOT_TOOL_CARGO_HOME, supplies transport-only configuration; the latter's Cargo configuration and source substitutions are not imported.

The cross-repository integration repository owns boot execution scenarios and virtual-machine topology.

Status

Implemented baseline:

  • boot.img load/parse/verify path
  • allocation-free ELF extraction and validated program-header iteration
  • dynamic-kernel boot-store validation and relocation path for the signed dynlink-store and dynlink-early sections
  • dynamic-kernel validation of the real ld.lld dynamic tags used by the kernel and shared-object relink path, including eager -Bsymbolic -z now flags, DT_SONAME, .rela.plt, and bounded DT_RELACOUNT
  • dynamic-kernel import resolution from validated direct/transitive shared objects, scoped to declared dependency edges with only approved kernel/runtime exports available to shared objects
  • streaming application of both relative and symbol-bearing dynamic-kernel relocations without an independent planning cap
  • relocation of loaded kernel shared objects before entry, including declared object-graph exports and kernel-provided runtime helper symbols
  • verified dynamic boot catalog emission for every signed boot-image dynamic executable/shared object, segment, hash, and dependency edge
  • image-derived dynamic catalog tables and handoff storage sized exactly from the verified object, segment, dependency, and module counts; catalog growth is limited only by checked address-space/allocation arithmetic and available boot memory. The shared count/emission predicate excludes required kernel and deferred system-service sections that do not become handoff modules, so unrelated section ordering cannot trigger a false capacity failure
  • dynamic-kernel and shared-object loading count validated program headers first, retain every segment record in exactly sized bootloader-owned page storage, and return that temporary storage to firmware before ExitBootServices; there is no separate kernel/object segment ceiling or fixed large firmware-stack frame
  • every firmware page or pool operation receives an explicit BootServices handle. The UEFI image links no Rust global allocator: boot-image parsing, canonical hash/signature verification, and ELF program-header iteration all borrow validated bytes. Owned page storage retains only the handle needed for checked release, and temporary file-info, protocol-handle, and failed image-read buffers are cleanup-complete. The successfully read signed-image allocation remains scoped until a successful firmware exit explicitly transfers it to the kernel memory contract. Optional framebuffer trace authority is likewise local to efi_main and is revoked before firmware exit; no writable framebuffer or font pointer is stored globally
  • exact handoff serialization into its final mapped allocation, followed by a non-returning SysV64 kernel transfer with the handoff pointer in rdi and its externally authoritative serialized length in rsi; the allocation receives a collision-free high-half virtual range derived from the mappings already required for transfer
  • processor timestamp-clock calibration through the explicitly selected UEFI delay service before firmware exit; the non-zero measured frequency is part of the validated handoff so the kernel can use elapsed-time hardware deadlines without implicitly acquiring a timer device
  • firmware memory-map capture, normalization-event storage, transition mapping storage, normalized records, handoff storage, and a contiguous page-table arena are all sized from the current firmware/image shape; reported-size retries have no descriptor-count or attempt ceiling
  • transition mappings carry a separate optional physical-ownership classification, so framebuffer, ACPI, bootloader-image, and active-firmware identity mappings do not accidentally reserve their backing pages; UEFI loader and boot-service memory becomes usable after firmware exit unless an explicit persistent allocation overlays it
  • memory-map normalization uses a sorted event sweep and checked arithmetic rather than fixed boundary tables, quadratic interval scans, or silently truncated firmware descriptors
  • non-executable blob module loading (including console-font)
  • boot-config module loading (SectionType::BootConfig) and handoff inclusion
  • GOP framebuffer mode capture + continuity metadata in handoff
  • dev-profile early console rendering via lib-console, retaining one validated PF2 index across writes and exporting cursor/generation continuity while preserving firmware framebuffer contents until EriX text is rendered over them
  • release-profile quiet early boot (no bootloader serial/framebuffer trace emission); the initial release GOP handoff clears visible pixels once to opaque black so firmware text/logos cannot overlap the first EriX banner. Geometry and aperture bounds are checked before mutation; scanline padding and trailing aperture bytes remain untouched. Dev trace/cursor continuity is unchanged, and no runtime clear operation or terminal authority is added
  • high-memory firmware placement hardening for 4 GiB+ VM configurations: bootloader image, active stack, and ACPI regions are covered before the kernel jump, while a supervisor-only recursive mapping gives the kernel stable access to every active page-table level regardless of physical placement
  • integration-owned system boot, malformed-image, and dynamic-kernel missing/stale object, missing/duplicate export, unsupported relocation, and W^X scenario coverage
  • focused dynamic boot catalog VM coverage for successful catalog handoff and duplicate logical-name rejection before kernel entry
  • operator evidence now identifies bootloader as the only static executable exception while it validates and relocates the dynamic kernel and emits the boot catalog used for dynamic service startup
  • boot-tool inspect/extract workflows can confirm the signed dynlink-img, dynlink-early, dynlink-objs, and dynlink-store sections that this bootloader consumes before kernel entry
  • bootloader failure markers distinguish dynamic kernel-link and catalog failures from later kernel, dynlinkd, and service dynamic-link failures

Remaining work is focused on contract freeze (kernel/rootd alignment), portability hardening, and expanded adversarial coverage.

Governance Principles

bootloader governance is scoped to early machine setup and verified transfer into the kernel.

The scoped governance rules are:

  • It keeps boot policy narrow: validate the image, prepare the handoff, and enter the kernel.
  • It must not embed service policy that belongs to rootd or later user-space services.
  • It treats malformed or unverifiable boot images as fatal startup errors.
  • It keeps platform assumptions documented because later components depend on the handoff contract.
  • It remains the only approved static runtime executable exception; every other kernel or service artifact is expected to be dynamic in final migration evidence.

Authority Boundaries

  • Boot-time authority ends at the kernel handoff; runtime authority is represented by explicit capabilities after startup.
  • Firmware timing authority is used only while boot services are live; the handoff carries inert calibrated frequency metadata rather than a firmware service handle or residual callback.
  • Changes to handoff data require matching updates in kernel and boot-image validation tests.

Contact

Development occurs in EriX organization and discussions happen in issues and design documents.

No decisions are considered valid without documented rationale.

Maintainers can be reached via email: admin@erikinkinen.fi.