Share via


Développer des modules d’extensibilité du transport KDNET

Cette rubrique décrit comment le transport KDNET peut être étendu pour s’exécuter sur n’importe quel matériel via l’utilisation d’une dll de module d’extensibilité de pilote matériel distincte. Les modules d’extensibilité du transport KDNET sont développés par des fournisseurs de carte réseau pour ajouter la prise en charge du débogage du noyau à des cartes réseau spécifiques.

Vue d’ensemble de KDNET

KDNET est un transport de débogage de noyau qui permet le débogage de noyau de fenêtres sur un réseau. Initialement, il était utilisé pour prendre en charge le débogage du noyau avec des cartes réseau Ethernet. Il est conçu de sorte que la couche de prise en charge matérielle soit intégrée dans un module distinct du traitement des paquets réseau et de la couche d’interface du noyau. Cette couche de prise en charge du pilote matériel est appelée module d’extensibilité KDNET.

KDNET est le seul transport qui peut être étendu pour s’exécuter sur n’importe quel matériel via l’utilisation d’une dll de module d’extensibilité de pilote matériel distincte. L’objectif est de prendre en charge tout le débogage de Windows via les modules d’extensibilité KDNET et KDNET. Toutes les autres DLL de transport du noyau (kdcom.dll, kd1394.dll, kdusb.dll, etc.) seront finalement dépréciées et supprimées de Windows.

KDNET utilise deux types d’interfaces pour communiquer avec les modules d’extensibilité KDNET. L’une est une interface basée sur des paquets qui est utilisée pour les cartes réseau, usb et le matériel sans fil, et l’autre est une interface basée sur des octets qui est utilisée pour prendre en charge KDNET sur du matériel série.

Les modules d’extensibilité KDNET doivent respecter des exigences très strictes pour fonctionner correctement. Étant donné qu’ils sont utilisés pour le débogage du noyau, ils sont appelés et exécutés lorsque le système est en attente de l’exécution ultérieure du code. En règle générale, tous les processeurs du système sont verrouillés en rotation dans un IPI, à l’exception du processeur qui communique avec l’application de débogueur s’exécutant sur l’ordinateur hôte via le transport de débogage du noyau. Ce processeur s’exécute généralement avec des interruptions complètement désactivées et tourne essentiellement sur le matériel de transport de débogage en attendant que les commandes proviennent du débogueur.

Les modules d’extensibilité KDNET ont exactement une exportation explicite : KdInitializeLibrary. Ils n’ont pas non plus d’importations explicites. Les modules d’extensibilité KDNET reçoivent un pointeur vers une structure avec une liste des routines qu’ils sont autorisés à appeler par KDNET lorsqu’il appelle KdInitializeLibrary. Aucune autre routine ne peut être appelée. Période. Les modules extensiblity KDNET qui ont des importations sont mal conçus et ne sont pas pris en charge.

Si vous sauvegardez les importations et les exportations d’un module extensiblity KDNET à l’aide du lien /dump /exports et du lien /dump /imports, vous verrez qu’ils n’ont qu’une seule exportation (KdInitializeLibrary) et aucune importation. Les modules d’extensibilité KDNET signalent leurs exportations supplémentaires vers KDNET en remplissant des pointeurs de fonction dans une structure de fonctions d’exportation à laquelle KDNET transmet un pointeur lorsque KdInitializeLibrary est appelé. KDNET utilise ensuite les pointeurs de fonction dans cette structure pour appeler le module d’extensibilité et effectuer des transferts de données à l’aide du matériel pris en charge par le module. KDNET détermine si le module est un module basé sur des paquets ou sur des octets en examinant les fonctions spécifiques que le module remplit dans la table de fonctions d’exportation de la structure. Certaines de ces fonctions sont destinées à prendre en charge le matériel basé sur les paquets, tandis que d’autres sont destinées au matériel série. Certaines des fonctions de la table sont utilisées par le matériel série et basé sur les paquets (KdInitializeController, KdShutdownController, KdGetHardwareContextSize).

