vfio: synthesize PASID capability for nested devices - #4375
vfio: synthesize PASID capability for nested devices#4375Henry Li (henryli001) wants to merge 1 commit into
Conversation
Read per-device PASID width and execution/privileged support from IOMMU_GET_HW_INFO, keep those capabilities separate from physical SMMU capabilities, and expose a synthetic PASID extended capability when VFIO hides the physical one. Append the capability to the visible extended-capability chain, emulate and reset its control register, keep its fabricated header read-only, and leave devices without PASID support unchanged.
|
This PR modifies files containing For more on why we check whole files, instead of just diffs, check out the Rustonomicon |
|
This is the endpoint half split from #4344. It is independently based on |
There was a problem hiding this comment.
🟡 Changes recommended
The synthetic PASID insertion logic can attach the new capability to an extended-capability header that this code also patches into an invalid/filtered state, which risks making the synthetic capability undiscoverable to guests.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR adds per-endpoint PASID discovery for nested (IOMMUFD-accelerated) VFIO devices and, when VFIO does not expose a physical PASID capability, synthesizes a guest-visible PCIe PASID extended capability (including control emulation/reset) so PASID-capable endpoints can function correctly behind a shared vSMMU.
Changes:
- Extend
IOMMU_GET_HW_INFOplumbing to return per-endpoint PASID parameters (max PASID width + exec/privileged support) and thread them through the VFIO assigned-device bring-up path. - Track PASID as a recognized PCIe extended capability ID and discover existing PASID capability presence.
- Append and emulate a synthetic PASID extended capability (header patching + control register emulation) when the endpoint supports PASID and no PASID capability is already exposed.
File summaries
| File | Description |
|---|---|
| vm/devices/user_driver/vfio_sys/src/iommufd.rs | Exposes additional IOMMU_GET_HW_INFO outputs (max PASID width + capability bits) via get_hw_info. |
| vm/devices/pci/vfio_assigned_device/src/iommufd_nesting.rs | Returns both host SMMU caps and new per-device PASID caps derived from IOMMU_GET_HW_INFO. |
| vm/devices/pci/vfio_assigned_device/src/manager.rs | Threads per-device PASID caps through nesting output alongside host SMMU caps. |
| vm/devices/pci/vfio_assigned_device/src/resolver.rs | Constructs per-device PasidCapabilities and passes them into assigned-device construction. |
| vm/devices/pci/vfio_assigned_device/src/lib.rs | Detects existing PASID extended capability, patches extended-cap chain, synthesizes PASID capability, and emulates PASID control/reset. |
| vm/devices/pci/pci_core/src/spec.rs | Adds PASID to the PCIe extended capability ID enum. |
Review details
- Files reviewed: 6/6 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| let cap_id = caps::ExtendedCapabilityId((header & 0xFFFF) as u16); | ||
| let cap_next = ((header >> 20) & 0xFFF) as u16; | ||
| result.last_ext_cap_offset = Some(offset); | ||
|
|
||
| tracing::debug!( |
| value: u32, | ||
| } | ||
|
|
||
| const SYNTHETIC_PASID_OFFSET: u16 = 0xff8; |
There was a problem hiding this comment.
Is it feasible to find a free place in config space instead? While unlikely, I think a device could have something (or a config space patch) here, and this hardcoded approach doesn't scale very well
| let cap_id = caps::ExtendedCapabilityId((header & 0xFFFF) as u16); | ||
| let cap_next = ((header >> 20) & 0xFFF) as u16; | ||
| result.last_ext_cap_offset = Some(offset); | ||
|
|
||
| tracing::debug!( |
| if self.capability & PASID_CAP_PRIV != 0 { | ||
| writable |= PASID_CAP_PRIV; | ||
| } | ||
| self.control = requested & writable; |
There was a problem hiding this comment.
I am not super familiar with VFIO or iommufd, does this change end up enabling PASID in endpoint hardware / physical SMMU?
| let af_flr_control_offset = caps.af_flr_control_offset; | ||
| let config_patches = caps.config_patches; | ||
| let mut config_patches = caps.config_patches; | ||
| let synthetic_pasid = synthesize_pasid_capability( |
There was a problem hiding this comment.
Do you think there's a reason we would want to disable this feature and present the config space without a synthesized capability? I'm trying to understand whether this should be configurable in the CLI
Summary
Expose a synthetic PCIe PASID capability for nested IOMMUFD devices when Linux VFIO hides the physical capability from the guest.
Changes
IOMMU_GET_HW_INFO.This is the endpoint-capability portion split out of #4344. It is based directly on
mainand does not depend on that PR.Validation
cargo +1.95.0 test -p vfio_assigned_device --lib(33 passed)RUSTFLAGS='-D warnings' cargo +1.95.0 clippy -p vfio_assigned_device --all-targets --all-featurescargo xtask fmt --only-diffed