Partager 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 les fournisseurs de carte réseau pour ajouter la prise en charge du débogage du noyau à des carte réseau spécifiques.

Vue d’ensemble de KDNET

KDNET est un transport de débogage du noyau qui permet le débogage du noyau pour Windows à travers un réseau. Au départ, il était utilisé pour prendre en charge le débogage du noyau avec des cartes d’interface réseau Ethernet. Il est conçu pour que la couche de support matérielle soit intégrée à un module distinct du traitement des paquets réseau et de la couche d’interface du noyau. Cette couche de support du pilote matériel est appelée module d’extensibilité KDNET.

KDNET est le seul transport que l’on peut étendre 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 l’ensemble du débogage de Windows par l’intermédiaire de KDNET et des modules d’extension de KDNET. Toutes les autres DLL de transport du noyau (kdcom.dll, kd1394.dll, kdusb.dll, etc.) seront finalement obsolètes et supprimées de Windows.

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

Pour fonctionner correctement, les modules d’extensibilité KDNET doivent répondre à des exigences très strictes. Comme ils sont utilisés pour le débogage du noyau, ils sont appelés et exécutés lorsque le système suspend l’exécution du code. En règle générale, tous les processeurs du système sont verrouillés dans un IPI, à l’exception du processeur qui communique avec l’application du 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 est essentiellement en rotation sur le matériel de transport de débogage en attente de commandes provenant du débogueur.

Importer et exporter

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

Si vous videz les importations et les exportations d’un module d’extensibilité KDNET en utilisant link /dump /exports et link /dump /imports, vous verrez qu’il n’y a 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 de 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 des octets en examinant quelles fonctions spécifiques le module remplit dans la table de fonctions d’exportation dans la structure. Certaines de ces fonctions sont destinées à prendre en charge le matériel basé sur des paquets, d’autres sont destinées au matériel basé sur les séries. Certaines fonctions de la table sont utilisées à la fois par le matériel basé sur les séries et les paquets (KdInitializeController, KdShutdownController, KdGetHardwareContextSize).

Conception du code

Les modules d’extensibilité KDNET doivent être écrits en tant que code monothread. 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 possède un verrou de débogage 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 ne seront libérés que lorsque le débogueur du noyau fonctionnant sur l’hôte indiquera à la machine cible d’autoriser 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 spinlock, 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 ou des octets.

Le code du module d’extensibilité KDNET doit être simplifié autant que possible. On s’assure ainsi qu’il est aussi exempt de bogues que possible, étant donné que le débogage du code du module d’extension 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 du noyau pour déboguer le code de transport du noyau. Si vous essayez de le faire, la machine redémarrera en raison d’une pile de noyau défectueuse (ce qui se termine généralement par une double erreur et un redémarrage), ou d’un blocage, ou parce que le transport doit être réintroduit, ce qui, dans la plupart des cas, empêche ce dernier de fonctionner correctement.

Conventions d’affectation de noms des modules d’extensibilité KDNET

Votre module de transport de débogage du noyau doit suivre l’une des deux conventions d’affectation de noms pour les modules d’extensibilité KDNET. Si votre module est destiné à prendre en charge du matériel basé sur PCI, il doit être nommé kd_YYY_XXXX.dll où XXXX est l’ID du fournisseur PCI de votre matériel en hexadécimal, et YY est la classe PCI de votre matériel. Il existe plusieurs modules d’extension KDNET livrés dans la boîte de Windows qui prennent en charge le matériel basé sur PCI. Par exemple, les kd_02_8086.dll d’Intel, les kd_02_14e4.dll de Broadcom et les kd_02_10ec.dll de Realtek. Vous pouvez rechercher des ID de fournisseur PCI inscrits sur 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 du nom de leur module. Le code de classe de la plupart des modules de la boîte est 02, parce qu’il s’agit de périphériques de classe réseau et qu’ils ont donc une classe PCI de 0x02 dans leur espace de configuration PCI. Winload.exe établit le nom des modules d’extension KDNET basés sur PCI en lisant la classe d’appareil PCI et le VID PCI de l’appareil de débogage sélectionné dans son espace de configuration PCI, et tente de charger un module dont le nom contient ces identifiants. 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. Dans le cas contraire, votre module ne sera pas chargé correctement par winload. Le _02_ dans 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’appellation des dispositifs de débogage de la table DBG2 est kd_XXXX_YYYY.dll où XXXX est le PortType hexadécimal de la table DBG2 et YYYY est le PortSubtype hexadécimal de la table DBG2 de l’entrée de la table DBG2. Kd_8003_5143.dll est une DLL intégrée pour prendre en charge un PortType net (0x8003) avec un sous-type de 0x5143. Dans ce cas, 5143 est le VID PCI Qualcomm, puisqu’il s’agit de prendre en charge KDNET sur les contrôleurs USB Qualcomm, et pour les entrées de la table Net DBG2, le PortSubtype est défini comme étant le VID PCI du fournisseur du matériel. Il convient de noter que vous pouvez prendre en charge les appareils série, USB et autres appareils de la table DBG2 en utilisant cette convention d’affectation de noms. Les valeurs de PortType actuellement prises en charge en hexadécimal sont les suivantes : 8000 pour les appareils série, 8001 pour les appareils 1394, 8002 pour les appareils USB, 8003 pour les appareils NET. Il faut souligner que les sous-types pour les appareils série et USB doivent être réservés avec Microsoft. Microsoft gère 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 de modules d’extensibilité KDNET