Les modules d’extensibilité KDNET doivent être écrits en tant que code à thread unique. Ils ne doivent pas effectuer de synchronisation. Tous les transports de débogage du noyau dépendent du noyau Windows pour effectuer la synchronisation appropriée lorsque le débogueur est entré. Le noyau a un verrou de débogueur qu’il prend lorsqu’il entre dans le débogueur du noyau, et il verrouille également les autres processeurs du système dans un IPI lorsque le débogueur est entré. Ces processeurs seront libérés uniquement lorsque le débogueur du noyau en cours d’exécution sur l’hôte indique à l’ordinateur cible de permettre la poursuite de l’exécution. Étant donné que le noyau effectue cette synchronisation, les modules d’extensibilité KDNET ne doivent absolument pas utiliser de verrouillages tournants, de mutex, de portes ou d’autres mécanismes de synchronisation Windows dans leur code. Ils doivent être écrits pour programmer directement leur matériel respectif pour envoyer et recevoir des paquets et ou des octets.

Le code du module d’extensibilité KDNET doit être aussi simple que possible. Cela permet de s’assurer qu’il est aussi exempt de bogues que possible, car le débogage du code du module d’extensibilité KDNET en direct sur une machine n’est actuellement pas possible sans l’utilisation d’un débogueur matériel. Vous ne pouvez pas utiliser le débogueur de noyau pour déboguer le code de transport de débogage du noyau. Si vous tentez de le faire, l’ordinateur redémarre en raison d’une pile de noyau soufflée (qui se termine généralement par une double erreur et un redémarrage), ou d’un blocage, ou entraîne la réentration du transport, ce qui, dans la plupart des cas, entraîne le mauvais fonctionnement du transport.

Votre module de transport de débogage du noyau doit suivre l’une des deux conventions d’affectation de noms pour les modues d’extensibilité KDNET. Si votre module est destiné à prendre en charge le matériel pci, il doit être nommé kd_YY_XXXX.dll où XXXX est l’ID de fournisseur PCI de votre matériel en hexadécimal et YY la classe PCI pour votre matériel. Plusieurs modules d’extensibilité KDNET fournis dans windows prennent en charge le matériel PCI. Par exemple, la kd_02_8086.dll d’Intel, la kd_02_14e4.dll de Broadcom et la kd_02_10ec.dll de Realtek. Vous pouvez rechercher les ID de fournisseur PCI inscrits dans https://www.pcisig.com/membership/member-companies Tous les modules d’extensibilité KDNET basés sur PCI utilisent le VID du fournisseur du matériel qu’ils prennent en charge en hexadécimal comme les 4 derniers caractères dans le nom de leur module. Le code de classe de la plupart des modules in box est 02, car il s’agit d’appareils de classe réseau et ont donc une classe PCI de 0x02 dans leur espace de configuration PCI. Winload.exe crée le nom des modules d’extensibilité KDNET basés sur PCI en lisant la classe d’appareil PCI et la VID PCI de l’appareil de débogage sélectionné à partir de son espace de configuration PCI, et tente de charger un module avec ces identificateurs dans le nom. Si votre appareil a un code de classe PCI qui n’est pas la classe 0x02 réseau, vous devez utiliser le code de classe PCI correct en hexadécimal pour votre appareil, dans le nom de votre module d’extensibilité KDNET. Sinon, votre module ne sera pas chargé correctement par winload. Dans _02_ chacun de ces noms est le code de classe PCI pour les appareils de classe réseau en hexadécimal. Ce code est également trouvé et lu à partir de l’espace de configuration PCI de l’appareil de débogage.

Si vous avez un appareil qui a une entrée de table DBG2 et n’est pas un appareil PCI, la convention d’affectation de noms de votre module est différente. La convention d’affectation de noms pour les appareils de débogage de table DBG2 est kd_XXXX_YYYY.dll où XXXX est la table hex DBG2 PortType et YYYY est le portSubtype de table HEx DBG2 de l’entrée de table DBG2. Kd_8003_5143.dll est une DLL de boîte de réception permettant de prendre en charge un portType net (0x8003) avec un sous-type de 0x5143. Dans ce cas, 5143 est le vid PCI Qualcomm, car il s’agit de la prise en charge de KDNET sur les contrôleurs Qualcomm USB, et pour les entrées de table Net DBG2, portSubtype est défini comme étant le VID PCI pour le fournisseur du matériel. Notez que vous pouvez prendre en charge les périphériques série, USB et d’autres appareils de table DBG2 à l’aide de cette convention d’affectation de noms. Voici les valeurs PortType actuellement prises en charge en hexadécimal : 8000 pour les appareils série, 8001 pour les appareils 1394, 8002 pour les périphériques USB, 8003 pour les appareils NET. Notez que les sous-types pour les périphériques série et USB doivent être réservés auprès de Microsoft. Microsoft tient à jour une liste des sous-types série et USB alloués. Envoyez un e-mail à kdnet@microsoft.com pour réserver un sous-type série ou USB, si les types pris en charge existants ne fonctionnent pas avec votre matériel.

