pcivirt.h 标头

有关使用用于向虚拟机公开 VF 的接口的参考指南。

符合 PCI Express Single-Root I/O 虚拟化 (SR-IOV) 规范的设备可以为设备提供多个接口。 这些接口称为虚拟功能 (VF),是独立的,通过初始设备接口(称为物理功能 (PF))提供。 例如,支持 SR-IOV 的以太网 NIC 可以设计为具有一个具有一个物理以太网端口(连接到物理线路)和多个虚拟以太网端口的交换机。

PF 的配置空间允许 PF 驱动程序管理 VF 的 PCI 资源,包括内存映射 I/O 空间和消息信号中断。 由于 VF 是完整器件的子集,因此它们在硬件中公开的成本可能比多功能封装中的传统功能更低。 这允许设备制造商构建更多接口,并集中管理任何共享资源。

当 Windows 直接在机器硬件上运行时,设备驱动程序参与与即插即用、电源管理、中断管理和其他任务相关的作。 受信任的 Windows 总线驱动程序和硬件抽象层 (HAL) 拥有总线配置并配置整个总线。 驱动程序在相同的权限级别内运行,并且在内核模式下没有信任边界。

当 Windows 在虚拟机 (VM) 上运行时,这些假设不适用。 VF 可以置于非特权 VM 的控制之下。 但是,必须对硬件进行安全检查,以便系统的安全性或性能不受影响。

当 VF 上运行的驱动程序请求读取或写入配置空间时,虚拟化堆栈将接收该请求并发送到 SR-IOV 设备的 PF 驱动程序。 PF 驱动程序负责响应这些请求并为 VF 提供详细信息。 PF 驱动程序有时可能需要将配置读取或写入请求向下传递到硬件。

堆栈使用 I/O MMU 来区分来自设备公开的各种接口的流量,并强制实施设备可以访问的内存区域以及可以生成的中断的策略。

显示 PCI 虚拟化的图表。

硬件要求

SR-IOV 设备分配的系统必须满足 SR-IOV 组网和 直接设备分配 的要求。 系统必须有一个 IOMMU,该 IOMMU 必须配置为将设备控制权交给作系统,并且必须启用和配置 PCIe ACS(访问控制服务)以供作系统使用。 最后,有问题的设备不得使用基于线路的中断,并且不得需要 ATS(地址转换服务)。

更多信息请见:

要确定系统是否支持设备分配,以及特定 PCI 设备是否可用于设备分配,请执行以下作:

查询 SR-IOV 设备

GUID_DEVINTERFACE_VIRTUALIZABLE_DEVICE 是由 SR-IOV 设备的驱动程序提供的设备类接口。 此 GUID 提供了一种查询所有设备堆栈的方法,这些堆栈公开用于管理设备的虚拟化相关功能的各种函数表。 驱动程序注册 GUID 后,通过发送 IRP_MN_QUERY_INTERFACE 来发现各个功能。 驾驶员必须使用 GUID_SRIOV_DEVICE_INTERFACE_STANDARD 响应该请求。 司机还必须处理 IOCTL_SRIOV_NOTIFICATION 和 IOCTL_SRIOV_EVENT_COMPLETE。

在特权 VM 中运行的 SR_IOV 设备的驱动程序是主机 OS。 它拥有整台机器的即插即用和电源管理,并在非特权 VM 中公开 PCI Express SR-IOV 虚拟功能,必须提供 GUID_SRIOV_DEVICE_INTERFACE_STANDARD(在标头 Pcivirt.h 中定义)。 该驱动程序可能是创建 FDO 的 PCI Express SR-IOV 物理功能 (PF) 驱动程序,或者当 FDO 由端口驱动程序管理时,它可能是该设备节点上的较低筛选器。

设备接口是必需的,以便驱动程序可以访问 VF 的配置空间。

在 PF 驱动程序的 EVT_WDF_DRIVER_DEVICE_ADD 实现中,执行以下任务:

  • 调用 WdfDeviceCreate 创建函数设备对象 (FDO) 后,调用 WdfDeviceCreateDeviceInterface 以注册GUID_DEVINTERFACE_VIRTUALIZABLE_DEVICE。 这允许虚拟化堆栈检索 SR-IOV 设备的设备句柄。
  • 公开GUID_SRIOV_DEVICE_INTERFACE_STANDARD。
    • 初始化 SRIOV_DEVICE_INTERFACE_STANDARD 结构,并将成员设置为 PF 驱动程序实现的回调函数的函数指针。
    • 通过调用 WDF_QUERY_INTERFACE_CONFIG_INIT 配置结构。
    • 通过调用 WdfDeviceAddQueryInterface 向 FDO 注册接口。
// Make the device visible as an assignable device.
//
status = WdfDeviceCreateDeviceInterface(
    fdo,
    &GUID_DEVINTERFACE_VIRTUALIZABLE_DEVICE,
    NULL);
