Skip to content

feat(arch): exception vectors and a reporter that names the fault - #4

Merged
MatejGomboc merged 1 commit into
mainfrom
feat/aarch64-exception-vectors
Jul 30, 2026
Merged

feat(arch): exception vectors and a reporter that names the fault#4
MatejGomboc merged 1 commit into
mainfrom
feat/aarch64-exception-vectors

Conversation

@MatejGomboc

Copy link
Copy Markdown
Member

Summary

Installs the AArch64 exception vector table (VBAR_EL1, 2 KiB-aligned, sixteen entries) before the first Rust instruction, routing every exception to a reporter that decodes ESR_EL1 into a sentence and halts. The soft-float bug that cost an afternoon of instruction tracing becomes one console line β€” EC 0x07's decode names CPACR_EL1.FPEN outright.

Proven, not trusted: a provoke-exception feature boots, greets, then executes brk #0, and the CI boot job greps for the decoded EC = 0x3c β€” BRK instruction report on every PR. Local run shows exactly that at vector 4 (synchronous, current EL, SP_ELx).

Which pillar does this serve?

None directly β€” this is kernel-doctrine infrastructure (Β§3: minimal, mechanism-only) and the debugging instrument for everything Β§10 Phase 1 still owes: scheduler, IPC, capabilities, MMU all get bring-up faults, and now those faults speak.

Borrow Ledger

Microkernel core / boot path β€” write ourselves, authored AI-first per amended Β§5.3, reviewed line by line by the maintainer. The table layout is architecturally dictated; the design decisions (terminal-by-design, SPSel forcing, EL1 assumption made explicit) are documented in vectors.s, exception.rs and the commit message.

unsafe register

  • arch/aarch64/mod.rs β€” one new block: brk #0 in the feature-gated self-test, with SAFETY comment
  • arch/x86_64/mod.rs β€” one new block: ud2, same surface on the other Tier-1 target, unreachable until its boot path exists (documented)
  • arch/aarch64/exception.rs β€” #[unsafe(no_mangle)] attribute so the assembly can name the reporter
  • New assembly: vectors.s (whole file), boot.s (four-instruction VBAR_EL1 install) β€” please check these against the Arm ARM; this is the least forgiving code in the tree

Checklist

  • Builds + clippy clean, both Tier-1 targets, both feature states, -D warnings
  • Formatted, pins agree, British spelling, markdown lint-clean
  • Boots in QEMU: ordinary greeting and provoked-fault decode verified locally in the devcontainer
  • CHANGELOG.md updated under [Unreleased]
  • Commits GPG-signed
  • unsafe register above; all blocks in the designated arch/** tree with // SAFETY: comments

πŸ€– Generated with Claude Code

The instrument the soft-float bug had to be diagnosed without. That bug β€”
an FP/SIMD trap vectoring through VBAR_EL1 = 0 into unmapped memory, one
instruction before the kernel's first console character β€” took an
instruction trace and three wrong hypotheses to find. With this table
installed it is one line:

    [EXCEPTION] synchronous, current EL, SP_ELx (vector 4)
      EC   = 0x07 β€” FP/SIMD access trapped by CPACR_EL1.FPEN ...

boot.s installs the 2 KiB-aligned sixteen-entry table into VBAR_EL1 before
the first Rust instruction runs, so even the earliest fault is reported
rather than dying mute. Every entry routes to a common stub that forces
SPSel back to SP_ELx (so even the never-used SP_EL0 group lands on a real
stack), marshals ESR/ELR/FAR/SPSR, and calls a never-returning Rust
reporter that decodes the exception class into a sentence and halts.

Design decisions, for the reviewer:

  - Terminal by design. Until there is a scheduler, every exception is a
    report and a halt: recovery is policy, and there is nothing yet to
    recover to. The vectors clobber registers freely and save no frame β€”
    vectors.s documents that this discipline ends the day the timer IRQ
    arrives and the IRQ entries grow a real save/restore path.
  - The reporter prints line by line on the lock-free console, for the
    same reason the panic handler does: when the machine is dying, half a
    message is evidence and a lock is a hang.
  - Decoded classes name causes, not numbers: EC 0x07 names CPACR_EL1.FPEN
    outright; data aborts point at FAR. Classes the kernel cannot yet meet
    report raw rather than guessing.
  - The EL1 assumption is now load-bearing (VBAR_EL1, SPSel) and boot.s's
    header says so explicitly: an explicit CurrentEL check and EL2 descent
    are owed before real hardware or virtualization=on. QEMU virt without
    that flag enters -kernel images at EL1, which is what the xtask
    harness always uses.

Self-testing, not trusted: a provoke-exception feature (never on by
default) boots, greets, then executes brk #0; CI's boot job greps the
console for the decoded "BRK instruction" report on every pull request.
cargo xtask grows --features passthrough for exactly that. The ordinary
greeting path is asserted unchanged in the same job.

unsafe register (constitution Β§11.3) β€” all in the designated arch tree:

  - arch/aarch64/mod.rs  one new block: `brk #0` (feature-gated self-test)
  - arch/x86_64/mod.rs   one new block: `ud2` (same surface; unreachable
                         until the x86_64 boot path exists, documented)
  - arch/aarch64/exception.rs  `#[unsafe(no_mangle)]` attribute so
                         vectors.s can name the reporter

New assembly: vectors.s in full, and the four-instruction VBAR_EL1 install
in boot.s β€” per the header of boot.s, every instruction there should be
checked against the Arm ARM by the reviewer; the writing is delegated, the
understanding is not (Β§5.3).

Verified in the devcontainer: fmt, pins, spelling, markdown; clippy and
build for both Tier-1 targets in both feature states; xtask clippy and
tests; boot-test greeting; boot-test provoked fault decoding EC 0x3c at
vector 4.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@MatejGomboc
MatejGomboc merged commit c4c6476 into main Jul 30, 2026
6 checks passed
@MatejGomboc
MatejGomboc deleted the feat/aarch64-exception-vectors branch July 30, 2026 04:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant