Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
L’appel du gestionnaire d’E/S à la routine de répartition d’un pilote est la première étape du traitement d’une requête d’E/S de l’appareil. La routine StartIo est la deuxième étape. Chaque pilote de périphérique avec une routine StartIo est susceptible d’appeler IoStartPacket à partir de ses routines DispatchRead et DispatchWrite , et généralement pour un sous-ensemble des codes de contrôle d’E/S qu’il prend en charge dans sa routine DispatchDeviceControl . La routine IoStartPacket ajoute l’IRP à la file d’attente d’appareils fournie par le système de l’appareil ou, si la file d’attente est vide, appelle immédiatement la routine StartIo du pilote pour traiter l’IRP.
Vous pouvez supposer que lorsque la routine StartIo d’un pilote est appelée, l’appareil cible n’est pas occupé. Cela est dû au fait que le gestionnaire d’E/S appelle StartIo dans deux circonstances ; l’une des routines de répartition du pilote vient d’appeler IoStartPacket et la file d’attente de l’appareil a été vide, ou la routine DpcForIsr du pilote effectue une autre requête et vient d’appeler IoStartNextPacket pour mettre en file d’attente l’IRP suivante.
Avant l’appel de la routine StartIo dans le pilote de périphérique de niveau supérieur, la routine de distribution du pilote doit avoir sondé et verrouillé la mémoire tampon de l’utilisateur, si nécessaire, pour configurer des adresses tampons mappées valides dans l'IRP mis en file d'attente pour la routine StartIo . Si un pilote de périphérique de niveau supérieur configure ses objets d’appareil pour les E/S directes (ou pour ni les E/S tampons ni les E/S directes), le pilote ne peut pas différer le verrouillage d’une mémoire tampon utilisateur à sa routine StartIo ; chaque routine StartIo est appelée dans un contexte de thread arbitraire à IRQL = DISPATCH_LEVEL.
Remarque
Toute mémoire tampon accessible par la routine StartIo d’un pilote doit être verrouillée ou allouée à partir de la mémoire résidente, de l’espace système et doit être accessible dans un contexte de thread arbitraire.
En règle générale, toute routine StartIo du pilote de périphérique de niveau inférieur est chargée d’appeler IoGetCurrentIrpStackLocation avec l’IRP d’entrée, puis d’effectuer le traitement spécifique à la requête nécessaire pour démarrer l’opération d’E/S sur son appareil. Le traitement spécifique à la demande peut inclure les éléments suivants :
Configuration ou mise à jour de toute information d'état concernant la requête actuelle que le pilote gère. Les informations d’état peuvent être stockées dans l’extension de périphérique de l’objet de périphérique cible ou ailleurs dans un pool non paginé alloué par le pilote.
Par exemple, si un pilote de périphérique gère un booléen InterruptExpected pour l’opération de transfert actuelle, sa routine StartIo pourrait définir cette variable sur TRUE. Si le pilote conserve un compteur de délai d’attente pour l’opération actuelle, sa routine StartIo peut configurer cette valeur, ou la routine StartIo peut mettre en file d’attente la routine CustomTimerDpc du pilote.
Si la routine StartIo partage l’accès aux informations d’état ou aux ressources matérielles avec d’autres routines de pilote, les informations d’état ou la ressource doivent être protégées par un verrou de rotation. (Voir Spinlocks.)
Si la routine StartIo partage l’accès aux informations d’état ou aux ressources avec la routine InterruptService du pilote, StartIo doit utiliser KeSynchronizeExecution pour appeler une routine SynchCritSection qui accède à l’état ou aux informations de ressource. (Voir Utilisation des sections critiques.)
Affectation d’un numéro de séquence à l’IRP si le pilote doit consigner une erreur d’E/S d’appareil lors du traitement de l’IRP.
Pour plus d’informations, consultez Erreurs de journalisation .
Si nécessaire, traduire les paramètres dans l’emplacement de la pile d’E/S du pilote en valeurs spécifiques à l’appareil.
Par exemple, un pilote de disque peut avoir besoin de calculer le secteur de départ ou le décalage d’octets vers l’adresse du disque physique pour une opération de transfert, et si la longueur demandée du transfert traversera une limite de secteur particulière ou dépassera la capacité de transfert de son appareil physique.
Si le pilote gère un périphérique de média amovible, vérifiez les modifications de média avant de programmer l'appareil pour les I/O et de notifier son système de fichiers sous-jacent si le média a changé.
Pour plus d’informations, consultez prise en charge des supports amovibles.
Si l’appareil utilise le DMA, vérifiez si la longueur demandée (nombre d’octets à transférer, trouvée dans la pile des E/S du pilote de l'IRP) doit être fractionnée en opérations de transfert partiel, comme expliqué dans les techniques d’entrée/sortie, en supposant qu’un pilote de niveau supérieur étroitement couplé ne pré-segmente pas les transferts importants pour le pilote de périphérique.
La routine StartIo d’un tel pilote de périphérique peut également être responsable de l’appel de KeFlushIoBuffers et, si le pilote utilise la DMA basée sur des paquets, pour appeler AllocateAdapterChannel avec la routine AdapterControl du pilote.
Pour plus d’informations, consultez Objets d’adaptateur et DMA et Maintenance de la cohérence du cache.
Si l’appareil utilise le PIO, associez l’adresse virtuelle de base de la mémoire tampon, décrite dans l’IRP à Irp-MdlAddress>, à une adresse d’espace système avec MmGetSystemAddressForMdlSafe.
Pour les demandes de lecture, la routine StartIo du pilote de périphérique peut être responsable de l’appel de KeFlushIoBuffers avant que les opérations PIO ne commencent. Pour plus d’informations, consultez Maintenance de la cohérence du cache .
Si un pilote non-WDM utilise un objet de contrôleur, appelez IoAllocateController pour inscrire sa routine ControllerControl .
Si le pilote gère les IRP annulables, vérifiez si l’IRP d’entrée a déjà été annulé.
Si un IRP d’entrée peut être annulé avant de se terminer, la routine StartIo doit appeler IoSetCancelRoutine avec l’IRP et le point d’entrée de la routine Cancel du pilote. La routine StartIo doit acquérir le verrou d'annulation du spin lock pour son appel à IoSetCancelRoutine. Vous pouvez également utiliser IoSetStartIoAttributes pour définir l’attribut NonCancelable de la routine StartIo sur TRUE. Cela empêche le système d’essayer d’annuler un IRP qui a été passé à StartIo par un appel à IoStartPacket.
En règle générale, un pilote qui utilise des E/S mis en mémoire tampon a une routine StartIo plus simple que celle qui utilise des E/S directes. Les pilotes qui utilisent des E/S mis en mémoire tampon transfèrent de petites quantités de données pour chaque demande de transfert, tandis que ceux qui utilisent des E/S directes (que ce soit DMA ou PIO) transfèrent de grandes quantités de données vers ou depuis des mémoires tampons verrouillées qui peuvent couvrir les limites de page physiques dans la mémoire système.
Les pilotes de niveau supérieur superposés au-dessus des pilotes de périphériques physiques configurent généralement leurs objets d’appareil pour qu’ils correspondent à ceux de leurs pilotes de périphérique respectifs. Toutefois, un pilote de niveau supérieur, en particulier un pilote de système de fichiers, peut configurer des objets d’appareil pour ni les E/S directes ni les E/S mises en mémoire tampon.
Les pilotes qui configurent leurs objets d’appareil pour les E/S mises en mémoire tampon peuvent s’appuyer sur le gestionnaire d’E/S pour transmettre des mémoires tampons valides dans tous les IRPs qu’il envoie au pilote. Les pilotes de niveau inférieur qui configurent des objets d’appareil pour les E/S directes peuvent s’appuyer sur le pilote de niveau le plus élevé de leur chaîne pour passer des mémoires tampons valides dans tous les IRPs envoyés par tous les pilotes intermédiaires au pilote de périphérique de niveau inférieur sous-jacent.
Utilisation des E/S mises en mémoire tampon dans les routines StartIo
Si la routine DispatchRead, DispatchWrite ou DispatchDeviceControl d’un pilote détermine qu’une demande est valide et appelle IoStartPacket, le gestionnaire d’E/S appelle la routine StartIo du pilote pour traiter immédiatement l’IRP si la file d’attente de l’appareil est vide. Si la file d’attente n’est pas vide, IoStartPacket met en file d’attente l’IRP. Par la suite, un appel à IoStartNextPacket à partir de la routine DpcForIsr ou CustomDpc du pilote entraîne le gestionnaire d'E/S à retirer l'IRP de la file d'attente et à appeler la routine StartIo du pilote.
La routine StartIo appelle IoGetCurrentIrpStackLocation et détermine quelle opération doit être effectuée pour satisfaire la requête. Il prétraite l’IRP de toute façon nécessaire avant de programmer l’appareil physique pour effectuer la demande d’E/S.
Si l’accès à l’appareil physique (ou à l’extension de l’appareil) doit être synchronisé avec une routine InterruptService , la routine StartIo doit appeler une routine SynchCritSection pour effectuer la programmation nécessaire de l’appareil. Pour plus d’informations, consultez Utilisation des sections critiques.
Un pilote de périphérique physique qui utilise des E/S mis en mémoire tampon transfère les données vers ou à partir d’une mémoire tampon d’espace système, allouée par le gestionnaire d’E/S, que le pilote trouve dans chaque IRP sur Irp-AssociatedIrp.SystemBuffer>.
Utilisation d’E/S directes dans les routines StartIo
Si la routine DispatchRead, DispatchWrite ou DispatchDeviceControl d’un pilote détermine qu’une demande est valide et appelle IoStartPacket, le gestionnaire d’E/S appelle la routine StartIo du pilote pour traiter immédiatement l’IRP si la file d’attente de l’appareil est vide. Si la file d’attente n’est pas vide, IoStartPacket met en file d’attente l’IRP. Par la suite, un appel à IoStartNextPacket à partir de la routine DpcForIsr ou CustomDpc du pilote entraîne le gestionnaire d’E/S à retirer l'IRP de la file d’attente et à appeler la routine StartIo du pilote.
La routine StartIo appelle IoGetCurrentIrpStackLocation et détermine quelle opération doit être effectuée pour satisfaire la requête. Il prétraite l’IRP de toutes les manières nécessaires, par exemple en fractionnant une demande de transfert DMA volumineuse en plages de transfert partielles et en enregistrant l’état concernant la longueur d’une demande de transfert entrante qui doit être fractionnée. Ensuite, il programme l’appareil physique pour effectuer la demande d’E/S.
Si l’accès à l’appareil physique (ou à l’extension de périphérique) doit être synchronisé avec l’ISR du pilote, la routine StartIo doit utiliser une routine SynchCritSection fournie par le pilote pour effectuer la programmation nécessaire. Pour plus d’informations, consultez Utilisation des sections critiques.
Tout pilote qui utilise des E/S directes lit ou écrit des données à partir d’une mémoire tampon verrouillée, décrite par une liste mdL (memory descriptor list), que le pilote trouve dans l’IRP sur Irp-MdlAddress>. Ce pilote utilise couramment les E/S mises en mémoire tampon pour les demandes de contrôle d’appareil. Pour plus d’informations, consultez Gestion des demandes de contrôle d’E/S dans les routines StartIo.
Le type MDL est un type opaque auquel les pilotes n’accèdent pas directement. Au lieu de cela, les pilotes qui utilisent l'entrée-sortie programmée (PIO) remappent les tampons d'espace utilisateur en appelant MmGetSystemAddressForMdlSafe avec >Irp-MdlAddress comme paramètre. Les pilotes qui utilisent le DMA passent également Irp-MdlAddress> pour les routines de prise en charge pendant leurs opérations de transfert, afin que les adresses de mémoire tampon soient remappées sur des plages logiques pour leurs appareils.
À moins qu’un pilote de niveau supérieur étroitement couplé fractionne les demandes de transfert DMA volumineuses pour le pilote de périphérique sous-jacent, la routine StartIo du pilote de périphérique de niveau inférieur doit fractionner chaque demande de transfert supérieure à celle de son appareil peut gérer dans une seule opération de transfert. Les pilotes qui utilisent la DMA du système doivent fractionner les demandes de transfert trop volumineuses pour que le contrôleur DMA du système ou leurs appareils puissent les gérer dans une seule opération de transfert.
Si l’appareil est un périphérique DMA subordonné, son pilote doit synchroniser les transferts via un contrôleur DMA système avec un objet adaptateur alloué au pilote, représentant le canal DMA et une routine AdapterControl fournie par le pilote. Le pilote d’un périphérique DMA maître de bus doit également utiliser un objet adaptateur alloué par le pilote pour synchroniser ses transferts et fournir une routine AdapterControl s'il utilise la prise en charge DMA basée sur les paquets du système ou une routine AdapterListControl s'il utilise la prise en charge scatter/gather du système.
Selon la conception du pilote, il peut synchroniser les opérations de transfert et de contrôle d’appareil sur un appareil physique avec un objet contrôleur et fournir une routine ControllerControl .
Pour plus d’informations, consultez Objets d’adaptateur et objets DMA et Contrôleur .
Gestion des demandes de contrôle d’E/S dans les routines StartIo
En général, seul un sous-ensemble de demandes de contrôle d’E/S d’appareil est transmis à partir de la routine DispatchDeviceControl ou DispatchInternalDeviceControl d’un pilote pour un traitement ultérieur par la routine StartIo du pilote. La routine StartIo du pilote doit uniquement gérer les demandes de contrôle d’appareil valides qui nécessitent des modifications d’état de l’appareil ou retournent des informations volatiles sur l’état actuel de l’appareil.
Chaque nouveau pilote doit prendre en charge le même ensemble de codes de contrôle d’E/S publics que tous les autres pilotes pour le même type d’appareil. Le système définit les codes de contrôle d’E/S publics spécifiques au type d’appareil pour les demandes IRP_MJ_DEVICE_CONTROL comme requêtes mises en mémoire tampon.
Par conséquent, les pilotes de périphériques physiques effectuent des transferts de données vers ou à partir d’une mémoire tampon d’espace système que chaque pilote trouve dans l’IRP sur Irp-AssociatedIrp.SystemBuffer> pour les demandes de contrôle d’appareil. Même les pilotes qui configurent leurs objets d’appareil pour les E/S directes utilisent des E/S mises en mémoire tampon pour satisfaire les demandes de contrôle d’appareil avec des codes de contrôle d’E/S publics.
La définition de chaque code de contrôle d’E/S détermine si les données transférées pour cette demande sont mises en mémoire tampon. Les codes de contrôle d’E/S définis en privé pour les requêtes IRP_MJ_INTERNAL_DEVICE_CONTROL spécifiques au pilote peuvent définir un code avec une méthode mise en mémoire tampon, une méthode directe ou ni l'une ni l'autre. En règle générale, tout code de contrôle E/S défini en privé ne devrait pas être défini avec de méthode si un pilote de niveau supérieur étroitement couplé doit allouer une mémoire tampon pour cette demande.
Programmation de l’appareil pour les opérations d’E/S
En règle générale, la routine StartIo dans un pilote de périphérique de niveau le plus bas doit synchroniser l’accès à n’importe quelle mémoire ou périphérique qu’il inscrit auprès de l’ISR du pilote à l’aide de KeSynchronizeExecution pour appeler une routine SynchCritSection fournie par le pilote. La routine StartIo du pilote utilise la routine SynchCritSection pour programmer réellement l’appareil physique pour les E/S au niveau de DIRQL. Pour plus d’informations, consultez Utilisation des sections critiques.
Avant d’appeler KeSynchronizeExecution, la routine StartIo doit effectuer tout prétraitement nécessaire pour la requête. Le prétraitement peut inclure le calcul d’une plage de transfert partielle initiale et l’enregistrement des informations d’état concernant la demande d’origine pour d’autres routines de driver.
Si un pilote de périphérique utilise DMA, sa routine StartIo appelle généralement AllocateAdapterChannel avec une routine AdapterControl fournie par le pilote. Dans ces circonstances, la routine StartIo reporte la responsabilité de la programmation de l’appareil physique à la routine AdapterControl . À son tour, il peut appeler KeSynchronizeExecution pour qu'une routine SynchCritSection fournie par le pilote programme l'appareil pour un transfert DMA.