Extensions d’appareil

Pour la plupart des pilotes intermédiaires et de niveau le plus bas, l’extension de périphérique est la structure de données la plus importante associée à un objet de périphérique. Sa structure interne est définie par le pilote, et elle est généralement utilisée pour :

  • Conservez les informations d’état de l’appareil.

  • Fournir un stockage pour tous les objets définis par le noyau ou d’autres ressources système, telles que les verrous de rotation, utilisés par le pilote.

  • Conservez toutes les données que le pilote doit avoir résidentes et dans l’espace système pour effectuer ses opérations d’E/S.

Étant donné que la plupart des pilotes de bus, de fonction et de filtre (pilotes de niveau le plus bas et intermédiaire) s’exécutent dans un contexte de thread arbitraire (celui de tout thread qui se trouve être actuel), une extension de périphérique est l’emplacement principal de chaque pilote pour conserver l’état du périphérique et toutes les autres données spécifiques au périphérique dont le pilote a besoin. Par exemple, tout pilote qui implémente une routine CustomTimerDpc ou CustomDpc fournit généralement un stockage pour les objets du minuteur et/ou DPC définis par le noyau requis dans une extension de périphérique.

Chaque pilote disposant d’un ISR doit fournir un stockage pour un pointeur vers un ensemble d’objets d’interruption définis par le noyau, et la plupart des pilotes de périphérique stockent ce pointeur dans une extension de périphérique. Chaque pilote détermine la taille de l’extension de périphérique lorsqu’il crée un objet de périphérique, et chaque pilote définit le contenu et la structure de ses propres extensions de périphérique.

Les routines IoCreateDevice et IoCreateDeviceSecure du gestionnaire d’E/S allouent de la mémoire pour l’objet d’appareil et l’extension à partir du pool de mémoire sans pagination.

Chaque routine de pilote standard qui reçoit un IRP reçoit également un pointeur vers un objet de périphérique représentant l’appareil cible pour l’opération d’E/S demandée. Ces routines de pilotes peuvent accéder à l’extension de périphérique correspondante via ce pointeur. En règle générale, un pointeur DeviceObject est également un paramètre d’entrée vers l’ISR d’un pilote de niveau inférieur.

La figure suivante montre un ensemble représentatif de données définies par le pilote pour l’extension de périphérique d’un objet de périphérique de pilote de niveau inférieur. Un pilote de niveau supérieur ne fournit pas de stockage pour un pointeur d’objet d’interruption retourné par IoConnectInterrupt et transmis à KeSynchronizeExecution et IoDisconnectInterrupt. Toutefois, un pilote de niveau supérieur fournit un stockage pour les objets minuteur et DPC illustrés dans la figure suivante si le pilote a une routine CustomTimerDpc . Un pilote de niveau supérieur peut également fournir un stockage pour un verrou de rotation exécutif et une file d’attente de travail verrouillée.

diagramme illustrant un exemple d’extension de périphérique pour un pilote de niveau inférieur.

En plus de fournir un stockage pour un pointeur d’objet d’interruption, un pilote de périphérique de niveau inférieur doit fournir un stockage pour un verrou de rotation d’interruption si son ISR gère les interruptions pour deux ou plusieurs appareils sur des vecteurs différents ou s’il a plusieurs ISR. Pour plus d’informations sur l’inscription d’un ISR, consultez Inscription d’un ISR.

En règle générale, les pilotes stockent des pointeurs vers leurs objets d’appareil dans leurs extensions de périphérique, comme illustré dans la figure. Un pilote peut également conserver une copie de la liste des ressources pour l’appareil dans l’extension.

Un pilote de niveau supérieur stocke généralement un pointeur vers l’objet de périphérique du pilote inférieur suivant dans son extension de périphérique. Un pilote de niveau supérieur doit passer un pointeur vers l’objet de périphérique du pilote inférieur suivant vers IoCallDriver, après avoir configuré l’emplacement de la pile d’E/S du pilote inférieur suivant dans un IRP, comme expliqué dans Gestion des irps.

Notez également que tout pilote de niveau supérieur qui alloue des IRP pour les pilotes de niveau inférieur doit spécifier le nombre d’emplacements de pile que les nouveaux IRP doivent avoir. En particulier, si un pilote de niveau supérieur appelle IoMakeAssociatedIrp, IoAllocateIrp ou IoInitializeIrp, il doit accéder à l’objet d’appareil cible du pilote de niveau inférieur suivant pour lire sa valeur StackSize , afin de fournir le StackSize correct en tant qu’argument à ces routines de support.

Bien qu’un pilote de niveau supérieur puisse lire les données de l’objet de périphérique du pilote de niveau inférieur suivant via le pointeur retourné par IoAttachDeviceToDeviceStack, ce pilote doit suivre les instructions d’implémentation suivantes :

  • N’essayez jamais d’écrire des données dans l’objet de périphérique du pilote inférieur.

    Les seules exceptions à cette recommandation sont les systèmes de fichiers, qui définissent et effacent DO_VERIFY_VOLUME dans les indicateurs des objets de périphérique des pilotes de média amovible de niveau inférieur.

  • N’essayez jamais d’accéder à l’extension de périphérique du pilote inférieur pour les raisons suivantes :

    • Il n’existe aucun moyen sûr de synchroniser l’accès à une seule extension de périphérique entre deux pilotes.

    • Une paire de pilotes qui implémentent un tel schéma de communication par porte dérobée ne peut pas être mise à niveau individuellement, ne peut pas avoir un pilote intermédiaire inséré entre eux sans modifier la source de pilote existante et ne peut pas être recompilée et déplacée facilement d’une plateforme Windows à l’autre.

Pour préserver leur interopérabilité avec les pilotes de niveau inférieur d’une plateforme ou d’une version Windows à l’autre, les pilotes de niveau supérieur doivent réutiliser les IRP donnés ou créer de nouveaux IRP, et ils doivent utiliser IoCallDriver pour communiquer les demandes aux pilotes de niveau inférieur.