ioctl

Un article de Wikipédia, l'encyclopédie libre.
Aller à : navigation, rechercher

En informatique, ioctl, raccourci signifiant input-output control (contrôles des entrées/sorties), est un appel système pour des opérations d'entrée/sortie spécifiques à un périphérique qui ne peuvent être exécutées par un appel système classique. Il reçoit un paramètre spécifiant un code-requête à exécuter ; l'effet de cet appel dépend complètement du code-requête. Les codes-requête sont souvent spécifiques au périphérique. Par exemple, un pilote de CD-ROM qui souhaite éjecter un disque d'un lecteur doit fournir un code-requête à un ioctl pour faire cela. Des codes-requête indépendants du périphérique sont quelquefois utilisés pour donner un accès, depuis l'espace utilisateur, à des fonctions du noyau utilisées uniquement par le cœur du système ou encore en développement.

L'appel-système "ioctl" est apparu pour la première fois dans la version 7 d'Unix sous ce nom. il est supporté par la plupart des systèmes Unix et apparentés, dont Linux et Mac OS X, bien que les codes-requête proposés diffèrent d'un système d'exploitation à l'autre. Microsoft Windows fournit une fonction similaire, nommée "DeviceIoControl", dans son API Win32.

Fonctionnement[modifier | modifier le code]

Les systèmes d'exploitation conventionnels divisent la mémoire en 2 espaces, l'espace utilisateur et l'espace noyau. Le code d'une application telle qu'un éditeur de texte réside dans l'espace utilisateur, tandis que les fonctionnalités sous-jacentes du système d'exploitation, telles que la pile réseau, résident dans le noyau. Le code du noyau gère les ressources sensibles et met en œuvre les barrières de sécurité et de fiabilité entre les applications. Pour cette raison, les applications dans l'espace utilisateur ne peuvent pas accéder directement aux ressources du noyau.

Les applications en espace utilisateur font généralement des requêtes au noyau par l'intermédiaire des appels système, dont le code se trouve dans l'espace noyau. Un appel système prend généralement la forme d'un "vecteur d'appels système", dans lequel l'appel système désiré est indiqué par un numéro d'index. Par exemple, "exit()" peut être l'appel système numéro 1, et "write()" l'appel système numéro 4. Le vecteur d'appels système est utilisé pour trouver la fonction du noyau désirée pour la requête. C'est pourquoi les systèmes d'exploitation classiques offrent généralement plusieurs centaines d'appels système à l'espace utilisateur.

