pcivirt.h 标头

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

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

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

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

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

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

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

PCI 虚拟化。

硬件要求

用于 SR-IOV 设备分配的系统必须满足 SR-IOV 网络和直接设备分配的要求。 系统必须具有 IOMMU,该 IOMMU 必须配置为将设备的控制权授予操作系统,并且 PCIe ACS (访问控制 Services) 必须启用并配置为供操作系统使用。 最后,相关设备不得使用基于线路的中断,也不得要求 ATS (地址翻译服务) 。

以下主题提供了详细信息:

想要了解的有关 Hyper-V 中 SR-IOV 的所有信息。 第 1 部分

离散设备分配 - 说明和背景

若要确定系统是否支持设备分配,以及特定 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 虚拟函数,必须提供标头 Pcivirt.h) 中定义的GUID_SRIOV_DEVICE_INTERFACE_STANDARD (。 该驱动程序可能是 PCI Express SR-IOV 物理功能 (PF) 驱动程序,用于创建 FDO;如果 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;
    }

处理即插即用事件

虚拟化堆栈负责将适当的消息发送到 VM,在 vm) 超时的情况下等待回复 (,并应用适当的操作,例如否决 PnP 事件或意外从非特权 VM 中删除设备。 实现GUID_DEVINTERFACE_VIRTUALIZABLE_DEVICE的 PF 驱动程序还必须处理这些 I/O 控制请求,这些 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 包含以下编程接口:

IOCTL

 
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 虚拟函数提供供应商和设备 ID, (VF) 用于为 VF 生成更通用的即插即用 ID。 无法直接从 VF 的配置空间读取这些 ID。
SRIOV_QUERY_LUID

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

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

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

查询从指定的 PCI Express SR-IOV 虚拟函数读取的数据 (VF) 基址寄存器 (BA) 如果先写入值 -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

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

将函数指针存储到物理函数 (PF) 驱动程序实现的回调函数,这些函数指针存储在 SR-IOV 设备的 设备堆栈中。 这是 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请求的输入缓冲区,以指示虚拟函数 (VF) 其内存映射 I/O 空间必须得到缓解。
SRIOV_MITIGATED_RANGE_UPDATE_OUTPUT

此结构是IOCTL_SRIOV_MITIGATED_RANGE_UPDATE请求接收的输出缓冲区,指示 (VF) 其内存映射 I/O 空间已减少的虚拟函数。
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 设备的事件值。