調試程式 2PF KDNET 支援

本主題描述如何啟用迷你埠 NDIS 驅動程式,以支援 2PF 調試程式,以允許高速適配卡的效能提升,通常用於數據中心。 這項功能適用於 Windows 11 和更新版本。

在網路介面卡上啟用核心偵錯功能時,核心偵錯支援會掌控實體裝置,提供系統的核心偵錯和網路連線功能。 這在消費級低頻寬網卡(1–10 Gbps)上運作良好。 然而,在支援 10–40+ Gbps 的高吞吐量裝置上,核心除錯擴充模組無法跟上來自 Windows 網路堆疊的流量。 因此,整體系統效能會下降。

針對 KDNET 使用 PCI 多重實體函式 (PF) 功能可讓偵錯啟用,幾乎不會影響效能。

實體函式 (PF) 是網路適配器的 PCI Express (PCIe) 函式,可支援單一根 I/O 虛擬化 (SR-IOV) 介面。 PF 在 PCIe 設定空間中包含 SR-IOV 擴展功能。 此功能可用來設定和管理網路適配器的 SR-IOV 功能,例如啟用虛擬化和公開PCIe虛擬函式 (VFs)。

PF 在其 PCIe 設定空間中支援 SR-IOV 擴充功能結構。 此結構定義於 PCI-SIG 單根 I/O 虛擬化與共用 1.1 規格中。

除錯器傳輸利用多個或啟用 2PF 的 Miniport 驅動程式。 為了方便除錯高速伺服器系統,建議網卡廠商在所有支援多重 PF 的網卡韌體中啟用 2PF。

如需設定 2PF 支援以測試連線的資訊,請參閱 使用 KDNET設定 2PF Kernel-Mode 偵錯。

多重 PF KDNET 架構總覽

  • 多重 PF(2PF)功能是將新的 PF 新增或指派到原本的 PCI 網路埠(例如 Bus.dev.fun0.0)。

  • 新增的 PF(例如 bus.dev.fun0.1)僅由 KDNET 用於將除錯器封包路由至目標或從目標端。

  • Windows 收件匣的網卡驅動程式使用原始的 PF 來路由 Windows 網路封包(TCP/IP)。

  • 使用此方法,這兩個驅動程式可以平行運作,而不干擾彼此的工作。

  • 兩個驅動程式都運行於分割的 PCI 配置空間

    • Windows Inbox 驅動程式在 bus.dev 時會用不到原本的網路埠。樂趣0.0

    • KDNET-KDNET-延伸模組在 bus.dev 時會用盡額外的 PF。fun0.1,這樣可以確保 Windows 收件匣的網卡驅動程式不會因為與 KDNET 共享網卡而受到影響。

  • kdnet.exe 使用者模式工具會藉由新增特定的 IOCTL 程式代碼來新增/移除 KDNET PF,使用 Windows 收件匣驅動程式來設定 2PF 功能。

顯示兩個網路堆疊的圖表,其中一個使用合併的 PCI 介面卡設定來支援 2PF。

多個 PFS 功能設計需求

  1. KDNET 2PF 功能必須適用於所有目前的 KD 場景,無論是前 NT 作業系統(例如 Boot Manager、OS loader、WinResume、Hyper-V、SK 等)、NT OS 或 Windows 桌面。

  2. 若新增裝置的 PF 導致除錯 BCD 設定變更,則需重新啟動系統。 此要求意味著額外 PF 的設定必須在多個開機間持續存在。

  3. 除錯時只使用 KDNET 2PF。 這確保當除錯器擁有裝置時,沒有任何 Windows 或 UEFI 乙太網路驅動程式能存取 PCI 2PF 位置。 2PF 的位置是透過使用 dbgsettings::busparams 來設定的。

  4. 即使系統中沒有啟用 KDNET,Windows 或 UEFI 乙太網路驅動程式也無法用掉新增的 KDNET 2PF。

  5. 2PF 功能應該支援動態機制,以便在目前的 NIC 上新增/啟用和移除/停用功能。

  6. Windows Miniport 驅動程式透過服務以下 NDIS OID 實作 2PF 功能。