Bien qu'étant un moyen facile d'accéder aux fonctions de l'OS, les appels système peuvent ne pas être adaptés pour l'accès à des périphériques physiques non standard. Les périphériques ne sont adressables directement que depuis l'espace noyau. Mais souvent le code en espace utilisateur a besoin d'accéder directement à un périphérique (par exemple: configurer le "media type" d'une interface Ethernet). Les OS modernes supportent un grand nombre de périphériques avec eux-mêmes un grand nombre de fonctions. Beaucoup de ces fonctions ne peuvent pas être prévues à l'avance et ne sont donc pas forcément implémentables par des appels système.

Pour résoudre ce problème les noyaux sont conçus pour être extensible et acceptent donc des modules appelés pilote de périphérique qui s'exécutent en espace noyau et peuvent adresser directement des périphériques. Une interface de type ioctl se caractérise par un seul appel système par lequel le programme en espace utilisateur peut communiquer avec le périphérique. Comme vu plus haut, les requêtes vers le périphérique sont vectorisées à partir de cet appel système en utilisant typiquement un identifiant unique et un code de requête. Le noyau permet, par ce moyen, au programme utilisateur de communiquer avec le pilote de périphérique sans connaitre les fonctions de celui-ci et sans implémenter un nombre important d'appels système.

Exemples d'utilisations[modifier | modifier le code]

Configuration de périphériques[modifier | modifier le code]

L'utilisation la plus courante des ioctls concerne le contrôle des périphériques physiques. Par exemple, sur les O.S. Win32 (Windows) on peut communiquer avec les périphériques USB à l'aide d'ioctls. On peut aussi obtenir des informations sur la géométrie des disques durs.

Les O.S. de type Unix (Linux, FreeBSD, MacOS X) utilisent les ioctls pour configurer les interfaces réseau. Par exemple, sur les systèmes dérivés de BSD on peut configurer le masque de sous-réseau en ouvrant une Socket puis en utilisant l'ioctl "SIOCSIFNETMASK" sur celle-ci.

Terminaux[modifier | modifier le code]

Une utilisation visible des ioctls est le contrôle des terminaux.

Les O.S. de type Unix ont traditionnellement comme interface un Interpréteur de commandes. L'interpréteur de commande Unix est basé sur des pseudo-terminaux (voir TTY) qui émulent les anciens terminaux physiques en mode texte comme des VT100. Ces pseudo-terminaux sont configurés comme s'il étaient des périphériques physiques à l'aide d'ioctls. Par exemple, la taille de la fenêtre d'un pseudo-terminal peut être configurée en utilisant l'ioctl "TIOCSWINSZ".

Extensions du noyau[modifier | modifier le code]

Quand une application veut étendre les possibilités du noyau, pour accélérer les traitements réseau par exemple, les ioctls fournissent un pont entre le code en espace utilisateur et les extensions ou modules. L'interface de ces modules est souvent constituée d'entrée dans le système de fichier au travers desquelles un certain nombre d'ioctls peuvent être appliqués. Par exemple, sur l'O.S. Solaris la couche de filtrage des paquets IP peut être configurée grâce aux ioctls de la famille "SIOCIPF* ".

Implementations[modifier | modifier le code]

Unix[modifier | modifier le code]

Un ioctl Unix prend comme paramètre:

  1. un Descripteur de fichier ouvert.
  2. Le code spécifique de la requête.
  3. Soit une valeur discrète (entier ou autre) soit un pointeur sur une structure de donnée vers le pilote de périphérique ou depuis le pilote de périphérique, ou bien les deux.

Le noyau transfère directement la requête au pilote de périphérique. Charge à celui-ci d'interpréter la requête. Les développeurs du pilote de périphérique fournissent la liste documentée des ioctls supportés par ce pilote sous forme de constantes dans un header (fichier .h).

Les O.S. de type Unix, y compris Linux, suivent une convention qui consiste à encoder à l'intérieur de la requête :

  1. la taille des données à transférer.
  2. la direction du transfert.
  3. l'identité du pilote de périphérique.

Si le pilote de périphérique ne reconnait pas la requête un code d'erreur unique est renvoyé (code ENOTTY).

NOTE: le code ENOTTY (dérivé du message "Not a typewriter") vient du fait que dans les anciens systèmes seul les télétypes (tty) pouvaient renvoyer cette erreur. Bien qu'utilisé pour des raisons de compatibilité les systèmes plus récent renvoient plutôt un message du type "Inappropriate device control operation".

Par exemple, l'ioctl TCSETS est utilisé par les ports série. Le transfert de données est géré par les appels read() et write() alors que l'appel ioctl(fd,TCSETS,data) permet de contrôler divers états du port.

Win32[modifier | modifier le code]

Un ioctl Win32 prend comme paramètre:

  1. un handle ouvert sur un objet(l'équivalent Win32d'un Descripteur de fichier).
  2. un code de requête (le "control code")
  3. un tampon pour les paramètres d'entrée.
  4. La taille du tampon d'entrée.
  5. un tampon pour les paramètres de sortie.
  6. La taille du tampon de sortie.
  7. une structure 'OVERLAPPED' si le mode overlapped est utilisé.

Le code de requête prend en compte le mode de l'opération (impactant pour la sécurité du pilote):

  1. METHOD_IN_DIRECT - l'adresse du tampon doit être autorisée en lecture pour l'appelant en mode utilisateur.
  2. METHOD_OUT_DIRECT - l'adresse du tampon doit être autorisée en écriture pour l'appelant en mode utilisateur.
  3. METHOD_NEITHER - l'adresse virtuelle du tampon est passé sans vérification ni mapping.
  4. METHOD_BUFFERED - les tampons partagés du IO Manager sont utilisés pour transférer des données de et vers l'espace utilisateur.

Alternatives[modifier | modifier le code]

Autres interfaces d'appel à base de vecteurs[modifier | modifier le code]

Les périphériques et modules peuvent s'interfacer avec l'espace utilisateur grâce à des nouveaux appels système. Cependant cette approche est rarement utilisée.

Sur des O.S. de type Unix deux autres interfaces sont couramment utilisées :

  1. L'appel fcntl ("file control") permet de configurer des fichiers préalablement ouverts (permet, par exemple, d'activer les I/O non bloquantes).
  2. L'appel setsockopt ("set socket option") permet de configurer des sockets préalablement ouvertes (permet, par exemple, de configurer le pare-feu ipfw sur les systèmes BSD).

Mapping mémoire[modifier | modifier le code]

Unix[modifier | modifier le code]

Références[modifier | modifier le code]