VFIO中介设备
版权
© 2016,NVIDIA CORPORATION。保留所有权利。
作者
Neo Jia cjia@nvidia.com
Kirti Wankhede kwankhede@nvidia.com
虚拟功能I/O(VFIO)中介设备[1]
虚拟化没有内置SR_IOV功能的DMA设备的用例数量正在增加。以前,要虚拟化这些设备,开发人员必须创建自己的管理接口和API,然后将它们与用户空间软件集成。为了简化与用户空间软件的集成,我们已经确定了这些设备的常见要求和统一的管理接口。
VFIO驱动程序框架提供了直接设备访问的统一API。它是一个面向设备的IOMMU/设备不可知的框架,用于在安全的IOMMU保护环境中向用户空间公开直接设备访问。该框架用于多个设备,如GPU、网络适配器和计算加速器。通过直接设备访问,虚拟机或用户空间应用程序可以直接访问物理设备。该框架被中介设备重复使用。
中介核心驱动程序提供了一个通用接口,用于不同设备的中介设备管理。该模块提供了执行以下操作的通用接口:
- 创建和销毁中介设备
- 将中介设备添加到中介总线驱动程序并从中移除
- 将中介设备添加到IOMMU组并从中移除
中介核心驱动程序还提供了一个注册总线驱动程序的接口。例如,中介VFIO mdev驱动程序专为中介设备设计,并支持VFIO API。中介总线驱动程序将中介设备添加到VFIO组并从中移除。
以下高级块图显示了VFIO中介驱动程序框架中的主要组件和接口。该图显示了NVIDIA、Intel和IBM设备作为示例,因为这些设备是首批使用该模块的设备:
[图略]
注册接口
中介核心驱动程序提供以下类型的注册接口:
- 中介总线驱动程序的注册接口
- 物理设备驱动程序接口
中介总线驱动程序的注册接口
中介设备驱动程序的注册接口提供以下结构来表示中介设备的驱动程序:
struct mdev_driver { int (*probe) (struct mdev_device *dev); void (*remove) (struct mdev_device *dev); unsigned int (*get_available)(struct mdev_type *mtype); ssize_t (*show_description)(struct mdev_type *mtype, char *buf); struct device_driver driver; };
中介总线驱动程序应在函数调用中使用此结构来向核心驱动程序注册和注销自身:
- 注册:
int mdev_register_driver(struct mdev_driver *drv);
- 注销:
void mdev_unregister_driver(struct mdev_driver *drv);
中介总线驱动程序的探测函数应在mdev_device上创建一个vfio_device,并将其连接到vfio_device_ops的适当实现。
当驱动程序想要将GUID创建sysfs添加到已经探测到的现有设备时,应调用:
int mdev_register_parent(struct mdev_parent *parent, struct device *dev, struct mdev_driver *mdev_driver);
这将提供'mdev_supported_types/XX/create'文件,然后可以用它们来触发mdev_device的创建。创建的mdev_device将附加到指定的驱动程序。
当驱动程序需要自行移除时,调用:
void mdev_unregister_parent(struct mdev_parent *parent);
这将解绑并销毁所有已创建的mdev,并移除sysfs文件。
通过sysfs的中介设备管理接口
通过sysfs的管理接口使用户空间软件(如libvirt)能够以硬件无关的方式查询和配置中介设备。该管理接口为底层物理设备的驱动程序提供了灵活性,以支持以下功能:
- 中介设备热插拔
- 单个虚拟机中的多个中介设备
- 来自不同物理设备的多个中介设备
mdev_bus类目录中的链接
/sys/class/mdev_bus/目录包含已向mdev核心驱动程序注册的设备的链接。
每个物理设备的sysfs下的目录和文件
[略]
每个mdev设备的sysfs下的目录和文件
[略]
中介设备热插拔
中介设备可以在运行时创建和分配。热插拔中介设备的过程与热插拔PCI设备的过程相同。
中介设备的翻译API
为中介设备提供了以下API,用于在VFIO驱动程序中将用户PFN翻译为主机PFN:
int vfio_pin_pages(struct vfio_device *device, dma_addr_t iova, int npage, int prot, struct page **pages); void vfio_unpin_pages(struct vfio_device *device, dma_addr_t iova, int npage); C 复制 全屏
这些函数通过使用struct vfio_iommu_driver_ops[4]的pin_pages和unpin_pages回调调用后端IOMMU模块。目前,这些回调仅在TYPE1 IOMMU模块中受支持。要在其他IOMMU后端模块(例如PPC64 sPAPR模块)中启用它们,它们需要提供这两个回调函数。
参考资料
- 有关VFIO的更多信息,请参阅"虚拟功能I/O"。
- include/linux/mdev.h中的struct mdev_driver
- include/linux/mdev.h中的struct mdev_parent_ops
- include/linux/vfio.h中的struct vfio_iommu_driver_ops