Skip to topic | Skip to bottom
Home
Minfo
Minfo.Tp3r1.2 - 23 Sep 2007 - 19:39 - NicolasNobelistopic end

Start of topic | Skip to actions

Un périphérique caractère minimal

Cahier des charges

Écrivez un module qui :
  • implémente un pilote caractère pour un périphérique virtuel
  • prend en paramètres :
    • un numéro de major (mais utilise un major dynamique par défaut)
    • un message (chaîne de caractères)

Fonctionnement du périphérique virtuel :

  • Non seekable (plus simple)
  • Opération d' écriture :
    • Génère une trace printk à partir des données écrites
      • Programmation "paranoïaque" : vérifier la qualité et la quantité ...
      • Se conformer au comportement de la fonction d'écriture décrite dans write(2) (man 2 write)
  • Opération de lecture :
    • Récupération de la chaîne donnée en paramètre au module
      • Se conformer au comportement de la fonction de lecture décrite dans read(2) (man 2 read)

N'oubliez pas d'utiliser la fonction copy_to_user (resp. copy_from_user) pour copier les données depuis l'espace mémoire du noyau vers l'espace mémoire utilisateur des processus (resp. depuis l'espace mémoire utilisateur vers l'espace mémoire du noyau) : les pointeurs fournis en second paramètre des fonctions qui implémentent les opérations de lecture et d'écriture pointent vers l'espace mémoire utilisateur...

Indications

Le fichier de périphérique

  • Pour utiliser votre pilote vous devrez créer un fichier spécial de périphérique caractère. Vous pouvez créer ce fichier où vous voulez, mais autant le faire dans /dev, à l'aide de la commande mknod.

  • Pour créer ce fichier spécial, vous devrez préciser ses numéros de major et minor. Quels sont-ils ? C'est à vous d'en décider !
    • Major : il faut choisir un numéro de major qui n'est pas déjà utilisé. Cf. indications données en cours.
    • Minor : Comme votre pilote ne gère qu'un seul périphérique virtuel, la question du minor ne pose pas, vous pouvez choisir n'importe lequel (0 par exemple).

* Attention : mknod se fiche éperdument de savoir s'il y a bien en pilote dans le noyau pour le major que vous lui donnez en paramètre. Ce n'est que lorsque vous essaierez d'utiliser le fichier spécial que le système se mettra à la recherche du pilote. Si aucun pilote n'est trouvé au moment de l'utilisation, vous obtenez un message d'erreur.

* Positionnez les droits en lecture et en écriture sur ce fichier (chmod 666).

* Lors de son chargement, votre module devra enregistrer ses services de pilote caractère auprès du système, à l'aide de la fonction register_chrdev().

* De façon symétrique, n'oubliez pas le code qui permet de supprimer les services de votre pilote lors du déchargement du module (fonction unregister_chrdev()). Dans le cas contraire, votre module serait "scotché" dans le noyau (impossible de le décharger).

* Si cette mésaventure vous arrive, vous avez deux solutions :

  • Redémarrer.
  • Écrire un module qui appellera unregister_chrdev() pour vous, il faudra aussi changer le nom de votre module pour que le noyau accepte de le charger si l'ancien n'a pas pu être correctement déchargé.

Utilisation du pilote

Q: Comment utiliser les services de votre pilote ?
R: Puisque votre pilote fournit les opérations de lecture et écriture, tout programme capable de lire et écrire dans un fichier fera l'affaire. Par exemple la commande cat pour lire le "contenu" du fichier device et les simples redirections du shell pour écrire dans le fichier device (ex echo bonjour > ficdev).

Q: J'utilise la commande cat et celle-ci boucle à l'infini (probablement en affichant toujours la même chose) ?
R : Vous avez simplement oublié de faire en sorte que votre pilote signale que la fin de fichier était atteinte : tant qu'elle ne voit pas d'erreur ou de fin de fichier, la commande cat poursuit ses lectures...

