Partager via


Définition des codes de contrôle d’E/S

Cet article explique comment créer un code de contrôle d’E/S unique (IOCTL). Les IOCTL peuvent être :

  • Les IOCTL publics, qui sont généralement définis par le système et documentés par Microsoft.
  • Les IOCTL privés, qui sont généralement destinés à être utilisés exclusivement par les composants logiciels d’un fournisseur pour communiquer entre eux. Ils sont généralement définis dans le fichier d’en-tête d’un fournisseur et ne sont pas documentés par Microsoft.

Structure d'un IOCTL

Un IOCTL est une valeur 32 bits qui se compose de plusieurs champs. La figure suivante illustre la disposition en mode bit d’un IOCTL :

Diagramme illustrant la disposition au niveau du bit d’un code de contrôle i/o 32 bits.

Chaque champ du IOCTL a un objectif spécifique, comme décrit dans le tableau suivant :

Terrain Bits dans l'IOCTL Descriptif
Commun 31 Les fournisseurs doivent définir ce bit lorsqu’ils utilisent une valeur attribuée par le fournisseur pour DeviceType.
DeviceType 16-30 Identifie le type d’appareil. Cette valeur doit correspondre à la valeur définie dans le membre DeviceType de la structure DEVICE_OBJECT du pilote. Les fournisseurs doivent utiliser une valeur comprise entre 32768 et 65535 (0x8000 via 0xffff) et définir le bit commun . Les valeurs 0 à 32767 (0x0000 via 0x7fff) sont réservées à Microsoft. Pour plus d’informations, consultez Spécification des types d’appareils.
Accès 14-15 Indique le type d’accès qu’un appelant doit demander lors de l’ouverture de l’objet de fichier qui représente l’appareil (voir IRP_MJ_CREATE). Le gestionnaire d’E/S crée des IRPs et appelle le pilote avec un IOCTL particulier uniquement si l’appelant a demandé les droits d’accès spécifiés. Ce champ est spécifié à l’aide des constantes définies par le système suivantes : FILE_ANY_ACCESS, FILE_READ_DATA et FILE_WRITE_DATA.
Personnalisée 13 Lorsqu’il est défini, indique que le IOCTL est un IOCTL défini par le fournisseur.
Fonction 2-12 Code unique pour le pilote qui identifie la fonction à exécuter. Pour un IOCTL créé par le fournisseur, utilisez une valeur 2048 à 4095 (0x800 via 0xfff) et définissez le bit personnalisé . Les valeurs inférieures à 2048 (0x000 via 0x7ff) sont réservées à Microsoft.
Méthode 0-1 Indique comment le système doit transmettre des données entre l’appelant de DeviceIoControl (ou IoBuildDeviceIoControlRequest) et le pilote qui gère l’IRP. Pour plus d’informations, consultez Conseils pour définir les bits de méthode.

Macro permettant de définir des codes de contrôle d’E/S

Utilisez la macro CTL_CODE fournie par le système pour définir de nouveaux codes de contrôle d’E/S. Cette macro est définie dans devioctl.h comme suit :

#define CTL_CODE( DeviceType, Function, Method, Access ) (                 \
    ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \
)

Consultez la section précédente pour obtenir une description de DeviceType, Function, Method et Access.

Gardez à l’esprit les règles suivantes lors de la définition de nouveaux codes de contrôle d’E/S :

La définition d’un nouveau code IOCTL, qu’il soit destiné à être utilisé avec des requêtes IRP_MJ_DEVICE_CONTROL ou IRP_MJ_INTERNAL_DEVICE_CONTROL , utilise le format suivant :

#define IOCTL_Device_Function CTL_CODE(DeviceType, Function, Method, Access)

Choisissez un nom de constante descriptive pour le IOCTL, sous la forme IOCTL_Device_Function, où l’appareil indique le type d’appareil et la fonction indique l’opération. Par exemple, la constante IOCTL_VIDEO_ENABLE_CURSOR fournie par le système utilise « VIDEO » pour l’appareil et « ENABLE_CURSOR » pour la fonction.

Conseils pour définir les bits d’accès

Lors de la définition d’un nouveau IOCTL, vous devez choisir une valeur pour le champ Bit Access qui indique le type d’accès qu’un appelant doit demander lors de l’ouverture de l’objet de fichier qui représente l’appareil. Le gestionnaire d’E/S crée des IRPs et appelle le pilote avec un IOCTL particulier uniquement si l’appelant a demandé les droits d’accès spécifiés.

L’accès est spécifié à l’aide des constantes définies par le système suivantes :

  • FILE_ANY_ACCESS

    Le gestionnaire d’E/S envoie l’IRP pour tout appelant qui possède un handle vers l’objet de fichier représentant l’objet de périphérique cible. Avant de spécifier FILE_ANY_ACCESS pour un nouveau code IOCTL, vous devez être absolument certain que l’autorisation d’un accès illimité à votre appareil ne crée pas de chemin d’accès possible pour que les utilisateurs malveillants puissent compromettre le système.

  • Données_Lecture_Fichier

    Le gestionnaire d’E/S envoie l’IRP uniquement pour un appelant disposant de droits d’accès en lecture, ce qui permet au pilote de périphérique sous-jacent de transférer des données de l’appareil vers la mémoire système.

  • FILE_WRITE_DATA

    Le gestionnaire d’E/S envoie l’IRP uniquement pour un appelant disposant de droits d’accès en écriture, ce qui permet au pilote de périphérique sous-jacent de transférer des données de la mémoire système vers son appareil.

