Accès aux mémoires tampons de données dans les pilotes WDF (KMDF ou UMDF)

Lorsqu’un pilote WDF (Windows Driver Frameworks) reçoit une demande de contrôle d’E/S de périphérique en lecture, en écriture ou en écriture, l’objet de demande contient une mémoire tampon d’entrée, une mémoire tampon de sortie, ou les deux.

Les mémoires tampons d’entrée contiennent des informations dont le pilote a besoin. Pour les demandes d’écriture, ces informations sont généralement des données qu’un pilote de fonction doit envoyer à un appareil. Pour les demandes de contrôle d’E/S d’appareil, une mémoire tampon d’entrée peut contenir des informations indiquant le type d’opération que le pilote doit effectuer.

Les mémoires tampons de sortie reçoivent des informations du pilote. Pour les demandes de lecture, ces informations sont généralement des données qu’un pilote de fonction reçoit d’un appareil. Pour les demandes de contrôle d’E/S d’appareil, une mémoire tampon de sortie peut recevoir des status ou d’autres informations spécifiées par le code de contrôle d’E/S de la demande.

La technique utilisée par votre pilote pour accéder aux mémoires tampons de données d’une requête dépend de la méthode du pilote pour accéder aux mémoires tampons de données d’un appareil. Il existe trois méthodes d’accès :

  • E/S mises en mémoire tampon. Le gestionnaire d’E/S crée des mémoires tampons intermédiaires qu’il partage avec le pilote.
  • E/S directes. Le gestionnaire d’E/S verrouille l’espace de mémoire tampon dans la mémoire physique, puis fournit au pilote un accès direct à l’espace de mémoire tampon.
  • Ni mise en mémoire tampon ni E/S directes. Le gestionnaire d’E/S fournit au pilote les adresses virtuelles de l’espace tampon de la requête. Le gestionnaire d’E/S ne valide pas l’espace de mémoire tampon de la requête. Le pilote doit donc vérifier que l’espace de mémoire tampon est accessible et verrouiller l’espace de mémoire tampon dans la mémoire physique.

Un pilote KMDF (Kernel-Mode Driver Framework) peut utiliser l’une des trois méthodes d’accès. Un pilote UMDF (User-Mode Driver Framework) peut utiliser des E/S en mémoire tampon ou directes pour les demandes de lecture, d’écriture et IOCTL, et peut convertir des requêtes qui spécifient la méthode METHOD_NEITHER.

Spécification de la méthode d’accès à la mémoire tampon

Pilotes KMDF

Pour les demandes de lecture et d’écriture, tous les pilotes d’une pile de pilotes doivent utiliser la même méthode pour accéder aux mémoires tampons d’un périphérique, à l’exception du pilote de niveau supérieur, qui peut utiliser la méthode « ni l’un ni l’autre », quelle que soit la méthode utilisée par les pilotes inférieurs.

À compter de la version 1.13, un pilote KMDF spécifie la méthode d’accès pour toutes les demandes de lecture et d’écriture d’un appareil en appelant WdfDeviceInitSetIoTypeEx pour chaque appareil. Par exemple, si un pilote spécifie la méthode d’E/S mise en mémoire tampon pour l’un de ses appareils, le gestionnaire d’E/S utilise la méthode d’E/S mise en mémoire tampon lors de la remise de demandes de lecture et d’écriture au pilote pour ce périphérique.

Pour les demandes de contrôle d’E/S d’appareil, le code de contrôle d’E/S (IOCTL) contient des bits qui spécifient la méthode d’accès à la mémoire tampon. Par conséquent, un pilote KMDF n’a pas besoin d’effectuer une action pour sélectionner une méthode de mise en mémoire tampon pour les IOCTL. Pour plus d’informations sur les IOCTL, consultez Définition de codes de contrôle d’E/S. Contrairement aux demandes de lecture et d’écriture, tous les IOCTL d’un appareil n’ont pas besoin de spécifier la même méthode d’accès.

Pilotes UMDF

