IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

ldd3

Date de publication : 19/07/2007 , Date de mise à jour : 19/07/2007


III. Une introduction aux pilotes de périphériques
III-1. Le rôle d'un pilote de périphérique
III-2. Décomposition du Noyau
III-3. Modules chargeables
III-4. Classes de périphériques et modules
III-5. Problèmes de sécurité
III-6. Numérotation des versions
III-7. Termes de licence
III-8. Joignez la communauté de développement du noyau
III-9. Vue d'ensemble du livre


III. Une introduction aux pilotes de périphériques

L'un des nombreux avantages des systèmes d'exploitation libres, caractérisé par Linux, est que leurs composants internes sont libres de consultation. Ce système d'exploitation, initialement un domaine sombre et mystérieux dont le code était réservé à un petit nombre de programmeurs, peut désormais être aisément lu, compris et modifié par n'importe qui ayant les compétences requises. Linux a contribué à démocratiser les systèmes d'exploitation. Le noyau Linux reste un grand ensemble complexe de code, cependant, les futurs experts du noyau ont besoin d'un point de départ où ils peuvent entrer dans ce code sans en être submergés par sa complexité. Souvent, les pilotes de périphériques, nous fournissent cette passerelle.

Les pilotes de périphériques prennent un rôle spécifique dans le noyau Linux. Ils sont les différentes "boîtes noires" qui font qu'une partie matérielle particulière répond à une interface de programmation (API) bien définie. Ils cachent complètement les détails de fonctionnement du périphérique. Les actions utilisateur sont exécutées par un ensemble d'appels normalisés qui sont indépendants du pilote, reliant ces appels aux opérations spécifiques du pilote pour agir sur le vrai périphérique. Ceci est donc le rôle du pilote de périphérique. Cette interface de programmation est telle que les pilotes peuvent être compilés séparément du reste du noyau et "connectés" au besoin au moment de l'exécution. Cette modularité rend l'écriture de pilotes Linux facile, au point que des centaines d'entre eux sont maintenant disponibles.

Il y a bon nombre de raisons de s'intéresser à l'écriture de pilotes de périphériques Linux. La rapidité à laquelle le nouveau matériel devient disponible (et obsolète!) donne garantie que les programmeurs de pilotes seront sans nuls doutes occupés dans le futur. Les individus peuvent avoir besoin de connaître les pilotes de périphériques afin d'avoir accès à un matériel qui les intéresse. Les constructeurs de périphériques, en réalisant un pilote Linux pour leurs produits, peuvent ajouter l'importante et croissante part des utilisateurs de Linux à leurs marchés potentiels. Et la nature Open Source du système Linux implique que si le programmeur d'un pilote le souhaite, le code d'un pilote peut être partagé à des millions d'utilisateurs en un rien de temps.

Ce livre vous apprend à écrire vos propres pilotes et à vous situer dans les parties relatives du noyau. Nous avons choisi une approche indépendante pour chaque type de périphérique. Les techniques et interfaces de programmation sont présentées, tant que c'est possible, sans être spécifiques à un périphérique particulier. Chaque pilote est différent. En tant que programmeur de pilotes, vous avez besoin de bien comprendre votre périphérique spécifique. Mais la plupart des principes et techniques de bases sont les mêmes pour tous les pilotes. Ce livre ne peut pas vous enseigner sur votre périphérique, mais il vous donne le savoir nécessaire pour le faire fonctionner.

En apprenant à écrire des pilotes, vous apprenez beaucoup sur le noyau Linux en général. Ceci peut vous aider à comprendre comment fonctionne votre ordinateur et pourquoi les choses ne sont pas toujours aussi rapides que vous le souhaiteriez ou ne fait pas vraiment ce que vous voulez. Nous introduisons de nouvelles idées graduellement, en commençant par de très simples pilotes et en nous nous baserons sur ces concepts pour la suite. Chaque nouveau concept est accompagné d'un échantillon de code qui ne nécessite pas de périphérique particulier pour être testé.

Ce chapitre ne porte pas pour l'instant sur l'écriture de code. Cependant, nous introduisons d'abord quelques concepts de base sur le noyau Linux que vous serez heureux de connaître plus tard, quand nous nous lancerons dans la programmation.


III-1. Le rôle d'un pilote de périphérique

En tant que programmeur, vous êtes capable de faire votre propre choix à propos de votre pilote et choisir un compromis acceptable entre le temps de programmation nécessaire et la souplesse du résultat. Bien que ça puisse sembler étrange de dire qu'un pilote est "souple", nous aimons ce mot car il insiste sur le fait qu'un périphérique nous procure un mécanisme, et non une politique.

La distinction entre mécanisme et règles est l'une des meilleures idées du concept Unix. La plupart des problèmes de programmation peuvent tout à fait être séparés en deux parties: "De quelles fonctionnalités avons nous besoin ?" (le mécanisme) et "comment ces fonctionnalités peuvent-elles être utilisées ?" (la politique). Si les deux problèmes sont abordés par deux parties distinctes du programme, ou même par des programmes entièrement différents, alors l'application sera plus facile à développer et à adapter à des besoins particuliers.

