- Rust 90.6%
- Python 5.2%
- Shell 4.1%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
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: |
||
| .cargo | ||
| .github | ||
| scripts | ||
| src | ||
| tests | ||
| .editorconfig | ||
| .gitignore | ||
| .markdownlint-cli2.yaml | ||
| ARCHITECTURE.md | ||
| Cargo.toml | ||
| CODE_OF_CONDUCT.md | ||
| CONTRIBUTING.md | ||
| LICENSE | ||
| Makefile | ||
| README.md | ||
| ROADMAP.md | ||
| rustfmt.toml | ||
| SECURITY.md | ||
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-bootimgforboot.imgparsing/verificationlib-elffor ELF64 parsinglib-handofffor handoff schema typeslib-dynlinkfor early dynamic-kernel metadata constants and relocation policy alignmentlib-sha2for 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.imgload/parse/verify path- allocation-free ELF extraction and validated program-header iteration
- dynamic-kernel boot-store validation and relocation path for the signed
dynlink-storeanddynlink-earlysections - dynamic-kernel validation of the real
ld.llddynamic tags used by the kernel and shared-object relink path, including eager-Bsymbolic -z nowflags,DT_SONAME,.rela.plt, and boundedDT_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
BootServiceshandle. 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 toefi_mainand 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
rdiand its externally authoritative serialized length inrsi; 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
bootloaderas the only static executable exception while it validates and relocates the dynamickerneland emits the boot catalog used for dynamic service startup boot-tool inspect/extractworkflows can confirm the signeddynlink-img,dynlink-early,dynlink-objs, anddynlink-storesections 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
rootdor 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.