次の方法で共有


KDNETトランスポート拡張モジュールの開発

このトピックでは、個別のハードウェア ドライバー拡張モジュール dll を使用して、KDNET トランスポートを任意のハードウェアで実行するように拡張する方法について説明します。 KDNET トランスポート拡張モジュールは、特定のネットワーク カードにカーネル デバッグのサポートを追加するために、ネットワーク カード ベンダーによって開発されています。

KDNETの概要

KDNET は、ネットワーク経由でのウィンドウのカーネル デバッグを可能にするカーネル デバッグ トランスポートです。 当初は、イーサネット NIC を使用したカーネル デバッグをサポートするために使用されていました。 これは、ハードウェア サポート層が、ネットワーク パケット処理およびカーネル インターフェイス層とは別のモジュールに組み込まれるように設計されています。 このハードウェア ドライバーサポート層は、KDNET 拡張モジュールと呼ばれます。

KDNET は、別のハードウェア ドライバー拡張モジュール dll を使用して、任意のハードウェアで実行するように拡張できる唯一のトランスポートです。 KDNET および KDNET 拡張モジュールを介して Windows のすべてのデバッグをサポートすることが目標です。 その他のすべてのカーネル トランスポート DLL (kdcom.dll、kd1394.dll、kdusb.dllなど) は最終的に非推奨になり、Windows から削除されます。

KDNET は、KDNET 拡張モジュールとの通信に使用する 2 種類のインターフェイスがあります。 1 つは NIC、USB、ワイヤレス ハードウェアに使用されるパケット ベースのインターフェイスで、もう 1 つはシリアル ハードウェア経由で KDNET をサポートするために使用されるバイト ベースのインターフェイスです。

KDNET 拡張性モジュールは、正しく動作するために非常に厳しい要件に従う必要があります。 これらはカーネルデバッグに使用されるため、システムがコードの追加の実行を保留しているときに呼び出され、実行されます。 一般に、システム内のすべてのプロセッサは、カーネル デバッグ トランスポートを介してホスト コンピューター上で実行されているデバッガー アプリケーションと通信しているプロセッサを除き、IPI でスピンがロックされます。 通常、そのプロセッサは割り込みを完全に無効にして実行され、基本的にはデバッグ トランスポート ハードウェア上でスピンし、デバッガーからコマンドが送信されるのを待機しています。

インポートとエクスポート

KDNET 拡張モジュールには、KdInitializeLibrary という 1 つの明示的なエクスポートがあります。 また、明示的なインポートもありません。 KDNET 拡張モジュールは、KdInitializeLibrary を呼び出すときに KDNET によって呼び出すことが許可されているルーチンの一覧を持つ構造体へのポインターを渡します。 他のルーチンは呼び出されません。 以上。 インポートがある KDNET 拡張モジュールは誤って設計されており、サポートされません。

リンク /dump /exports とリンク /dump /imports を使用して KDNET 拡張モジュールのインポートとエクスポートをダンプすると、エクスポートは 1 つだけ (KdInitializeLibrary) になり、インポートはありません。 KDNET 拡張モジュールは、KdInitializeLibrary が呼び出されたときに KDNET がポインターを渡すエクスポート関数構造体に関数ポインターを入力することによって、KDNET への追加のエクスポートを報告します。 その後、KDNET はその構造体の関数ポインターを使用して拡張モジュールを呼び出し、モジュールでサポートされているハードウェアを使用してデータ転送を行います。 KDNET は、モジュールがパケット ベースのモジュールかバイト ベースのモジュールかを判断します。このモジュールが構造体のエクスポート関数テーブルに入力する特定の関数を調べます。 これらの関数の中には、パケット ベースのハードウェアをサポートするものもあれば、シリアル ベースのハードウェア用の関数もあります。 テーブル内の関数の一部は、シリアル ベースとパケット ベースのハードウェア (KdInitializeController、KdShutdownController、KdGetHardwareContextSize) の両方で使用されます。

コード設計

KDNET 拡張モジュールは、シングル スレッド コードとして記述する必要があります。 同期は実行しないでください。 すべてのカーネル デバッグ トランスポートは、デバッガーが入力されたときに適切な同期を行うために Windows カーネルに依存します。 カーネルには、カーネル デバッガーに入るときに必要なデバッガー ロックがあり、デバッガーが入力されたときに IPI 内のシステム内の他のプロセッサもロックされます。 これらのプロセッサは、ホスト上で実行されているカーネル デバッガーが実行を続行できるようにターゲット コンピューターに指示した場合にのみ解放されます。 カーネルはこの同期を行うため、KDNET 拡張モジュールは、スピンロック、ミューテックス、ゲート、またはその他の Windows 同期メカニズムをコードで絶対に使用してはなりません。 パケットやバイトを送受信するために、それぞれのハードウェアを直接プログラムするように書き込む必要があります。

KDNET 拡張モジュール コードは、可能な限り単純にする必要があります。 これにより、KDNET 拡張機能モジュール コードをコンピューター上でライブデバッグすることは現在、ハードウェア デバッガーを使用せずに実行できないため、可能な限りバグがないことを確認できます。 カーネル デバッガーを使用してカーネル デバッグ トランスポート コードをデバッグすることはできません。 これを試みると、カーネル スタックが吹き飛ばされたり (通常は二重障害と再起動で終了する)、またはデッドロックが発生したり、トランスポートが再入力されたりして、ほとんどの場合、トランスポートが正常に動作しなくなります。