Importations d’extensibilité KDNET

Voici la liste des routines que vous pouvez appeler à partir d’un module d’extensibilité KDNET. Notez que toutes ces routines sont passées à la routine KdInitializeLibrary, et que l’en-tête kdnetextensibility.h remappera les appels normaux à ces routines pour passer par la table d’importation. Votre code doit les appeler via la table d’importation, afin que votre module n’ait aucune importation. Vous ne pouvez pas appeler d’autres routines exportées par le noyau, le HAL ou tout autre module de noyau. Vous pouvez uniquement appeler ces routines. Cet ensemble de routines s’est avéré suffisant pour développer tous les modules d’extensibilité KDNET dans la boîte, et devrait suffire pour les scénarios normaux. Si vous avez besoin de routines supplémentaires qui sont exportées par le noyau, mais ne figurent pas dans cette liste, envoyez un e-mail pour kdnet@microsoft.com expliquer votre scénario, ainsi que les routines supplémentaires dont vous avez besoin et pourquoi. Notez que cette liste sera ajoutée uniquement à, le cas échéant, lors des principaux cycles de publication de Windows. Notez que la plupart de ces routines correspondent directement aux API du noyau Windows qui sont prises en charge par le noyau ou hal. Une ou deux sont des routines KDNET personnalisées uniquement.

Il est essentiel que vous incluiez correctement kdnetextensibility.h dans vos en-têtes afin que le remappage correct des routines via la table d’importation puisse se produire. Si ce n’est pas le cas, votre module aura des importations et ne sera pas pris en charge.

Les routines suivantes doivent être utilisées pour lire et écrire dans la mémoire mappée de l’appareil. Ceux-ci ont la même convention d’appel et sont mappés à leurs routines de noyau correspondantes : READ_REGISTER_UCHAR, READ_REGISTER_USHORT, READ_REGISTER_ULONG, WRITE_REGISTER_UCHAR, WRITE_REGISTER_USHORT, WRITE_REGISTER_ULONG et sur les plateformes 64 bits uniquement READ_REGISTER_ULONG64 et WRITE_REGISTER_ULONG64. Tous les accès à la mémoire de l’appareil doivent être effectués via ces routines, car elles garantissent que les lectures et les écritures ne sont pas réorganisées par le processeur. Notez que les documents msdn.microsoft.com Windows CE routines Compact 2013 qui correspondent dans la convention d’appel à ces routines. Malheureusement, il semble que les routines NT ne soient pas documentées, mais la convention d’appel est la même.

Les routines suivantes doivent être utilisées pour la lecture et l’écriture dans les ports d’E/S de l’appareil. Ceux-ci ont la même convention d’appel et sont mappés à leurs routines de noyau correspondantes : READ_PORT_UCHAR, READ_PORT_USHORT, READ_PORT_ULONG, WRITE_PORT_UCHAR, WRITE_PORT_USHORT et WRITE_PORT_ULONG. Tous les ports d’E/S d’appareil doivent être accessibles via ces routines. Notez que les documents msdn.microsoft.com Windows CE routines Compact 2013 qui correspondent dans la convention d’appel à ces routines.

Les routines supplémentaires suivantes peuvent être appelées et doivent être appelées normalement avec les paramètres spécifiés. Notez que cela, tout en incluant correctement l’en-tête kdnetextensibility.h, remapper les appels de fonction via la table d’importation d’extensibilité KDNET, ce qui entraîne l’absence d’importation explicite dans votre module comme requis pour les modules d’extensibilité 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

    );

