Skip to content

RV1103 Linux direct boot implementation plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development. Root owns commits and merges. Steps use checkbox syntax for tracking.

Goal: Run a pinned, real Linux kernel and static userspace with timer-driven wakeups through LabWired's RV1103 physical Bus.

Architecture: The optional native system CPU connects to a bus-owned ARM fabric. GIC distributor/CPU-interface devices share one controller; the architectural timer shares its PPI levels and synchronizes from the bus clock. The normal Machine scheduler remains authoritative, including zero-retirement WFI and IRQ transitions.

Tech Stack: Existing Rust core, embedded tlib, GICv2, DW APB UART, ARM zImage/DTB, deterministic newc initramfs, Alpine ARMv7 binaries, Python artifact preparation, dtc.

Task 1: Retirement and ARM bus interfaces

Files: crates/core/src/lib.rs, crates/core/src/machine/{boundary.rs,advance.rs,plan.rs}, crates/core/src/bus/{interrupt_fabric.rs,accessors.rs,construct.rs}, crates/core/tests/qemu_arm_system.rs.

  • [x] Add a zero-retirement CPU test: Machine single and batch execution must report zero instructions/time for an already-waiting CPU. Run the focused test and preserve red output before the scheduler change.
  • [x] Add Cpu::step_retired(bus,observers,config)->SimResult<u32> defaulting to step(...)?; Ok(1) and forward through Box. Native overrides it with actual retirement. SingleDirect uses the count and restores its provisional cycle charge on zero; existing CPUs retain their counts and clocks.
  • [x] Native adapter resolves bounded zero-retirement exception transitions internally (at most eight native calls before error), until one instruction retires or WFI is observed. Do not emit an instruction trace for an exception transition. Capture translated instruction bytes for observers only when tracing is requested, and emit retirement events only for executed instructions.
  • [x] Add default Bus methods: arm_irq_fiq_levels()->Option<(bool,bool)> returning None; arm_cp15_read(instruction,wide)->SimResult<u64> and write returning explicit unsupported errors; next_cpu_interrupt_deadline_cycle()->Option<u64> returning None; arm_code_identity()->Option<u64> returning None. ARM fabric owns an allocation-unique monotonic identity used by the native code cache.
  • [x] Native step_batch uses native retirement, publishes time for actual instructions and stops at waiting, timer programming or a newly asserting IRQ. Start with one native instruction per call. Observer-free optimization must retain interrupt/deadline boundaries.
  • [x] Before NoProgress on a zero-retirement window, attempt the existing configured idle advance if the CPU is waiting. Do not fabricate retirement. Idle disabled/no reachable event returns NoProgress. Test IRQ-entry transitions, waiting with no event, timer wake, masked IRQ and single/batch equivalence.

Task 2: GIC, architectural timer and UART2