Voici la liste des routines que vous pouvez appeler à partir d’un module d’extensibilité KDNET. Il convient de noter que toutes ces routines sont passées à la routine KdInitializeLibrary, et que l’en-tête kdnetextensibility.h mappera 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 pouvez ne pas appeler d’autres routines exportées par le noyau, le HAL ou tout autre module du noyau. Vous pouvez uniquement appeler ces routines. Cet ensemble de routines s’est avéré suffisant pour développer tous les modules d’extension du KDNET et devrait suffire pour les scénarios normaux. Si vous avez besoin de routines supplémentaires exportées par le noyau, mais qui ne figurent pas dans cette liste, veuillez envoyer un message à kdnet@microsoft.com en expliquant votre scénario, les routines supplémentaires dont vous avez besoin et pourquoi. Il convient de noter que cette liste ne sera ajoutée qu’à l’occasion des principaux cycles de mise à jour de Windows, si tant est qu’elle le soit. Soulignons que la plupart de ces routines correspondent directement aux API de noyau Windows prises en charge par le noyau ou la HAL. Une ou deux d’entre elles sont des routines personnalisées réservées à KDNET.

Vous devez impérativement inclure correctement le fichier kdnetextensibility.h dans vos en-têtes afin que le remappage correct des routines dans la table d’importation puisse avoir lieu. Si ce n’est pas le cas, votre module aura des importations et ne sera pas pris en charge.

Lire les routines de mémoire d’écriture

Les routines suivantes doivent être utilisées pour la lecture et l’écriture dans la mémoire des appareils mappés en mémoire. Ceux-ci ont la même convention d’appel et sont mappés sur les routines correspondantes du noyau : 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 par l’intermédiaire de ces routines, car elles garantissent que les lectures et les écritures ne sont pas réordonnées par le processeur. Il convient de noter que le msdn.microsoft.com documente les routines Windows CE Compact 2013 qui correspondent à la convention d’appel à ces routines. Malheureusement, il apparaît que les routines NT ne sont pas documentées, mais la convention d’appel est la même.

Lire les routines de port d’E/S

Les routines suivantes doivent être utilisées pour la lecture et l’écriture dans les ports d’E/S de l’appareil. Ils 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 accès aux ports d’E/S de l’appareil doivent être effectués par le biais de ces routines. Il convient de noter que le msdn.microsoft.com documente les routines Windows CE Compact 2013 qui correspondent à la convention d’appel à ces routines.

Routines supplémentaires

Les routines supplémentaires suivantes peuvent être appelées et doivent être appelées normalement avec les paramètres spécifiés. Il convient de noter qu’en procédant ainsi, tout en incluant correctement l’en-tête kdnetextensibility.h, les appels de fonction seront remappés vers la table d’importation d’extensibilité KDNET, ce qui signifie qu’il n’y aura pas d’importations explicites dans votre module, comme c’est le cas 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

    );

Signalons que la fonction PoSetHiberRange ne doit être appelée qu’à 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 de mémoire physique nécessaires à la programmation des moteurs DMA des appareils, et nombre d’entre eux devront appeler KeStallExecutionProcessor, KdGetPciDataByOffset et KdSetPciDataByOffset. Les deux dernières routines permettent d’accéder à l’espace de configuration PCI de l’appareil.

Exportations de modules 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 les paquets ou un module d’extensibilité KDNET basé sur la série. Les exportations ci-dessous sont celles du module d’extensibilité KDNET par paquets.

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;
}

