Repository navigation
hw-iommu: unmap notifiers on the SMMUv3 - #343
Merged
Merged
Conversation
This was referenced Oct 14, 2026
tamnd
added a commit
that referenced
this pull request
Oct 15, 2026
…handler (#345) Part of #9. vfio-pci now resets a device the way QEMU 11.1 does when the device has no FLR. `vfio_pci_reset()` tries FLR first. Without it, it tries a bus or slot reset through `VFIO_DEVICE_PCI_HOT_RESET`, and falls back to the PM reset of `VFIO_DEVICE_RESET` only when nothing else worked. On a system reset, `vfio_device_reset_handler()` runs before any device is reset and resets together the devices in use that share a bus. What is in it: - ruvm-sys: `VFIO_DEVICE_GET_PCI_HOT_RESET_INFO`, which reports how many devices a hot reset takes along even when it fails with `ENOSPC`, and `VFIO_DEVICE_PCI_HOT_RESET` with the group descriptors as proof of ownership. The group descriptor is now reachable through `AsFd`. - vfio-pci: - `vfio_pci_pre_reset()` and `vfio_pci_post_reset()`. The first stops interrupts and DMA, clears INTx Disable and brings the device to D0. The second turns INTx back on and clears the BARs. - `vfio_pci_compute_needs_reset()` and `vfio_legacy_pci_hot_reset()`, with QEMU's errors for a device with no reset mechanism and for a dependent group that is not owned. - A list of the realized devices, so a reset can find the other devices in use that it takes along. - q35: early reset hooks, which run before any device is reset. That is where QEMU's `qemu_register_reset()` handlers run, since the system bus reset is registered only after every `-device` is realized. The first vfio-pci registers the vfio reset handler there. - vfio-pci no longer resets the device at realize. QEMU doesn't, and the first system reset, which `machine_done()` runs once every device is plugged, resets it on both the TCG and KVM paths. ruvm has no `device_add`, so there is no hotplug path that would need its own reset after realize. Checked: On server2, on c64ade1, the branch with main up to #343 merged in: - clippy with `-D warnings` and `--all-targets` for ruvm-mem, ruvm-hw-iommu, ruvm-sys, ruvm-hw-pci, ruvm-hw-vfio, ruvm-machine-x86, ruvm-machine-arm and ruvm-system. - clippy for x86_64-pc-windows-gnu and aarch64-apple-darwin on the same crates. - tests of ruvm-mem, ruvm-hw-iommu, ruvm-sys, ruvm-hw-pci and ruvm-hw-vfio, and the ruvm-machine-x86, ruvm-machine-arm and ruvm-system libs (40, 36 and 113). A new ruvm-sys test decodes the dependent devices of a hot reset info reply. ruvm-machine-x86 has 40 tests, not 43 as at ce49dd2, because #340 and #342 removed three. - xtask unsafe-audit, provenance, layers and style. - An L1 compare on the release build of c64ade1. L1 is QEMU 11.1 with an e1000e behind a pcie-root-port at 01:00.0, bound to vfio-pci. L2 is run with `-device vfio-pci,host=0000:01:00.0,addr=2` under qtest and strace, as QEMU 11.1, ruvm and QEMU 11.1 again, one at a time. qtest sets RAL0 of the e1000e, resets the system through 0xcf9, waits until BAR0 reads 0, maps BAR0 again and reads RAL0 and RAH0. The runs waited until the host load was under 16 and ran at a host load between 15 and 21. The ioctls on the device descriptor are the same in all three, at start and again after the 0xcf9 reset: | Step | Ioctl | Result | | --- | --- | --- | | reset handler | GET_PCI_HOT_RESET_INFO, no room | ENOSPC | | | GET_PCI_HOT_RESET_INFO | 0, no other device in use, so nothing to do | | device reset | GET_PCI_HOT_RESET_INFO, no room | ENOSPC | | | GET_PCI_HOT_RESET_INFO | 0 | | | PCI_HOT_RESET | ENOTTY | | | DEVICE_RESET | 0 | All the answers are the same in the three runs. RAL0 reads 0x12005452, reads back 0xa1b2c3d4 after the write, and reads 0x12005452 again after the reset, with RAH0 0x80005634. So the device really was reset. ruvm took two BAR0 polls to see the reset where QEMU took one. Before this change, ruvm reset the device at realize too, which added four calls at start (ENOSPC, 0, ENOTTY, 0) before the sequence above. The compare that found it ran on 919a7c1.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of #9.
What
IOMMU notifiers on the SMMUv3, on the notifier API from #330, as in QEMU 11.1's hw/arm/smmuv3.c and smmu-common.c.
smmuv3_notify_flag_changed()is ported: a notifier asking for MAP or DEVIOTLB_UNMAP events is refused with QEMU's message, and the device goes on or offdevices_with_notifiersas its first notifier comes or its last one goes.smmuv3_inv_notifiers_iova(),smmuv3_notify_iova()andsmmu_inv_notifiers_all()do:Replay
There is no SMMUv3 replay, as in QEMU. hw/arm/smmuv3.c has no
replaycallback. The only callers ofmemory_region_iommu_replay()are VFIO and vhost-vdpa, and both register MAP notifiers, which the SMMUv3 refuses. So the defaultIommuOps::replayof #330, which does nothing, is the right one here.What it changes for guests
Nothing in ruvm registers an unmap-only notifier behind the SMMU yet: vfio-pci is on q35 only, and it needs MAP anyway. So this is the device model side, tested at the unit level. To check that the translation path still works, the root port boot from #336 ran on QEMU 11.1 and on this build: an Alpine 6.12 guest with
-M virt,iommu=smmuv3,gic-version=3 -cpu max -m 1G -smp 1and a virtio-blk-pci withiommu_platform=onbehind a pcie-root-port. It takes the md5 of /dev/vda, writes a sector, drops caches, reads it back and takes the md5 again.The host image md5 after the run was 269d53a2fae97c0c7de47a8a3d6776b2 on all four boots. The guest's PCI addresses differ by the default NIC (a virtio-net at 00:01.0), which ruvm does not add. The ruvm boots used a release build of this diff on e7c7db9; #342, which came in after, migrates the ACPI GED and does not touch hw-iommu.
Not done here
accel=on, CMDQV) needs host SMMU hardware we do not have, so it comes last.Tests
notifiers_take_unmap_only: MAP and DEVIOTLB_UNMAP notifiers are refused with QEMU's messages and leave nothing on the list. An UNMAP notifier goes on the list and comes off it again.stage1_invalidations_unmap_for_the_notifiers: one page for a matching ASID and nothing for another, a range split into its powers of two, whole-range unmaps for TLBI_NH_ASID and TLBI_NSNH_ALL, nothing for CFGI_STE, and nothing once the notifier is gone.stage2_invalidations_unmap_for_the_notifiers: one page for a matching VMID and nothing for another, nothing for TLBI_NH_ALL with stage 2, a whole-range unmap for TLBI_S12_VMALL, and with nesting nothing for TLBI_S2_IPA but a page for TLBI_NH_VA.cargo fmt --check -p ruvm-hw-iommu; clippy-D warningson hw-iommu, machine-arm and system;cargo check --workspace --all-targets;cargo test -p ruvm-system --lib(113 passed); the tests of hw-iommu, mem, machine-arm, system, hw-pci and hw-virtio, and the linux-user x86 suite (user-common, linux-user, jit-x86_64, jit-core), 770 passed and 0 failed in all; the provenance, unsafe-audit, layers and style xtasks;cargo check --target x86_64-pc-windows-msvcon hw-iommu, machine-arm and system with no warnings.