IOMMUFD¶
- 作者:
Jason Gunthorpe
- 作者:
Kevin Tian
概述¶
IOMMUFD 是用户 API,用于控制 IOMMU 子系统,因为它涉及到使用文件描述符从用户空间管理 IO 页表。它旨在通用,并且可以被任何想要向用户空间暴露 DMA 的驱动程序使用。这些驱动程序最终预计会弃用它们可能已经/历史上实现的任何内部 IOMMU 逻辑(例如,vfio_iommu_type1.c)。
IOMMUFD 至少为所有 IOMMU 提供管理 I/O 地址空间和 I/O 页表的通用支持,并且设计中留有空间来添加非通用功能,以满足特定硬件功能的需求。
在此上下文中,大写字母 (IOMMUFD) 指的是子系统,而小写字母 (iommufd) 指的是通过 /dev/iommu 创建的供用户空间使用的文件描述符。
关键概念¶
用户可见对象¶
以下 IOMMUFD 对象暴露给用户空间
IOMMUFD_OBJ_IOAS,表示 I/O 地址空间 (IOAS),允许将用户空间内存映射/取消映射到 I/O 虚拟地址 (IOVA) 的范围内。
IOAS 是 VFIO 容器的功能替代品,并且像 VFIO 容器一样,它将 IOVA 映射复制到其中包含的 iommu_domain 列表。
IOMMUFD_OBJ_DEVICE,表示由外部驱动程序绑定到 iommufd 的设备。
IOMMUFD_OBJ_HWPT_PAGING,表示由 iommu 驱动程序管理的实际硬件 I/O 页表(即单个 struct iommu_domain)。 “PAGING” 主要指示此类型的 HWPT 应链接到 IOAS。它还表明它由具有 __IOMMU_DOMAIN_PAGING 功能标志的 iommu_domain 支持。这可以是用户空间中运行的设备的 UNMANAGED stage-1 域,也可以是从客户机级物理地址到主机级物理地址的映射的嵌套父级 stage-2 域。
IOAS 有一个 HWPT_PAGING 列表,这些列表共享相同的 IOVA 映射,并且它将使其映射与每个成员 HWPT_PAGING 同步。
IOMMUFD_OBJ_HWPT_NESTED,表示由用户空间(例如,客户机操作系统)管理的实际硬件 I/O 页表(即单个 struct iommu_domain)。 “NESTED” 表示此类型的 HWPT 应链接到 HWPT_PAGING。它还表明它由具有 IOMMU_DOMAIN_NESTED 类型的 iommu_domain 支持。这必须是用户空间中运行的设备的 stage-1 域(例如,在启用 IOMMU 嵌套转换功能的客户机 VM 中)。因此,必须使用给定的嵌套父级 stage-2 域创建它才能关联。用户空间管理的此嵌套 stage-1 页表通常具有从客户机级 I/O 虚拟地址到客户机级物理地址的映射。
IOMMUFD_OBJ_VIOMMU,表示传递给 VM 或与 VM 共享的物理 IOMMU 实例的一部分。它可能是一些硬件加速的虚拟化功能和 VM 使用的一些软件资源。 例如
客户机拥有的 ID 的安全命名空间,例如,客户机控制的缓存标签
非设备相关的事件报告,例如,失效队列错误
访问跨物理 IOMMU 的可共享嵌套父页表
各种平台 ID 的虚拟化,例如,RID 和其他
传递半虚拟化失效
直接分配的失效队列
直接分配的中断
这样的 vIOMMU 对象通常可以访问嵌套的父页表,以支持一些硬件加速的虚拟化功能。因此,必须给定一个嵌套的父 HWPT_PAGING 对象来创建 vIOMMU 对象,然后它将封装该 HWPT_PAGING 对象。因此,可以使用 vIOMMU 对象来分配封装的 HWPT_PAGING 的 HWPT_NESTED 对象。
注意
名称 “vIOMMU” 不一定与 VM 中的虚拟化 IOMMU 相同。VM 可以在具有多个物理 IOMMU 的机器上运行一个巨大的虚拟化 IOMMU,在这种情况下,VMM 会将来自此单个虚拟化 IOMMU 实例的请求或配置分派到为不同物理 IOMMU 的各个切片创建的多个 vIOMMU 对象。换句话说,vIOMMU 对象始终是物理 IOMMU 的表示,而不一定是虚拟化 IOMMU 的表示。对于希望从物理 IOMMU 获得完整虚拟化功能的 VMM,建议构建与物理 IOMMU 数量相同的虚拟化 IOMMU,以便传递的设备连接到其自己的虚拟化 IOMMU,这些 IOMMU 由相应的 vIOMMU 对象支持,在这种情况下,客户机操作系统将自然地执行“分派”,而不是 VMM 陷阱。
IOMMUFD_OBJ_VDEVICE,表示针对 IOMMUFD_OBJ_VIOMMU 的 IOMMUFD_OBJ_DEVICE 的虚拟设备。此虚拟设备在 VM 中保存设备的虚拟信息或属性(与 vIOMMU 相关)。一个直接的 vDATA 示例可以是设备在 vIOMMU 上的虚拟 ID,这是 VMM 为 vIOMMU 的转换通道/端口分配给设备的唯一 ID,例如,ARM SMMUv3 的 vSID,AMD IOMMU 的 vDeviceID 以及 Intel VT-d 到上下文表的 vRID。一些高级安全信息的潜在用例也可以通过此对象转发,例如,机密计算架构中的安全级别或领域信息。当 VMM 将设备连接到 vIOMMU 时,VMM 应创建一个 vDEVICE 对象以转发 VM 中的所有设备信息,这与将同一设备附加到 vIOMMU 持有的 HWPT_PAGING 的 ioctl 调用是分开的。
所有用户可见的对象都通过 IOMMU_DESTROY uAPI 销毁。
下图显示了用户可见对象和内核数据结构(iommufd 外部)之间的关系,其中数字指的是创建对象和链接的操作
_______________________________________________________________________
| 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|____________| |____________| |______|
IOMMUFD_OBJ_IOAS 通过 IOMMU_IOAS_ALLOC uAPI 创建。一个 iommufd 可以保存多个 IOAS 对象。 IOAS 是最通用的对象,不暴露特定于单个 IOMMU 驱动程序的接口。对 IOAS 的所有操作都必须平等地作用于其中的每个 iommu_domain。
当外部驱动程序调用 IOMMUFD kAPI 将设备绑定到 iommufd 时,会创建 IOMMUFD_OBJ_DEVICE。驱动程序应实现一组 ioctl,以允许用户空间启动绑定操作。此操作成功完成后,将建立对设备的所需 DMA 所有权。驱动程序还必须设置 driver_managed_dma 标志,并且在操作成功之前不得接触设备。
IOMMUFD_OBJ_HWPT_PAGING 可以通过两种方式创建
当外部驱动程序调用 IOMMUFD kAPI 将绑定的设备附加到 IOAS 时,会自动创建 IOMMUFD_OBJ_HWPT_PAGING。类似地,外部驱动程序 uAPI 允许用户空间启动附加操作。如果 IOAS 的 HWPT_PAGING 列表中存在兼容的成员 HWPT_PAGING 对象,则将重用它。否则,将创建一个新的 HWPT_PAGING,该 HWPT_PAGING 表示用户空间的 iommu_domain,然后将其添加到列表中。此操作成功完成后,将建立 IOAS、设备和 iommu_domain 之间的链接。完成此操作后,设备可以执行 DMA。
IOMMUFD_OBJ_HWPT_PAGING 可以通过 IOMMU_HWPT_ALLOC uAPI 手动创建,前提是通过 @pt_id 提供 ioas_id,以将新的 HWPT_PAGING 与相应的 IOAS 对象关联。此手动分配的好处是允许分配标志(在
enum iommufd_hwpt_alloc_flags
中定义),例如,如果设置了 IOMMU_HWPT_ALLOC_NEST_PARENT 标志,它将分配一个嵌套的父 HWPT_PAGING。
IOMMUFD_OBJ_HWPT_NESTED 只能通过 IOMMU_HWPT_ALLOC uAPI 手动创建,前提是通过 @pt_id 提供一个 hwpt_id 或一个封装嵌套父 HWPT_PAGING 的 vIOMMU 对象的 viommu_id,以将新的 HWPT_NESTED 对象与相应的 HWPT_PAGING 对象关联。关联的 HWPT_PAGING 对象必须是通过同一 uAPI 之前使用 IOMMU_HWPT_ALLOC_NEST_PARENT 标志手动分配的嵌套父级,否则分配将失败。IOMMU 驱动程序将进一步验证该分配,以确保嵌套父域和要分配的嵌套域兼容。此操作成功完成后,将在 IOAS、设备和 iommu_domain 之间建立链接。完成此操作后,设备可以通过 2 阶段转换(又名嵌套转换)执行 DMA。 请注意,可以通过(然后关联到)同一个嵌套父级来分配多个 HWPT_NESTED 对象。
注意
手动 IOMMUFD_OBJ_HWPT_PAGING 或 IOMMUFD_OBJ_HWPT_NESTED 都是通过同一 IOMMU_HWPT_ALLOC uAPI 创建的。区别在于通过 struct iommufd_hwpt_alloc 的 @pt_id 字段传入的对象类型。
IOMMUFD_OBJ_VIOMMU 只能通过 IOMMU_VIOMMU_ALLOC uAPI 手动创建,前提是提供 dev_id(用于支持 vIOMMU 的设备的物理 IOMMU)和一个 hwpt_id(将 vIOMMU 与嵌套的父 HWPT_PAGING 关联)。iommufd 核心会将 vIOMMU 对象链接到
struct device
后面的 struct iommu_device。并且 IOMMU 驱动程序可以实现 viommu_alloc op,以分配其自己的 vIOMMU 数据结构,该结构嵌入核心级结构 iommufd_viommu 和一些特定于驱动程序的数据。如有必要,驱动程序还可以为该 vIOMMU(以及 VM)配置其硬件虚拟化功能。此操作成功完成后,将在 vIOMMU 对象和 HWPT_PAGING 之间建立链接,然后可以将此 vIOMMU 对象用作嵌套父对象来分配上述 HWPT_NESTED 对象。IOMMUFD_OBJ_VDEVICE 只能通过 IOMMU_VDEVICE_ALLOC uAPI 手动创建,前提是提供一个 iommufd_viommu 对象的 viommu_id 和一个 iommufd_device 对象的 dev_id。vDEVICE 对象将是这两个父对象之间的绑定。还将通过 uAPI 设置另一个 @virt_id,从而为 iommufd 核心提供一个索引,以便将 vDEVICE 对象存储到每个 vIOMMU 的 vDEVICE 数组中。如有必要,IOMMU 驱动程序可以选择实现 vdevce_alloc op,以初始化其与 vDEVICE 相关的硬件虚拟化功能。此操作成功完成后,将在 vIOMMU 和设备之间建立链接。
由于 DMA 所有权声明,一个设备只能绑定到一个 iommufd,并且最多可以附加到一个 IOAS 对象(尚不支持 PASID)。
内核数据结构¶
用户可见的对象由以下数据结构支持
用于 IOMMUFD_OBJ_IOAS 的 iommufd_ioas。
用于 IOMMUFD_OBJ_DEVICE 的 iommufd_device。
用于 IOMMUFD_OBJ_HWPT_PAGING 的 iommufd_hwpt_paging。
用于 IOMMUFD_OBJ_HWPT_NESTED 的 iommufd_hwpt_nested。
用于 IOMMUFD_OBJ_VIOMMU 的 iommufd_viommu。
用于 IOMMUFD_OBJ_VDEVICE 的 iommufd_vdevice。
查看这些数据结构时的一些术语
自动域 - 指的是将设备附加到 IOAS 对象时自动创建的 iommu 域。这与 VFIO type1 的语义兼容。
手动域 - 指的是用户指定的 IOMMU 域,作为设备要附加到的目标页表。虽然目前没有直接创建此类域的 uAPI,但数据结构和算法已准备好处理该用例。
内核用户 - 指的是类似 VFIO mdev 这样的东西,它使用 IOMMUFD 访问接口来访问 IOAS。这首先创建一个 iommufd_access 对象,类似于物理设备进行域绑定。然后,访问对象将允许将 IOVA 范围转换为 struct page * 列表,或者对 IOVA 进行直接读/写。
iommufd_ioas 作为元数据数据结构,用于管理 IOVA 范围如何映射到内存页,由以下部分组成:
struct io_pagetable,保存 IOVA 映射
struct iopt_area,表示 IOVA 的已填充部分
struct iopt_pages,表示 PFN 的存储
struct iommu_domain,表示 IOMMU 中的 IO 页表
struct iopt_pages_access,表示 PFN 的内核用户
struct xarray
pinned_pfns,保存内核用户固定的页面列表
每个 iopt_pages 代表一个完整的 PFN 的逻辑线性数组。PFN 最终通过 mm_struct 从用户空间 VA 派生而来。一旦它们被固定,PFN 将存储在 iommu_domain 的 IOPTE 中,或者如果它们是通过 iommufd_access 固定的,则存储在 pinned_pfns xarray 中。
PFN 必须在所有存储位置的组合之间复制,具体取决于存在哪些域以及存在哪些类型的内核“软件访问”用户。该机制确保一个页面只被固定一次。
一个 io_pagetable 由指向 iopt_pages 的 iopt_area 以及镜像 IOVA 到 PFN 映射的 iommu_domain 列表组成。
多个 io_pagetable 通过它们的 iopt_area 可以共享单个 iopt_pages,这避免了多重固定和页面消耗的双重计算。
iommufd_ioas 可在子系统(例如 VFIO 和 VDPA)之间共享,只要由不同子系统管理的设备绑定到同一个 iommufd。
IOMMUFD 用户 API¶
通用 ioctl 格式
ioctl 接口遵循通用格式以允许扩展。每个 ioctl 都以结构指针作为参数传入,在第一个 u32 中提供结构的大小。内核检查超出其理解的任何结构空间是否为 0。这允许用户空间使用向后兼容的部分,同时始终使用较新的、较大的结构。
ioctl 对常见的错误码使用标准含义
ENOTTY:根本不支持 IOCTL 号本身
E2BIG:支持 IOCTL 号,但提供的结构在内核不理解的部分中包含非零值。
EOPNOTSUPP:支持 IOCTL 号,并且理解该结构,但已知字段的值内核不理解或不支持。
EINVAL:关于 IOCTL 的所有内容都被理解了,但某个字段不正确。
ENOENT:提供的 ID 或 IOVA 不存在。
ENOMEM:内存不足。
EOVERFLOW:数学运算溢出。
以及特定 ioctl 中的其他错误码。
-
struct iommu_destroy¶
ioctl(IOMMU_DESTROY)
定义:
struct iommu_destroy {
__u32 size;
__u32 id;
};
成员
size
sizeof(
struct iommu_destroy
)id
要销毁的 iommufd 对象 ID。可以是任何可销毁的对象类型。
描述
销毁 iommufd 中持有的任何对象。
-
struct iommu_ioas_alloc¶
ioctl(IOMMU_IOAS_ALLOC)
定义:
struct iommu_ioas_alloc {
__u32 size;
__u32 flags;
__u32 out_ioas_id;
};
成员
size
sizeof(
struct iommu_ioas_alloc
)flags
必须为 0
out_ioas_id
分配的对象输出 IOAS ID
描述
分配一个 IO 地址空间 (IOAS),其中包含 IO 虚拟地址 (IOVA) 到内存的映射。
-
struct iommu_iova_range¶
ioctl(IOMMU_IOVA_RANGE)
定义:
struct iommu_iova_range {
__aligned_u64 start;
__aligned_u64 last;
};
成员
start
第一个 IOVA
last
包含的最后一个 IOVA
描述
IOVA 空间中的间隔。
-
struct iommu_ioas_iova_ranges¶
ioctl(IOMMU_IOAS_IOVA_RANGES)
定义:
struct iommu_ioas_iova_ranges {
__u32 size;
__u32 ioas_id;
__u32 num_iovas;
__u32 __reserved;
__aligned_u64 allowed_iovas;
__aligned_u64 out_iova_alignment;
};
成员
size
sizeof(
struct iommu_ioas_iova_ranges
)ioas_id
从中读取范围的 IOAS ID
num_iovas
输入/输出 IOAS 中范围的总数
__reserved
必须为 0
allowed_iovas
指向
struct iommu_iova_range
输出数组的指针out_iova_alignment
映射 IOVA 所需的最小对齐
描述
查询 IOAS 以获取允许的 IOVA 范围。不允许映射这些范围之外的 IOVA。num_iovas 将设置为 iova 的总数,并且 allowed_iovas[] 将在允许的空间中填充。
允许的范围取决于 DMA 操作采取的硬件路径,并且可以在 IOAS 的生命周期内更改。一个新的空 IOAS 将具有完整的范围,并且每个附加的设备将根据该设备的硬件限制缩小范围。分离设备可以扩大范围。用户空间应在每次附加/分离后查询范围,以了解哪些 IOVA 可用于映射。
在输入时,num_iovas 是 allowed_iovas 数组的长度。在输出时,它是填充的 iova 的总数。如果 num_iovas 太小,ioctl 将返回 -EMSGSIZE 并将 num_iovas 设置为所需的值。在这种情况下,调用者应分配一个更大的输出数组并重新发出 ioctl。
out_iova_alignment 返回可以给 IOMMU_IOAS_MAP/COPY 的最小 IOVA 对齐方式。IOVA 必须满足
starting_iova % out_iova_alignment == 0
(starting_iova + length) % out_iova_alignment == 0
out_iova_alignment 可以为 1,表示允许任何 IOVA。它不能高于系统 PAGE_SIZE。
-
struct iommu_ioas_allow_iovas¶
ioctl(IOMMU_IOAS_ALLOW_IOVAS)
定义:
struct iommu_ioas_allow_iovas {
__u32 size;
__u32 ioas_id;
__u32 num_iovas;
__u32 __reserved;
__aligned_u64 allowed_iovas;
};
成员
size
sizeof(
struct iommu_ioas_allow_iovas
)ioas_id
要从中允许 IOVA 的 IOAS ID
num_iovas
输入/输出 IOAS 中范围的总数
__reserved
必须为 0
allowed_iovas
指向
struct iommu_iova_range
数组的指针
描述
确保 IOVA 范围始终可用于分配。如果此调用成功,则 IOMMU_IOAS_IOVA_RANGES 将永远不会返回比此处提供的范围窄的 IOVA 范围列表。如果 IOMMU_IOAS_IOVA_RANGES 当前比给定的范围窄,则此调用将失败。
首次创建 IOAS 时,IOVA_RANGES 的大小将最大,并且随着设备的附加,IOVA 将根据设备限制而缩小。当指定允许的范围时,将拒绝任何缩小,即如果设备需要在允许的范围内进行限制,则设备附加可能会失败。
自动 IOVA 分配也会受到此调用的影响。如果存在允许的 IOVA,则 MAP 将仅在允许的 IOVA 内分配。
此调用将使用给定的列表替换整个允许列表。
-
enum iommufd_ioas_map_flags¶
映射和复制的标志
常量
IOMMU_IOAS_MAP_FIXED_IOVA
如果清除,内核将计算一个适当的 IOVA 来放置映射
IOMMU_IOAS_MAP_WRITEABLE
允许 DMA 写入此映射
IOMMU_IOAS_MAP_READABLE
允许 DMA 从此映射读取
-
struct iommu_ioas_map¶
ioctl(IOMMU_IOAS_MAP)
定义:
struct iommu_ioas_map {
__u32 size;
__u32 flags;
__u32 ioas_id;
__u32 __reserved;
__aligned_u64 user_va;
__aligned_u64 length;
__aligned_u64 iova;
};
成员
size
sizeof(
struct iommu_ioas_map
)flags
ioas_id
要更改映射的 IOAS ID
__reserved
必须为 0
user_va
指向要开始映射的用户空间指针
length
要映射的字节数
iova
放置映射的 IOVA。如果设置了 IOMMU_IOAS_MAP_FIXED_IOVA,则必须将其作为输入提供。
描述
从用户指针设置 IOVA 映射。如果指定了 FIXED_IOVA,则映射将在 iova 处建立,否则将根据保留列表和允许列表自动选择一个合适的位置并在 iova 中返回。
如果指定了 IOMMU_IOAS_MAP_FIXED_IOVA,则 iova 范围当前必须未使用,无法替换现有 IOVA。
-
struct iommu_ioas_map_file¶
ioctl(IOMMU_IOAS_MAP_FILE)
定义:
struct iommu_ioas_map_file {
__u32 size;
__u32 flags;
__u32 ioas_id;
__s32 fd;
__aligned_u64 start;
__aligned_u64 length;
__aligned_u64 iova;
};
成员
size
sizeof(
struct iommu_ioas_map_file
)flags
与 iommu_ioas_map 相同
ioas_id
与 iommu_ioas_map 相同
fd
要映射的 memfd
start
从文件起始位置到映射起始位置的字节偏移量
length
与 iommu_ioas_map 相同
iova
与 iommu_ioas_map 相同
描述
从 memfd 文件设置 IOVA 映射。所有其他参数和语义与 IOMMU_IOAS_MAP 匹配。
-
struct iommu_ioas_copy¶
ioctl(IOMMU_IOAS_COPY)
定义:
struct iommu_ioas_copy {
__u32 size;
__u32 flags;
__u32 dst_ioas_id;
__u32 src_ioas_id;
__aligned_u64 length;
__aligned_u64 dst_iova;
__aligned_u64 src_iova;
};
成员
size
sizeof(
struct iommu_ioas_copy
)flags
dst_ioas_id
要更改映射的 IOAS ID
src_ioas_id
要复制的源 IOAS ID
length
要复制和映射的字节数
dst_iova
放置映射的 IOVA。如果设置了 IOMMU_IOAS_MAP_FIXED_IOVA,则必须将其作为输入提供。
src_iova
开始复制的 IOVA
描述
从 src_ioas_id 复制已存在的映射,并在 dst_ioas_id 中建立该映射。src iova/长度必须与 IOMMU_IOAS_MAP 使用的范围完全匹配。
这可以用于高效地将 IOAS 的子集克隆到另一个 IOAS,或者作为一种“缓存”来加速映射。与建立等效的新映射相比,复制具有效率优势,因为内部资源是共享的,并且内核只会固定用户内存一次。
-
struct iommu_ioas_unmap¶
ioctl(IOMMU_IOAS_UNMAP)
定义:
struct iommu_ioas_unmap {
__u32 size;
__u32 ioas_id;
__aligned_u64 iova;
__aligned_u64 length;
};
成员
size
sizeof(
struct iommu_ioas_unmap
)ioas_id
要更改映射的 IOAS ID
iova
开始取消映射的 IOVA
length
要取消映射的字节数,并返回取消映射的字节数
描述
取消映射一个 IOVA 范围。iova/长度必须是先前使用 IOMMU_IOAS_MAP 或 IOMMU_IOAS_COPY 映射的范围的超集。不允许拆分或截断范围。值 0 到 U64_MAX 将取消映射所有内容。
-
enum iommufd_option¶
ioctl(IOMMU_OPTION_RLIMIT_MODE) 和 ioctl(IOMMU_OPTION_HUGE_PAGES)
常量
IOMMU_OPTION_RLIMIT_MODE
更改 RLIMIT_MEMLOCK 记账的工作方式。调用者必须具有调用此功能的权限。值 0(默认)是基于用户的记账,1 使用基于进程的记账。全局选项,object_id 必须为 0
IOMMU_OPTION_HUGE_PAGES
值 1(默认)允许在生成 iommu 映射时组合连续的页。值 0 禁用组合,所有内容都映射到 PAGE_SIZE。这对于基准测试很有用。这是一个按 IOAS 设置的选项,object_id 必须是 IOAS ID。
-
enum iommufd_option_ops¶
ioctl(IOMMU_OPTION_OP_SET) 和 ioctl(IOMMU_OPTION_OP_GET)
常量
IOMMU_OPTION_OP_SET
设置选项的值
IOMMU_OPTION_OP_GET
获取选项的值
-
struct iommu_option¶
iommu 选项多路复用器
定义:
struct iommu_option {
__u32 size;
__u32 option_id;
__u16 op;
__u16 __reserved;
__u32 object_id;
__aligned_u64 val64;
};
成员
size
sizeof(
struct iommu_option
)option_id
op
__reserved
必须为 0
object_id
如果需要,对象的 ID
val64
要设置的选项值或获取时返回的值
描述
更改一个简单的选项值。此多路复用器允许控制对象上的选项。IOMMU_OPTION_OP_SET 将加载一个选项,IOMMU_OPTION_OP_GET 将返回当前值。
-
enum iommufd_vfio_ioas_op¶
IOMMU_VFIO_IOAS_* ioctl
常量
IOMMU_VFIO_IOAS_GET
获取当前的兼容性 IOAS
IOMMU_VFIO_IOAS_SET
更改当前的兼容性 IOAS
IOMMU_VFIO_IOAS_CLEAR
禁用 VFIO 兼容性
-
struct iommu_vfio_ioas¶
ioctl(IOMMU_VFIO_IOAS)
定义:
struct iommu_vfio_ioas {
__u32 size;
__u32 ioas_id;
__u16 op;
__u16 __reserved;
};
成员
size
sizeof(
struct iommu_vfio_ioas
)ioas_id
对于 IOMMU_VFIO_IOAS_SET,是要设置的输入 IOAS ID。对于 IOMMU_VFIO_IOAS_GET,将输出 IOAS ID
op
__reserved
必须为 0
描述
VFIO 兼容性支持使用单个 ioas,因为 VFIO API 不支持 ID 字段。设置或获取 VFIO 兼容性将使用的 IOAS。当在 iommufd 上使用 VFIO_GROUP_SET_CONTAINER 时,它将获取兼容性 ioas,或者通过获取已设置的内容,或者自动创建一个。从那时起,VFIO 将继续使用该 ioas,并且不受此 ioctl 的影响。SET 或 CLEAR 不会销毁任何自动创建的 IOAS。
-
enum iommufd_hwpt_alloc_flags¶
HWPT 分配的标志
常量
IOMMU_HWPT_ALLOC_NEST_PARENT
如果设置,则分配一个可以作为嵌套配置中的父 HWPT 的 HWPT。
IOMMU_HWPT_ALLOC_DIRTY_TRACKING
设备 IOMMU 的脏跟踪支持在设备附加时强制执行
IOMMU_HWPT_FAULT_ID_VALID
hwpt 分配数据的 fault_id 字段有效。
IOMMU_HWPT_ALLOC_PASID
请求一个可以与 PASID 一起使用的域。该域可以附加到设备上的任何 PASID。附加到设备的非 PASID 部分的任何域也必须标记,否则附加 PASID 将被阻止。如果 IOMMU 不支持 PASID,它将返回错误 (-EOPNOTSUPP)。
-
enum iommu_hwpt_vtd_s1_flags¶
英特尔 VT-d stage-1 页表条目属性
常量
IOMMU_VTD_S1_SRE
监管者请求
IOMMU_VTD_S1_EAFE
扩展访问使能
IOMMU_VTD_S1_WPE
写保护使能
-
struct iommu_hwpt_vtd_s1¶
英特尔 VT-d stage-1 页表信息 (IOMMU_HWPT_DATA_VTD_S1)
定义:
struct iommu_hwpt_vtd_s1 {
__aligned_u64 flags;
__aligned_u64 pgtbl_addr;
__u32 addr_width;
__u32 __reserved;
};
成员
flags
pgtbl_addr
stage-1 页表的基址。
addr_width
stage-1 页表的地址宽度
__reserved
必须为 0
-
struct iommu_hwpt_arm_smmuv3¶
ARM SMMUv3 嵌套 STE (IOMMU_HWPT_DATA_ARM_SMMUV3)
定义:
struct iommu_hwpt_arm_smmuv3 {
__aligned_le64 ste[2];
};
成员
ste
用于转换的用户空间流表条目的前两个双字。必须是小端字节序。允许的字段:(请参阅 SMMUv3 HW 规范中的“5.2 流表条目”)- word-0:V,Cfg,S1Fmt,S1ContextPtr,S1CDMax - word-1:EATS,S1DSS,S1CIR,S1COR,S1CSH,S1STALLD
描述
如果 ste 不合法或包含任何不允许的字段,将返回 -EIO。Cfg 可用于选择 S1,Bypass 或 Abort 配置。Bypass 嵌套域的转换将与嵌套父级相同。S1 将安装一个指向用户空间内存的上下文描述符表,该用户空间内存由嵌套父级转换。
-
enum iommu_hwpt_data_type¶
IOMMU HWPT 数据类型
常量
IOMMU_HWPT_DATA_NONE
无数据
IOMMU_HWPT_DATA_VTD_S1
英特尔 VT-d stage-1 页表
IOMMU_HWPT_DATA_ARM_SMMUV3
ARM SMMUv3 上下文描述符表
-
struct iommu_hwpt_alloc¶
ioctl(IOMMU_HWPT_ALLOC)
定义:
struct iommu_hwpt_alloc {
__u32 size;
__u32 flags;
__u32 dev_id;
__u32 pt_id;
__u32 out_hwpt_id;
__u32 __reserved;
__u32 data_type;
__u32 data_len;
__aligned_u64 data_uptr;
__u32 fault_id;
__u32 __reserved2;
};
成员
size
sizeof(
struct iommu_hwpt_alloc
)flags
dev_id
为其分配此 HWPT 的设备
pt_id
要将此 HWPT 连接到的 IOAS 或 HWPT 或 vIOMMU
out_hwpt_id
新 HWPT 的 ID
__reserved
必须为 0
data_type
data_len
类型特定数据的长度
data_uptr
指向类型特定数据的用户指针
fault_id
IOMMUFD_FAULT 对象的 ID。仅当设置 IOMMU_HWPT_FAULT_ID_VALID 的 flags 字段时才有效。
__reserved2
填充为 64 位对齐。必须为 0。
描述
显式分配硬件页表对象。这是 iommufd_device_attach()
返回的相同对象类型,表示底层 iommu 驱动程序的 iommu_domain 内核对象。
将创建一个内核管理的 HWPT,其中包含来自给定 IOAS 的映射(通过 pt_id)。此分配的 data_type 必须设置为 IOMMU_HWPT_DATA_NONE。可以通过 flags 传递 IOMMU_HWPT_ALLOC_NEST_PARENT,将 HWPT 分配为嵌套配置的父 HWPT。
将通过给定的 vIOMMU(包装父 HWPT)或父 HWPT(通过 pt_id)创建一个用户管理的嵌套 HWPT,其中父 HWPT 必须先前通过同一 ioctl 从给定的 IOAS (pt_id) 分配。在这种情况下,data_type 必须设置为与底层 IOMMU 硬件支持的 I/O 页表类型相对应的预定义类型。通过 dev_id 的设备和通过 pt_id 的 vIOMMU 必须与同一 IOMMU 实例相关联。
如果 data_type 设置为 IOMMU_HWPT_DATA_NONE,则 data_len 和 data_uptr 应为零。否则,必须给出 data_len 和 data_uptr。
-
enum iommu_hw_info_vtd_flags¶
VT-d 硬件信息的标志
常量
IOMMU_HW_INFO_VTD_ERRATA_772415_SPR17
如果设置,则禁止在 nested_parent 域上进行只读映射。https://www.intel.com/content/www/us/en/content-details/772415/content-details.html
-
struct iommu_hw_info_vtd¶
Intel VT-d 硬件信息
定义:
struct iommu_hw_info_vtd {
__u32 flags;
__u32 __reserved;
__aligned_u64 cap_reg;
__aligned_u64 ecap_reg;
};
成员
flags
__reserved
必须为 0
cap_reg
Intel VT-d 规范 11.4.2 节“能力寄存器”中定义的 Intel VT-d 能力寄存器的值。
ecap_reg
Intel VT-d 规范 11.4.3 节“扩展能力寄存器”中定义的 Intel VT-d 扩展能力寄存器的值。
描述
用户需要理解 Intel VT-d 规范才能解码寄存器值。
-
struct iommu_hw_info_arm_smmuv3¶
ARM SMMUv3 硬件信息 (IOMMU_HW_INFO_TYPE_ARM_SMMUV3)
定义:
struct iommu_hw_info_arm_smmuv3 {
__u32 flags;
__u32 __reserved;
__u32 idr[6];
__u32 iidr;
__u32 aidr;
};
成员
flags
必须设置为 0
__reserved
必须为 0
idr
ARM SMMU 非安全编程接口的已实现功能
iidr
关于 ARM SMMU 的实现和实现者以及支持的架构版本的信息
aidr
ARM SMMU 架构版本
描述
有关 idr、iidr 和 aidr 的详细信息,请参阅 SMMUv3 规范中的 6.3.1 到 6.3.6 章。
这报告了原始硬件功能,并非所有位都对用户空间有意义。仅应使用以下字段
idr[0]: ST_LEVEL、TERM_MODEL、STALL_MODEL、TTENDIAN、CD2L、ASID16、TTF idr[1]: SIDSIZE、SSIDSIZE idr[3]: BBML、RIL idr[5]: VAX、GRAN64K、GRAN16K、GRAN4K
如果可以创建 NESTED HWPT,则应假定 S1P 为 true
VFIO/iommufd 仅支持具有 COHACC 的平台,应假定为 true。
ATS 是每个设备的属性。如果 VMM 在 ACPI/DT 中将任何设备描述为具有 ATS 功能,则应设置相应的 idr。
此列表将来可能会扩展(例如,E0PD、AIE、PBHA、D128、DS 等)。重要的是 VMM 不要读取列表之外的位,以允许与未来的内核兼容。内核目前不支持 SMMUv3 架构中的多种功能用于嵌套:HTTU、BTM、MPAM 等。
-
enum iommu_hw_info_type¶
IOMMU 硬件信息类型
常量
IOMMU_HW_INFO_TYPE_NONE
由不报告硬件信息的驱动程序使用
IOMMU_HW_INFO_TYPE_INTEL_VTD
Intel VT-d iommu 信息类型
IOMMU_HW_INFO_TYPE_ARM_SMMUV3
ARM SMMUv3 iommu 信息类型
-
enum iommufd_hw_capabilities¶
常量
IOMMU_HW_CAP_DIRTY_TRACKING
IOMMU 硬件支持脏跟踪。 如果可用,则意味着支持以下 API
IOMMU_HWPT_GET_DIRTY_BITMAP IOMMU_HWPT_SET_DIRTY_TRACKING
-
struct iommu_hw_info¶
ioctl(IOMMU_GET_HW_INFO)
定义:
struct iommu_hw_info {
__u32 size;
__u32 flags;
__u32 dev_id;
__u32 data_len;
__aligned_u64 data_uptr;
__u32 out_data_type;
__u32 __reserved;
__aligned_u64 out_capabilities;
};
成员
size
sizeof(
struct iommu_hw_info
)flags
必须为 0
dev_id
绑定到 iommufd 的设备
data_len
以字节为单位输入用户缓冲区的长度。输出内核支持的数据长度
data_uptr
用户指向的用户空间缓冲区的指针,内核使用该缓冲区填充 iommu 类型特定的硬件信息数据
out_data_type
输出在
enum iommu_hw_info_type
中定义的 iommu 硬件信息类型。__reserved
必须为 0
out_capabilities
输出在 enum iommu_hw_capabilities 中定义的通用 iommu 功能信息类型。
描述
从绑定到 iommufd 的给定设备后面的 iommu 查询 iommu 类型特定的硬件信息数据。此硬件信息数据将用于同步虚拟 iommu 和物理 iommu 之间的功能,例如,嵌套转换设置需要检查硬件信息,以便来宾阶段 1 页表可以与物理 iommu 兼容。
要捕获 iommu 类型特定的硬件信息数据,必须提供 data_uptr 及其长度 data_len。如果用户缓冲区大于内核拥有的数据,则尾随字节将归零。否则,内核仅使用 data_len 中给定的长度填充缓冲区。如果 ioctl 成功,则 data_len 将更新为内核实际支持的长度,out_data_type 将被填充以解码 data_uptr 指向的缓冲区中填充的数据。允许输入 data_len == 零。
-
struct iommu_hwpt_set_dirty_tracking¶
ioctl(IOMMU_HWPT_SET_DIRTY_TRACKING)
定义:
struct iommu_hwpt_set_dirty_tracking {
__u32 size;
__u32 flags;
__u32 hwpt_id;
__u32 __reserved;
};
成员
size
flags
enum iommufd_hwpt_set_dirty_tracking_flags 的组合
hwpt_id
表示 IOMMU 域的 HW 页表 ID
__reserved
必须为 0
描述
在 HW 页表上切换脏跟踪。
-
enum iommufd_hwpt_get_dirty_bitmap_flags¶
用于获取脏位的标志
常量
IOMMU_HWPT_GET_DIRTY_BITMAP_NO_CLEAR
仅读取 PTE,而不清除任何脏位元数据。可以在期望下一个操作是取消映射同一 IOVA 范围的情况下传递此标志。
-
struct iommu_hwpt_get_dirty_bitmap¶
ioctl(IOMMU_HWPT_GET_DIRTY_BITMAP)
定义:
struct iommu_hwpt_get_dirty_bitmap {
__u32 size;
__u32 hwpt_id;
__u32 flags;
__u32 __reserved;
__aligned_u64 iova;
__aligned_u64 length;
__aligned_u64 page_size;
__aligned_u64 data;
};
成员
size
hwpt_id
表示 IOMMU 域的 HW 页表 ID
flags
__reserved
必须为 0
iova
位图第一位的基本 IOVA
length
IOVA 范围大小
page_size
位图中每位的页大小粒度
data
设置脏位的位图。位图中的每个位都表示一个 page_size,它偏离了任意 iova。
描述
检查给定的 IOVA 是否为脏
data[(iova / page_size) / 64] & (1ULL << ((iova / page_size) % 64))
遍历给定 IOVA 范围的 IOMMU 页表,以返回具有脏 IOVA 的位图。在此过程中,它还会默认清除 IOPTE 中设置的任何脏位元数据。
-
enum iommu_hwpt_invalidate_data_type¶
IOMMU HWPT 缓存失效数据类型
常量
IOMMU_HWPT_INVALIDATE_DATA_VTD_S1
VTD_S1 的失效数据
IOMMU_VIOMMU_INVALIDATE_DATA_ARM_SMMUV3
ARM SMMUv3 的失效数据
-
enum iommu_hwpt_vtd_s1_invalidate_flags¶
用于 Intel VT-d 阶段 1 缓存失效的标志
常量
IOMMU_VTD_INV_FLAGS_LEAF
指示失效是应用于所有级别的页面结构缓存还是仅应用于叶 PTE 缓存。
-
struct iommu_hwpt_vtd_s1_invalidate¶
Intel VT-d 缓存失效 (IOMMU_HWPT_INVALIDATE_DATA_VTD_S1)
定义:
struct iommu_hwpt_vtd_s1_invalidate {
__aligned_u64 addr;
__aligned_u64 npages;
__u32 flags;
__u32 __reserved;
};
成员
addr
要失效的范围的起始地址。它需要 4KB 对齐。
npages
要失效的连续 4K 页面的数量。
flags
__reserved
必须为 0
描述
用于嵌套转换中用户管理的阶段 1 缓存失效的 Intel VT-d 特定失效数据。 用户空间使用此结构在修改阶段 1 页表后告知受影响的缓存范围。
通过将 addr 设置为 0 并将 npages 设置为 U64_MAX,使与页表相关的所有缓存失效。
如果启用 ATS,则设备 TLB 将自动失效。
-
struct iommu_viommu_arm_smmuv3_invalidate¶
ARM SMMUv3 缓存失效 (IOMMU_VIOMMU_INVALIDATE_DATA_ARM_SMMUV3)
定义:
struct iommu_viommu_arm_smmuv3_invalidate {
__aligned_le64 cmd[2];
};
成员
cmd
在 SMMU CMDQ 中运行的 128 位缓存失效命令。必须采用小端字节序。
描述
- 仅在通过 hwpt_id 传入 vIOMMU 时才支持命令列表
CMDQ_OP_TLBI_NSNH_ALL CMDQ_OP_TLBI_NH_VA CMDQ_OP_TLBI_NH_VAA CMDQ_OP_TLBI_NH_ALL CMDQ_OP_TLBI_NH_ASID CMDQ_OP_ATC_INV CMDQ_OP_CFGI_CD CMDQ_OP_CFGI_CD_ALL
如果不支持该命令,将返回 -EIO。
-
struct iommu_hwpt_invalidate¶
ioctl(IOMMU_HWPT_INVALIDATE)
定义:
struct iommu_hwpt_invalidate {
__u32 size;
__u32 hwpt_id;
__aligned_u64 data_uptr;
__u32 data_type;
__u32 entry_len;
__u32 entry_num;
__u32 __reserved;
};
成员
size
sizeof(
struct iommu_hwpt_invalidate
)hwpt_id
嵌套 HWPT 或 vIOMMU 的 ID,用于缓存失效
data_uptr
用户指向驱动程序特定缓存失效数据数组的指针。
data_type
其中一个
enum iommu_hwpt_invalidate_data_type
,定义失效请求数组中所有条目的数据类型。它应该是 hwpt_id 指向的 hwpt 支持的类型。entry_len
请求数组中请求条目的长度(以字节为单位)
entry_num
输入数组中缓存失效请求的数量。输出内核成功处理的请求数量。
__reserved
必须为 0。
描述
使⽤户管理⻚表或 vIOMMU 的 iommu 缓存失效。如果通过 hwpt_id 传递了 HWPT,则修改⽤户管理⻚表后应执⾏此操作。如果通过 hwpt_id 字段传递了 vIOMMU,则可以刷新其他缓存,例如设备缓存或描述符缓存。
每个 ioctl 可以⽀持数组中的⼀个或多个缓存失效请求,该数组的总⼤⼩为 entry_len * entry_num。
允许通过设置 entry_num == 0 来使失效请求数组为空,在这种情况下,entry_len 和 data_uptr 将被忽略。 这可以⽤于检查内核是否⽀持给定的 data_type。
-
enum iommu_hwpt_pgfault_flags¶
常量
IOMMU_PGFAULT_FLAGS_PASID_VALID
故障数据的 pasid 字段有效。
IOMMU_PGFAULT_FLAGS_LAST_PAGE
它是故障组的最后⼀个故障。
-
enum iommu_hwpt_pgfault_perm¶
常量
IOMMU_PGFAULT_PERM_READ
请求读取权限
IOMMU_PGFAULT_PERM_WRITE
请求写⼊权限
IOMMU_PGFAULT_PERM_EXEC
(PCIE 10.4.1) 请求的 PASID 在 PASID TLP 前缀中设置了 Execute Requested 位。
IOMMU_PGFAULT_PERM_PRIV
(PCIE 10.4.1) 请求的 PASID 在 PASID TLP 前缀中设置了 Privileged Mode Requested 位。
-
struct iommu_hwpt_pgfault¶
iommu ⻚⾯故障数据
定义:
struct iommu_hwpt_pgfault {
__u32 flags;
__u32 dev_id;
__u32 pasid;
__u32 grpid;
__u32 perm;
__u64 addr;
__u32 length;
__u32 cookie;
};
成员
flags
dev_id
始发设备的 ID
pasid
进程地址空间 ID
grpid
⻚⾯请求组索引
perm
addr
故障地址
length
请求者期望获取多少数据的提示。例如,如果 PRI 发起者知道它将进⾏ 10MB 的传输,则可以填写 10MB,并且 OS 可以预先在 10MB 的 IOVA 中进⾏故障处理。如果没有此类提示,则默认值为 0。
cookie
内核管理的 cookie,⽤于标识⼀组故障消息。组的最后⼀个⻚⾯故障中编码的 cookie 号码应在响应消息中回显。
-
enum iommufd_page_response_code¶
故障处理程序的返回状态
常量
IOMMUFD_PAGE_RESP_SUCCESS
故障已处理,⻚表已填充,请重试访问。这是 PCI 10.4.2.1 中定义的“Success”。
IOMMUFD_PAGE_RESP_INVALID
⽆法处理此故障,请⽆需重试访问。这是 PCI 10.4.2.1 中的“Invalid Request”。
-
struct iommu_hwpt_page_response¶
IOMMU ⻚⾯故障响应
定义:
struct iommu_hwpt_page_response {
__u32 cookie;
__u32 code;
};
成员
cookie
故障消息中报告的内核管理的 cookie。
code
enum iommufd_page_response_code
中的响应代码之⼀。
-
struct iommu_fault_alloc¶
ioctl(IOMMU_FAULT_QUEUE_ALLOC)
定义:
struct iommu_fault_alloc {
__u32 size;
__u32 flags;
__u32 out_fault_id;
__u32 out_fault_fd;
};
成员
size
sizeof(
struct iommu_fault_alloc
)flags
必须为 0
out_fault_id
新 FAULT 的 ID
out_fault_fd
新 FAULT 的 fd
描述
显式分配故障处理对象。
-
enum iommu_viommu_type¶
虚拟 IOMMU 类型
常量
IOMMU_VIOMMU_TYPE_DEFAULT
为将来使⽤保留
IOMMU_VIOMMU_TYPE_ARM_SMMUV3
ARM SMMUv3 驱动程序特定类型
-
struct iommu_viommu_alloc¶
ioctl(IOMMU_VIOMMU_ALLOC)
定义:
struct iommu_viommu_alloc {
__u32 size;
__u32 flags;
__u32 type;
__u32 dev_id;
__u32 hwpt_id;
__u32 out_viommu_id;
};
成员
size
sizeof(
struct iommu_viommu_alloc
)flags
必须为 0
type
虚拟 IOMMU 的类型。必须在
enum iommu_viommu_type
中定义dev_id
设备的物理 IOMMU 将⽤于⽀持虚拟 IOMMU
hwpt_id
要关联的嵌套⽗ HWPT 的 ID
out_viommu_id
已分配对象的输出虚拟 IOMMU ID
描述
分配虚拟 IOMMU 对象,该对象表示底层物理 IOMMU 的虚拟化⽀持,该⽀持是真实 IOMMU HW 的安全隔离⽚,对于特定的 VM 是唯⼀的。全局 IOMMU 的操作连接到 vIOMMU,例如:- 客⼾拥有的 ID 的安全命名空间,例如,客⼾控制的缓存标记 -⾮设备附属的事件报告,例如,失效队列错误 - 访问跨物理 IOMMU 的可共享嵌套⻚表 - 各平台 ID 的虚拟化,例如,RID 和其他 - 交付半虚拟化失效 - 直接分配的失效队列 - 直接分配的中断
-
struct iommu_vdevice_alloc¶
ioctl(IOMMU_VDEVICE_ALLOC)
定义:
struct iommu_vdevice_alloc {
__u32 size;
__u32 viommu_id;
__u32 dev_id;
__u32 out_vdevice_id;
__aligned_u64 virt_id;
};
成员
size
sizeof(
struct iommu_vdevice_alloc
)viommu_id
与虚拟设备关联的 vIOMMU ID
dev_id
在 vIOMMU 上分配虚拟实例的物理设备
out_vdevice_id
vDevice 的对象句柄。传递给 IOMMU_DESTORY
virt_id
每个 vIOMMU 的虚拟设备 ID,例如,ARM SMMUv3 的 vSID、AMD IOMMU 的 vDeviceID 和嵌套的 Intel VT-d 到上下⽂表的 vRID
描述
针对 vIOMMU 分配虚拟设备实例(针对物理设备)。此实例在 VM 中保存设备的信息(与其 vIOMMU 相关)。
-
struct iommu_ioas_change_process¶
ioctl(VFIO_IOAS_CHANGE_PROCESS)
定义:
struct iommu_ioas_change_process {
__u32 size;
__u32 __reserved;
};
成员
size
sizeof(
struct iommu_ioas_change_process
)__reserved
必须为 0
描述
这会将上下⽂中每个 IOAS 中每个内存映射的固定内存计数传输到当前进程。这仅⽀持使⽤ IOMMU_IOAS_MAP_FILE 创建的映射,如果存在其他映射,则返回 EINVAL。如果 ioctl 返回失败状态,则不进⾏任何更改。
此 API ⽤于将设备的操作从⼀个进程转移到另⼀个进程,例如在⽤户态实时更新期间。
IOMMUFD 内核 API¶
IOMMUFD kAPI 是以设备为中⼼的,组相关的技巧在幕后管理。这允许调⽤此类 kAPI 的外部驱动程序实现简单的以设备为中⼼的 uAPI,以将其设备连接到 iommufd,⽽不是像 VFIO 那样在其 uAPI 中显式强加组语义。
-
struct iommufd_device *iommufd_device_bind(struct iommufd_ctx *ictx, struct device *dev, u32 *id)¶
将物理设备绑定到 iommu fd
参数
struct iommufd_ctx *ictx
iommufd ⽂件描述符
struct device *dev
指向物理设备结构的指针
u32 *id
返回给⽤户空间的此设备的输出 ID 号码
描述
成功绑定会建⽴对设备的所有权并返回 struct iommufd_device 指针,否则返回错误指针。
使⽤此 API 的驱动程序必须设置 driver_managed_dma,并且在例程成功并建⽴所有权之前不得触摸设备。
绑定 PCI 设备会将整个 RID 置于 iommufd 控制之下。
调⽤者必须使⽤ iommufd_device_unbind()
撤消此操作
-
bool iommufd_ctx_has_group(struct iommufd_ctx *ictx, struct iommu_group *group)¶
如果组中的任何设备绑定到 ictx,则为 True
参数
struct iommufd_ctx *ictx
iommufd ⽂件描述符
struct iommu_group *group
指向物理 iommu_group 结构的指针
描述
如果组中的任何设备已绑定到此 ictx,例如,通过 iommufd_device_bind()
,因此暗示 ictx 拥有该组,则为 True。
-
void iommufd_device_unbind(struct iommufd_device *idev)¶
参数
struct iommufd_device *idev
由
iommufd_device_bind()
返回的设备
描述
将设备从 iommufd 控制中释放。DMA 所有权将返回到无主状态,DMA 由 DMA API 控制。这将使 iommufd_device 指针失效,不得并发调用其他使用该指针的 API。
-
int iommufd_device_attach(struct iommufd_device *idev, u32 *pt_id)¶
将设备连接到 iommu_domain
参数
struct iommufd_device *idev
要连接的设备
u32 *pt_id
输入 IOMMUFD_OBJ_IOAS 或 IOMMUFD_OBJ_HWPT_PAGING,输出 IOMMUFD_OBJ_HWPT_PAGING ID
描述
这会将设备连接到 iommu_domain,可以是自动选择的,也可以是手动选择的。一旦完成此操作,设备就可以进行 DMA。
调用者应将生成的 pt_id 返回给用户空间。此函数可通过调用 iommufd_device_detach()
来撤销。
-
int iommufd_device_replace(struct iommufd_device *idev, u32 *pt_id)¶
更改设备的 iommu_domain
参数
struct iommufd_device *idev
要更改的设备
u32 *pt_id
输入 IOMMUFD_OBJ_IOAS 或 IOMMUFD_OBJ_HWPT_PAGING,输出 IOMMUFD_OBJ_HWPT_PAGING ID
描述
这与以下操作相同
iommufd_device_detach();
iommufd_device_attach();
如果失败,则不会对连接进行任何更改。iommu 驱动程序可能会实现这一点,以确保翻译不会中断。只有在 iommufd_device_attach()
成功后才能调用此函数。
-
void iommufd_device_detach(struct iommufd_device *idev)¶
断开设备与 iommu_domain 的连接
参数
struct iommufd_device *idev
要断开的设备
描述
撤销 iommufd_device_attach()
。这将断开 idev 与先前连接的 pt_id 的连接。设备返回到阻止 DMA 转换的状态。
-
struct iommufd_access *iommufd_access_create(struct iommufd_ctx *ictx, const struct iommufd_access_ops *ops, void *data, u32 *id)¶
创建 iommufd_access
参数
struct iommufd_ctx *ictx
iommufd ⽂件描述符
const struct iommufd_access_ops *ops
驱动程序要与访问关联的操作
void *data
要传递到 ops 函数的不透明数据
u32 *id
输出要返回给用户空间以用于此访问的 ID 号
描述
iommufd_access 允许驱动程序在不使用 DMA 的情况下读取/写入 IOAS。可以使用 iommufd_access_pin_pages()
或 iommufd_access_rw()
函数访问底层 CPU 内存。
必须使用提供的操作 iommufd_access_pin_pages()
。
-
void iommufd_access_destroy(struct iommufd_access *access)¶
销毁 iommufd_access
参数
struct iommufd_access *access
要销毁的访问
描述
调用者必须在销毁访问之前停止使用该访问。
-
void iommufd_access_unpin_pages(struct iommufd_access *access, unsigned long iova, unsigned long length)¶
撤销 iommufd_access_pin_pages
参数
struct iommufd_access *access
要操作的 IOAS 访问
unsigned long iova
起始 IOVA
unsigned long length
要访问的字节数
描述
返回 struct page 的信息。调用者必须在调用此函数之前停止访问它们。iova/length 必须与提供给 access_pages 的完全匹配。
-
int iommufd_access_pin_pages(struct iommufd_access *access, unsigned long iova, unsigned long length, struct page **out_pages, unsigned int flags)¶
返回 iova 下的页面列表
参数
struct iommufd_access *access
要操作的 IOAS 访问
unsigned long iova
起始 IOVA
unsigned long length
要访问的字节数
struct page **out_pages
输出页面列表
unsigned int flags
IOPMMUFD_ACCESS_RW_* 标志
描述
读取从 iova 开始的 **length** 个字节,并返回 struct page * 指针。调用者可以使用 kmap 对其进行 CPU 访问。
调用者完成后必须执行 iommufd_access_unpin_pages()
以平衡此操作。
此 API 始终需要页面对齐的 iova。如果 ioas 对齐 >= PAGE_SIZE 并且 iova 是 PAGE_SIZE 对齐的,则会自然发生这种情况。但是,较小的对齐方式存在一些极端情况,其中此 API 可能会在其他对齐的 iova 上失败。
-
int iommufd_access_rw(struct iommufd_access *access, unsigned long iova, void *data, size_t length, unsigned int flags)¶
读取或写入 iova 下的数据
参数
struct iommufd_access *access
要操作的 IOAS 访问
unsigned long iova
起始 IOVA
void *data
要复制到/从复制的内核缓冲区
size_t length
要访问的字节数
unsigned int flags
IOMMUFD_ACCESS_RW_* 标志
描述
将内核数据复制到/从 IOVA/length 给定的范围。如果标志指示 IOMMUFD_ACCESS_RW_KTHREAD,则可以通过将其更改为 copy_to/from_user() 来优化大型复制。
-
void iommufd_ctx_get(struct iommufd_ctx *ictx)¶
获取上下文引用
参数
struct iommufd_ctx *ictx
要获取的上下文
描述
调用者必须已经持有对 ictx 的有效引用。
参数
struct file *file
从中获取引用的文件
描述
返回指向 iommufd_ctx 的指针,否则返回 ERR_PTR。 struct file
仍然归调用者所有,调用者仍然必须执行 fput。成功后,调用者负责调用 iommufd_ctx_put()
。
-
struct iommufd_ctx *iommufd_ctx_from_fd(int fd)¶
获取对 iommufd 上下文的引用
-
void iommufd_ctx_put(struct iommufd_ctx *ictx)¶
放回一个引用
参数
struct iommufd_ctx *ictx
要放回的上下文
VFIO 和 IOMMUFD¶
将 VFIO 设备连接到 iommufd 可以通过两种方式完成。
第一种是 VFIO 兼容的方式,通过将 /dev/vfio/vfio 容器 IOCTL 直接映射到 io_pagetable 操作来实现。这样做允许在传统的 VFIO 应用程序中使用 iommufd,方法是将 /dev/vfio/vfio 符号链接到 /dev/iommufd,或者扩展 VFIO 以使用 iommufd 而不是容器 fd 来 SET_CONTAINER。
第二种方法直接扩展 VFIO,以支持基于上述 IOMMUFD 内核 API 的一组新的以设备为中心的用户 API。它需要用户空间更改,但更好地匹配 IOMMUFD API 语义,并且在与第一种方法相比,更容易支持新的 iommufd 功能。
目前,这两种方法都仍在进行中。
正如 iommufd_vfio_check_extension() 中记录的那样,仍然有一些差距需要解决才能赶上 VFIO type1。
未来的 TODO¶
目前,IOMMUFD 仅支持内核管理的 I/O 页表,类似于 VFIO type1。雷达上的新功能包括
将 iommu_domain 绑定到 PASID/SSID
用于 ARM、x86 和 S390 的用户空间页表
内核绕过的用户页表失效
在 IOMMU 中重用 KVM 页表
在 IOMMU 中跟踪脏页
运行时增加/减少 IOPTE 大小
使用用户空间中解决的故障的 PRI 支持