KDNET 拡張モジュールの名前付け規則

カーネル デバッグ トランスポート モジュールは、KDNET 拡張モジュールの 2 つの命名規則のいずれかに従う必要があります。 モジュールが PCI ベースのハードウェアをサポートする場合は、ハードウェアkd_YY_XXXX.dll名前を付ける必要があります。XXXX はハードウェアの PCI ベンダー ID (16 進数) で、YY はハードウェアの PCI クラスです。 PCI ベースのハードウェアをサポートするウィンドウのボックスに付属する KDNET 拡張モジュールがいくつかあります。 たとえば、Intel のkd_02_8086.dll、Broadcom のkd_02_14e4.dll、Realtek のkd_02_10ec.dllなどです。 登録されている PCI ベンダー ID は https://www.pcisig.com/membership/member-companies すべての PCI ベースの KDNET 拡張モジュールで検索できます。モジュール名の最後の 4 文字には、サポートするハードウェアのベンダー VID が 16 進数で使用されます。 ほとんどのインボックス モジュールのクラス コードは 02 です。これは、ネットワーク クラス デバイスであるため、PCI 構成空間に0x02の PCI クラスがあるためです。 Winload.exe PCI ベースの KDNET 拡張モジュールの名前を作成するには、PCI デバイス クラスと選択したデバッグ デバイスの PCI VID を PCI 構成領域から読み取り、それらの識別子を含むモジュールを名前に読み込もうとします。 デバイスにネットワーク 0x02 クラスではない PCI クラス コードがある場合は、KDNET 拡張モジュールの名前で、デバイスの正しい PCI クラス コードを 16 進数で使用する必要があります。 それ以外の場合、モジュールは winload によって正しく読み込まれません。 _02_ これらの各名前は、16 進数のネットワーク クラス デバイスの PCI クラス コードです。 このコードは、デバッグ デバイスの PCI 構成領域からも検出され、読み取られます。

DBG2 テーブル エントリを持ち、PCI ベースのデバイスではないデバイスがある場合、モジュールの名前付け規則は異なります。 DBG2 テーブル デバッグ デバイスの名前付け規則はkd_XXXX_YYYY.dll、XXXX は 16 進数の DBG2 テーブル PortType、YYYY は DBG2 テーブル エントリからの 16 進数の DBG2 テーブル PortSubtype です。 Kd_8003_5143.dllは、0x5143のサブタイプを持つ net (0x8003) PortType をサポートするための受信トレイ DLL です。 この場合、5143 は Qualcomm PCI vid です。これは Qualcomm USB コントローラーで KDNET をサポートするため、Net DBG2 テーブル エントリの場合、PortSubtype はハードウェアのベンダーの PCI VID として定義されています。 この名前付け規則を使用して、シリアル、USB、およびその他の DBG2 テーブル デバイスをサポートできることに注意してください。 現在サポートされている 16 進数の PortType 値を次に示します。シリアル デバイスの場合は 8000、1394 デバイスの場合は 8001、USB デバイスの場合は 8002、NET デバイスの場合は 8003 です。 シリアル デバイスと USB デバイスのサブタイプは、Microsoft で予約する必要があることに注意してください。 Microsoft メイン割り当てられたシリアル サブタイプと USB サブタイプの一覧が含まれています。 サポートされている既存の種類がハードウェアで動作しない場合は kdnet@microsoft.com シリアルまたは USB サブタイプを予約するためにメール を送信してください。

KDNET 拡張機能のインポート

KDNET 拡張モジュールから呼び出すことができるルーチンの一覧を次に示します。 これらのルーチンはすべて KdInitializeLibrary ルーチンに渡され、kdnetextensibility.h ヘッダーは、インポート テーブルを通過するためにこれらのルーチンへの通常の呼び出しを再マップします。 モジュールにインポートがないように、コードはインポート テーブルを介してこれらを呼び出す必要があります。 カーネル、HAL、またはその他のカーネル モジュールによってエクスポートされる他のルーチンは呼び出しできません。 これらのルーチンのみを呼び出す場合があります。 この一連のルーチンは、ボックス内の KDNET 拡張性モジュールをすべて開発するのに十分であることが証明されており、通常のシナリオでは十分です。 カーネルによってエクスポートされるが、このリストにない追加ルーチンが必要な場合は、シナリオと必要な追加ルーチンとその理由を説明したメールを kdnet@microsoft.com 送信してください。 この一覧は、主要な Windows リリース サイクルの場合にのみ追加されることに注意してください。 これらのルーチンのほとんどは、カーネルまたは HAL でサポートされている Windows カーネル API に直接対応しています。 1 つまたは 2 つはカスタム KDNET のみのルーチンです。

インポート テーブルを介してルーチンを正しく再マップできるように、kdnetextensibility.h をヘッダーに適切に含める必要があります。 これが行われなければ、モジュールにはインポートが含まれますが、サポートされません。

読み取り書き込みメモリ ルーチン