Cette routine est appelée pour transmettre les routines d’importation et d’exportation entre KDNET et ce module d’extensibilité KDNET. Cette routine doit confirmer que la version des tables d’importation et d’exportation est attendue et prise en charge, et échouer si ce n’est pas le cas. Elle doit effectuer une copie de la table d’importation dans sa propre mémoire globale. Elle doit écrire les routines qu’elle exporte dans la structure vers laquelle pointe le champ Exportations de la table d’importations. Elle doit également définir le champ Longueur de la structure Mémoire qui fait partie du pointeur de descripteur de l’appareil de débogage transmis à cette routine, avec le nombre d’octets de mémoire requis pour prendre en charge l’appareil matériel.

Valider le nombre d’exportations d’importation

Le code doit vérifier que Imports FunctionCount correspond à ce qui est disponible dans le système d’exploitation, par exemple , (KdNetExtensibilityImports->FunctionCount != KDNET_EXT_IMPORTS) et retourner STATUS_INVALID_PARAMETER si le nombre ne correspond pas.

La vérification du nombre garantit la compatibilité entre la version de KDNET du système d’exploitation Windows en cours d’exécution (par exemple, le gestionnaire de démarrage/le chargeur de système d’exploitation/hyperviseur/noyau sécurisé/NT OS, qui sont tous liés à la bibliothèque KDNET) et la version WDK utilisée pour générer le module d’extensibilité KDNET actuel. Le WDK et la version du système d’exploitation doivent être synchronisés ; sinon, la vérification ci-dessus échoue si la valeur du compteur d’importation/exportation change. Par exemple, si l’interface d’extensibilité KDNET a ajouté une nouvelle fonction de fonctionnalité, le nombre ne correspond plus. Pour vous assurer qu’ils correspondent, utilisez toujours la version WDK qui correspond au système d’exploitation hébergeant la version KDNET.

Personnaliser la mémoire requise

Notez que l’appareil sera renseigné 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 1 Go et 10 Go peuvent augmenter la taille de mémoire demandée pour les appareils 10 Go. Ils peuvent déterminer quel appareil est utilisé en examinant le champ DeviceID du descripteur de l’appareil de débogage.

KdInitializeLibrary est la seule exportation

