Repository navigation
hw-vfio, intel-iommu: DMA through the vIOMMU for vfio-pci - #330
Merged
Merged
Conversation
3 of 11 tasks
tamnd
added a commit
that referenced
this pull request
Oct 14, 2026
This was referenced Oct 14, 2026
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.
vfio-pci can now sit behind intel-iommu. The device does DMA into its own address space, which holds the vIOMMU's region once the guest turns DMAR on, and the vfio container follows that region with an IOMMU notifier the way hw/vfio/listener.c does. When the guest maps a page and invalidates, the container maps the IOVA to the guest page in the host IOMMU, and when it takes the page away, the container unmaps it. This needs caching-mode=on, as in QEMU.
What is in it:
IOMMUNotifierwithmemory_region_register_iommu_notifier(),memory_region_unregister_iommu_notifier(),notify_flag_changedandreplay, andFlatRange::iommu()so a listener can find the region's callbacks.vtd_page_walk()sends map and unmap events, andvtd_sync_shadow_page_table()runs after context, domain, page and global invalidations, and after TE and SRTP.vtd_iommu_notify_flag_changed()refuses MAP without caching mode with QEMU's error, andvtd_dev_set_iommu_device()refuses assignment without caching mode, a second set and fsts=on.vtd_switch_address_space()does.vfio_iommu_map_notify(), with QEMU's checks for the target address space and the granularity and its map and unmap errors. A section of the whole 2^64 space is unmapped withVFIO_DMA_UNMAP_FLAG_ALLwhen the kernel hasVFIO_UNMAP_ALL, or in two halves when it does not. realize callspci_device_set_iommu_device()after the config setup and unsets it on a later failure, with the "Failed to set vIOMMU: " prefix.Where it differs from QEMU:
error_report_once()lines for a failed translation ("detected sspte permission error", "detected translation failure", "New fault is not recorded due to compression of faults"). The L2 here never hits them, and that is left for a later change.Checked:
All on 2cc01b5, the branch with main merged in, on server2:
-D warningsand--all-targetsfor ruvm-mem, ruvm-hw-iommu, ruvm-sys, ruvm-hw-pci, ruvm-hw-vfio, ruvm-machine-x86 and ruvm-system.intel-iommu,caching-mode=onand an e1000e at 00:04.0 bound to vfio-pci. L2 is run with-device intel-iommu,caching-mode=on,intremap=off -device vfio-pci,host=0000:00:04.0,addr=2under qtest, as QEMU 11.1 (Q), ruvm (R), QEMU again (Q2) and ruvm before this change (P). Each batch waits for all of its answers. In L2, qtest writes a root table, a context entry for 00:02.0 in domain 1 and a 3 level table mapping IOVA 0x40000000 to the TX ring and 0x40001000 to a buffer, then sets SRTP, invalidates and sets TE. The e1000e then sends from IOVAs only.All 29 answers are the same in Q, R and Q2. GSTS reads 0xc0000000 after TE and the fault status stays 0 in L2, since the fault for the unmapped IOVA happens in L1. The outer e1000e ignores the failed read, so TDH still moves to 3 and DD is set in both. For the unmapped IOVA, the L1 kernel logs the same fault in all three runs: "DMAR: [DMA Read NO_PASID] Request device [00:04.0] fault addr 0x40001000 [fault reason 0x06] PTE Read access is not set". The outer QEMU also prints its vtd lines for it, but with
error_report_once(), so only the first run in an L1 boot shows them. A second L1 boot on the same build with R run first shows them during R, the same 29 answers for R and Q, the same L1 DMAR fault for both, and the same caching-mode=off error.