cabeçalho pcivirt.h

Guia de referência para usar interfaces usadas para expor VFs a uma Máquina Virtual.

Os dispositivos que estão em conformidade com a especificação sr-IOV (virtualização de E/S) do PCI Express Single-Root podem fornecer várias interfaces para o dispositivo. Essas interfaces, conhecidas como VFs (Funções Virtuais), são independentes e são fornecidas por meio da interface inicial do dispositivo, conhecida como PF (Função Física). Por exemplo, uma NIC Ethernet compatível com SR-IOV pode ser projetada para ter uma opção com uma porta Ethernet física (conectada ao fio físico) e muitas portas Ethernet virtuais.

O espaço de configuração do PF permite que o driver PF gerencie os recursos de PCI do VF, incluindo espaço de E/S mapeado pela memória e interrupções sinalizadas por mensagem. Como as VFs são um subconjunto de um dispositivo completo, elas podem ser menos caras para expor em hardware do que uma função tradicional em um pacote de várias funções. Isso permite que o fabricante do dispositivo crie mais interfaces e gerencie todos os recursos compartilhados centralmente.

Quando o Windows está sendo executado diretamente no hardware do computador, os drivers de dispositivo participam de operações relacionadas ao Plug and Play, gerenciamento de energia, gerenciamento de interrupções e outras tarefas. Um driver de barramento confiável do Windows e uma configuração de barramento própria de HAL (Camada de Abstração de Hardware) e configuram todo o barramento. O driver é executado no mesmo nível de privilégio e não há limites de confiança no modo kernel.

Quando o Windows está em execução em uma VM (máquina virtual), essas suposições não se aplicam. As VFs podem ser colocadas sob o controle de uma VM não privilegiada. No entanto, o hardware deve ser verificado de segurança para que a segurança ou o desempenho do sistema não seja afetado.

Quando um driver em execução no VF solicita um espaço de configuração lido ou gravado, a solicitação é recebida pela pilha de virtualização e enviada para o driver PF do dispositivo SR-IOV. É responsabilidade do driver PF responder a essas solicitações e fornecer detalhes para o VF. Ocasionalmente, o driver PF pode exigir que uma solicitação de leitura ou gravação de configuração seja passada para o hardware.

A pilha usa uma MMU de E/S para diferenciar o tráfego proveniente das várias interfaces que o dispositivo expõe, impondo a política sobre quais regiões de memória um dispositivo pode acessar e quais interrupções ele pode gerar.

Virtualização de PCI.

Requisitos de hardware

O sistema a ser usado para atribuição de dispositivo SR-IOV deve atender aos requisitos de rede SR-IOV e Atribuição direta de dispositivo. O sistema deve ter uma IOMMU, que o IOMMU deve ser configurado para fornecer o controle de dispositivos para o sistema operacional, e o PCIe ACS (serviços de Controle de Acesso) deve ser habilitado e configurado para uso pelo sistema operacional. Por fim, o dispositivo em questão não deve usar interrupções baseadas em linha e não deve exigir ATS (Serviços de Tradução de Endereços).

Mais informações aqui:

Tudo o que você queria saber sobre SR-IOV no Hyper-V. Parte 1

Atribuição de dispositivo discreta – Descrição e plano de fundo

Para determinar se um sistema dá suporte à atribuição de dispositivo e se um dispositivo PCI específico funcionará para atribuição de dispositivo:

Script de atribuição de dispositivo discreto

Consultando dispositivos SR-IOV

GUID_DEVINTERFACE_VIRTUALIZABLE_DEVICE é uma interface de classe de dispositivo fornecida por drivers para dispositivos SR-IOV. Esse GUID fornece uma maneira de consultar todas as pilhas de dispositivos que expõem as várias tabelas de funções usadas para gerenciar os recursos relacionados à virtualização do dispositivo. Depois que o driver registra o GUID, as funcionalidades individuais são descobertas enviando IRP_MN_QUERY_INTERFACE. O driver deve responder a essa solicitação com GUID_SRIOV_DEVICE_INTERFACE_STANDARD. Os drivers também devem lidar com IOCTL_SRIOV_NOTIFICATION e IOCTL_SRIOV_EVENT_COMPLETE.

Um driver para um dispositivo SR_IOV, que é executado em uma VM com privilégios, é o sistema operacional host. Ele é proprietário do plug-and-play e do gerenciamento de energia de um computador inteiro e expõe as funções virtuais sr-IOV do PCI Express em VMs não privilegiadas, deve fornecer o GUID_SRIOV_DEVICE_INTERFACE_STANDARD (definido no cabeçalho Pcivirt.h). Esse driver pode ser um driver PF (função física) PCI Express SR-IOV que cria o FDO ou pode ser um filtro inferior nesse nó de dispositivo no caso de o FDO estar sendo gerenciado por um driver de porta.

A interface do dispositivo é necessária para que o driver possa acessar o espaço de configuração das VFs.