Un pilote UMDF spécifie des préférences pour la méthode d’accès que l’infrastructure utilise pour les demandes de lecture et d’écriture, ainsi que pour les demandes de contrôle d’E/S de périphérique. Les valeurs qu’un pilote UMDF fournit sont uniquement des préférences et ne sont pas garanties d’utilisation par le framework. Pour plus d’informations, consultez Gestion des méthodes d’accès aux tampons dans les pilotes UMDF.

Un pilote UMDF spécifie la méthode d’accès pour toutes les demandes de lecture, d’écriture et IOCTL d’un appareil en appelant WdfDeviceInitSetIoTypeEx pour chaque appareil. Par exemple, si un pilote spécifie la méthode d’E/S mise en mémoire tampon pour l’un de ses appareils, l’infrastructure utilise la méthode d’E/S mise en mémoire tampon lors de la remise de demandes de lecture, d’écriture et d’IOCTL au pilote pour ce périphérique.

Notez la différence de technique d’accès à la mémoire tampon pour les IOCTL entre KMDF et UMDF. Les pilotes KMDF ne spécifient pas la méthode d’accès à la mémoire tampon pour les IOCTL, tandis que les pilotes UMDF spécifient la méthode d’accès à la mémoire tampon pour les IOCTL.

Si un pilote WDF décrit la mémoire tampon d’une demande d’E/S à l’aide d’une technique incorrecte pour la méthode d’E/S utilisée par une cible d’E/S, l’infrastructure corrige la description de la mémoire tampon. Par exemple, si un pilote utilise une MDL pour décrire une mémoire tampon qu’il transmet à WdfIoTargetSendReadSynchronously, et si la cible d’E/S utilise des E/S mises en mémoire tampon (ce qui nécessite que les mémoires tampons soient spécifiées à l’aide d’adresses virtuelles au lieu de MDL), l’infrastructure convertit la description de la mémoire tampon d’une MDL en une adresse virtuelle et une longueur. Toutefois, il est plus efficace si votre pilote spécifie des mémoires tampons dans le format approprié.

Pour plus d’informations sur les objets mémoire du framework, les listes de recherche, les DLL et les mémoires tampons locales, consultez Utilisation des mémoires tampons.

Pour plus d’informations sur le moment où les mémoires tampons sont supprimées, consultez Cycle de vie des mémoires tampons.

Accès aux mémoires tampons de données pour les E/S mises en mémoire tampon

Si votre pilote utilise des E/S mises en mémoire tampon, son comportement change en fonction du type de demande de données et de l’utilisation de KMDF ou UMDF.

Pilotes KMDF

Lorsqu’un pilote KMDF utilise des E/S mises en mémoire tampon, le gestionnaire d’E/S crée une mémoire tampon intermédiaire à laquelle le pilote peut accéder pour chaque type de requête. Voici ce qui se passe :

  • Écrire des demandes. Le gestionnaire d’E/S transfère les informations d’entrée de la mémoire tampon d’entrée de l’application appelante avant d’appeler la pile des pilotes. Ensuite, le pilote KMDF lit les informations d’entrée de la mémoire tampon intermédiaire et les écrit sur l’appareil.
  • Demandes de lecture. Le pilote KMDF lit les informations de l’appareil et les stocke dans la mémoire tampon intermédiaire. Ensuite, le gestionnaire d’E/S copie les données de sortie de la mémoire tampon intermédiaire vers la mémoire tampon de sortie de l’application.
  • Demandes de contrôle d’E/S d’appareil. Le pilote KMDF lit ou écrit des données pour cette requête vers ou à partir de la mémoire tampon intermédiaire.

Pilotes UMDF