メモリ マップされたデバイス メモリの読み取りと書き込みには、次のルーチンを使用する必要があります。 これらは同じ呼び出し規則を持ち、対応するカーネル ルーチン (READ_REGISTER_UCHAR、READ_REGISTER_USHORT、READ_REGISTER_ULONG、WRITE_REGISTER_UCHAR、WRITE_REGISTER_USHORT、WRITE_REGISTER_ULONG、および 64 ビット プラットフォームではREAD_REGISTER_ULONG64とWRITE_REGISTER_ULONG64のみ) にマップされます。 すべてのデバイス メモリ アクセスは、プロセッサによって読み取りと書き込みが並べ替えられないようにするため、これらのルーチンを使用して実行する必要があります。 msdn.microsoft.com では、これらのルーチンの呼び出し規則に対応する Windows CE Compact 2013 ルーチンが文書化されていることに注意してください。 残念ながら、NT ルーチンは文書化されていないようですが、呼び出し規約は同じです。

IO ポート ルーチンの読み取り

デバイス IO ポートの読み取りと書き込みには、次のルーチンを使用する必要があります。 これらは同じ呼び出し規則を持ち、対応するカーネル ルーチン (READ_PORT_UCHAR、READ_PORT_USHORT、READ_PORT_ULONG、WRITE_PORT_UCHAR、WRITE_PORT_USHORT、WRITE_PORT_ULONG) にマップされます。 すべてのデバイス IO ポート アクセスは、これらのルーチンを使用して行う必要があります。 msdn.microsoft.com では、これらのルーチンの呼び出し規則に対応する Windows CE Compact 2013 ルーチンが文書化されていることに注意してください。

その他のルーチン

次の追加ルーチンを呼び出すことができます。また、指定されたパラメーターを使用して通常どおり呼び出す必要があります。 これを行うと、kdnetextensibility.h ヘッダーを適切に含めながら、KDNET 拡張インポート テーブルを介して関数呼び出しが再マップされるため、KDNET 拡張モジュールに必要であるため、モジュールに明示的なインポートは行われません。

PHYSICAL_ADDRESS

KdGetPhysicalAddress (

    __in PVOID Va

    );
 

VOID

KeStallExecutionProcessor (

    __in ULONG Microseconds

    );


ULONG

KdGetPciDataByOffset (

    __in ULONG BusNumber,

    __in ULONG SlotNumber,

    __out_bcount(Length) PVOID Buffer,

    __in ULONG Offset,

    __in ULONG Length

    );
 

ULONG

KdSetPciDataByOffset (

    __in ULONG BusNumber,

    __in ULONG SlotNumber,

    __in_bcount(Length) PVOID Buffer,

    __in ULONG Offset,

    __in ULONG Length

    );

 
VOID

KdSetDebuggerNotPresent (

    __in BOOLEAN NotPresent

    );
 

VOID

PoSetHiberRange (

    _In_opt_ PVOID MemoryMap,

    _In_ ULONG     Flags,

    _In_ PVOID     Address,

    _In_ ULONG_PTR Length,

    _In_ ULONG     Tag

    );

 

VOID

KeBugCheckEx (

    __in ULONG BugCheckCode,

    __in ULONG_PTR BugCheckParameter1,

    __in ULONG_PTR BugCheckParameter2,

    __in ULONG_PTR BugCheckParameter3,

    __in ULONG_PTR BugCheckParameter4

    );


PVOID

KdMapPhysicalMemory64 (

    _In_ PHYSICAL_ADDRESS PhysicalAddress,

    _In_ ULONG NumberPages,

    _In_ BOOLEAN FlushCurrentTLB

    );
 

VOID

KdUnmapVirtualAddress (

    _In_ PVOID VirtualAddress,

    _In_ ULONG NumberPages,

    _In_ BOOLEAN FlushCurrentTLB

    );
 

ULONG64

KdReadCycleCounter (

    __out_opt PULONG64 Frequency

    );

PoSetHiberRange 関数は KdSetHibernateRange ルーチンからのみ呼び出す必要があることに注意してください。 また、ほとんどの KDNET 拡張機能モジュールでは、KeBugCheckEx、KdMapPhysicalMemory64、KdUnmapVirtualAddress を呼び出す必要はありません。 一方、基本的にすべての KDNET 拡張モジュールは、デバイス DMA エンジンをプログラムするために必要な物理メモリ アドレスを取得するために KdGetPhysicalAddress を呼び出す必要があり、多くの場合、KeStallExecutionProcessor、KdGetPciDataByOffset、KdSetPciDataByOffset を呼び出す必要があります。 最後の 2 つのルーチンは、デバイスの PCI 構成領域にアクセスするためのルーチンです。

KDNET 拡張機能のエクスポート

KDNET の各機能拡張ルーチンの簡単な説明を次に示します。 パケット ベースの KDNET 拡張モジュールまたはシリアル ベースの KDNET 拡張モジュールに必要なすべてのルーチンを実装する必要があります。 パケット KDNET 拡張可能モジュールのエクスポートを次に示します。

KdInitializeLibrary