Create crates/core/src/peripherals/armv7/{mod.rs,gic.rs,timer.rs,dw_uart.rs} and tests crates/core/tests/rv1103_devices.rs; wire optional Armv7Fabric through the existing bus fabric. New peripheral types implement the existing console/RX attachment methods.

  • [x] Write red tests for GIC enable/priority/acknowledge/EOI/deassert, timer compare/control/mask/IRQ deadline, and UART DLAB/FIFO/IER/IIR/LSR, using actual register widths.
  • [x] Implement one CPU GICv2 with 256 INTIDs. Distributor CTLR/TYPER/IIDR, group/enables/pending/active bitmap sets and clears, priority/targets/config bytes, SGIR and ID registers; CPU interface CTLR/PMR/BPR/IAR/EOIR/RPR/HPPIR and ID registers. Source level persists across EOI; active sources do not repeatedly acknowledge. Respect priority mask and current active priority. Group0 FIQEn routes to FIQ; normal enabled interrupt groups route to IRQ. No virtualization/multicore claim.
  • [x] Implement 24 MHz CP15 generic timer owner. Decode MRC/MCR fields (opc1,CRn,CRm,opc2) and MRRC/MCRR (opc1,CRm). Support CNTFRQ, CNTKCTL, CNTP/CNTV TVAL/CTL/CVAL, CNTPCT/CNTVCT and CNTVOFF. Signed TVAL, writable ENABLE/IMASK and derived ISTATUS are required. Unknown external CP15 accesses return errors. Counter conversion uses absolute u128 arithmetic from modeled CPU ticks, not host time. Expose the nearest unmasked enabled compare deadline in CPU ticks. Initial reduction: CNTKCTL retains EL0 access, event direction and index fields, but enabling EVNTEN returns an explicit error before mutation. The pinned kernel enables CONFIG_ARM_ARCH_TIMER_EVTSTREAM; the supported Linux early parameter clocksource.arm_arch_timer.evtstrm=0 therefore disables its WFE event stream in the reduced fixture. Generic timer IRQs, WFI and guest sleep remain required.
  • [x] SystemBus::set_current_cycle updates the ARM counter and GIC INTID29 for the direct-boot secure physical timer and INTID27 for the virtual timer. The vendor-derived minimal DT advertises only secure/nonsecure physical PPI13/14, so the tested Linux guest selects INTID29. Do not misroute CNTV to the nonsecure physical INTID30. Independent TrustZone timer banks remain outside this slice. The planner includes its deadline, and native WFI idle budget stops there. Timer register writes end the current execution window so new deadlines cannot be overrun.
  • [x] Implement DW UART2 at ff4c0000 (reg-shift2/mmio32) with divisor latch, RX FIFO, THRE/TEMT, IER/IIR, FCR clear, line/modem/scratch registers and RX injection; console bytes pass through existing sinks. Source SPI27 means GIC INTID59. Do not use a UART stub that emits divisor bytes as console output. Unimplemented DMA/modem timing is disclosed.
  • [x] Run cargo test -p labwired-core --features qemu-arm-system,event-scheduler --test rv1103_devices --test qemu_arm_system under a bounded unwind test profile. Review both correctness and default-path regressions.

Required native correction before the loader

A bounded diagnostic run through the actual SystemBus/Machine reached the architectural timer and scheduler, then panicked in vfp_init at VMRS MVFR1 (eef60a10). The pinned native Cortex-A7 sets VFP4 without VFP3 and pairs a NEON execution flag with FPU-only capability IDs. Correct the generated Cortex-A7 model to the RV1103 NEON/FPU profile and verify actual capability reads and arithmetic results before claiming Linux boot. Preserve vendor bytes and kernel configuration; the strict loader/userspace acceptance gates below remain pending.

Task 3: Artifacts and loader

