| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384 |
- .. SPDX-License-Identifier: GPL-2.0+
- =======
- IOMMUFD
- =======
- :Author: Jason Gunthorpe
- :Author: Kevin Tian
- Overview
- ========
- IOMMUFD is the user API to control the IOMMU subsystem as it relates to managing
- IO page tables from userspace using file descriptors. It intends to be general
- and consumable by any driver that wants to expose DMA to userspace. These
- drivers are eventually expected to deprecate any internal IOMMU logic
- they may already/historically implement (e.g. vfio_iommu_type1.c).
- At minimum iommufd provides universal support of managing I/O address spaces and
- I/O page tables for all IOMMUs, with room in the design to add non-generic
- features to cater to specific hardware functionality.
- In this context the capital letter (IOMMUFD) refers to the subsystem while the
- small letter (iommufd) refers to the file descriptors created via /dev/iommu for
- use by userspace.
- Key Concepts
- ============
- User Visible Objects
- --------------------
- Following IOMMUFD objects are exposed to userspace:
- - IOMMUFD_OBJ_IOAS, representing an I/O address space (IOAS), allowing map/unmap
- of user space memory into ranges of I/O Virtual Address (IOVA).
- The IOAS is a functional replacement for the VFIO container, and like the VFIO
- container it copies an IOVA map to a list of iommu_domains held within it.
- - IOMMUFD_OBJ_DEVICE, representing a device that is bound to iommufd by an
- external driver.
- - IOMMUFD_OBJ_HWPT_PAGING, representing an actual hardware I/O page table
- (i.e. a single struct iommu_domain) managed by the iommu driver. "PAGING"
- primarily indicates this type of HWPT should be linked to an IOAS. It also
- indicates that it is backed by an iommu_domain with __IOMMU_DOMAIN_PAGING
- feature flag. This can be either an UNMANAGED stage-1 domain for a device
- running in the user space, or a nesting parent stage-2 domain for mappings
- from guest-level physical addresses to host-level physical addresses.
- The IOAS has a list of HWPT_PAGINGs that share the same IOVA mapping and
- it will synchronize its mapping with each member HWPT_PAGING.
- - IOMMUFD_OBJ_HWPT_NESTED, representing an actual hardware I/O page table
- (i.e. a single struct iommu_domain) managed by user space (e.g. guest OS).
- "NESTED" indicates that this type of HWPT should be linked to an HWPT_PAGING.
- It also indicates that it is backed by an iommu_domain that has a type of
- IOMMU_DOMAIN_NESTED. This must be a stage-1 domain for a device running in
- the user space (e.g. in a guest VM enabling the IOMMU nested translation
- feature.) As such, it must be created with a given nesting parent stage-2
- domain to associate to. This nested stage-1 page table managed by the user
- space usually has mappings from guest-level I/O virtual addresses to guest-
- level physical addresses.
- - IOMMUFD_FAULT, representing a software queue for an HWPT reporting IO page
- faults using the IOMMU HW's PRI (Page Request Interface). This queue object
- provides user space an FD to poll the page fault events and also to respond
- to those events. A FAULT object must be created first to get a fault_id that
- could be then used to allocate a fault-enabled HWPT via the IOMMU_HWPT_ALLOC
- command by setting the IOMMU_HWPT_FAULT_ID_VALID bit in its flags field.
- - IOMMUFD_OBJ_VIOMMU, representing a slice of the physical IOMMU instance,
- passed to or shared with a VM. It may be some HW-accelerated virtualization
- features and some SW resources used by the VM. For examples:
- * Security namespace for guest owned ID, e.g. guest-controlled cache tags
- * Non-device-affiliated event reporting, e.g. invalidation queue errors
- * Access to a shareable nesting parent pagetable across physical IOMMUs
- * Virtualization of various platforms IDs, e.g. RIDs and others
- * Delivery of paravirtualized invalidation
- * Direct assigned invalidation queues
- * Direct assigned interrupts
- Such a vIOMMU object generally has the access to a nesting parent pagetable
- to support some HW-accelerated virtualization features. So, a vIOMMU object
- must be created given a nesting parent HWPT_PAGING object, and then it would
- encapsulate that HWPT_PAGING object. Therefore, a vIOMMU object can be used
- to allocate an HWPT_NESTED object in place of the encapsulated HWPT_PAGING.
- .. note::
- The name "vIOMMU" isn't necessarily identical to a virtualized IOMMU in a
- VM. A VM can have one giant virtualized IOMMU running on a machine having
- multiple physical IOMMUs, in which case the VMM will dispatch the requests
- or configurations from this single virtualized IOMMU instance to multiple
- vIOMMU objects created for individual slices of different physical IOMMUs.
- In other words, a vIOMMU object is always a representation of one physical
- IOMMU, not necessarily of a virtualized IOMMU. For VMMs that want the full
- virtualization features from physical IOMMUs, it is suggested to build the
- same number of virtualized IOMMUs as the number of physical IOMMUs, so the
- passed-through devices would be connected to their own virtualized IOMMUs
- backed by corresponding vIOMMU objects, in which case a guest OS would do
- the "dispatch" naturally instead of VMM trappings.
- - IOMMUFD_OBJ_VDEVICE, representing a virtual device for an IOMMUFD_OBJ_DEVICE
- against an IOMMUFD_OBJ_VIOMMU. This virtual device holds the device's virtual
- information or attributes (related to the vIOMMU) in a VM. An immediate vDATA
- example can be the virtual ID of the device on a vIOMMU, which is a unique ID
- that VMM assigns to the device for a translation channel/port of the vIOMMU,
- e.g. vSID of ARM SMMUv3, vDeviceID of AMD IOMMU, and vRID of Intel VT-d to a
- Context Table. Potential use cases of some advanced security information can
- be forwarded via this object too, such as security level or realm information
- in a Confidential Compute Architecture. A VMM should create a vDEVICE object
- to forward all the device information in a VM, when it connects a device to a
- vIOMMU, which is a separate ioctl call from attaching the same device to an
- HWPT_PAGING that the vIOMMU holds.
- - IOMMUFD_OBJ_VEVENTQ, representing a software queue for a vIOMMU to report its
- events such as translation faults occurred to a nested stage-1 (excluding I/O
- page faults that should go through IOMMUFD_OBJ_FAULT) and HW-specific events.
- This queue object provides user space an FD to poll/read the vIOMMU events. A
- vIOMMU object must be created first to get its viommu_id, which could be then
- used to allocate a vEVENTQ. Each vIOMMU can support multiple types of vEVENTS,
- but is confined to one vEVENTQ per vEVENTQ type.
- - IOMMUFD_OBJ_HW_QUEUE, representing a hardware accelerated queue, as a subset
- of IOMMU's virtualization features, for the IOMMU HW to directly read or write
- the virtual queue memory owned by a guest OS. This HW-acceleration feature can
- allow VM to work with the IOMMU HW directly without a VM Exit, so as to reduce
- overhead from the hypercalls. Along with the HW QUEUE object, iommufd provides
- user space an mmap interface for VMM to mmap a physical MMIO region from the
- host physical address space to the guest physical address space, allowing the
- guest OS to directly control the allocated HW QUEUE. Thus, when allocating a
- HW QUEUE, the VMM must request a pair of mmap info (offset/length) and pass in
- exactly to an mmap syscall via its offset and length arguments.
- All user-visible objects are destroyed via the IOMMU_DESTROY uAPI.
- The diagrams below show relationships between user-visible objects and kernel
- datastructures (external to iommufd), with numbers referred to operations
- creating the objects and links::
- _______________________________________________________________________
- | iommufd (HWPT_PAGING only) |
- | |
- | [1] [3] [2] |
- | ________________ _____________ ________ |
- | | | | | | | |
- | | IOAS |<---| HWPT_PAGING |<---------------------| DEVICE | |
- | |________________| |_____________| |________| |
- | | | | |
- |_________|____________________|__________________________________|_____|
- | | |
- | ______v_____ ___v__
- | PFN storage | (paging) | |struct|
- |------------>|iommu_domain|<-----------------------|device|
- |____________| |______|
- _______________________________________________________________________
- | iommufd (with HWPT_NESTED) |
- | |
- | [1] [3] [4] [2] |
- | ________________ _____________ _____________ ________ |
- | | | | | | | | | |
- | | IOAS |<---| HWPT_PAGING |<---| HWPT_NESTED |<--| DEVICE | |
- | |________________| |_____________| |_____________| |________| |
- | | | | | |
- |_________|____________________|__________________|_______________|_____|
- | | | |
- | ______v_____ ______v_____ ___v__
- | PFN storage | (paging) | | (nested) | |struct|
- |------------>|iommu_domain|<----|iommu_domain|<----|device|
- |____________| |____________| |______|
- _______________________________________________________________________
- | iommufd (with vIOMMU/vDEVICE) |
- | |
- | [5] [6] |
- | _____________ _____________ |
- | | | | | |
- | |----------------| vIOMMU |<---| vDEVICE |<----| |
- | | | | |_____________| | |
- | | | | | |
- | | [1] | | [4] | [2] |
- | | ______ | | _____________ _|______ |
- | | | | | [3] | | | | | |
- | | | IOAS |<---|(HWPT_PAGING)|<---| HWPT_NESTED |<--| DEVICE | |
- | | |______| |_____________| |_____________| |________| |
- | | | | | | |
- |______|________|______________|__________________|_______________|_____|
- | | | | |
- ______v_____ | ______v_____ ______v_____ ___v__
- | struct | | PFN | (paging) | | (nested) | |struct|
- |iommu_device| |------>|iommu_domain|<----|iommu_domain|<----|device|
- |____________| storage|____________| |____________| |______|
- 1. IOMMUFD_OBJ_IOAS is created via the IOMMU_IOAS_ALLOC uAPI. An iommufd can
- hold multiple IOAS objects. IOAS is the most generic object and does not
- expose interfaces that are specific to single IOMMU drivers. All operations
- on the IOAS must operate equally on each of the iommu_domains inside of it.
- 2. IOMMUFD_OBJ_DEVICE is created when an external driver calls the IOMMUFD kAPI
- to bind a device to an iommufd. The driver is expected to implement a set of
- ioctls to allow userspace to initiate the binding operation. Successful
- completion of this operation establishes the desired DMA ownership over the
- device. The driver must also set the driver_managed_dma flag and must not
- touch the device until this operation succeeds.
- 3. IOMMUFD_OBJ_HWPT_PAGING can be created in two ways:
- * IOMMUFD_OBJ_HWPT_PAGING is automatically created when an external driver
- calls the IOMMUFD kAPI to attach a bound device to an IOAS. Similarly the
- external driver uAPI allows userspace to initiate the attaching operation.
- If a compatible member HWPT_PAGING object exists in the IOAS's HWPT_PAGING
- list, then it will be reused. Otherwise a new HWPT_PAGING that represents
- an iommu_domain to userspace will be created, and then added to the list.
- Successful completion of this operation sets up the linkages among IOAS,
- device and iommu_domain. Once this completes the device could do DMA.
- * IOMMUFD_OBJ_HWPT_PAGING can be manually created via the IOMMU_HWPT_ALLOC
- uAPI, provided an ioas_id via @pt_id to associate the new HWPT_PAGING to
- the corresponding IOAS object. The benefit of this manual allocation is to
- allow allocation flags (defined in enum iommufd_hwpt_alloc_flags), e.g. it
- allocates a nesting parent HWPT_PAGING if the IOMMU_HWPT_ALLOC_NEST_PARENT
- flag is set.
- 4. IOMMUFD_OBJ_HWPT_NESTED can be only manually created via the IOMMU_HWPT_ALLOC
- uAPI, provided an hwpt_id or a viommu_id of a vIOMMU object encapsulating a
- nesting parent HWPT_PAGING via @pt_id to associate the new HWPT_NESTED object
- to the corresponding HWPT_PAGING object. The associating HWPT_PAGING object
- must be a nesting parent manually allocated via the same uAPI previously with
- an IOMMU_HWPT_ALLOC_NEST_PARENT flag, otherwise the allocation will fail. The
- allocation will be further validated by the IOMMU driver to ensure that the
- nesting parent domain and the nested domain being allocated are compatible.
- Successful completion of this operation sets up linkages among IOAS, device,
- and iommu_domains. Once this completes the device could do DMA via a 2-stage
- translation, a.k.a nested translation. Note that multiple HWPT_NESTED objects
- can be allocated by (and then associated to) the same nesting parent.
- .. note::
- Either a manual IOMMUFD_OBJ_HWPT_PAGING or an IOMMUFD_OBJ_HWPT_NESTED is
- created via the same IOMMU_HWPT_ALLOC uAPI. The difference is at the type
- of the object passed in via the @pt_id field of struct iommufd_hwpt_alloc.
- 5. IOMMUFD_OBJ_VIOMMU can be only manually created via the IOMMU_VIOMMU_ALLOC
- uAPI, provided a dev_id (for the device's physical IOMMU to back the vIOMMU)
- and an hwpt_id (to associate the vIOMMU to a nesting parent HWPT_PAGING). The
- iommufd core will link the vIOMMU object to the struct iommu_device that the
- struct device is behind. And an IOMMU driver can implement a viommu_alloc op
- to allocate its own vIOMMU data structure embedding the core-level structure
- iommufd_viommu and some driver-specific data. If necessary, the driver can
- also configure its HW virtualization feature for that vIOMMU (and thus for
- the VM). Successful completion of this operation sets up the linkages between
- the vIOMMU object and the HWPT_PAGING, then this vIOMMU object can be used
- as a nesting parent object to allocate an HWPT_NESTED object described above.
- 6. IOMMUFD_OBJ_VDEVICE can be only manually created via the IOMMU_VDEVICE_ALLOC
- uAPI, provided a viommu_id for an iommufd_viommu object and a dev_id for an
- iommufd_device object. The vDEVICE object will be the binding between these
- two parent objects. Another @virt_id will be also set via the uAPI providing
- the iommufd core an index to store the vDEVICE object to a vDEVICE array per
- vIOMMU. If necessary, the IOMMU driver may choose to implement a vdevce_alloc
- op to init its HW for virtualization feature related to a vDEVICE. Successful
- completion of this operation sets up the linkages between vIOMMU and device.
- A device can only bind to an iommufd due to DMA ownership claim and attach to at
- most one IOAS object (no support of PASID yet).
- Kernel Datastructure
- --------------------
- User visible objects are backed by following datastructures:
- - iommufd_ioas for IOMMUFD_OBJ_IOAS.
- - iommufd_device for IOMMUFD_OBJ_DEVICE.
- - iommufd_hwpt_paging for IOMMUFD_OBJ_HWPT_PAGING.
- - iommufd_hwpt_nested for IOMMUFD_OBJ_HWPT_NESTED.
- - iommufd_fault for IOMMUFD_OBJ_FAULT.
- - iommufd_viommu for IOMMUFD_OBJ_VIOMMU.
- - iommufd_vdevice for IOMMUFD_OBJ_VDEVICE.
- - iommufd_veventq for IOMMUFD_OBJ_VEVENTQ.
- - iommufd_hw_queue for IOMMUFD_OBJ_HW_QUEUE.
- Several terminologies when looking at these datastructures:
- - Automatic domain - refers to an iommu domain created automatically when
- attaching a device to an IOAS object. This is compatible to the semantics of
- VFIO type1.
- - Manual domain - refers to an iommu domain designated by the user as the
- target pagetable to be attached to by a device. Though currently there are
- no uAPIs to directly create such domain, the datastructure and algorithms
- are ready for handling that use case.
- - In-kernel user - refers to something like a VFIO mdev that is using the
- IOMMUFD access interface to access the IOAS. This starts by creating an
- iommufd_access object that is similar to the domain binding a physical device
- would do. The access object will then allow converting IOVA ranges into struct
- page * lists, or doing direct read/write to an IOVA.
- iommufd_ioas serves as the metadata datastructure to manage how IOVA ranges are
- mapped to memory pages, composed of:
- - struct io_pagetable holding the IOVA map
- - struct iopt_area's representing populated portions of IOVA
- - struct iopt_pages representing the storage of PFNs
- - struct iommu_domain representing the IO page table in the IOMMU
- - struct iopt_pages_access representing in-kernel users of PFNs
- - struct xarray pinned_pfns holding a list of pages pinned by in-kernel users
- Each iopt_pages represents a logical linear array of full PFNs. The PFNs are
- ultimately derived from userspace VAs via an mm_struct. Once they have been
- pinned the PFNs are stored in IOPTEs of an iommu_domain or inside the pinned_pfns
- xarray if they have been pinned through an iommufd_access.
- PFN have to be copied between all combinations of storage locations, depending
- on what domains are present and what kinds of in-kernel "software access" users
- exist. The mechanism ensures that a page is pinned only once.
- An io_pagetable is composed of iopt_areas pointing at iopt_pages, along with a
- list of iommu_domains that mirror the IOVA to PFN map.
- Multiple io_pagetable-s, through their iopt_area-s, can share a single
- iopt_pages which avoids multi-pinning and double accounting of page
- consumption.
- iommufd_ioas is shareable between subsystems, e.g. VFIO and VDPA, as long as
- devices managed by different subsystems are bound to a same iommufd.
- IOMMUFD User API
- ================
- .. kernel-doc:: include/uapi/linux/iommufd.h
- IOMMUFD Kernel API
- ==================
- The IOMMUFD kAPI is device-centric with group-related tricks managed behind the
- scene. This allows the external drivers calling such kAPI to implement a simple
- device-centric uAPI for connecting its device to an iommufd, instead of
- explicitly imposing the group semantics in its uAPI as VFIO does.
- .. kernel-doc:: drivers/iommu/iommufd/device.c
- :export:
- .. kernel-doc:: drivers/iommu/iommufd/main.c
- :export:
- VFIO and IOMMUFD
- ----------------
- Connecting a VFIO device to iommufd can be done in two ways.
- First is a VFIO compatible way by directly implementing the /dev/vfio/vfio
- container IOCTLs by mapping them into io_pagetable operations. Doing so allows
- the use of iommufd in legacy VFIO applications by symlinking /dev/vfio/vfio to
- /dev/iommufd or extending VFIO to SET_CONTAINER using an iommufd instead of a
- container fd.
- The second approach directly extends VFIO to support a new set of device-centric
- user API based on aforementioned IOMMUFD kernel API. It requires userspace
- change but better matches the IOMMUFD API semantics and easier to support new
- iommufd features when comparing it to the first approach.
- Currently both approaches are still work-in-progress.
- There are still a few gaps to be resolved to catch up with VFIO type1, as
- documented in iommufd_vfio_check_extension().
- Future TODOs
- ============
- Currently IOMMUFD supports only kernel-managed I/O page table, similar to VFIO
- type1. New features on the radar include:
- - Binding iommu_domain's to PASID/SSID
- - Userspace page tables, for ARM, x86 and S390
- - Kernel bypass'd invalidation of user page tables
- - Re-use of the KVM page table in the IOMMU
- - Dirty page tracking in the IOMMU
- - Runtime Increase/Decrease of IOPTE size
- - PRI support with faults resolved in userspace
|