Na implementação EVT_WDF_DRIVER_DEVICE_ADD do driver PF, execute estas tarefas:

  • Depois de chamar WdfDeviceCreate para criar o FDO (objeto do dispositivo de função), chame WdfDeviceCreateDeviceInterface para registrar GUID_DEVINTERFACE_VIRTUALIZABLE_DEVICE. Isso permite que a pilha de virtualização recupere um identificador de dispositivo para o dispositivo SR-IOV.
  • Exponha o GUID_SRIOV_DEVICE_INTERFACE_STANDARD.
    • Inicialize uma estrutura SRIOV_DEVICE_INTERFACE_STANDARD e defina membros como ponteiros de função das funções de retorno de chamada implementadas pelo driver PF.
    • Configure a estrutura chamando WDF_QUERY_INTERFACE_CONFIG_INIT.
    • Registre a interface com o FDO chamando WdfDeviceAddQueryInterface.
    // 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;
    }

Manipulando eventos plug and play

A pilha de virtualização é responsável por enviar as mensagens apropriadas para a VM, aguardar a resposta (com um tempo limite) e em caso de VM não respondendo e aplicar a ação apropriada, como vetar o evento PnP ou remover o dispositivo da VM sem privilégios. Os drivers PF que implementam GUID_DEVINTERFACE_VIRTUALIZABLE_DEVICE também devem lidar com essas solicitações de controle de E/S que permitem que a pilha de virtualização reaja a eventos PnP.

  • A pilha de virtualização primeiro envia IOCTL_SRIOV_ATTACH para o dispositivo. Isso notifica o dispositivo de que a pilha de virtualização precisa ser notificada sobre determinados eventos PnP.

  • Isso está em vigor até que a pilha de virtualização envie IOCTL_SRIOV_DETACH.

  • A pilha de virtualização consulta os dispositivos sobre eventos PnP enviando IOCTL_SRIOV_NOTIFICATION solicitações. O driver PF pode informar a pilha de virtualização de um evento PnP concluindo a solicitação de IOCTL_SRIOV_NOTIFICATION.

  • A pilha de virtualização desbloqueia esses eventos enviando IOCTL_SRIOV_EVENT_COMPLETE.

pcivirt.h contém as seguintes interfaces de programação:

IOCTLs

 
IOCTL_SRIOV_ATTACH

A solicitação indica que a pilha de virtualização deseja se registrar para eventos Plug and Play recebidos pelo dispositivo SR-IOV.
IOCTL_SRIOV_DETACH

A solicitação indica que a pilha de virtualização deseja cancelar o registro de eventos Plug and Play (registrados anteriormente por meio da solicitação IOCTL_SRIOV_ATTACH).
IOCTL_SRIOV_EVENT_COMPLETE

A solicitação indica que a pilha de virtualização ou o dispositivo SR-IOV recebeu um dos eventos listados em SRIOV_PF_EVENT.
IOCTL_SRIOV_INVALIDATE_BLOCK

A solicitação IOCTL_SRIOV_INVALIDATE_BLOCK indica que a pilha de virtualização deseja redefinir o conteúdo do bloco de configuração especificado.
IOCTL_SRIOV_MITIGATED_RANGE_UPDATE

A solicitação IOCTL_SRIOV_MITIGATED_RANGE_UPDATE indica que a pilha de virtualização deseja atualizar para os intervalos de mitigação.
IOCTL_SRIOV_NOTIFICATION

A solicitação indica que a pilha de virtualização deseja ser notificada quando ocorre um dos eventos listados em SRIOV_PF_EVENT.
IOCTL_SRIOV_PROXY_QUERY_LUID

Essa solicitação fornece o identificador exclusivo local do dispositivo SR_IOV implementando a interface.
IOCTL_SRIOV_QUERY_MITIGATED_RANGE_COUNT

A solicitação determina os intervalos de espaço de E/S mapeado pela memória que devem ser mitigados.
IOCTL_SRIOV_QUERY_MITIGATED_RANGES

A solicitação determina os intervalos específicos nos quais as interceptações devem ser colocadas.

Funções de retorno de chamada

 
READ_WRITE_MITIGATED_REGISTER

Lê ou grava em espaços de endereço mitigados.
SRIOV_GET_DEVICE_LOCATION

Recupera informações sobre o local atual do dispositivo PCI no barramento, como Segmento PCI, Barramento, Dispositivo e Número da Função.
SRIOV_GET_MMIO_REQUIREMENTS

Não há suporte para essa função de retorno de chamada.
SRIOV_GET_RESOURCE_FOR_BAR

Obtém o recurso traduzido para um BAR (Registro de Endereço Base) específico.
SRIOV_GET_VENDOR_AND_DEVICE_IDS

Fornece a ID do fornecedor e do dispositivo para uma VF (Função Virtual sr-IOV) PCI Express a ser usada para gerar uma ID de Plug and Play mais genérica para o VF. Essas IDs não podem ser lidas diretamente do espaço de configuração do VF.
SRIOV_QUERY_LUID