OID 名稱 描述
OID_KDNET_ENUMERATE_PFS 列舉目前 bus.dev.fun (BDF) 上的 PF,其中迷你埠驅動程式正在執行。
OID_KDNET_ADD_PF 在迷你埠驅動程式運行的環境下,將 PF 新增至目前的 BDF。
OID_KDNET_REMOVE_PF 從傳入的 BDF 中移除新增的 PF。
OID_KDNET_QUERY_PF_INFORMATION 從傳入的 BDF 查詢 PF 信息數據。

OID 及其結構定義於 ntddndis.h 和 kdnetpf.h 檔案中,這些檔案會隨著公用 WDK 發行。

請參閱以下關於每個 OID 的輸入/輸出參數細節,以及 kdnetpf.h 標頭檔案中提供的資訊。

  1. 在支援多個 PF 的網卡上,使用 KDNET 2PF 功能來設定 KDNET。 確保網卡符合本節所述所有要求,以啟用 2PF 功能。

適用於 Windows NIC 驅動程式的 KDNET 多重 PF 介面

為了支援 KDNET 多重 PF 介面,Miniport 驅動程式需要實作以下四個 NDIS OID 的處理。

  • OID_KDNET_ENUMERATE_PFS

  • OID_KDNET_ADD_PF

  • OID_KDNET_REMOVE_PF

  • OID_KDNET_QUERY_PF_INFORMATION

這些 OID 和資料結構填入在此路徑的公開版 WDK 中的 ntddndis.h 和 kdnetpf.h 檔案:

<WDK root directory>\ddk\inc\ndis

這些檔案也可在 Windows SDK 中使用,而且可在此目錄中找到。

\Program Files (x86)\Windows Kits\10\Include\<Version for example 10.0.21301.0>\shared

用戶端工具(kdnet.exe)使用私人 NDIS IOCTL,將 KDNET 2PF NDIS OIDs 路由至小端口驅動程式。

多重 PF 功能 NDIS OID

多重 PF 功能是使用這四個 NDIS OID 來運作。

