Interruptions matérielles, ISR et synchronisation dans un driver WDM

Ce cours dédiée au développement de drivers en kernel mode sans Framework

Moderator: Rick

Post Reply
Hydraxx
Site Admin
Posts: 144
Joined: Mon Jan 12, 2026 4:04 pm
Location: France
Contact:

Interruptions matérielles, ISR et synchronisation dans un driver WDM

Post by Hydraxx »

Interruptions matérielles, ISR et synchronisation dans un driver WDM

Introduction

Un périphérique matériel ne doit pas obliger le processeur à vérifier constamment son état. Il peut signaler un événement au processeur en générant une interruption matérielle.

Le driver fournit alors une routine appelée ISR : Interrupt Service Routine.

1. Pourquoi les interruptions existent

Sans interruption, le processeur devrait faire du polling :

Code: Select all

while (!(READ_REGISTER_ULONG(status) & READY))
{
    // attendre
}
Avec une interruption :

Code: Select all

CPU lance l'opération
      |
      v
périphérique travaille
      |
      v
interruption
      |
      v
ISR du driver
2. Connecter une interruption

Dans les anciens drivers WDM, l'API historique est :

IoConnectInterrupt

La connexion crée un objet KINTERRUPT et associe l'ISR du driver à l'interruption.

Exemple conceptuel :

Code: Select all

PKINTERRUPT interruptObject = NULL;

status = IoConnectInterrupt(
    &interruptObject,
    IsrRoutine,
    DeviceExtension,
    NULL,
    vector,
    irql,
    irql,
    interruptMode,
    shareVector,
    affinity,
    FALSE
);
Sur des Windows modernes, les variantes Ex et les abstractions WDF sont souvent préférées, mais le principe reste identique.

3. Prototype d'une ISR

Code: Select all

BOOLEAN IsrRoutine(
    PKINTERRUPT Interrupt,
    PVOID ServiceContext
);
La valeur de retour indique si le driver a reconnu l'interruption comme provenant de son périphérique.

Code: Select all

return TRUE;  // interruption reconnue
return FALSE; // pas notre périphérique
4. Vérifier si l'interruption appartient au périphérique

Une interruption peut être partagée. L'ISR doit donc lire un registre de statut du périphérique.

Code: Select all

ULONG status = READ_REGISTER_ULONG(devExt->StatusRegister);

if (!(status & DEVICE_INTERRUPT_PENDING))
    return FALSE;
Règle importante

Une ISR ne doit pas retourner TRUE simplement parce qu'elle a été appelée. Elle doit confirmer que le matériel concerné a réellement demandé l'interruption.

5. Acquitter l'interruption

De nombreux périphériques exigent que le driver efface ou acquitte le bit d'interruption.

Code: Select all

WRITE_REGISTER_ULONG(
    devExt->InterruptStatus,
    INTERRUPT_ACK
);
Sinon, le périphérique peut immédiatement réinterrompre le processeur.

6. L'ISR doit rester très courte

Une ISR s'exécute à un IRQL élevé. Elle bloque temporairement certaines autres activités du système.

Une bonne ISR fait généralement seulement :
  • Vérifier la source de l'interruption.
  • Acquitter le matériel.
  • Lire ou sauvegarder quelques informations urgentes.
  • Déclencher un DPC.
  • Retourner rapidement.
Elle ne doit pas effectuer un traitement long ou bloquant.

7. IRQL et ISR

L'ISR s'exécute au DIRQL correspondant à l'interruption.

À ce niveau :
  • Pas d'attente bloquante.
  • Pas d'accès à de la mémoire paginable.
  • Le code utilisé par l'ISR doit résider en mémoire non paginée.
  • Les opérations doivent être courtes et déterministes.
8. Données partagées entre ISR et reste du driver

L'ISR peut partager des variables avec un DPC ou d'autres routines du driver.

Exemple :

Code: Select all

typedef struct _DEVICE_EXTENSION
{
    volatile BOOLEAN InterruptPending;
    volatile ULONG BytesTransferred;
    PKINTERRUPT InterruptObject;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
Une simple variable volatile ne suffit pas toujours pour assurer la synchronisation correcte entre contextes.

9. KeSynchronizeExecution

Pour exécuter une routine en synchronisation avec l'ISR :

Code: Select all

BOOLEAN result = KeSynchronizeExecution(
    devExt->InterruptObject,
    SynchronizeRoutine,
    context
);
La routine synchronisée :

Code: Select all

BOOLEAN SynchronizeRoutine(PVOID Context)
{
    PDEVICE_EXTENSION devExt =
        (PDEVICE_EXTENSION)Context;

    // accès synchronisé aux données partagées
    return TRUE;
}
Cela permet d'éviter qu'une ISR modifie simultanément certaines données critiques.

10. Spin lock d'interruption

Le système associe une synchronisation interne à l'objet d'interruption. Les routines prévues permettent de coordonner correctement le code s'exécutant au niveau du driver avec l'ISR.

Il ne faut pas utiliser un mécanisme bloquant classique depuis une ISR.

11. Level-triggered et edge-triggered

Deux grandes familles existent :
  • Level-sensitive : l'interruption reste active tant que la condition matérielle existe.
  • Latched / edge-triggered : l'événement est capturé lors d'une transition.
Le mode est fourni avec les ressources d'interruption et doit correspondre au matériel.

12. Déconnecter l'interruption

Lors de l'arrêt ou de la suppression du périphérique :

Code: Select all

if (devExt->InterruptObject)
{
    IoDisconnectInterrupt(devExt->InterruptObject);
    devExt->InterruptObject = NULL;
}
Le matériel doit idéalement être désactivé avant de déconnecter l'interruption, afin d'éviter qu'il continue à en générer.

13. Exemple conceptuel d'ISR

Code: Select all

BOOLEAN IsrRoutine(PKINTERRUPT Interrupt, PVOID Context)
{
    UNREFERENCED_PARAMETER(Interrupt);

    PDEVICE_EXTENSION devExt =
        (PDEVICE_EXTENSION)Context;

    ULONG status =
        READ_REGISTER_ULONG(devExt->StatusRegister);

    if (!(status & INT_PENDING))
        return FALSE;

    WRITE_REGISTER_ULONG(
        devExt->StatusRegister,
        INT_ACK
    );

    devExt->InterruptPending = TRUE;

    IoRequestDpc(
        devExt->DeviceObject,
        NULL,
        NULL
    );

    return TRUE;
}
14. Résumé

Code: Select all

Périphérique
    |
    v
Interruption
    |
    v
ISR
    |
    +--> vérifier la source
    +--> acquitter le matériel
    +--> sauvegarder l'état minimal
    +--> demander un DPC
    |
    v
retour rapide
Le DPC est le mécanisme naturel pour déplacer le traitement lourd hors de l'ISR.

Who is online

Users browsing this forum: No registered users and 1 guest