/*++

Routine Description:

    This routine validates that the ImportTable is a supported version.  Makes
    a copy of the ImportTable in its own global memory, and writes pointers to
    functions that it exports into the Exports pointer also located in that
    table.

    This routine also writes the size in bytes of the Memory it needs into
    the Length field of the Memory structure contained in the debug device
    descriptor passed to this routine.

    When kernel debugging is enabled, this routine will be called twice during
    boot.  The first time by winload to determine how much memory to allocate
    for KDNET and its extensibility module, and the second time by KDNET when
    the kernel first initializes the kernel debugging subsystem.

Arguments:

    ImportTable - Supplies a pointer to the KDNET_EXTENSIBILITY_IMPORT
        structure.

    LoaderOptions - Supplies a pointer to the LoaderOptions passed to the
        kernel.  This allows settings to be passed to the KDNET extensibility
        module using the loadoptions BCD setting.

    Device - Supplies a pointer to the debug device descriptor.

Return Value:

    STATUS_INVALID_PARAMETER if the version of the import or export table is
        incorrect.

    STATUS_SUCCESS if initialization succeeds.

--*/
NTSTATUS
KdInitializeLibrary (
    __in PKDNET_EXTENSIBILITY_IMPORTS ImportTable,
    __in_opt PCHAR LoaderOptions,
    __inout PDEBUG_DEVICE_DESCRIPTOR Device
    )
{
    NTSTATUS Status;
    PKDNET_EXTENSIBILITY_EXPORTS Exports;

    __security_init_cookie();
    Status = STATUS_SUCCESS;
    KdNetExtensibilityImports = ImportTable;
    if ((KdNetExtensibilityImports == NULL) ||
        (KdNetExtensibilityImports->FunctionCount != KDNET_EXT_IMPORTS)) {

        Status = STATUS_INVALID_PARAMETER;
        goto KdInitializeLibraryEnd;
    }

    Exports = KdNetExtensibilityImports->Exports;
    if ((Exports == NULL) || (Exports->FunctionCount != KDNET_EXT_EXPORTS)) {
        Status = STATUS_INVALID_PARAMETER;
        goto KdInitializeLibraryEnd;
    }

    //
    // Return the function pointers this KDNET extensibility module exports.
    //

    Exports->KdInitializeController = KdInitializeController;
    Exports->KdShutdownController = KdShutdownController;
    Exports->KdSetHibernateRange = KdSetHibernateRange;
    Exports->KdGetRxPacket = KdGetRxPacket;
    Exports->KdReleaseRxPacket = KdReleaseRxPacket;
    Exports->KdGetTxPacket = KdGetTxPacket;
    Exports->KdSendTxPacket = KdSendTxPacket;
    Exports->KdGetPacketAddress = KdGetPacketAddress;
    Exports->KdGetPacketLength = KdGetPacketLength;
    Exports->KdGetHardwareContextSize = KdGetHardwareContextSize;

    //
    // Return the hardware context size required to support this device.
    //

    Status = ContosoInitializeLibrary(LoaderOptions, Device);

KdInitializeLibraryEnd:
    return Status;
}

このルーチンは、KDNET とこの KDNET 拡張モジュールの間でインポートおよびエクスポート ルーチンを渡すために呼び出されます。 このルーチンは、インポート テーブルとエクスポート テーブルの両方のバージョンが予期され、サポートされていることを検証し、サポートされていない場合は失敗する必要があります。 インポート テーブルのコピーを独自のグローバル メモリに作成する必要があります。 エクスポートするルーチンは、インポート テーブルの Exports フィールドが指す構造に書き込む必要があります。 また、このルーチンに渡されるデバッグ デバイス記述子ポインタの一部であるメモリ構造体の長さフィールドを、ハードウェア デバイスをサポートするために必要なメモリのバイト数で設定する必要があります。

インポート エクスポートの数を検証する

このコードでは、Imports FunctionCount が OS で使用可能なもの (たとえば、 (KdNetExtensibilityImports->FunctionCount != KDNET_EXT_IMPORTS) ) と一致することを確認し、カウントが一致しない場合は STATUS_INVALID_PARAMETER を返す必要があります。

カウントを確認すると、実行中の Windows OS KDNET バージョン (ブート マネージャー、OS ローダー、ハイパーバイザー、Secure kernel/NT OS、KDNET ライブラリへのリンクなど) と、現在の KDNET 拡張機能モジュールのビルドに使用される WDK バージョンとの間の互換性が確保されます。 WDK と OS のバージョンを同期する必要があります。それ以外の場合、インポート/エクスポート カウンター値が変更された場合、上記のチェックは失敗します。 たとえば、KDNET 機能拡張インターフェイスが新しい機能関数を追加した場合、カウントは一致しなくなります。 それらが確実に一致するようにするには、KDNET バージョンをホストしている OS と一致する WDK リリースを常に使用してください。

必要なメモリをカスタマイズする

デバイスには、デバッガー用に選択されたハードウェアが設定されることに注意してください。 このルーチンでは、必要に応じて、デバイスに基づいて必要なメモリの量をカスタマイズする必要があります。 たとえば、1Gig ハードウェアと 10Gig ハードウェアの両方をサポートする拡張モジュールでは、10Gig デバイスに要求するメモリ サイズを増やすことができます。 デバッグ デバイス記述子の DeviceID フィールドを調べることで、どのデバイスが使用されているかを判断できます。

KdInitializeLibrary は唯一のエクスポートです

このルーチンは、winload によって呼び出され、KdInitSystem 呼び出し中に KDNET によって呼び出されることに注意してください。 これは KDNET 拡張モジュールによってエクスポートされる唯一のルーチンであることに注意してください。 これは、.def ファイルに配置される唯一のルーチンです。 KDNET 拡張モジュールには、明示的なエクスポート (このルーチン) が 1 つだけあり、インポートはありません。

KdSetHibernateRange

VOID

KdSetHibernateRange (

    VOID

    )

/*++
Routine Description:

    This routine is called to mark the code in the KDNET extensiblity module
    so that it can be properly handled during hibernate and resume from
    hibernate.

Arguments:
    None.

Return Value:
    None.
--*/

