Suporte ao Depurador 2PF KDNET
Este tópico descreve como habilitar o driver NDIS de miniporta para suporte ao depurador 2PF para permitir maior desempenho para adaptadores de alta velocidade, frequentemente usados em data centers. Esse recurso está disponível no Windows 11 e posterior.
Ao ativar a depuração do kernel em uma NIC, o suporte à depuração do kernel assume o dispositivo físico para fornecer uma depuração do kernel e uma conexão de rede na caixa. Isso funciona bem em NICs de baixa largura de banda do consumidor (1-10 Gbps), mas em dispositivos de alta taxa de transferência que suportam 10-40+ Gbps, os módulos de extensibilidade de depuração do kernel que conversam com o hardware geralmente não conseguem acompanhar a quantidade de tráfego que vem da pilha de rede do Windows, portanto, isso degrada o desempenho geral do sistema.
O uso do recurso PCI de múltiplas funções físicas (PF) para o KDNET permite que a depuração seja habilitada com quase nenhum impacto no desempenho.
A função física (PF) é uma função PCI Express (PCIe) de um adaptador de rede que oferece suporte à interface de virtualização de E/S de raiz única (SR-IOV). O PF inclui o SR-IOV Extended Capability no espaço PCIe Configuration. O recurso é usado para configurar e gerenciar a funcionalidade SR-IOV do adaptador de rede, como habilitar a virtualização e expor VFs (Funções Virtuais) PCIe.
O PF suporta a estrutura SR-IOV Extended Capability em seu espaço de configuração PCIe. Essa estrutura é definida na especificação PCI-SIG Single Root I/O Virtualization and Sharing 1.1.
O transporte do depurador aproveitará vários ou 2PF habilitados para drivers de miniporta. Para permitir a depuração de sistemas de servidores de alta velocidade, recomenda-se que os fornecedores de NIC habilitem 2PF em todas as NICs que suportam vários PF no firmware da placa de rede.
Para obter informações sobre como configurar o suporte ao 2PF para testar uma conexão, consulte Configurando a depuração do modo kernel do 2PF usando o KDNET.
Visão geral da arquitetura KDNET de vários PF
A funcionalidade Multiple PF (2PF) é adicionar/atribuir um novo PF à porta de rede PCI original (por exemplo, Bus.dev.fun0.0).
O novo PF adicionado (por exemplo, bus.dev.fun0.1) é usado apenas pelo KDNET para rotear pacotes do Depurador de/para o destino.
O PF original será usado pelo driver de NIC da caixa de entrada do Windows para rotear os pacotes de rede do Windows (TCP/IP).
Usando essa abordagem, ambos os drivers podem trabalhar em paralelo sem interferir no trabalho um do outro.
Ambos os drivers serão executados sobre o espaço de configuração PCI particionado
O driver da Caixa de Entrada do Windows ficará sem a porta de rede original em bus.dev.fun0.0
KDNET-KDNET-Ext. módulo ficará sem o PF adicionado em bus.dev.fun0.1, Dessa forma, garante que o driver de NIC da caixa de entrada do Windows não seja afetado pelo compartilhamento da NIC com o KDNET.
A ferramenta de modo de usuário kdnet.exe configura o recurso 2PF usando o driver da caixa de entrada do Windows adicionando códigos IOCTL específicos para adicionar/remover o KDNET PF.
Vários requisitos de design de recursos de PFs
O recurso KDNET 2PF precisa funcionar para todos os cenários atuais do KD, seja o sistema operacional pré-NT (por exemplo, Gerenciador de inicialização, carregador de SO, WinResume, Hyper-V, SK, etc.), NT OS ou Windows Desktop.
A reinicialização do sistema será necessária quando a adição de um novo PF para um dispositivo resultar em uma alteração necessária na configuração do BCD para as configurações de depuração. Isso significa que a configuração de um PF adicional deve ser persistente nas inicializações.
O KDNET 2PF deve ser usado apenas pelo depurador para garantir que não haja nenhum outro driver ethernet Windows/UEFI acessando/executando a partir do local PCI 2PF quando o depurador possui o dispositivo de depuração (o local 2PF é configurado usando dbgsettings::busparams).
Os drivers Ethernet do Windows ou UEFI não podem ficar sem o KDNET 2PF adicionado, mesmo quando o KDNET não está habilitado no sistema.
O recurso 2PF deve oferecer suporte a um mecanismo dinâmico para adicionar/habilitar e remover/desabilitar a funcionalidade na NIC atual.
Os drivers de miniporta do Windows implementarão o recurso 2PF por meio da manutenção dos seguintes OIDs NDIS.
Nome do OID | Descrição |
---|---|
OID_KDNET_ENUMERATE_PFS | Enumera PFs no bus.dev.fun atual (BDF), onde o driver de miniporta está sendo executado. |
OID_KDNET_ADD_PF | Adiciona um PF ao BDF atual, onde o driver de miniporta está em execução. |
OID_KDNET_REMOVE_PF | Remove o PF adicionado, do passado em BDF. |
OID_KDNET_QUERY_PF_INFORMATION | Consulta dados de informações da PF a partir do repassado no BDF. |
Os OIDs e suas estruturas são definidos em arquivos ntddndis.h e kdnetpf.h que são liberados com o WDK público.
Consulte os detalhes abaixo sobre os parâmetros de entrada/saída para cada OID e as informações fornecidas no arquivo de cabeçalho kdnetpf.h.
- O KDNET deve ser configurado por meio do recurso KDNET 2PF no NICS onde vários recursos PF estão disponíveis, e o NIC habilita a funcionalidade 2PF seguindo todos os requisitos descritos acima.
KDNET Multiple PF Interface para drivers de NIC do Windows
Para suportar o KDNET, os drivers de Miniporta de Interface PF Múltipla precisarão implementar o tratamento dos quatro OIDs NDIS a seguir.
OID_KDNET_ENUMERATE_PFS
OID_KDNET_ADD_PF
OID_KDNET_REMOVE_PF
OID_KDNET_QUERY_PF_INFORMATION
Esses OIDs e estruturas são preenchidos nos arquivos ntddndis.h e kdnetpf.h na versão pública do WDK neste caminho:
<WDK root directory>\ddk\inc\ndis
Esses arquivos também estão disponíveis no SDK do Windows e podem ser encontrados neste diretório.
\Program Files (x86)\Windows Kits\10\Include\<Version for example 10.0.21301.0>\shared
A ferramenta cliente (kdnet.exe) usa um NDIS IOCTL privado para rotear os OIDs NDIS KDNET 2PF para os drivers de miniporta.
O recurso Multiple PF NDIS OIDs
O recurso Multiple PF é operado usando esses quatro OIDs NDIS.
1. Enumere PFs na porta primária BDF de miniporta usando OID: OID_KDNET_ENUMERATE_PFS, veja a definição abaixo.
OID_KDNET_ENUMERATE_PFS retorna uma lista de todos os BDFs associados à porta primária especificada de onde o driver de miniporta está sendo executado. A porta é representada pelo bus.dev.fun (BDF). A operação listará/enumerará a lista de PFs que estão associados apenas à bus.dev.fun (porta BDF) de onde o driver de miniporta está sendo executado no sistema, uma vez que cada driver de miniporta pode determinar sua localização BDF.
A lista de PFs será retornada ao cliente por meio de uma operação de consulta NDIS.
O OID_KDNET_ENUMERATE_PFS OID está associado à estrutura NDIS_KDNET_ENUMERATE_PFS.
O manipulador de driver OID_KDNET_ENUMERATE_PFS retornará um buffer contendo a lista PFs com cada elemento PF descrito pelo tipo NDIS_KDNET_PF_ENUM_ELEMENT.
O campo PfNumber contém o Número da Função PF (por exemplo, bus.dev.diversão)
O campo PfState contém os valores possíveis do estado PF - cada tipo de elemento descrito por NDIS_KDNET_PF_STATE enum.
NDIS_KDNET_PF_STATE::NdisKdNetPfStatePrimary - Este é um PF primário e geralmente é usado apenas pelo driver de miniporta.
NDIS_KDNET_PF_STATE::NdisKdnetPfStateEnabled - Este é um PF secundário adicionado, que é usado pelo KDNET.
NDIS_KDNET_PF_STATE::NdisKdnetPfStateConfigured - Este é um PF adicionado, mas é apenas adicionado/configurado e não é usado.
Se o tamanho do buffer de saída da lista PF não for grande o suficiente para alocar a lista PFs real, o manipulador OID precisará retornar
E_NOT_SUFFICIENT_BUFFER
o valor de retorno de erro, juntamente com o tamanho do buffer necessário, para que a ferramenta cliente possa alocar o buffer de tamanho necessário e, em seguida, o cliente possa fazer outra chamada com o tamanho correto do buffer alocado. Além disso, o campo de status da solicitação OID (descrito por NDIS_IOCTL_OID_REQUEST_INFO.status) deve ser definido como igual aNDIS_STATUS_BUFFER_TOO_SHORT
.
2. Adicione PCI PF à porta primária BDF miniporta (OID: OID_KDNET_ADD_PF, veja a definição abaixo)
Adicione um PF à porta primária da miniporta. A porta é representada pelo BDF.
O PF recém-adicionado será devolvido ao cliente por meio de uma operação de consulta NDIS.
O OID_KDNET_ADD_PF OID está associado à estrutura NDIS_KDNET_ADD_PF.
O manipulador de driver OID_KDNET_ADD_PF retornará um ULONG contendo o número de função PF adicionado .
Essa solicitação OID terá apenas um parâmetro Output:
AddedFunctionNumber
. OAddedFunctionNumber
indica o valor do número de função adicionado no local PCI da miniporta (a miniporta BDF). O utilitário kdnet.exe receberá esse valor e configurará dbgsettings::busparams para apontar para o PF adicionado.
Observação
O PF adicionado pode ser usado exclusivamente pelo KDNET, então os drivers de NIC do Windows são manipulados para executar expressamente *NÃO* em um PF adicionado, então isso também se aplica quando o KDNET está *NÃO* habilitado no sistema e o PF foi adicionado à porta.
3. Remover PCI PF (OID: OID_KDNET_REMOVE_PF, veja a definição abaixo)
Remova um PF da porta fornecida. A porta é representada pelo BDF.
O OID_KDNET_REMOVE_PF OID está associado à estrutura NDIS_KDNET_REMOVE_PF.
O OID OID_KDNET_REMOVE_PF tem uma porta BDF de entrada e retorna um ULONG contendo o número da função PF removido por meio de uma operação do Método NDIS.
Essa função terá êxito somente nos PFs que foram adicionados usando o OID_KDNET_ADD_PF OID.
Essa solicitação OID terá a porta BDF de entrada de onde precisa ser removido o BDF. Esta função tem um parâmetro Output de
FunctionNumber
. A saídaFunctionNumber
conterá o valor do número da função removido.
4. Consultar informações do PCI PF (OID: OID_KDNET_QUERY_PF_INFORMATION, ver definição abaixo)
Este código OID permite consultar dados PF específicos em uma determinada porta. A porta é representada pelo BDF.
As informações solicitadas do PF serão devolvidas ao cliente por meio de uma operação do Método NDIS.
O OID_KDNET_QUERY_PF_INFORMATION OID está associado à estrutura NDIS_KDNET_QUERY_PF_INFORMATION.
O OID OID_KDNET_QUERY_PF_INFORMATION tem uma porta BDF de entrada e retorna um buffer contendo os seguintes dados:
Endereço MAC: Endereço de rede do novo KDNET PF atribuído, se houver.
Tag de uso: descreve a entidade proprietária da porta PF. Ele contém um valor constante descrito por NDIS_KDNET_PF_USAGE_TAG enum.
Número máximo de PFs: Contém um ULONG com o número máximo de PFs que podem ser adicionados ao BDF fornecido.
ID do dispositivo: contém o ID do dispositivo associado à porta BDF fornecida. Isso é necessário para os casos em que o FW da NIC atribui um novo ID de dispositivo à nova porta KDNET PF adicionada.
Esse OID solicita as informações para qualquer porta BDF passada (BDF é um parâmetro de entrada para esta operação), portanto, não está necessariamente relacionado ao BDF atual de onde o driver está sendo executado.
NDIS OIDs para KDNET em 2PF
O arquivo Ntddndis.h define os OIDs.
#if (NDIS_SUPPORT_NDIS686)
//
// Optional OIDs to handle network multiple PF feature.
//
#define OID_KDNET_ENUMERATE_PFS 0x00020222
#define OID_KDNET_ADD_PF 0x00020223
#define OID_KDNET_REMOVE_PF 0x00020224
#define OID_KDNET_QUERY_PF_INFORMATION 0x00020225
#endif // (NDIS_SUPPORT_NDIS686)
O arquivo Kdnetpf.h descreve o tipo e as estruturas associadas aos OIDs NDIS.
#if (NDIS_SUPPORT_NDIS686)
//
// Used to query/add/remove Physical function on a network port.
// These structures are used by these OIDs:
// OID_KDNET_ENUMERATE_PFS
// OID_KDNET_ADD_PF
// OID_KDNET_REMOVE_PF
// OID_KDNET_QUERY_PF_INFORMATION
// These OIDs handle PFs that are primary intended to be used by KDNET.
//
//
// PCI location of the port to query
//
typedef struct _NDIS_KDNET_BDF
{
ULONG SegmentNumber;
ULONG BusNumber;
ULONG DeviceNumber;
ULONG FunctionNumber;
ULONG Reserved;
} NDIS_KDNET_BDF, *PNDIS_KDNET_PCI_BDF;
//
// PF supported states.
//
typedef enum _NDIS_KDNET_PF_STATE
{
NdisKdNetPfStatePrimary = 0x0,
NdisKdnetPfStateEnabled = 0x1,
NdisKdnetPfStateConfigured = 0x2,
} NDIS_KDNET_PF_STATE,*PNDIS_KDNET_PF_STATE;
//
// PF Usage Tag
// Used to indicate the entity that owns the PF.
// Used by the query NdisKdnetQueryUsageTag.
//
typedef enum _NDIS_KDNET_PF_USAGE_TAG
{
NdisKdnetPfUsageUnknown = 0x0,
NdisKdnetPfUsageKdModule = 0x1,
} NDIS_KDNET_PF_USAGE_TAG,*PNDIS_KDNET_PF_USAGE_TAG;
//
// PF element array structure
//
typedef struct _NDIS_KDNET_PF_ENUM_ELEMENT
{
NDIS_OBJECT_HEADER Header;
//
// PF value (e.g. if <bus.dev.fun>, then PF value = fun)
//
ULONG PfNumber;
//
// The PF state value (defined by NDIS_KDNET_PF_STATE)
//
NDIS_KDNET_PF_STATE PfState;
} NDIS_KDNET_PF_ENUM_ELEMENT, *PNDIS_KDNET_PF_ENUM_ELEMENT;
#define NDIS_KDNET_PF_ENUM_ELEMENT_REVISION_1 1
#define NDIS_SIZEOF_KDNET_PF_ENUM_ELEMENT_REVISION_1 \
RTL_SIZEOF_THROUGH_FIELD(NDIS_KDNET_PF_ENUM_ELEMENT, PfState)
//
// This structure describes the data required to enumerate the list of PF
// Used by OID_KDNET_ENUMERATE_PFS.
//
typedef struct _NDIS_KDNET_ENUMERATE_PFS
{
NDIS_OBJECT_HEADER Header;
//
// The size of each element is the sizeof(NDIS_KDNET_PF_ENUM_ELEMENT)
//
ULONG ElementSize;
//
// The number of elements in the returned array
//
ULONG NumberOfElements;
//
// Offset value to the first element of the returned array.
// Each array element is defined by NDIS_KDNET_PF_ENUM_ELEMENT.
//
ULONG OffsetToFirstElement;
} NDIS_KDNET_ENUMERATE_PFS, *PNDIS_KDNET_ENUMERATE_PFS;
#define NDIS_KDNET_ENUMERATE_PFS_REVISION_1 1
#define NDIS_SIZEOF_KDNET_ENUMERATE_PFS_REVISION_1 \
RTL_SIZEOF_THROUGH_FIELD(NDIS_KDNET_ENUMERATE_PFS,
OffsetToFirstElement)
//
// This structure indicates the data required to add a PF to the BDF port.
// Used by OID_KDNET_ADD_PF.
//
typedef struct _NDIS_KDNET_ADD_PF
{
NDIS_OBJECT_HEADER Header;
//
// One element containing the added PF port number
//
ULONG AddedFunctionNumber;
} NDIS_KDNET_ADD_PF, *PNDIS_KDNET_ADD_PF;
#define NDIS_KDNET_ADD_PF_REVISION_1 1
#define NDIS_SIZEOF_KDNET_ADD_PF_REVISION_1 \
RTL_SIZEOF_THROUGH_FIELD(NDIS_KDNET_ADD_PF, AddedFunctionNumber)
//
// This structure indicates the data required to remove a PF from the BDF port.
// Used by OID_KDNET_REMOVE_PF.
//
typedef struct _NDIS_KDNET_REMOVE_PF
{
NDIS_OBJECT_HEADER Header;
//
// PCI location that points to the PF that needs to be removed
//
NDIS_KDNET_BDF Bdf;
//
// One element containing the removed PF port
//
ULONG FunctionNumber;
} NDIS_KDNET_REMOVE_PF, *PNDIS_KDNET_REMOVE_PF;
#define NDIS_KDNET_REMOVE_PF_REVISION_1 1
#define NDIS_SIZEOF_KDNET_REMOVE_PF_REVISION_1 \
RTL_SIZEOF_THROUGH_FIELD(NDIS_KDNET_REMOVE_PF, FunctionNumber)
//
// This structure describes the data required to query the PF management data
// Used by OID_KDNET_QUERY_PF_INFORMATION
//
typedef struct _NDIS_KDNET_QUERY_PF_INFORMATION
{
NDIS_OBJECT_HEADER Header;
//
// PF PCI location to query for
//
NDIS_KDNET_BDF Bdf;
//
// PF assigned MAC address
//
UCHAR NetworkAdddress[6];
//
// PF Usage tag described by NDIS_KDNET_PF_USAGE_TAG
//
ULONG UsageTag;
//
// Maximum number of Pfs that can be associated to the Primary BDF.
//
ULONG MaximumNumberOfSupportedPfs;
//
// KDNET PF device ID (Used if there is a new added PF and
// the FW assigns a new DeviceID to the added KDNET PF)
//
ULONG DeviceId;
} NDIS_KDNET_QUERY_PF_INFORMATION, *PNDIS_KDNET_QUERY_PF_INFORMATION;
#define NDIS_KDNET_QUERY_PF_INFORMATION_REVISION_1 1
#define NDIS_SIZEOF_KDNET_QUERY_PF_INFORMATION_REVISION_1 \
RTL_SIZEOF_THROUGH_FIELD(NDIS_KDNET_QUERY_PF_INFORMATION, DeviceId)
#endif // (NDIS_SUPPORT_NDIS686)