Notez que la fonction PoSetHiberRange doit être appelée uniquement à partir de la routine KdSetHibernateRange. En outre, la plupart des modules d’extensibilité KDNET ne doivent pas avoir besoin d’appeler KeBugCheckEx, KdMapPhysicalMemory64 et KdUnmapVirtualAddress. D’autre part, la plupart des modules d’extensibilité KDNET devront appeler KdGetPhysicalAddress pour obtenir les adresses mémoire physiques requises pour programmer les moteurs DMA des appareils, et beaucoup devront appeler KeStallExecutionProcessor, KdGetPciDataByOffset et KdSetPciDataByOffset. Les deux dernières routines permettent d’accéder à l’espace de configuration PCI de l’appareil.

Exportations d’extensibilité KDNET

Voici une brève description de chacune des routines d’extensibilité KDNET. Vous devez implémenter toutes les routines requises pour un module d’extensibilité KDNET basé sur des paquets ou un module d’extensibilité KDNET basé sur la série. Voici les exportations de module extensiblity KDNET de paquets.

KdInitializeLibrary

NTSTATUS

KdInitializeLibrary (

    __in PKDNET_EXTENSIBILITY_IMPORTS ImportTable,

    __in_opt PCHAR LoaderOptions,

    __inout PDEBUG_DEVICE_DESCRIPTOR Device

    )

/*++

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 kenrel 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.
--*/

Cette routine est appelée pour passer les routines d’importation et d’exportation entre KDNET et ce module d’extensibilité KDNET. Cette routine doit vérifier que la version des tables d’importation et d’exportation est attendue et prise en charge, et qu’elle échoue si ce n’est pas le cas. Il doit effectuer une copie de la table d’importation dans sa propre mémoire globale. Il doit écrire les routines qu’il exporte dans la structure pointée par le champ Exportations de la table d’importation. Il doit également définir le champ Longueur de la structure mémoire qui fait partie du pointeur de descripteur de périphérique de débogage passé à cette routine, avec le nombre d’octets de mémoire dont elle a besoin pour prendre en charge le périphérique matériel.

Notez que l’appareil sera rempli avec le matériel sélectionné pour le débogueur. Cette routine doit personnaliser la quantité de mémoire requise en fonction de l’appareil, si nécessaire. Par exemple, les modules d’extensibilité qui prennent en charge le matériel 1Gig et 10Gig peuvent augmenter la taille de mémoire qu’ils demandent pour les appareils 10Gig. Ils peuvent déterminer l’appareil utilisé en examinant le champ DeviceID du descripteur d’appareil de débogage.

Notez que cette routine sera appelée à la fois par winload et par KDNET pendant l’appel KdInitSystem. Notez qu’il s’agit de la SEULE routine exportée par les modules d’extensibilité KDNET. Il s’agit de la seule routine placée dans un fichier .def. Les modules d’extensibilité KDNET ont exactement une exportation explicite (cette routine) et aucune importation.

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.
--*/

Cette routine est appelée par le système avant la mise en veille prolongée afin qu’il puisse inscrire correctement le code utilisé par le module d’extensibilité KDNET auprès du système. Cela permet au système de gérer correctement cette mémoire pendant la mise en veille prolongée et la reprise de la mise en veille prolongée. (La mémoire est enregistrée tardivement et chargée tôt, car elle sera appelée très tôt lors de la reprise.)

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.
--*/

Cette routine est appelée pour initialiser le matériel. Il est appelé lorsque le système s’initialise et chaque fois que le système sort d’un état de faible puissance pour lequel il a appelé KdShutdownController. Cette routine DOIT s’assurer que le matériel a entièrement terminé l’initialisation et qu’il est prêt à envoyer des paquets AVANT de retourner. Cette routine doit attendre que le PHY arrive, et que le lien soit établi. Notez que si aucun câble n’est connecté, cette routine ne doit pas se bloquer indéfiniment. Cette routine définit la vitesse de liaison et le duplex dans la structure de données partagées KDNET partagée entre KDNET et ce module d’extensibilité. Il écrit également l’adresse MAC utilisée par le matériel, dans l’emplacement pointé par TargetMacAddress dans la structure de données partagée KDNET.

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.
--*/