Lorsqu’un pilote UMDF utilise des E/S mises en mémoire tampon, le processus hôte du pilote crée une ou deux mémoires tampons intermédiaires, selon le type de requête. Voici ce qui se passe :

  • Écrire des demandes. L’infrastructure crée une mémoire tampon, transfère les informations d’entrée à partir de la mémoire tampon d’entrée de l’application appelante, puis appelle la pile des pilotes. Le pilote UMDF lit les informations d’entrée de la mémoire tampon intermédiaire et les écrit sur l’appareil.
  • Demandes de lecture. Un pilote UMDF lit les informations d’un appareil et les stocke dans une mémoire tampon créée par l’infrastructure. Le processus hôte du pilote copie les données de sortie de la mémoire tampon intermédiaire vers la mémoire tampon de sortie de l’application.
  • Demandes de contrôle d’E/S d’appareil. L’infrastructure crée deux mémoires tampons correspondant aux mémoires tampons d’entrée et de sortie de l’IOCTL auxquelles le pilote peut accéder. Le framework copie les informations d’entrée de l’IOCTL dans la nouvelle mémoire tampon intermédiaire et les met à la disposition du pilote. L’infrastructure ne copie pas le contenu de la mémoire tampon de sortie. Par conséquent, le pilote ne doit pas tenter de lire à partir de celle-ci (sinon, il finira par lire des données de mémoire). Toutes les données que le pilote écrit dans la mémoire tampon de sortie sont copiées dans la mémoire tampon IOCTL d’origine et sont retournées à l’application une fois la demande d’E/S terminée. Notez que toutes les données que le pilote écrit dans la mémoire tampon d’entrée sont ignorées et ne sont pas retournées à l’application appelante.

Pour récupérer un handle dans un objet de mémoire d’infrastructure qui représente la mémoire tampon, les pilotes KMDF et UMDF appellent WdfRequestRetrieveInputMemory ou WdfRequestRetrieveOutputMemory, selon qu’il s’agit d’une demande de lecture ou d’écriture. Le pilote peut ensuite récupérer un pointeur vers la mémoire tampon en appelant WdfMemoryGetBuffer. Pour lire et écrire la mémoire tampon, le pilote appelle WdfMemoryCopyFromBuffer ou WdfMemoryCopyToBuffer.

Pour récupérer l’adresse virtuelle et la longueur de la mémoire tampon, le pilote appelle WdfRequestRetrieveInputBuffer ou WdfRequestRetrieveOutputBuffer.

Pour allouer et générer une liste de descripteurs mémoire (MDL) pour la mémoire tampon, un pilote KMDF appelle WdfRequestRetrieveInputWdmMdl ou WdfRequestRetrieveOutputWdmMdl.

Accès aux mémoires tampons de données pour les E/S directes

Pilotes KMDF

Si votre pilote utilise des E/S directes, le gestionnaire d’E/S vérifie l’accessibilité de l’espace tampon spécifié par l’auteur de la demande d’E/S (généralement une application en mode utilisateur), verrouille l’espace de mémoire tampon dans la mémoire physique, puis fournit au pilote un accès direct à l’espace tampon.

Pilotes UMDF

Si votre pilote a spécifié une préférence pour les E/S directes et que toutes les exigences UMDF pour les E/S directes ont été satisfaites (consultez Gestion des méthodes d’accès aux tampons dans les pilotes UMDF), l’infrastructure mappe la mémoire tampon qu’il reçoit du gestionnaire d’E/S directement dans l’espace d’adressage du processus hôte du pilote, et fournit ainsi au pilote un accès direct à l’espace de mémoire tampon.

Pour récupérer un handle dans un objet de mémoire d’infrastructure qui représente l’espace de mémoire tampon, le pilote appelle WdfRequestRetrieveInputMemory ou WdfRequestRetrieveOutputMemory. Le pilote peut ensuite récupérer un pointeur vers la mémoire tampon en appelant WdfMemoryGetBuffer. Pour lire et écrire la mémoire tampon, le pilote appelle WdfMemoryCopyFromBuffer ou WdfMemoryCopyToBuffer.

Pour récupérer l’adresse virtuelle et la longueur de l’espace de mémoire tampon, le pilote appelle WdfRequestRetrieveInputBuffer ou WdfRequestRetrieveOutputBuffer.

Si les pilotes d’un appareil utilisent des E/S directes, le gestionnaire d’E/S décrit les mémoires tampons à l’aide de DLL. Pour récupérer un pointeur vers la MDL d’une mémoire tampon, un pilote KMDF appelle WdfRequestRetrieveInputWdmMdl ou WdfRequestRetrieveOutputWdmMdl. Un pilote UMDF ne peut pas accéder aux DLL.

Accès aux mémoires tampons de données pour les E/S directes ou mises en mémoire tampon