Par exemple, la gestion du système graphique sous Unix est partagée entre le serveur X, qui connaît le matériel et offre une interface unifiée aux programmes utilisateurs, et les gestionnaires de fenêtres et de sessions, qui implémentent une politique particulière sans rien connaître du matériel. On peut utiliser le même gestionnaire de fenêtres sur des matériels différents, et différents utilisateurs peuvent exécuter plusieurs configurations sur la même station de travail. Même des environnements de bureau totalement différents, comme KDE et GNOME, peuvent cohabiter sur le même système. Un autre exemple concerne la structure en couches de la gestion du réseau TCP/IP: le système d'exploitation offre l'abstraction de socket, qui n'implémente pas de politique concernant les données à transférer, tandis que d'autres serveurs sont an charge des services (et leur politique associée). Qui plus est, un serveur comme ftpd nous procure le mécanisme de transfert de fichiers, tandis que les utilisateurs peuvent utiliser n'importe quel client ftp de leur choix. Il existe à la fois des clients en ligne de commande et des clients en mode graphique et n'importe qui peut écrire une nouvelle interface utilisateur pour transférer des fichiers.

Concernant les pilotes, la même séparation entre le mécanisme et la politique s'applique. Le pilote de la disquette est exempt de toute politique, son rôle est seulement de présenter la disquette comme un tableau continu de blocs de données. Les niveaux plus élevés du système fournissent des politiques, comme qui à le droit d'accéder à la disquette, si la disquette est accessible directement ou via un système de fichiers, et si tous les utilisateurs ont le droit de monter la disquette. A partir du moment ou différents environnements ont besoin d'utiliser le matériel de différentes manières, il est important d'avoir une politique aussi libre que possible.

En écrivant des pilotes, un programmeur devrait prêter une attention particulière à ce concept fondamental : écrire du code noyau pour accéder au matériel, mais ne pas forcer l'utilisateur à adopter une politique particulière, à partir du moment ou des utilisateurs différents ont des besoins différents. Le pilote devrait permettre l'accès au matériel disponible, laissant tous les problèmes d'utilisation aux applications. Un pilote, donc, est flexible s'il procure un accès aux fonctionnalités du matériel sans ajouter de contraintes. Quelquefois, cependant, quelques décisions de politique doivent être appliquées. Par exemple, un pilote d'entrée/sortie numérique ne peut procurer qu'un accès d'un multiplet de long au matériel afin d'éviter le code supplémentaire pour manipuler les bits individuels.

Vous pouvez aussi regarder votre pilote sous un autre angle : c'est une couche logicielle qui réside entre les applications et le périphérique en question. Ce rôle privilégié du pilote permet au programmeur de pilotes de choisir précisément comment le périphérique doit apparaître: différents pilotes peuvent offrir différentes fonctionnalités, et ce pour le même périphérique. La conception d'un pilote doit être un compromis entre différentes considérations. Par exemple, un périphérique unique peut être utilisé par plusieurs programmes différents, et le programmeur de pilotes est totalement libre de gérer la concurrence entre les accès. Vous pourriez mettre en place une gestion de mémoire sur le périphérique indépendamment de ses propriétés matérielles ou bien vous pourriez procurer une bibliothèque utilisateurs afin d'aider les développeurs d'applications à mettre en place de nouvelles politiques au-dessus des primitives disponibles, et ainsi de suite. Une considération majeure est le compromis entre le désir de présenter autant d'options que possible à l'utilisateur et le temps que vous avez pour écrire le pilote, et aussi la nécessité que les choses restent simples afin d'éviter les erreurs.

Les pilotes sans politique ont un nombre de caractéristiques typiques. Celles-ci incluent le support pour les opérations synchrones et asynchrones, la capacité d'être ouverts plusieurs fois, la capacité d'exploiter toutes les fonctionnalités du matériel, et l'absence de couches logicielles pour "simplifier les choses" ou fournir des opérations sur mesure. Les pilotes de ce genre ne fonctionnent pas seulement mieux pour leurs utilisateurs finaux, mais ils s'avèrent aussi plus faciles à écrire et à maintenir. Être exempt de politique est en réalité une cible commune pour les développeurs de logiciels.

Beaucoup de pilotes de périphériques, en effet, sont publiés en même temps avec les programmes utilisateurs pour faciliter la configuration et l'accès au périphérique. Ces programmes vont des simples utilitaires aux applications graphiques complètes. Par exemple le programme tunelp, qui ajuste le comportement du port parallèle de l'imprimante, et l'utilitaire graphique cardctl qui fait partie du paquet pilote PCMCIA. Souvent une bibliothèque cliente est également disponible, laquelle fournie des fonctionnalités qui n'ont pas à être intégrées dans le pilote lui-même.