このルーチンは、KDNET 拡張モジュールで使用されるコードをシステムに適切に登録できるように、休止前にシステムによって呼び出されます。 これにより、システムは休止中にそのメモリを適切に管理し、休止状態から再開できます。 (メモリは、再開中に非常に早く呼び出されるため、遅延保存され、早期に読み込まれます)。

KdInitializeController

NTSTATUS

KdInitializeController(

    __in PVOID Adapter

    )

/*++
Routine Description:

    This function initializes the Network controller.  The controller is setup
    to send and recieve packets at the fastest rate supported by the hardware
    link.  Packet send and receive will be functional on successful exit of
    this routine.  The controller will be initialized with Interrupts masked
    since all debug devices must operate without interrupt support.

Arguments:

    Adapter - Supplies a pointer to the debug adapter object.

Return Value:
    STATUS_SUCCESS on successful initialization.  Appropriate failure code if
    initialization fails.
--*/

このルーチンは、ハードウェアを初期化するために呼び出されます。 これは、システムが初期化するとき、および KdShutdownController を呼び出した低電力状態からシステムが復帰するたびに呼び出されます。 このルーチンは、ハードウェアが完全に初期化を完了し、返される前にパケットを送信する準備ができていることを確認する必要があります。 このルーチンは、PHY が起動し、リンクが確立されるのを待つ必要があります。 ケーブルが接続されていない場合、このルーチンは無期限にストールしないことに注意してください。 このルーチンは、KDNET とこの拡張モジュールの間で共有される KDNET 共有データ構造のリンク速度と二重を設定します。 また、ハードウェアで使用される MAC アドレスを、KDNET 共有データ構造の TargetMacAddress が指す場所に書き込みます。

KdShutdownController

VOID

KdShutdownController (

    __in PVOID Adapter

    )

/*++
Routine Description:

    This function shuts down the Network controller.  No further packets can
    be sent or received until the controller is reinitialized.

Arguments:

    Adapter - Supplies a pointer to the debug adapter object.

Return Value:

    None.
--*/

このルーチンは、保留中のすべての送信パケットが実際にネットワーク上で送信されるまで待機することが重要です。 このルーチンは、すべての送信パケットが メイン メモリから DMA に接続され、ネットワーク上に出るまで待機してから、ハードウェア上の送信をシャットダウンする必要があります。 保留中のすべての送信パケットが送信されると、このルーチンはハードウェアを完全にシャットダウンする必要があります。 このルーチンは、システムがシャットダウンしたときに呼び出されます。また、システムが電源を入れてデバッグ トランスポートを低電力状態に管理することを決定した場合にも呼び出されます。 これは、システムがシャットダウンされている場合に加えて、システムがスタンバイ、休止状態、スリープ、およびコネクト スタンバイになったときに呼び出すことができます。

KdGetHardwareContextSize

ULONG

KdGetHardwareContextSize (

    __in PDEBUG_DEVICE_DESCRIPTOR Device

    )
 

/*++
Routine Description:

    This function returns the required size of the hardware context in bytes.

Arguments:

    Device - Supplies a pointer to the debug device descriptor.

Return Value:

    None.

--*/

このルーチンは、ハードウェアをサポートするために必要なすべてのメモリに必要なバイト数を返す必要があります。 これには、コンテキスト構造、受信と送信のすべてのパケット バッファー、ハードウェア パケット記述子およびその他の構造が含まれます。 必要なすべてのメモリのサイズをここで報告する必要があります。 ハードウェアがパケット、パケット記述子、またはその他の構造に対して持つ可能性があるアラインメント制限に必要な追加メモリを含めます。

このルーチンは、デバッグ デバイス記述子のメモリ長フィールドを設定するときに、KdInitializeLibrary ルーチンによって呼び出される必要があることに注意してください。

KdGetRxPacket

NTSTATUS

KdGetRxPacket (

    __in PVOID Adapter,

    __out PULONG Handle,

    __out PVOID *Packet,

    __out PULONG Length

)

/*++

Routine Description:

    This function returns the next available received packet to the caller.

Arguments:

    Adapter - Supplies a pointer to the debug adapter object.

    Handle - Supplies a pointer to the handle for this packet.  This handle
        will be used to release the resources associated with this packet back
        to the hardware.

    Packet - Supplies a pointer that will be written with the address of the
        start of the packet.

    Length - Supplies a pointer that will be written with the length of the
        received packet.

Return Value:

    STATUS_SUCCESS when a packet has been received.
    STATUS_IO_TIMEOUT otherwise.

--*/

このルーチンは、受信されたが、まだ処理されていない、次に使用可能なパケットを取得します。 そのパケットのハンドルを返します。 このハンドルを使用して、KdGetPacketAddress を呼び出してパケットのアドレスを取得し、KdGetPacketLength を呼び出して長さを取得します。 パケットとハンドルはメイン KdReleaseRxPacket を呼び出してパケットが解放されるまで、再び使用可能で有効である必要があります。 また、このルーチンは、パケット アドレスと長さを呼び出し元に直接返します。

現在使用できるパケットがない場合、このルーチンはSTATUS_IO_TIMEOUTを使用して直ちに戻る必要があります。 このルーチンは、パケットの受信を待つ必要はありません。 ハンドルの上位 2 ビットが予約されていることに注意してください。 TRANSMIT_HANDLEとTRANSMIT_ASYNCの両方が明確である必要があります。

KdReleaseRxPacket

VOID

