Utilisation des routines de service d’interruption de Passive-Level

À compter de Windows 8, un pilote peut utiliser la routine IoConnectInterruptEx pour inscrire une routine InterruptService (ISR) de niveau passif. Lorsque l’interruption associée se produit, le gestionnaire d’interruptions du noyau planifie l’exécution de cette routine à IRQL = PASSIVE_LEVEL. Un ISR peut avoir besoin de s’exécuter au niveau passif s’il peut accéder aux registres matériels d’un appareil uniquement par le biais de demandes d’E/S. Un ISR de niveau passif peut envoyer de manière synchrone une demande d’E/S à un appareil et le bloquer jusqu’à ce que la demande soit terminée.

Inscription d’un isr Passive-Level

Le paramètre input vers IoConnectInterruptEx est un pointeur vers une structure IO_CONNECT_INTERRUPT_PARAMETERS . Pour inscrire un ISR de niveau passif, définissez le membre Version de cette structure sur CONNECT_FULLY_SPECIFIED ou CONNECT_LINE_BASED. Si Version = CONNECT_FULLY_SPECIFIED, définissez le membre Irql sur PASSIVE_LEVEL, le membre SynchronizeIrql sur PASSIVE_LEVEL et le membre SpinLock sur NULL. Si Version = CONNECT_LINE_BASED, définissez SynchronizeIrql = PASSIVE_LEVEL et SpinLock = NULL.

Si l’objet d’interruption spécifie un ISR de niveau passif, la routine KeSynchronizeExecution utilise un objet d’événement de synchronisation du noyau au lieu d’un verrou de rotation pour synchroniser l’exécution de la routine SynchCritSection avec l’ISR.

Cet objet d’événement est alloué par la routine IoConnectInterruptEx dans l’appel qui inscrit l’ISR de niveau passif. L’appelant ne doit pas fournir de verrou tournant dans cet appel. (Autrement dit, l’appelant doit définir le membre SpinLock de la structure IO_CONNECT_INTERRUPT_PARAMETERS sur NULL si l’ISR doit s’exécuter au niveau passif.) Sinon, IoConnectInterruptEx échoue et retourne l’erreur status STATUS_INVALID_PARAMETER.

Les routines KeAcquireInterruptSpinLock et KeReleaseInterruptSpinLock provoquent un bogue case activée si l’ISR de l’objet d’interruption fourni s’exécute à IRQL = PASSIVE_LEVEL.

Appareils qui nécessitent la gestion des interruptions Passive-Level

Pour un appareil mappé en mémoire qui signale une demande d’interruption déclenchée au niveau, l’ISR de l’appareil est généralement appelé au niveau DIRQL à partir du gestionnaire d’interruptions du noyau. L’ISR manipule les registres matériels dans l’appareil pour désactiver l’interruption.

Toutefois, un ISR peut avoir besoin de s’exécuter sur IRQL = PASSIVE_LEVEL si l’appareil associé signale une demande d’interruption déclenchée au niveau, mais que les registres matériels de l’appareil ne sont pas accessibles directement à partir d’un ISR appelé au niveau DIRQL à partir du gestionnaire d’interruptions du noyau. Par exemple, les registres d’appareils peuvent ne pas être mappés en mémoire, ou l’ISR peut être temporairement bloqué pendant un accès au registre.

À compter de Windows 8, un pilote peut inscrire un ISR passif. Lorsque l’interruption se produit, le gestionnaire d’interruptions du noyau planifie l’exécution de l’ISR à IRQL = PASSIVE_LEVEL. Avant le retour du gestionnaire, il doit faire taire l’interruption dans le contrôleur d’interruption (ou contrôleur GPIO). Si un appareil signale une interruption déclenchée par le périmètre, le gestionnaire efface l’interruption dans le contrôleur d’interruption. Si l’appareil signale une interruption déclenchée au niveau, le gestionnaire masque temporairement l’interruption dans le contrôleur d’interruption ; après l’exécution de l’ISR, le noyau démasque l’interruption.

Exemple

Un exemple d’appareil qui peut nécessiter un ISR de niveau passif est un appareil capteur connecté à un bus série basse consommation, tel que I²C. À compter de Windows 8, la prise en charge d’I²C et d’autres bus périphériques simples (SPB) est assurée par l’extension SPB Framework (SpbCx).

Pour accéder aux registres de l’appareil de capteur connecté à I²C, le pilote de capteur envoie au périphérique de capteur une demande d’E/S, qui est gérée conjointement par SpbCx et par le pilote du contrôleur pour le bus. Pour effectuer l’opération demandée, le contrôleur SPB doit transférer des données en série sur le bus. Ce transfert est relativement lent et ne peut pas être effectué dans les contraintes de temps d’un ISR qui s’exécute au niveau de DIRQL. Toutefois, un ISR de niveau passif peut envoyer la requête d’E/S de manière synchrone, puis bloquer jusqu’à ce que la demande se termine.

L’ISR de niveau passif dans cet exemple peut être bloqué plus longtemps si le contrôleur de bus I²C est désactivé lorsque l’ISR envoie la demande d’E/S à l’appareil d’interruption. Dans ce cas, le contrôleur doit terminer la transition vers l’état d’alimentation D0 avant de pouvoir transférer les données sur le bus.

Contrairement à un bus tel que PCI, le bus I²C dans cet exemple ne fournit aucun moyen spécifique au bus de transmettre les demandes d’interruption des périphériques au processeur. Au lieu de cela, le périphérique de capteur peut signaler une interruption à une broche sur un périphérique de contrôleur GPIO, qui relaie ensuite la demande d’interruption au processeur. Pour plus d’informations, consultez Interruptions GPIO.

En règle générale, les registres matériels d’un contrôleur GPIO sont mappés en mémoire et sont accessibles au niveau de DIRQL par le gestionnaire d’interruptions du noyau. Lorsque le périphérique de capteur provoque une interruption, le gestionnaire doit la faire taire en manipulant les bits d’interruption dans les registres du contrôleur GPIO.

Pour une interruption déclenchée par un niveau, le gestionnaire d’interruptions du noyau masque la demande d’interruption au niveau de la broche GPIO, puis planifie l’ISR du périphérique de capteur pour qu’il s’exécute au niveau passif. L’ISR doit effacer la demande d’interruption de l’appareil de capteur. Une fois l’ISR retourné, le noyau démasque la demande d’interruption au niveau de la broche GPIO.

Pour une interruption déclenchée en périphérie, le gestionnaire d’interruption du noyau efface la demande d’interruption au niveau de la broche GPIO, puis planifie l’ISR du périphérique de capteur pour qu’il s’exécute au niveau passif.

Routines de travail

Dans l’appel à IoConnectInterruptEx, un pilote a la possibilité de fractionner le traitement de l’interruption entre un ISR de niveau passif et une routine worker. En règle générale, l’ISR doit effectuer le traitement initial de l’interruption (par exemple, faire taire une interruption déclenchée par un niveau) et différer le traitement supplémentaire au worker. Bien que l’ISR et le worker s’exécutent tous les deux au niveau passif, l’ISR s’exécute à une priorité relativement élevée et peut retarder d’autres tâches à priorité élevée. Ces tâches peuvent inclure des ISR passifs pour les nouvelles interruptions.

Dans de rares cas, une interruption peut nécessiter si peu de traitement que l’ISR de niveau passif peut effectuer tout le traitement de l’interruption, et aucune routine de travail n’est requise.

Pour plus d’informations sur l’utilisation des ISR de niveau passif dans les pilotes KMDF, consultez Prise en charge des interruptions de Passive-Level.