Le contenu de ce livre est le noyau, ainsi nous essaierons de ne pas traiter les questions de politique, des programmes d'applications ou des bibliothèques de support. Parfois nous parlons des différentes politiques et comment les supporter, mais nous n'entrerons pas plus en détail sur la manière dont les programmes utilisent le périphérique ou les politiques qu'ils mettent en oeuvre. Vous devriez comprendre, cependant, que les programmes utilisateurs font partie intégrante d'un paquet logiciel et que même les paquets exempts de politique sont distribués avec des fichiers de configuration qui appliquent un comportement par défaut aux mécanismes sous-jacents.


III-2. Décomposition du Noyau

Dans un système Unix, plusieurs processus concurrents s'occupent de différentes tâches. Chaque processus demande des ressources systèmes, que ce soit processeur, mémoire, connexion au réseau ou d'autres ressources. Le noyau est la grosse partie de code exécutable en charge de manipuler de telles requêtes. Bien que la distinction entre les différentes tâches du noyau ne soit pas toujours clairement définie, le rôle du noyau peut être séparé (figure 1-1) en ces différentes parties:

  • Gestion de processus: le noyau est en charge de la création et de la destruction des processus ainsi que de la gestion de leur connexion au monde extérieur (entrée et sortie). La communication entre les différents processus (au travers de signaux, des tubes nommés ou des primitives de communication inter-processus) est commune à l'ensemble des fonctionnalités du système et est aussi géré par le noyau. De plus, le planificateur, qui contrôle la façon dont les processus partagent le CPU, fait partie de la gestion de processus. Plus généralement, l'activité de gestion des processus par le noyau implémente l'abstraction de plusieurs processus au dessus d'un simple CPU.
  • Gestion de mémoire : la mémoire est une ressource majeure et la règle à appliquer est critique pour la performance du système. Le noyau met en place un espace d'adressage virtuel pour n'importe quel processus dépassant la limite des ressources disponibles. Les différentes parties du noyau interagissent avec le sous-système de gestion de mémoire au travers d'un ensemble d'appels de fonctions, allant de la simple paire malloc/free à des fonctionnalités plus complexes.
  • Système de fichiers: Unix est fortement basé sur le concept de système de fichiers. Presque tout dans Unix peut être traité comme un fichier. Le noyau fabrique une structure au dessus du matériel non structuré et l'abstraction de fichier résultante est fortement utilisée d'un bout à l'autre du système. De plus, Linux supporte plusieurs types de systèmes de fichiers, qui correspondent, à des façons différentes d'organiser les données sur le support physique. Par exemple, les disques peuvent être formatés avec le système de fichiers standard de Linux ext3, le système de fichier FAT utilisé communément, ou plusieurs autres.
  • Contrôle de périphérique: chaque opération système ou presque est liée à un périphérique physique. A l'exception du processeur, de la mémoire et de très peu d'autres entités, toutes les opérations de contrôle de périphérique sont réalisées par du code qui est spécifique au périphérique auquel on s'adresse. Ce code est appelé «un pilote de périphérique». Le noyau doit comprendre un pilote de périphérique pour chaque périphérique présent sur un système, du disque dur au clavier et au système d'enregistrement sur bande. Cet aspect des fonctions du noyau est notre principal intérêt dans ce livre.
  • Réseau: le réseau doit être pris en charge par le système d'exploitation, car la plupart des opérations réseau ne sont pas spécifique à un processus: les paquets entrants sont des évènements asynchrones. Les paquets doivent être collectés, identifiés, et dispatchés avant qu'un processus ne puisse y prêter attention. Le système est en charge de la livraison des paquets de données aux programmes, aux interfaces réseau et il doit contrôler l'exécution des programmes en fonction de l'activité réseau. De plus, toutes les opérations de routage et de résolution d'adresses sont implémentées à l'intérieur du noyau.

III-3. Modules chargeables

L'un des avantages de Linux est la possibilité d'étendre pendant l'exécution, le choix de caractéristiques offertes par le noyau. Cela signifie que vous pouvez ajouter des fonctionnalités au noyau (et aussi les enlever) pendant que le système est démarré et actif.