KdReleaseRxPacket (

    __in PVOID Adapter,

    ULONG Handle

)

/*++

Routine Description:

    This function reclaims the hardware resources used for the packet
    associated with the passed Handle.  It reprograms the hardware to use those
    resources to receive another packet.

Arguments:

    Adapter - Supplies a pointer to the debug adapter object.
    Handle - Supplies the handle of the packet whose resources should be
        reclaimed to receive another packet.

Return Value:

    None.

--*/

このルーチンは、パケット ハンドルに関連付けられているリソースをハードウェアに解放して、別のパケットを受信するために使用できるようにします。 KdGetRxPacket への呼び出しが成功するたびに、KdGetRxPacket から返されたハンドルを持つ KdReleaseRxPacket への別の呼び出しが続きます。 KdGetRxPacket が成功した直後に KdReleaseRxPacket が呼び出されることは保証されません。 別の KdGetRxPacket 呼び出しが最初に行われる可能性があります。 ただし、KdGetRxPacket 呼び出しが成功するたびに、KdReleaseRxPacket 呼び出しでリソースが解放されます。

このルーチンは、解放されたリソースを使用して別のパケットを受信できるように、ハードウェアを適切にプログラムする必要があります。

KdGetTxPacket

NTSTATUS

KdGetTxPacket (

    __in PVOID Adapter,

    __out PULONG Handle

)

/*++

Routine Description:

    This function acquires the hardware resources needed to send a packet and
    returns a handle to those resources.

Arguments:

    Adapter - Supplies a pointer to the debug adapter object.

    Handle - Supplies a pointer to the handle for the packet for which hardware
        resources have been reserved.

Return Value:

    STATUS_SUCCESS when hardware resources have been successfully reserved.
    STATUS_IO_TIMEOUT if the hardware resources could not be reserved.
    STATUS_INVALID_PARAMETER if an invalid Handle pointer or Adapter is passed.

--*/

このルーチンは、次に使用可能な送信リソースを取得し、それらにハンドルを返します。 このハンドルは、KdGetPacketAddress と KdGetPacketLength を呼び出すために使用されます。 KdGetPacketAddress によって返されるパケット アドレスは、パケットの内容を直接書き込むのに使用されます。 パケット アドレスはパケットの先頭である必要があり、長さはパケットに書き込むことができる最大バイト数である必要があります。 使用可能なハードウェア リソースがない場合、すべてが取得され、まだ送信されていないため、このルーチンはすぐにSTATUS_IO_TIMEOUTを返す必要があることに注意してください。

TRANSMIT_HANDLEは、返されるハンドルで設定する必要があります。 ハンドルの上位 2 ビットは、TRANSMIT_ASYNCフラグと TRANSMIT_HANDLE フラグ用に予約されていることに注意してください。

KdSendTxPacket

NTSTATUS

KdSendTxPacket (

    __in PVOID Adapter,

    ULONG Handle,

    ULONG Length

)

/*++

Routine Description:

    This function sends the packet associated with the passed Handle out to the
    network.  It does not return until the packet has been sent.

Arguments:

    Adapter - Supplies a pointer to the debug adapter object.

    Handle - Supplies the handle of the packet to send.

    Length - Supplies the length of the packet to send.

Return Value:

    STATUS_SUCCESS when a packet has been successfully sent.

    STATUS_IO_TIMEOUT if the packet could not be sent within 100ms.

    STATUS_INVALID_PARAMETER if an invalid Handle or Adapter is passed.

--*/

このルーチンは、渡されたハンドルに関連付けられているパケットをネットワークに送信します。 ハンドルには、送信が非同期転送であるかどうかを示す追加のビットが設定されている場合があることに注意してください。 TRANSMIT_ASYNC フラグがハンドルに設定されている場合、このルーチンは、パケットを送信するようにハードウェアをプログラムし、ハードウェアが送信を完了するのを待たずに直ちに戻る必要があります。 これは、送信中に発生したエラーが失われることを意味します。 これは問題ありません。パケットはネットワーク上で失われる可能性があります。 TRANSMIT_ASYNC フラグがハンドルに設定されていない場合、このルーチンは、パケットがネットワーク上で送信されるまで待機する必要があり、送信中に発生したエラーがあれば返す必要があります。 ダンプ ファイルがデバッガー ホストに送信されている場合、または Windows ネットワーク パケットが KDNIC から KDNET 経由で送信されている場合は、TRANSMIT_ASYNCが設定されることに注意してください。 他のすべてのデバッガー パケットが送信されている場合、TRANSMIT_ASYNCはクリアされます。

TRANSMIT_ASYNC設定 TRUE でパケットのセットが送信され、その後にTRANSMIT_ASYNCが設定されていないパケットが送信された場合、ハードウェアは、フラグが設定されていないパケットが実際に送信されるまで待機する必要があります。つまり、以前の非同期パケットも送信されるのを待機する必要があります。

KdGetPacketAddress

PVOID

KdGetPacketAddress (

    __in PVOID Adapter,

    ULONG Handle

)

/*++

Routine Description:

    This function returns a pointer to the first byte of a packet associated
    with the passed handle.

Arguments:

    Adapter - Supplies a pointer to the debug adapter object.

    Handle - Supplies a handle to the packet for which to return the
        starting address.

Return Value:

    Pointer to the first byte of the packet.

--*/

