From 1c582085da855b65c1e1d46b202982503aa696d4 Mon Sep 17 00:00:00 2001 From: japabu Date: Mon, 12 Oct 2026 09:14:15 +0200 Subject: [PATCH] Enable isolated ARM PCI claims and keep ECAM out of BAR placement The interactive AArch64 machine enabled SMMUv3 without an ITS, so NVMe, network and sound claims were refused before their drivers could start. Use QEMU's emulated GICv3 with its ITS under HVF. That exposes a second defect: the placement survey omitted MCFG windows. Firmware's free MMIO includes configuration space, so all eight attempted BAR addresses could land in ECAM instead of PCI memory. Exclude the ECAM ranges enumerated by the PCI layer, with the same saturated endpoint form used for other decoded extents. A shipping ARM image with the old machine reproduces refused claims. Adding ITS alone arms LPIs but exhausts BAR placement in configuration space. With both changes, NVMe initializes and the NIC acquires DHCP; the sound function is claimed. Keyboard and mouse delivery remain absent, and the compositor still exits at its keyboard endowment. Record that remaining ARM desktop defect without weakening isolation. Extend the existing virt_low_ecam guest to reject an allocator free run overlapping its actual MCFG window. This needs the live kernel's assembly of firmware and PCI extents; the pure allocator excludes what it is given. Removing both production changes builds and fails that check, exit 1; restoring them passes, exit 0. virt_smmu and x86 bar_map_again also pass. The ARM shipping image builds, exit 0. No timing or audio-quality claim. --- build/qemu.rs | 5 +++- ...esktop-starts-with-no-keyboard-or-mouse.md | 30 +++++++++++++++++++ kernel/src/pcidev/mod.rs | 5 ++++ tests/toyos.rs | 18 ++++++++++- 4 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 issues/the-arm-desktop-starts-with-no-keyboard-or-mouse.md diff --git a/build/qemu.rs b/build/qemu.rs index 002c7782844..d2713f48d79 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 00000000000..4a4ab234d4a --- /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 acf6686f2d3..5b906da80b2 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 36f92181a34..8b6f5bda81e 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(()) }