Toute partie de code qui peut être ajoutée au noyau pendant son fonctionnement s'appelle un module. Le noyau Linux offre des supports pour peu de types (ou classes) de modules différents dont, mais sans se limiter à ceux-ci, les pilotes de périphériques. Chaque module est constitué d'un code objet (non lié en tant qu'exécutable final) qui peut être dynamiquement lié au noyau actif par le programme insmod et peut être délié par le programme rmmod.

La figure 1.1 identifie différentes classes de modules en charge de fonctions spécifiques. On dit d'un module qu'il appartient à une classe spécifique en fonction de la fonctionnalité qu'il procure. La représentation des modules dans la figure 1.1 couvre les classes les plus importantes, mais est loin d'être complète car de plus en plus de fonctionnalités sont modularisées dans Linux.


III-4. Classes de périphériques et modules

La façon dont Linux reconnaît les périphériques se décompose en trois types fondamentaux. Chaque module implémente normalement l'un des ces types, ainsi classifiable comme, un module en mode caractère, un en mode bloc ou un module réseau. Cette division de modules en différents types, ou classes, n'est pas stricte. Le programmeur peut choisir de faire de très gros modules implémentant plusieurs pilotes dans un seul bloc de code. Les bons programmeurs, néanmoins, créent habituellement un module différent pour chaque nouvelle fonctionnalité qu'ils implémentent, car la décomposition est un élément clé pour l'optimisation et l'évolution. Figure 1-1. Une vue décomposée du noyau :

Les trois classes sont :

  • Périphériques en mode caractère: un périphérique caractère (char) est un périphérique qui peut être vu comme flux d'octets (comme un fichier). Un pilote en mode caractère a la charge de mettre en oeuvre ce comportement. Un tel pilote implémente habituellement au moins les appels systèmes open, close, read et write. La console (/dev/console) et les ports séries (/dev/ttyS0 et autres) sont des exemples de périphériques en mode caractère, comme ils sont bien représentés par l'abstraction de flux. Les périphériques caractère sont vus par représentations de noeuds du système de fichiers, comme /dev/tty1 et /dev/lp0. La seule différence notoire entre un périphérique caractère et un fichier régulier est que vous pouvez toujours retourner en arrière et ainsi de suite dans le fichier régulier, tandis que la plupart des périphériques orientés caractère sont juste des chaînes de données, lequels sont uniquement accessibles séquentiellement. Il existe, néanmoins, des périphériques orientés caractère ressemblant à des zones de données où vous pouvez retourner en arrière et ainsi de suite. Par exemple, ceci s'applique habituellement aux capteurs de trames, où les applications peuvent accéder à une image complète acquise en utilisant mmap ou lseek.
  • Périphérique en mode bloc: comme les périphériques orienté caractère, les périphériques en mode bloc sont accessibles par des noeuds sur le système de fichiers dans le répertoire /dev. Un périphérique bloc est un périphérique (par exemple: un disque) qui peut héberger un système de fichiers. Dans la plupart de systèmes Unix, un périphérique en mode bloc ne peut que manipuler des opérations entrées/sorties qui transfèrent un ou plusieurs blocs complets, qui sont habituellement de 512 octets (ou une plus grande puissance de 2) octets de long. Linux, quant à lui, autorise l'application à lire et écrire un périphérique en mode bloc comme un périphérique en mode caractère, il permet le transfert de n'importe quel nombre d'octets en une fois. Par conséquent, les périphériques bloc et caractère ne diffèrent que dans la façon dont les données sont gérées en interne par le noyau, et par la suite, dans l'interface logicielle du noyau/pilote. Comme un périphérique orienté caractère, chaque périphérique en mode bloc est accessible au travers d'un noeud du système de fichiers, et la différence entre eux est transparente pour l'utilisateur. Les pilotes en mode bloc ont une interface complètement différente au noyau que les pilotes en mode caractère.
  • Interfaces réseau: toute transmission réseau est faite au travers d'une interface, qui est, un périphérique capable d'échanger des données avec d'autres hôtes. Habituellement, une interface est un périphérique matériel, mais il peut aussi être un périphérique purement logiciel, comme l'interface loopback. Une interface réseau est en charge d'envoyer et recevoir des paquets de données, piloté par le sous-système réseau du noyau, sans avoir connaissance de la manière dont les transmissions individuelles tracent les paquets en cours de transfert. Plusieurs connexions réseau (particulièrement celles utilisant TCP) sont orientées flux, mais les périphériques réseau sont, habituellement, conçus autour de la transmission et réception de paquets. Un pilote réseau ne connaît rien des connexions individuelles, il ne fait que manipuler des paquets.
    N'étant pas un périphérique orienté flux, une interface réseau n'est pas facilement liée à un noeud du système de fichier, comme /dev/tty1 l'est. La méthode Unix pour procurer un accès aux interfaces est encore en leur assignant un nom unique (comme eth0), mais ce nom n'as pas d'entrée correspondante dans le système de fichiers. La communication entre le noyau et un pilote de périphérique réseau est totalement différente de celle utilisée avec les pilotes caractère et bloc. Au lieu de read et write le noyau fait appel à des fonctions relatives à la transmission de paquets.
Il y a d'autres moyens de classifier les modules qui sont orthogonaux aux types de périphérique ci-dessus. En général, quelques types de pilotes fonctionnent avec des couches additionnelles qui font parties des fonctions du support noyaux pour un type donné de périphérique. Par exemple, si on parle des modules du bus série universel (Universal Serial Bus), les modules serial, les modules SCSI et ainsi de suite. Tout périphérique USB est piloté par un module USB qui fonctionne avec le sous-systèmeUSB, mais le périphérique lui-même apparaît dans le système comme un périphérique caractère (dit à port série USB), un périphérique bloc (un lecteur de cartes mémoires USB), ou une interface réseau (une interface Ethernet USB).

Les autres classes de pilotes de périphériques ont été récemment ajoutées au noyau, incluant les pilotes FireWire et les pilotes I2O. En même temps qu'ils manipulaient les pilotes USB et SCSI, les développeurs de noyau ont recueillit des propriétés de large classe et les ont exportées aux fournisseurs de modules afin d'éviter le travail en double et les bugs, et aussi simplifier et renforcer le processus pour écrire de tel pilotes.

En plus des pilotes de périphériques, d'autres fonctions, tant matérielles que logicielles, sont modularisées dans le noyau. Un exemple commun est le système de fichiers. Le type de système de fichiers détermine comment l'information est organisée sur un périphérique bloc afin de représenter un arborescence de répertoires et fichiers. Une telle entité n'est pas un pilote de périphériques, par le fait qu'il n'y a pas de périphérique explicite associé à la manière dont l'information y est redirigée, c'est plutôt le type de système de fichiers plutôt que le pilote logiciel, car il fait correspondre les structures de données bas-niveau à des structures de données de haut niveau. C'est le système de fichiers qui détermine de quelle longueur peut être un nom de fichier et quelles informations sur chaque fichier sont stockées dans un répertoire. Le module du système de fichiers doit implémenter le plus bas niveau d'appels système qui accède aux répertoires et fichiers en cartographiant les noms de fichiers et les chemins (aussi bien que d'autres informations comme les droits d'accès) aux structures de données contenues dans les blocs de données. Une telle interface est totalement indépendante du transfert de données en cours vers et du disque (ou autre medium), qui est accompli par un pilote de périphériques en mode bloc.

Si vous vous demandez à quel point un système Unix dépend du système de fichiers sous-jacent, vous vous rendrez compte qu'un tel concept logiciel est vital pour les opérations systèmes. La capacité de décoder les informations du système de fichiers est ancrée au plus bas niveau de la hiérarchie du noyau est d'une importance majeure. Même si vous écrivez un pilote en mode bloc pour votre nouveau lecteur de CD-ROM, il est inutile si vous n'êtes pas capable de lancer les commandes ls ou cp sur les données qu'il contient. Linux supporte le concept d'un module système de fichiers, dont l'interface logicielle déclare les différentes opérations qui peuvent être exécutées sur l'inode, le répertoire, le fichier et le superbloc du système de fichiers. Il est très peu courant actuellement qu'un programmeur ai besoin d'écrire un module système de fichiers, car le noyau officiel inclut déjà le code pour les types de systèmes de fichiers les plus importants.


III-5. Problèmes de sécurité

La sécurité est un souci de plus en plus important dans les temps modernes. Nous discuterons des problèmes de sécurité au fur et à  mesure qu'ils apparaissent dans ce livre. Il y a néanmoins quelques concepts généraux qu'il vaut la peine de mentionner maintenant.

Chaque contrôle de sécurité dans le système est imposé par le code du noyau. Si le noyau contient des trous de sécurité, alors tout le système en contient. Dans la distribution officielle du noyau, seul un utilisateur autorisé peut charger des modules. L'appel système init_module contrôle si le processus est invoqué est autorisé à  charger des modules dans le noyau. De cette manière, quand un noyau officiel est actif, seul l'administrateur système (techniquement, seulement quelqu'un avec la capacité de CAP_SYS_MODULE peut accomplir cette opération. Nous discuterons des capacités dans le chapitre 6), ou un intrus qui a réussi à  obtenir ces droits, peut exploiter le pouvoir du code privilégié.

Si possible, les programmeurs de pilotes devraient éviter de coder la politique de sécurité dans leur code. La sécurité est une question de politique qui est souvent mieux manipulée à  des niveaux plus élevés dans le noyau, sous le contrôle de l'administrateur système. Néanmoins, il y a toujours des exceptions

En tant que programmeur de pilote, vous devriez être conscient des situations dans lesquelles quelques types d'accès aux périphériques pourraient compromettre l'ensemble du système et devrait fournir des contrôles proportionnés. Par exemple, les opérations de périphériques qui affectent les ressources globales (comme placer une ligne d'interruption), qui pourrait endommager le matériel (chargement de firmware par exemple) ou qui pourrait affecter d'autres utilisateurs (comme placer un bloc par défaut sur une bande magnétique) sont habituellement seulement disponible aux utilisateurs suffisamment privilégiés et ce contrôle doit être effectuer dans le pilote lui-même.

Les programmeurs de pilotes doivent donc être prudent, bien sûr, à éviter d'introduire des bugs de sécurité. Le langage de programmation C rend facile le fait de faire des erreurs de ce type. Plusieurs des problèmes de sécurité actuels sont créés, par exemple, par des erreurs de dépassement de tampon dans lequel le programmeur oublie de contrôler combien de données sont écrites dans le tampon et les données finissent par être écrites à  la fin du tampon, recouvrant de ce fait des données indépendantes. De telles erreurs peuvent compromettre le système et doivent être évitées. Heureusement, éviter ces erreurs est habituellement relativement simple dans le contexte du pilote de périphérique, dans lequel, l'interface utilisateur est étroitement défini et hautement contrôlé.

Quelques autres idées de sécurité générale valent la peine d'être gardé en mémoire. Chaque entrée reçue par le processus utilisateur devrait être traité avec la plus grande suspicion, ne jamais y croire sans que vous ayez un moyen de le vérifier. Soyez prudent avec l'espace mémoire non alloué et de la mémoire obtenue à  partir du noyau doit être remise à  zéro ou être autrement initialisée avant de la rendre disponible à  un processus utilisateur ou périphérique. Autrement, les fuites d'informations (révélation de données, mots de passe, etc.) pourrait être révélées. Si votre périphérique interprète les données transmises, soyez sûr que l'utilisateur ne puisse pas envoyer tout ce qui pourrait compromettre le système. Finalement, envisagez les effets possibles des opérations de périphériques. S'il y a des opérations spécifiques (par exemple, recharger le firmware d'une carte d'extension ou formater un disque) qui peuvent affecter le système, ces opérations devraient certainement être restreintes aux utilisateurs privilégiés.

Soyez prudent, aussi, quand vous recevez des logiciels d'une tierce personne, et plus particulièrement quand le noyau est concerné: car tout le monde a accès au code source, tout le monde peut le corrompre et recompiler certaines choses. Bien que vous puissiez faire confiance aux noyaux précompilés trouvés dans votre distribution, vous devriez éviter d'utiliser des noyaux par une personne à  qui vous ne pouvez pas faire confiance. Si vous ne voulez pas exécuter les fichiers binaires précompilés en tant qu'administrateur système, alors vous ne devriez pas utiliser un noyau précompilé. Par exemple, un noyau malicieux modifié pourrait autoriser n'importe qui à  charger un module, ceci ouvrant une porte secrète inattendue via init_module.

Notez que le noyau Linux peut être compilé de telle sorte à  ce que les modules ne soient plus supportés, ceci fermant tous les trous de sécurité relatif aux modules. Dans ce cas, bien sûr, tous les pilotes requis doivent être directement écrits en dur dans le noyau. Il est aussi possible, avec les versions 2.2 du noyau et supérieures, de désactiver le chargement de modules dans le noyau après le système de démarrage par l'intermédiaire du mécanisme approprié.


III-6. Numérotation des versions

Avant d'approfondir le côté programmation, nous devrions commenter le schéma de numérotation des versions utilisées dans Linux, lesquelles sont couvertes par ce livre.

Tout d'abord, notez que chaque paquet logiciel utilisé dans un système Linux à  son propre numéro de parution et il y a souvent des interdépendances entre eux: vous avez besoin d'une version particulière d'un paquet pour faire tourner une autre version d'un paquet particulier. Les créateurs de distributions Linux gèrent habituellement le problème de dépendances et l'utilisateur qui installe une distribution précompilée n'a pas besoin de s'occuper des numéros de versions. Ceux qui remplacent et mettent à  jour les logiciels systèmes, de l'autre côté, ont leur propre point de vue. Heureusement, presque toutes les distributions modernes supportent la mise à  jour de paquet unique en contrôlant les dépendances interpaquet. Le gestionnaire de paquets de la distribution n'autorise généralement pas la mise à  jour si les dépendances ne sont pas satisfaites.

Pour exécuter les exemples que nous introduisons au cours de la discussion, vous n'avez pas besoin de versions particulières de chaque outil au-delà  de la version 2.6, n'importe quelle distribution récente de Linux peut être utilisée pour exécuter nos exemples. Nous n'allons pas détailler les besoins spécifiques car le fichier Documentation/Changes dans les sources de votre noyau est la meilleure source d'information si vous rencontrez des problèmes.

En ce qui concerne le noyau, les versions paires du noyau (par exemple, 2.6.x) sont stables, ils sont prévus pour la distribution générale. Les versions impaires (par exemple, 2.6.x), au contraire, sont en développement et sont tout à  fait éphémères. La dernière d'entre elles représente l'état actuel du développement, mais deviendra obsolète dans quelques jours à  peu près.

Ce livre couvre la version 2.6 du noyau. Notre objectif a été de montrer toutes les nouvelles fonctionnalités disponibles aux programmeurs de pilotes de périphériques dans la version 2.6.10, la version actuelle à  l'heure ou nous écrivons. Cette édition du livre ne couvre pas les versions antérieures du noyau. Pour ceux d'entre vous qui sont intéressés, la seconde édition montre le noyau 2.4 en détails. Cette édition est encore disponible en ligne à l'adresse http://lwn.net/Kernel/LDD2/.

Les programmeurs du noyau devraient se rendre compte que le procédé de développement à  changer avec la version 2.6. Les séries 2.6 acceptent maintenant les changements qui précédemment auraient été considérés comme trop importants pour un noyau "stable". Entre autres, cela signifie que l'interface de développement interne au noyau peut changer, ceci rendant potentiellement obsolète certaines parties de ce livre. Pour cette raison, le code exemple accompagnant le texte est connu pour fonctionner avec la version 2.6.10, mais quelques modules ne compilent pas sur des versions précédentes. Les programmeurs voulant suivre les modifications de la programmation du noyau sont encouragés à  joindre les mailings lists et utiliser les sites web listés dans la bibliographie. Il y a aussi une page web maintenue à  l'adresse http://lwn.net/Articles/2.6-kernel-api/ qui contient les informations à  propos des changements de l'API qui se sont produits depuis que ce livre a été édité.

Ce texte ne parle pas particulièrement des versions impaires du noyau. Les simples utilisateurs n'ont jamais de raison de tourner sur une version en développement. Les développeurs expérimentant les nouvelles caractéristiques, par contre, veulent tourner sur la dernière version en développement. Ils continuent habituellement à  améliorer la version la plus récente pour corriger les bugs et les nouvelles implémentations de caractéristiques. Notez, par contre, qu'il n'y a aucune garantie sur les noyaux expérimentaux (notez qu'il n'y a pas non plus de garantie sur les versions "stables", à  moins que vous comptiez sur un fournisseur commercial qui accorde sa propre garantie), et que personne ne vous aide si vous avez des problèmes dus à  un bug dans noyau en cours de développement. Ceux qui utilisent une version impaire du noyau sont habituellement assez qualifiés pour plonger dans le code sans avoir besoin de livre, ce qui est une autre raison pour laquelle nous ne parlons pas des noyaux de développement ici.

Une autre caractéristique de Linux est qu'il est indépendant de la plate-forme du système d'exploitation, non plus juste "un clone Unix pour des clones PC": il supporte actuellement quelques 20 architectures. Ce livre est indépendant de la plate-forme autant que possible et tous les exemples de codes ont été testés sur les plates-formes x86 et x86-64 au minimum. étant donné que le code a été testé sur les processeurs 32 et 64 bits, il devrait compiler et tourner sur toutes les plates-formes. Comme vous pourriez vous y attendre, les exemples de codes qui se fondent sur un périphérique spécifique ne fonctionnent pas sur toutes les plates-formes supportées, mais ceci est toujours énoncé dans le code source.


III-7. Termes de licence

Linux est sous licence GNU General Public License (GPL) dans sa version 2, un document conçu pour le projet GNU de la Free Software Foundation. La GPL autorise n'importe qui à  redistribuer, et même vendre, un produit publié sous GPL du moment que le destinataire a accès aux sources et est capable de bénéficier des mêmes droits. De plus, n'importe quel logiciel publié sous GPL doit, s'il est distribué, être sous licence GPL

Le principal but de cette licence est d'autoriser le développement des connaissances en permettant à  tout le monde de modifier les programmes comme bon leur semble; dans le même temps, les gens vendant des logiciels au public peuvent continuer à  faire leur travail. Malgré cet objectif simple, il existe une discussion sans fin à  propos de la GPL et son utilisation. Si vous voulez lire la licence, vous pouvez la trouver à  différents endroits dans votre système, y compris dans le répertoire de base contenant l'arborescence des sources du noyau dans le fichier COPYING.

Les fournisseurs demandent souvent s'ils peuvent distribuer des modules du noyau sous forme binaire seulement. La réponse à  cette question a été délibérément laissée ambiguë. La distribution de modules binaires - dès qu'ils adhèrent à  l'interface du noyau - sont tolérés depuis longtemps. Mais les droits de copies du noyau sont maintenus par beaucoup de développeurs, et tous n'acceptent pas que les modules ne soient pas des produits dérivés. Si vous ou votre employeur veut distribuer des modules du noyau sous une licence non libre, vous aurez vraiment besoin d'en discuter avec votre service juridique. Veuillez également prendre note que les développeurs du noyau n'ont aucun scrupule à  casser les modules binaires entre les publications du noyau, même en plein milieu d'une série stable de noyaux. Si c'est possible, vos utilisateurs et vous-même préféreront que vous publiez votre module comme du code libre.

Si vous voulez que votre code soit intégré officiellement dans le noyau, ou si votre code requiert de patcher le noyau, vous devez utiliser une licence compatible avec la GPL dès que vous publierez votre code. Quoique l'utilisation personnelle de vos changements ne vous force pas à  la licence GPL, si vous fournissez le code, vous devez inclure le code source dans sa distribution - les gens qui récupèrent votre paquet doivent pouvoir reconstruire le fichier binaire à  volonté.

Puisque ce livre est concerné, la plupart du code est redistribuable gratuitement, aussi bien sous forme de sources que sous forme binaire, et ni nous ni O'Reilly se réservent de droits sur tous les travaux dérivés. Tous les programmes sont disponibles à  ftp://ftp.ora.com/pub/examples/linux/drivers/, et les termes exacts de licence sont situés dans le fichier LICENSE du même répertoire.


III-8. Joignez la communauté de développement du noyau

Comme vous commencez à écrire des modules pour le noyau Linux, vous ferez partie d'une plus grande communauté de développeurs. Dans cette communauté, vous pouvez trouver non seulement des personnes engagées dans un travail semblable, mais aussi un groupe d'ingénieurs fortement engagés travaillant pour faire de Linux un système meilleur. Ces personnes peuvent être une source d'aide, d'idées et de revue critique. Ils seront les premiers vers qui vous vous tournerez quand vous chercherez des testeurs pour un nouveau pilote.

L'assemblée centrale de développeurs Linux est la mailing-list linux-kernel. Tous les développeurs en chef, de Linus Torvalds et inférieur, ont souscrit à cette liste. Notez s'il vous plaît que la liste n'est pas là pour les peines de coeur: le trafic de cette liste peut être de 200 messages par jour, voire plus. Néanmoins, suivre cette liste est essentielle pour ceux qui sont intéressés dans le développement du noyau. Elle peut donc être une ressource de première qualité pour ceux qui aident au développement du noyau.

Pour joindre cette liste, suivez les instructions trouvées sur la FAQ de cette mailing-list: http://www.tux.org/lkml. Lisez le reste de la FAQ pendant que vous y êtes. Il y a un grand nombre d'informations ici. Les développeurs du noyau Linux sont des personnes occupées, et elles sont plus enclines à  aider des personnes qui ont clairement fait leurs devoirs personnels en premier.


III-9. Vue d'ensemble du livre

À partir d'ici, on entre dans le monde de la programmation du noyau. Le chapitre 2 introduit la modularisation, expliquant les secrets de l'art et montrant le code pour faire tourner les modules. Le chapitre 3 traite des pilotes de caractères et montre le code complet pour les pilotes périphériques basés sur la mémoire qui peut être lu et écrit pour le fun. Employer la mémoire comme matériel de base pour le périphérique permet à  n'importe qui d'exécuter les codes exemples sans avoir besoin d'acquérir du matériel spécial.

Les techniques de débogage sont des outils vitaux pour le programmeur et est introduit dans le chapitre 4. La gestion de la concurrence et de courses sont également importantes pour ceux qui veulent modifier les noyaux contemporains. Le chapitre 5 est dédié aux problèmes posés par l'accès simultané aux ressources et présente les mécanismes Linux pour contrôler la concurrence.

Avec le débogage et les compétences de gestion de concurrence en place, nous nous déplaçons aux fonctions avancées des pilotes caractères, comme le blocage d'opérations, l'utilisation de select, et l'appel important d'ioctl. Ces parties sont le sujet du Chapitre 6.

Avant de traiter la gestion du matériel, nous disséquons encore plus des interfaces logicielles du noyau: le chapitre 7 montre comment le temps est géré dans le noyau et le chapitre 8 explique l'allocation de la mémoire.

Ensuite nous nous penchons sur le matériel. Le chapitre 9 décrit la gestion des ports d'entrées/sorties et les tampons mémoire qui sont sur le périphérique. Après vient la manipulation des interruptions dans le chapitre 10. Malheureusement, tout le monde n'est pas capable d'exécuter les exemples de code pour ce chapitre, car un peu de support matériel est en réalité encore nécessaire pour tester l'interface des interruptions logicielles. Nous avons fait notre possible pour garder le support de matériel nécessaire au minimum, mais vous avez encore besoin d'un peu de matériel basique, comme un port parallèle standard pour travailler avec les exemples de codes pour ces chapitres.

Le chapitre 11 couvre l'utilisation des types de données du noyau et l'écriture de code portable.

La seconde moitié de ce livre est dédiée à  des sujets plus avancés. Nous commençons par entrer plus profondément dans le matériel et plus particulièrement le fonctionnement de certains bus périphériques. Le chapitre 12 couvre en détail l'écriture de pilotes de périphériques pour les périphériques PCI, et le chapitre 13 décortique l'API pour travailler avec les périphériques USB.

Avec une compréhension des bus périphériques, nous pouvons faire une vue détaillée du modèle de périphériques Linux, lequel est la couche d'abstraction utilisée par le noyau pour décrire la gestion des ressources matérielles et logicielles. Le chapitre 14 est une vue d'ensemble de l'infrastructure du modèle de périphérique. Il couvre l'intégralité des modèles de périphériques avec le vrai matériel. Il utilise alors cette connaissance pour couvrir le sujet des périphériques connectables à  chaud et la gestion de l'alimentation.

Dans le chapitre 15, nous faisons une déviation dans la gestion de la mémoire dans Linux. Ce chapitre montre comment organiser la mémoire du noyau dans l'espace utilisateur (l'appel système nmap), organiser la mémoire dans l'espace du noyau (avec get_user_page) et comment organiser l'une ou l'autre mémoire dans l'espace périphérique (pour accomplir les opérations d'accès direct de la mémoire [DMA]).

Vos connaissances sur la mémoire vont être utile pour suivre les deux prochains chapitres, qui couvrent les autres principales classes de pilotes. Le chapitre 16 introduit les pilotes en mode bloc et montre en quoi ils sont différents des pilotes en mode caractère avec lesquels nous avons travaillé jusqu'ici. Ensuite, le chapitre 17 rentre dans la manière d'écrire des pilotes réseau. Nous conclurons avec une discussion sur les pilotes séries (chapitre 18) et une bibliographie.

 

Valid XHTML 1.1!Valid CSS!

creative commons 2. à refaire lors de la mise en ligne finale