Il est ESSENTIEL que cette routine ATTENDe jusqu’à ce que tous les paquets de transmission qui sont encore en attente soient effectivement envoyés sur le réseau. Cette routine doit attendre que tous les paquets de transmission aient été DMA’ed à partir de main mémoire et soient sur le réseau AVANT d’arrêter la transmission sur le matériel. Une fois que tous les paquets de transmission en attente ont été envoyés, cette routine doit arrêter complètement le matériel. Cette routine est appelée lorsque le système s’arrête, ainsi que lorsque le système décide de l’alimentation gérer le transport de débogage vers un état de faible consommation. Cela peut être appelé lorsque le système passe en veille, en veille prolongée, en veille et en veille connectée, en plus de l’arrêt du système.

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.

--*/

Cette routine doit retourner le nombre d’octets requis pour toute la mémoire nécessaire à la prise en charge de votre matériel. Cela inclut votre structure de contexte et toutes les mémoires tampons de paquets pour la réception et la transmission, ainsi que les descripteurs de paquets matériels et autres structures. La taille de toute la mémoire dont vous avez besoin doit être signalée ici. Y compris toute mémoire supplémentaire requise pour les limitations d’alignement que votre matériel peut avoir pour les paquets, les descripteurs de paquets ou d’autres structures.

Notez que cette routine doit être appelée par votre routine KdInitializeLibrary lorsqu’elle définit le champ Longueur de la mémoire dans le descripteur d’appareil de débogage.

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.

--*/

Cette routine obtient le paquet disponible suivant qui a été reçu, mais qui n’a pas encore été traité. Elle retourne un handle pour ce paquet. Le handle sera utilisé pour obtenir l’adresse du paquet en appelant KdGetPacketAddress, ainsi que la longueur en appelant KdGetPacketLength. Le paquet et le handle doivent rester disponibles et valides jusqu’à ce que le paquet soit libéré en appelant KdReleaseRxPacket. Cette routine retourne également directement l’adresse et la longueur du paquet à l’appelant.

Si aucun paquet n’est disponible actuellement, cette routine DOIT retourner immédiatement avec STATUS_IO_TIMEOUT. Cette routine NE DOIT PAS attendre la réception d’un paquet. Notez que les 2 premiers bits de Handle sont réservés. TRANSMIT_HANDLE et TRANSMIT_ASYNC doivent être clairs.

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.

--*/

Cette routine libère les ressources associées au handle de paquet sur le matériel afin qu’elles puissent être utilisées pour recevoir un autre paquet. Chaque appel à KdGetRxPacket réussi sera suivi d’un autre appel à KdReleaseRxPacket avec le handle retourné par KdGetRxPacket. Notez qu’il n’est PAS garanti que KdReleaseRxPacket sera appelé immédiatement après la réussite de KdGetRxPacket. Il est possible qu’un autre appel KdGetRxPacket soit effectué en premier. Toutefois, chaque appel KdGetRxPacket réussi aura ses ressources publiées avec un appel KdReleaseRxPacket.

Cette routine doit programmer correctement le matériel afin que les ressources libérées puissent être utilisées pour recevoir un autre paquet.

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.

--*/

Cette routine obtient les ressources de transmission disponibles suivantes et leur retourne un handle. Ce handle sera utilisé pour appeler KdGetPacketAddress et KdGetPacketLength. L’adresse de paquet retournée par KdGetPacketAddress sera utilisée pour écrire directement le contenu du paquet. L’adresse du paquet doit être le début du paquet, et la longueur doit être le nombre maximal d’octets pouvant être écrits dans le paquet. Notez que s’il n’y a pas de ressources matérielles disponibles, car elles ont toutes été acquises et n’ont pas encore été transmises, cette routine doit immédiatement retourner STATUS_IO_TIMEOUT.

TRANSMIT_HANDLE doit être défini dans le handle retourné. Notez que les deux premiers bits de Handle sont réservés aux indicateurs TRANSMIT_ASYNC et 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.

--*/

