diff --git a/build/qemu.rs b/build/qemu.rs index 002c778284..d2713f48d7 100644 --- a/build/qemu.rs +++ b/build/qemu.rs @@ -325,7 +325,10 @@ fn machine(arch: Arch, iommu: bool) -> String { match (arch, iommu) { (Arch::X86_64, true) => format!("{base},kernel-irqchip=split"), (Arch::X86_64, false) => base.to_string(), - (Arch::Aarch64, true) => format!("{base},gic-version=3,iommu=smmuv3"), + // HVF's GIC has no ITS; PCI claims need QEMU's GIC to remap their messages. + (Arch::Aarch64, true) => { + format!("{base},gic-version=3,iommu=smmuv3,its=on,kernel-irqchip=off") + } (Arch::Aarch64, false) => format!("{base},gic-version=3"), } } diff --git a/issues/the-arm-desktop-starts-with-no-keyboard-or-mouse.md b/issues/the-arm-desktop-starts-with-no-keyboard-or-mouse.md new file mode 100644 index 0000000000..4a4ab234d4 --- /dev/null +++ b/issues/the-arm-desktop-starts-with-no-keyboard-or-mouse.md @@ -0,0 +1,30 @@ +--- +status: open +kind: defect +opened: 2026-10-11 +--- + +# The ARM desktop starts with no keyboard or mouse + +An AArch64 boot of `images/system.toml` under QEMU `virt` reaches the +supervisor and initializes virtio-gpu, but the compositor exits 101 at +`system/compositor/src/session.rs` because its keyboard endowment is absent. +The supervisor reports both keyboard and mouse absent. This was read in +the owner's boot of `57616a067` and reproduced with the shipping image. + +The launcher attaches a USB keyboard and tablet to its xHCI. The kernel's +xHCI driver refuses to arm on AArch64: `arch/aarch64/irqchip/its.rs::msi` +refuses kernel drivers. Enabling the ITS makes PCI claims possible but +does not give that driver an interrupt. `system/usbd` currently enumerates +devices without binding their classes and is not started by the shipped +manifest. There is no virtio-input driver. + +Owner: `issues/toyos-runs-on-arm64.md`, stages 6 and 7, with the userland +USB move in `issues/the-kernel-is-small-interrupts-post-and-threads-wait.md`. +DMA and interrupt isolation remain required. + +Exit: an ARM boot of the shipped manifest supplies real keyboard and mouse +input to the compositor; injected key transitions and pointer events reach +the desktop and an application's window in a test that fails when delivery +is removed. The compositor starts and presents a frame without the missing +keyboard panic. diff --git a/kernel/src/pcidev/mod.rs b/kernel/src/pcidev/mod.rs index acf6686f2d..5b906da80b 100644 --- a/kernel/src/pcidev/mod.rs +++ b/kernel/src/pcidev/mod.rs @@ -495,6 +495,11 @@ pub fn publish(devices: &[PciDevice], segment: u16, maps: &[MemoryMapEntry], fir let mut decoded = Vec::new(); let mut taken: Vec = maps.iter().map(|entry| Window { start: entry.start, end: entry.end }).collect(); + // ECAM decodes configuration space even when firmware lists it as free MMIO. + taken.extend(crate::drivers::pci::windows().into_iter().map(|ecam| { + let (start, bytes) = ecam.decoded(); + Window { start, end: start.saturating_add(bytes) } + })); for device in devices { // Bounded by the header's own declaration: a bridge has two BAR slots // and four registers past them that are not BARs, and `bar_size` below diff --git a/tests/toyos.rs b/tests/toyos.rs index 36f92181a3..8b6f5bda81 100644 --- a/tests/toyos.rs +++ b/tests/toyos.rs @@ -2246,7 +2246,8 @@ fn virt_no_seed_refused(profile: qemu::Profile, test_config: &Path) -> Result<() /// A machine whose MCFG decodes sixteen buses, with RAM past them: the kernel /// maps those sixteen buses' megabytes and no more, and enumerates the -/// functions QEMU put there and nothing else, and the boot goes on. +/// functions QEMU put there and nothing else. BAR placement keeps the +/// configuration window out of its free runs, and the boot goes on. fn virt_low_ecam(profile: qemu::Profile, test_config: &Path) -> Result<(), String> { const WINDOW: &str = "ACPI: ECAM window: segment 0 buses 0x00..=0x0f, bus 0 at 0x3f000000"; const MAPPED: &str = "mmio: 0x3f000000+0x1000000 "; @@ -2281,6 +2282,21 @@ fn virt_low_ecam(profile: qemu::Profile, test_config: &Path) -> Result<(), Strin return Err(format!("{want:?} not on the PL011\nserial:\n{serial}")); } } + let mut runs = 0; + for line in serial.lines().filter_map(|l| l.split_once("pcidev: ").map(|(_, run)| run)) { + let range = line.split_whitespace().next().ok_or("an empty PCI free run")?; + let (start, end) = range.split_once("..").ok_or("a PCI free run without its end")?; + let address = |word: &str| u64::from_str_radix(word.trim_start_matches("0x"), 16) + .map_err(|why| format!("invalid PCI free-run address {word:?}: {why}")); + let (start, end) = (address(start)?, address(end)?); + if start < 0x4000_0000 && end > 0x3f00_0000 { + return Err(format!("BAR placement offers ECAM configuration space in {range}\nserial:\n{serial}")); + } + runs += 1; + } + if runs == 0 { + return Err(format!("the boot reported no PCI free runs\nserial:\n{serial}")); + } eprintln!(" [virt] {WINDOW}; {} functions: {found:?}", found.len()); Ok(()) }