Q: Comment signaler que la fin de fichier est atteinte ?
R: C'est très simple. Comme l'indique la page de manuel de la fonction read(2), la fin de fichier est atteinte quand read renvoie 0. Et d'où vient la valeur renvoyée par la fonction read ? Et bien quand le fichier lu est votre pilote de périphérique virtuel, cette valeur est celle que retourne la fonction que vous avez écrite pour implémenter l'opération de lecture. Il suffit donc de faire retourner 0 à cette fonction quand vous décidez que la fin de fichier est atteinte.

Q: Quand décider que la fin de fichier est atteinte ?
R: La fonction qui implémente l'opération de lecture est toujours supposée savoir où elle en est : elle doit savoir combien de caractères ont déjà été lus, et, si tous les caractères du fichier ont déjà été lus, retourner 0 pour indiquer qu'il n'y a plus rien (et donc que la fin de fichier est atteinte).

Q: Comment savoir combien de caractères ont déjà été lus ?
R: Avant de répondre à cette question, vous devez garder à l'esprit un point de sémantique système très important : le système se souvient de ce qu'il vous a déjà retourné les fois précédentes. Autrement dit, quand vous lisez deux fois de suite dans un fichier (sans l'avoir fermé entre-temps), la seconde lecture vous retournera les caractères en partant de l'endroit où elle en était resté lors de la précédente lecture : si le fichier contient "bonjour" et que vous lisez deux fois de suite 3 caractères dans le fichier, vous obtenez "bon" la première fois, et "jou" la seconde. Puisque c'est vous qui écrivez le pilote, c'est à vous d'implémenter ce comportement.

Q: Comment implémenter ce comportement ?
R: Dans un programme normal, on se contenterait d'utiliser une variable entière déclarée statique dans le corps de la fonction pour se souvenir de la position de lecture courante. Dans le cas de notre pilote, c'est presque la même chose, si ce n'est que vous n'avez pas besoin de déclarer une variable statique, car le système a déjà prévu une variable exprès pour ça : elle est référencée par le troisième paramètre des fonctions implémentant les opérations de lecture et d'écriture (de type loff_t * ).
Cette variable s'appelle offset.

Tests

La lecture (avec cat) ainsi que l'écriture (avec echo) fonctionnent. Mais comment savoir si votre gestion des offsets est correcte ?

* Utilisez dd pour lire ou écrire exactement le nombre d'octets souhaités (ce que ne permet ni cat ni echo qui utilisent des buffers conséquents (ex. 4096)). Par exemple la commande dd if=ficdev bs=3 count=100 lit 100x3 caractères depuis le fichier ficdev et place le résultat sur la sortie standard.
* Écrivez un programme en C qui utilisera les primitives open(2) et read(2)/write(2). Attention: pour pouvoir se servir d'une taille personnalisée de buffer, il faut ouvrir le fichier en mode synchronisé O_SYNC (voir cet exemple).

Un compteur

Cahier des charges

L'objectif de cet exercice est de repartir du pilote précédent et de le modifier pour qu'il se comporte comme un compteur. cat ficdev devra se comporter à peu près comme seq 4000000000.

Indications

  • Une lecture n'est pas obligée de remplir totalement le buffer utilisateur
  • On supposera dans un premier lieu que le buffer de lecture est toujours suffisamment grand pour accueillir un nombre

Améliorations

  • Gérer les buffers trop petits pour accueillir un nombre "entier"
  • Implémenter l'écriture afin de pouvoir fixer la valeur initiale du compteur. Voici un exemple d'utilisation :
$ cat ficdev
0
1
2
3
....
$ echo chaine > ficdev
===> erreur
$ echo 45 > ficdev
===> OK
$ cat ficdev
45
46
47
...
  • Comparez la vitesse de votre pilote avec le voisin en utilisant la commande pv : pv ficdev > /dev/null

-- NicolasNobelis - 23 Sep 2007


to top

You are here: Minfo > ApprofondissementSysteme > Tp3

to top

Copyright © 1999-2017 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding WIKIDeptinfo? Send feedback