Cette routine envoie le paquet associé au handle passé sur le réseau. Notez que Handle peut avoir un bit supplémentaire défini, qui indique si l’envoi est un transfert asynchrone ou non. Si l’indicateur TRANSMIT_ASYNC est défini dans le handle, cette routine doit programmer le matériel pour envoyer le paquet, puis doit immédiatement retourner sans attendre que le matériel termine l’envoi. Cela signifie que toutes les erreurs qui se produisent pendant la transmission seront perdues. C’est ok, et par conception, car les paquets peuvent être perdus sur le réseau de toute façon. Si l’indicateur TRANSMIT_ASYNC n’est pas défini dans le handle, cette routine DOIT attendre que le paquet ait été envoyé sur le réseau et doit retourner toute erreur qui se produit lors de la transmission, le cas échéant. Notez que lorsque des fichiers de vidage sont envoyés à l’hôte du débogueur ou lorsque des paquets réseau Windows sont envoyés à partir de la carte KDNIC via KDNET, TRANSMIT_ASYNC est défini. Lorsque tous les autres paquets du débogueur sont envoyés TRANSMIT_ASYNC est clair.

Si un ensemble de paquets est envoyé avec TRANSMIT_ASYNC défini sur TRUE, suivi d’un paquet qui n’a pas TRANSMIT_ASYNC défini, le matériel doit attendre que le paquet sans l’indicateur défini soit effectivement envoyé, même si cela signifie qu’il doit également attendre que les paquets asynchrones précédents soient également envoyés.

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.

--*/