このルーチンは、渡されたハンドルに関連付けられているパケットの最初のバイトへのポインターを返します。 ハンドルには送信パケットにTRANSMIT_HANDLE ビットが設定され、受信パケットのTRANSMIT_HANDLE ビットがクリアされることに注意してください。 返されるポインターは、プロセッサによって読み取りまたは書き込み可能な Windows 仮想アドレスである必要があります。 このアドレスは、デバッグ デバイス記述子のメモリ構造で渡される KDNET 拡張モジュール用に予約されたメモリ ブロック内に含まれている必要があります。 (KDNET 拡張モジュールは、そのメモリにアクセスするときに KdInitializeLibrary で要求されたメモリ サイズを超えて使用しないでください。ブロックの末尾にある追加のメモリは KDNET で使用するために予約されており、KDNET 拡張モジュールで操作することはできません)。

KdGetPacketLength

ULONG

KdGetPacketLength (

    __in PVOID Adapter,

    ULONG Handle

)

/*++

Routine Description:

    This function returns the length of the packet associated with the passed
    handle.

Arguments:

    Adapter - Supplies a pointer to the debug adapter object.

    Handle - Supplies a handle to the packet for which to return the
        length.

Return Value:

    The length of the packet.

--*/

このルーチンは、渡されたハンドルに関連付けられているパケットの長さをバイト単位で返します。 ハンドルには送信パケットにTRANSMIT_HANDLE ビットが設定され、受信パケットのTRANSMIT_HANDLE ビットがクリアされることに注意してください。 送信パケットの場合、この長さはパケットに書き込むことができる最大バイト数である必要があります。 受信パケットの場合、この長さは受信パケットの実際のバイト数である必要があります。

KDNET 機能拡張モジュールのデバッグ

KDNET 拡張モジュールをデバッグするには、ターゲット コンピューターで管理者特権のコマンド プロンプトから次の bcdedit コマンドを実行する必要があります。

まず、最も重要なのは、次の 2 つのコマンドを実行して、デバッガーに中断して通常の起動を妨げる特別な障害パスをダウンさせずに、Winload で繰り返し起動エラーが発生することを確認する必要があります。 これらのコマンドを実行すると、新しいビットでマシンを繰り返し再起動し、それらの新しいビットを問題なくデバッグできます。

Bcdedit -set {current} BootStatusPolicy IgnoreAllFailures

Bcdedit -set {current} RecoveryEnabled No

ターゲット コンピューター上の com1 でシリアル デバッグを使用して拡張モジュールをデバッグする場合は、次の操作を行います。

bcdedit -dbgsettings serial debugport:1 baudrate:115200

これにより、com1 の既定のデバッグ トランスポートが 115200 ボーでシリアルに設定されます。 これらの設定は、ブート デバッグにも使用されます。

bcdedit -debug on

これにより、カーネルのデバッグが有効になります。

bcdedit -bootdebug on

これにより、KDNET 拡張モジュールを含む初期カーネル初期化にデバッグするために使用する、winload.exeでのブート デバッグが可能になります。

bcdedit -set kerneldebugtype net

これにより、既定のデバッグ トランスポート設定に関係なく、カーネル デバッグの種類が強制的に net になります。 これにより、winload.exeはカーネル デバッグ トランスポートとしてkdnet.dllを読み込みます。

bcdedit -set kernelbusparams b.d.f

ここで、b はバス番号、d はデバイス番号、f は KDNET 拡張モジュールを作成するハードウェアの関数番号 (すべて 10 進数) です。 これらの番号は、ハードウェアが配置されている PCI スロットによって異なります。 これらは、Windows デバイス マネージャーのネットワーク デバイスのデバイス プロパティ ページで場所の文字列を見つけることで確認できます。 Windows デバイス マネージャーを開き、ネットワーク デバイスをダブルクリックし、デバイスを見つけてダブルクリックします。開いたウィンドウには、PCI バス上のハードウェアのバス、デバイス、機能を含む [場所] フィールドが表示されます。 その情報がマスクされる原因となるバス ドライバーがある場合は、ドライバーから場所を特定する必要があります。その他の方法もあります。

これにより、カーネル バスパラムが b.d.f に強制されます。これにより、その特定のデバイスがカーネル デバッグ デバイスとして選択されます。

bcdedit -set kernelhostip N

ここでNは、下記式により求められる。 ホスト デバッガー マシンの IPv4 アドレスが w.x.y.z の場合、N = (w0x01000000) + (x0x00010000) + (y0x00000100) + (z0x00000001)。 N は、16 進数ではなく、10 進数でコマンド ラインで指定する必要があります。 実際には、IPv4 アドレスの各バイトを取得し、それを (16 進数で) 連結して 16 進数で 32 ビット番号を作成し、それを 10 進数に変換します。

bcdedit -set kernelport N

N が 50000 または内部ネットワークでブロックされないその他のポートです。

これにより、KDNET はネットワーク デバッグ ポートとしてポート N を使用するように強制されます。

bcdedit -set kernelkey 1.2.3.4

これにより、KDNET デバッグ キーが 1.2.3.4 に強制されます。 1.2.3.4 は、ネットワーク キーでセキュリティで保護されているか一意ではありません。 ターゲット コンピューターを常にセキュリティで保護するには、ホスト コンピューターとターゲット コンピューターの間を移動するパケットを暗号化する必要があります。 自動生成された暗号化キーを使用することを強くお勧めします。 詳細については KDNET ネットワーク カーネル デバッグの自動設定 を参照してください。

bcdedit -set kerneldhcp on

