ADR-007 — PL011 UART RX as virt input
- Status: Accepted
- Date: 2026-09-09
Context
FR-08 already covers hardware interrupts (timer via the virt GIC, M5 / ADR-006) and named “later input” as the rest of that ID. Roadmap M6 is that input path. The x86-era reading of FR-08 was a keyboard. Frozen IDs stay; the arm64 text is revised here.
Options on QEMU virt:
- PL011 UART RX at
0x0900_0000(already the console). - virtio-input / virtio-keyboard (virtio-mmio, virtqueues, DMA). No paging or heap yet (M7/M8). Too much device stack for one milestone.
- PL011 UARTCR.LBE loopback as a self-test. QEMU 8.2 (Ubuntu 24.04 / this repo’s GHA and cloud probe) does not implement LBE —
hw/char/pl011.cstill says the loopback bit is unimplemented. LBE landed in later QEMU. A loopback-only probe would be a false pass on newer hosts and a false fail on 8.2.
Host stdin on -serial stdio does reach pl011_receive → the RX FIFO. UARTLCR_H.FEN toggles reset that FIFO, so a byte sent before uart::init is lost. Inject after Hello World! (init already ran).
Decision
- M6 input is PL011 RX poll, not virtio-keyboard and not a UART RX IRQ. FR-08’s “via the virt GIC” remains the M5 timer. Input does not take a new FR ID.
- Prove a received byte with a host inject:
scripts/qemu-serial-inject.pywrites0x41('A') to QEMU stdin after it seesHello World!. The hello kernel pollsUARTFR.RXFE/UARTDR(DAIF.I still masked after the timer window) and printsinput: rx 0x41. - Fail closed. Missing marker or
input: rx missedfailsscripts/qemu-smoke.sh.#[test_case]only asserts the FIFO is empty when cargo test does not inject — the character proof is the serial smoke. - Do not claim Raspberry Pi UART, virtio-input, GICv3 UART SPI, or QEMU LBE.
Consequences
scripts/qemu-smoke.shneedspython3to drive the inject (Dockerfile installs it).cargo test/scripts/qemu-aarch64.shstay inject-free so M2–M5 cases do not wait on stdin.- A later virtio-keyboard or UART-RX-via-GIC path needs a new ADR; it is not this milestone.