Cette routine retourne un pointeur vers le premier octet du paquet associé au handle passé. Notez que le handle a le bit TRANSMIT_HANDLE défini pour les paquets de transmission, et le TRANSMIT_HANDLE bit clear pour les paquets de réception. Le pointeur retourné doit être une adresse virtuelle Windows qui peut être lue ou écrite par le processeur. Cette adresse doit se trouver dans le bloc de mémoire réservé au module d’extensibilité KDNET qui est passé dans la structure mémoire du descripteur de périphérique de débogage. (Notez que le module d’extensibilité KDNET ne doit JAMAIS utiliser plus que la taille de mémoire demandée dans KdInitializeLibrary lors de l’accès à cette mémoire. Toute mémoire supplémentaire à la fin du bloc est réservée à une utilisation par KDNET et ne doit pas être touchée par le module d’extensibilité 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.

--*/

Cette routine retourne une longueur en octets du paquet associé au handle passé. Notez que le handle a le bit TRANSMIT_HANDLE défini pour les paquets de transmission, et le TRANSMIT_HANDLE bit clear pour les paquets de réception. Pour les paquets de transmission, cette longueur doit être le nombre maximal d’octets pouvant être écrits dans le paquet. Pour les paquets de réception, cette longueur doit être le nombre réel d’octets dans le paquet reçu.

Débogage des modules d’extensibilité KDNET

Pour déboguer un module d’extensibilité KDNET, vous devez exécuter les commandes bcdedit suivantes à partir d’une invite de commandes avec élévation de privilèges sur l’ordinateur cible.

Tout d’abord, et le plus important, vous devez exécuter les deux commandes suivantes pour vous assurer que Winload autorise les échecs de démarrage répétés sans descendre d’un chemin d’accès d’échec spécial qui s’interrompt dans le débogueur et empêche le démarrage normal. L’exécution de ces commandes vous permet de redémarrer l’ordinateur à plusieurs reprises avec de nouveaux bits et de déboguer ces nouveaux bits sans problème.

Bcdedit -set {current} BootStatusPolicy IgnoreAllFailures

Bcdedit -set {current} RecoveryEnabled No

En supposant que vous allez utiliser le débogage série sur com1 sur l’ordinateur cible pour déboguer le module d’extensibilité, procédez comme suit.

bcdedit -dbgsettings serial debugport:1 baudrate:115200

Cela définit le transport de débogage par défaut sur série sur com1 à 115200 bauds. Ces paramètres seront également utilisés pour le débogage de démarrage.

bcdedit -debug on

Cela permet le débogage du noyau.

bcdedit -bootdebug on

Cela permet de démarrer le débogage sur winload.exe, que vous utiliserez pour déboguer dans l’initialisation du noyau, y compris votre module d’extensibilité KDNET.

bcdedit -set kerneldebugtype net

Cela force le type de débogage du noyau à net, quels que soient les paramètres de transport de débogage par défaut. Cela entraîne le chargement winload.exe kdnet.dll en tant que transport de débogage du noyau.

bcdedit -set kernelbusparams b.d.f

Où b est le numéro de bus, d est le numéro d’appareil et f le numéro de fonction (tout en décimal) du matériel pour lequel vous écrivez le module extensiblity KDNET. Ces nombres dépendent de l’emplacement PCI dans lequel se trouve le matériel. Vous pouvez les trouver en recherchant la chaîne d’emplacement dans la page des propriétés de l’appareil du périphérique réseau dans le Gestionnaire d’appareils Windows. Ouvrez le Gestionnaire de périphériques Windows, double-cliquez sur les périphériques réseau, recherchez votre appareil, double-cliquez dessus. Dans la fenêtre qui s’ouvre, il doit y avoir un champ Emplacement : qui contient le bus, l’appareil et la fonction du matériel sur le bus PCI. Si vous avez un pilote de bus qui fait que ces informations sont masquées, vous devrez déterminer l’emplacement à partir de vos chauffeurs, ou d’une autre façon.

Cela force le busparams du noyau à b.d.f, ce qui force cet appareil particulier à être sélectionné en tant qu’appareil de débogage du noyau.

bcdedit -set kernelhostip N

Où N est déterminé par la formule suivante. Si votre ordinateur du débogueur hôte a une adresse IPv4 w.x.y.z, N = (w0x01000000) + (x0x00010000) + (y0x00000100) + (z0x00000001). N doit être spécifié sur la ligne de commande en décimal, et non en hexadécimal. En fait, vous prenez chaque octet de l’adresse IPv4 et vous la concaténer (en hexadécimal) pour générer un nombre de 32 bits en hexadécimal, puis vous le convertissez en décimal.

bcdedit -set kernelport N

Où N est 50000 ou un autre port qui ne sera pas bloqué sur votre réseau interne.

Cela force KDNET à utiliser le port N comme port de débogage réseau.

bcdedit -set kernelkey 1.2.3.4

Cela force la clé de débogage KDNET à 1.2.3.4. 1.2.3.4 n’est pas sécurisé ou unique sur la clé réseau. Pour assurer la sécurité de l’ordinateur cible, les paquets qui transitent entre l’ordinateur hôte et les ordinateurs cibles doivent être chiffrés. Nous vous recommandons vivement d’utiliser une clé de chiffrement générée automatiquement. Pour plus d’informations, consultez Configuration automatique du débogage du noyau réseau KDNET.

bcdedit -set kerneldhcp on

Cela force le paramètre dhcp du noyau KDNET à activer.

Exécutez votre débogueur sur l’ordinateur hôte du débogueur avec la ligne de commande suivante en supposant que vous utilisez com1 comme port de débogage série sur l’ordinateur hôte :

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

Cela exécutera le débogueur et provoquera son arrêt lorsque le débogueur de démarrage windbg communique pour la première fois avec l’ordinateur hôte.

Redémarrez ensuite l’ordinateur cible en exécutant

shutdown -r -t 0

Lorsque le débogueur se brise dans windbg, assurez-vous que les symboles sont chargés pour winload. (vous devrez peut-être définir le fichier .sympath et effectuer un .reload). Exécutez ensuite x winload!*deb*tra*. L’un des symboles répertoriés est similaire à BdDebugTransitions.

Ensuite, exécutez ed winload!BdDebugTransitions 1, mais veillez à utiliser le nom de symbole correct.

Exécutez ensuite pour bu winload!blbdstop définir un point d’arrêt.

Puis appuyez g pour aller.

Vous devriez vous arrêter à winload ! BlBdStop.

Exécutez ensuite les commande suivantes.

bu nt!KdInitSystem

bu kdnet!KdInitialize

bu kdstub!KdInitializeLibrary

Notez que vous utiliserez probablement kdstub lors de la définition de points d’arrêt dans votre module d’extensibilité KDNET. Si cela ne fonctionne pas, utilisez

bu kd_YY_XXXX!KdInitializeLibrary

Où YY est votre classe PCI et XXXX votre VID PCI. (Par exemple , utilisez le nom de votre module d’extensibilité KDNET.)

Généralement, dans le débogueur, vous devez utiliser kdstub au lieu d’utiliser le nom réel de votre module d’extensibilité.

bl Exécutez ensuite pour répertorier les points d’arrêt. Assurez-vous que les points d’arrêt sont en place (ils doivent tous avoir un e à côté d’eux).

Appuyez ensuite sur g. Tu devrais frapper la fourmi ! Point d’arrêt KdInitSystem.

Appuyez g à nouveau, et vous devriez frapper kdnet ! KdInitialize

Appuyez g à nouveau et vous devez atteindre un point d’arrêt dans votre propre module sur KdInitializeLibrary.

Vous pouvez ensuite définir un point d’arrêt sur votre routine InitializeController, ainsi que toutes vos autres routines, et parcourir votre code.

Une fois que vous parcourez KdInitializeLibrary, appuyez sur g, et si vous définissez un point d’arrêt sur votre routine InitializeController, cela sera atteint ensuite.

Une fois cette opération terminée, assurez-vous que des points d’arrêt sont définis sur vos routines KdGetTxPacket, KdSendTxPacket, KdGetRxPacket, KdReleaseRxPacket, puis appuyez à nouveau sur g, et ces routines seront exécutées dans le cadre de l’initialisation réseau effectuée par KDNET au démarrage.

Vous devrez peut-être ajouter du code temporaire à vos routines KdInitializeLibrary ou KdInitializeController pour vous assurer que toutes vos routines sont appelées afin que vous puissiez parcourir l’ensemble de votre code. (KdShutdownController, par exemple, n’est pas appelé au démarrage lorsque les choses fonctionnent normalement. Vous devrez donc l’appeler explicitement à partir de code temporaire afin de pouvoir le parcourir pas à pas et vous assurer qu’il est correct.)

Une fois que vous avez parcouru tout votre code et que vous êtes sûr qu’il est correct, redémarrez la cible, mais ne définissez PAS le winload ! Indicateur BdDebugTransitions sur true (laissez la valeur par défaut zéro).

Ensuite, exécutez une autre instance du débogueur de noyau sur votre ordinateur du débogueur hôte.

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

Laissez l’ordinateur cible démarrer et il doit se connecter à l’autre instance du débogueur du noyau sur le réseau.

Ensuite, exécutez les commandes dans le débogueur du noyau et assurez-vous qu’elle fonctionne, puis laissez la cible continuer à démarrer, et assurez-vous que vous pouvez par la suite s’arrêter et exécuter des commandes.

Notes

La définition de l’indicateur de transitions de débogage dans winload garantit que Windows NE DÉMARRE PAS. Si vous essayez d’autoriser Windows à terminer le démarrage après avoir défini cet indicateur, Windows se bloque simplement ou se bloque. Si vous souhaitez que Windows démarre correctement, vous ne pouvez pas définir cet indicateur de transitions de débogage. La définition de l’indicateur vous permet de déboguer votre code et de vérifier qu’il est correct en le parcourant pas à pas dans le débogueur, mais au final, vous n’aurez pas besoin de définir l’indicateur afin de pouvoir vérifier que le débogage fonctionne lorsque vous démarrez normalement. Cela signifie que vous ne pouvez pas parcourir votre code lors du démarrage normal du système et, en fait, lorsque Windows s’exécute normalement, avec le débogage activé sur votre matériel, votre module d’extensibilité KDNET ne peut pas être débogué. Toute tentative de débogage avec le débogueur du noyau entraîne le blocage de l’ordinateur. (Vous ne pouvez pas définir de points d’arrêt dans le code qui s’exécute dans les chemins de débogage du noyau, car cela provoque une réentrée infinie, une pile soufflée et un redémarrage.)

Fonctions physiques multiples - 2PF

En plus de l’extensibilité KDNET, KDNET prend en charge le débogage du noyau à l’aide de plusieurs fonctions physiques (PFs) sur les cartes réseau prises en charge en partitionnant l’espace de configuration PCI. Les fournisseurs de carte réseau sont encouragés à activer la prise en charge de cette fonctionnalité. Pour plus d’informations, consultez Prise en charge du pilote réseau KDNET Miniport du débogueur 2PF.

Voir aussi

Configuration automatique du débogage du noyau réseau KDNET

Configuration manuelle du débogage du noyau réseau KDNET

Prise en charge du pilote réseau KDNET Miniport du débogueur 2PF