FILE_READ_DATA et FILE_WRITE_DATA peuvent être combinés avec l’opérateur OU si l’appelant doit avoir à la fois les droits d’accès en lecture et en écriture.

Certains codes de contrôle d’E/S définis par le système ont une valeur d’accès de FILE_ANY_ACCESS, ce qui permet à l’appelant d’envoyer l'IOCTL particulier, quel que soit l’accès accordé au périphérique. Des exemples incluent des codes de contrôle d’E/S envoyés aux pilotes d’appareils exclusifs.

D’autres codes de contrôle d’E/S définis par le système nécessitent que l’appelant dispose de droits d’accès en lecture, de droits d’accès en écriture ou des deux. Par exemple, la définition suivante du IOCTL_DISK_SET_PARTITION_INFO IOCTL public montre que cette demande d’E/S peut être envoyée à un pilote uniquement si l’appelant dispose à la fois de droits d’accès en lecture et en écriture :

#define IOCTL_DISK_SET_PARTITION_INFO\
        CTL_CODE(IOCTL_DISK_BASE, 0x008, METHOD_BUFFERED,\
        FILE_READ_DATA | FILE_WRITE_DATA)

Les pilotes peuvent utiliser IoValidateDeviceIoControlAccess pour effectuer une vérification d’accès plus stricte que celle fournie par les bits d’accès d’un IOCTL.

Conseils pour définir les bits de méthode

Lors de la définition d’un nouveau IOCTL, vous devez choisir une valeur pour le champ Bit Method qui indique comment le système doit transmettre des données entre l’appelant de DeviceIoControl (ou IoBuildDeviceIoControlRequest) et le pilote qui gère l’IRP.

Utilisez l’une des constantes définies par le système suivantes pour définir le champ Méthode .

  • METHOD_BUFFERED

    Spécifie la méthode d’E/S mise en mémoire tampon , généralement utilisée pour transférer de petites quantités de données par requête. La plupart des codes de contrôle d’E/S pour les pilotes d’appareil et intermédiaire utilisent cette valeur.

    Pour plus d’informations sur la façon dont le système spécifie des mémoires tampons de données pour METHOD_BUFFERED codes de contrôle d’E/S, consultez Descriptions des mémoires tampons pour les codes de contrôle d’E/S.

    Pour plus d’informations sur les E/S mises en mémoire tampon, consultez Utilisation des E/S mises en mémoire tampon.

  • METHOD_IN_DIRECT ou METHOD_OUT_DIRECT

    Spécifie la méthode d’E/S directe , généralement utilisée pour la lecture ou l’écriture de grandes quantités de données à l’aide de DMA ou piO qui doivent être transférées rapidement.

    • Spécifiez METHOD_IN_DIRECT si l’appelant de DeviceIoControl ou IoBuildDeviceIoControlRequest transmet les données au pilote.

    • Spécifiez METHOD_OUT_DIRECT si l’appelant de DeviceIoControl ou IoBuildDeviceIoControlRequest reçoit les données du pilote.

    Pour plus d’informations sur la façon dont le système spécifie des mémoires tampons de données pour METHOD_IN_DIRECT et METHOD_OUT_DIRECT codes de contrôle d’E/S, consultez Descriptions des tampons pour les codes de contrôle d’E/S.

    Pour plus d’informations sur les E/S directes, consultez Utilisation d’E/S directes.

  • METHOD_NEITHER

    Spécifie que la méthode d’E/S n’est pas mise en mémoire tampon ni directe. Le gestionnaire d’E/S ne fournit aucune mémoire tampon système ni MDL. L’IRP fournit les adresses virtuelles en mode utilisateur des mémoires tampons d’entrée et de sortie spécifiées à DeviceIoControl ou IoBuildDeviceIoControlRequest, sans les valider ni les mapper.

    Pour plus d’informations sur la façon dont le système spécifie des mémoires tampons de données pour les codes de contrôle d’E/S METHOD_NEITHER, consultez Descriptions des mémoires tampons pour les codes de contrôle d’E/S.

    Cette méthode ne peut être utilisée que s'il est garanti que le pilote s'exécute dans le contexte du thread à l'origine de la requête de contrôle d'entrée/sortie. Seul un pilote en mode noyau de niveau supérieur est garanti pour répondre à cette condition. Par conséquent, METHOD_NEITHER est rarement utilisé pour les IOCTL passés aux pilotes de périphérique de bas niveau.

    Avec cette méthode, le pilote de niveau supérieur :

    • Doit déterminer s’il faut configurer un accès mis en mémoire tampon ou directe aux données utilisateur lors de la réception de la demande.
    • Doit éventuellement verrouiller la mémoire tampon utilisateur.
    • Doit encapsuler son accès à la mémoire tampon utilisateur dans un gestionnaire d’exceptions structurées (voir Gestion des exceptions).

    Dans le cas contraire, l’appelant en mode utilisateur d’origine peut modifier les données mises en mémoire tampon avant que le pilote puisse l’utiliser, ou l’appelant peut être échangé comme le pilote accède à la mémoire tampon utilisateur.

    Pour plus d’informations, consultez Utilisation d’E/S sans mémoire tampon ni d’E/S directes.

Autres macros utiles

Les macros suivantes sont utiles pour extraire les champs DeviceType 16 bits et Méthode 2 bits d’un IOCTL.

#define DEVICE_TYPE_FROM_CTL_CODE(ctrlCode)   (((ULONG)(ctrlCode & 0xffff0000)) >> 16)
#define METHOD_FROM_CTL_CODE(ctrlCode)        ((ULONG)(ctrlCode & 3))

Ces macros sont définies dans Wdm.h et Ntddk.h.