Create examples/luckfox-pico-mini-a-linux/{README.md,REQUIRED_DOCS.md,EXTERNAL_COMPONENTS.md,VALIDATION.md,rv1103-direct.dts,artifact-manifest.json,init}, scripts/prepare-rv1103-linux.py, crates/core/src/system/rv1103_linux.rs, and crates/core/tests/rv1103_linux_loader.rs. Add qemu-arm-system CLI feature and a native Linux command/argument surface using the established CLI patterns.

  • [x] Loader red tests reject wrong board, malformed zImage/DTB, hash mismatch, overlapping or oversized ranges and unavailable backend before modifying RAM.
  • [x] Use official Alpine v3.23 armv7 linux-lts-6.18.56-r0.apk SHA256 00059546e63df3dbadb80ff08f577dce1ef871b8cd800665d6404936a956eade; extracted vmlinuz SHA256 eac9582162e912bdb577bba6ea224d98a29c997e52ee891383ea836aa704680a. Config SHA256 4e64812402b287e13fd7513aa830432782a1ae94a5461bfe579999d1e18432fb. Verify MMU, ARM_GIC, ARM_ARCH_TIMER, SERIAL_8250_CONSOLE/DW, INITRD built in and ARM_LPAE disabled. Record package/source recipe provenance b599422f9f640e35932a995ceedf52ec76b66963 and licenses.
  • [x] Static BusyBox APK SHA256 fb023d6a1e2dce9069b11b302e674c273b9e17d04d17b03ee16526475b0971e6, executable SHA256 1c0ed2db00c0bbdd796e4bdb4de58c564a3df8e61afc716652004b3ce0ee50f2. Download with size limits and hashes; extract only needed entries; do not commit binaries. Generate deterministic newc with fixed metadata, /bin/busybox, sh link, /init, proc/sys/tmp and console/null device nodes. Print boot identity, PID1 identity, cpuinfo, memory size and uptime before/after a real guest sleep, then acceptance sentinel. Failure to mount or execute a command exits with a failure marker.
  • [x] Minimal DT uses actual rockchip,rv1103 root compatible and generic ARM multiplatform fallback, DDR0/64MiB, Cortex-A7, GIC400 ff1f1000/ff1f2000, architectural timer PPI13/14, UART2 ff4c0000 SPI27 with fixed24MHz clock and serial2 alias. Omit FIQ debugger, CRU, pinctrl, DMA, SD and other unsupported devices explicitly. No other SoC compatible.
  • [x] Place zImage at02000000, DTB03000000, initramfs03100000, decompression/BSS reservation00008000..016e5850; validate all against64MiB. Boot r0=0,r1=ffffffff,r2=DTB, ARM/SVC IRQ+FIQ masked, MMU/cache off. Bootargs mem=64M cma=0 maxcpus=1 earlycon=uart8250,mmio32,0xff4c0000,115200n8 console=ttyS2,115200n8 rdinit=/init loglevel=8 panic=-1 clocksource.arm_arch_timer.evtstrm=0; any calibration override is recorded.
  • [x] Load through the real SystemBus and create Machine, enabling configured idle advance/event scheduling. Return exact artifact/backend hashes and reduced-platform capability list with bounded step/time limits and captured guest console.

Task 4: Real Linux acceptance and release

Create feature-required crates/core/tests/rv1103_linux_boot.rs; extend .github/workflows/core-qemu-arm.yml to run native-system default-off/backend/device tests and pinned artifact preparation/guest acceptance.

  • [x] Require kernel boot log, userspace marker, actual syscall and advancing uptime after guest sleep. Production optimized zImage gate passed on 2026-10-12 (1 actual test, 0 failures); complete receipt/CLI identity retained in examples/luckfox-pico-mini-a-linux/evidence. Earlier debug wall-timeout receipt remains FAIL; raw Image diagnostics stay separate. No runtime workaround was needed.
  • [x] Verify default/browser builds remain independent, old qemu-arm fixture passes, scheduler accounting regressions pass and native snapshots refuse incomplete restore. Default/native focused suites and actual wasm32 check passed; CortexA7System::try_apply_snapshot rejection is exercised by qemu_arm_system.
  • [x] Update board/example/docs capability statements after actual acceptance. Direct boot success does not certify SD/BootROM/vendor image, RK3x I2C or the basket yet; generic YAML and old ELF adapter remain separate.
  • [x] Root reviews and protected merge completed in PR1372 on 2026-10-12, merge 7fe1722e9fb40a2c67962568b9ae4b66c6bff4ee. All 34 current-head checks completed successfully or with expected skips before merge. Post-merge main CI is a separate check; local guest boot, CI, merge and physical acceptance remain separate receipts.

Basket continuation

After this boot plan, implement RK3x I2C3 with actual transfers/IRQ and attach existing ADXL345 at0x53; implement UART4 attached to a new bounded behavioral ESP-AT model. Build the pinned upstream I2C_RK3X source as an external module against exactly matching 6.18.56 headers and Module.symvers; retain the matching stock I2C_CHARDEV module. Guest insmod must succeed without forced version or symbol checks. Require guest reads of device ID and stimulated axes plus actual guest UART AT exchanges. Modeled battery/power coupling uses existing circuit contracts with labeled assumptions. SD rootfs and physical acceptance remain separate gates.