1. 使用 OID: OID_KDNET_ENUMERATE_PFS 列舉迷你埠 BDF 主埠上的 PF,詳見以下定義。

  • OID_KDNET_ENUMERATE_PFS 會從迷你埠驅動程序執行所在的指定主要埠傳回與指定主要埠相關聯的所有 BDF 清單。 bus.dev.fun(BDF)代表港口。 操作列出僅與迷你埠驅動程式運行的 bus.dev.fun(BDF 埠) 相關聯 的 PF。 每個迷你埠驅動程式都可以決定其 BDF 位置。

  • PF 清單會透過 NDIS 查詢操作回傳給用戶端。

  • OID_KDNET_ENUMERATE_PFS OID 與 NDIS_KDNET_ENUMERATE_PFS 結構相關聯。

  • OID_KDNET_ENUMERATE_PFS驅動處理器會回傳一個緩衝區,內含 PF 清單,每個 PF 元素皆以 NDIS_KDNET_PF_ENUM_ELEMENT 型別描述。

    PfNumber 欄位包含 PF 功能編號(例如 bus.dev。有趣

    PfState 字段包含 PF 狀態的可能值,每個元素類型由列舉 NDIS_KDNET_PF_STATE 描述。

    NDIS_KDNET_PF_STATE::NdisKdNetPfStatePrimary - 這是主要 PF,通常只供迷你埠驅動程式使用。

    NDIS_KDNET_PF_STATE::NdisKdnetPfStateEnabled - 這是 KDNET 使用的額外次要 PF。

    NDIS_KDNET_PF_STATE::NdisKdnetPfStateConfigured - 這是新增的 PF,但只是新增/設定,並未被使用。

  • 如果 PF 清單的輸出緩衝區大小不足以分配實際的 PF 清單,則 OID 處理器必須回傳 E_NOT_SUFFICIENT_BUFFER 錯誤回傳值及所需的緩衝區大小,讓用戶端工具能分配所需的緩衝區大小,然後用戶端再以正確分配的緩衝區大小進行呼叫。 此外,OID 請求狀態欄位(由 NDIS_IOCTL_OID_REQUEST_INFO.status 描述)應設為 NDIS_STATUS_BUFFER_TOO_SHORT

2. 將 PCI PF 加入迷你埠 BDF 主埠(OID: OID_KDNET_ADD_PF, 詳見以下定義)

  • 將 PF 新增至迷你埠主要埠。 bus.dev.fun(BDF)代表港口。

  • 新增的 PF 會透過 NDIS 查詢操作回傳給用戶端。

  • OID_KDNET_ADD_PF OID 與 NDIS_KDNET_ADD_PF 結構相關聯。

  • OID_KDNET_ADD_PF驅動處理器會回傳包含新增的 PF 函式編號的 ULONG。

  • 此 OID 請求僅有一個輸出參數: AddedFunctionNumberAddedFunctionNumber 表示在迷你埠 PCI 位置(BDF 迷你埠)新增的函數數值。 kdnet.exe 工具接收此值,並設定 dbgsettings::busparams 指向新增的 PF。

提示

KDNET 可以專門使用新增的 PF。 Windows 的 NIC 驅動程式被設定為明確不允許在新增的 PF 上執行。 當系統上 KDNET *未*啟用且 PF 被加入埠口時,這同樣適用。

3. 移除 PCI PF(OID : OID_KDNET_REMOVE_PF,詳見以下定義)

  • 從指定連接埠 移除 PF。 bus.dev.fun(BDF)代表港口。

  • OID_KDNET_REMOVE_PF OID 與 NDIS_KDNET_REMOVE_PF 結構相關聯。

  • OID_KDNET_REMOVE_PF OID 具有一個輸入 BDF 埠,並透過 NDIS 方法操作返還一個 ULONG,其中包含已移除的 PF 函數編號

  • 此功能僅在使用 OID_KDNET_ADD_PF OID 新增的 PF 上成功。

  • 此 OID 請求的輸入 BDF 埠需移除 BDF。 此函式具有 FunctionNumber的 Output 參數。 輸出 FunctionNumber 包含被移除的函式數值。

4. 查詢 PCI PF 資訊(OID: OID_KDNET_QUERY_PF_INFORMATION,詳見以下定義)

  • 此 OID 程式代碼允許在指定的連接埠 上查詢特定 PF 資料,。 bus.dev.fun(BDF)代表港口。

  • 所請求的 PF 資訊會透過 NDIS 方法操作回傳給用戶端。

  • OID_KDNET_QUERY_PF_INFORMATION OID 與 NDIS_KDNET_QUERY_PF_INFORMATION 結構相關聯。

  • OID_KDNET_QUERY_PF_INFORMATION OID 具有輸入 BDF 埠,並傳回包含下列數據的緩衝區:

    • MAC 位址:指派新 KDNET PF 的網路位址(如果有的話)。

    • 使用標籤:描述擁有 PF 埠的實體。 它包含一個由 NDIS_KDNET_PF_USAGE_TAG 列舉所描述的常數值。

    • PF 數目上限:包含一個 ULONG,該值為可新增至指定 BDF 的 PF 最多數量。

    • 裝置標識碼:包含與指定 BDF 埠相關聯的裝置識別碼。 當 NIC FW 將新的裝置識別碼指派給新增的 KDNET PF 埠時,這是必要的。

  • 此 OID 會請求任何在 BDF 埠傳遞的資訊(BDF 是此操作的輸入參數)。 這 一定和駕駛者目前逃跑的 BDF 無關。

用於 2PF 上 KDNET 的 NDIS OIDs

Ntddndis.h 檔案會定義 OID。

#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)

Kdnetpf.h 檔案描述與 NDIS OID 相關聯的類型和結構。

#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 (for example, 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's 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)

另請參閱

使用 KDNET 設定 2PF Kernel-Mode 偵錯

網路 OID

kdnetpf.h 標頭