if (!NT_SUCCESS(status))
{
    TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT,
                "Failed to create interface: %!STATUS!",
                status);
    goto Cleanup;
}

//
// Expose SRIOV_DEVICE_INTERFACE_STANDARD
//
RtlZeroMemory(&sriovInterface, sizeof(sriovInterface));
sriovInterface.Size = sizeof(sriovInterface);
sriovInterface.Version = 1;
sriovInterface.Context = deviceContext;
sriovInterface.InterfaceReference = Virtualization_ReferenceInterface;
sriovInterface.InterfaceDereference = Virtualization_DereferenceInterface;
sriovInterface.ReadVfConfig = Virtualization_ReadConfig;
sriovInterface.WriteVfConfig = Virtualization_WriteConfig;
sriovInterface.ReadVfConfigBlock = Virtualization_ReadBlock;
sriovInterface.WriteVfConfigBlock = Virtualization_WriteBlock;
sriovInterface.ResetVf = Virtualization_ResetFunction;
sriovInterface.SetVfPowerState = Virtualization_SetPowerState;
sriovInterface.GetDeviceLocation = Virtualization_GetDeviceLocation;
sriovInterface.GetVendorAndDevice = Virtualization_GetVendorAndDevice;
sriovInterface.QueryProbedBars = Virtualization_QueryProbedBars;
sriovInterface.QueryLuid = Virtualization_QueryLuid;


WDF_QUERY_INTERFACE_CONFIG_INIT(&qiConfig,
                                (PINTERFACE)&sriovInterface,
                                &GUID_SRIOV_DEVICE_INTERFACE_STANDARD,
                                NULL);

status = WdfDeviceAddQueryInterface(fdo, &qiConfig);

if (!NT_SUCCESS(status))
{
    TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT,
                "WdfDeviceAddQueryInterface failed: %!STATUS!\n",
                status);
    goto Cleanup;
}

处理 Plug and Play 事件

虚拟化堆栈负责向 VM 发送适当的消息,等待回复(超时)和未响应的 VM,并应用适当的作,例如否决 PnP 事件,或从非特权 VM 中意外删除设备。 实现 GUID_DEVINTERFACE_VIRTUALIZABLE_DEVICE 的 PF 驱动程序还必须处理这些 I/O 控制请求,这些请求允许虚拟化堆栈对 PnP 事件做出反应。

  • 虚拟化堆栈首先将 IOCTL_SRIOV_ATTACH 发送到设备。 这会通知设备需要通知虚拟化堆栈某些 PnP 事件。

  • 在虚拟化堆栈发送 IOCTL_SRIOV_DETACH 之前,这一直有效。

  • 虚拟化堆栈通过发送 IOCTL_SRIOV_NOTIFICATION 请求来查询设备有关 PnP 事件的信息。 PF 驱动程序可以通过完成 IOCTL_SRIOV_NOTIFICATION 请求来通知虚拟化堆栈 PnP 事件。

  • 虚拟化堆栈通过发送 IOCTL_SRIOV_EVENT_COMPLETE 来取消阻止这些事件。

pcivirt.h 包含以下编程接口:

IOCTLs

 
IOCTL_SRIOV_ATTACH

请求指示虚拟化堆栈希望注册 SR-IOV 设备收到的即插即用事件。
IOCTL_SRIOV_DETACH

请求指示虚拟化堆栈希望注销即插即用事件(以前通过IOCTL_SRIOV_ATTACH请求注册)。
IOCTL_SRIOV_EVENT_COMPLETE

请求指示虚拟化堆栈或 SR-IOV 设备收到了SRIOV_PF_EVENT中列出的事件之一。
IOCTL_SRIOV_INVALIDATE_BLOCK

IOCTL_SRIOV_INVALIDATE_BLOCK请求指示虚拟化堆栈想要重置指定配置块的内容。
IOCTL_SRIOV_MITIGATED_RANGE_UPDATE

IOCTL_SRIOV_MITIGATED_RANGE_UPDATE请求指示虚拟化堆栈希望更新到缓解范围。
IOCTL_SRIOV_NOTIFICATION

请求指示虚拟化堆栈希望在发生SRIOV_PF_EVENT中列出的某个事件时收到通知。
IOCTL_SRIOV_PROXY_QUERY_LUID

此请求提供实现接口的SR_IOV设备的本地唯一标识符。
IOCTL_SRIOV_QUERY_MITIGATED_RANGE_COUNT

请求确定必须缓解的内存映射 I/O 空间的范围。
IOCTL_SRIOV_QUERY_MITIGATED_RANGES

请求确定必须放置截距的特定范围。

回调函数

 
READ_WRITE_MITIGATED_REGISTER

读取或写入以缓解地址空间。
SRIOV_GET_DEVICE_LOCATION

检索有关总线上 PCI 设备的当前位置的信息,例如 PCI 段、总线、设备和函数号。
SRIOV_GET_MMIO_REQUIREMENTS

