ReviewOS

home-lang/home-os

Pi 5 entry: `boot.s` for BCM2712 (EL2→EL1, stack, BSS, DTB in x0, park cores 1–3, jump to Home `kernel_main`) + corrected `config.txt` — and the very first UART banner on real hardware

#57
Open chris opened this 8 days ago ·
8 days ago

Epic: #113 · Milestone: MC2 — Pi 5 bring-up

Why

No arm64 .s exists in this repo; build.sh borrows packages/kernel/src/arm64/boot.s from the compiler repo, which is written for Pi 3/4. kernel/src/arch/arm64/boot.home calls foundation.arm64_read_currentel(), arm64_write_hcr_el2, arm64_eret, get_pc — none of which exist in core/foundation.home. rpi5_main.home does not typecheck (Zig-style for (x) |y|, undefined property). The Pi 5 boots core 0 at EL2 at 0x80000 with the DTB address in x0; the EEPROM bootloader loads the image named by kernel= (default kernel_2712.img).

This issue also carries the rig smoke test: before the compiler can produce ARM code, an assembly-only banner (assembly is allowed for boot code) proves the SD/TFTP/UART/power loop end to end. That is a means, not an endpoint; the Home entry replaces it as soon as rung 1 of #51 exists.

Tasks

  • kernel/src/arch/arm64/boot.s: MPIDR check, park secondaries in wfe loop with a spin-table mailbox for later SMP; save x0 (DTB); if EL2: set HCR_EL2.RW=1, SCTLR_EL1 sane, SPSR_EL2, ELR_EL2 → eret to EL1; zero .bss; 16-byte-aligned stack below _start; bl kernel_main (Home, export fn kernel_main(dtb: u64): never); on return wfe forever. Vector table symbol exported for #61.
  • Temporary uart_banner in the same file for the rig smoke test (PL011 at the BCM2712 debug UART base, see #58), removed once Home prints the banner.
  • Rewrite kernel/src/arch/arm64/boot.home against real foundation intrinsics from #53; delete rpi5_main.home or make it the Home entry that calls arch_init → drivers → shell.
  • rpi5/config.txt: kernel=kernel_2712.img, arm_64bit=1, enable_uart=1, uart_2ndstage=1 (bootloader messages on the debug UART), disable_splash=1, boot_delay=0; remove dtoverlay=miniuart-bt (Pi 4 concept). Keep hdmi_* lines commented until #74. Delete the stale "start.elf" prose.
  • kernel/linker-rpi5.ld: entry _start, base 0x80000, .text.boot first, page-aligned .bss, __stack_top.

Acceptance

Serial capture on the rig shows the bootloader log followed by HomeOS rpi5: EL1 kernel_main reached printed by Home code. (Interim: the assembly banner alone proves the rig, recorded as a non-gate.)

Size: M · Depends on: #48, #51 (rung 1), #54 · Blocks: #58, #63

8 days ago

The ARM64 boot and codegen gates exist and pass

home-lang/home-os@b856128 and @0b0e290.

A Home-compiled kernel boots on ARM64. On QEMU's virt machine:

HomeOS v0.1: aarch64 kernel_main reached

Landed for this issue:

kernel/src/arm64_poc.homeARM64 proof-of-life, drives a PL011 over MMIO
kernel/src/arch/arm64/boot.sparks secondaries, EL2→EL1, stack, BSS, into Home
kernel/linker-virt.ld0x40080000, .text.boot first, BSS bracketed
scripts/boot-gate-aarch64.sh + boot-milestones-aarch64.txtthe ARM boot ratchet
scripts/mvk-compiles.sh --arch=aarch64 + scripts/mvk-floor-aarch64.txtthe ARM codegen ratchet
CI jobs mvk-compiles-aarch64, boot-qemu-aarch64both wired into .github/workflows/ci.yml

IMPLEMENTATION_STATUS.md now measures both on every run.

Measured this run

gateresult
parse-rate415/415 (100%)
mvk-compiles x86-6470/70
mvk-compiles aarch6413/70
boot-qemu-x86_6455/55 milestones
boot-qemu-aarch64PASS

Two findings that cost real debugging time

Unaligned loads fault on ARM with the MMU off. mvk_poc.home reads a string one byte at a time as a word load masked to its low byte. ARMv8 treats all memory as Device-nGnRnE while the MMU is off, and unaligned access to Device memory raises an alignment fault instead of being fixed up in hardware. The kernel printed exactly H and stopped. arm64_poc.home uses a *u8 parameter so the deref is one byte wide and lowers to ldrb. Anything in the tree using that idiom will need the same treatment, and it will not show up until the MMU work (#61) or a hardware boot.

A latent x86 correctness bug, found by porting. Bitfield struct literals were assembled in one register, so fields at bit 64 and above were shifted out — the shift was emitted as shlq $N, %rax with N up to 127, and x86 masks a shift count to six bits, so shlq $64 shifts by zero and the field landed on top of bit 0. IDT entries are 128-bit packed structs, so kernel/src/idt.home has been compiling to descriptors the CPU would reject, silently, while counting as a passing file in this ratchet the whole time. Fixed in home-lang/home@896d002f0, which assembles wide containers a word at a time in memory.

What the 57 remaining files are blocked on — and it is not the backend

core/foundation.home has 29 asm volatile blocks. Inline assembly is emitted verbatim by definition, so an x86 block reaches the ARM assembler as x86 text. Because the whole tree imports this module, those blocks account for most of the gap.

Eight of them had direct architecture-neutral equivalents and are now gone (@578ddc6, using new arch_halt / arch_disable_interrupts / arch_enable_interrupts / arch_nop / arch_spin_hint intrinsics). The generated x86 assembly is unchanged and the boot gate still reaches 55/55.

The other 21 are genuinely x86-only CPU state: cpuid ×3, rdtsc, cr2/cr3/cr4, stac/clac, ltr, lgdt, pushfq/popfq, lock xaddq, and port I/O ×6. Those need an ARM counterpart and a way to select between the two per target, which HomeOS does not have yet. That decision is #62's, and it is the single thing standing between 13/70 and a much larger number.

Sign in to comment on this issue.