これにより、KDNET カーネルの dhcp 設定が強制的にオンになります。

ホスト コンピューターでシリアル デバッグ ポートとして com1 を使用していることを前提として、次のコマンド ラインを使用してデバッガー ホスト コンピューターでデバッガーを実行します。

windbg -d -k com:port=com1,baud=115200

これによりデバッガーが実行され、windbg ブート デバッガーが最初にホスト コンピューターと通信するときに中断します。

次に、次を実行してターゲット マシンを再起動します。

shutdown -r -t 0

デバッガーが windbg に分割されたら、winload 用にシンボルが読み込まれていることを確認します。 (.sympath を設定し、.reload を実行する必要がある場合があります)。 次に x winload!*deb*tra* を実行します。 一覧表示されているシンボルの 1 つは、BdDebugTransitions のようになります。

次に実行 ed winload!BdDebugTransitions 1しますが、正しいシンボル名を使用してください。

次に、 bu winload!blbdstop ブレークポイントを設定するために実行します。

次に、ヒット g して移動します。

あなたは、winloadで中断する必要があります!BlBdStop。

次に、以下のコマンドを実行します。

bu nt!KdInitSystem

bu kdnet!KdInitialize

bu kdstub!KdInitializeLibrary

KDNET 機能拡張モジュールでブレークポイントを設定するときに kdstub を使用する可能性が最も高い点に注意してください。これが機能しない場合は、

bu kd_YY_XXXX!KdInitializeLibrary

ここで、YY は PCI クラスで、XXXX は PCI VID です。 (つまり、KDNET 拡張モジュールの名前を使用します)。

通常、デバッガーでは、拡張モジュールの実際の名前を使用する代わりに kdstub を使用する必要があります。

次に、ブレークポイントを一覧表示するために実行 bl します。 ブレークポイントが配置されていることを確認します (すべてのブレークポイントの横に e が必要です)。

その後、ヒット g. あなたはntをヒットする必要があります!KdInitSystem ブレークポイント。

もう一度ヒット g し、あなたはkdnetを打つ必要があります!KdInitialize

もう一度ヒット g すると、KdInitializeLibrary で独自のモジュールのブレークポイントにヒットします。

その後、InitializeController ルーチンと他のすべてのルーチンにブレークポイントを設定し、コードをステップ実行できます。

KdInitializeLibrary をステップ実行したら、g キーを押します。InitializeController ルーチンにブレークポイントを設定すると、次にヒットします。

その後、完了したら、KdGetTxPacket、KdSendTxPacket、KdGetRxPacket、KdReleaseRxPacket ルーチンにブレークポイントが設定されていることを確認し、もう一度 g キーを押すと、それらのルーチンは起動時に KDNET によって実行されるネットワーク初期化の一部として実行されます。

すべてのコードをステップ実行できるように、すべてのルーチンが確実に呼び出されるように、KdInitializeLibrary ルーチンまたは KdInitializeController ルーチンに一時的なコードを追加する必要がある場合があります。 (たとえば、KdShutdownController は起動時に正常に動作するときに呼び出されないため、一時的なコードから明示的に呼び出して、ステップ実行して正しいことを確認できるようにする必要があります)。

すべてのコードをステップ実行し、正しいと確信したら、ターゲットを再起動しますが、winload を設定しないでください。BdDebugTransitions フラグを true に設定します (既定値は 0 のままにします)。

次に、ホスト デバッガー コンピューターでカーネル デバッガーの別のインスタンスも実行します。

Windbg -d -k net:port=50000,key=1.2.3.4

ターゲット マシンを起動させ、ネットワーク経由でカーネル デバッガーの他のインスタンスに接続する必要があります。

次に、カーネル デバッガーでコマンドを実行し、動作することを確認してから、ターゲットの起動を続行し、後でコマンドを中断して実行できることを確認します。

Note

winload でデバッグ遷移フラグを設定すると、Windows が起動しないことが保証されます。 フラグの設定後に Windows の起動を完了しようとすると、Windows がクラッシュするかハングします。 Windows を正常に起動させる場合は、そのデバッグ遷移フラグを設定できません。 フラグを設定すると、デバッガーでステップ実行してコードをデバッグし、正しいことを確認できますが、通常の起動時にデバッグが機能することを確認できるように、最終的にはフラグを設定する必要はありません。 つまり、システムを正常に起動するときにコードをステップ実行することはできません。実際、Windows が正常に実行されている場合、ハードウェアでデバッグが有効になっている場合、KDNET 拡張機能モジュールはデバッグできません。 カーネル デバッガーでデバッグしようとすると、マシンがクラッシュします。 (カーネル デバッグ パスで実行されるコードにブレークポイントを設定することはできません。これは、無限の再入、吹き出しスタック、再起動が発生するためです)。

複数の物理機能 - 2PF

KDNETの拡張性に加えて、KDNETは、PCI構成空間をパーティション分割することで、サポートされているNICで複数の物理関数 (PF) を使用したカーネル デバッグをサポートします。 ネットワーク カード ベンダーは、この機能のサポートを有効にすることをお勧めします。 詳細については デバッガ― 2PF KDNET ミニポート ネットワーク ドライバーのサポート を参照してください。

関連項目

KDNET ネットワーク カーネル デバッグの自動設定

KDNET ネットワーク カーネル デバッグの手動設定

デバッガー2PF KDNETミニポート ネットワーク ドライバーのサポート