不支持此回调函数。
SRIOV_GET_RESOURCE_FOR_BAR

获取特定基址寄存器(BAR)的已转换资源。
SRIOV_GET_VENDOR_AND_DEVICE_IDS

提供 PCI Express SR-IOV 虚拟函数(VF)的供应商和设备 ID,用于为 VF 生成更通用的即插即用 ID。 无法直接从 VF 的配置空间读取这些 ID。
SRIOV_QUERY_LUID

获取 SR-IOV 设备的本地唯一标识符。
SRIOV_QUERY_LUID_VF

获取给定唯一标识符的 PCI Express SR-IOV 虚拟函数(VF)。
SRIOV_QUERY_PROBED_BARS

查询从物理函数 (PF) 基址寄存器(BAR)读取的数据(如果值 -1 先写入到它们)。
SRIOV_QUERY_PROBED_BARS_2

查询从指定的 PCI Express SR-IOV 虚拟函数(VF)基址寄存器(BAR)读取的数据(如果值 -1 先写入到它们)。
SRIOV_QUERY_VF_LUID

获取 PCI Express SR-IOV 虚拟函数(VF)的本地唯一标识符。
SRIOV_READ_BLOCK

从 PCI Express SR-IOV 虚拟函数(VF)的指定配置块读取数据。
SRIOV_READ_CONFIG

从指定的 PCI Express SR-IOV 虚拟函数(VF)的配置空间读取数据。
SRIOV_RESET_FUNCTION

重置指定的 PCI Express SR-IOV 虚拟函数(VF)。
SRIOV_SET_POWER_STATE

设置指定的 PCI Express SR-IOV 虚拟函数(VF)的电源状态。
SRIOV_WRITE_BLOCK

将数据写入 PCI Express SR-IOV 虚拟函数(VF)的指定配置块。
SRIOV_WRITE_CONFIG

将配置数据写入 PCI Express SR-IOV 虚拟函数(VF)。

结构

 
MITIGABLE_DEVICE_INTERFACE

存储函数指针,该指针指向可误导设备接口的物理函数(PF)驱动程序实现的回调函数。
SRIOV_DEVICE_INTERFACE_STANDARD

将函数指针存储在 SR-IOV 设备的设备堆栈中由物理函数(PF)驱动程序实现的回调函数。
SRIOV_DEVICE_INTERFACE_STANDARD_2

将函数指针存储在 SR-IOV 设备的设备堆栈中由物理函数(PF)驱动程序实现的回调函数。 这是SRIOV_DEVICE_INTERFACE_STANDARD的扩展版本。
SRIOV_INVALIDATE_BLOCK

包含配置块信息。 此结构用于IOCTL_SRIOV_INVALIDATE_BLOCK请求。
SRIOV_MITIGATED_RANGE_COUNT_INPUT

此结构用作IOCTL_SRIOV_QUERY_MITIGATED_RANGE_COUNT请求的输入缓冲区,以确定必须缓解的内存映射 I/O 空间的范围。
SRIOV_MITIGATED_RANGE_COUNT_OUTPUT

此结构是IOCTL_SRIOV_QUERY_MITIGATED_RANGE_COUNT请求收到的输出缓冲区,该请求包含必须缓解的内存映射 I/O 空间范围的数组。
SRIOV_MITIGATED_RANGE_UPDATE_INPUT

此结构用作IOCTL_SRIOV_MITIGATED_RANGE_UPDATE请求的输入缓冲区,以指示必须缓解其内存映射 I/O 空间的虚拟函数(VF)。
SRIOV_MITIGATED_RANGE_UPDATE_OUTPUT

此结构是IOCTL_SRIOV_MITIGATED_RANGE_UPDATE请求收到的输出缓冲区,该请求指示其内存映射 I/O 空间已缓解的虚拟函数(VF)。
SRIOV_MITIGATED_RANGES_INPUT

此结构是IOCTL_SRIOV_QUERY_MITIGATED_RANGES请求中的输入缓冲区,用于获取必须放置截距的特定范围。
SRIOV_MITIGATED_RANGES_OUTPUT

此结构是IOCTL_SRIOV_QUERY_MITIGATED_RANGES请求接收的输出缓冲区,用于获取必须放置截距的特定范围。
SRIOV_PNP_EVENT_COMPLETE

存储 SR-IOV 物理函数(PF)驱动程序应为即插即用(甚至完成)设置的事件的状态。 此结构用于IOCTL_SRIOV_EVENT_COMPLETE请求的输入缓冲区中。
SRIOV_PROXY_QUERY_LUID_OUTPUT

存储实现接口的SR_IOV设备的本地唯一标识符。 此结构是IOCTL_SRIOV_PROXY_QUERY_LUID请求的输出缓冲区。

枚举

 
SRIOV_PF_EVENT

定义 SR-IOV 设备的事件值。