Programmation Noyau Sous Linux . API Des Modules Linux.pdf
(
388 KB
)
Pobierz
Programmation noyau sous Linux Partie 1 : API des
modules Linux
Cette série d’articles a pour but de présenter les techniques de programmation dans l’espace du
noyau Linux. Ce type de programmation requiert des connaissances particulières et il existe somme
toute assez peu de documentation francophone et synthétique sur le sujet. Le sujet a déjà été traité
partiellement lors de diverses publications dans GNU/Linux Magazine, mais il s’agit aujourd’hui de
dispenser une information la plus exhaustive et à jour possible.
Nous aborderons des sujets comme :
•
•
•
•
•
•
•
l’interface de programmation (API) des modules Linux, les contraintes techniques et légales
associées ;
la mise au point des programmes en espace noyau (KGDB).
les différents types de pilotes de périphériques (caractère, bloc, réseau) ;
l’utilisation des threads du noyau ;
la gestion des interruptions ;
la gestion du DMA et de mmap() ;
les pilotes PCI, USB et Vidéo For Linux, version 2 (V4L2) ;
A la fin de la série, nous aborderons également la programmation de tâches temps réel " dur " en
utilisant les principales extensions disponibles, soit XENOMAI, RTAI et RTLinux, bien que ce
dernier ne fasse plus réellement partie de la nébuleuse du Logiciel libre.
A l’issue de ces articles, le lecteur attentif et motivé devrait être capable de développer des pilotes
de périphériques simples pour Linux et suivre ainsi la célèbre citation de Linus Torvalds :
" We’re back to the times when men were men and wrote their own device drivers. "
Résumé de l’article
Le présent article introduit l’interface de programmation des modules Linux (ou Application
Programming Interface, API). Cette API est systématiquement utilisée pour la programmation dans
l’espace du noyau, tant pour la programmation des pilotes de périphériques que de certaines
extensions temps réel dur. Nous aborderons aujourd’hui les aspects techniques de cette API :
•
•
•
•
•
•
•
•
•
les espaces mémoire de Linux ;
les contraintes légales (GPL/LGPL) ;
un exemple de module Hello World et son fichier Makefile associé ;
l’installation des modules ;
la dépendance entre les modules ;
l’identification des modules ;
le passage de paramètres ;
la programmation d’un compteur régulier ;
l’accès au répertoire /proc.
Nous insisterons sur les contraintes légales liées à la GPL, ce point étant fondamental bien que
souvent mal connu des développeurs.
Les espaces mémoire de Linux
Les versions normales du noyau Linux utilisent deux espaces de mémoire :
•
•
L’espace dit " utilisateur " (ou user space). Cet espace mémoire correspond à l’espace
d’exécution des programmes applicatifs.
L’espace dit " noyau " (ou kernel space). Cet espace correspond à l’espace d’exécution du
noyau Linux et de ses extensions (modules).
L’architecture de Linux est décrite par le schéma cidessous (merci à Wikipedia).
Figure 1 : Architecture de Linux
La plupart des développeurs travaillent dans l’espace utilisateur dans lequel résident la majorité des
applications. Depuis une application, on peut cependant effectuer une requête au noyau en
effectuant un appel système. Un cas simple est l’obtention du numéro d’identification du processus
associé au programme en cours d’exécution (PID). Dans un programme classique, on l’obtient par
le code C suivant :
/* Obtention du PID */
my_pid = getpid();
printf (“Mon PID est %d\n”, my_pid);
Bien entendu, l’accès à l’espace mémoire du noyau ne se limite pas à cela. La plupart du temps, les
applications doivent accéder à des périphériques et donc à la mémoire. Si l’on respecte le principe
des deux espaces séparés, l’accès à la mémoire ne se fait jamais directement, mais le plus souvent
en passant par un composant dédié résidant dans l’espace du noyau. C’est une définition simple du
pilote de périphérique. Le comportement normal du noyau Linux se base également sur la MMU
(pour Memory Management Unit) un composant matériel inclus dans le processeur et qui permet la
séparation physique de la mémoire. Telle est d’ailleurs l’origine du noyau Linux, puisque les
premiers travaux de Linus Torvalds consistaient à utiliser le mode dit " protégé " (noyau) du
processeur Intel 386, premier processeur de la gamme x86 à disposer d’une MMU.
Corollaire : dans le cas d’un environnement Linux sur un processeur disposant d’une MMU, les
espaces mémoire sont physiquement séparés et il n’est donc pas possible qu’un programme
utilisateur " plante " directement le système. Ce n’est bien sûr pas le cas d’un module Linux. La
programmation et la mise au point des programmes en espace noyau est d’autant plus délicate. Un
noyau Linux adapté peut fonctionner sur des processeurs sans MMU (on parle alors de µCLinux).
L’API de programmation est similaire, mais il y a alors un seul espace de mémoire physique (plus de
mode protégé).
Il est cependant possible d’accéder à un périphérique sans passer par un pilote en utilisant la
fonction ioperm(). Cette fonction permet de définir une zone de mémoire sur laquelle un
programme utilisateur aura un accès direct en utilisant des fonctions d’entrée/sortie comme inb() et
outb(). Elle est assez fréquemment utilisée en x86, mais elle n’est pas forcément disponible sur
toutes les architectures.
Les contraintes légales
Certains lecteurs pourront s’étonner de la présence et de la taille d’un tel paragraphe dans un article
technique. La raison est simple : Linux est de plus en plus utilisé à des fins industrielles et le respect
des licences est fondamental dans ce cas puisqu’un problème légal peut avoir de lourdes
conséquences. Par expérience, nous savons que de nombreux utilisateurs sont mal informés sur ce
sujet et nous allons tenter en quelques lignes de dégager les points importants.
Le système Linux a une particularité : il y a dans une distribution Linux une grande quantité de
code source provenant de projets libres externes (GNU, X, KDE, etc.) donc non spécifique à Linux.
C’est la raison pour laquelle les puristes parlent de système " GNULinux " et non de système "
Linux ". Au niveau des licences, la conséquence est la cohabitation de plusieurs licences libres.
•
•
•
•
•
•
GNU GPL (General Public License) ;
GNU LGPL (Lesser GPL) ;
BSD (Licence Berkeley) ;
X (Licence X Window/X.org) ;
MPL (Mozilla Public License) ;
etc.
Si l’on se place du point de vue du développeur, la GPL est plus " contraignante " que la plupart des
autres licences libres, car elle est stricte sur deux points importants.
•
•
1. La notion de " travail dérivé ". Un code source dérivé – au sens large – d’un code sous
GPL doit rester sous GPL.
2. L’édition de lien entre du code GPL et du code propriétaire n’est pas autorisée sauf dans
certains cas très précis (voir la FAQ de la licence GPL). En particulier, et contrairement à
certaines croyances, le fait d’effectuer une édition de lien dynamique (utilisation de
bibliothèques partagées) n’est pas suffisante pour s’affranchir de la GPL.
C’est la raison pour laquelle de nombreuses bibliothèques importantes sont diffusées sous Lesser
GPL (LGPL) et non sous GPL. Dans le cas de la LGPL, la contrainte de l’édition de lien disparaît.
Le cas le plus flagrant est la GNULibc (glibc) utilisée par tous les programmes de l’espace
utilisateur (sauf ceux qui sont compilés en mode statique). Pour cette raison, la GNULibc est
diffusée sous LGPL.
En résumé, il est relativement aisé de développer du code propriétaire dans l’espace utilisateur de
Linux.
Le cas de l’espace noyau est très différent. Si l’on reprend le début du paragraphe précédent, on note
que cet espace est réservé au noyau Linux et à ses extensions (les modules). Le noyau Linux étant
diffusé sous GPL, on en déduit que seule la GPL est théoriquement utilisable dans cet espace. Si
l’on reprend les propos de Linus Torvalds sur ce sujet, les choses sont claires comme l’indique un
courrier de Linus datant du 4 décembre 2003 et posté sur la liste LKML (Linux Kernel Mailing
List) :
It is very clear: a kernel module is a derived work of the kernel by default. End of story.
You can then try to prove (through development history, etc.) that there would be major reasons why
it’s not really derived. But your argument seems to be that nothing is derived, which is clearly totally
false, as you yourself admit when you replace “kernel” with “Harry Potter”.
Linus
Un autre courrier posté le même jour est tout aussi clair :
So you can run the kernel and create nonGPL’d programs while running it to your hearts content.
You can use it to control a nuclear submarine, and that’s totally outside the scope of the license (but
if you do, please
note that the license does not imply any kind of warranty or similar).
BUT YOU CAN NOT USE THE KERNEL HEADER FILES TO CREATE NONGPL’D
BINARIES.
Comprende?
Linus
Bien évidemment, il existe des modules Linux diffusés sous forme binaire, mais, en toute rigueur,
ils ne devraient pas exister. Si l’on se place du coté des fabricants de matériel, il est cependant clair
que la GPL est une contrainte forte, puisqu’il n’est théoriquement pas possible de placer des
informations non diffusables (relevant de la propriété intellectuelle) dans l’espace du noyau. C’est la
raison pour laquelle il existe une certaine tolérance visàvis de ces écarts et qu’il est techniquement
possible d’utiliser un module binaire.
Nous verrons plus loin que le module binaire est intimement lié à la version du noyau. De ce fait, un
module binaire pourra être utilisé uniquement dans l’environnement de noyau ayant servi à sa
génération, ce qui représente une contrainte non négligeable.
Lorsque l’on interroge Linus sur ce sujet, il tolère cet état de fait à partir du moment ou il ne s’agit
pas de travail dérivé (voir l’interview par Alessandro Rubini datant de septembre 1998).
Alessandro : What is your position about the availability of Linux modules in binaryonly form ?
Linus : I kind of accept them, but I never support them and I don’t like them.
The reason I accept binaryonly modules at all is that in many cases you have for example a device
driver that is not written for Linux at all, but for example works on SCO Unix or other operating
systems, and the manufacturer suddenly wakes up and notices that Linux has a larger audience than
the other groups. And as a result he wants to port that driver to Linux.
En résumé, les choses sont assez claires.
•
•
•
•
1. Dans l’espace du noyau, SEULE LA GPL est théoriquement utilisable. L’utilisation d’une
autre licence et, a fortiori, la diffusion de modules binaires relèvent de la tolérance.
2. La diffusion de modules binaires est très contraignante pour l’utilisateur final, puisque le
module fonctionne uniquement pour la version de noyau prévue lors de la compilation du
module.
3. Le fait que le module soit chargé dynamiquement ne change rien au problème de licence.
4. Dans le cas de problème de propriété intellectuelle, il est conseillé – si possible – d’isoler
les portions de code concernées dans l’espace utilisateur. Les portions de code dans l’espace
noyau devront alors être suffisamment génériques pour être diffusées sous GPL. En gros,
cela correspond à réduire le niveau de complexité du module quitte à reporter la complexité
dans l’espace utilisateur.
Présentation de l’API des modules
La suite du document décrit l’API des modules Linux pour le noyau 2.6. Comme à l’accoutumée,
nous nous baserons sur un exemple simple qui évoluera au fur et à mesure de la démonstration.
Historique et introduction
Les modules Linux furent introduits en 1995 lors de la sortie de la version 1.2 du noyau. Nous
rappelons qu’il existe deux manières de valider le support d’un périphérique dans le noyau Linux.
•
•
1. Compiler ce pilote dans la partie statique du noyau (le fichier bzImage ou vmlinuz)
2. Compiler ce pilote en tant que module. Ce dernier sera chargé ultérieurement si
nécessaire. Nous verrons plus tard que le chargement peut s’effectuer manuellement ou bien
de manière automatique.
Si nous devons ajouter le support d’un périphérique inconnu du noyau, il est évident que la première
solution n’est pas envisageable, puisqu’elle impliquerait de modifier le code source du noyau. De ce
fait, nous traiterons uniquement le cas des modules, car dans un système Linux moderne (soit
depuis 1995), un pilote est forcément un module (mais un module n’est pas forcément un pilote).
On peut faire une analogie entre un module et une bibliothèque dynamique qui serait chargée dans
l’espace utilisateur par la primitive dlopen(). Le déchargement du module est similaire à
l’utilisation de la primitive dlclose() dans l’espace utilisateur.
Exemple du module " Hello World "
Afin de simplifier le problème, nous allons partir d’un exemple de module simple (le traditionnel
Hello World). Malgré sa simplicité, la mise en place de ce module nous permettra de découvrir les
concepts fondamentaux de la programmation dans l’espace noyau. Pour tester le module présenté, il
faut bien entendu disposer de la chaîne de compilation GNU, mais également des sources du noyau
2.6 livrés avec la distribution ou bien chargés depuis http://www.kernel.org (vanilla kernel).
La référence de l’API utilisée sera celle du noyau 2.6.
•
•
•
•
•
•
•
structure du code source d’un module ;
fonctions module_init() et module_exit() ;
utilisation de printk() et interface avec le système de trace du système ;
fichier Makefile associé ;
macros d’identification du module ;
test de chargement/déchargement ;
installation dans l’arborescence du noyau.
Le fonctionnement du module en question est trivial : au chargement, il affiche le message Hello
World dans le système de trace. Au déchargement, il affiche le message Goodbye cruel world.
Un module minimal comme le nôtre contient au moins les fichiers d’entête suivants. Le fichier
linux/kernel.h est nécessaire dès lors que l’on utilise la fonction printk() qui est l’homologue de
printf() en espace noyau. L’accès aux fichiers d’entête est relatif au répertoire des sources du
noyau, soit en général /usr/src/linux2.6.x.
#include <linux/module.h>
#include <linux/kernel.h>
/* API des modules */
/* Pour KERN_INFO dans printk() */
Le paramètre KERN_INFO indique le niveau d’erreur associé au message. Dans notre cas, il s’agit
d’un simple message de trace. Les valeurs sont définies dans linux/kernel.h.
#define
#define
#define
#define
#define
#define
#define
KERN_EMERG
"<0>"
/* system is unusable
*/
KERN_ALERT
"<1>"
/* action must be taken immediately */
KERN_CRIT
"<2>"
/* critical conditions
*/
KERN_ERR
"<3>"
/* error conditions
*/
KERN_WARNING "<4>"
/* warning conditions
*/
KERN_NOTICE "<5>"
/* normal but significant condition */
KERN_INFO
“<6>”
/* informational
*/
Plik z chomika:
musli_com
Inne pliki z tego folderu:
Linux System Programming Talking Directly to the Kernel and C Library.pdf
(8858 KB)
Unix Network Programming Volume 1.pdf
(14024 KB)
Unix Network Programming Volume 2.pdf
(21636 KB)
Developpement d un espiogiciel d evaluation.pdf
(1302 KB)
Developpement avance d un rootkit pour les modules du noyau.pdf
(970 KB)
Inne foldery tego chomika:
3D Design - Programming
ActionScript
Actionscript - Flash - Flex - Air
Ada
ADO
Zgłoś jeśli
naruszono regulamin