Il convient de noter que cette routine sera appelée à la fois par winload et par KDNET pendant l’appel KdInitSystem. Notons 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’elle puisse inscrire correctement le code utilisé par le module d’extensibilité KDNET avec le système. Cela permet à ce dernier de gérer correctement cette mémoire pendant la mise en veille prolongée et de reprendre à partir de cette dernière. (La mémoire est enregistrée en retard et chargée tôt, car elle sera appelée très tôt pendant 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. Elle est appelée lors de l’initialisation du système et chaque fois que le système se réveille d’un état de faible consommation pour lequel il a appelé KdShutdownController. Cette routine DOIT s’assurer que le matériel a totalement terminé l’initialisation et qu’il est prêt à envoyer des paquets AVANT de retourner. Cette routine doit attendre que la PHY soit mise en place et que le lien soit établi. Il convient de noter qu’en l’absence de câble connecté, cette routine ne doit pas se bloquer indéfiniment. Cette dernière définit la vitesse de liaison et le duplex dans la structure de données partagée KDNET partagée entre KDNET et ce module d’extensibilité. Elle écrit également l’adresse MAC utilisée par le matériel dans l’emplacement vers lequel TargetMacAddress pointe 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 CRITIQUE que cette routine ATTENDE jusqu’à ce que tous les paquets de transmission encore en attente soient effectivement transmis. Cette routine doit attendre que tous les paquets de transmission aient été transmis par DMA à partir de la mémoire principale et qu’ils le soient AVANT l’arrêt de 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. Elle est appelée lorsque le système s’arrête, et aussi lorsque le système décide de gérer le transport de débogage vers un état d’alimentation faible. Elle peut être appelée lorsque le système passe en attente, en veille prolongée, en veille et en veille connectée, en plus du moment où le système est arrêté.

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 renvoyer le nombre d’octets requis pour l’ensemble de la mémoire nécessaire au fonctionnement 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 tous les descripteurs de paquets matériels et autres structures. La taille de TOUTE la mémoire dont vous avez besoin doit être indiqué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.

Il convient de noter 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 de l’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 pas encore traité. Elle renvoie 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 la libération du paquet en appelant KdReleaseRxPacket. Cette routine renvoie également directement l’adresse et la longueur du paquet à l’appelant.

Si aucun paquet n’est disponible, cette routine DOIT renvoyer immédiatement le message STATUS_IO_TIMEOUT. Cette routine NE DOIT PAS attendre la réception d’un paquet. Notez que les 2 premiers bits du de handle sont réservés. TRANSMIT_HANDLE et TRANSMIT_ASYNC doivent tous deux être libres.

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 paquet Handle et les restitue au matériel afin qu’elles puissent être utilisées pour la réception d’un autre paquet. Chaque appel à KdGetRxPacket qui réussit sera suivi d’un autre appel à KdReleaseRxPacket avec le handle renvoyé à partir de KdGetRxPacket. Signalons qu’il n’est PAS garanti que KdReleaseRxPacket soit 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 libérées avec un appel KdReleaseRxPacket.

Cette routine doit correctement programmer 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 renvoie un handle. Ce handle sera utilisé pour appeler KdGetPacketAddress et KdGetPacketLength. L’adresse de paquet renvoyée par KdGetPacketAddress permettra d’é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. Signalons qu’en l’absence de ressources matérielles disponibles, parce qu’elles ont tous été acquises et n’ont pas encore été transmises, cette routine doit immédiatement renvoyer le message STATUS_IO_TIMEOUT.

TRANSMIT_HANDLE devez être défini dans le handle renvoyé. Il faut noter que les deux premiers bits du 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 transmis sur le réseau. Il convient de noter que le handle peut contenir 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 renvoyer immédiatement, 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 normal et c’est voulu, 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 renvoyer toute erreur survenue pendant la transmission, le cas échéant. Signalons que lorsque les fichiers de vidage sont envoyés à l’hôte du débogueur, ou lorsque les paquets réseau Windows sont envoyés à partir de la carte réseau KDNIC via KDNET, TRANSMIT_ASYNC sera défini. Lorsque tous les autres paquets de débogueur sont envoyés TRANSMIT_ASYNC sera effacé.

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 le drapeau défini soit effectivement envoyé, même si cela signifie qu’il doit attendre l’envoi des paquets asynchrones précédents.

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 renvoie un pointeur vers le premier octet du paquet associé au handle transmis. Notez que le handle aura le bit TRANSMIT_HANDLE défini pour les paquets de transmission, et le bit TRANSMIT_HANDLE effacé pour les paquets de réception. Le pointeur renvoyé doit être une adresse virtuelle Windows que le processeur peut lire ou écrire. Cette adresse doit se trouver dans le bloc de mémoire réservé au module d’extensibilité KDNET qui est transmis dans la structure Mémoire du descripteur de l’appareil de débogage. (Notez que le module d’extensibilité KDNET ne doit JAMAIS utiliser plus que la taille de mémoire qu’il a demandée dans KdInitializeLibrary lorsqu’il accède à cette mémoire. Toute mémoire supplémentaire à la fin du bloc est réservée à l’usage de 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 renvoie une longueur en octets du paquet associé au handle transmis. Notez que le handle aura le bit TRANSMIT_HANDLE défini pour les paquets de transmission, et le bit TRANSMIT_HANDLE effacé 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.

En premier lieu, et ce qui est le plus important, vous devez exécuter les deux commandes suivantes pour vous assurer que Winload autorisera des échecs de démarrage répétés sans passer par un chemin d’échec spécial qui permet d’entrer dans le débogueur et d’empêcher un démarrage normal. L’exécution de ces commandes vous permet de redémarrer à plusieurs reprises l’ordinateur 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 partant du principe que vous utiliserez 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

Ceci définit le transport de débogage par défaut en série sur com1 à 115 200 baud. Ces paramètres seront également utilisés pour le débogage de démarrage.

bcdedit -debug on

Ceci permet le débogage du noyau.

bcdedit -bootdebug on

Ceci permet le débogage au démarrage sur winload.exe, que vous utiliserez pour déboguer les premières initialisations du noyau, y compris votre module d’extensibilité KDNET.

bcdedit -set kerneldebugtype net

Ceci force le type de débogage du noyau sur net, quels que soient les paramètres de transport de débogage par défaut. Ceci oblige winload.exe à charger 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 de l’appareil et f est le numéro de fonction (tous en décimales) du matériel pour lequel vous écrivez le module d’extensibilité 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 réseau dans le Gestionnaire d’appareils Windows. Ouvrez le gestionnaire d’appareils Windows, double-cliquez sur les appareils réseau, recherchez votre appareil, cliquez deux fois dessus et la fenêtre qui s’ouvre doit contenir un champ Emplacement qui contient le bus, l’appareil et la fonction du matériel sur le bus PCI. Si un pilote de bus masque cette information, vous devrez alors déterminer l’emplacement à partir de vos pilotes, ou d’une autre façon.

Cela force les busparams du noyau sur b.d.f, ce qui force l’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 de débogage hôte a une adresse IPv4 de 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 le concaténez (en hexadécimal) pour construire un nombre de 32 bits en hexadécimal, puis vous le convertissez en décimal.

bcdedit -set kernelport N

Où N est 50 000 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 sur 1.2.3.4. 1.2.3.4 n’est pas une clé réseau sécurisée ou unique. Pour sécuriser l’ordinateur cible, les paquets qui circulent entre les ordinateurs hôte et cible doivent être chiffrés. Nous vous recommandons vivement d’utiliser une clé de chiffrement générée automatiquement. Pour plus d’informations, consultez la rubrique Configuration automatique du débogage réseau du noyau KDNET.

bcdedit -set kerneldhcp on

Cela force le paramètre dhcp du noyau KDNET à être activé.

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

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

cela exécutera le débogueur et le fera planter lorsque le débogueur de démarrage windbg communiquera 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 s’arrête dans windbg, assurez-vous d’obtenir des symboles chargés pour winload. (il peut être nécessaire de définir .sympath et d’effectuer un .reload). Exécutez ensuite x winload!*deb*tra*. L’un des symboles répertoriés ressemblerait à BdDebugTransitions.

Exécutez ed winload!BdDebugTransitions 1 ensuite, mais veillez à utiliser le nom de symbole approprié.

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

Puis cliquez sur g pour accéder.

Vous devriez vous arrêter à winload!BlBdStop.

Exécutez ensuite les commande suivantes.

bu nt!KdInitSystem

bu kdnet!KdInitialize

bu kdstub!KdInitializeLibrary

Il convient de noter 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 alors

bu kd_YY_XXXX!KdInitializeLibrary

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

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

Exécutez ensuite bl pour répertorier les points d’arrêt. Assurez-vous que les points d’arrêt sont en place (ils doivent tous être accompagnés d’un e).

Puis cliquez sur g. Vous devriez atteindre le nt!KdInitSystem breakpoint.

Cliquez sur g à nouveau, et vous devriez atteindre kdnet!KdInitialize

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

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

Une fois que vous avez parcouru KdInitializeLibrary, appuyez sur g, et si vous avez placé un point d’arrêt sur votre routine InitializeController, celle-ci sera atteinte ensuite.

Ensuite, une fois que vous avez terminé, assurez-vous d’avoir des points d’arrêt définis sur vos routines KdGetTxPacket, KdSendTxPacket, KdGetRxPacket, KdReleaseRxPacket. Appuyez à nouveau sur g, et ces routines seront exécutées dans le cadre de l’initialisation du réseau effectuée par KDNET pendant le 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 de vous permettre de parcourir tout votre code. (Par exemple, si tout fonctionne normalement, KdShutdownController ne sera pas appelée lors du démarrage. Vous devrez donc l’appeler explicitement à partir du code temporaire pour le parcourir 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 l’indicateur winload!BdDebugTransitions sur true (laissez la valeur par défaut zéro).

Exécutez ensuite également une autre instance du débogueur du 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. Il devrait se connecter à l’autre instance du débogueur du noyau sur le réseau.

Exécutez ensuite des commandes dans le débogueur du noyau et assurez-vous que cela fonctionne, puis laissez la cible poursuivre son démarrage et assurez-vous que vous pourrez plus tard y accéder et exécuter des commandes.

Remarque

L’activation de l’indicateur de transition de débogage dans winload garantit que Windows NE DÉMARRE PAS. Si vous tentez d’autoriser Windows à terminer le démarrage après avoir défini cet indicateur, Windows plante ou bloque. Si vous souhaitez que Windows démarre correctement, vous ne pouvez pas définir cet indicateur de transitions de débogage. L’activation de cet indicateur vous permet de déboguer votre code et de vérifier qu’il est correct en le parcourant dans le débogueur. Mais en fin de compte, vous ne devrez pas l’activer afin de vous assurer que le débogage fonctionne lorsque vous démarrez normalement. Cela signifie que vous ne pouvez pas parcourir votre code lorsque vous démarrez le système normalement, et en fait, lorsque Windows fonctionne normalement, avec le débogage activé sur votre matériel, votre module d’extensibilité KDNET ne peut pas être débogué. Toute tentative de le déboguer avec le débogueur du noyau entraîne le plantage de l’ordinateur. (Vous ne pouvez pas définir de points d’arrêt dans le code qui s’exécute dans les chemins d’accès de débogage du noyau, car ils provoquent une nouvelle 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 (PF) sur les cartes réseau prises en charge en partitionnant l’espace de configuration PCI. Les fournisseurs de cartes réseau sont encouragés à activer la prise en charge de cette fonctionnalité. Pour plus d’informations, consultez le support du pilote réseau miniport KDNET 2PF du débogueur.

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 de réseau miniport KDNET 2PF du débogueur