Pilotes KMDF

Si votre pilote utilise la méthode d’accès à la mémoire tampon connue sous le nom d’E/S en mémoire tampon ni de méthode d’E/S directe (ou, en bref, la méthode « aucun », le gestionnaire d’E/S fournit simplement au pilote les adresses virtuelles que l’initiateur de la demande d’E/S a spécifiées pour l’espace tampon de la requête. Le gestionnaire d’E/S ne valide pas l’espace tampon de la demande d’E/S. Le pilote doit donc vérifier que l’espace de mémoire tampon est accessible et verrouiller l’espace de mémoire tampon dans la mémoire physique.

Les adresses virtuelles que fournit le gestionnaire d’E/S ne sont accessibles que dans le contexte de processus de l’initiateur de la demande d’E/S. Seul le pilote de niveau supérieur de la pile de pilotes est garanti pour s’exécuter dans le contexte de processus de l’initiateur.

Pour obtenir l’accès à l’espace tampon d’une demande d’E/S, le pilote de niveau supérieur doit fournir une fonction de rappel EvtIoInCallerContext . L’infrastructure appelle cette fonction de rappel chaque fois qu’elle reçoit une demande d’E/S pour le pilote.

Si la méthode d’accès à la mémoire tampon d’une requête est « ni », un pilote KMDF doit effectuer les opérations suivantes pour chaque mémoire tampon :

  1. Appelez WdfRequestRetrieveUnsafeUserInputBuffer ou WdfRequestRetrieveUnsafeUserOutputBuffer pour obtenir l’adresse virtuelle de la mémoire tampon.

  2. Appelez WdfRequestProbeAndLockUserBufferForRead ou WdfRequestProbeAndLockUserBufferForWrite pour sonder et verrouiller la mémoire tampon et obtenir un handle sur un objet de mémoire framework pour la mémoire tampon.

  3. Enregistrez les handles de l’objet mémoire dans l’espace de contexte de la requête.

  4. Appelez WdfDeviceEnqueueRequest, qui retourne la demande à l’infrastructure.

L’infrastructure ajoute ensuite la requête à l’une des files d’attente d’E/S du pilote. Si le pilote a fourni des gestionnaires de requêtes, l’infrastructure appellera finalement le gestionnaire de requêtes approprié.

Le gestionnaire de requêtes peut récupérer les handles d’objet mémoire de la requête à partir de l’espace de contexte de la requête. Le pilote peut passer les handles à WdfMemoryGetBuffer pour obtenir l’adresse de la mémoire tampon.

Parfois, un pilote de niveau supérieur doit utiliser les étapes précédentes pour accéder à une mémoire tampon en mode utilisateur, même si le pilote n’utilise pas la méthode d’accès « aucun ». Par exemple, supposons que le pilote utilise des E/S mises en mémoire tampon. Un code de contrôle d’E/S qui utilise la méthode d’accès mis en mémoire tampon peut passer une structure qui contient un pointeur incorporé vers une mémoire tampon en mode utilisateur. Dans ce cas, le pilote doit fournir une fonction de rappel EvtIoInCallerContext qui extrait les pointeurs de la structure, puis utilise les étapes précédentes 2 à 4.

Pilotes UMDF

L’UMDF ne prend pas en charge ni les mémoires tampons de type E/S directes, donc un pilote UMDF n’a jamais besoin de gérer ce type de mémoire tampon directement.

Toutefois, si l’infrastructure reçoit ces mémoires tampons pour la lecture ou l’écriture du gestionnaire d’E/S, elle les met à la disposition d’un pilote UMDF en tant qu’E/S mises en mémoire tampon ou E/S directes, en fonction de la méthode d’accès sélectionnée par le pilote. Si l’infrastructure reçoit un IOCTL spécifiant la méthode de mémoire tampon « aucun », il peut éventuellement convertir la méthode d’accès à la mémoire tampon de la demande IOCTL en E/S mises en mémoire tampon ou en E/S directes en fonction de la présence d’une directive INF. Pour plus d’informations, consultez Gestion des méthodes d’accès à la mémoire tampon dans les pilotes UMDF .