Obtém o identificador exclusivo local do dispositivo SR-IOV.
SRIOV_QUERY_LUID_VF

Obtém a VF (Função Virtual SR-IOV) do PCI Express, dado um identificador exclusivo.
SRIOV_QUERY_PROBED_BARS

Consulta os dados lidos dos BARs (registros de endereço base) da função física (PF) se o valor -1 tiver sido gravado neles primeiro.
SRIOV_QUERY_PROBED_BARS_2

Consulta os dados lidos dos BARs (registros de endereços base) PCI Express SR-IOV (Função Virtual VF) especificados se o valor -1 tiver sido gravado neles primeiro.
SRIOV_QUERY_VF_LUID

Obtém o identificador exclusivo local da função virtual PCI Express SR-IOV (VF).
SRIOV_READ_BLOCK

Lê dados do bloco de configuração especificado de uma VF (Função Virtual sr-IOV) do PCI Express.
SRIOV_READ_CONFIG

Lê dados do espaço de configuração da VF (Função Virtual sr-IOV) do PCI Express.
SRIOV_RESET_FUNCTION

Redefine a VF (Função Virtual sr-IOV) do PCI Express especificada.
SRIOV_SET_POWER_STATE

Define o estado de energia da VF (Função Virtual SR-IOV) expressa PCI especificada.
SRIOV_WRITE_BLOCK

Grava dados no bloco de configuração especificado de uma VF (Função Virtual SR-IOV) do PCI Express.
SRIOV_WRITE_CONFIG

Grava dados de configuração em uma VF (Função Virtual SR-IOV) do PCI Express.

Estruturas

 
MITIGABLE_DEVICE_INTERFACE

Armazena ponteiros de função para funções de retorno de chamada implementadas pelo driver de função física (PF) para a interface de dispositivo atenuante.
SRIOV_DEVICE_INTERFACE_STANDARD

Armazena ponteiros de função para funções de retorno de chamada implementadas pelo driver de função física (PF) na pilha do dispositivo do dispositivo SR-IOV.
SRIOV_DEVICE_INTERFACE_STANDARD_2

Armazena ponteiros de função para funções de retorno de chamada implementadas pelo driver de função física (PF) na pilha do dispositivo do dispositivo SR-IOV. Esta é uma versão estendida do SRIOV_DEVICE_INTERFACE_STANDARD.
SRIOV_INVALIDATE_BLOCK

Contém as informações do bloco de configuração. Essa estrutura é usada em uma solicitação de IOCTL_SRIOV_INVALIDATE_BLOCK.
SRIOV_MITIGATED_RANGE_COUNT_INPUT

Essa estrutura é usada como um buffer de entrada para a solicitação IOCTL_SRIOV_QUERY_MITIGATED_RANGE_COUNT para determinar os intervalos de espaço de E/S mapeado pela memória que devem ser mitigados.
SRIOV_MITIGATED_RANGE_COUNT_OUTPUT

Essas estruturas são o buffer de saída recebido pela solicitação IOCTL_SRIOV_QUERY_MITIGATED_RANGE_COUNT que contém uma matriz de intervalos de espaço de E/S mapeado pela memória que devem ser mitigados.
SRIOV_MITIGATED_RANGE_UPDATE_INPUT

Essa estrutura é usada como um buffer de entrada para a solicitação de IOCTL_SRIOV_MITIGATED_RANGE_UPDATE para indicar a VF (função virtual) cujo espaço de E/S mapeado pela memória deve ser mitigado.
SRIOV_MITIGATED_RANGE_UPDATE_OUTPUT

Essas estruturas são o buffer de saída recebido pela solicitação IOCTL_SRIOV_MITIGATED_RANGE_UPDATE que indica a VF (função virtual) cujo espaço de E/S mapeado pela memória foi mitigado.
SRIOV_MITIGATED_RANGES_INPUT

Essa estrutura é o buffer de entrada na solicitação IOCTL_SRIOV_QUERY_MITIGATED_RANGES para obter os intervalos específicos nos quais as interceptações devem ser colocadas.
SRIOV_MITIGATED_RANGES_OUTPUT

Essa estrutura é o buffer de saída recebido pela solicitação IOCTL_SRIOV_QUERY_MITIGATED_RANGES para obter os intervalos específicos nos quais as interceptações devem ser colocadas.
SRIOV_PNP_EVENT_COMPLETE

Armazena o status para um evento que o driver PF (Função Física) SR-IOV deve definir para conclusão uniforme do Plug and Play. Essa estrutura é usada no buffer de entrada da solicitação de IOCTL_SRIOV_EVENT_COMPLETE.
SRIOV_PROXY_QUERY_LUID_OUTPUT

Armazena o identificador exclusivo local do dispositivo SR_IOV implementando a interface. Essa estrutura é o buffer de saída da solicitação de IOCTL_SRIOV_PROXY_QUERY_LUID.

Enumerações

 
SRIOV_PF_EVENT

Define valores de evento para o dispositivo SR-IOV.