Formation linux
noyau et drivers
© Copyright Eurogiciel – RENNES
Thierry GAYET
Thierry.Gayet@eurogiciel.fr
FORMATION
LINUX
TIMING DE LA FORMATION
Timing journalier :
 Matin :
09h00-10h30 : première partie
10h30-10h45 : pause
10h45-13h00 : seconde partie
 Pause déjeuner
 Après-midi :
14h00-15h30 : troisième partie
15h30-15h45 : pause
15h45-17h00 : quatrième partie
 Questions libres.
 merci de signaler toute contrainte de temps sur cette période dès le début.
FORMATION
LINUX
PLAN DE LA FORMATION
 Introduction
 Generation d’un noyau linux
 Execution
 Architecture du noyau
 Méthodologie
 Architecture du noyau
 Développement
 Kthreads
 Synchronisation
 Liste chaînée
 Queue de travail
 /proc et /sys
 Mise au point
 DMA
 Interruptions
 Timers et horloges
FORMATION
LINUX
INTRODUCTION
 Historique :
 Unix
 GNU Linux
 Organisation du projet
 Métriques & caractéristiques
 Nouveautés de la version 2.6
 Versioning du noyau
 Problématiques de la licence GPL
4
BUT : comprendre le projet GNU Linux
FORMATION
LINUX
Origine d’Unix
1969 Ken Thompson (laboratoires de Bell) écrit la première version de ce qui devait par la suite s'appeler Unix. Le nom "Unix" était à l'origine un
calembour sur le système d'exploitation Multics (Multiplexed Information and Computing Service) et a été écrit "Unics" en premier lieu
(UNiplexed Information and Computing System). Cette première mouture a fonctionné sur un DEC PDP-7. En 1970, Ken Thompson et Dennis
Ritchie l'adaptent au DEC PDP-11/20. Il résultat de cette expérience le premier compilateur C. Le langage C a été conçu spécifiquement pour un
OS portable. Ces versions initiales ont été intitulées "la Version n" ou "la Énième Edition ».
1971 La première version d'Unix, avec l'assembleur du PDP-11/20. Incluant les systèmes de fichiers, fork(), roff, ed, elle a été employée comme un
outil de traitement de texte pour la préparation de brevets d'invention. La fonction pipe() est apparue pour la première fois dans la V2.
1973 Ritchie et Thompson réécrivent le noyau d'Unix en C.
1974-1977 Le code source d'Unix est distribué librement aux universités (dû, au moins en partie, aux restrictions commerciales des USA à ATT). En
conséquence, UNIX a gagné la faveur de la communauté scientifique et universitaire. Il a été ainsi à la base des systèmes d'exploitation des
principales universités.
1978 UNIX, 7ème édition. Cette version a été développée expressément pour être portée sur diverses architectures matérielles. En outre, avec la
version 7, ATT annonce qu'ils font payer des licences pour accéder aux sources du système. En conséquence, la version 7 forme la base de toutes
les versions d'Unix actuellement disponibles. Les écrits de Brian Kernighan et Rob Pike (deux chercheurs des laboratoires Bell fortement
impliqués dans le développement d'Unix) présentent la philosophie de conception d'Unix. Commençant par la structure de base d'Unix et son
exécution, il conclut avec la programmation du système inférieur en C. Pour beaucoup, c'est le "dernier vrai Unix", "une amélioration sans
précédent" [Bourne]. Il a inclus la version complète de K&RC, uucp, Bourne shell. Le noyau V7 avait une taille de seulement 40 Ko ! Voici les
fonctions de la V7 : _exit, access, acct, alarm, brk, chdir, chmod, chown, chroot, close, creat, dup, dup2, exec*, exit, fork, fstat, ftime, getegid,
geteuid, getgid, getpid, getuid, gtty, indir, ioctl, kill, link, lock, lseek, mknod, mount, mpxcall, nice, open, pause, phys, pipe, pkoff, pkon, profil,
ptrace, read, sbrk, setgid, setuid, signal, stat, stime, stty, sync, tell, time, times, umask, umount, unlink, time, ait, write.
1979 L'annonce d'ATT de son intention de commercialiser UNIX a incité l'université de Californie à Berkeley pour créer sa propre variante : BSD
UNIX. Les versions les plus répandues de BSD sont la 4.2 (1983) et la 4.3 (1987). Le développement commandité par le DARPA (Defense
Advanced Research Projects Agency) d'Internet était basé sur le BSD UNIX. La plupart des premiers constructeurs commerciaux d'Unix (Sun
(SunOS), DEC (Ultrix), etc...) se sont en grande partie basés sur le BSD UNIX. De plus beaucoup de plates-formes hardware (de mini à Cray)
utilisent le BSD. Le manuel d'administration de système Unix par Nemeth, Snyder et Seebass est publié. Le système V d'ATT y est détaillé. La
deuxième édition , éditée en 1995, est une mise à jour qui traite de Solaris 2.4, SunOS 4.1.3, HP-UX 9.0, DEC OSF/1 2.0, IRIX 5.2 et BSDI 1.1.
5
FORMATION
LINUX
Origine d’Unix
1983 ATT met en vente la version commerciale du système V.
1987 Diffusion de X Window, une interface client/serveur graphique développée au MIT (Massachussetts Institute of Technology). La
version 3 du système V d'ATT est opérationnelle . C'est la version qui a forcé les constructeurs principaux (HP (HP-UX) et IBM
(AIX), a développer un OS propriétaire. C'est également en 1987 que la version 4.3 de BSD a été développée. Et finalement, c'est
cette année là qu'ATT et Sun ont choisi conjointement d'unifier le Système V et BSD.
1990 La version 4 du système V d'ATT comporte de nouveaux standard d'unification d'UNIX. C'est le résultat de la coopération entre Sun
et ATT. Cependant, d'autres grands constructeurs (en particulier DEC, HP et IBM) se sentant menacés par cette collaboration entre
deux des plus grands développeurs d'Unix ont décidés de créer l'OSF(Open Software Foundation). Le Perl, langage de
programmation écrit par Larry Wall spécifiquement pour les besoins de gestion d'Unix s'est grandement répandu. Tandis que le C est
le langage de choix pour la programmation système d'Unix, le Perl st le langage pour la gestion de systèmes Unix (Majordomo et
ftpmail sont juste deux exemples des programmes significatifs écrits en Perl).
1991 OSF-1 .C'est l'année ou les clones d'Unix comme Linux et FreeBSD ont commencé à émerger.
1992 Sun développe son OS, Solaris, un dérivé de la version 4 du système V avec la gestion des threads. Ces versions Vn ont été
développées par le Computer Research Group (CRG) des Laboratoires Bell. Un autre groupe, le Unix System Group (USG), était
responsable du support. Un troisième groupe aux Laboratoires Bell a été aussi impliqué dans le développement d'Unix, le
Programmer's WorkBench (PWB), auquel l'on doit, par exemple, sccs, le nom pipes et d'autres idées importantes. Tous les groupes
ont fusionné dans le Laboratoire de Développement de Système Unix en 1983. CB Unix (Columbus Unix) était une autre variante
d'Unix de la branche Columbus des Laboratoires Bell, responsables de Systèmes d'Appui d'Opérations. Sa principale contribution fut
les parties de SV IPC. Dans les années 1980, le travail sur Unix continua aux Laboratoires Bell. La série V a été poussée plus loin
par le CRG (Stroustrup mentionne V10 dans la seconde édition de son livre sur le C++), mais on ne parla pas beaucoup de cela par la
suite. La société maintenant responsable d'Unix (le Système V) est appelée Unix System Laboratories (USL) et appartient en
majorité à AT&T. Novell a acheté USL (au début de 93) et il a donné des droits à la marque déposée "UNIX" à X/Open (à la fin de
93). Mais des changements sont encore survenus sur Unix en dehors d'AT&T, particulièrement à Berkeley.
6

Le projet alternatif GNU Hurd propose un autre noyau à celui de GNU Linux mais celui-ci n’a jamais eu autant
de succès que Linux.
http://www.gnu.org/software/hurd/hurd.html
FORMATION
LINUX
Synthèse des UniX
Famille système III et V
Temps
7
FORMATION
LINUX
Petit historique de Linux
 1991: Le noyau Linux est écrit à partir de zéro (from scratch) en 6 mois par Linus Torvalds dans sa
chambre de l'université d'Helsinki, afin de contourner les limitations de son PC 80386.
 1991: Linus distribue son noyau sur Internet. Des programmeurs du monde entier le rejoignent et
contribuent au code et aux tests.
 1992: Linux est distribué sous la licence GNU GPL
 1993 : Première distribution Slackware avec le noyau 0.99
 1994: Sortie de Linux 1.0
 1994: La société Red Hat est fondée par Bob Young et Marc Ewing, créant ainsi un nouveau modèle
économique basé sur une technologie OSS.
 1995-: GNU/Linux et les logiciels libres se répandent dans les serveurs Internet.
 2001: IBM investit 1 milliard de dollars dans Linux
 2002-: L'adoption massive de GNU/Linux démarre dans de nombreux secteurs de l'industrie.
8
 Linux 2.6.32 : 12 Millions SLOC
FORMATION
LINUX
Petit historique de Linux
9
 Crée par Linus Torvalds en 1991 pour ses besoins personnels:
 découvrir les entrailles des systèmes d'exploitation
 pas de UNIX financièrement accessible à l'époque
 insuffisances et inertie de Minix
 Choix de l'environnement GNU
 outils de développement (compilateur, ...)
 outils système (bash, ls, cp...)
 Publication des sources sur Internet
 Choix de la licence GPL (oblige a redistribuer le code issu des modifications)
Linux : LINUs + uniX
FORMATION
LINUX
Linux : premier contact
Path: gmdzi!unido!fauern!ira.uka.de!sol.ctr.columbia.edu!zaphod.mps.ohio-state.edu!
wupost!uunet!mcsun!news.funet.fi!hydra!klaava!torvalds From:
torva...@klaava.Helsinki.FI (Linus Benedict Torvalds) Newsgroups: comp.os.minix
Subject: What would you like to see most in minix? Summary: small poll for my new
operating system Keywords: 386, preferences Message-ID:
<1991Aug25.205708.9541@klaava.Helsinki.FI> Date: 25 Aug 91 20:57:08 GMT
Organization: University of Helsinki Lines: 20
Hello everybody out there using minix –
I'm doing a (free) operating system (just a hobby, won't be big and professional
like gnu) for 386(486) AT clones. This has been brewing since april, and is
starting to get ready. I'd like any feedback on things people like/dislike in
minix, as my OS resembles it somewhat (same physical layout of the file-system
(due to practical reasons) among other things).
I've currently ported bash(1.08) and gcc(1.40), and things seem to work. This
implies that I'll get something practical within a few months, and I'd like to
know what features most people would want. Any suggestions are welcome, but I
won't promise I'll implement them :-)
Linus (torva...@kruuna.helsinki.fi)
PS. Yes - it's free of any minix code, and it has a multi-threaded fs. It is NOT
portable (uses 386 task switching etc), and it probably never will support
anything other than AT-harddisks, as that's all I have :-(.
Premier post effectué par Linux Torvald sur le forum Usenet (newsgroup) :
http://www.minix3.org/ 10
FORMATION
LINUX
Organisation du
développement
Une hiérarchie bien éprouvée…
11
FORMATION
LINUX
Organisation du
développement Linus TORVALD
Le décideur et responsable du projet,
propriétaire du nom "Linux".
Andrew MORTON
Adjoint au projet, le numéro 2
Alan COX
responsable de la partie réseau
Russell KING
responsable de l'architecture ARM
Andi KLEEN
responsable de l'architecture x86-64 Alexander Viro
David Miller
CORE MAINTENERS
Greg Kroah-
Hartman
SuSE Labs
etc … 12
FORMATION
LINUX
Gestion et organisation du projet

http://opensource.mit.edu/papers/dafermoslinux.p
df

http://catb.org/~esr/writings/cathedral-bazaar/
Organisation de la gestion du projet GNU Linux
à partir de Linus Torvald.
13
FORMATION
LINUX
Cycle de développement
14
FORMATION
LINUX
Le processus de développement
 Le code remonte de la base à Linus Torvalds :
 Les développeurs de base proposent leurs modifications :
• Elles sont débatues sur la LKML (Linux Kernel MailList) ;
• Des aller-retours avec les responsables de sous systèmes permettent de les rafiner : Linus
Torvalds intervient parfois dès ce stade ;
 Les modifications solides et très demandées sont intégrées à l'arbre d'Andrew Morton pour
plus de tests (après discussions) :
 Plus de visibilité, tests et commentaires, dont ceux de Torvalds,
 Le code est intégré s'il est prouvé solide, élégant et utile (Linux Torvalds définit son rôle de
décideur comme « le pouvoir de dire non ») ;
 Un processus souvent plus chaotique que cette description idéalisée.
http://vger.kernel.org/vger-lists.html
15

http://www.kernel.org/pub/linux/docs/lkml/

http://lkml.org/

http://vger.kernel.org/vger-lists.html

http://en.wikipedia.org/wiki/Linux_kernel_mailing_list
FORMATION
LINUX
Les développeurs du noyau
" Un travail de longue durée par une équipe de Geeks / Nerds / professionnels passionnés. "
16
FORMATION
LINUX
Le processus de développement
 Le développement du noyau « mainline » :
 Une fenêtre d'ajouts de fonctionnalités (merge window) :
• Durée d'environ 2 semaines,
• Clôture officielle par la sortie d'une pré-version -rc1,
• Parfois, des oublis contaminent la pré-version suivante ;
 Une période de stabilisation :
• Seulement des corrections,
• Un -rc par semaine environ jusqu'à la stabilité apparente,
• Un objectif à 2 mois (en pratique, jusqu'à 3) ;
 Sortie de la version officielle :
 Cette version est rarement parfaite,
 Maintien d'une liste de régressions par Michal Piotrowski
(http://kernelnewbies.org/known_regressions).
 Quelques chiffres :
 Nouvelle release tous les 2 mois et 1/2
 2,89 changement par heure
 8,2 millions de ligne de code
 2000 lignes de code ajoutés tous les jours
 2800 lignes modifiés chaque jour
17
FORMATION
LINUX
Acteurs professionnels du noyau Linux
http://www.kernel.org/pub/linux/kernel/people/gregkh/kernel_history/ 18
Plus de 3200 développeurs tous les 2 ans et demi
FORMATION
LINUX
Croissance du noyau GNU
Linux
 La version 2.6.32 du noyau a été publiée le 2 décembre 2009
19
10% de
croissance 2.89 changements par heure
8.2 million de lignes de code
2000 ligne de code ajoutés chaque jour
2800 ligne de code modifiés chaque jour
7 jours sur 7 et 24 heures sur 24 : linux est un projet mondial en continuelle évolution.
FORMATION
LINUX
Quelques branches de développements
 Les architectures alternatives :
 ARM : http://www.arm.linux.org.uk/
 MIPS : http://www.linux-mips.org/
 SH4 : http://sourceforge.net/projects/linuxsh
 Power PC : http://penguinppc.org/
 uClinux : http://www.uclinux.org/ (destiné aux microcontroleurs)
 Quelques branches de développement :
 USAGI (IPv6) : http://www.linux-ipv6.org/
 les ordonnanceurs expérimentaux :
• SD : http://members.optusnet.com.au/ckolivas/kernel/
• CFS : http://people.redhat.com/mingo/cfs-scheduler/
 RT-preempt : http://people.redhat.com/~mingo/realtime-preempt/
 Des projets comme Google Android ont un clone du repository du noyau linux.
20
FORMATION
LINUX
Caractéristiques principales de Linux
 Noyau monolitique (pas de micro-noyau) : tout le code du noyau tourne sur le même espace
d’adressage. Les briques indépendament les unes des autres.
 Multi-tâches (préemptif à partir de 2.6) : possibilité de gérer plusieurs processus en parallèle ;
 Réentrant : possibilité d’appels concurrents (entre processeurs sur machines SMP, entre gestionnaire
d’IRQ et appels systèmes) ;
 Multi-processeurs : support SMP
 Multi-utilisateurs : possibilité d’avoir plusieurs utilisateurs connectés en parallèles ;
 Multi-plateforme (portabilité et support matériel) : voir liste des processeurs supportés ;
 Scalabilité : tourne aussi bien sur des devices embarqués , que sur des super calculateur comme les
célèbres CRAY ;
 Conformité et interropabilité : avec les standards POSIX, CIFS, etc … ;
 Support réseau : pile très complète (issue de BSD) ;
 Sécurité : grsecurity, selinux, revues de code (couvertures) ;
 Robustesse : code stable et fiable grace au travail de la communauté ;
 Licence : logiciel libre mais couvert par la GPL ; code source indépendant des Unix commerciaux ;
 Modularité : possibilité de chargement de modules en dynamique.
21
FORMATION
LINUX
Portabilité
 Il est développé principalement en langage C (pas de langage objet tel que le C++) avec une
légère couche en assembleur. Ce découpage est hérité directement du système MINIX qui a
inspiré Linus Torvald dès la version 0.01 du noyau GNU Linux.
 Pour les portages sur une nouvelle architecture, il convient donc d'adapter cette dernière.
 En résumé, ce qui est propre à une architecture donnée est localisé dans le répertoire arch/ des
sources du noyau.
 Minimum: processeurs 32 bits avec ou sans MMU (Memory Management Unit)
 Architectures 32 bits:
alpha, arm, cris, h8300, i386, m68k, m68knommu, mips, parisc, ppc, s390, sh, sparc, um, v850
 Architectures 64 bits:
ia64, mips64, ppc64, sh64, sparc64, x86_64
 Voir arch/README ou Documentation/arch/README pour plus de détails.
22
FORMATION
LINUX
Numérotation des versions du noyau
Linux
Les versions sont numérotées : XX.YY.ZZ.KK
XX : le numéro majeur définit la version.
YY : le numéro mineur de la version :

Avant la version 2.6, ce numéro désignait le type de la version
: s’il était impaire la version était de développement et si elle
était paire elle était stable ;

Désormais, il faut considérer que toute version doit être
stable. Chaque version étant placé en branche avec Z comme
numéro de version intermédiaire. Le début du développement
est lancé par un premier gel des fonctionalités attendus
(features freeze). A la fin de la période de développement, il y
a un second gel (code freeze) des développements entrainant
un merge vers la branche main ce qui donne une version pre-
release. Ce merge lance l’étape de débug et de correction.
Cela doit donner lieu à des versions intermédiaire appelés
Release Candidate (RC). La version finale est la version dite
stable. Cette version servira de référentiel initial pour les
patchs successifs.
XX.YY : Elle désigne une génération (ou branche) du noyau.
ZZ : désigne la version dans la génération actuelle.
KK : désigne les corrections de bugs (patchs) depuis
XX.YY.ZZ 23
Arbre des versions
FORMATION
LINUX
Evolutions des versions
 Linux 0.01 (août 1991) : La toute première
 Linux 0.02 : Annonce officielle
 Linux 1.0 (mars 1994)
 x86 seulement,
 Monolithique
 Linux 1.2 (1995)
 Ajout d'Alpha et Sparc
 Linux 2.0 (mi-1996)
 MIPS, Power PC, m68k
 Modulaire
 Multi-processeur
 Linux 2.2 (janvier 1999)
 Ultra Sparc et ARM
 Linux 2.4 (janvier 2001)
 IA64 (Itanium), MIPS64,
 IBM S390 et SuperH
 support grand systèmes
 USB, PnP, hotplug,
 firewall stateful
 Linux 2.6 (fin 2003)
Quelques versions majeures …
24
 Linux 1.x / 2.0 / 2.2
 Branche plus maintenue.
 Linux 2.4
 Mûr et exhaustif
 Mais les développements sont arrêtés; peu de
développeurs voudront apporter leur aide.
 Sera définitivement obsolète
lorsqu'un nouveau produit sera lancé.
 Toujours bien si les sources, outils et support
viennent de vendeurs Linux commerciaux.
 Tend à devenir obsolète.
 Linux 2.6 : la version courante
 Supporté par la communauté de développeurs de
Linux
 Désormais mature et exhaustif. La plupart des
pilotes ont été mis à niveau.
 Toutes nouvelles fonctionnalités et performances
accrues
Etat actuelle des versions :
http://www.linux-foundation.org/publications/
FORMATION
LINUX
Frise chronologique des versions
25
FORMATION
LINUX
Nouveautés du noyau 2.6
 Un nouvel ordonnanceur de tâches, nommé O(1) a fait son apparition. Celui-ci tient beaucoup mieux la
charge quand de nombreuses tâches concurrentes s'exécutent, et privilégie une répartition équitable du
temps de calcul entre celles-ci.
 Le noyau 2.6 est capable de gérer plus de 4 Go de mémoire physique sur des machines x86 32 bits.
 Ce noyau apporte NPTL, une bibliothèque optimisée pour la gestion des threads POSIX et Futexes des
sémaphores optimisées pour les processus.
 L'interactivité du nouveau noyau a été largement améliorée. Ainsi, des modifications visant à diminuer
le temps d'exécution des appels systèmes (patchs low-latency et preempt) ont été intégrés.
 Simplification de devfs en udev.
 La granularité de l'horloge (tick) est passée de 10 ms à 1 ms.
 L'architecture ALSA, qui fournit un système avancé de gestion des cartes sons, a été intégrée au noyau,
en lieu et place d'OSS.
 Concernant les systèmes de fichiers, de nombreuses optimisations sont disponibles pour ext2/ext3/ext4 :
EA, ACL, répertoires indéxés et allocateur Orlov.
 Côté périphériques, plus besoin d'émuler un graveur IDE en SCSI pour graver. Notez également le
support amélioré de l'USB 2 et de l'ACPI.
 Une dernière amélioration très importante est l'incorporation d'un ordonnanceur intelligent des accès
aux disques durs. Celui-ci limite très largement les déplacements de la tête de lecture du disque, et
apporte des débits élevés en cas d'accès concurrents.
26
FORMATION
LINUX
A propos des logiciels libres
 Le système d'exploitation GNU est un système complet de logiciels libres qui a
une compatibilité ascendante avec Unix. « GNU » signifie « GNU's Not Unix ».
Richard Stallman a fait l'annonce initiale du projet GNU en septembre 1983.
 Le noyau GNU Linux est un Logiciel Libre qui a été rattaché à GNU un an
après se création à savoir en 1992. La licence GPL2 auquel est rattaché Linux
est maintenu et défendu juridiquement par le Free Software Fundation (FSF).
 Pas de notions de gratuité mais plutôt de liberté.
 Les logiciels Libres donnent à l'utilisateur 4 libertés (ou contraintes) :
1. La liberté d'utiliser le programme, comme bon lui semble ;
2. La liberté d'étudier comment le programme fonctionne, et de l'adapter à
ses besoins ;
3. La liberté de redistribuer des copies pour aider les autres ;
4. La liberté d'améliorer le programme, et de distribuer les améliorations au
public
"Free software is a matter of liberty, not price. To understand the concept, you
should think of free as in free speech, not as in free beer."
http://www.gnu.org/philosophy/free-sw.html
http://www.gnu.org/gnu/gnu-history.fr.html
27
FORMATION
LINUX
La GNU General Public License (GPL)
 Les licences Copyleft se reposent sur le droit d'auteur pour exiger que toute version modifiée reste un
logiciel libre.
 La GNU GPL requiert que les modifications et les travaux dérivés soient aussi placés sous GPL:
 Ne s'applique qu'aux logiciels distribués (pas en test ou développement)
 Tout programme utilisant du code GPL (lié statiquement ou dynamiquement) est considéré comme une
extension de ce code et donc placé sous GPL
 Pour plus de détails :
 Copyleft: http://www.gnu.org/copyleft/copyleft.html
 FAQ GPL: http://www.gnu.org/licenses/gpl-faq.html
 Pour plus d'information pratique sur le sujet dans l'Union Européenne, contacter la Fondation pour une
Infrastructure de l'Information Libre : http://ffii.org/index.en.html
 Au jour d’aujourd’hui, Linux est rattaché à la GPL v2 depuis la version 2.4.0. Linus considère son
rattachement à la GPL comme une étape décisive : "best thing I ever did".
 Après une remarque d’Alan Cox, une enquête a été lancé en septembre 2006 auprès des développeurs du
noyau. Il en a résulté une préférence de la GPLv2 face la version 3 pour des questions de restrictions. Selon
les propres termes de Linux : "I think a number of outsiders... believed that I personally was just the odd
man out, because I've been so publicly not a huge fan of the GPLv3".
28
FORMATION
LINUX
Contraintes de licence sur le noyau
Linux
Exemple de contraintes au moment de distribuer :
 Aucune contrainte avant toute distribution. Vous pouvez partager vos modifications au début dans votre
propre intérêt, mais n'y êtes pas obligés !
 Pour tout périphérique embarquant Linux et des Logiciels Libres, vous devez distribuer vos sources à
l'utilisateur final. Vous n'avez aucune obligation de les distribuer à qui que soit d'autre !
 Les modules propriétaires sont tolérés (mais non recommandés) tant qu'ils ne sont pas considérés comme
dérivés de code GPL.
 Le portage d'un code fonctionnant déjà sous un autre système d'exploitation peut être exempt de
contamination avec la GPL.
 Les pilotes propriétaires ne peuvent pas être liés statiquement au noyau.
 Un pilote écrit de zéro est considéré comme une souche propre non contaminée.
 Aucun soucis pour les pilotes disponibles sous une licence compatible avec la GPL (détails dans la partie
sur l'écriture de modules)
 S'appliquent aussi lorsque vous développez dans des pays libres de brevets. Il se peut que vous ne
puissiez pas exporter vos produits.
 Pilotes noyau avec brevets: vérifiez toujours la description du pilote dans la configuration du noyau Les
problèmes avec des brevets connus sont toujours documentés.
 Préférer toujours les alternatives sans brevets (Linux RTAI au lieu de RTLinux, etc.)
29
FORMATION
LINUX
Modules binaires de Linux
 Une clause supplémentaire à la licence GPL auquel est rattaché Linux permet l’utilisation et la
distribution de modules binaires.
 Elle doit utiliser uniquement l’interface standard des modules.
 Il est cependant impossible de mettre à disposition de clients, des modules binaires compatibles avec
toutes les configurations possibles du noyau (Version , patch externes, …. ).
 Ce mode est légal juridiquement mais reste très déconseillé car aucune aide, ni de support n’est offert par
la communauté.
30
FORMATION
LINUX
Génération d’un noyau Linux
BUT : savoir configurer et générer un noyau GNU Linux
Phases pour la génération d'un noyau :
 Récupération du code source du noyau
 Vérification de l'intégrité des packages reçus
 Application et génération de patchs
 Génération d'une configuration
 Compilation
 Analyse des fichiers résultant
 Installation
FORMATION
LINUX
Paquets nécessaires pour la
compilation
 Pour installer le noyau 2.6.x, assurez-vous d'avoir les paquets suivants :
 la librairie ncurses-5, certaines distributions l'appellent libncurses5 et
libncurses5-dev (ou libncurses5-devel)
 l'utilitaire bzip2
 l'utilitaire gzip
 Gnu gcc 2.95.3 (commande : gcc --version)
 Gnu make 3.78 (commande : make --version)
 binutils 2.12 (commande : ld -v)
 util-linux 2.10 (commande : fdformat --version)
 module-init-tools 0.9.10 (commande : depmod -V)
 procps 3.1.13 (commande : ps --version)
 gpg
 Sous GNU Debian ou ubuntu il suffit d’installer le package build-essential
32
FORMATION
LINUX
Récupération des sources officiels
33
Plusieurs méthodes via différents protocoles :
 HTTP
 FTP
 NFS
 SMB / CIFS
 GIT
 RSYNC
 Packages d’une distribution officielle (RPM, DEB, …. )
serveurs anciennement maintenus par la
société Transmeta et gérés désormais par Linux Kernel
Organisation (CA/USA).
La homepage de kernel.org
FORMATION
LINUX
Récupération des sources officiels - http /
ftp
wget http://kernel.org/pub/linux/kernel/v2.6/linux-2.6.32.tar.bz
et
wget http://kernel.org/pub/linux/kernel/v2.6/linux-2.6.32.tar.bz.sign
34
 Téléchargement des sources via http depuis le site
http://www.kernel.org/pub/linux/kernel/v2.6/ :
l peut être aussi nécessaire de récupérez une mise à jour (ensemble de correctifs) pour la version
 A noter que deux formats sont disponibles : tar.gz et tar.bz2 ; pour chaque type d’archive, il y a une signature
Associés.
wget ftp://ftp.kernel.org/pub/linux/kernel/v2.6/patch-2.6.32.bz
et
wget ftp://ftp.kernel.org/pub/linux/kernel/v2.6/patch-2.6.32.bz.sign
 Téléchargement des sources via ftp depuis le site ftp
://ftp.kernel.org/pub/linux/kernel/v2.6/ :
Pour ce protocole,la méthode est similaire au http.
Il vaut mieux utiliser ftp.xx.kernel.org où xx est votre code de pays, par exemple ftp.fr.kernel.org pour la France.
Pour extraire les sources dans le répertoire officiel (/usr/src/) : tar -xjvf linux-2.6.32.tar.bz2 -C /usr/src
FORMATION
LINUX
Vérification de l'intégrité des sources
 Détails sur GnuPG: http://www.gnupg.org/gph/en/manual.html
 Détails sur la signature des sources du noyau: http://www.kernel.org/signature.html
35
$ gpg --keyserver wwwkeys.pgp.net --recv-keys 0x517D0F0E
gpg: requête de la clé 517D0F0E du serveur hkp wwwkeys.pgp.net
gpg: clé 517D0F0E: clé publique « Linux Kernel Archives Verification Key <ftpadmin@kernel.org> » importée
gpg: aucune clé de confiance ultime n'a été trouvée
gpg: Quantité totale traitée: 1
gpg: importée: 1
$ gpg --verify linux-2.6.32.tar.sign linux-2.6.32.tar.gz
gpg: Signature faite le jeu. 03 déc. 2009 07:28:51 CET avec la clé DSA ID 517D0F0E
gpg: MAUVAISE signature de « Linux Kernel Archives Verification Key <ftpadmin@kernel.org> »
$ gpg --verify linux-2.6.32.tar.gz.sign linux-2.6.32.tar.gz
gpg: Signature faite le jeu. 03 déc. 2009 07:28:57 CET avec la clé DSA ID 517D0F0E
gpg: Bonne signature de « Linux Kernel Archives Verification Key <ftpadmin@kernel.org> »
gpg: ATTENTION: Cette clé n'est pas certifiée avec une signature de confiance !
gpg: Rien ne dit que la signature appartient à son propriétaire.Empreinte de clé principale: C75D C40A 11D7 AF88 9981
ED5B C86B A06A 517D 0F0E
 Vérification correcte de l'intégrité de l’archive téléchargé par ftp ou http :
 Exemple de vérification incorrecte :
Il faudra au préalable importer la clef publique du projet gnu linux kernel :
 Cette étape rarement effectuée est pourtant importante pour être sûr de l'intégrité du code source récupéré. Il en va de même pour
tout autre package open-source. Elle se doit d’être effectué à la fois pour le code du noyau mais aussi pour les patch.
FORMATION
LINUX
Récupération des sources officiels - git
36
 Téléchargement des sources via git :
 git est un logiciel de gestion de versions décentralisé (comme mercurial) écrits
par Linus
Torvald en remplacement de bitKeeper qui ne voulait plus proposer de version
gratuite de son
produit en 2005.
http://linux.yyz.us/git-howto.html
http://www.kernel.org/pub/software/scm/git/
http://kernel.org/pub/software/scm/git/docs/git-clone.html
$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git linux-2.6
 Cela va créer un répertoire linux-2.6 de plus de 300 Mo avec tous les sources du noyau. L’intérêt est d’avoir
en une fois toutes les branches, évolution effectué sur le code source du noyau.
 Petit memento d’usage de git :
 Checkout : git checkout –f
 Ajout ou suppression : git add ou git rm
 Commit : git commit –a
 Suppression les deux derniers commits : git reset HEAD^2
 Différentiel depuis le dernier ajout/suppression: git diff
 Différentiel depuis le dernier commit : git diff HEAD
 Création d’une branche : git checkout –b ma-nouvelle-branch master
 Résumé des opérations : git status
 Résumé des changements : git log
FORMATION
LINUX
Récupération des sources officiels
37
Récupération de paquets officiels :
 Mandriva
urpmi kernel-headers kernel-source
 Fedora
yum install kernel-source
 Debian
apt-get install kernel-headers-$(uname -r) kernel-source-$(uname -r)
 Ubuntu
apt-get install linux-headers-N°_de_noyau linux-source-$(uname -r)
 Slackware
installpkg /où_est/kernel-source-2.6.x.tgz /où_est/kernel-headers-2.6.x.tgz
 Gentoo
emerge gentoo-sources
FORMATION
LINUX
Application des patchs
 Commande patch: utilise la sortie (stdout) de la commande diff pour appliquer un ensemble de
changements à une arborescence de fichiers sources.
 Utilisation classique de patch :
 patch -sp<n> < diff_file
 cat diff_file | patch -sp<n>
 bzcat diff_file.bz2 | patch -sp<n>
 zcat diff_file.gz | patch -sp<n>
n: nombre de niveaux de répertoires à sauter
 Patches Linux:
 Toujours à appliquer sur la version x.y.<z-1>
 Toujours prévu pour n=1: patch -sp1 < linux_patch
 A noter qu'il est possible d'inverser un patch de la façon suivante :
patch -R -sp1 < ../patch-x.y.z
 Pour retrouver les patchs ayant échoués : find . -name '*.rej' -print
 A noter l’usage du paramètre ‘s’ permettant l’application d’un patch en mode silent ce qui fait gagner
30% de temps.
 Pour tester un patch avant application, il suffit d’utiliser l’option –dry-run
38
FORMATION
LINUX
Exemple d'application d'un patch
 Dump d'un Patch sur un fichier donné :
 Exemple d'utilisation :
 Applique dans ce cas les changements au header include/asm-arm/hardware.h. Un patch peut cependant être récursif et toucher donc un ensemble de
fichiers.
-pnombre : enleve le plus petit préfixe contenant nombre slashs de la tête de chaque nom de fichier trouvé dans le fichier
patch. Une séquence d'un ou de plusieurs slashs adjacents compte pour un slash unique. Cela contrôle la façon dont les
noms trouvés dans le fichier patch sont traités, au cas où vous conserveriez vos fichiers dans un répertoire différent de celui
qui a envoyé le patch. Par exemple, en supposant que le nom du fichier dans le fichier patch était u/howard/src/blurfl/blurfl.c
 Spécifier -sp0 donne le nom de fichier entier non modifié, -sp1 donne : u/howard/src/blurfl/blurfl.c
 Sans le slash de tête, -sp4 donne : blurfl/blurfl.c
 Ne pas spécifier de -sp du tout vous donne blurfl.c. Ce que vous obtenez finalement est recherché soit dans le répertoire courant,
soit dans le répertoire spécifié par l'option -d. 39
--- linux-2.6.8.1/include/asm-arm/hardware.h 2004-08-14 12:54:48.000000000 +0200
+++ linux-2.6.8.1_modified/include/asm-arm/hardware.h 2004-08-17
12:42:06.119650556 +0200
@@ -15,13 +15,4 @@
#include <asm/arch/hardware.h>
-#ifndef __ASSEMBLY__
-
-struct platform_device;
-
-extern int platform_add_devices(struct platform_device **, int);
-extern int platform_add_device(struct platform_device *);
-
-#endif
-
#endif
$ cd linux-2.6.8.1
$ patch -sp1 < hardware.diff
FORMATION
LINUX
Création d'un patch noyau
 Téléchargez la dernière version des sources du noyau sur lequel vous travaillez.
 Faites une copie de ces sources :
rsync -a linux-2.6.9-rc2/ linux-2.6.9-rc2-patch/
 Appliquez vos modifications aux sources copiés et testez les.
 Créez un fichier correctif («patch») :
diff -Nru linux-2.6.9-rc2/ linux-2.6.9-rc2-patch/ > patchfile
 Patchfile doit suivre une charte de nommage rappelant la version du noyau prise comme référence, le(s)
bug(s) corrigé(s).
 Comparez toujours la structure complète des sources (utilisable par patch -sp1)
Nom du fichier correctif: doit rappeler le problème résolu
40
La commande diff effectuant un différentiel récursif entre un ou plusieurs fichiers, les patchs doivent être
regénérés pour chaque version de kernel du fait de l'évolution du code source du noyau Linux.
FORMATION
LINUX
Utilisation de quilt
41
$ tar -zxf linux-2.6.19.tar.gz
$ cd linux-2.6.19
$ mkdir patches
$ quilt new patch1  Ajout d’un patch
Patch patches/patch1 is now on top
$ quilt add Makefile  Ajout du
Makefileà quilt
File Makefile added to patch patches/patch1
 Modification du Makefile
$ quilt refreshRefreshed patch patches/patch1  Mise à jour du patch
cat patches/patch1  Affichage du
patch courant
Index: linux-2.6.19/Makefile
===================================================================
--- linux-2.6.19.orig/Makefile
+++ linux-2.6.19/Makefile@@ -1,7 +1,7 @@
VERSION = 2
PATCHLEVEL = 6
SUBLEVEL = 19
-EXTRAVERSION =
+EXTRAVERSION = -dirty
NAME=Crazed Snow-Weasel
# *DOCUMENTATION*
Modifications successives
$ quilt series –v 
Affiche la série de patch
+ patches/patch1
http://linux.die.net/man/1/quilt
http://www.suse.de/~agruen/quilt.pdf
Démonstration par l’exemple :
FORMATION
LINUX
Utilisation de ketchup
42
http://www.selenic.com/ketchup/
 Ketchup est un script écrit en python permettant de passer une version linux donnés à une autre en téléchargeant les
patchs nécessaires.
 Il peut aussi bien avancer dans les versions suivantes que dans les versions précédentes.
 Il vérifié aussi les signatures des sources mais aussi des patch.
Exemple d’usage :
 Se placer dans le répertoire des sources du noyau :
$ cd linux-2.6.32
 Vérifier la version courante du noyau :
$ ketchup –m
2.6.32
 Aller à la dernière version :
$ ketchup –G 2.6-tip
 Aller à une version précédente :
$ ketchup –G 2.6.28
 L’option –G désactive la vérification des signatures

Le script ketchup doit être présent dans le path courant (/usr/bin/ketchup). De plus, il est nécess
Qu’un accès internet soit disponible.
FORMATION
LINUX
Remonter un bug du noyau Linux
 Premièrement, assurez vous d'utiliser la dernière version : intérêt de git permettant des différentiel
inter-version.
 Assurez vous d'avoir creusé le problème autant que possible: voir Documentation/BUG-HUNTING
 Assurez vous que le bogue n'a pas encore été signalé. Vérifiez en particulier la base de donnée
officielle des bogues Linux(http://bugzilla.kernel.org/).
 Si le sous-système pour lequel vous reportez un bogue a une liste de diffusion, utiliser la. Sinon,
contactez le mainteneur officiel (voir le fichier MAINTAINERS). Donnez toujours le plus de détails
possible.
 Ou remplissez un nouveau bogue dans http://bugzilla.kernel.org/
43
FORMATION
LINUX
Configuration du noyau
 Éditer le Makefile pour définir la version et l'architecture de la cible (si nécessaire) :
 La commande uname –r retournera : 2.6.32-montag
 Configuration : définir quelles fonctionnalités mettre dans le noyau. Plusieurs méthodes peuvent être utilisées :
 Pour récupérer la configuration actuelle d'un noyau 2.6 :
Option non disponible par défaut. Seulement si le kernel a été compile avec l'option : CONFIG_IKCONFIG_PROC = y
make config mode texte)
make menuconfig interface ncurses)
make allnoconfig positionne automatiquement toutes les options à no
make allyesconfig positionne automatiquement toutes les options à yes
make randconfig configure le noyau de façon aléatoire
make oldconfig chargement d'une ancienne configuration
make xconfig interface X utilisant le librairie graphique Qt/KDE
make gconfig interface X utilisant la librairie graphique de GNOME
 Il est aussi possible d'éditer la configuration à la main
Pour identifier l'image de votre noyau avec d'autres, compilées à partir des même sources, utilisez la variable
EXTRAVERSION:
VERSION = 2
PATCHLEVEL = 6
SUBLEVEL = 7
EXTRAVERSION = -montag
sudo zcat /proc/config.gz > /usr/src/linux/.config
44
FORMATION
LINUX
Configuration en mode texte
 make menuconfig :
Interface texte sous ncurses. Pratique également.
Vous pouvez aussi éditer le fichier .config à
la main ! Attention cependant aux
dépendances.
 make oldconfig
Permet de mettre à jour un fichier de config d'un
ancien noyau
Mise en garde pour les symboles optionnels
Demande les valeurs des nouveaux symboles
 make config :
mode texte, ou on choisit une à une toutes les
options (c'est à dire des centaines !), sans
possibilité de retour arrière.
Très fastidieux. Déconseillé.
45
 Il faudra d'abord installer le paquet libncurses-dev
FORMATION
LINUX
Configuration en mode graphique
 make xconfig :
 qconf: nouvelle interface Qt de
configuration pour Linux 2.6. Bien
plus facile à utiliser !
 Lisez help -> introduction:
vous y trouverez des options utiles!
 Navigateur de fichiers: plus simple
de charger les fichiers de
configuration
 Il faudra d'abord installer les paquets libqt3-mt-dev et g++
 Il faudra d'abord installer le paquet liglade2-dev.
 make gconfig :
Identique à xconfig, mais avec les
bibliothèques graphiques de gnome
(GTK).
46
FORMATION
LINUX
Fichier de configuration du noyau
47
## CD-ROM/DVD Filesystems
#CONFIG_ISO9660_FS=m
CONFIG_JOLIET=y
CONFIG_ZISOFS=y
CONFIG_UDF_FS=y
CONFIG_UDF_NLS=y
## DOS/FAT/NT Filesystems
## CONFIG_MSDOS_FS is not set
# CONFIG_VFAT_FS is not set
CONFIG_NTFS_FS=m
# CONFIG_NTFS_DEBUG is not set
CONFIG_NTFS_RW=y
Extrait de fichier .config généré 
Tous les nom de paramètres sont préfixés par CONFIG_
Compilé comme un module dans un fichier .ko séparé :
Options du drivers :
Compilé statiquement dans le noyau :
FORMATION
LINUX
Fichier de configuration du noyau
48
 La configuration du noyau inclus un système de dépendances entre les options :
Exemple : l’activation d’un driver réseau active la pile réseau
 Il existe deux types de dépendances :
 Dépendance sur dépendances : une option A dont dépend B reste invisible tant que B n’est pas
Activé
 Sélection de dépendance : avec une option A dépendant de B, quand A est activé, B est
automatiquement activé également.
 make xconfig perment d’afficher toutes les options même celles qui ne sont pas active. Dans cette
version, les options inactive sont juste grisés.
 Optimisations :
 Cette phase de configuration est importante pour choisir les drivers à inclure dans le noyau.
 Il faut éviter de laisser des drivers inutile car cela augmente la taille du noyau
 La part de drivers compilés en statique face aux modules dynamique doit être prise en compte au
sujet du temps de chargement du noyau en mémoire. Il en va aussi de l’initialisation.
 Trop de drivers compilés en statique inclu une phase de chargement longue sauf si XIP et AXFS sont
utilisés (eXecute In Place).
http://elinux.org/AXFS
http://www.scribd.com/doc/19855245/Application-eXecuteInPlace-XIP-with-Linux-and-AXFS
FORMATION
LINUX
Positionner les options
 Le moment est venu de choisir vos options. Si c'est la première fois que vous compilez le noyau, je vous
conseille de les passer toutes en revue les unes après les autres en lisant l'aide qui y est attachée, dans l'ordre,
afin de voir si elles s'appliquent à vous ou non.
 Dans l'outil de configuration du noyau, chaque question attend une réponse :
 'oui' (Y),
 'non' (N)
 ou éventuellement 'module' (M) pour rendre la fonctionnalité chargeable dynamiquement.
 De manière générale, il est bon de modulariser les fonctionnalités qui ne servent pas en permanence (lecteur de
CD, carte réseau, clefs USB, ...), mais tout n'est pas possible (enfin... pas simplement :).
 Par exemple, vous ne devriez pas mettre en module ce qui est utilisé lors du démarrage de votre ordinateur
(pilotes des disques-durs IDE, système de fichiers que vous utilisez pour votre partition /, ou encore le support
réseau si votre partition racine est montée par le réseau et NFS dans le cas des stations diskless par exemple,
etc). En effet, les modules sont chargés après le noyau, et si les modules IDE sont sur un disque IDE, il faut
d'abord les charger avant de pouvoir accéder au disque, mais pour les charger, il faut avoir accès au disque et
donc les avoir chargés avant... vous voyez le cercle vicieux ? En fait, il est possible de contourner ce problème
grâce à initrd, mais cela dépasserait l'ambition de ce document…
 Tout le reste peut être compilé en modules, c'est à dire carte son, carte réseau (sauf si votre racine est déportée
sur un serveur NFS comme dit précédemment), le support ppp (pour internet par modem), le CD-ROM, …
 Quoi qu'il arrive, dans le doute, il vaut mieux laisser les options par défaut.
 Les options correspondent à des fonctionnalités que vous pouvez activer/désactiver dans le noyau suivant
vos besoins. Elles sont organisées suivant différentes sections et sous-sections, nous allons ici décrire les
principales sections qui existent et en donner une brève description pour vous donner une idée des options
qu'elles peuvent contenir.
 Il est important de noter que d'une version à l'autre du noyau, les options, sous-sections ou même les
sections peuvent changer, mais l'idée générale reste conservée.
 Le fichier .config contient un ensemble d’éléments dépendante d’une architecture.
 Sans définition particulière, le système de génération du noyau linux génèrera un noyau compatible avec
le host
49
FORMATION
LINUX
Sections des options du noyau
 Les options section par section :
 Code maturity level options: Permet de cacher ou de faire apparaître les options qui sont encore en développement et donc
considérées comme instables (souvent utile de dire 'oui' ici si l'on veut pouvoir profiter des dernières avancées du noyau).
 General setup: Ensemble d'options générales sur votre système (sauf si vous voulez compiler pour des architectures très particulières,
vous pouvez le laisser tel quel).
 Loadable module support: Options concernant la gestion des modules (le défaut est presque toujours correct pour une utilisation
normale).
 Block layer: Les entrées/sorties sur votre carte-mère (peut être supprimé pour un usage embarqué)
 Processor type and features: Options relatives au(x) processeur(s): type (x86, Sparc, ...), hyper-thread, dual-core, SMP, etc.
 Power management options (ACPI, APM): Options concernant l'économie d'énergie, la mise en veille et l'ACPI/APM.
 Bus options (PCI, PCMCIA, EISA, MCA, ISA): Gestion de tous les endroits où vous pourriez enficher des cartes (PCI, PCMCIA,
ISA, etc).
 Executable file formats: La gestion des fichiers exécutable (Le support ELF doit toujours être à 'Y').
 Networking: Options concernant les protocoles réseau gérés par votre noyau (le défaut est bien souvent suffisant, mais jetez y un coup
d'œil à tout hasard).
 Device Drivers: Options concernant tous les pilotes matériel (c'est bien souvent ici que l'on passe le plus de temps).
 File systems: Options concernant les systèmes de fichiers gérés par votre noyau (vous aurez à y jeter un coup d'oeil).
 Instrumentation Support: Option de profilage du noyau (inutile de l'activer).
 Kernel hacking; Options de débogage du noyau (inutile de l'activer sauf si vous avez des envies particulières).
 Security options: Options concernant le modèle de sécurité de votre noyau (le défaut est suffisant)
 Cryptographic options: Algorithmes cryptographiques pouvant être implantés dans le noyau (le défaut est suffisant).
 Library routines: Bibliothèques communes du noyau (le défaut est suffisant) @
50
Ce listing étant parsé dynamiquement pour l’affichage, toute interrogation sur une option pourra
être complété par l’analyse du répertoire associé.
FORMATION
LINUX
Connaissance du
matériel
 PCI : lspci lspci -t
ou lspcidrake (sous mandrake)
01:00.0 VGA compatible controller: nVidia Corporation NV34M [GeForce FX Go 5200] (rev a1)
(prog-if 00 [VGA]) Subsystem: Samsung Electronics Co Ltd: Unknown device c00f Flags: bus
master, 66Mhz, medium devsel, latency 248, IRQ 11 Memory at c8000000 (32-bit, non-
prefetchable) [size=16M] Memory at d8000000 (32-bit, prefetchable) [size=128M] Expansion ROM
at <unassigned> [disabled] [size=128K] Capabilities: [60] Power Management version 2
Capabilities: [44] AGP version 3.0
 DMI (Desktop Management Interface) : dmidecode
[...] DMI type 2, 8 bytes.
Board Information Block
Vendor: ASUSTeK Computer INC.
Product: P4S8L
Version: REV 1.xx
Serial Number: xxxxxxxxxx [...]
 Disques IDE : hdparam
hdparm -i /dev/hda /dev/hda: Model=FUJITSU MHT2040AT, FwRev=0022,
SerialNo=NN77T3C13KB9 Config={ HardSect NotMFM HdSw>15uSec Fixed DTR>10Mbs }
RawCHS=16383/16/63, TrkSize=0, SectSize=0, ECCbytes=4 BuffType=DualPortCache,
BuffSize=2048kB, MaxMultSect=16, MultSect=16 CurCHS=16383/16/63, CurSects=16514064,
LBA=yes, LBAsects=78140160 IORDY=yes, tPIO={min:240,w/IORDY:120},
tDMA={min:120,rec:120} PIO modes: pio0 pio1 pio2 pio3 pio4 DMA modes: mdma0 mdma1
mdma2 UDMA modes: udma0 udma1 udma2 udma3 udma4 *udma5 AdvancedPM=yes:
mode=0x80 (128) WriteCache=enabled Drive conforms to: ATA/ATAPI-6 T13 1410D revision 3a:
51
La connaissance de son matériel permet de bien configurer son noyau :
FORMATION
LINUX
Connaissance du
matériel
 PROCESSEUR : cat /proc/cpuinfo
 USB : lsusb
 HARDWARE : lshw
 APCI : cat /proc/acpi/info
cat /proc/acpi/battery/BAT1/info
cat /proc/acpi/thermal_zone/THRM/temperature /proc/acpi/thermal_zone/THRM/trip_points
 Il faut aussi regarder les messages du noyau : dmesg
 Quelques liens :
 http://rhlinux.redhat.com/kudzu/
 http://www.freedesktop.org/wiki/Software/hal
 http://www.linux.org/apps/AppId_4812.html
 http://ezix.org/project/wiki/HardwareLiSter
 http://ezix.sourceforge.net/software/lshw.html
 http://smartmontools.sourceforge.net/
 http://www.nongnu.org/dmidecode/
 http://secure.netroedge.com/~lm78/
 http://www.nt.phys.kyushu-u.ac.jp/shimizu/download/download.html
52
FORMATION
LINUX
Compilation du noyau
 Pour une compilation croisée (pour une autre architecture) il faut modifier la plateforme cible par défaut :
 Compilation : make
 Phase la plus longue (Ex: 45 minutes pour compiler un noyau 2.6.15.4 (38 Mo compressé) sur un
portable Pentium 4 3,2 GHz avec 512 Mo de RAM).
 Pour compiler depuis un autre répertoire, il est possible de préciser le répertoire : make –C /linuxdir
 Possibilité de cumuler plusieurs action sur une seule commande : make && make install
ou bien : make ; make install
 Nettoyage :
 make clean : nettoye les fichiers générés (force la recompilation des drivers)
 make mrproper : même action que le make clean mais supprime aussi le .config
 make distclean : nettoye toute l’arborescence de fichiers temporaires issue des editeurs et des
applications de patch (au lieu de faire soit même : find . -name '*.orig' | xargs rm)
(surtout utile pour la création de patchs)
 En version 2.4, il fallait faire : make dep && make clean && make bzImage puis make modules
 Les commandes suivantes ne sont plus nécessaires en 2.6 : make depends
ARCH ?= arm
CROSS_COMPILE ?= arm-linux- (préfixe du compilateur croisé)
Ou bien définit les variables en même temps que make ARCH=arm CROSS_COMPILE=arm-linux-
(Utile quand vous compilez pour différentes plateformes)
Voir les commentaires dans les Makefile du noyau Linux pour plus de détails
53
FORMATION
LINUX
Installation du noyau
 Autres commandes du makefile :
 make prepare : adapte le fichier version.h et crée un lien symbolique de include/asm vers include/asm-<ARCH>.
 make script : compile des outils
 make bzImage : crée une image compressée le noyau dans arch/<ARCH>/boot/bzImage
 make fdimage : crée une image à destination d’une disquette 1.44 Mo
 make modules : lance la compilation des modules (l’option doit avoir été activée).
 make isoimage : crée une image ISO pour CDROM bootable dans arch/<ARCH>/boot/image.iso
 make uImage : crée une image pour uBoot dans arch/<ARCH>/boot/uImage
(nécessite d’avoir le binaire d’uBoot mkimage dans le path ; ce binaire étant utilisé par le scriptscript/mkuboot.sh).
 Exemple de compilation d’un noyau pour l’architecture STM (coeur ST40) :
make –j5 -C=/tmp/linux_src/ ARCH=sh CROSS_COMPILE=sh4-linux-
make –j5 -C=/tmp/linux_src/ ARCH=sh CROSS_COMPILE=sh4-linux- uImage
 Installation (en tant que root !) :
 sudo make install : install le noyau
 sudo make modules_install : install les modules dynamiques dans /lib/`uname -r`/kernel/drivers/
 Bien évidemment, pour l’installation, il faut garder les paramètres d’architecture :
make ARCH=arm CROSS_COMPILE-arm-linux- install
 Pour spécifier un chemin d’installation des modules, il est possible de préciser un path:
make INSTALL_MOD_PATH=$ROOTFS_PATH/usr/lib modules_install
54
http://www.denx.de/wiki/DULG/LinuxConfiguration
http://pyfourmond.free.fr/Compilation-Noyau-Linux.htm#prerequis
FORMATION
LINUX
Optimisation de la phase de
compilation
 Adapter la configuration de votre noyau en ne choisissant que les modules nécessaires à votre
matériel. Cela peut diviser le temps de compilation par 30 et gagner des Mo.
 Compiler plusieurs fichiers en parallèle : make -j <nombre>
Lance plusieurs compilations en parallèle, autant que possible
 make -j 4
Plus rapide même sur les machines uniprocesseur ! Moins de temps perdu à lire ou écrire les
fichiers (les autres processus occupent le processeur)
 Pas utile de dépasser 4 (trop de changements de contexte)
 make -j <4*number_of_processors>
 make V=n : pour lancer la compilation en mode détaillée / Verbose (gcc, ld)
(n=0 : silencieux et n=1 : détaillé)
 make C=n : pour lancer la vérifications des dépendances des codes sources en C
(n=1 : vérification normale et n=2 : force la vérification)
 Surtout utile sur des machines ayant plusieurs processeurs ou plusieurs core interne au cpu.
55
FORMATION
LINUX
Fichiers résultants d’une compilation
 vmlinux
 Image brute du noyau Linux au format ELF, non compressée.
 Version utilisé entre autre pour le debug ou le profiling (Oprofile)
 Habituellement sur les Unix, le noyau s’appelle unix ; avec le développement de la mémoire virtuelle, le
préfix « vm » s’est imposé.
 Le nom vmlinux est la mutation de vmunix avec vmlinuz. Cependant, le « z » aurait pu sous-entendre qu’il
est compressé ce qui n’est justement pas le cas.
 Fichier de mapping des symboles System.map
 Listes des adresses des symboles des primitives inclues dans le noyau linux compilé
 arch/<arch>/boot/zImage
 Image du noyau compressée avec l’algorithme zlib.
 Depuis la version 2.6.30 les algorithmes de compression LZMA ou BZIP2 sont disponibles.
 arch/<arch>/boot/bzImage
 Image du noyau compressée aussi avec zlib. Généralement suffisamment petite pour tenir sur une
disquette ! Image par défaut sur i386
 arch/<arch>/boot/uImage
 Image du noyau pour le bootloader uBoot.
Si la compilation arrive au bout, les fichiers suivants sont générés :
56
FORMATION
LINUX
Le noyau linux : vmlinux
 La commande « file vmlinux » donne certaines informations sur le noyau linux :
vmlinux: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, not stripped
57
 La commande « objdump –dS vmlinux » donne aussi des détail intéressant :
vmlinux: file format elf32-i386
Disassembly of section .text.head:
c0100000 <_text>:
*/
.section .text.head,"ax",@progbits
ENTRY(startup_32)
/* test KEEP_SEGMENTS flag to see if the bootloader is asking us to not reload segments */
testb $(1<<6), BP_loadflags(%esi)
c0100000: f6 86 11 02 00 00 40 testb $0x40,0x211(%esi)
jnz 2f
c0100007: 75 14 jne c010001d <_text+0x1d>
 La commande « readelf -h vmlinux » est aussi instructive :
ELF Header: Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Intel 80386
Version: 0x111:31
Entry point address: 0x1000000
Start of program headers: 52 (bytes into file)
Start of section headers: 1299456 (bytes into file)
Flags: 0x0
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 3
Size of section headers: 40 (bytes)
Number of section headers: 20
Section header string table index: 17
FORMATION
LINUX
Le noyau linux : bzimage
58
ANATOMIE D’UNE IMAGE BZIMAGE
Le format bzImage a été crée pour répondre à l’accroissement de la taille du noyau linux au fil
des années. En effet, sur certain système l’espace de stockage peut être limité.
Le format bzImage contient la concaténation des objets : bootsect.o + setup.o + misc.o + piggy.o
piggy.o contient le fichier vmlinux gzippé dans la section data de son entête ELF.
FORMATION
LINUX
Le noyau linux : bzimage
 Il n’y a pas d’outils spécifique pour décompresser l’image bzImage, mais le script suivant
décompresse l’image et en extrait sa configuration :
59
#! /bin/bash -x
# extracts .config info from a [b]zImage file
# uses: binoffset (new), dd, zcat, strings, grep
# $arg1 is [b]zImage filename
HDR=`binoffset $1 0x1f 0x8b 0x08 0x0`
PID=$$
TMPFILE="$1.vmlin.$PID"
# dd if=$1 bs=1 skip=$HDR | zcat - | strings /dev/stdin 
# | grep "[A-Za-z_0-9]=[ynm]$" | sed "s/^/CONFIG_/" > $1.oldconfig.$PID
# exit
dd if=$1 bs=1 skip=$HDR | zcat - > $TMPFILE
strings $TMPFILE | grep "^[#[:blank:]]*CONFIG_[A-Za-z_0-9]*" > $1.oldconfig.$PID
wc $1.oldconfig.$PID
rm $TMPFILE
$ cd scripts/
$ gcc binoffset.c -o binoffset
$ export=`pwd`:$PATH
 Il faudra au préalable compiler l’utilitaire binoffset dont le source est dans le répertoire script/
 Quelques distribution comme RedHat fournissent une copie du noyau vmlinux
dans le répertoire : /usr/lib/debug/lib/modules/`uname -r`/vmlinux
FORMATION
LINUX
Le noyau linux : uImage (pour
uBoot)
60
 Commande pour générer une image uImage non-compressée :
mkimage -A arm -O linux -C none -T kernel -a 20008000 -e 20008000 -n linux-2.6 -d arch/arm/boot/Image uImage
 Commande pour générer une image uImage non-compressée :
mkimage -A arm -O linux -C none -T kernel -a 20008000 -e 20008000 -n linux-2.6 -d arch/arm/boot/zImage uImage
 Commandes de génération :
http://docs.blackfin.uclinux.org/doku.php?id=bootloaders:u-boot:uimage
http://docs.blackfin.uclinux.org/doku.php?id=bootloaders:u-boot:serial_port_loading_files
$ gzip -9 vmlinux $ mkimage 
-A blackfin -O linux -T kernel 
-C gzip 
-n 'My Linux Image' 
-a 0x1000 -e 0x1000 
-d vmlinux.gz vmImage
 Pour créer une image avec une image compressé avec gzip :
FORMATION
LINUX
Fichiers installés
 make install
/boot/vmlinuz-<version> Image du noyau
/boot/System.map-<version> Stocke les adresses des symboles (primitives systèmes) du noyau
/boot/initrd-<version>.img Initial RAM disk, contenant les modules nécessaires pour monter le
système de fichier root. make install lance mkinitrd si nécessaire.
/etc/grub.conf ou /etc/lilo.conf make install met à jour les fichiers de configuration de votre bootloader
pour supporter votre nouveau noyau ! Il relance /sbin/lilo si LILO est votre
bootloader.
 make modules_install
/lib/modules/<version>/ Modules noyau et autres fichiers
build/ Tout ce qui est nécessaire pour construire des modules pour ce noyau:
fichier .config (build/.config), informations sur les symboles des
modules(build/module.symVers), headers du noyau (build/include/)
kernel/ Fichiers modules .ko (Kernel Object), avec la même structure de
répertoires que dans les sources.
/lib/modules/<version>/ modules.alias
Aliases des modules pour insmod et modprobe. Exemple:
alias sound-service-?-0 snd_mixer_oss
modules.dep Dépendances des modules pour insmod et modprobe. Aussi utilisé pour ne
copier que les modules nécessaires dans un système de fichier minimal.
modules.symbols Dit à quel module appartient un symbole donné. 61
FORMATION
LINUX
Mapping des symboles
$ cat System.map
00100000 A phys_startup_32
bfffe400 A __kernel_vsyscall
bfffe410 A SYSENTER_RETURN
bfffe420 A __kernel_sigreturn
bfffe440 A __kernel_rt_sigreturn
c0100000 A _text
c0100000 T startup_32
c01000a4 T startup_32_smp
c0100124 t checkCPUtype
c01001a5 t is486
c01001ac t is386
c0100210 t L6
c0100212 t check_x87
c010023a t setup_idt
c0100257 t rp_sidt
(...)
62
 Le fichier System.map est généré à la fin d’un compilation noyau. Il donne l’adresse de chaque
symbole (primitive incluse dans le noyau) :
La connaissance de ce mapping est utile au debug ; cela pouvait servir pour un piratage de
primitive.
FORMATION
LINUX
DKMS : Dynamic Kernel Module Support
63
 Sous Linux, les pilotes (le logiciel qui permet au système d'exploitation de communiquer avec le matériel)
peuvent soit être directement inclus dans le noyau soit être disponibles sous la forme de modules à charger
dans le noyau. Un tel module est compilé pour un noyau particulier et ne peut être utilisé sur un autre.
 En ce qui concerne les pilotes libres, cela ne pose en général aucun problème car ils sont soit livrés avec
votre noyau, soit compilés en même temps que le noyau que vous compilez vous-même.
 Dans le cas de pilotes non libres (comme ceux de nVidia ou ATI) ou de pilotes distribués séparément et que
vous compilez à la main, le pilote doit être recompilé à chaque version de noyau, ce qui peut devenir
fastidieux.
 De plus, si vous souhaitez utiliser les pilotes distribués par votre distributeur Linux, vous devez attendre que
les pilotes soient recompilés pour le nouveau noyau, et ne pouvez espérer qu'ils fonctionnent avec un noyau
que vous auriez personnalisé.
 DKMS (Dynamic Kernel Module Support ou en français Gestion Dynamique des Modules Noyau) est un
système très simple conçu par Dell labs et permettant de compiler dynamiquement et facilement les modules
noyau pour tous les noyaux de votre système. Ce système est à la base conçu pour faciliter à Dell la
distribution de pilotes Linux et de correctifs.
 Cela évite à la fois aux éditeurs et aux utilisateurs de devoir passer par des mises à jour du noyau pour une
correction sur un pilote particulier et permet de distribuer un pilote supplémentaire sous la forme d'un seul
paquetage quel que soit le noyau de l'utilisateur.
FORMATION
LINUX
DKMS : Dynamic Kernel Module Support
64
 Workflow utilisé par DKMS :
Ajoute Génère
Installe
Désinstalle
installé
ajouté construit
Pas répertorié
 Le principe de DKMS est très simple. A condition que le module soit prévu pour être utilisé avec
DKMS (fourniture d'un dkms.conf), l'utilisation d'un nouveau module en passant par DKMS consiste à
exécuter les 3 étapes suivantes :
 Insertion dans l'arbre DKMS (action add)
 Compilation pour le noyau (action build)
 Installation avec les autres modules du noyau (action install)
 Ces étapes sont séparées et ne sont pas forcement toutes réalisées à la suite.
BUILT_MODULE_NAME=vboxdrv
DEST_MODULE_LOCATION=/kernel/misc
PACKAGE_NAME=vboxdrv
PACKAGE_VERSION=3.1.2
AUTOINSTALL=yes
POST_BUILD="do_Module.symvers vboxdrv save $dkms_tree/$module/$module_version/build/Module.symvers"
 Exemple de fichier dkms.conf utilisé dans le module vboxdrv du projet virtualBox de SUN :
FORMATION
LINUX
DKMS : Dynamic Kernel Module Support
65
Travail sans DKMS 
Travail avec DKMS 
Utilisation de DKMS
chez Mandriva :
FORMATION
LINUX
DKMS : Dynamic Kernel Module Support
66
http://linux.dell.com/dkms/permalink/
http://linux.dell.com/dkms/
http://linux.dell.com/dkms/manpage.html
http://www.linuxjournal.com/article.php?sid=6896
http://www.dell.com/downloads/global/power/1q04-ler.pdf
http://linux.dell.com/dkms/dkms-ols2004.pdf
http://wiki.mandriva.com/fr/DKMS
https://wiki.ubuntu.com/IntrepidIbex/TechnicalOverview
https://admin.fedoraproject.org/pkgdb/packages/name/dkms
http://wiki.centos.org/HowTos/BuildingKernelModules#head-d313bd351f90d4f25a2143b7bbcff73f927731f0
 Afin de bien séparer la gestion des différentes versions de module et de la version du noyau, le
fonctionnement de DKMS se base sur la présence de 3 arborescences :
 Les sources des modules, dans /usr/src
 L'arborescence des modules du noyau /lib/modules : DKMS y remplacera ou ajoutera les modules que
l'on va lui faire gérer
 L'arborescence de DKMS /var/lib/dkms, contenant :
• Les répertoires ou seront construits les modules
• Les modules originaux sauvegardés
• Les modules générés par DKMS
 Les chemins indiqués sont ceux par défaut et il est possible de les modifier dans /etc/dkms/framework.conf
mais nous supposerons dans le reste que les valeurs par défaut ont été conservées.
FORMATION
LINUX
DKMS : Dynamic Kernel Module Support
67
 Mise en oeuvre de DKMS va la commande du même nom :
La gestion des modules au sein du système DKMS se fait à l'aide de la commande dkms. Cette commande a une
syntaxe très simple : dkms <action> [options] Les actions et les options sont par contre plutôt nombreuses et
même si je vous les explique ci-dessous, seules les principales devraient être utiles à la majorité d'entre vous (à
savoir: add, build, install, remove en ce qui concerne les actions et -m, -v et --all en ce qui concerne les options).
Liste des options génériques :
 -m <module> : Le nom du module sur lequel effectuer l'action.
 -v <version du module> : La version du module sur laquelle effectuer l'action.
 -k <version du noyau> : La version du noyau sur laquelle effectuer l'action. Il est possible pour certaines
actions de spécifier plusieurs versions du noyau en utilisant plusieurs fois -k, si l'action spécifiée ne le
supporte pas une erreur sera émise.
 -a <architecture> : L'architecture pour laquelle effectuer l'action. Si cette option n'est pas précisée,
l'architecture choisie est celle indiquée par uname -m. Il est possible de répéter cette option afin d'indiquer
plusieurs architectures, mais dans ce cas il doit y avoir exactement autant de -k que de -a. Chaque noyau
sera associé à l'architecture de position identique. Par exemple si vous indiquez -k noyau1 -k noyau2 -a
i386 -k noyau3 -a i586 -a x86_64, DKMS comprendra que noyau1 est en i386, noyau2 est en i586 et
noyau3 est en x86_64.
 --all : Indique d'appliquer l'action pour toutes les versions de noyau et toutes les architectures pour
lesquelles le module a été compilé. Cela est particulièrement utile pour l'action remove.
 --rpm_safe_upgrade : Cette option est nécessaire pour les commandes DKMS appelées à l'intérieur d'un
RPM. Cela évite des problèmes lors de mise à jour d'un RPM à un autre contenant la même version du
module. Cela évite aussi les problèmes d'interblocage dus au système de verrous de rpm.
FORMATION
LINUX
DKMS : Dynamic Kernel Module Support
68
 add : ajoute à l'arbre des sources de DKMS une version d'un module (les options -m et -v sont donc
obligatoires, c'est le cas pour la majorité des commandes). Les sources du module doivent être
précédemment placées dans /usr/src/<module>-<version du module>/ et contenir un fichier dkms.conf. Si
le fichier dkms.conf ne se trouve pas dans /usr/src/<module>-<version du module>/, il faut ajouter l'option
-c pour indiquer son chemin.
Exemple :
$ dkms add -m exemple -v 0.9.0 -c /tmp/dkms.conf
Creating symlink /var/lib/dkms/exemple/0.9.0/source -> /usr/src/exemple-0.9.0
DKMS: add Completed.
 remove : supprime une version d'un module. Il faut en plus des options -m et -v, soit préciser
une version de noyau avec l'option -k, soit demander à supprimer le module de tout les noyaux
pour lesquelles cette version avait été compilée, avec l'option --all.
Si le module avait été installé, il est d'abord désinstallé (comme si on avait appelé l'action
uninstall) et d'éventuelles versions précédentes sont réinstallées. Après un remove, le module
n'est plus du tout connu de DKMS et il faut recommencer à l'étape add.
Exemple :
$ dkms remove -m exemple -v 0.9.0 –all
Deleting module version: 0.9.0
completely from the DKMS tree.
Done.
FORMATION
LINUX
DKMS : Dynamic Kernel Module Support
69
 build : compile une version d'un module pour le noyau indiqué avec l'option -k ou pour le noyau utilisé
actuellement si aucun n'est précisé. En cas d'erreurs lors de la compilation, il est utile de savoir que celle-
ci se déroule dans /var/lib/dkms/<module>/<version du module>/build/ et que tout ce qui est affiché
pendant la compilation est enregistré dans un fichier make.log dans ce même répertoire.
La commande build accepte quelques options facultatives :
 --config <fichier .config du noyau> : Cette option permet d'indiquer à la commande build ou trouver le
fichier .config si celui-ci n'est pas à l'emplacement standard de la distribution ou n'a pas le nom
habituel.
 --no-prepare-kernel : Cette option demande à DKMS de ne pas préparer les sources du noyau avant de
compiler un module pour lui. Il est recommandé de ne pas utiliser cette option si l'on souhaite que les
modules soient correctement construits.
 --no-clean-kernel : Cette option demande à DKMS de ne pas nettoyer les sources du noyau après avoir
compilé un module.
 --kernelsourcedir <chemin vers les sources du noyau> : Cette option permet d'indiquer l'emplacement des sources du
noyau lorsqu'elles ne se trouvent pas dans /lib/modules/<version du noyau>/build.
Exemple : $ dkms build -m slmodem -v 2.9.10 -k 2.6.12-12mdk-i686-up-4GB
Preparing kernel 2.6.12-12mdk-i686-up-4GB for module build:
(This is not compiling a kernel, only just preparing kernel symbols)
Storing current .config to be restored when complete
Running Generic preparation routine
make mrproper.........
using /boot/config-2.6.12-12mdk-i686-up-4GB
make oldconfig......
make prepare-all......
Building module:
cleaning build area....
make KERNELRELEASE=2.6.12-12mdk-i686-up-4GB KERNEL_DIR=/lib/modules/2.6.12-12mdk-i686-up-4GB/build drivers....
cleaning build area....
cleaning kernel tree (make mrproper)....
FORMATION
LINUX
DKMS : Dynamic Kernel Module Support
70
 install : installe une version d'un module dans l'arborescence du noyau indiqué (ou du noyau utilisé
actuellement si aucun n'est précisé par l'option -k). Cette version doit précédemment avoir été compilée
pour le noyau en question à l'aide de l'action build.
Lors de la première installation d'une version d'un module donné sur un noyau donné, DKMS cherche si
ce module existait déjà avec ce noyau et le sauvegarde pour pouvoir le réinstaller lorsque l'on demandera
à DKMS de désinstaller la nouvelle version. Pour information, la version originale est sauvée dans
/var/lib/dkms/<module>/original_module/<version du noyau>/<architecture>/
$ dkms install -m slmodem -v 2.9.10 -k 2.6.12-12mdk-i686-up-4GB
Running module version sanity check.
slamr.ko.gz:
- Original module
etc…
 uninstall : désinstalle une version d'un module pour une version du noyau (celle précisée par l'option -k
ou la version utilisée actuellement si aucune n'est précisée). Cette commande ne gère pas l'option --all
donc il vous faudra désinstaller pour chaque noyau séparément.
$ dkms uninstall -m slmodem -v 2.9.10 -k 2.6.12-12mdk-i686-up-4GB
Uninstall Beginning --------
Module: slmodem
Version: 2.9.10
Kernel: 2.6.12-12mdk-i686-up-4GB (i586)
etc…
FORMATION
LINUX
KSPLICE : mise à jour du noyau sans
reboot
71
http://www.ksplice.com/doc/ksplice.pdf
Diagramme de synthèse permettant le remplacement de code.
 Ksplice est une extension libre du noyau Linux
permettant à l'administrateur système d'appliquer
"à chaud" des patchs du noyau, sans redémarrage
du système. Ksplice fonctionne pour les
architectures x86 et x86-64 et est développé par
Ksplice, Inc sous GNU General Public License.
Détermination de la valeur du symbole à changer à chaud.
FORMATION
LINUX
KSPLICE : mise à jour du noyau sans
reboot
72
 Ksplice indique que
l'utilisation de son service
Uptrack «accélère
grandement les processus
de mises à jour et améliore
la sécurité du système»,
tout en sauvant du temps
en raison de l'absence
d'une interruption ce
service ou d'une baisse de
performance. Les
distributions Linux
exigent, rappelle Ksplice,
un redémarrage mensuel
dans le but de tirer profit
des importantes mises à
jour de sécurité du noyau.
FORMATION
LINUX
EXECUTION
 Etapes du démarrage d'un système GNU Linux
 Le bootloader
 L’initialisation de l’espace noyau
 Le ramfs Initrd
 L’initialisation de l’espace utilisateur
BUT : comprendre le démarrage d’un système basé sur Linux
FORMATION
LINUX
Démarrage d'un système GNU Linux
 Le démarrage d’un système Linux peut
être résumé à 3 étapes :
 Le Boot loader :
• Initialise le hardware
• Charge le noyau
• Transfère le contrôle au noyau
 L’initialisation du noyau :
• Initialisation et démarrage des
sous-systèmes du noyau
• Démarrage du multitâches
• Montage du système de fichier
racine
• Passe le contrôle au mode user
 L’initialisation en espace user :
• Démarrage des services et
applications
FORMATION
LINUX
75
Le Boot loader
 Quand le système démarre (boot ou reboot), le CPU invoque le vecteur de reset de façon à récupérer l'adresse d'un
programme localisé à exécuter ; pour un système traditionel, cet emplacement est localisé dans le B.I.O.S. de la carte
mère.
 Quand un device bootable est trouvé, la première étape consiste en un chargement du boot loader en RAM (MBR).
 Le boot loader doit être d'une taille inférieure ou égale à 512 octets (un seul secteur) et son rôle est de charger en
RAM puis d'exécuter la seconde étape (GRUB, LILO, …).
 Une fois que le boot loader a initialisé le hardware, il doit démarrer le noyau :
 Chargement du noyau (depuis une mémoire flash ou le réseau)
 Décompression du noyau
 Si un disque mémoire initial (initial ram disk = initrd) est requis, il est chargé en mémoire
 Initialisation d’une zone mémoire pour passage
de paramètres au noyau (avec éventuellement
l’adresse de l’image initrd)
 Appelle le point d’entrée du noyau
 Généralement le noyau pourra récupérer
l’espace mémoire du boot loader qui n’est
plus utilisé.
http://fr.wikipedia.org/wiki/Master_boot_record
 Backup du MBR :
dd if=/dev/hda of=boot.mbr bs=512
count=1
 Restauration du MBR :
dd if=boot.mbr of=/dev/hda bs=512
count=1
FORMATION
LINUX
Quelques chargeurs de démarrage
 LILO: LInux LOader. Chargeur de démarrage originel de Linux. Toujours utilisé !
http://freshmeat.net/projects/lilo/
Matériel supporté: x86
 GRUB: GRand Unified Bootloader de GNU. Plus puissant.
http://www.gnu.org/software/grub/
Matériel supporté: x86
 CoreBoot (Ex Linux Bios) : Remplaçant du BIOS, basé sur Linux.
http://www.coreboot.org/Matériel supporté: x86
 sh-boot: Chargeur de démarrage du projet LinuxSH.
http://cvs.sourceforge.net/viewcvs.py/linuxsh/sh-boot/
Matériel supporté: sh
 LAB: Linux As Bootloader, de Handhelds.org
Partie du noyau Linux de Handhelds.org
Voir http://handhelds.org/moin/moin.cgi/Linux26ToolsAndSources
Matériel supporté: arm (expérimental)
 U-Boot: Universal Bootloader. Le plus utilisé sur arm.
http://u-boot.sourceforge.net/
Matériel supporté: arm, ppc, mips, x86
 RedBoot: Chargeur de démarrage basé sur eCos de Red-Hat.
http://sources.redhat.com/redboot/
Matériel supporté: x86, arm, ppc, mips, sh, m68k...
 Loadlin : le chargeur de linux (LOADLIN = LOAD LINux)
ftp://ftp.sunet.se/pub/Linux/distributions/slackware/slackware-current/kernels/loadlin16c.zip
http://en.wikipedia.org/wiki/Loadlin
 Syslinux, chargeur utilé pour les clef usb et les liveCD
http://www.kernel.org/pub/linux/utils/boot/syslinux/
 ISOLINUX : un chargeur pour les cdrom ISO 9660
http://syslinux.zytor.com/iso.php
 QI : bootloader minimal utilisé sous OpenMoko pour le portage de Google Android
http://gitorious.net/+0xlab/0xlab-bootloader/qi-bootloader
76
FORMATION
LINUX
77
Initialisation du noyau
 Le démarrage du noyau se fait en plusieurs phases :
 Initialisation du hardware (CPU, MMU, caches, stack, etc.)
 Analyse des paramètres passés par le boot loader
 Si un initrd est utilisé, il est monté comme système de fichiers racine en ramfs. Une fois cette
seconde étape de lancée, charge le noyau linux en mémoire vive puis invoque ce dernier. Par le
suite il y a commutation entre le rootfs temporaire et celui qui sera utilisé par la suite
(réellement).
 Autres initialisations :(mémoire virtuelle, interruptions, timers, etc.
• Calibration du bogomips
• Détection du nouveau matériel
 Initialisation des drivers :
 Interrogation du bus PCI
 Interrogation des slot IDE
 Interrogation de la chaine USB
 Exécute /linuxrc si présent dans l’initrd
 Montage du système de fichiers "maitre" (disque, flash, NFS, etc.), éventuellement en place du
système initrd
 Exécute en espace user la première application de l’espace utilisateur init ou tout autre process
spécifié par le paramètre init. Sous la distribution Ubuntu, /sbin/init est remplacé par upstart :
http://upstart.ubuntu.com/
FORMATION
LINUX
Ligne de commande du noyau
Exemple (utilisé pour le PDA HP iPAQ h2200) :
root=/dev/ram0 rw init=/linuxrc  console=ttyS0,115200n8 console=tty0  ramdisk_size=8192
cachepolicy=writethrough 
ro root=/dev/mapper/vg_workstation-lv_root rhgb quiet SYSFONT=latarcyrheb-sun16 LANG=fr_FR.UTF-8 KEYTABLE=fr
78
 Des centaines de paramètres sont décrit dans Documentation/kernel-parameters.txt
Le positionnement de init=/bin/bash et avec un accès en lecture et écriture (rw) permet d’obtenir un accès
root sur une machine ; cela montre l’importance de la sécurisation d’un bootloader.
 Comme la plupart des programmes C, le noyau Linux accepte des arguments en
ligne de commande.
 La ligne de commande est une chaine de 255 caractères terminé par NULL (/0)
 Utile pour configurer le noyau au démarrage, sans avoir à le recompiler. Cette
technique est particulièrement utilisé pour initialiser le noyau linux au chargement
par le bootloader.
 Une fois lancé les paramètres du noyau sont accessible par la commande : cat
/proc/cmdline
 Les paramètres sont soit pour la partie core du noyau ou pour certain modules
compilés en statiques. Les modules dynamiques ont eux aussi leur paramètres.
 Exemples :
Vous pouvez avoir l'ensemble des options pour le noyau linux sur les pages suivantes :
noyau 2.4 : http://lxr.linux.no/source/Documentation/kernel-parameters.txt?v=2.4.26
noyau 2.6 : http://lxr.linux.no/source/Documentation/kernel-parameters.txt?v=2.6.8.1
FORMATION
LINUX
Ligne de commande du noyau
79
 Des centaines de paramètres sont décrit dans Documentation/kernel-parameters.txt
Le positionnement de init=/bin/bash et avec un accès en lecture et écriture (rw) permet d’obtenir un accès
root sur une machine ; cela montre l’importance de la sécurisation d’un bootloader.
 Paramètres les plus utilisés :
console Console pour les messages de démarrage
init Script à exécuter à la fin de l'initialisation du noyau. Par défaut: /sbin/init
mem Permet d'indiquer la valeur de mémoire vive présente sur la machine pour le cas ou l'auto-
detection échouerait. On peut utiliser des lettres pour cette taille. Par exemple 512M
désignera 512 Méga-octets de mémoire.
ro / rw Monte le file système root en lecture seule ou bien en lecture/écriture
root Permet d'identifier le système de fichier racine
vga Sert à changer la résolution d'écran utilisée pendant le démarrage. Utile si celle par défaut
n'est pas reconnue par la carte graphique.
debug Active ou non le mode debug
selinux Active ou non Security Enhanced Linux (SELINUX)
ether Définit la carte nic Ethernet (irq,iobase, ,name). Exemple: ether=0,0,eth0
Pour information, si irq=0 et iobase=0 c’est que la détection automatique doit être activé.
nousb Désactive la détection des périphériques USB.
FORMATION
LINUX
Démarrage d'un système GNU Linux
80
 L’initialisation même du noyau comporte elle-même 4 étapes :
 Chargement de l’image du noyau
 Initialisation de la partie en assembleur :
• boot/head.S : initialise les registres, configure la pile noyau, appel de setup_idt() pour remplir
l’IDT de gestionnaire d’IRG nuls, appel setup_gdt() pour remplir la GDT, mise en place de la
pagination, appel de la fonction start_kernel(). Elle s’appelait main() initialement. Cette fonction
est une boucle infinie.
 Initialisation de la partie en langage C (init/main.c).
 Exécution du processus Init
FORMATION
LINUX
Démarrage d'un système GNU Linux
81
Boot d’un noyau Linux bzImage et sa phase de décompression.
http://www.ibiblio.org/oswg/oswg-nightly/oswg/en_US.ISO_8859-1/articles/alessandro-rubini/boot/boot/zimage.html
FORMATION
LINUX
Initrd (initial RAM Disk)
Initrd = Initial RAM disk
 Disque mémoire minimaliste temporaire utilisé au démarrage. Il est chargé en RAM.
 Utilisé traditionnellement pour minimiser le nombres de pilotes de périphériques compilés dans le noyau.
Exemple: le module ext3 qui permet de monter le système de fichier racine final.
 Utile aussi pour lancer des scripts d'initialisation complexes
 Utile pour charger des modules propriétaires (qui ne peuvent être liés statiquement au noyau)
 Pendant la phase d'installation (make install), il y a la création d’une image initrd (init RAM disk) :
mkinitrd -o /boot/initrd.img-2.6.32.4 /lib/modules/2.6.32.4.
 Pour plus d'information : il suffit de lire Documentation/initrd.txt dans les sources du noyau. Elle couvre
aussi le changement de système de fichier racine («pivot_root»).
Exemple de création d'une image initrd :
mkdir /mnt/initrd
dd if=/dev/zero of=initrd.img bs=1k count=2048
mkfs.ext2 -F initrd.img
mount -o loop initrd.img /mnt/initrd
( Peut être rempli avec: busybox, les modules, le script linuxrc )
umount /mnt/initrd
gzip --best -c initrd.img > initrd
 http://www.ibm.com/developerworks/linux/library/l-initrd.html 82
FORMATION
LINUX
83
Initialisation de l’espace utilisateur
 Le processus /sbin/init est exécuté en espace user par le noyau. Il peut être surchargé par le paramètre init.
 Le processus init est spécial :
 Il ne peut jamais être terminé
 Il adopte les processus orphelins (processus fils dont le parent est terminé en premier)
 Le noyau informe le processus init de certains événements comme Ctrl-Alt-Del
 Le processus init a pour tache de lancer les autres services et applications du système
 Généralement, ces actions sont spécifiées dans /etc/inittab
 La valeur de initdefault détermine le numéro d’init (runlevel)
 Cela déclenche le démarrage des scripts /etc/rc*.d/ associés à la séquence d’init (deamon). Les
répertoires /etc/rc*.d ne contiennent pas les scripts de démarrage réels, mais plutôt des liens
symboliques vers des scripts situés dans le répertoire /etc/init.d. Ceci permet d’éviter une
redondance inutile. La manière dont sont nommés les liens symboliques déterminera l’ordre dans
lequel les services seront démarrés : simple, ingénieux et pratique. Les liens symboliques à démarrer
commencent par la lettre ‘S’ (Start) et ceux à arrèter par la lettre ‘K’ (Kill). S’en suit un chiffre qui
agence l’ordre de lancement (init order). Enfin vient le nom du daemon.
 En embarqué, le script exécuté au démarrage est /etc/init.d/rcS. Il lance tout d’abord les scripts du répertoire
/etc/rcS.d/, qui ne s’exécutent qu’une fois, au démarrage de la machine.
$ ps axfl
UID PID PPID STAT TTY TIME COMMAND
0 1 0 S ? 0:03 init
La commande pstree permet de confirmer le lien de parenté des processus avec init.
La commande « who -r » permet de consulter le run level actuel.
0 : Arrêt
1 : Mode mono-utilisateur (Single) ou maintenance
2 à 5 : dépend du système d'exploitation
6 : Redémarrage
FORMATION
LINUX
ARCHITECTURE DU NOYAU
 Arborescence des sources
 Différences vues du noyau
 Rôle du noyau
 Découpage du noyau
 Descriptions des différents composants :
 Virtual File System (VFS)
 Process Management (PM)
 Memory Management (MM)
 Gestion des entrées/sorties (I/O)
 Network Stack (NS)
 System Call Interface (SCI)
BUT : comprendre l’architecture du noyau GNU Linux
FORMATION
LINUX
Arborescence des sources du noyau
 Détail des répertoires :
 arch/ Code dépendant de l'architecture
 COPYING Conditions de copie de Linux (GNU GPL
 CREDITS Contributeurs principaux de Linux
 crypto/ Bibliothèques de cryptographie
 Documentation/ Documentation du noyau.
 drivers/ Pilotes de périphériques (drivers/usb/, etc…)
 fs/ Systèmes de fichier (fs/ext3/, etc.)
 include/ Entêtes du noyau
 include/asm-<arch> Entêtes dépendant de l'architecture
 include/linux Entêtes du coeur du noyau Linux
 init/ Initialisation de Linux (contient main.c)
 ipc/ Code utilisé pour la communication entre processus
85
FORMATION
LINUX
Arborescence des sources du
noyau
kernel/ Coeur du noyau Linux
lib/ Bibliothèques diverses (zlib, crc32...)
MAINTAINERS Responsables de parties du noyau.
Makefile Makefile principal (définit arch et version)
mm/ Code de la gestion mémoire
net/ Support réseau (pas les pilotes)
README Introduction et instructions de compilation
REPORTING-BUGS Instructions pour le rapport de bogues
scripts/ Scripts utilisés en interne ou en externe
security/ Implémentations du modèle de sécurité (selinux...)
sound/ Support du son et pilotes
usr/ Utilitaires: gen_init_cpio et initramfs_data.S
86
FORMATION
LINUX
Répartition du code dans l’arborescence du noyau 
87
Répartition du code du noyau
Obtenu par la commande : du -s --apparent-size
Version 1.2 : 50% de code en langage C et 50% de code en langage assembleur
Version 2.0 : 95% de code en langage C et 5% de code en langage assembleur
FORMATION
LINUX
 Linux possède plusieurs
hypergraphes tel que celui-ci ou
bien celui représentant les
dépendances des paquets quant à
l'établissement d'une distribution
conforme LSB (même basique).
 Vue de l'hypergraphe formé par l'arborescence des sources du noyau 2.4.9 
Note : ce schéma n'est pas très lisible mais montre
cependant la représentation en oignon
(concentrique) du noyau GNU Linux 
88
Vue hypergraphe du noyau
FORMATION
LINUX
Vue simplifiée d'un diagramme matriciel du noyau GNU Linux 
89
Vue simplifiée du noyau
FORMATION
LINUX
Vue modulaire du noyau GNU Linux 
90
Vue modulaire du noyau
FORMATION
LINUX
Rôle du noyau GNU Linux
 GNU (GNU is Not Unix) Linux est le coeur du
système. Il fournit une API basse dépendant
de l’architecture au hardware et une API haute
(SCI) destiné au monde utilisateur.
 Il gère aussi l'ordonnacement des tâches
rendant ce dernier :
• multi-tâches ;
• préemptif (davantage en 2.6 qu'en 2.4) ;
• multi-utilisateurs
 Cependant il n'est pas nativement temps réel.
Pour ce faire il faut rajouter un microkernel
temps réel tel que RTAI, RTLINUX ou
XENOMAI.
 En d'autre terme le noyau manage les tâches
tant en espace noyau qu'en espace utilisateur.
 Vue de l'espace user, le noyau peut être
contacté via un ensemble d'appels systèmes
référencés dans la librairie C (glibc).
91
FORMATION
LINUX
Mode utilisateur et mode
noyau
 Utilisation de la protection matérielle du microprocesseur
 Différence entre les deux mondes :
 Espace noyau : où tout est permi même le pire
• Espace prévilégie
• Accès à toutes les ressources
• Utilisé par les entrées et sorties
• Espace utilisateur : accès plus restreint
• Espace non-privilégié
• Accès restreint aux ressources
• Pas d’accès aux entrées et sorties
 Tout processus au cours de son exécution passe d’un espace à l’autre. La transition se
faisant via :
 la SCI qui est la frontière entre les deux mondes (c’est l’API publique normalisé par la norme
POSIX offerte par le noyau au monde user).
 les interruptions issue de timers, entrées et sorties, etc …
 Les exceptions issue du processeur (accès illégal à la mémoire, instruction illégale, etc … )
 Attention : tout changement de contexte est couteux en temps d’exécution.
92
FORMATION
LINUX
Linux et le temps réel
http://uuu.enseirb.fr/~kadionik/embedded/linux_realtime/linux_realtime9.html
http://en.wikipedia.org/wiki/RTLinux
http://en.wikipedia.org/wiki/RTAI
http://en.wikipedia.org/wiki/Wind_River_Systems
http://fr.wikipedia.org/wiki/Xenomai
http://www.xenomai.org/index.php/Main_Page
http://fr.wikipedia.org/wiki/Xenomai
 Le noyau Linux n'étant pas temps
réel en natif il est Cependant
possible de le Compléter d'un micro-
kernel Temps réel où linux est
exécuté Comme sous UML, c'est-à-
dire sous la forme d'un process 
 Le noyau 2.6 n’est préemtable que
dans certaines conditions, il existe
un patch RT-Prempt pour rendre le
noyau préemptable :
http://rt.wiki.kernel.org
93
FORMATION
LINUX
Découpage du noyau Linux
 Le noyau GNU Linux a hérité de
l'architecture des UNIX propriétaires.
 Il est souvent comparé à un oignon tant il
est organisé en couches successives, en
partant du matériel, au drivers jusqu'à
l'espace utilisateur qui est sa frontière 
Espace utilisateur
Matériel
94
FORMATION
LINUX
VFS - Virtual File System
95
FORMATION
LINUX
VFS : Virtual File System
 Linux n'étant pas monolithique c'est-à-
dire qu'il est constitué d'un ensemble de
parties comme la pile réseau, la gestion
de la mémoire, etc…
 VFS est la couche d'abstraction de haut
niveau intra-kernel regroupant un
ensemble de primitives génériques
comme open, close, read, write (au nom
près).
 S'il s'agit d'écrire un fichier (une fifo ou
autre) sur un disque, hé bien
l'implémentation dans le kernel sera la
même qu'il s'agisse d'un disque avec un
système de fichier cramfs, jffs2 ou 3,
ext2 ou 3, reizerfs, etc… VFS est la
couche virtuelle qui permet de niveler
les appels d'un point de vue noyau ou
drivers en se souciant pas du système de
fichiers réellement utilisé. VFS est donc
une sorte de dispatcher de haut niveau
vers les module spécifique à chaque
système de fichiers.
96
FORMATION
LINUX
VFS : Virtual File System
97
Autres représentations de l’interface VFS :
FORMATION
LINUX
Opérations sur les fichiers
La primitive register_chrdev(), permet de déclarer des
«file_operations» (appellées fops).
Voici ses principales opérations :
 loff_t (*llseek) (struct file *, loff_t, int);
 ssize_t (*read) (struct file *, char *, size_t, loff_t *);
 ssize_t (*write) (struct file *, const char *, size_t, loff_t *);
 int (*open) (struct inode *, struct file *);
 int (*release) (struct inode *, struct file *);
 http://www.ibm.com/developerworks/linux/library/l-linux-filesystem/
98
FORMATION
LINUX
Opérations sur les fichiers
 int (*ioctl) (struct inode *, struct file *,
unsigned int, unsigned long);
Utilisée pour envoyer au périphérique des
commandes spécifiques, qui ne sont ni des
lectures, ni des écritures (ex: formater un
disque, changer une configuration).
 int (*mmap) (struct file *, struct
vm_area_struct);
Demande que la mémoire du périphérique soit
mappée dans l'espace d'adressage du
processus utilisateur
 struct module *owner;
Utilisée par le noyau pour garder une trace de
qui utilise cette structure et compter le nombre
d'utilisateurs du module.
LFH :
http://www.tldp.org/LDP/Linux-Filesystem-Hierarchy/Linux-Filesystem-Hierarc
99
FORMATION
LINUX
La structure « file »
 Au niveau kernel, VFS fournit la méthode open() pour ouvrir un fichier et
retourner un pointeur sur la structure représentant le fichier ouvert.
 Les pointeurs vers cette structure sont les "fips".
 mode_t f_mode;
Mode d'ouverture du fichier (FMODE_READ, FMODE_WRITE)
 loff_t f_pos;
Position dans le fichier ouvert.
 struct file_operations *f_op;
Peuvent être changées à la volée.
 struct dentry *f_dentry
Utilisé pour accéder à l'inode: filp->f_dentry->d_inode.
100
FORMATION
LINUX
Table des systèmes de fichiers
courants
101
Systèmes de fichiers courants
FORMATION
LINUX
Fuse : un système de fichier en espace user
 Pas mal de qualités :
 API simple via la librairie dynamique libfuse
 Implémentation d'un système de fichiers en espace user (pas de développement noyau)
 Utilisation ne nécessitant pas de patcher le noyau
 Implémentation sécurisée
 Transfert entre l'espace noyau et l'espace utilisateur optimisé
 Ne nécessite pas des droit root
 Fonctionne sous GNU Linux 2.4 et 2.6
 A prouvé sa stabilité
http://fuse.sourceforge.net/
http://fuse.sourceforge.net/wiki/index.php/FileSystems
102
FORMATION
LINUX
PM (Process Management)
103
FORMATION
LINUX
PM : Process
Management
Diagramme états
transition des
processus géré par
l'ordonnanceur du
noyau GNU Linux

104
TACHE
ZOMBIE
(La tâche
est
terminée)
Tâche
existante qui
en crée une
nouvelle.
TACHE
INTERRUPTIBLE
ou
TACHE
UNINTERRUPTIBLE
(attente)
TASK
COURANTE
(en cours)
TASK
RUNNING
(prête mais
pas courante)
Tâche
crée
Tâche se
termine
via un
do_exit()
Tache préempeptée
par une tâche de priorité
supérieure
La tâche
dort dans
une liste
d’attente
d’un
évènement
spécifique
Le scheduler sélectionne la tâche
pour être active :
schedule() appel context_switch()
Un événement déclenche
le réveil d’une tâche et la
Place dans la queue des
tâche à exécuter
FORMATION
LINUX
L’ordonnanceur ou scheduler
105
 Dans les systèmes d'exploitation, l’ordonnanceur désigne le composant du noyau du système
d'exploitation qui choisit les processus qui vont être exécutés par les processeurs d'un ordinateur. En
anglais, l'ordonnanceur est appelé scheduler.
 Un processus peut avoir besoin de la ressource processeur pour, par exemple, effectuer des calculs,
déclencher une interruption, etc. La plupart des composants matériel, et en particulier le processeur d'un
ordinateur, n'est pas capable d'effectuer plusieurs traitements simultanément. Pour la très grande majorité
des ordinateurs, avoir un seul processeur implique de ne pouvoir effectuer qu'un traitement à la fois.
 A un instant donné, il est possible qu'il y ait plus de processus à exécuter qu'il n'y a de processeurs. Il est
courant que de nombreux programmes soient exécutés en parallèle sur une machine mono processeur.
 Un des rôles du système d'exploitation, et plus précisément de l'ordonnanceur du noyau, est de
permettre à tous ces processus de s'exécuter et d'utiliser le processeur de manière optimale du point de vue
de l'utilisateur. Pour arriver à donner l'illusion que plusieurs tâches sont traitées simultanément,
l'ordonnanceur du noyau du système s'appuie sur les notions de commutation de contexte et
d'ordonnancement.
 Pour effectuer ces tâches, l'ordonnanceur procède de la manière suivante : à intervalles réguliers, le
système appelle une procédure d'ordonnancement qui élit le processus à exécuter. Si le nouveau processus
est différent de l'ancien alors survient un changement de contexte, opération qui consiste à sauvegarder le
contexte d'exécution de l'ancienne tâche, comme par exemple, les registres du processeur. Cette structure
de données est généralement appelée PCB. Le système d'exploitation restaure le PCB de la nouvelle tâche.
FORMATION
LINUX
L’ordonnanceur ou scheduler
106
 Multi-tâche préemptif
 Le noyau lui même est préemptif (à partir du 2.6) : possibilité de prendre la main dans un driver.
 Politique Unix de partage du temps machine entre processus (time slicing)
 API POSIX.1b pour le temps réel : priorité FIFO (de 0 à 99)
 Linux n'est pas pour autant un noyau temps réel (comprendre ici, qu’il n’y a aucune garantie de
terminer une tâche dans un temps déterminée) :
 temps d'exécution non prédictif (le noyau est prioritaire face au processus du monde utilisateur)
 système non déterministe.
 Gestion des priorités (41 niveaux standards + 99 niveaux temps réel).
FORMATION
LINUX
L’ordonnanceur ou scheduler
107
 Types d'algorithmes :
Du choix de l'algorithme d'ordonnancement dépend le comportement du système. Il existe deux grandes
classes d'ordonnancement.
 L'ordonnancement en temps partagé :
Il est présent sur la plupart des ordinateurs « classiques ». Par exemple l'ordonnancement « decay » ; qui est
celui par défaut sous Unix. Il consiste en un système de priorités adaptatives, par exemple il privilégie les
tâches interactives pour que leur temps de réponse soit bon. Une sous-classe de l'ordonnancement en temps
partagé sont les ordonnanceurs dits « proportional share », eux sont plus destinés aux stations de calcul et
permettent une gestion rigoureuse des ressources. On peut citer notamment « lottery » et « stride ».
 Algorithmes d'ordonnancement :
 Round-robin : garantie d’un temps minimum pour l’exécution d’une tâche
 Rate-monotonic scheduling (RMS)
 Earliest deadline first scheduling (EDF)
 FIFO
 Shortest job first (SJF, ou SJN -Shortest Job Next-)
 Completely Fair Scheduler (CFS) http://kerneltrap.org/node/8059
http://people.redhat.com/mingo/cfs-scheduler/
http://www.ibm.com/developerworks/linux/library/l-cfs/
http://en.wikipedia.org/wiki/Completely_Fair_Scheduler
http://en.wikipedia.org/wiki/O%281%29_scheduler
http://www.ibm.com/developerworks/linux/library/l-scheduler
/
http://www.informit.com/articles/article.aspx?p=101760&seq
Num=2
FORMATION
LINUX
Le scheduler CFS - O(1) (depuis 2.6.23)
 Le Completely Fair Scheduler (ordonnanceur complètement équitable en anglais), ou CFS est un
ordonnanceur de tâches pour le noyau linux, qui a fait son apparition avec la version 2.6.23 sortie le
9 octobre 2007, remplaçant ainsi le précédent ordonnanceur qui était apparu dans le noyau 2.5.2-pre10 en
janvier 2002. Il gère l'allocation de ressource processeur pour l'exécution des processus, en maximisant
l'utilisation globale du CPU tout en optimisant l'interactivité. Il a été écrit par Ingo Molnár.
 Contrairement au précédent ordonnanceur utilisé par le noyau linux, CFS n'est pas basé sur des files de
processus, mais utilise un arbre rouge-noir implémentant une chronologie des futures exécutions des tâches.
En effet, l'arbre trie les processus selon une valeur représentative du manque de ces processus en temps
d'allocation du processeur, par rapport au temps qu'aurait alloué un processeur dit multitâche idéal, sur
lequel tous les processus s'exécuterait en même temps et à la même vitesse. Ainsi, à chaque intervention de
l'ordonnanceur, il "suffit" à ce dernier de choisir le processus le plus en manque de temps d'exécution pour
tendre au mieux vers le comportement du processeur multitâche idéal. De plus, l'ordonnanceur utilise une
granularité temporelle à la nanoseconde, rendant redondante la notion de tranches de temps, les unités
atomiques utilisées pour le partage du CPU entre processus. Cette connaissance précise signifie également
qu'aucune heuristique (basée sur des statistiques, donc pouvant commettre des erreurs) n'est requise pour
déterminer l'interactivité d'un processus.
 Plusieurs avancées sont apportées par le nouveau noyau 2.6.25. L'ordonnanceur CFS a été rendu plus
agressif dans le déplacement des processus entre les coeurs de calcul. Maintenant, dans le cas d'une
compétition entre des tâches temps réel pour accaparer un seul coeur, le noyau migrera plus efficacement
certaines tâches vers les autres processeurs afin d'éviter les temps d'attente. D'autre part le verrou global du
noyau (big kernel lock) est maintenant préemptible par défaut et l'option permettant de ne pas le rendre
préemptible va sans doute disparaître. Les timers à haute résolution peuvent maintenant être utilisés pour
calculer les priorités entre les processus ce qui rend l'ordonnanceur plus précis lors de ses allocations de
temps. On peut également noter que la fonction d'ordonnancement de groupe, introduite dans le noyau
précédent, gagne des fonctions de support du temps réel.
108
FORMATION
LINUX
Etat d'attente
 L'endormissement est nécessaire lorsqu'un
processus utilisateur attend des données
qui ne sont pas encore prêtes. Il est alors
placé dans une queue/file d'attente.
 Déclarer la queue :
DECLARE_WAIT_QUEUE_HEAD
(module_queue);
Plusieurs moyens d'endormir un processus :
 sleep_on()
Ne peut pas être interrompu !
 interruptible_sleep_on()
Peut être interrompu par un signal
 sleep_on_timeout()
interruptible_sleep_on_timeout()
Similaire à ci-dessus, mais avec un délai
d'expiration.
 wait_event()
wait_event_interruptible()
Dort jusqu'à ce qu'une condition
soit vérifiée.
Utilisez seulement les commandes interruptibles, les autres
sont rarement nécessaires.
109
FORMATION
LINUX
Se réveiller
 Souvent un processus se retrouve à attendre un évènement dans le noyau (exemple: arrivée données)
 Plutôt que de faire du polling, le processus se met dans une file d'attente et relâche le CPU
 Lorsque l'évènement intervient, le gestionnaire d'interruptions (ou le bottom-half) réveille le ou les
processus de la file correspondante.
 Les routines de manipulation des files d'attente sont les suivantes:
 wait_event{_interruptible}{timeout}() :
• endort le processus courant, de façon interruptible ou pas et avec ou sans délais
d'expiration, et le place dans une file d'attente jusqu’à ce qu’une condition soit satisfaite.
 wake_up{_interruptible}{_nr,_all}() :
• réveille un processus (ou x, ou tous) endormi d'une file d'attente et les rend éligibles, c’est
à dire ordonnançable.
Interruptible : permet de terminer un processus par un signal.
 wake_up(&queue);
Réveille tous les processus attendant dans la queue donnée
 wake_up_interruptible(&queue);
Réveille seulement les processus interruptibles (peut être rveillé par un signal).
 wake_up_sync(&queue);
Ne réordonnance pas lorsque vous savez qu'un autre processus est sur le point de s'endormir, car dans
ce cas un réordonnancement va de toute façon se produire.
110
FORMATION
LINUX
Se réveiller
 La version 'interruptible' teste si un signal a été envoyé au processus et renvoie un code d'erreur dans
ce cas (ERESTARTSYS), qui doit être propagé en tant que retour de l'appel système.
 Initialisation d'une file d'attente (type wait_queue_head_t) :
 en statique: DECLARE_WAIT_QUEUE_HEAD(name)
 au runtime: init_waitqueue_head()
 Exemple :
111
static DECLARE_WAIT_QUEUE_HEAD(ma_file);
int fonction_lecture (void *adresse)
{ ...
ret = wait_event_interruptible(&ma_file, readb() != 0);
if (ret < 0)
return ret;
... }
void mon_handler(int irq, void *priv, struct pt_regs *regs)
{ ...
wake_up_interruptible(& ma_file);
...}
FORMATION
LINUX
Se réveiller
 Prototypes (<linux/wait.h>) :
 DECLARE_WAIT_QUEUE_HEAD(name);
 void init_waitqueue_head(wait_queue_head_t *wq);
 Prototypes (<linux/sched.h>, <linux/wait.h>):
 void wait_event(wait_queue_head_t *wq, condition);
 int wait_event_interruptible (wait_queue_head_t *wq, condition);
 int wait_event_interruptible_timeout(wait_queue_head_t *wq, condition, long timeout);
 void wake_up{_interruptible}(wait_queue_head_t *wq);
 void wake_up{_interruptible}_nr(wait_queue_head_t *wq, int nr);
 void wake_up_all()
112
FORMATION
LINUX
MM (Memory Management)
113
FORMATION
LINUX
Organisation de la mémoire
0 GB
1 GB
Mémoire virtuelle Mémoire physique
 Il est possible d'étendre l'utilisation de la mémoire au dela des 4 Go
Via l'utilisation de la mémoire haute (ZONE_HIGHMEM).
ZONE_NORMAL :
KERNEL
PHYSICAL
SPACE
KERNEL
VIRTUAL
SPACE
USER
VIRTUAL
SPACE
0 GB
3 GB
4 GB
http://www.informit.com/content/images/0131453483/downloads/gorman_book.pdf
114
FORMATION
LINUX
Espace d’adressage
115
 Espace d'adressage noyau :
 virtuel (pas physique) : adresse logique de 0x0000 à la fin de la ram
 vision linéaire de la RAM (pas de segmentation)
 pas de protection lors d'accès illégaux
 taille maximum en fonction de la mémoire physique
 Espace d'adressage utilisateur:
 Virtuel : de 0x00 jusqu’à la taille max de la machine
 privé pour chaque processus
 taille maximum en fonction de l'architecture (gestion du swap)
FORMATION
LINUX
Caractéristiques par architecture
116
ARCHITECTURE PAGE_SHIFT PAGE_SIZE en Ko
alpha 13 8
arm 12, 14, 15 4, 16, 32
cris 13 8
h8300 12 4
i386 12 4
ia64 12, 13, 14, 16 4, 8, 16, 64
m32r 12 4
m68k 12, 13 4, 8
m68knommu 12 4
mips 12 4
mips64 12 4
parisc 12 4
ppc 12 4
ppc64 12 4
x390 12 4
sh 12 4
sparc 12, 13 4, 8
sparc64 13 8
v850 12 4
X86_64 12 4
FORMATION
LINUX
kmalloc et kfree
 Allocateurs basiques, équivalents noyau des
malloc et free de la glibc. kmalloc()/kfree():
alloue / désalloue un bloc de mémoire réelle
contiguë dans le noyau (GFP_KERNEL = peut
dormir car le noyau est préempté en attendant
d’avoir un bloc de disponible, GFP_ATOMIC =
atomique, si pas de bloc disponible renvoie
NULL) :
 static inline void *kmalloc(size_t size, int flags);
size: quantité d'octets à allouer
flags: priorité
 void kfree (const void *objp);
Exemple:
data = kmalloc(sizeof(*data), GFP_KERNEL);
117
Conversions d'adressage successif.
 Adressage logique : utilisé par les instructions du microprocesseur.
 Adressage linéaire : entier non-signé de 32 bits (jusqu'à 4 294 967 296 cellules de mémoire).
 Adressage : utiliser pour adresser physiquement la mémoire vive via le bus hardware.
FORMATION
LINUX
Propriétés de kmalloc
 Rapide (à moins qu'il ne soit bloqué
en attente de pages).
 N'initialise pas la zone allouée.
 La zone allouée est contiguë en
RAM physique.
 Allocation par taille de 2n
-k (k:
quelques octets de gestion)
Ne demandez pas 1024 quand vous
avez besoin de 1000 ! Vous
recevriez 2048 !
118
FORMATION
LINUX
Options pour kmalloc
 GFP_KERNEL
Allocation mémoire standard du noyau. Peut
être bloquante. Bien pour la plupart des cas.
 GFP_ATOMIC
Allocation de RAM depuis les gestionnaires
d'interruption ou le code non liés aux
processus utilisateurs. Jamais bloquante.
 GFP_USER
Alloue de la mémoire pour les processus
utilisateur. Peut être bloquante. Priorité la plus
basse.
 GFP_NOIO
Peut être bloquante, mais aucune action sur
les E/S ne sera exécutée.
 GFP_NOFS
Peut être bloquante, mais aucune opération
sur les systèmes de fichier ne sera lancée.
 GFS_HIGHUSER
Allocation de pages en mémoire haute en
espace utilisateur. Peut être bloquante.
Priorité basse.
Définis dans le header include/linux/gfp.h (GFP: get_free_pages)
119
FORMATION
LINUX
Flags pour kmalloc
 __GFP_DMA
Allocation dans la zone DMA
 __GFP_HIGHMEM
Allocation en mémoire étendue (x86 et
sparc)
 __GFP_REPEAT
Demande d'essayer plusieurs fois. Peut se bloquer,
mais moins probable.
 __GFP_NOFAIL
Ne doit pas échouer. N'abandonne jamais.
Attention: à utiliser qu'en cas de nécessité!
 __GFP_NORETRY
Si l'allocation échoue, n'essaie pas d'obtenir de
page libre.
Options supplémentaires (pouvant être ajoutés avec l'opérateur) :
120
FORMATION
LINUX
Allocation par pages
Plus appropriée que kmalloc pour les grosses tranches de mémoire :
 unsigned long get_zeroed_page(int flags);
Retourne un pointeur vers une page libre et la remplit avec des zéros
 __get_free_pages()/free_pages(): alloue / désalloue un nombre entier (2^n) de pages contiguës de mémoire
réelle (idem précédentes mais pour des besoins plus conséquents - limité à 128 ko). Le contenu n'est pas
initialisé :
 unsigned long __get_free_page(int flags);
 unsigned long __get_free_pages(int flags, unsigned long order);
Retourne un pointeur sur une zone mémoire de plusieurs pages continues en mémoire physique. order:
log2
(nombre_de_pages).
 Libérer des pages :
 void free_page(unsigned long addr);
 void free_pages(unsigned long addr, unsigned long order);
Utiliser le même ordre que lors de l'allocation.
121
FORMATION
LINUX
Mapper des adresses physiques
 vmalloc et ioremap peuvent être utilisés pour obtenir des zones mémoire continues dans l'espace
d'adresse virtuel (même si les pages peuvent ne pas être continues en mémoire physique).
vmalloc()/vfree() : alloue / désalloue un bloc de mémoire virtuelle composé de plusieurs blocs
discontiguës de mémoire réelle.
 void* vmalloc(unsigned long size);
 void vfree(void* addr);
 void* ioremap(unsigned long phys_addr, unsigned long size);
• Ne fait pas d'allocation.
• Fait correspondre le segment donné en mémoire physique dans l'espace d'adressage virtuel.
 void iounmap(void* address);
122
 Transfert de données entre espace utilisateur et noyau et vice et versa :
 copy_from_user
Copie des données de l'espace utilisateur vers l'espace noyau.
 copy_to_user
Copie des données de l'espace noyau vers l'espace utilisateur.
FORMATION
LINUX
Utilitaires pour la mémoire
 void* memset(void* s, int valeur, size_t taille);
Remplit une région mémoire avec la valeur donnée.
 void* memcpy(void* dest, const void* src, size_t count);
 Copie une zone mémoire vers une autre.
 Utiliser memmove avec des zones qui se chevauchent.
 De nombreuses fonctions équivalentes à celles de la glibc sont définies dans include/linux/string.h
123
FORMATION
LINUX
Allocation de mémoire
 Prototypes des primitives d’allocations :
 Headers :
• #include <linux/slab.h>
• #include <linux/vmalloc.h>
 Fonctions :
• void *kmalloc (size_t size, int flags);
• void kfree (const void *addr);
• unsigned long __get_free_pages (int
• gfp_mask, unsigned long order);
• void free_pages (unsigned long addr,
• unsigned long order);
• void *vmalloc (unsigned long size);
• void vfree (void *addr);
124
FORMATION
LINUX
Choix d’un intervalle d'E/S
 Les limites de la mémoire et des ports d'E/S peuvent être passés comme paramètres de module. Un
moyen facile de définir ces paramètre est au travers de /etc/modprobe.conf
 Les modules peuvent aussi essayer de trouver des zones libres par eux-mêmes (en faisant plusieurs
appels à request_region).
125
FORMATION
LINUX
Différences avec la mémoire standard
 Écriture et lecture sur la mémoire peuvent être mis en cache.
 Le compilateur peut choisir d'écrire la valeur dans un registre du processeur, et ne jamais
l'écrire dans la mémoire principale.
 Le compilateur peut décider d'optimiser ou réordonner les instructions de lecture /
écriture.
126
FORMATION
LINUX
Eviter les problèmes d'accès aux E/S
 Le cache sur la mémoire et les ports d'E/S est désactivé, soit par le hardware ou par le code d'init
Linux.
 Linux fournit les Barrières Mémoire pour empêcher le compilateur de réordonnancer les accès:
Dépendant de l'architecture
#include <asm/system.h>
void rmb(void);
void wmb(void);
void mb(void);
Indépendant
#include <asm/kernel.h>
void barrier(void);
127
FORMATION
LINUX
Transferts de mémoire
 Le noyau utilise de la mémoire virtuelle noyau
 Les processus utilisent chacun leur propre espace mémoire virtuel
 Besoin de transférer les données de l'espace mémoire noyau vers l'espace mémoire du processus
appelant et inversement
 Les principales fonctions sont :
 {get,put}_user() : transfert d'une variable depuis / vers l'espace mémoire utilisateur
(utilisation en lvalue). Souvent utilisé pour le transfert d’une valeur.
 copy_{from,to}_user() : transfert d'un buffer depuis / vers l'espace mémoire utilisateur.
Utilisé pour le le transfert d’un buffer.
 Ces fonctions utilisent la fonction access_ok() qui vérifie la validité des buffers utilisateurs
 On peut s'affranchir de cet appel en utilisant les mêmes fonctions préfixées par __ (déconseillé)
 Prototypes :
#include <asm/uaccess.h>
int get_user (lvalue, addr);
int put_user (expression, addr);
int copy_{to,from}_user (unsigned long
dest, unsigned long src, unsigned long
len);
int access_ok (int type, unsigned long
addr, unsigned long size);
128
FORMATION
LINUX
Mémoire mappée directement
 Dans certaines architectures (principalement MIPS), la mémoire d'E/S peut être directement mappée
dans l'espace d'adressage physique.
 Dans ce cas, les pointeurs d'E/S ne doivent pas être déréférencés.
 Pour éviter les problèmes de portabilité à travers les architectures, les fonctions suivantes peuvent être
utilisées :
unsigned read[b|w|l](address);
void writeb[b|w|l](unsigned value, address);
void memset_io(address, value, count);
void memcpy_fromio(dest, source, num);
void memcpy_toio(dest, source, num);
129
FORMATION
LINUX
Mapper la mémoire d'E/S en mémoire
virtuelle
 Pour accéder à la mémoire d'E/S, les pilotes ont besoin d'une adresse virtuelle que le processeur peut
gérer.
 Les fonctions ioremap permettent cela:
#include <asm/io.h>
void* ioremap(unsigned long phys_addr, unsigned long size);
void* ioremap_nocache(unsigned long phys_addr, unsigned long size);
void iounmap(void* address);
 Attention: vérifiez que ioremap ne retourne pas NULL !
130
FORMATION
LINUX
mmap
 Répond aux requêtes de la fonction mmap de la glibc:
void* mmap(void* start, size_t length, int prot, int flags, int fd, off_t offset);
int munmap(void *start, size_t length);
 Permet aux programmes utilisateurs d'accéder directement à la mémoire du périphérique.
 Utilisé par des programmes comme le serveur X-Window ou V4L. Plus rapide que les autres méthodes
(comme écrire dans le fichier /dev correspondant) pour les applications utilisateur à fort besoin en
bande passante.
131
FORMATION
LINUX
Zones de Mémoire Virtuelle
 Zone de Mémoire Virtuelle (Virtual Memory Areas): zone contiguë dans la mémoire virtuelle d'un
processus, avec les mêmes permissions.
$ cat /proc/1/maps (processus init)
Début fin perm décalage majeur:mineur inode Nom du fichier mappé
00771000-0077f000 r-xp 00000000 03:05 1165839 /lib/libselinux.so.1
0077f000-00781000 rw-p 0000d000 03:05 1165839 /lib/libselinux.so.1
0097d000-00992000 r-xp 00000000 03:05 1158767 /lib/ld-2.3.3.so
00992000-00993000 r--p 00014000 03:05 1158767 /lib/ld-2.3.3.so
00993000-00994000 rw-p 00015000 03:05 1158767 /lib/ld-2.3.3.so
00996000-00aac000 r-xp 00000000 03:05 1158770 /lib/tls/libc-2.3.3.so
00aac000-00aad000 r--p 00116000 03:05 1158770 /lib/tls/libc-2.3.3.so
00aad000-00ab0000 rw-p 00117000 03:05 1158770 /lib/tls/libc-2.3.3.so
00ab0000-00ab2000 rw-p 00ab0000 00:00 0
08048000-08050000 r-xp 00000000 03:05 571452 /sbin/init programme
08050000-08051000 rw-p 00008000 03:05 571452 /sbin/init données, pile
08b43000-08b64000 rw-p 08b43000 00:00 0
f6fdf000-f6fe0000 rw-p f6fdf000 00:00 0
fefd4000-ff000000 rw-p fefd4000 00:00 0
ffffe000-fffff000 ---p 00000000 00:00 0
132
FORMATION
LINUX
Zones de Mémoire Virtuelle
Exemple du serveur X (extrait) :
Début fin perm décalage majeur:mineur inode Nom du fichier mappé
08047000-081be000 r-xp 00000000 03:05 310295 /usr/X11R6/bin/Xorg
081be000-081f0000 rw-p 00176000 03:05 310295 /usr/X11R6/bin/Xorg
...
f4e08000-f4f09000 rw-s e0000000 03:05 655295 /dev/dri/card0
f4f09000-f4f0b000 rw-s 4281a000 03:05 655295 /dev/dri/card0
f4f0b000-f6f0b000 rw-s e8000000 03:05 652822 /dev/mem
f6f0b000-f6f8b000 rw-s fcff0000 03:05 652822 /dev/mem
133
FORMATION
LINUX
mmap simple
 Pour autoriser les opérations mmap(), le pilote a juste besoin de créer des pages de mémoire mappant une
zone physique.
 Cela peut être fait avec la fonction suivante (linux/mm.h) à appeler dans une fonction driver_mmap:
int remap_page_range(
struct vm_area_struct *vma,
unsigned long from, /* Virtual */
unsigned long to, /* Physical */
unsigned long size, pgprot_t prot);
 Cette fonction est alors à ajouter à la structure file_operations du pilote.
Exemple: drivers/char/mem.c
134
FORMATION
LINUX
NS (Network Stack)
135
FORMATION
LINUX
Historique de la pile réseau
136
Le développement de la couche réseau dans le noyau Linux a été
orchestré par plusieurs programmeurs indépendants.
Le but est d'implémenter un système qui soit au moins aussi performant
que les autres tout en restant dans le domaine du logiciel libre.
C'est avant tout le protocole TCP/IP qui a été
développé avec des primitives de base par
Ross Biro. Orest Zborowski produisit la
première interface socket BSD pour le noyau
GNU Linux.
Le code fut ensuite repris par Alan Cox de Red
Hat.
FORMATION
LINUX
Protocoles supportés
137
Linux gère une multitude de protocoles réseau :
OSI 2 : couche liaison (Driver réseaux) : 1. Ethernet
2. ARP / RARP
3. Tokenring
4. ATM
OSI 3 : couche réseau :
OSI 4 : couche transport :
1. TCP
2. UDP
3. Netbios
1. IP
2. ICMP
3. IGMP
4. ATM

La pile réseau de GNU Linux peut être considéré comme la plus complète et disponible à ce jour.
UNIX Unix domain sockets
INET TCP/IP
AX25 Amateur radio
IPX Novell IPX
APPLETALK Appletalk
X25 X.25
Etc…
(define in include/linux/socket.h)
FORMATION
LINUX
Protocoles supportés
138
 Disponibilité des fonctionnalités dans la pile
réseau en fonction des versions du noyau Linux
2.2, 2.4 et 2.6 
FORMATION
LINUX
Support du réseau dans le
noyau
139
Modèle Internet de la pile réseau. Architecture de la pile réseau.
 La pile réseau couvre le protocole TCP/IP
de la couche liaison (drivers) jusqu'à la
couche transport (sockets BSD).
 D'un point de vue de Linux, la pile est localisée
dans le noyau avec une API (les sockets BSD)
pouvant être appelée depuis l'espace utilisateur.
Couche matérielle
Couche de liaison
Couche réseau
Couche transport
Couche applicative
Application utilisateur
Driver réseau
Protocoles réseaux
Interface de diagnostique des devices
Interface de diagnostique des protocoles
Appels système
Carte réseau
Application
User
space
Kernel
space
FORMATION
LINUX
Pile réseau
La pile réseau s'interface
avec le module VFS et le
Process Manager 
140
FORMATION
LINUX
SCI (System Call Interface)
141
FORMATION
LINUX
API des primitives système
 Les primitives systèmes du noyau son
accessible via une API POSIX 
 L'appel à ces fonctions se faisant via
la librairie C standard 
142
NOYAU LINUX
Implémentation privée
Interface SCI publique compatible POSIX.1
Programme en espace utilisateur
FORMATION
LINUX
Schéma synthétique d’un appel
système
libc
Interface User/Kernel
L'appel d'une primitive
du noyau Linux se fait
via la librairie libc.so.6

143
FORMATION
LINUX
Tout passe par les appels système
(syscalls)
 déroulement d'une session de login 144
Interface User/Kernel
FORMATION
LINUX
Hooking de primitive système
#include <linux/syscall.h>
#include <asm/unistd.h>
static void **sys_call_table;
extern void *system_utsname;
static int locate_sys_call_table(void)
{
unsigned long *begin;
int i;
begin=(unsigned long *) &system_utsname;
for (i=0;i<1024;i++) {
if (*(begin+i)==(unsigned long) sys_socketcall)
{
sys_call_table=(void *) (begin+i-__NR_socketcall);
//are you sure?
if (sys_call_table[__NR_exit]==(void *) sys_exit)
{
printk("success: located sys_call_table: %Xn",(unsigned 
int) sys_call_table);
return(1);
}
}
}
return(0);
}
 La technique consiste à rechercher la table
des symboles de façon à pouvoir redéfinir,
Intercepter, masquer, espionner
Une primitive du noyau.
145
int __init init_exportmodule (void)
{
if (!locate_sys_call_table())
{
// Retourne une erreur
}
//.....sys_call_table[] fonctionne!!
}
FORMATION
LINUX
Table des symboles des primitives
 Anciennement (avec un noyau 2.4), lorsqu'il fallait retrouver une primitive dans le noyau, il suffisait
d'utiliser le tableau suivant (issue de System.map) :
sys_call_table[__NR_open] = (void*)my_func_ptr;
 Cependant, du fait de l'utilisation de cette variable par les RootKit, cette dernière n'est plus exportée.
 Désormais, la fonction ‘system_call’ effectue un accès direct à ‘sys_call_table[]’
(arch/i386/kernel/entry.S:240) :
call *sys_call_table(,%eax,4)
 Sur une machine x86 cela est traduit de la façon suivante :
0xff 0x14 0x85 <addr4> <addr3> <addr2> <addr1>
Where the 4 ‘addr’ bytes form the address of ‘sys_call_table[]’.
146
FORMATION
LINUX
Table des symboles des primitives
 System_call n'étant pas exporté non plus, elle est définie quand même comme au niveau système
(arch/i386/kernel/traps.c:1195) :
set_system_gate(SYSCALL_VECTOR,&system_call);
 Sur la plateforme x86, cela signifie que cette adresse est stockée dans une table de descripteur
d'interruption (IDT : Interrupt Descriptor Table). L'emplacement de cette table peut être connue via
le registre IDT (IDTR) et finalement cette IDTR peut à son tour être retrouvée par l'instruction
SIDT.
 Résumé :
 Récupérer l'IDTR utilisant SIDT
 Extraire l'adresse de l'IDT à partir de l'IDTR
 Récupérer l'adresse de ‘system_call’ à partir de la 0x80ième entrée de la table IDT.
147
FORMATION
LINUX
Code valide avec le noyau 2.6.x
// -----------------------------------------------------------------------------
// Sys Call Table Address finder function
// -----------------------------------------------------------------------------
unsigned long **find_sys_call_table(void)
{
unsigned long **sctable;
unsigned long ptr;
extern int loops_per_jiffy;
sctable = NULL;
for (ptr = (unsigned long)&unlock_kernel;
ptr < (unsigned long)&loops_per_jiffy;
ptr += sizeof(void *))
{
unsigned long *p;
p = (unsigned long *)ptr;
if (p[__NR_close] == (unsigned long) sys_close)
{
sctable = (unsigned long **)p;
return &sctable[0];
}
}
return NULL;
}
http://www.subversity.net/linux/finding-sys_call_table
http://kerneltrap.org/node/6416
http://lwn.net/Articles/339253/
http://lwn.net/Articles/306804/
 Listing d'une fonction de recherche de la table de symbole :
148
Note : depuis la version 2.6.30, la sys_call_table a été placé en lecture seule pour des raisons de sécurité. En
effet, le risque avec cette table est de remplaçer une primitive par une autre. Une alternative est d’utiliser l’API
fanotify (toujours en développement).
FORMATION
LINUX
REGLES DE CODAGE
 Indentation
 Briser les lignes longues
 Accolades
 Nommage
 Flags de compilation
 Divers
 Précepts globaux
BUT : maitriser les règles de codage dans le noyau linux
FORMATION
LINUX
Règles de codage - indentation
150
 Les tabulations sont de 8 caractères.
 L'idée derrière l'indentation est de définir clairement les cas où un bloc de contrôle commence et se
termine. Surtout quand vous avez été en regardant votre écran pendant 20 heures d'affilée, vous verrez
qu'il sera beaucoup plus facile de voir comment l'indentation fonctionne si vous avez de grandes
échancrures.
 Maintenant, certains prétendent que les gens vont avoir 8-indentations caractère qui fait bouger le code
trop loin vers la droite, et il devient difficile à lire à l'écran du terminal de 80 caractères. La réponse à cela
est que si vous avez besoin de plus de 3 niveaux d'indentation, tu es vissé quand même, et devrait fixer
votre programme.
 En bref, 8-tirets char rendre les choses plus faciles à lire, et ont l'avantage supplémentaire de vous avertir
lorsque vous êtes nidification vos fonctions trop profonde. Heed that warning. Compte de cet
avertissement.
 Ne mettez pas de déclarations multiples sur une seule ligne, sauf si vous avez quelque chose à cacher:
if (condition) do_this; do_something_everytime; NOK
if (condition) do_this;
OK
do_something_everytime;
 En dehors des commentaires, documentation et sauf dans kconfig, les espaces ne sont jamais utilisés
pour l'indentation, et l'exemple ci-dessus est délibérément rompu.
FORMATION
LINUX
Briser les chaines longues
 La limite sur la longueur des lignes est de 80 colonnes, et c'est une limite dure.
 Des déclarations de plus de 80 colonnes doivent être brisées en morceaux sensibles.
 La même chose s'applique aux appels de fonction avec une longue liste d'arguments.
 De longues files sont ainsi divisées en chaînes plus courtes.
void fun(int a, int b, int c)
{
if (condition)
printk(KERN_WARNING "Warning this is a long printk with "
"3 paramètres a UB:%:% u" "c:% u  n", a, b, c);
else autre
next_statement; next_statement;
}
151
FORMATION
LINUX
Les accolades
152
Les accolades peuvent suivre les règles défini par Kernighan and Ritchie.
Exemple :
int fonction(void)
{
char msg[] = "hello worldn";
char *end = msg + sizeof(msg);
char *cur;
for (cur = msg; cur != end; ++cur)
{
putchar(*cur);
}
return 0;
}
FORMATION
LINUX
Nommage
153
 Ne pas utiliser de noms mignons comme ThisVariableIsATemporaryCounter.
 Les variables globales sont à proscrire.
 Le nom des variables doivent être le plus court possible mais aussi le plus significatif aussi.
FORMATION
LINUX
Codes de retour
154
 Les codes de retour sont normalisés depuis Posix 1003.1 :
 Valeurs négatives d'erreurs définies (positivement) dans <linux/errno.h> et <asm/errno.h>
 Valeurs positives ou nulles en cas de fonctionnement correct
 Toutes les fonctions du noyau utilisent cette normalisation
 Transmission des valeurs d'erreur entre fonctions
 Extrait des valeurs :
[E2BIG]Argument list too long.
[EACCES]Permission denied.
[EADDRINUSE]Address in use.
[EADDRNOTAVAIL]Address not available.
[EAFNOSUPPORT]Address family not supported.
[EAGAIN]Resource unavailable, try again (may be the same value as
[EWOULDBLOCK]).
[EALREADY]Connection already in progress.
[EBADF]Bad file descriptor.
[EBADMSG]Bad message.f
http://www.opengroup.org/onlinepubs/000095399/basedefs/errno.h.html
FORMATION
LINUX
Flags de compilation
155
 Linux accepte la compilation conditionnelle via le préprocesseur mais il faut respecter la règle suivante :
#ifdef condition
…
#else
…
#endif
Il est important en effet d’avoir les deux closes d’implémentés, pour savoir ce que l’on doit faire si
le flag n’est pas positionné.
FORMATION
LINUX
Divers
 Includes C: vous ne pouvez pas utiliser les fonctions de la bibliothèque C standard (printf(),
strcat(), etc.). La bibliothèque C est implémentée au dessus du noyau et non l'inverse.
 Linux a quelques fonctions C utiles comme printk(), qui possède une interface similaire à printf().
 Donc, seul les fichiers d'entêtes du noyau sont autorisés.
 N'utilisez jamais de nombres à virgule flottante dans le code du noyau. Votre code peut être
exécuter sur un processeur sans unité de calcul à virgule flottante (comme sur ARM). L'émulation
par le noyau est possible mais très lente.
 Définissez tous vos symboles en local/statique, hormis ceux qui sont exportés (afin d'éviter la
pollution de l'espace de nommage).
 Consultez: Documentation/CodingStyle.
 Il est toujours bon de connaître, voir d'appliquer, les règles de codage GNU:
http://www.gnu.org/prep/standards.html
156
FORMATION
LINUX
Precepts
 Il faut toujours essayer de déporter la complexité “algorithmique” en dehors du noyau. Cela
implique donc :
 Que le noyau doit rester le plus petit possible. Selectionner juste ce qui est nécessaire lors de la
configuration du noyau (.config).
 Les appels systèmes doivent rester en nombre limité à cause de la latence engendré par le
changement de contexte.
 La complexité doit résider soit dant la librairie C (libc, uclibc, dietlibc, … ) ou bien dans les
applications utilisateurs.
157
FORMATION
LINUX
METHODOLOGIES DE DEVELOPPEMENT
BUT : maitriser les règles d’usage dans le noyau linux
 Pourquoi une méthodologie ?
 Plusieurs méthodologie :
 Travail en local
 Dé/chargement de modules
 Travail avec un second noyau via UML
 Simulation via un simulateur
 Via un second système
FORMATION
LINUX
Pourquoi une méthodologie ?
Un kernel panic du noyau GNU linux
 Le noyau GNU Linux est le cœur du
système d'exploitation.
 Travailler directement au cœur du noyau
peut le rendre instable et engendrer un
KERNEL PANIC, le rendant donc
inutilisable 
 Avant toute installation d'un nouveau
noyau, il est conseillé d'en avoir un autre
de référence enregistré au niveau du
BOOT loader connu pour ne pas poser de
problème lors du démarrage.
 Développer et surtout tester un nouveau
noyau Linux s'accompagne souvent d'un
ensemble de méthodes très utiles.
159
FORMATION
LINUX
Travail en local
 But : cela revient à travailler en local sur un driver et à le (dé)charger manuellement sur le noyau en
courant.
 Avantage : facile à mettre en place et à utiliser.
 Inconvénient : si le noyau devient instable, il peut être nécessaire de rebooter. A préconiser pour de petit
drivers mais à déconseiller vivement pour des drivers complexe (réseau ou vfs par exmple).
C'est envisageable pour des modules mais s'il est nécessaire de modifier le cœur de même du noyau alors
cette technique est à éviter.
 Debug / traces :
sudo tail -f /proc/kmsg
sudo tail -f /var/log/messages
dmesg [ -c ] [ -n niveau ] [ -s taille ]
syslogd
 Pour information, le chargement d'un driver dans le noyau en dynamique revient au chargement d'une
librairie dynamique. il y a fusion des symboles du modules avec ceux du noyau.
160
FORMATION
LINUX
(Dé)chargement de modules
161
 Ce paquet contient un ensemble de programmes pour charger, insérer et supprimer des modules du
noyau Linux
 Le nom du packages change suivant les version de Linux :
 Linux 2.4 : modutils
 Linux 2.6 : module-init-tools
 Ce package contient les outils suivants :
 depmod Crée un fichier de dépendances basé sur les symboles trouvés dans l'ensemble de
modules existants ; ce fichier de dépendances est utilisé par modprobe pour charger
automatiquement les modules requis
 insmod Installe un module chargeable dans le noyau en cours d'exécution
 insmod.static Une version compilée statiquement de insmod
 lsmod Liste les modules déjà chargés
 modinfo Examine un fichier objet associé à un module du noyau et affiche toute information
qu'il peut récupérer
 modprobe Utilise un fichier de dépendances, créé par depmod, pour charger automatiquement
les modules adéquats
 rmmod Décharge les modules du noyau en cours d'exécution
http://www.kerneltools.org/KernelTools.org
FORMATION
LINUX
(Dé)chargement de modules
 Exemple de listing des modules chargés :
$ lsmod
…
snd_pcm_oss 40384 0
snd_mixer_oss 16096 2 snd_pcm_oss
…
 En résumé :
 insmod snd_pcm_oss : OK
 insmod snd_mixer_oss : OK si snd_pcm_oss déjà chargé sinon NOK
 modprobe snd_pcm_oss : OK
 modprobe snd_mixer_oss : OK chargera snd_pcm_oss si pas chargé
 Le raisonnement est le même pour le déchargement. Seule les commandes changent. rmmod <modulename>
remplace insmod et modprobe –r <modulename> remplace modprobe. Modprobe –r, déchargera aussi les
autres modules dépendant si non utilisés.
modinfo <modulename> donne les informations sur un module comme l'auteur, sa licence, ses paramètres.
sudo depmod : permet de recréer le cache de la liste des modules (mécanisme similaire à ldconfig).
A noter qu'il est possible de rajouter le nom des modules à charger lors d'un boot dans le fichier de
configuration /etc/modules.
 Dans le listing suivant, snd_pcm_oss n'as pas de
dépendances mais par contre snd_mixer_oss a le module
snd_pcm_oss comme dépendance ce qui veut dire qu'il est
possible de charger le module snd_pcm_oss de façon unitaire et
directement alors que le module snd_mixer_oss nécessitera que
le module snd_pcm_oss soit chargé au préalable.
Pour info lsmod met en forme les informations générés dans
/proc/modules
162
FORMATION
LINUX
(Dé)chargement de modules
insmod
ou
modprobe
rmmod
ou
modprobe -r
 Lors du chargement dynamique
d'un module, cela se passe comme
pour le chargement d'une librairie
dynamique c'est-à-dire que le
module est linké au noyau.
Les symboles (primitives) du module
sont rajouté et peuvent être utilisés
dans d'autres modules ou dans le
noyau lui-même.
163
FORMATION
LINUX
Dépendances de modules
 Les dépendances des modules n'ont pas à être spécifiées explicitement par le créateur du module.
 Elles sont déduites automatiquement lors de la compilation du noyau, grâce aux symboles exportés
par le module: module2 dépend de module1 si module2 utilise un symbole exporté par module1.
 Les dépendances des modules sont stockées dans : /lib/modules/<version>/modules.dep
 Ce fichier est mis à jour (en tant que root) avec : depmod -a [<version>]
164
FORMATION
LINUX
Utilisation de User Mode Linux (UML)
 User Mode Linux ou UML est un noyau Linux compilé qui peut être exécuté dans
l'espace utilisateur comme un simple programme. Il permet donc d'avoir plusieurs
systèmes d'exploitation virtuels (principe de virtualisation) sur une seule machine
physique hôte exécutant Linux.
 Avantages :
 Si un User Mode Linux plante, le système hôte n'est pas affecté.
 Un utilisateur sera root sur un User Mode Linux, mais pas sur le système hôte.
 Au niveau développement, gdb peut servir à débuguer le noyau de dev puisqu'il est considéré comme un
processus normal.
 Il permet aussi de tester différents paramètres noyaux sans se soucier des conséquences.
 Il permet de tester différentes configurations ou compilations du noyau sans avoir à l'installer et
redémarrer la machine.
 Il permet de mettre en place un réseau complètement virtuel de machines Linux, pouvant communiquer entre
elles. Les tests de topologies lourdes d'un
point de vue physique peuvent donc être menés aisément ici.
 Inconvénients :
 Très lent, plutôt conçu pour des tests fonctionnels que
pour la performance
 Nécessite de patcher le noyau
Noyau GNU Linux courant
Diagramme d'une architecture UML
http://user-mode-linux.sourceforge.net/
http://www.rstack.org/oudot/20022003/7/7_rapport.pdf
http://www.ibm.com/developerworks/edu/l-dw-linuxuml-i.html
http://www.metz.supelec.fr/metz/personnel/galtier/PagesPerso/TutorielUML/UML_avec_briques_existantes/index.h
tml
Noyau
expérimental
ESPACE UTILISATEUR
UML
165
FORMATION
LINUX
Kernel Mode Linux (KML)
http://www.linuxjournal.com/article/6516
http://web.yl.is.s.u-tokyo.ac.jp/~tosh/kml/
http://web.yl.is.s.u-tokyo.ac.jp/~tosh/kml/tosh_master_kml_e.ps
http://en.wikipedia.org/wiki/Linux_kernel
http://www.ibiblio.org/pub/Linux/docs/HOWTO/translations/fr/pdf/Kernel-HOWTO.pdf
 Cette technique réciproque de UML, permet d'exécuter dans le noyau un processus habituellement
prévu pour l'espace user.
 Tout comme pour UML, cela nécessite de patcher le noyau et d'activer la fonctionnalité lors de la
Compilation du noyau.
 Les architectures supportées sont : IA-32 et AMD64.
 Actuellement, les binaires ne peuvent pas modifier les registres suivants : CS, DS, SS or FS.
 Ce système peut être cependant intéressant de façon à diminuer la latence :
Latency of System Calls (Unit: CPU cycles) :
Original Linux (using sysenter) Kernel Mode Linux
Getpid 432 12
Gettimeofday 820 404
166
FORMATION
LINUX
Utilisation d’un simulateur
 Plusieurs architectures existent : QEMU, VMWARE, BOCHS, VirtualBox et bien d'autres permettent de générer une
Image bootable permettant d'avoir un système d'exploitation à l'intérieur d'un autre. C'est une autre forme de
virtualisation qui peut garantir une sécurité au niveau du système en cours de développement.
 Avantages :
• Très pratique pour des développment sur le
noyau même.
• Pas besoin de patcher le noyau comme avec
UML.
 Inconvénients :
• Dépend de la puissance de la machine hôte.
• Peut nécessiter de régénérer l'image à chaque
fois que l'on souhaite la tester.
# Création du rootfs
mkdir iso
# Création de l'image ISO
mkisofs -o rootfs-dev.iso -J -R ./iso
# Cela peut être une recopie d'un média
dd if=/dev/dvd of=dvd.iso # for dvd
dd if=/dev/cdrom of=cd.iso # for cdrom
dd if=/dev/scd0 of=cd.iso # if cdrom is scsi
# Simulation
qemu -boot d -cdrom ./rootfs-dev.iso
# Montage
sudo modprobe loop
sudo mount -o loop rootfs-dev.iso /mnt/disk
# Démontage
sudo umount mnt/disk
http://fabrice.bellard.free.fr/qemu/
http://www.vmware.com/fr/
http://www.virtualbox.org/
http://packages.debian.org/mkinitrd-cd
http://packages.debian.org/sid/mkinitrd-cd
http://www.mayrhofer.eu.org/mkinitrd-cd
http://bochs.sourceforge.net/
167
FORMATION
LINUX
Utilisation d’un second système
 De loin la technique la plus adaptée car permet de développer au coeur du noyau ou bien des modules complexes.
 Cette technique est de plus adaptée pour un usage embarqué.
 Avantages :
 Très pratique pour des développement sur le noyau même.
 Permet de debuguer via la liaison série ou le réseau le noyau
courant du second système en pouvant oser un point d'arrêt.
 Inconvénients :
 Nécessite de disposer d'une seconde machine.
http://kgdb.linsyssoft.com/
http://www.mulix.org/lectures/kernel_oopsing/kernel_oopsing.pdf
http://www.alcove.com/IMG/pdf/kernel_debugging.pdf
http://www.ibm.com/developerworks/linux/library/l-kdbug/
http://www.ibm.com/developerworks/linux/library/l-debug/
 Activation de KDB sur le système de dev :
echo "1" >/proc/sys/kernel/kdb
Liaison
série Liaison
ethernet
Poste servant
aux développements
seconde plateforme
de développement
168
FORMATION
LINUX
En remplacement d'un port série de
débug
 Sur la plate-forme de développement:
 Pas de problème. Vous pouvez utiliser un convertisseur
USB<-> série. Bien supporté par Linux. Ce périphérique apparaît en tant que /dev/ttyUSB0 sur
la cible:
 Vérifiez si vous avez un port IrDA. C'est aussi un port série.
 Si vous avez une interface Ethernet, essayez de l'utiliser.
 Vous pouvez aussi connecter en JTAG directement les broches série du processeur (vérifiez
d'abord les spécifications électriques!)
http://www.jtag.com/?gclid=CJrAjLLT7pICFQgNuwodQBgD4w
http://www.linux-mips.org/wiki/JTAG
http://www.coreboot.org/JTAG/BSDL_Guide
http://www.intel.com/design/flcomp/applnots/29218602.PDF
http://packages.debian.org/testing/embedded/openwince-jtag
http://wiki.openwrt.org/OpenWrtDocs/Customizing/Hardware/JTAG_Cable
http://irda.sourceforge.net/
http://www.ibiblio.org/pub/Linux/docs/howto/translations/fr/pdf/Infrared-HOWTO.pdf
http://www.hpl.hp.com/personal/Jean_Tourrilhes/IrDA/
http://www.linux-usb.org/
169
FORMATION
LINUX
Quelques editeurs
 Liste de quelques editeurs recommandés pour le développement noyau :
 Ajunta
 Eclipse
 Kdevelop
 Kscope
 Netbean
 Source navigator
 Développer des drivers Linux est plus facile si la machine de dev est native linux.
170
FORMATION
LINUX
DEVELOPPEMENT DANS LE NOYAU
BUT : apprendre à développer des drivers.
 Ajout d’un répertoire
 Makefile d’un module
 Squelettes de drivers
 Les pilotes de caractères
 Les pilotes de blocs
FORMATION
LINUX
Ajout d’un répertoire au noyau
 Pour ajouter un répertoire mon_drivers/ aux sources du noyau:
 Dans le répertoire parent :
• Créer un répertoire mon_drivers/ à l'endroit approprié dans les sources du noyau
• Dans le fichier Kconfig, ajouter:
source “mon_driver/Kconfig”
• Dans le fichier Makefile du répertoire parent, ajouter:
“obj-$(CONFIG_MONFLAG) += mon_driver/” (juste 1 condition)
or
“obj-y += mon_driver/” (plusieurs conditions)
 Dans le répertoire mon_drivers/ :
• Créer un fichier mon_driver/Kconfig
• Créer un fichier mon_driver/Makefile basé sur les variables Kconfig
 Lancer make xconfig et utiliser vos nouvelles options !
 Lancer make et vos nouveaux fichiers sont compilés !
 Regardez Documentation/kbuild/*.txt pour plus de détails
172
obj-y objets à inclure au noyau de façon statique
obj-m objets d’un modules dynamique
FORMATION
LINUX
Création d’un makefile indépendant
173
obj-m := mondriver.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
all:
make ARCH=sh CROSS_COMPILE=sh4-linux- M=$(PWD) -C $(KDIR)
clean:
make ARCH=sh CROSS_COMPILE=sh4-linux- M=$(PWD) -C $(KDIR) clean
 Il est possible de compiler un drivers séparément du noyau.
 Pour ce faire il faut juste renseigner définir quelques variables :
 Exemple de makefile permettant la génération d’un module mondriver.ko) :
 Utilisation :
KDIR Chemin vers les sources du noyau
PWD Chemin courant
Compilation du module make
Nettoyage make clean
 Il est à noter que les modules sont seulement compilés et pas linkés, le linkage s'effectuant lors du
chargement du drivers dans le noyau Linux.
 Anciennement (en 2.4), l'extension des modules étaient .o alors qu'en 2.6 c'est désormais .ko
Tabulation
(pas
d'espaces)
ifeq ($PATCHLEVEL, 4) correspond au noyau 2.4
FORMATION
LINUX
Dévelopement de modules noyau
 Les modules: ajoutent une fonctionnalité donnée au noyau (pilotes, support système de fichier,
etc...) ;
 Ils sont (dé)chargés à tout moment, quand leur fonctionnalité est requise (ou plus). Une fois chargés,
ils ont accès à tout le noyau. Aucune protection particulière ;
 Ils sont utiles pour garder une image du noyau à une taille minimum (essentiel pour les distributions
GNU/Linux pour PCs) ;
 Ils permettent de supporter l'incompatibilité entre pilotes (on charge soit l'un ou soit l'autre, mais pas
les 2) ;
 Ils permettent de fournir des pilotes binaires (mauvaise idée), utilisables sans avoir à recompiler le
noyau ;
 Ils permettent de développer des pilotes sans redémarrer: chargement, test, déchargement,
recompilation, chargement ;
 Ils peuvent aussi être compilés statiquement dans le noyau.
174
FORMATION
LINUX
Types de drivers
175
 Plusieurs types de périphériques :
 caractère (char) : lectures et
écritures séquentielles, non
bufferisés (exemple: carte graphique,
souris, lecteur de bande)
 bloc (block) : accès aléatoires, par
blocs de données, bufferisés et
optimisés, utilisé à travers la VFS
(exemple: disque dur, CDROM,
mémoire flash)
 réseau (net) : matériel de
communication utilisé à travers les
différentes couches réseau,
communications faites par paquets
sk_buff (exemple: cartes Ethernet,
Token Ring).
FORMATION
LINUX
Autres types de pilotes
 Ils n'ont aucune entrée correspondante dans /dev dans laquelle vous pouvez lire ou écrire avec une
commande Unix standard :
 Les pilotes réseaux
Ils sont représentés par un périphérique réseau comme ppp0, eth1, usbnet, irda0 (liste: ifconfig –a)
 Les autres pilotes
Souvent, ce sont des pilotes intermédiaires servant d'interface avec d'autres.
176
FORMATION
LINUX
Squelette de drivers : hello world simple
 Dépendance avec d'autres modules :
aucun
 Chargement :
insmod hello1
modprobe hello1
Résultat au chargement :
Hello, world
 Déchargement :
insmod hello1
modprobe -r hello1
Résultat au déchargement :
Au revoir…
 Les messages peuvent être obtenus
via la commande dmesg ou
/var/log/messages.
177
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
MODULE_LICENSE("Dual BSD/GPL");
static int hello_init(void)
{
printk(KERN_ALERT "Hello, worldn");
return 0;
}
static void hello_exit(void)
{
printk(KERN_ALERT "Au revoir...n");
}
module_init(hello_init);
module_exit(hello_exit);
obj-m += hello.o
default:
make -C /lib/modules/$(shell uname -r)/build/ SUBDIRS=$(PWD)
modules
 Listing :
 Makefile :
FORMATION
LINUX
Squelette de drivers
178
 Initialisation et libération : #include <linux/init.h>
 La fonction d'initialisation doit contenir tout le code nécessaire à l'initialisation du module
(allocations, initialisations matérielles, réservation des ressources...) :
module_init() : déclaration de la fonction d'initialisation de type int foo(void);
 Au contraire, la fonction de libération doit défaire tout ce qui a été fait à l'initialisation
(libération de mémoire, désactivation du matériel, libération des ressources...)
module_exit() : déclaration de la fonction de libération de type void foo(void);
FORMATION
LINUX
Squelette de drivers : compteur d’usage
179
 Chaque module possède un compteur d'usage.
 Permet d'éviter qu'un module soit déchargé pendant son utilisation.
 La gestion du compteur est faite par l'appellant.
 Le compteur peut être manipulé grâce à (<linux/module.h>) :
 MOD_INC_USE_COUNT : incrémente le compteur
 MOD_DEC_USE_COUNT : décrémente le compteur
 MOD_IN_USE : indique la valeur du compteur
 Le noyau 2.6 fournit à la place (<linux/module.h>) :
 try_module_get(THIS_MODULE) : essaye d'incrémenter la valeur du compteur
d'utilisation.
 module_put(THIS_MODULE) : décremente la valeur du compteur d'utilisation.
 module_refcount(THIS_MODULE) : indique la valeur du compteur d'utilisation.
FORMATION
LINUX
Squelette de drivers : hello world simple
180
 Tout driver doit initialiser son contexte via la fonction spécifié dans module_init().
 En revanche, il se doit de libérer tout ce qu’il a initialiser et qui ne sert plus via la fonction module_exit().
Il doit donc libérer toutes les ressources qu’il n’utilises plus.
 Ces deux fonctions sont donc les deux points d’entrée et de sortie obligé.
 La commande modinfo peut donner un ensemble d’informations sur un module :
$ modinfo /lib/modules/2.6.31.12-174.2.19.fc12.i686/kernel/drivers/video/vga16fb.ko
filename: /lib/modules/2.6.31.12-174.2.19.fc12.i686/kernel/drivers/video/vga16fb.ko
license: GPL
description: Legacy VGA framebuffer device driver
src version: 220D0B5A68FBFC014886CE0
depends: vgastate
vermagic: 2.6.31.12-174.2.19.fc12.i686 SMP mod_unload 686

http://www.tldp.org/LDP/lkmpg/2.6/lkmpg.pdf

http://www.tldp.org/LDP/lki/lki.pdf

http://www.tldp.org/LDP/lpg/index.html

http://www.tldp.org/LDP/khg/HyperNews/get/khg.html

http://tldp.org/LDP/lkmpg/2.6
/html/index.html.org/LDP/tlk/tlk.html

http://tldp.org/LDP/lkmpg/2.4/html/index.html
FORMATION
LINUX
Squelette de drivers : hello world + param.
181
#include <linux/init.h>#include <linux/module.h>
#include <linux/moduleparam.h>
MODULE_LICENSE("GPL");static char *nom=
"world";module_param(nom, charp, S_IRUGO);
static int nombre= 1;module_param(nombre, int,
S_IRUGO);static int hello_init(void){ int i; for (i = 0;
i < nombre; i++) printk(KERN_ALERT "(%d) Hello,
%sn", i, nom); return 0;}static void hello_exit(void){
printk(KERN_ALERT »Au revoir %sn", nom);}
module_init(hello_init);module_exit(hello_exit);
 Listing :
 Dépendance avec d'autres modules :
aucun
 Chargement 1 : insmod hello2
Résultat au chargement :
(0) Hello, world
 Chargement 2 :
insmod hello2 nom=toto
Résultat au chargement :
(0) Hello, toto
 Chargement 3 :
insmod hello2 nom=toto
nombre=2
Résultat au chargement :
(0) Hello, toto
(1) Hello, toto
 Déchargement : insmod hello2
Résultat au déchargement :
Au revoir…
FORMATION
LINUX
Squelette de drivers : hello world +
param.
 Déclarer des paramètres utilisable lors du chargement des modules :
 module_param(nom, type, perm);
• Nom : nom du paramètre
• Type : soit byte, short, ushort, int, uint, long, ulong, charp, bool ou invbool (vérifié à
la compilation !)
• Perm : permissions pour l'entrée correspondante dans
/sys/module/<module_name>/<param>. On peut utiliser 0.
 module_param_named(nom, valeur, type, perm);
Rend la variable nom disponible à l'extérieur du module et lui affecte valeur à l'intérieur.
 module_param_string(nom, chaine, taille, perm);
Crée une variable nom de type charp, pré-remplie avec la chaîne de longueur taille,
typiquement sizeof(string)
 module_param_array(name, type, num, perm);
Pour déclarer un tableau de paramètres
 Le passage de paramètres ne marche pour une compilation statique qu’à partir du 2.6. Avant il
fallait passer par la macro __setup().
182
FORMATION
LINUX
Passer des paramètres aux modules
 Avec insmod ou modprobe:
insmod ./hello_param.ko howmany=2 whom=universe
 Avec modprobe en changeant le fichier
/etc/modprobe.conf:
options hello_param howmany=2 whom=universe
 Avec la ligne de commande du noyau, lorsque le module est lié statiquement au noyau :
options hello_param.howmany=2 
hello_param.whom=universe
183
FORMATION
LINUX
License des modules
 GPL
GNU Public License v2 ou supérieure
 GPL v2
GNU Public License v2
 GPL and additional rights
 Dual BSD/GPL
Choix entre GNU Public License v2 et BSD
 Dual MPL/GPL
Choix entre GNU Public License v2 et
Mozilla
 Propriétaire
Produits non libres
La liste des licences est détaillée dans include/linux/module.h :
 Utilité des licences de module
 Utilisées par les développeurs du noyau pour identifier des problèmes venant de pilotes
propriétaires, qu'ils n'essaierons pas de résoudre
 Permettent aux utilisateurs de vérifier que leur système est à 100% libre.Permettent aux
distributeurs GNU/Linux de vérifier la conformité à leur politique de licence.
 L’idée est que le coeur doit rester sous licence GPL pure mais que des pilotes sous d’autres
licences soient tolérés.
184
FORMATION
LINUX
License des modules
 Les applications qui font des appels systèmes ne sont soumis à la licence GPL
 On peut faire du code non GPL dans les cas suivant :
 Pas de link statique, uniquement des modules
 Le module doit annoncer sa licence (MODULE_LICENCE)
 Restreint à une API de haut-niveau (EXPORT_SYMBOL) et pas (EXPORT_SYMBOL_GPL)
 Pas de travail dérivé
185
FORMATION
LINUX
La structure “device”
 Déclaration :
 La structure de donnée de base est struct device, définie dans include/linux/device.h
 En pratique, vous utiliserez plutôt une structure correspondant au bus auquel votre périphérique est
attaché: struct pci_dev, struct usb_device...
 Enregistrement
 Dépend toujours du type de périphérique, des fonctions spécifiques (de)d'(dés)enregistrement sont
fournies
 Références pour le «Device Model» :
La documentation dans les sources du noyau est très utile et très claire :
 Documentation/driver-model/
• binding.txt class.txt driver.txt overview.txt porting.txt bus.txt device.txt
interface.txt platform.txt
 Documentation/filesystems/sysfs.txt
186
FORMATION
LINUX
Les attributs du périphériques peuvent être lus/écrits depuis l'espace utilisateur :
Exemple :
struct device_attribute
{
struct attribute attr;
ssize_t (*show)(struct device * dev, char * buf, size_t count, loff_t off);
ssize_t (*store)(struct device * dev, const char * buf, size_t count, loff_t off);
};
#define DEVICE_ATTR(name,mode,show,store)
 Ajouter / enlever un fichier :
int device_create_file(struct device *device, struct device_attribute * entry);
void device_remove_file(struct device * dev, struct device_attribute * attr);
/* Créé un fichier nommé "power" avec un mode 0644 (-rw-r--r--) */
DEVICE_ATTR(power,0644,show_power,store_power);
device_create_file(dev,&dev_attr_power);
device_remove_file(dev,&dev_attr_power);
187
Les attributs de périphériques
FORMATION
LINUX
La structure «device_driver»
 Déclaration :
struct device_driver
{
/* Omitted a few internals */
char *name;
struct bus_type *bus;
int (*probe) (struct device * dev);
int (*remove) (struct device * dev);
void (*shutdown) (struct device * dev);
int (*suspend) (struct device * dev, u32 state, u32 level);
int (*resume) (struct device * dev, u32 level);
};
 Enregistrement :
extern int driver_register(struct device_driver * drv);
extern void driver_unregister(struct device_driver * drv);
 Attributs :
Disponibles de la même manière
188
FORMATION
LINUX
Portabilité des drivers
 Définition des types génériques interne au noyau :
u8 unsigned byte (8 bits)
u16 unsigned word (16 bits)
u32 unsigned 32-bit value
u64 unsigned 64-bit value
s8 signed byte (8 bits)
s16 signed word (16 bits)
s32 signed 32-bit value
s64 signed 64-bit value
 Exemple de fonction issue du bus i2c :
s32 i2c_smbus_write_byte(struct
i2c_client *client, u8 value);
s32 i2c_smbus_read_byte_data(struct
i2c_client *client, u8 command);
s32 i2c_smbus_write_byte_data(struct
i2c_client *client, u8 command,
u8 value);
Pour des variable pouvant être visible du userspace
(ex: ioctl) il est nécessaire d'utiliser cette notation :
__u8 unsigned byte (8 bits)
__u16 unsigned word (16 bits)
__u32 unsigned 32-bit value
__u64 unsigned 64-bit value
__s8 signed byte (8 bits)
__s16 signed word (16 bits)
__s32 signed 32-bit value
__s64 signed 64-bit value
Exemple d'utilisation, lors de l'envoie d'un message de
contrôle à un device USB :
struct usbdevfs_ctrltransfer {
__u8 requesttype;
__u8 request;
__u16 value;
__u16 index;
__u16 length;
__u32 timeout; /* in milliseconds */
void *data;
};
#define USBDEVFS_CONTROL_IOWR('U', 0, struct
usbdevfs_ctrltransfer)
 Définit dans linux/types.h
http://www.xml.com/ldd/chapter/book/ch10.html 189
FORMATION
LINUX
Format des octets en mémoire
190
 Deux formats de disposition des octets dans les mots :
 « Gros-boutiens » (Big-endian) : les octets de poids fort sont placés avant les octets de poids faible
(ex: Motorola 68k)
 « Petit-boutiens » (Little-endian) : les octets de poids faible sont placés avant les octets de poids fort
(ex: Intel x86)
 Certains périphériques peuvent utiliser un format différent de celui de la machine pour la
représentation de leurs données internes (bus PCI sur non x86, réseau sur x86 notamment)
 Des macros servent à optimiser les conversions entre différents formats (<asm/byteorder.h>) :
 cpu_to_{le,be}{16,32,64}() : conversion d'une donnée depuis le format local utilisé par le CPU vers un
format déterminé
 {le,be}{16,32,64}_to_cpu() : conversion d'une donnée depuis un format déterminé vers le format local
utilisé par le CPU
 Ces mêmes macros convertissent la donnée in situ quand elles sont suffixées pas un s et la donnée
pointée quand elles sont suffixées par un p.
FORMATION
LINUX
Export de symboles entre drivers
191
#include <linux/module.h>
#include "export_symbole.h »
static int __init chargement (void)
{
return 0;
}
static void __exit dechargement (void)
{
return 0;
}
void fonction_hello(int numero)
{
printk (KERN_INFO "Hello, le numero est %dn",
numero);
}
EXPORT_SYMBOL(fonction_hello);
MODULE_LICENSE("GPL");
module_init(chargement);
module_exit(dechargement);
 Listing d’un module avec export de symbole : :
#ifndef EXPORT_SYMBOLE_H
#define EXPORT_SYMBOLE_H
void fonction_hello(int numero);
#endif
 Header associé : :
#include <linux/module.h>
#include "export_symbole.h"
static int __init chargement (void)
{
fonction_hello(10);
return 0;
}
static void __exit dechargement (void)
{
fonction_hello(20);
}
module_init(chargement);
module_exit(dechargement);
MODULE_LICENSE("GPL");
 Listing d’un module avec import de symbole : :
 Pour vérifier la liste des symboles :
cat /proc/kallsyms
FORMATION
LINUX
PILOTE DE CARACTERES
BUT : apprendre à développer un pilote de caractères.
 Définition d’un pilote de caractères
 Exemple d’usage
FORMATION
LINUX
Les pilotes de caractères
193
 S'apparentent à des fichiers classiques :
 Lectures et écritures séquentielles
 Temps d'accès pouvant varier selon la position de la donnée (ex: bandes)
 Transferts de données de tailles arbitraires
 Exemples: cartes graphiques, bandes, imprimantes..
 La déclaration et la libération d'un pilote en mode caractère se font par les fonctions (<linux/fs.h>) :
int register_chrdev(unsigned int major, const char *name, struct file_operations *fops);
int unregister_chrdev(unsigned int major, const char *name);
 Possibilité d'allocation dynamique du majeur en mettant major à 0
 Les périphériques et leurs nombres majeurs sont listés dans /proc/devices
FORMATION
LINUX
Les pilotes de caractères
194
 La structure file_operations (fops) contient des pointeurs sur les fonctions implémentant le
fonctionnement du pilote: open(), read(), write(), etc :
struct file_operations mondriver_fops=
{
.owner = THIS_MODULE,
.read = mafonction_read,
.write = mafonction_write,
.ioctl = mafonction_ioctl,
.open = mafonction_open,
.release = mafonction_release,
};
 open()/release() :
 Appelées à l'ouverture/fermeture du fichier spécial
 Ces méthodes peuvent ne pas être déclarées mais le driver ne sera pas averti lors de ces
évènements (déconseillé).
 Prototypes (<linux/fs.h>) :
• int open(struct inode *inode, struct file *file);
• int release(struct inode *inode, struct file *file);
Méthode d’initialisation d’une structure
en nommant les champs.
FORMATION
LINUX
Les pilotes de caractères
195
 read()/write() :
 Utilisées pour lire/écrire des données sur le périphérique
 Méthodes les plus couramment implémentées
 Prototypes (<linux/fs.h>):
• ssize_t read(struct file *file, char *buffer, size_t size, loff_t *offset);
Si la valeur de retour est égale à zéro, cela signifie la fin du fichier.
Toutes les valeurs entre 1 et size sont correctes
Size correspond à la taille maximum à lire.
Buffer : adresse dans l’espace utilisateur
• ssize_t write(struct file *file, const char *buffer, size_t size, loff_t *offset);
Ne peut pas retourner 0.
 ioctl() :
 Généralement utilisée pour contrôler le périphérique
 La plus complète de toutes les méthodes
 On peut implémenter toutes les fonctionnalités d'un driver avec des commandes ioctl()
 Prototype (<linux/fs.h>) :
• int ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
FORMATION
LINUX
Les pilotes de caractères
196
 Autres méthodes utiles :
 llseek() : modifie la position courante de lecture/écriture
 poll() : base pour l'implémentation des appels système select() et poll()
Select : un kthread regarde un ou plusieurs file descriteur en même temps
 mmap() : projette une partie de la mémoire noyau dans l'espace mémoire du processus utilisateur
évitant les recopies entre l’espace utilisateur et l’espace noyau.
 Améliorations dans le noyau 2.6 :
 Modifications pour permettre de gérer l'espace de nommage sur 32 bits
 Possibilité de réserver une plage de couples major / minor
 Découplage entre la gestion de la plage major / minor et le périphérique en mode caractère
FORMATION
LINUX
Les pilotes de caractères
197
 Prototypes (<linux/fs.h>) :
 int register_chrdev_region(dev_t from, unsigned count, char *name);
 int unregister_chrdev_region(dev_t from, unsigned count);
 int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, char *name);
 struct cdev * cdev_alloc(void);
 void cdev_init(struct cdev *cdev, struct file_operations *fops);
 int cdev_add(struct cdev *p, dev_t dev, unsigned count);
 void cdev_del(struct cdev *p);
 void cdev_put(struct cdev *p);
FORMATION
LINUX
Les pilotes de caractères : fichiers spéciaux
198
 Manipulation des fichiers spéciaux
Le fichier /dev/urandom est un fichier spécial représentant un périphérique virtuel en mode caractère, de
numéros majeur 1 et mineur 9. Lorsqu'on lit ce fichier, le noyau nous renvoie des octets aléatoirement
choisis entre 0 et 255.
 Les deux commandes suivantes sont équivalentes :
$ hexdump /dev/urandom
et
$ mknod /dev/alea c 1 9
$ hexdump /dev/alea
1 = /dev/mem Physical memory access
2 = /dev/kmem Kernel virtual memory access
3 = /dev/null Null device
4 = /dev/port I/O port access
5 = /dev/zero Null byte source
6 = /dev/core OBSOLETE - replaced by
/proc/kcore
7 = /dev/full Returns ENOSPC on write
8 = /dev/random Nondeterministic random number gen.
9 = /dev/urandom Faster, less secure random number gen.
10 = /dev/aio Asynchronous I/O notification
interface
11 = /dev/kmsg Writes to this come out as printk's
12 = /dev/oldmem Used by crashdump kernels to access
the memory of the kernel
that crashed.
(….)
 Extrait de la liste des mineurs : :
FORMATION
LINUX
Les pilotes de caractères
 Communication grâce à un flux séquentiel de caractères individuels
 Les pilotes caractère peuvent être identifiés par leur type c (ls –l /dev/) :
 Exemples :
 Méthode pour développer un driver de caractères :
 Définir vos opérations sur fichier (fops)
 Définir votre fonction d'init. du module et appeler register_chrdev():
• Donner un numéro majeur, ou 0 (automatique)
• Donner vos fops
 Définir la fonction de sortie du module, et y appeler la fonction unregister_chrdev()
 Charger le module
 Trouver le numéro majeur (si nécessaire) et créer l'entrée dans /dev/

http://pficheux.free.fr/articles/lmf/drivers/

http://broux.developpez.com/articles/c/driver-c-linux/

http://ftp.traduc.org/doc-vf/gazette-linux/html/2006/122/lg122-D.ht
ml
199
crw-rw---- 1 root uucp 4, 64 Feb 23 2004 /dev/ttyS0
crw--w---- 1 jdoe tty 136, 1 Sep 13 06:51 /dev/pts/1
crw------- 1 root root 13, 32 Feb 23 2004 /dev/input/mouse0
crw-rw-rw- 1 root root 1, 3 Feb 23 2004 /dev/null

bluetoot
h

console
s,
 clavier
 souris
 port parallèle
 irDA
 terminaux
 etc …
FORMATION
LINUX
Les pilotes de caractères : implémentation
200
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
#include <asm/semaphore.h>
static char * nom_module = "file_msg";
static dev_t dev_file_msg = MKDEV(0, 0);
static int numero = 0;
module_param(numero, int, 0644);
static struct cdev cdev_file_msg;
static int read_msg (struct file * filp, char * buffer,
size_t length, loff_t * offset);
static int write_msg (struct file * filp, const char * buffer,
size_t length, loff_t * offset);
static struct file_operations fops_file_msg =
{
.owner = THIS_MODULE,
.read = read_msg,
.write = write_msg,
};
Nom de la file de messages
Paramètre pouvant être passé
au module lors de son
chargement.
Structure du device
Prototypes des fonctions
de lecture et d’écriture.
Enregistrement des
fonctions
 Implémentation pas à pas d’un driver de caractères gérant une file de messages :
FORMATION
LINUX
Les pilotes de caractères :
implémentation
201
static int __init chargement (void)
{
int erreur;
if (numero == 0) {
erreur = alloc_chrdev_region(&
dev_file_msg, 0, 1,
nom_module);
} else {
dev_file_msg = MKDEV(numero, 0);
erreur =
register_chrdev_region(dev_file_msg, 1,
nom_module);
}
if (erreur < 0)
return erreur;
cdev_init(& cdev_file_msg, & fops_file_msg);
erreur = cdev_add(& cdev_file_msg, dev_file_msg, 1);
if (erreur != 0)
goto out_unregister;
erreur = -ENOMEM;
cache_message = kmem_cache_create(nom_module,
sizeof(message_t), 0, 0, NULL, NULL);
if (cache_message == NULL)
goto out_cdev_del;
return 0;
out_cdev_del:
cdev_del(& cdev_file_msg);
out_unregister:
unregister_chrdev_region(dev_file_msg, 1);
 Chargement du module : :
Création d’un cache pour la file
de messages
Initialisation et ajout du driver
Enregistrement du major/minor
en auto si pas passé en
paramètre.
FORMATION
LINUX
Les pilotes de caractères :
implémentation
202
static void __exit dechargement (void)
{
message_t * suivant;
while (premier_message != NULL) {
suivant = premier_message-
>suivant;
kmem_cache_free(cache_message,
premier_message);
premier_message = suivant;
}
kmem_cache_destroy(cache_message);
cache_message = NULL;
cdev_del(& cdev_file_msg);
unregister_chrdev_region(dev_file_msg, 1);
}
Libération de la file de messages
Libération du driver
#define LG_MESSAGE_MAX 64
typedef struct s_message {
char contenu [LG_MESSAGE_MAX];
struct s_message * suivant;
} message_t;
struct kmem_cache * cache_message = NULL;
message_t * premier_message = NULL;
DECLARE_MUTEX(mtx_premier_message);
 Déchargement du module : :
 Données globales au driver : :
module_init(chargement);
module_exit(dechargement);
MODULE_LICENSE("GPL");
 Autres déclarations globales :
FORMATION
LINUX
Les pilotes de caractères :
implémentation
203
static int read_msg(struct file * filp, char * buffer, size_t length, loff_t * offset)
{
int retour;
int longueur;
message_t * suivant;
if (down_interruptible(& mtx_premier_message) != 0)
return -ERESTARTSYS;
retour = 0; /* 0 (=EOF), ou -EAGAIN */
if (premier_message == NULL)
goto out_up_mtx;
longueur = strlen(premier_message->contenu) + 1;
retour = -EINVAL;
if (length < longueur)
goto out_up_mtx;
retour = -EFAULT;
if (copy_to_user(buffer, premier_message->contenu, longueur) != 0)
goto out_up_mtx;
retour = longueur;
suivant = premier_message->suivant;
kmem_cache_free(cache_message, premier_message);
premier_message = suivant;
( … )
out_up_mtx:
up(&
mtx_premier_message);
return retour;
}
 Fonction de lecture : :
FORMATION
LINUX
Les pilotes de caractères :
implémentation
204
static int write_msg(struct file * filp, const char * buffer, size_t length, loff_t * offset)
{
int retour;
message_t * nouveau;
message_t * precedent;
if (down_interruptible(& mtx_premier_message) != 0)
return -ERESTARTSYS;
retour = -EINVAL;
if (length >= LG_MESSAGE_MAX)
goto out_up_mtx;
retour = -ENOMEM;
nouveau = kmem_cache_alloc(cache_message, 0);
if (nouveau == NULL)
goto out_up_mtx;
retour = -EFAULT;
if (copy_from_user(nouveau->contenu, buffer, length) != 0) {
kmem_cache_free(cache_message, nouveau);
goto out_up_mtx;
}
nouveau->contenu[length] = '0';
( … )
 Fonction d’écriture : :
nouveau->suivant = NULL;
if (premier_message == NULL)
premier_message = nouveau;
else {
for (precedent =
premier_message; precedent->suivant != NULL; precedent =
precedent->suivant)
;
precedent->suivant = nouveau;
}
retour = length;
out_up_mtx:
up(& mtx_premier_message);
return retour;
}
FORMATION
LINUX
PILOTE DE BLOCS
BUT : apprendre à développer un pilote de blocs.
 Définition d’un pilote de blocs
 Exemple d’usage
FORMATION
LINUX
Les pilotes de blocs
 Accès par blocs de données de taille fixe. On peut accéder aux blocs dans n'importe quel ordre.
 Les pilotes blocs peuvent être identifiés par leur type b (ls –l /dev) :
 Exemples :
206
brw-rw---- 1 root disk 3, 1 Feb 23 2004 /dev/hda1
brw-rw---- 1 jdoe floppy 2, 0 Feb 23 2004 fd0
brw-rw---- 1 root disk 7, 0 Feb 23 2004 loop0
brw-rw---- 1 root disk 1, 1 Feb 23 2004 ram1
brw------- 1 root root 8, 1 Feb 23 2004 sda1
(…)
 disques durs
 disques
mémoire
 périphériques de loopback (image de systèmes de fichiers)
 etc …
RAM disk
0 = /dev/ram0 First RAM disk
1 = /dev/ram1 Second RAM disk
...
250 = /dev/initrd Initial RAM disk.
 Extrait de la liste des minors utilisable pour des drivers de blocs :
$ ls /sys/block/
dm-0 dm-2 loop0 loop2 ram0 ram2 ram4 ram6 sda
dm-1 dm-3 loop1 loop3 ram1 ram3 ram5 ram7
 Liste des blocks initialisés :
FORMATION
LINUX
Les pilotes de blocs : architecture
globale
207
FORMATION
LINUX
Les pilotes de blocs : détail de la couche
blocs
208
FORMATION
LINUX
Les pilotes de blocs : détail de la couche
blocs
209
FORMATION
LINUX
Les pilotes de blocs : implémentation
210
 Détail sur l’implémentation d’un driver de bloc :
 Enregistrement du numéro majeur :
int register_blkdev(unsigned int major, const char *name);
Le numéro majeur peut être égal à zéro ; dans le cas, il est alloué automatiquement.
Une fois alloué, il doit apparaître dans /proc/devices
Au déchargement, le numéro majeur doit être libéré :
void unregister_blkdev(unsigned int major, const char *name);
Tous ces prototypes sont enregistrés dans le header suivant : <linux/fs.h>
 L'interface entre un pilote de périphériques et les applications se fait par un (ou plusieurs) fichiers
spéciaux (device nodes) :
 Le pilote définit ses points d'entrée grâce à une
structure file_operations (<linux/fs.h>)
 Les routines standards d'accès au système de
fichiers sont ainsi surchargées par les routines
du pilote
struct file_operations mondriver_fops={
.owner = THIS_MODULE,
.read = mondriver_read,
.write = mondriver_write,
.open = mondriver_open,
.release = mondriver_release,
};
FORMATION
LINUX
Les pilotes de blocs : les structures de
données
211
FORMATION
LINUX
Les pilotes de blocs : implémentation
212
#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/kernel.h> /* printk() */
#include <linux/slab.h> /* kmalloc() */
#include <linux/fs.h> /* everything... */
#include <linux/errno.h> /* error codes */
#include <linux/timer.h>
#include <linux/types.h> /* size_t */
#include <linux/fcntl.h> /* O_ACCMODE */
#include <linux/hdreg.h> /* HDIO_GETGEO */
#include <linux/kdev_t.h>
#include <linux/vmalloc.h>
#include <linux/genhd.h>
#include <linux/blkdev.h>
#include <linux/buffer_head.h> /* invalidate_bdev */
#include <linux/bio.h>
MODULE_LICENSE("Dual BSD/GPL");
static int sbull_major = 0;
module_param(sbull_major, int, 0);
static int hardsect_size = 512;
module_param(hardsect_size, int, 0);
static int nsectors = 1024; /* How big the drive is */
module_param(nsectors, int, 0);
static int ndevices = 4;
module_param(ndevices, int, 0);
/* Différents Modes utilisables. */
enum {
RM_SIMPLE = 0, /* The extra-simple
request function */
RM_FULL = 1, /* The full-blown version
*/
RM_NOQUEUE = 2, /* Use make_request */
};
static int request_mode = RM_SIMPLE;
module_param(request_mode, int, 0);
/* Nombre mineur et gestion des partition */
#define SBULL_MINORS 16
#define MINOR_SHIFT 4
#define DEVNUM(kdevnum)
(MINOR(kdev_t_to_nr(kdevnum)) >> MINOR_SHIFT
#define KERNEL_SECTOR_SIZE 512
/* Simulation du changement de media */
#define INVALIDATE_DELAY 30*HZ
/* Représention interne du device */
struct sbull_dev {
int size; /* Device size in sectors */
u8 *data; /* The data array */
short users; /* How many users */
short media_change; /* Flag a media change? */
spinlock_t lock; /* For mutual exclusion */
struct request_queue *queue; /* The device request queue */
struct gendisk *gd; /* The gendisk structure */
struct timer_list timer; /* For simulated media changes */
};
 Exemple de driver de disque :
FORMATION
LINUX
Les pilotes de blocs : implémentation
213
/*
* Ouverture et fermeture
*/
static int sbull_open(struct inode *inode, struct file *filp)
{
struct sbull_dev *dev = inode->i_bdev->bd_disk-
>private_data;
del_timer_sync(&dev->timer);
filp->private_data = dev;
spin_lock(&dev->lock);
if (! dev->users)
check_disk_change(inode->i_bdev);
dev->users++;
spin_unlock(&dev->lock);
return 0;
}
/*
* Structure des opérations disponible
*/
static struct block_device_operations sbull_ops = {
.owner = THIS_MODULE,
.open = sbull_open,
.release = sbull_release,
.media_changed =
sbull_media_changed,
.revalidate_disk = sbull_revalidate,
.ioctl = sbull_ioctl
};
FORMATION
LINUX
Les pilotes de blocs : implémentation
214
static int __init sbull_init(void)
{
int i;
/*
* Enregistrement.
*/
sbull_major = register_blkdev(sbull_major, "sbull");
if (sbull_major <= 0) {
printk(KERN_WARNING
"sbull: unable to get major numbern");
return -EBUSY;
}
/*
* Allocation du tableau et l’initialise
*/
Devices = kmalloc(ndevices*sizeof (struct sbull_dev),
GFP_KERNEL);
if (Devices == NULL)
goto out_unregister;
for (i = 0; i < ndevices; i++)
setup_device(Devices + i, i);
return 0;
out_unregister:
unregister_blkdev(sbull_major, "sbd");
return -ENOMEM;
}
static void sbull_exit(void)
{
int i;
for (i = 0; i < ndevices; i++) {
struct sbull_dev *dev = Devices +
i;
del_timer_sync(&dev->timer);
if (dev->gd) {
del_gendisk(dev-
>gd);
put_disk(dev->gd);
}
if (dev->queue) {
if (request_mode ==
RM_NOQUEUE)
blk_put_queue(dev->queue);
else
blk_cleanup_queue(dev->queue);
}
if (dev->data)
vfree(dev->data);
}
unregister_blkdev(sbull_major, "sbull");
kfree(Devices);
}
 Fonction de chargement :
 Fonction de chargement :
FORMATION
LINUX
DRIVERS RESEAUX
BUT : apprendre à développer des drivers réseaux.
 Architecture des drivers réseaux
 Découpage modulaire
 Découpage modulaire
 Circulation des paquets dans la pile réseau
 Netfilter et ses hooks
 Références
FORMATION
LINUX
DRIVERS RESEAUX : architecture
 Un driver réseau est la troisième catégorie
de drivers Linux après les drivers de blocs
et de caractères.
 Le fonctionnement d'une interface réseau au
sein du système est assez similaire à un driver
de blocs. Un driver de blocs est utilisé par le
noyau pour transmettre ou recevoir des blocs
de données. D'un point de vue similaire, un
driver réseau s'enregistre auprès du noyau de
Façon à pouvoir échanger des paquets de
données avec l'extérieur.
 Il y a cependant une différence avec un
driver de blocs qui consiste à ne pas avoir
de point d'entrée dans le répertoire dédié
aux devices /dev. Il n'est donc pas possible
de mettre en application la règle qui veut
que sous Unix / GNU Linux tout soit considéré
comme un fichier.
 La différence la plus importante entre ces
deux types de drivers est que le driver de blocs
n'est utilisé que lorsque le driver y fait appel
tandis qu'un drivers réseau reçoit les paquets
réseau de façon asynchrone depuis l'extérieur.
 Ainsi, alors qu'un driver de blocs demande
avant d'envoyer quelque chose au noyau,
le driver réseau demande à pusher des données. 
FORMATION
LINUX
DRIVERS RESEAUX : découpage
modulaire
 http://docs.huihoo.com/linux/kernel/a1/index.html
 L'architecture réseau permet au noyau
Linux de se connecter à d'autres système
via le réseau.
 Il existe un certain nombre important de
matériel ainsi qu'un nombre important de
protocole supportés .
 Chaque objet réseau est représenté via une
socket. Les sockets sont associées aux process
dans le même sens que les i-nodes d'un
système de fichiers peuvent être associées.
 Une socket peut être partagée par plusieurs
processus.
 L'architecture réseau utilise le scheduler de
process du noyau Linux schedule() pour
suspendre ou reprendre un process en état
d'attente de données (géré par un système de
gestion du contrôle et du flow de données).
 De plus, la couche VFS apporte un système
de fichiers logique (comme pour le cas de
NFS ;
il existe des possibilités en mode user via
libfuse)
FORMATION
LINUX
DRIVERS RESEAUX : liens
Interaction entre une carte réseau et le noyau :
 Toutes les cartes peuvent interagir avec le noyau de deux façon différentes :
 Polling : Le noyau vérifie le status du device à intervalle régulier de façon à vérifier s'il y a
quelque chose à faire ;
 Interruptions : La carte envoie un signal au noyau sous la forme d'une interruption pour lui
indiquer qu'il y a quelque chose à faire.
• Matériel : elle accepte les paquets entrant en provenance des interfaces réseaux et les
positionne directement en file d'entrée.
• Software (NET_RX_SOFTIRQ) : elle exécute le handle de paquets de réception. Elle est
responsable de la gestion des protocoles. Les paquets entrant sont gérés par cette
interruption et placés dans une file d'attente. Les paquets à forwarder sont placés dans la
file de sortie de l'interface de sortie.
FORMATION
LINUX
DRIVERS RESEAUX : les buffers sk
 Un paquet issu ou à destination du réseau n’est qu’une suite d’octets, un buffer, à émettre/recevoir.
 Il est associé dans le noyau Linux à une structure de contrôle de type sk_buff appelés sk_buffers (socket
buffer). A cette structure est attaché un bloc mémoire contenant le buffer reçu ou à émettre.
 Lorsqu’un paquet doit être émis ou est reçu par la carte réseau, un sk_buff est créé. Cette structure de
contrôle se compose notamment de :
 structures représentant les couches Ethernet, réseau et transport
 pointeurs pour la gestion du sk_buffer dans la liste des sk_buffers
 informations sur les périphériques (devices) d’entrée/sortie
 informations sur le type de paquet (broadcast, multicast, …)
 du buffer contenant le paquet à proprement parlé
 Des pointeurs *head, *data, *tail, et *end servent à la gestion du bloc mémoire associé au sk_buffer. head
et end pointent respectivement sur le début et la fin du bloc mémoire. Data pointe sur un en-tête du paquet
en fonction de l’endroit où le paquet se situe dans la pile de protocoles.
 Par exemple un paquet capturé à l’aide d’un hook netfilter aura son pointeur data positionné sur le premier
octet de l’en-tête IP. tail pointe sur le premier octet de bourrage du bloc mémoire (le bloc mémoire pouvant
être plus grand que le paquet à stocker).
FORMATION
LINUX
DRIVERS RESEAUX : les buffers sk
 Description d'un bloc mémoire associé à un sk_buffer, l'un vide et l'autre initialisé avec un bloc mémoire
initialisé avec un paquet :
 Il est possible de déplacer ces pointeurs pour, par exemple, positionner le pointeur data sur un en-tête
différent. Il faut cependant garder à l’esprit qu’en mode noyau aucun contrôle n’est effectué sur les accès
mémoire et qu’un plantage du noyau peut donc se produire du fait d’une manipulation hasardeuse de
pointeur.
 Les fonctions pour manipuler les sk_buffers sont définies dans le fichier header linux/skbuff.h.
FORMATION
LINUX
DRIVERS RESEAUX : les buffers sk
La structure du buffer_sk est géré via une liste doublement chaînée.
FORMATION
LINUX
DRIVERS RESEAUX : les buffers sk
struct sk_buff_head
{
/* These two members must be first. */
struct sk_buff * next;
struct sk_buff * prev;
_ _u32 qlen;
spinlock_t lock;
};
Structure
de
données

Init.

FORMATION
LINUX
DRIVERS RESEAUX
 La pile TCP/IP est directement implémentée dans le noyau.
 Les trames émises et reçues peuvent être amenées à traverser l’ensemble des couches (matérielles et
logicielles) :
Emission
Réception
 Représentation des trames dans le Kernel Space les paquets sont manipulés par le noyau dans des
structures de type sk_buffer (évite la recopie des données).
 Le parcours d’une trame reçue ou à émettre, le traitement dans la pile IP peut être découpé en phases.
FORMATION
LINUX
DRIVERS RESEAUX : circulation des paquets
 Le traitement IP comporte 4 grandes phases :
 La réception de trame : point d’entrée dans
la couche IP pour les trames reçues sur les
interfaces réseau.
 Le routage : choix de la route à suivre par le
paquet (réémission sur une autre interface
réseau ou destination locale)
 Le forwarding : contrôle du TTL et du
MTU avant de passer à la phase de
réémission.
 L’émission : les paquets à émettre ou à
réémettre passent par cette étape. Juste
avant de quitter la couche IP l’en-tête
Ethernet est complété.
FORMATION
LINUX
DRIVERS RESEAUX : circulation des paquets
Couche transport
OSI #4
Couche réseau
OSI #3
Couche liaison
OSI #2
Couche physique
OSI #1
 Cheminement des paquets
dans les différentes couches
de la stack réseau du kernel
GNU Linux 
 Une carte réseau utilise 2
listes permettant de gérer les
paquets entrants (rx_ring) et
les paquets sortants (tx_ring)
de la ou des interfaces
réseaux.
 On peut ainsi distinguer la
procédure d’émission de la
procédure de réception.
 Pour les noyaux 2.2 et
inférieurs, le traitement des
trames est différent (ex : on
ne retrouve pas les files tx et
rx).
FORMATION
LINUX
DRIVERS RESEAUX : le cas d’arp
 A l ‘émission, seuls les paquets de type ETH_P_ALL
peuvent être capturés.
 Il est important de noter que, comme pour le chemin
suivi par les trames dans le noyau, les fonctions utilisées dans le packet handling peuvent changer
selon la version du noyau utilisé.
 Pour récupérer les trames ARP, il suffit d’enregistrer
une structure packet_type dans une des listes
ptype (ptype_base ou ptype_all) avec la fonction de
callback dev_add_pack() (définie dans
linux/netdevice.h).
 Comme pour les netfilter hooks, il faut supprimer ce
hook (packet handling) lorsque le module est retiré
du noyau. Ceci se fait grâce à la fonction
dev_remove_pack() (linux/netdevice.h).
 En enregistrant une fonction pour ETH_P_ALL notre
packet type se retrouvera dans la liste ptype_all.
 On va ainsi récupérer toutes les trames arrivant
(ou à destination) du driver de la carte réseau.
Lorsque l’on récupère un sk_buffer avec ce type de hook, c’est en fait une copie du sk_buffer capturé sur
laquelle on va travailler. La copie doit être détruite en fin de fonction avec la fonction kfree_skb().
Ce type de hook n’est donc pas destiné à modifier le paquet capturé.
Position des hooks de type « packet handling » dans la chaîne
de traitement des trames reçues ou à émettre.
FORMATION
LINUX
DRIVERS RESEAUX : buffer sk
 Allocation :
FORMATION
LINUX
DRIVERS RESEAUX : buffer sk
FORMATION
LINUX
DRIVERS RESEAUX : netfilter
Patrick McHardy
:
Team Leader du
projet
Netfilter .
The core Team du projet Netfilter.
FORMATION
LINUX
DRIVERS RESEAUX : netfilter
 L'intégration de netfilter, le firewall de Linux, se fait au travers de hook, de la façon suivante.
 Les différents passages de fonctions s'effectuent via l'appel de NF_HOOK, une constante préprocesseur,
avec les paramètres suivants :
 protocole du HOOK, exemple : PF_INET pour IPv4 ;
 chaîne, exemple : NF_IP_PRE_ROUTING, NF_IP_LOCAL_IN, etc ;
 pointeur vers une structure struct sk_buff, qui contient en fait des données relative au paquet ;
 interface d'entrée ;
 interface de sortie (peut être NULL) ;
 la fonction à appeler si le paquet n'est pas supprimé.
 Ainsi, si CONFIG_NETFILTER, n'est pas définie, la constante NF_HOOK est définie à :
#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb)
se résumant à un simple appel de la fonction okfn, avec le paramètre skb.
[1]
on peut traduire hook par crochet, ou bien encore
intercepteur
FORMATION
LINUX
DRIVERS RESEAUX : netfilter
 Un hook peut se définir comme un
point d’accès dans une chaîne de
traitement (par exemple : saisie au
clavier, parcours de la pile TCP/IP…).
 Netfilter est un ensemble de hooks à
l’intérieur du noyau Linux
permettant aux modules noyau
d’enregistrer des fonctions de
callback dans la pile IP.
 Les trames ainsi capturées peuvent
être analysées, jetées ou modifiées.
 Le firewall « natif » de linux iptables
n’est qu’un module « sur-couche » de
netfilter permettant de définir un
système de règles de filtrage et
masquerading (translation d’adresse) de
trames IP à partir des hooks.
FORMATION
LINUX
DRIVERS RESEAUX : hook netfilter
 Ecriture d'un driver gérant un hook netfilter :
/* Fonction standard de chargement d'un driver sous GNU linux */
int init_module()
{
nfho_tunnel_in.hook = hook_func_tunnel_in;
nfho_tunnel_in.hooknum = NF_IP_PRE_ROUTING;
nfho_tunnel_in.pf = PF_INET;
nfho_tunnel_in.priority = NF_IP_PRI_FIRST;
nf_register_hook(&nfho_tunnel_in);
printk("ntNF_HOOK: Module instalenn");
return 0;
}
/* Fonction standard de déchargement d'un driver
sous GNU Linux */
void cleanup_module()
{
printk("nt NF_HOOK: I'll be back ....nn");
nf_unregister_hook(&nfho_tunnel_in);
}
FORMATION
LINUX
DRIVERS RESEAUX : hook netfilter
unsigned int hook_func_tunnel_in (unsigned int hooknum,
struct sk_buff **skb,
const struct net_device *in,
const struct net_
device *out,
int (*okfn)(struct sk_buff *))
{
struct sk_buff* sb= *skb;
struct iphdr* ip;
struct net_device *dev= NULL;
struct Qdisc *q;
int len;
len = sb->len;
ip = sb->nh.iph;
if((strcmp("eth0", in->name)==0) && (ip->daddr == ip1) )
{
affic_skb(sb,0);
sb->data -= 14;
sb->len = len+ 14;
memcpy(sb->data, hd_mac2, 14);
dev = dev_get_by_name("eth1");
spin_lock_bh (&(dev->queue_lock));
q = dev->qdisc;
q->enqueue(sb,q);
qdisc_run(dev);
spin_unlock_bh(&(dev->queue_lock));
affic_skb(sb,1);
return( NF_STOLEN );
}
(SUITE)
if((strcmp("eth1", in->name)==0) &&(ip->daddr ==
ip0))
{
affic_skb(sb,0);
sb->data -= 14;
sb->len = len+14 ;
memcpy(sb->data,hd_mac1, 14);
dev = dev_get_by_name("eth0");
spin_lock_bh (&(dev->queue_lock));
q = dev->qdisc;
q->enqueue(sb,q);
qdisc_run(dev);
spin_unlock_bh(&(dev-
>queue_lock));
return NF_STOLEN;
}
return( NF_ACCEPT );
}
Exemple d'implémentation de la fonction de hook utilisée dans le driver réseau.
FORMATION
LINUX
DRIVERS RESEAUX : références
 «Essential Linux Device Drivers», chapter 15
 «Linux Device Drivers», chapter 17
 Documentation/networking/netdevices.txt
 Documentation/networking/phy.txt
 include/linux/netdevice.h, include/linux/ethtool.h
 include/linux/phy.h, include/linux/sk_buff.h
 drivers/net/ avec plusieurs implémentation de drivers réseaux
 Autres modèle de drivers :
 drivers/usb/usb-skeleton.c
 drivers/net/isa-skeleton.c
 drivers/net/pci-skeleton.c
 drivers/pci/hotplug/pcihp_skeleton.c
FORMATION
LINUX
DRIVERS PCI
BUT : apprendre à développer des drivers PCI.
 Les différents standards PCI
 Structure d’un drivers PCI
 La commande lspci
 Structure dans /sys
 Enregistrement des devices dans le noyau
FORMATION
LINUX
DRIVERS PCI : les standards
 PCI
32 bit bus, 33 or 66 MHz
 MiniPCI
Slots plus petits sur les ordinateurs portables
Smaller slot in laptops
 CardBus
Slot externe sur les ordinateurs portables
 PIX Extended (PCI-X)
Slot PCI plus large, 64 bits, peut néanmoins accepter une carte PCI standard.
 PCI Express (PCIe or PCI-E)
Générération courante de PCI. Bus série au lieu de parallèle.
 PCI Express Mini Card
Remplace miniPCI sur les portables récents
 Express Card
Remplace les cardbus sur les portables récents
Les standards existants :
FORMATION
LINUX
DRIVERS PCI
 Bus le plus répandu sur les architectures supportées par Linux, API simple
 Configuration dynamique des ressources à l'initialisation du noyau
 Gère les différentes versions et variantes du bus PCI (Hot-plug, CardBus...)
 Utilisation de l'outil lspci (lecture de /proc/bus/pci) et /proc/pci pour débogage et informations
 Le sous-système PCI repose sur un mécanisme de gestion dynamique des périphériques et de leurs
états
 Pour implémenter un driver PCI on définit une structure pci_driver qui pointe sur les routines de
contrôle du pilote
 Exemple :
struct pci_driver mon_pci_driver =
{
.name = "mondriver",
.id_table = mondriver_id_table,
.probe = mondriver_probe,
.remove = mondriver_remove
};
FORMATION
LINUX
DRIVERS PCI
 Les fonctions pci_{register,unregister}_driver() servent alors à ajouter/supprimer le pilote de la liste
des pilotes PCI.
 Le tableau mondriver_id_table décrit les périphériques PCI (identifiants standardisés) que supporte
le pilote.
 A chaque fois qu'un périphérique définit dans le tableau mondriver_id_table change d'état (détection,
suppression...), la fonction correspondante de la structure pci_driver est appelée: mondriver_probe(),
mondriver_remove()
 Exemple :
struct pci_device_id mondriver_id_table[] =
{
{0x10B7, 0x9200, PCI_ANY_ID,
PCI_ANY_ID, 0, 0, madata_1},
{0x1105, 0x8400, PCI_ANY_ID,
PCI_ANY_ID, 0, 0, madata_2},
{0,}
};
MODULE_DEVICE_TABLE(pci,
mondriver_id_table);
FORMATION
LINUX
DRIVERS PCI
 La fonction mondriver_probe() doit contenir tout le code nécessaire à l'initialisation d'un
périphérique (allocations privées, initialisations matérielles, réservation des ressources...)
 Au contraire, la fonction mondriver_remove() doit défaire tout ce qui a été fait à l'initialisation
(libération des données allouées et des ressources, désactivations matérielles...)
 Les fonctions d'initialisation et de libération du pilote ne s'occupent alors que des paramètres
globaux du pilote (pilote PCI, nombre majeur, ressources et données globales...)
 Les fonctions d'initialisation du pilote sont les suivantes :
 pci_{register,unregister}_driver() : enregistrement/désenregistrement du pilote PCI
 Prototypes (<linux/pci.h>) :
 int pci_register_driver(struct pci_driver *drv) ;
 void pci_unregister_driver(struct pci_driver *drv);
 int probe(struct pci_dev *dev, const struct pci_device_id *id);
 void remove(struct pci_dev *dev);
FORMATION
LINUX
DRIVERS PCI
 Un ensemble de fonctions utilitaires permet de manipuler les ressources et les en-têtes PCI :
 pci_{set,get}_drvdata() : attache/récupère une donnée privée (ex: pointeur sur structure privée) sur
le descripteur du périphérique
 pci_{enable,disable}_device() : active/désactive le périphérique au niveau matériel
 pci_{read,write}_config_{byte,word,dword}() : lit/écrit 8, 16 ou 32 bits dans les en-têtes PCI
 pci_find_capability() : détermine si le périphérique supporte une fonctionnalité PCI donnée (ex:
PCI_CAP_ID_PM)
 pci_{request,release}_regions() : réserve/libère automatiquement tous les ports et plages mémoire
d'E/S du périphérique
 pci_resource_{start,end,len,flags}() : retourne l'adresse de début/fin, la longueur ou les
caractéristiques d'une ressource d'E/S (port ou mémoire).
FORMATION
LINUX
DRIVERS PCI
 Prototypes (<linux/pci.h>) :
 void * pci_get_drvdata(struct pci_dev *dev);
 void pci_set_drvdata(struct pci_dev *dev, void *data);
 int pci_enable_device(struct pci_dev *dev);
 void pci_disable_device(struct pci_dev *dev);
 int pci_read_config_{byte,word,dword}(struct pci_dev *dev, int addr, u{8,16,32} *val);
 int pci_write_config_{byte,word,dword}(struct pci_dev *dev, int addr, u{8,16,32} val);
 int pci_find_capability(struct pci_dev *dev, int capability);
 int pci_request_regions(struct pci_dev *dev, char *name);
 int pci_release_regions(struct pci_dev *dev);
 unsigned long pci_resource_{start,end,len,flags}(struct pci_dev *dev, int bar);
FORMATION
LINUX
DRIVERS PCI : lspci
FORMATION
LINUX
DRIVERS PCI : lspci
FORMATION
LINUX
DRIVERS PCI
 : Enregistrement des drivers supportés
FORMATION
LINUX
DRIVERS PCI
 Enregistrement d’un drivers PCI :
FORMATION
LINUX
DRIVERS PCI
FORMATION
LINUX
DRIVERS PCI
 Activation d’un driver PCI :
FORMATION
LINUX
DRIVERS PCI : lecture
FORMATION
LINUX
DRIVERS PCI : écriture
FORMATION
LINUX
DRIVERS USB
BUT : apprendre à développer des drivers USB.
 Architecture
 Standards
 Vue d’un device
 Implémentation d’un driver
FORMATION
LINUX
DRIVERS USB : architecture
Device USB
FORMATION
LINUX
DRIVERS USB : standard
OHCI - Open Host Controller Interface
Implémentation de HP/Compaq adopté comme standard pour l’USB 1.0 et 1.1
UHCI - Universal Host Controller Interface.
Crée par la société Intel
 USB : Universal Serial Bus
 Protocole Maître / Esclave
 Les deux interfaces HCD (Host Control Device):
EHCI - Extended Host Controller Interface : pour les débit plus élevés en USB 2.0
Low-Speed: up to 1.5 MbpsSince USB 1.0
Full-Speed: up to 12 MbpsSince USB 1.1
Hi-Speed: up to 480 MbpsSince USB 2.0
 Les débits :
FORMATION
LINUX
DRIVERS USB : standard
Topologie en arbre
FORMATION
LINUX
DRIVERS USB
Description d’un périphérique USB
FORMATION
LINUX
DRIVERS USB : standard
 Un périphérique USB est décrit par :
 device descriptor : unique, paramètres globaux du périphérique
 configuration descriptor : modifient le comportement global du périphérique (ex: mode
d'énergie), une seule configuration active à la fois
 interface descriptor : interfaces offertes par le périphérique, plusieurs interfaces peuvent
être actives simultanément (et être gérées par des pilotes Linux différents)
 alternate settings : modifient le comportement de l'interface
 endpoint descriptor : canaux de communication d'une interface (0 pour les transferts de
contrôle)
 Transferts :
 Control : paquets courts prédéfinis (GET_DESCRIPTOR, SET_DESCRIPTOR,
GET_CONFIGURATION, SET_CONFIGURATION, GET_INTERFACE,
SET_INTERFACE, etc)
 Bulk : paquets plus longs au débit max
 Interrupt : bulk répétitifs (1-127 ms)
 Isochronous : flux avec garantie de bande passante
FORMATION
LINUX
DRIVERS USB
 Les transferts se font par des USB Request Blocks
 Comportement asynchrone par callback
 Les transferts se font par DMA ou non suivant le périphérique et le contrôleur USB
 Structure d'un pilote USB (proche d'un pilote PCI) :
 déclaration du pilote (usb_register avec en paramètre une structure usb_driver décrivant
les callbacks du pilote)
 initialisation du périphérique, choix de la configuration, etc.
 couplage avec une interface de communication avec le mode utilisateur (pilote char, bloc,
réseau etc)
 pour la communication (dans read/write etc), allocation d'un URB, envoi de l'URB et
attente de complétion asynchrone
 Documentation :
 Documentation/usb/
 Documentation/DocBook
 Resources : www.linux-usb.org/
 Exemple de pilote :
 drivers/usb/usbskeleton.c
 drivers/usb/*
FORMATION
LINUX
DRIVERS USB : vue d’un device USB
FORMATION
LINUX
DRIVERS USB
Drivers
USB
FORMATION
LINUX
DRIVERS USB : enregistrement
FORMATION
LINUX
DRIVERS USB : libération
FORMATION
LINUX
DRIVERS TTY
BUT : comprendre l’architecture d’un driver TTY.
 Architecture d’un driver tty
FORMATION
LINUX
Pilote gestionnaire de tty
262
Exemple de pilote gérant un TTY
(terminal en mode caractère sous unix) :
TTY est l’abérévation de « TeleTYpe ».
FORMATION
LINUX
ENREGISTREMENT DANS /DEV
BUT : apprendre à enregistrer des drivers.
 Enregistrement manuel :
 Les fichiers de périphériques
 Enregistrement des périphériques
 Périphériques enregistrés
 Recherche de numéro majeur libre
 Enregistrement automatique :
 Hotplug
 Udev
FORMATION
LINUX
 Nombres majeurs et nombres mineurs :
 Comme vous pouvez le voir dans l'exemple précédent, les périphériques ont 2 numéros qui
leurs sont associés :
• Premier numéro: nombre majeur
Associé de manière unique à chaque pilote
• Second numéro: nombre mineur
Associé de manière unique à chaque
périphérique / entrée dans /dev
 Pour trouver quel pilote correspond à un périphérique, regardez Documentation/devices.txt
et <linux/major.h>
Les fichiers de périphériques (ou fichiers spéciaux / device node) ne sont pas forcément créés dans
/dev (par défaut par convention mais pas obligatoire) lorsqu'un pilote est chargé.
Ils doivent être créés par avance : mknod /dev/<device> [c|b] <major> <minor>
Exemples :
mknod /dev/ttyS0 c 4 64
mknod /dev/hda1 b 3 1
264
Les fichiers de périphériques
FORMATION
LINUX
Enregistrement des périphériques
 Tout d'abord il faut créer la ou les entrée(s) correspondante(s) dans /dev
 Initialisation du pilote : enregistrement avec un numéro majeur (c’est le noyau qui donne un numéro de
major en retour de la fonction register) ; c’est au drivers de gérer son numéro minor.
 Enregistrement (linux/fs.h) :
int register_chrdev(
unsigned it major,
const char *name,
struct file_operations *fops);
Si le paramètre major est égal à zéro, alors son enregistrement est automatique (appel à
alloc_chrdev_region).
 Libération du périphérique :
int unregister_chrdev(
unsigned it major,
const char *name);
 Si ces fonctions échouent, elles retournent une valeur strictement < 0.
265
FORMATION
LINUX
Périphériques enregistrés
 Les périphériques une fois enregistrés sont visibles dans /proc/devices avec leur numéro majeur et
leur nom :
Character devices:
1 mem
4 /dev/vc/0
4 tty
4 ttyS
5 /dev/tty
5 /dev/console
5 /dev/ptmx
6 lp
7 vcs
10 misc
13 input
14 sound
...
Block devices:
1 ramdisk
3 ide0
8 sd
9 md
22 ide1
65 sd
66 sd
67 sd
68 sd
69 sd
...
266
FORMATION
LINUX
Trouver un numéro majeur libre
 De moins en moins de numéros majeurs sont disponibles
 Il n'est pas recommandé d'en prendre un arbitrairement, car il peut rentrer en conflit avec un autre pilote
(standard ou spécifique)
 Solution: laisser register_chrdev en trouver un libre dynamiquement pour vous !
major = register_chrdev (0, "foo", &name_fops);
 Problème: vous ne pouvez pas créer d'entrées /dev par avance !
 Exemple de script de chargement de module (se sert de /proc/devices) :
module=foo; device=foo
insmod $module.ko
major=`awk "$2=="$module" {print $1}" /proc/devices`
mknod /dev/foo0 c $major 0
267
FORMATION
LINUX
Aperçu du hotplug
 Introduit dans le noyau Linux 2.4. USB a été le pionnier.
 Mécanismes noyau pour notifier les programmes de l'espace utilisateur qu'un périphérique a été
inséré ou enlevé.
 Des scripts dans l'espace utilisateur prennent ensuite soin d'identifier le matériel et
d'insérer/enlever les modules requis.
 Linux 2.6: l'identification des périphériques est simplifiée grâce à sysfs.
 Rend possible le chargement de micrologiciel (firmware).
 Permet d'avoir des pilotes en mode utilisateur (par exemple libsane).
 Configuration dans le noyau : CONFIG_HOTPLUG=y (section "General setup”)
Page du projet et documentation : http://linux-hotplug.sourceforge.net/
Liste de diffusion : http://lists.sourceforge.net/lists/listinfo/linux-hotplug-devel
268
FORMATION
LINUX
Architecture d'hotplug
269
FORMATION
LINUX
Exemple de flux hotplug
/sbin/hotplug usb
/sys mis à jour
Support
hotplug du noyau
Variables
d'environment
usb.agent
Identifie le périphérique
(Dé)charge les modules
correspondant ou le pilote
en mode utilisateur
Appelle / notifie
les autres programmes
ACTION=add|remove
DEVPATH=<sysfs_path>
SEQNUM=<num> ACTION=add|remove
DEVPATH=<sysfs_path>
KERNEL
UserSpace
270
FORMATION
LINUX
 Le fichier de configuration de udev (/etc/udev/udev.conf) :
 Facile à éditer et à configurer
 Répertoire des fichiers de périphériques (/udev)
 Base de données udev (/dev/.udev.tdb)
 Règles udev (/etc/udev/rules.d/)
Permissions udev (/etc/udev/permissions.d/)
 mode par défaut (0600), utilisateur par défaut (root) et groupe (root), si pas trouvés dans les
permissions de udev.
 Activation des traces (log) (yes)
Les messages de déboguage sont dans /var/log/messages
Tire partie à la fois de hotplug et de sysfs :
271
Caractéristiques de udev
 Entièrement dans l'espace utilisateur
 Créé automatiquement les entrées pour les périphériques (par défaut dans /udev)
 Appelé par /sbin/hotplug, utilise les informations de sysfs (notamment les nombres
Majeur/Mineur)
 Ne requiert aucun changement dans le code du pilote
 Petite taille
FORMATION
LINUX
Fichiers utilisés par hotplug
/lib/modules/*/modules.*map
sortie de depmod
/proc/sys/kernel/hotplug
specifie le chemin du programme
hotplug
/sbin/hotplug
programme hotplug (par défaut)
/etc/hotplug/*
fichiers hotplug
/etc/hotplug/NAME*
fichiers spécifiques aux sous-systèmes, pour les
agents
/etc/hotplug/NAME/DRIVER
scripts de configuration des pilotes, invoqués
par les agents
/etc/hotplug/usb/DRIVER.usermap
données pour depmod pour les pilotes en mode
utilisateur
/etc/hotplug/NAME.agent
Agents spécifiques à des sous-systèmes de
hotplug.
272
FORMATION
LINUX
Problèmes et limitations de
/dev
 Sur Red Hat 9, il y avait 18 000 entrées dans le répertoire /dev !!!
A l'installation du système, toutes les entrées possibles des périphériques doivent être créées.
 Besoin d'une autorité pour assigner les major numbers
http://lanana.org/: Linux Assigned Names and Numbers Authority
 Pas assez de nombres dans 2.4, la limite a été étendue dans 2.6
 L'espace utilisateur ne sait pas quels périphériques sont présents dans le système.
 L'espace utilisateur ne sait pas associer une entrée dans /dev avec le périphérique auquel elle se
rapporte
 Montre seulement les périphériques présents
 Mais utilise des noms différents à ceux de /dev, ce qui pose des problèmes dans les scripts.
 Mais aucune flexibilité dans le nom des devices (par rapport à /dev/) i.e. le 1er disque IDE s'appelle
soit /dev/hda, soit /dev/ide/hd/c0b0t0u0.
 Mais ne permet pas l'allocation dynamique des nombres majeur et mineur.
 Mais requiert de stocker la politique de nommage des périphériques dans la mémoire du noyau. Ne
peut pas être swappée!
La solution devfs et ses limitations :
273
FORMATION
LINUX
Boîte à outils de udev
 Composants principaux :
 udevsend (8KB dans FC 3)
Gère les événements de /sbin/hotplug, et les envoie à udevd
 udevd (12KB dans FC 3)
Réordonne les événements de hotplug, avant d'appeler les instance de udev pour chacun
d'eux.
 udev (68KB dans FC 3)
Créé ou efface les fichiers périphériques et ensuite exécute les programmes dans /etc/dev.d/
 Autres utilitaires :
 udevinfo (48KB dans FC 3)
Permet aux utilisateurs d'interroger la base de données de udev
 udevstart (fonctionnalité apportée par udev)
Rempli le répertoire initial des périphériques avec des entrées valides trouvées dans l'arbre de
périphériques de sysfs.
 udevtest <chemin_dev_sysfs> (64KB dans FC 3)
Simule une exécution de udev pour tester les règles configurées
274
FORMATION
LINUX
Exemple de configuration
# Si /sbin/scsi_id retourne "OEM 0815", le périphérique sera appelé disk1
BUS="scsi", PROGRAM="/sbin/scsi_id", RESULT="OEM 0815", NAME="disk1"
# Imprimante USB appelée lp_color
BUS="usb", SYSFS{serial}="W09090207101241330", NAME="lp_color"
# Un disque SCSI avec un numéro de vendeur/modèle spécifique devient boot
BUS="scsi", SYSFS{vendor}="IBM", SYSFS{model}="ST336", NAME="boot%n"
# La carte son avec l'id 00:0b.0 sur le bus PCI sera appelée dsp
BUS="pci", ID="00:0b.0", NAME="dsp"
# La souris USB sur le 3ème port du 2nd
hub sera appelée mouse1
BUS="usb", PLACE="2.3", NAME="mouse1"
# ttyUSB1 doit tjrs être appelé pda et avoir 2 autres liens symboliques
KERNEL="ttyUSB1", NAME="pda", SYMLINK="palmtop handheld"
# Webcams USB multiples avec des liens appelés webcam0, webcam1, ...
BUS="usb", SYSFS{model}="XV3", NAME="video%n", SYMLINK="webcam%n"
#name:user:group:mode
input/*:root:root:644
ttyUSB1:0:8:0660
video*:root:video:0660
dsp1:::0666
Fichier de permissions udev :
Fichier de règles pour udev :
275
FORMATION
LINUX
 Les point de montage dans /etc/dev.d/
 Après la création, destruction, renommage des noeuds de périphériques, udev peut appeler des
programmes dans l'ordre suivant de priorité:
 /etc/dev.d/$(DEVNAME)/*.dev
 /etc/dev.d/$(SUBSYSTEM)/*.dev
 /etc/dev.d/default/*.dev
Les programmes de chaque répertoire sont triés par ordre alphabétique.
Cela permet de notifier les applications utilisateurs de changements au niveau des périphériques.
• Sources : http://kernel.org/pub/linux/utils/kernel/hotplug/
• Liste de diffusion : linux-hotplug-devel@lists.sourceforge.net
• Présentation de udev de Greg Kroah-Hartman : ttp://www.kroah.com/linux/talks/oscon_2004_udev/
• Documentation udev de Greg Kroah-Hartman :http://www.kroah.com/linux/talks/ols_2003_udev_paper/Reprint-Kroah-Hartman-OLS2003.pdf
 Le nom des fichiers de périphériques peut être défini :
 depuis un label ou un numéro de série
 depuis un numéro de périphérique sur le bus
 depuis une position dans la topologie du bus
 depuis un nom du noyau
 udev peut aussi créé des liens symboliques vers d'autres fichiers périphériques
276
Capacités de nommage de
udev
FORMATION
LINUX
Schéma d'architecture de udev
/sbin/hotplug
/sys
mis à jour
Support
hotplug du noyau
udevsend udevd
Lecture fichiers de config
Associe périph. et règles
Créé / efface les devices
udev
Programmes
/etc/dev.d/
Programmes utilisateur
*
*
* envoie de paramètres par
variables d'environnement
*
*
*
277
FORMATION
LINUX
THREADS NOYAU
BUT : apprendre à utilise des threads dans le noyau.
 Définition des thread noyau
 Primitives des kthreads
 Exemple simple
FORMATION
LINUX
Threads noyau
 Contexte d'exécution semblable à un processus standard
 Mais un thread noyau n'a aucune ressource correspondant au mode utilisateur (mémoire, handlers
des signaux etc)
 Utilisés pour implémenter les daemons noyau, chargés de réaliser des tâches récurrentes (ex:
gestion du swap, vidange des caches, gestion du journal de ext3, etc.)
 Toute fonction d'API utilisable en contexte processus l'est en contexte kernel thread (sémaphores,
allocation GFP_KERNEL, etc)
 Création d'une kernel thread :
 par la fonction kernel_thread()
 après la création il faut emanciper la kernel thread (libération des ressources) : daemonize()
 Arrêt d'une kernel thread :
 – par la fonction kill_proc()
 – la kernel thread doit prendre en compte sa terminaison et sortir de sa fonction main()
 – souvent l'appelant doit attendre la fin effective de la kernel thread (appel depuis
module_exit()) : utilisation d'une variable de terminaison
279
FORMATION
LINUX
Threads noyau
 Initialisation d'une variable de terminaison (type struct completion) :
 Statique : DECLARE_COMPLETION()
 Runtime : init_completion()
 Fonctions de terminaison des threads noyau :
 wait_for_completion() : attend la terminaison effective du thread
 complete() : signale la terminaison du thread
 complete_and_exit() : signale la terminaison et termine le thread (atomiquement)
 Prototypes (<linux/sched.h>) :
 int kernel_thread(int (*kth)(void *), void *arg, unsigned long flags);
 void daemonize(void);
 int kill_proc(pid_t pid, int sig, int priv);
 Prototypes (<linux/completion.h>) :
 DECLARE_COMPLETION(name);
 void init_completion(struct completion *comp);
 void wait_for_completion(struct completion *comp);
 void complete(struct completion *comp);
 void complete_and_exit(struct completion *comp, long code);
280
FORMATION
LINUX
Threads noyau
 API simplifié à partir du 2.6.14 :
 kthread_run(): crée et lance une kernel thread
 kthread_stop(): envoie une demande de terminaison à une kernel thread et attend la
terminaison effective
 kthread_stop_sem(): même comportement que kthread_stop() + up()
 kthread_should_stop(): doit être appelée par la kernel thread régulièrement pour prendre en
compte les demandes de terminaison, et si la valeur est true, la kernel thread doit se finir.
 Prototypes (<linux/kthread.h>) :
 struct task_struct *kthread_run(int (*threadfn)(void *data), void *data, const char
namefmt[], ...);
 void kthread_bind(struct task_struct *k, unsigned int cpu);
 int kthread_stop(struct task_struct *k);
 int kthread_stop_sem(struct task_struct *k, struct semaphore *s);
 int kthread_should_stop(void);
281
;Verdana;Verdana
FORMATION
LINUX
THREADS NOYAU : résumé
 start_kthread :
Crée un kthread dans le noyau (équivalent de pthread_create). Peut être appelé depuis n'importe
quel contexte mais pas par une interruption.
 stop_kthread :
Arrète un kthread. Peut être appelée depuis n'importe quel contexte mais pas depuis le kthread lui-
même. La fonction est blocante.
 init_kthread :
Configure l'environnement pour un nouveau kthread. Cette fonction peut être appelée en dehors
d'un kthread.
 exit_kthread :
nécessite d'être appelé par thread lui-même à la fin de son exécution
http://kernelnewbies.org/Simple_UDP_Server

http://lemmestart.blogspot.com/2007/05/linux-kernel-threads-in-device-drivers_14.html

http://kernelnewbies.org/Simple_UDP_Server

http://www.freeos.com/articles/4051/

http://www.freesoftwaremagazine.com/articles/drivers_linux

http://www.scs.ch/~frey/linux/kernelthreads.html
282
FORMATION
LINUX
Threads noyau : exemple simple
 Exemple simple:
283
static struct task_struct *th;
static int thd(void *data)
{
do
{
...
} while (!kthread_should_stop());
return 0;
}
...
th = kthread_run(thd, NULL, "thd%d", 42);
...
kthread_stop(th);
FORMATION
LINUX
SYNCHRONISATION
BUT : apprendre les techniques de synchonisations.
 Présentation des méthodes de synchronisation
 Opérations atomiques
 Désactivation des interruptions
 Sémaphores
 Mutexes
 Verrous
FORMATION
LINUX
Synchronisation
285
 Le noyau 2.6 est préemptif (capacité d'un système d'exploitation multitâche à exécuter ou stopper une
tâche planifiée en cours en faveur d'une tâche de priorité supérieure).
 Mais même si on désactive la préemption (ou noyau 2.4) :
 un processus en mode noyau peut relâcher le CPU :
• volontairement (ex : schedule(), wait_event()...)
• involontairement (ex : kmalloc(), {get,put}_user()...)
 un processus en mode noyau peut être interrompu par un gestionnaire d'interruptions
 un autre processus peut se trouver en mode noyau au même moment mais sur un autre processeur.
 Pour toutes ces raisons, on doit protéger les données ou ressources partagées afin d'éviter les accès
concurrents.
 Plusieurs mécanismes, plus ou moins coûteux, existent dans le noyau pour résoudre ces problèmes :
 Opérations atomiques
 Désactivation des interruptions
 Sémaphores
 Verrous
 Verrous séquentiels (seqlocks) : utilisable au début et à la fin de l’écriture d’un buffer (compteur avec
vérification e cohérence).
FORMATION
LINUX
Opérations atomiques
286
 Opérations atomiques sur les bits :
 {set,clear,change,test}_bit();
 test_and_{set,clear,change}_bit().
 Prototypes (<asm/bitops.h>) :
 void {set,clear,change}_bit(int nr, volatile void *addr);
 int test_*(int nr, volatile void *addr)
 Opérations atomiques sur des entiers (type atomic_t) :
 atomic_{read,set,add,sub,inc,dec}()
 atomic_{inc,dec}_and_test()
 Prototypes (<asm/atomic.h>) :
 int atomic_read(atomic_t *v);
 void atomic_set(atomic_t *v, int i);
 void atomic_{add,sub}(int i, volatile atomic_t *v);
 void atomic_{inc,dec}(volatile atomic_t *v);
 int atomic_{inc,dec}_and_test(volatile atomic_t *v);
FORMATION
LINUX
Désactivations des interruptions
287
 Protection des ressources en concurrence avec des gestionnaires d'interruptions uniquement :
 local_irq_disable()/local_irq_enable() : désactive/active les interruptions sur le processeur courant
 local_{save,restore}_flags() : sauvegarde/restore les drapeaux d'interruptions (IF) sur le processeur
courant
 {disable,enable}_irq( ): désactive/active une seule ligne d'IRQ sur tous les processeurs et pour une
IRQ donnée.
 Les macros cli()/sti() (applicables à tous les processeurs), présentes en 2.2, ont été dépréciées en 2.4 et
enlevées en 2.6.
 Prototypes (<asm/system.h> et <asm/irq.h>) :
 void local_irq_{enable/disable}(void);
 void local_{save,restore}_flags (unsigned long old);
 void {enable,disable}_irq(unsigned int irq);
 Attention, ne pas utiliser de fonctions qui relâchent le CPU (appel à schedule()) dans une section non
interruptible par une IRQ car il y a un risque de blocage.
 La macro local_restore_flags() réactive l'état précédent, donc pas besoin de faire un appel à
local_irq_enable();
FORMATION
LINUX
Désactivations des interruptions
288
 Exemple (uniquement pour système mono-processeur) :
local_save_flags(old);
local_irq_disable();
/*
...
accès exclusif à la ressource partagée
...
*/
local_restore_flags(old);
FORMATION
LINUX
SEMAPHORES
289
 Mécanisme universel de synchronisation et de protection des ressources partagées
 Basé sur un compteur et deux primitives atomiques :
 P() : « Puis-je accéder à la ressource ? » - décrémente le compteur et endort le processus si le
compteur est inférieur à 0
 V() : « Vas-y ! » - incrémente le compteur et débloque le premier processus bloqué sur la ressource.
 Il existe des sémaphores pour différentes problématiques :
 exclusion mutuelle (mutex)
 cohabitation producteurs-consommateurs (semaphore)
 cohabitation lecteurs-écrivains (rwsem)
 Pour la cohabitation producteursconsommateurs, les consommateurs ne peuvent consommer que ce qui
a été produit (sémaphores à compte)
 Pour la cohabitation lecteurs-écrivains :
 plusieurs lecteurs peuvent lire la ressource simultanément
 un seul écrivain peut la modifier
FORMATION
LINUX
SEMAPHORES
290
 Les fonctions down()/up() implémentent les concepts P() et V(). Une analogie possible peut être faite
avec un passage à niveau : barrière levée pour UP et barrière baissée pour DOWN.
 La fonction down() endort le processus appelant si la ressource n'est pas disponible
 Les sémaphores ne sont donc pas utilisables dans un cas de concurrence avec un gestionnaire
d'interruptions
 Principalement utilisés pour gérer la concurrence dans le code noyau exécuté à la demande de processus
utilisateurs (appels système)
 Les variantes suivantes sont également utiles :
 down_trylock() : permet de ne pas endormir automatiquement le processus si la ressource n'est pas
accessible (utilisable dans les gestionnaires d'interruptions)
 down_interruptible() : endort le processus si la ressource n'est pas accessible mais peut être réveillé
par un signal.
 Initialisation d'un mutex ou d'un semaphore (type struct semaphore) :
 Statique : DECLARE_MUTEX{_LOCKED}()
ou __DECLARE_SEMAPHORE_GENERIC() : sémaphore à compteur
 Runtime : init_MUTEX{_LOCKED}() ou sema_init().
FORMATION
LINUX
SEMAPHORES
291
 Prototypes (<{linux,asm}/semaphore.h>) :
 DECLARE_MUTEX{_LOCKED}(name);
 __DECLARE_SEMAPHORE_GENERIC(name, val);
 void init_MUTEX{_LOCKED}(struct semaphore *sem);
 void sema_init(struct semaphore *sem, int val);
 void {down,up}(struct semaphore *sem);
 int down_*(struct semaphore *sem);
 Initialisation d'un rwsem (type struct rw_semaphore) :
 Statique : DECLARE_RWSEM()
 Runtime : init_rwsem()
 Prototypes (<{linux,asm}/rwsem.h>) :
 DECLARE_RWSEM(name);
 void init_rwsem(struct rw_semaphore *sem);
 void {down,up}_{read,write}(struct rw_semaphore *sem);
FORMATION
LINUX
SEMAPHORES
292
 Exemple d'exclusion mutuelle :
 Exemple de lecteurs écrivains :
static DECLARE_MUTEX(foo_sem);
down(&foo_sem);
/* ...accès exclusif à la ressource foo en lecture/écriture... */
up(&foo_sem);
static DECLARE_RW_SEM(bar_rwsem);
down_read(&bar_rwsem);
/* ...accès exclusif à la ressource bar enlecture uniquement... */
up_read(&bar_rwsem);
FORMATION
LINUX
SEMAPHORES
293
 Exemple d'exclusion mutuelle :
 Exemple de lecteurs écrivains :
C’est au développeur de respecter la lecture/écriture.
static DECLARE_MUTEX(foo_sem);
down(&foo_sem);
/* ...accès exclusif à la ressource foo en lecture/écriture... */
up(&foo_sem);
static DECLARE_RW_SEM(bar_rwsem);
down_read(&bar_rwsem);
/* ...accès exclusif à la ressource bar enlecture uniquement... */
up_read(&bar_rwsem);
FORMATION
LINUX
MUTEXES
294
 Introduits en 2.6.16
 Spécialisation des sémaphores, destiné à remplacer les DECLARE_MUTEX()
 Utilisables uniquement en contexte processus, une prise de mutex endort le processus appelant si le
mutex n'est pas disponible
 L'opération P() se fait par mutex_lock()
 L'opération V() se fait par mutex_unlock()
 Initialisation d'un mutex (type struct mutex) :
 statique: DEFINE_MUTEX()
 runtime: mutex_init()
 Prototypes (<{linux,asm}/mutex.h>) :
 DEFINE_MUTEX(name);
 void mutex_init(struct mutex *lock);
 void mutex_lock(struct mutex *lock);
 int mutex_lock_interruptible(struct mutex *lock);
 int mutex_trylock(struct mutex *lock);
 void mutex_unlock(struct mutex *lock);
 int mutex_is_locked(struct mutex *lock);
FORMATION
LINUX
VERROUS
295
 A utiliser pour les zones critiques utilisés par le systèmes et les handlers d’interruptions.
 Les verrous (locks) sont des mécanismes de synchronisation pour les sections critiques intra-noyau
 Basés sur des mécanismes d'attente active de la ressource :
 en SMP : boucle while(1) try_get_lock(); -> vérouille le scheduler en mode multiprocesseurs
 en UP préemptible (en mode mono-processeur) : désactivation de la préemption noyau
 en UP non préemptible (en mode mono-proceeseur) : rien
 Plus désactivation éventuelle des interruptions dans le cas de concurrence avec un gestionnaire
d'interruptions
 Il existe des verrous pour différentes problématiques :
 exclusion mutuelle (spinlocks)
 cohabitation lecteurs-écrivains (rwlocks)
 Pour la cohabitation lecteurs-écrivains :
 plusieurs lecteurs peuvent lire la ressource simultanément
 un seul écrivain peut la modifier
FORMATION
LINUX
VERROUS
296
 Les fonctions de manipulation des locks (types spinlock_t ou rwlock_t) sont les suivantes :
 spin_{lock,unlock}() : ouverture/fermeture d'un verrou d'exclusion mutuelle
 spin_trylock() : essai de fermeture d'un verrou d'exclusion mutuelle
 {read,write}_lock() : fermeture d'un verrou par un lecteur/écrivain
 {read,write}_unlock() : ouverture d'un verrou par un lecteur/écrivain
 Si on veut aussi protéger contre un accès par un gestionnaire d'interruptions, on utilise les fonctions
suffixés par :
 _irq : blocage/déblocage des interruptions avec les fonctions *_lock()/*_unlock()
Exemple: spin_lock_irq
 _irqsave : blocage des interruptions et sauvegarde du contexte avec les fonctions *_lock()
 _irqrestore : déblocage des interruptions et restauration du contexte avec les fonctions *_unlock()
 Initialisation d'un spinlock (type spinlock_t) :
 Statique : constante SPIN_LOCK_{UN}LOCKED
 Runtime : spin_lock_init()
 Initialisation d'un rwlock (type rwlock_t) :
 Statique : constante RW_LOCK_{UN}LOCKED
 Runtime : rw_lock_init()
;Verdana
FORMATION
LINUX
VERROUS
297
 Prototypes (<asm/spinlock.h>) :
 void {spin,rw}_lock_init({spin,rw}lock_t lock);
 void {spin,read,write}_{lock,unlock}{_irq}({spin,rw}lock_t lock);
 void {spin,read,write}_lock_irqsave({spin,rw}lock_t lock, unsigned long flags);
 void {spin,read,write}_unlock_irqrestore({spin, rw}lock_t lock, unsigned long flags);
 int spin_trylock(spinlock_t lock);
 Exemple de lecteurs-écrivains :
;Verdana
rwlock_t foo_rw_lock = RW_LOCK_UNLOCKED;
read_lock(&foo_rw_lock);
/* ...accès exclusif à la ressource foo en lecture uniquement... */
read_unlock(&foo_rw_lock);
[...]
write_lock(&foo_rw_lock);
/* ...accès exclusif à la ressource foo en lecture/écriture... */
write_unlock(&foo_rw_lock);
FORMATION
LINUX
VERROUS
298
 Exemple d'exclusion mutuelle:
;Verdana
spinlock_t bar_spin_lock = SPIN_LOCK_UNLOCKED;
spin_lock(&bar_spin_lock);
/* ...accès exclusif à la ressource bar en lecture/écriture... */
spin_unlock(&bar_spin_lock);
FORMATION
LINUX
TIMERS
BUT : apprendre à maîtriser l’usage des timers.
 La variable jiffies et jiffies_64
 La mesure du temps
 Exemple de timer noyau à 5 secondes
 Exemple d’utilisation d’un timer dans un module
FORMATION
LINUX
Mesure du temps
300
 La variable jiffies représente le nombre de ticks d'horloge depuis le démarrage de la machine
(<linux/param.h>, <linux/jiffies.h>)
 Le noyau 2.6 introduit jiffies_64 qui est composé de jiffies en poids faible (accès par get_jiffies_64()).
 HZ est le nombre de ticks d'horloge par seconde (100 sur plate-forme Intel/2.4, 1000 sur Intel/2.6 :
valeur définie lors de la compilation).
 Exemple d'attente coopérative de 2 secondes :
 La fonction schedule_timeout() permet de réaliser une attente coopérative plus efficace (en ayant pris
soin de changer le statut du processus courant avec la macro set_current_state()) ;
 Exemple d'attente coopérative de 2 secondes :
 Pour des délais plus courts et non coopératifs (ex : synchronisation avec le matériel) on préférera
udelay() ou mdelay() (ou ndelay() en 2.6)
unsigned long jiffies_fin = jiffies + 2*HZ;
while (time_before(jiffies, jiffies_fin))
schedule();
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(2 * HZ);
FORMATION
LINUX
TIMERS
301
 Prototypes (<linux/sched.h> et <linux/delay.h>) :
 u64 get_jiffies_64 (void);
 long schedule_timeout(long timeout);
 void set_current_state(int state);
 void ndelay(unsigned long nsecs);
 void udelay(unsigned long usecs);
 void mdelay(unsigned long msecs);
 Permettent d'exécuter une fonction donnée à une date (en jiffies) précise dans le futur (one-shot).
 Routines de contrôle :
 init_timer() : créer un nouveau timer
 timer.function=my_func;
 timer.data=my_arg ;
 mod_timer() : initialise (champ expires) et lance un timer
 add_timer() : lance un timer (peu utilisé)
 del_timer{_sync}() : destruction du timer avant son expiration.
 Prototypes (<linux/timer.h>) :
 void init_timer(struct timer_list *timer);
 void mod_timer(struct timer_list *timer, unsigned long expires);
 void add_timer(struct timer_list *timer);
 int del_timer{_sync}(struct timer_list *timer);
 int add_timer_on(struct timer_list *timer, int cpu); (2.6 uniquement)
FORMATION
LINUX
TIMERS : exemple
302
 Exemple de timer noyau à 5 secondes :
static struct timer_list mon_timer;
init_timer(&mon_timer);
mon_timer.function = ma_fonction;
mon_timer.data = mon_argument;
mod_timer(&mon_timer, jiffies + 5 * HZ);
FORMATION
LINUX
TIMERS : exemple d’usage dans un module
303
#include <linux/module.h>
static void fonction_periodique (unsigned long);
static struct timer_list timer;
static int __init chargement (void)
{
init_timer (& timer);
timer.function = fonction_periodique;
timer.data = 0; /* inutilise */
timer.expires = jiffies + HZ;
add_timer(& timer);
return 0;
}
static void __exit dechargement (void)
{
del_timer(& timer);
}
static void fonction_periodique(unsigned long inutile)
{
struct timeval time_of_day;
do_gettimeofday(& time_of_day);
printk(KERN_INFO "time_of_day: %ld.%06ldn",
time_of_day.tv_sec, time_of_day.tv_usec);
mod_timer(& timer, jiffies+HZ);
}
module_init(chargement);
module_exit(dechargement);
MODULE_LICENSE("GPL");
Déclaration
Initialisation et exécution
Fonction appelée par le timer
FORMATION
LINUX
QUEUE DE TRAVAIL (WORKQUEUE)
BUT : apprendre à tes techniques de queue de travail.
 Définition des queues de travail
 Deux exemples simples
 Exemple d’usage d’une queue de travail dans un
module
FORMATION
LINUX
QUEUE DE TRAVAIL
305
 Noyau 2.6 uniquement
 Prototypes légèrement modifiés en 2.6.20 (disparition de l'argument data)
 Autre façon de reporter certaines exécutions
 Permettent d'accumuler des tâches dans une queue puis de les lancer de manière séquentielle à un
moment choisi
 L'exécution se déroule dans le contexte d'un processus
 Possibilité d'utiliser une queue système ou bien définir sa propre queue
 Création d'une workqueue (type struct workqueue_struct) :
 create_workqueue()
 Création d'une tâche (type struct work_struct) :
 Statique : DECLARE_WORK()
 Runtime :
• INIT_WORK() : alloue et initialise une tâche
• PREPARE_WORK() : initialise une tâche
 Par la suite, si utilisation de la queue système :
 schedule_{delayed_}work(): ajoute une tâche
 flush_scheduled_work(): attend la fin de toutes les tâches
FORMATION
LINUX
QUEUE DE TRAVAIL
306
 Si queue autogéréé :
 queue_{delayed_}work(): ajoute une tâche
 cancel_delayed_work(): annule une tâche
 flush_workqueue(): attend la fin de toutes les tâches d'une queue
 destroy_workqueue(): détruit la queue
 Prototype (<linux/workqueue.h>) :
 struct workqueue_struct *create_workqueue(const char *name);
 DECLARE_WORK(name, void (*func)(void *), void *data);
 {PREPARE,INIT}_WORK(struct work_struct *work, void (*func)(void *), void *data);
 int schedule_work(struct work_struct *work);
 int schedule_delayed_work(struct work_struct *work, unsigned long delay);
 void flush_scheduled_work(void);
 int queue_work(struct workqueue_struct *wq, struct work_struct *work);
 int queue_delayed_work(struct workqueue_struct *wq, struct work_struct *work, unsigned long
delay);
 int cancel_delayed_work(struct work_struct *work);
 void flush_workqueue(struct workqueue_struct *wq);
 void destroy_workqueue(struct workqueue_struct *wq);
FORMATION
LINUX
QUEUE DE TRAVAIL : exemples simples
307
 Exemple :
 Exemple avec queue privée :
void handler(void *data) {
...
}
DECLARE_WORK(ma_tache, handler, NULL);
...
schedule_work(ma_tache);
...
flush_scheduled_work();
void handler(void *data) {
...
}
DECLARE_WORK(ma_tache, handler, NULL);
...
ma_queue = create_workqueue("ma_queue");
...
queue_work(ma_queue, ma_tache);
...
flush_workqueue(ma_queue);
destroy_workqueue(ma_queue);
FORMATION
LINUX
QUEUE DE TRAVAIL : exemple d’usage
308
#include <linux/interrupt.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/workqueue.h>
#include <asm/io.h>
static char * nom_module = "exemple_11";
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
static irqreturn_t irq_handler(int irq, void * ident, struct pt_regs *
unused);
#else
static irqreturn_t irq_handler(int irq, void * ident);
#endif
#ifndef IRQF_SHARED
#define IRQF_SHARED SA_SHIRQ
#endif
static void fonction_workqueue (struct work_struct * unused);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
static DECLARE_WORK(workqueue_exemple, (void (*)
(void *)) fonction_workqueue, NULL);
#else
static DECLARE_WORK(workqueue_exemple,
fonction_workqueue);
#endif
static int __init chargement (void)
{
int erreur;
if (request_region(0x378, 3, nom_module) ==
NULL)
return -EBUSY;
erreur = request_irq(7, irq_handler,
IRQF_SHARED, nom_module, nom_module);
if (erreur != 0) {
release_region(0x378, 3);
return erreur;
}
outb(0x10, 0x37A);
return 0;
}
FORMATION
LINUX
Workqueue : exemple d’usage
309
static void __exit dechargement (void)
{
outb(0, 0x37A);
free_irq(7, nom_module);
flush_scheduled_work();
release_region(0x378, 3);
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
static irqreturn_t irq_handler(int irq, void * ident, struct pt_regs *
unused)
#else
static irqreturn_t irq_handler(int irq, void * ident)
#endif
{
if ((inb(0x379) & 0x40) == 0)
return IRQ_NONE;
schedule_work(& workqueue_exemple);
return IRQ_HANDLED;
}
static void fonction_workqueue(struct work_struct * unused)
{
static int valeur = 0;
outb(valeur, 0x378);
valeur = 0xFF - valeur;
}
module_init(chargement);
module_exit(dechargement);
MODULE_LICENSE("GPL");
FORMATION
LINUX
LISTES CHAINEES
BUT : apprendre à utiliser les listes chaînées.
 Description des listes chaînées
 Exemple d’usage d’une liste chaînée
FORMATION
LINUX
Liste chaînée
 http://www.linuxgrill.com/anonymous/fire/netfilter/kernel-hacking-HOWTO-5.html 311
 Listes doublement chaînées et circulaires
 Très utilisées dans le noyau
 Mécanisme d'encapsulation pour créer ses propres listes
 Simplifie les manipulations (parcours, ajout / retrait d'un élément...)
 Ajout d'un champ de type struct list_head dans la structure des éléments à chaîner
 Initialisation d'une tête de liste (type struct list_head) :
 Statique : LIST_HEAD() et LIST_HEAD_INIT()
 Runtime : INIT_LIST_HEAD()
 Fonctions de manipulation de la liste et des éléments :
 list_add{_tail}() : ajoute un élément en tête/queue d'une liste
 list_del() : supprime un élément d'une liste
 list_entry() : donne accès à un élément d'une liste
 list_for_each() : parcours une liste élément par élément
 list_splice() : joint deux listes en une seule
FORMATION
LINUX
Liste chaînée
312
 Prototypes (<linux/list.h>) :
 LIST_HEAD{_INIT}(name);
 void INIT_LIST_HEAD(struct list_head *head);
 void list_add{_tail}(struct list_head *new, struct list_head *head);
 void list_del(struct list_head *entry);
 type *list_entry(struct list_head *entry, type, member);
 void list_for_each(struct list_head *current, struct list_head *head);
 void list_splice(struct list_head *list, struct list_head *head);
Note : les listes chainées du noyau peuvent aussi servir dans l’espace utilisateur :
 http://isis.poly.edu/kulesh/stuff/src/klist/
FORMATION
LINUX
Liste chaînée: exemple d’usage
313
 Définissons une première structure :
struct mystruct {
int data ;
} ;
 Création d’une seconde structure struct list_head field :
struct mystruct {
int data ;
struct list_head mylist ;
} ;
 Création d’un premier élément :
Usage de la macro : #define LIST_HEAD_INIT(name) { &(name), &(name) }
 et un second élément :
struct mystruct first ;
first.data = 10 ;
first.mylist = LIST_HEAD_INIT(first.mylist) ;
struct mystruct second ;
second.data = 20 ;
INIT_LIST_HEAD( & second.mylist ) ;
Macro utilisé :
static inline void INIT_LIST_HEAD(struct list_head *list)
{
list->next = list;
list->prev = list;
}
FORMATION
LINUX
Liste chaînée: exemple d’usage
 http://www.linuxgrill.com/anonymous/fire/netfilter/kernel-hacking-HOWTO-5.html 314
 Variable définissant la tête de la liste :
 Ajout de deux éléments :
 Itération des éléments :
LIST_HEAD(mylinkedlist) ;
list_add ( &first.mylist , &mylinkedlist ) ;
list_add ( &second.mylist , &mylinkedlist ) ;
list_for_each ( position , & mylinkedlist )
{
datastructureprt = list_entry ( position, struct mystruct
, mylist );
printk ("data = %dn" , datastructureptr->data );
}
struct mystruct *datastructureptr = NULL ;
list_for_each_entry ( datastructureptr , & mylinkedlist,
mylist )
{
printk ("data = %dn" , datastructureptr->data );
}
FORMATION
LINUX
MISE AU POINT
BUT : maitriser les techniques de debug
 Printk
 Ksymoops
 Kprobes
 KGDB
 Oprofile
 LTT / LTTng
FORMATION
LINUX
Déboguer avec printk
 Technique universelle de débogage facile à utiliser.
 Prototype : int printk (const char *fmt, ...);
 Affiché ou non dans la console ou /var/log/messages suivant la priorité :
$ dmesg (Tampon circulaire)
$ tail –f /var/log/messages (via le daemon syslogd, entrées kern.*)
 Priorités disponibles (include/linux/kernel.h):
#define KERN_EMERG "<0>" /* système inutilisable */
#define KERN_ALERT "<1>" /* une action doit être prise de suite */
#define KERN_CRIT "<2>" /* conditions critiques */
#define KERN_ERR "<3>" /* conditions d'erreur */
#define KERN_WARNING "<4>" /* conditions de warning */
#define KERN_NOTICE "<5>" /* condition normale mais significative */
#define KERN_INFO "<6>" /* information */
#define KERN_DEBUG "<7>" /* messages de débogage */
 La priorité la plus élevée étant 0. Quand aucun niveau est spécifié, le niveau par défaut
DEFAULT_MESSAGE_LOGLEVEL est utilisé (spécifié dans kernel/printk.c).
http://ltp.sourceforge.net/documentation/technical_papers/UsingCodeCoverage.pdf 316
FORMATION
LINUX
Déboguer avec printk
317
 Si le noyau est compiler avec l’option CONFIG_PRINTK_TIME=y, un temps au format
seconds.nanoseconds :
[337567.060046] Buffer I/O error on device sr0, logical block 0
 Les messages printk pouvant être important, il est possible de définir un seuil. Pour ce faire, les deux valeurs
suivantes (valeurs en secondes) :
 /proc/sys/kernel/printk_ratelimit
 /proc/sys/kernel/printk_ratelimit_burst
 Niveau de bug peut être modifié, en dynamique dans le noyau
 Cela défini une suite de 4 nombres avec la signification suivante :
 Niveau de log courant
 Niveau de log par défault (DEFAULT_MESSAGE_LOGLEVEL)
 Niveau de log minimum (MINIMUM_CONSOLE_LOGLEVEL)
 Niveau de bug pour la phase de boot
 echo 8 > /proc/sys/kernel/printk
 Les messages peut être lu de la façon suivante :
$ cat /proc/kmsg
<4> ACPI-0352: *** Error: Looking up [Z005] in namespace, AE_NOT_FOUND
<4>search_node c14d0440 start_node c14d0440 return_node 00000000
<4> ACPI-1138: *** Error: Method execution failed [_SB_.BAT1._BST] (Node c14d0340), AE_NOT_FOUND
 cat /proc/sys/kernel/printk
7 4 1 7
FORMATION
LINUX
ksymoops
 Pour aider à décrypter les messages «oops», en convertissant les adresses et le code en informations
utiles. Il utilise pour cela la table des symboles system.map.
 Facile à utiliser: copiez/collez juste le texte oops dans un fichier.
 Exemple d'une ligne de commande :
ksymoops --no-ksyms -m System.map -v vmlinux oops.txt
 Regardez Documentation/oops-tracing.txt et man ksymoops pour plus de détails.
 La table des symboles peut être consultée dans le pseudo-système de fichiers :
 /proc/ksyms (Linux 2.4)
 /proc/kallsyms (Linux 2.6)
 http://tldp.org/HOWTO/Module-HOWTO/index.html
318
$ grep loops_per_jiffy /proc/kallsyms
ffffffff815968e0 r __ksymtab_loops_per_jiffy
ffffffff815aa295 r __kstrtab_loops_per_jiffy
ffffffff815f0420 D loops_per_jiffy
$ grep cdev_map /proc/kallsyms (even the static symbols)
ffffffff818c25e8 b cdev_map
FORMATION
LINUX
Déboguer avec Kprobes d'IBM
 Moyen simple d'insérer des points d'arrêt dans les routines du noyau
 Contrairement au débogage avec printk, vous n'avez pas besoin de recompiler ni de redémarrer votre
noyau. Vous avez juste besoin de compiler et charger un module dédié pour déclarer l'adresse de la
routine que vous voulez tester.
 Non disruptif, basé sur le gestionnaire d'interruption du noyau
 Kprobes permet même de modifier des registres et des structures de données globales.
319
 Voir http://www-106.ibm.com/developerworks/library/l-kprobes.html pour une présentation plus complète
FORMATION
LINUX
Astuce de débogage du noyau
 Si votre noyau ne démarre pas encore, il est recommandé d'activer le «Low Level debugging»
(dans la section «Kernel Hacking» des options du noyau, valable uniquement sur ARM)
CONFIG_DEBUG_LL=y
 Les codes d'erreur de Linux
Essayez de reporter les erreurs avec des numéros aussi précis que possible ! Heureusement,
les noms de macros sont explicites et vous pouvez vous en rappeler rapidement.
 Codes d'erreur génériques:
include/asm-generic/errno-base.h
 Codes d'erreur spécifiques à une plate-forme:
include/asm/errno.h
320
FORMATION
LINUX
Oprofile
321
1. Compiler et installer. Utiliser l’option --with-linux pour pointer indiquer le chemin vers les sources
du noyau linux.to point (autre option possible --with-kernel-support for 2.6 kernels.
2. Compiler le noyau linux avec les options : CONFIG_PROFILING=y et CONFIG_OPROFILE=y
3. Démarrer le profiler :
opcontrol –init
opcontrol --setup --ctr0-event=CPU_CLK_UNHALTED --ctr0-count=600000
--vmlinux=/usr/src/linux-2.4.20/vmlinux For RTC mode users, use --rtc-value=2048 #
opcontrol
--start
watch --interval=1 "opcontrol --dump && opreport -l 2>/dev/null | head -30 ; opcontrol --reset"
opcontrol --stop/--shutdown/--dump
opcontrol –stop
3. Génération d’un rapport :
opreport – merge-all -l
http://oprofile.sourceforge.net/news/
http://oprofile.sourceforge.net/examples/
http://oprofile.sourceforge.net/doc/index.html
http://oprofile.sourceforge.net/doc/internals/index.html
http://oprofile.sourceforge.net/examples/
http://oprofile.sourceforge.net/faq/
http://oprofile.sourceforge.net/doc/devel/index.html
http://citeseer.ist.psu.edu/700537.html
http://www-106.ibm.com/developerworks/linux/library/l-oprof.html (or
http://www.ibm.com/developerworks/linux/library/l-oprof.html)
http://www.eclipse.org/linuxtools/projectPages/oprofile/
http://www.ece.utexas.edu/~ljohn/wwc/wwc6/
http://people.redhat.com/wcohen/wwc2003/
http://people.redhat.com/wcohen/Oprofile.pdf
http://sourceforge.net/projects/oprofile/
http://www.lilax.org/meetings.html
http://www.tru64unix.compaq.com/dcpi/
http://www.tru64unix.compaq.com/dcpi/src-tn-1997-016a.html
http://prospect.sf.net/
 Le noyau 2.6 dispose de
oprofile, un analyseur noyau et
applicatif plus puissant
FORMATION
LINUX
Profiling noyau
322
 Possibilité d'analyser le temps passé dans chaque fonction du noyau :
 paramètre de boot: profile=n
 informations binaires dans /proc/profile
 lecture grâce à l'utilitaire readprofile
Le noyau mémorise tous les 2n
tick d’horloge, dans quelle fonction il se trouve. Vu que c’est par
un mode capture par échantillons, cela inclus une erreur.
 Permet de déceler :
 des dysfonctionnements structurels
 des parties d'un driver à optimiser
FORMATION
LINUX
KGDB
323
 Le patch kgdb est le nom d'un débogueur du noyau Linux au niveau code source. Un tel débogueur est un
outil d'aide au développement de drivers ou de fonctionnalités du noyau, permettant de comprendre
précisément ce qui se déroule réellement dans le cœur du système d'exploitation, de le mettre en pas à pas, et
d'agir dessus.
 Site officiel : http://kgdb.linsyssoft.com
 Pour chaque architecture, il y a deux patch à appliquer :
o Le patch core indépendant de l’architecture : core-lite.patch
o Le patch spécifique à l’architecture choisie : i386.patch
 Nécessite d'avoir deux machines :
 la cible (target) qui sera déboguée
 la machine de développement ayant les sources et le binaire du noyau
 reliées entre-elles par câble série (ou réseau)
 C'est un logiciel libre développé sous licence GNU GPL par Dave Grothe. Le projet est hébergé par
SourceForge.net et son développement est soutenu par la société LinSysSoft, qui en fournit par ailleurs un
support professionnel sous le nom de produit KGDB Pro.
 Avant les dernières version de linux, il fallait patcher le noyau pour inclure le stub (similaire à gdb server).
Dans les versions récente du noyau, Linus Torvald à accepté de l’inclure dans les sources même du noyau.
 Après l’usage est similaire à gdb / gdb server (facile à mettre en place)
http://kgdb.linsyssoft.com/downloads/kgdb-2/kgdbquickstart-2.4.pdf
FORMATION
LINUX
KGDB
324
 Deux modes de connexion possible entre la machine de développement & la cible :
 un câble série (null-modem)
 câble ethernet
 La machine de développement :
 possède une copie des sources et binaires
 (sert souvent à générer les binaires par un processus de compilation croisée)
 exécute le déboggueur (cross-déboggueur)
 pilote la cible
 KGDB permet de :
 interrompre l'exécution du noyau
 mettre des points d'arrêt (exécution, lecture/écriture)
 exécuter le code en mode pas à pas
 connaître la pile d'appel (tâche courante, toutes les tâches)
 examiner/modifier la mémoire (adresses, variables, listes chaînées etc)
 ... toute fonctionnalité de gdb standard ...
 L'utilisation d'interfaces graphiques par dessus gdb reste possible (exemple: ddd)
FORMATION
LINUX
KGDB
325
 KGDB est composé de :
 un déboggueur gdbtournant sur la machine de dev (presque) standard (diffère de part le système de
chargement en module)
 un stub gdb intégré au noyau sous forme de patch noyau
 Une version modifiée de gdb est nécessaire pour certaines fonctionnalités (exemple: déboggage de modules
noyau)
 Le stub gdb est disponible pour beaucoup d'architectures sous forme de patch (plusieurs variantes existent...)
 Télécharger le stub kgdb (par exemple à http://kgdb.linsyssoft.com/cvs.htm) :
 Appliquer le patch kgdb au noyau (attention, le stub kgdb est fait pour une version précise du noyau, des
modification manuelles peuvent être nécessaires si la version du noyau est différente) :
cvs d:pserver:anonymous@kgdb.cvs.sourceforge.net:/cvsroot/kgdb login
cvs z3 d:pserver:anonymous@kgdb.cvs.sourceforge.net:/cvsroot/kgdb co .
wget www.kernel.org/pub/linux/kernel/v2.6/linux2.6.17.
tar.bz2
tar xvfj linux2.6.17.
tar.bz2
cd linux2.6.17
mkdir patches
cp ../kgdb2/*
patches/
quilt push -a
nb : quilt étant un outil d’application d’une pile de patch
FORMATION
LINUX
KGDB
326
 Configurer le noyau :
 choisir le type de connexion (série ou ethernet)
 pour la connexion ethernet il faut avoir activé Netpoll (mode polling pour le debug ; évite de recourir
aux interruptions pour le débugger).
 Compiler le noyau :
 Installer le noyau et ses modules (exemple pour boot par TFTP et montage NFS-root) :
 Générer un déboggueur gdb comprenant les modules noyau :
cp arch/arm/boot/uImage /tftpboot
make modules_install INSTALL_MOD_PATH=/target
make
make oldconfig
wget http://ftp.gnu.org/gnu/gdb/gdb6.4.
tar.bz2
tar xvfj gdb6.4.
tar.bz2
cd gdb6.4
patch p1
< ../gdb/gdbkgdbmodulenotification.
patch
./configure –target=armlinuxuclibc
make
FORMATION
LINUX
KGDB
327
 Générer un déboggueur gdb comprenant les modules noyau:
 Sur la cible :
 pour liaison (over)ethernet, démarrer avec l'option : kgdboe=@TARGETIP/,@DEVIP/ dans lilo/grub
 activer le debug :
• dès le boot si option kgdbwait dans lilo/grub
• automatiquement si oops noyau
• en tapant sysrq+g sur la cible
 Sur la machine de développement :
 Se positionner dans les sources du noyau linux
wget linux-2.6.15.5-kgdb-2.4.tar.bz2
tar -jxvf linux-2.6.15.5-kgdb-2.4.tar.bz2
patch -p1 < ${BASE_DIR}/linux-2.6.15.5-kgdb-2.4/core-lite.patch
patch -p1 < ${BASE_DIR}/linux-2.6.15.5-kgdb-2.4/i386.patch
 Modifier l’extra-version à -kgdb
make xconfig ou make oldconfig
Sélectionner l’option dans le menu : Kernel hacking  Kernel Debugging with remote gdb ; Selectionner aussi :
« KGDB : Console message through gdb » et « KGDB : On généric serial port : 8250 ».
make bImage  le noyau sera crée ici : arch/i386/boot/bzImage
gdb ./vmlinux
 pour liaison série :
(gdb) set remotebaud 115200
(gdb) target remote /dev/ttyS0
 pour liaison ethernet :
(gdb) target remote udp:TARGETIP:6443
FORMATION
LINUX
KGDB
328
 Exemple de débug :
# gdb vmlinux
(gdb) target remote udp:kgdb:6443
breakpoint () at kernel/kgdb.c:1776
1776 atomic_set(&kgdb_setting_breakpoint, 0);
(gdb) b sys_open
Breakpoint 1 at 0xc01543c6: file fs/open.c, line 944.
(gdb) c
Continuing.
[New thread 2774]
[Switching to thread 2774]
Breakpoint 1, sys_open (filename=0x5 <Address 0x5 out of bounds>, flags=5,
mode=5) at fs/open.c:944
944 tmp = getname(filename);
(gdb) n
(gdb) n
946 if (!IS_ERR(tmp)) {
(gdb) p tmp
$2 = 0xcebcf000 "/etc/ld.so.cache »
FORMATION
LINUX
KDB
329
 Débogueur noyau embarqué
 Développé par SGI : http://oss.sgi.com/projects/kdb/
 Débogueur noyau en mode assembleur (pas de mode source)
 Pas de préparation spéciale du noyau à déboguer
 Ne nécessite pas de machine supplémentaire pour le debug
 Débogueur utile mais difficile à exploiter de par sa complexité
http://www.ibm.com/developerworks/linux/library/l-kdbug/
http://luv.asn.au/overheads/embedded/kdb.pdf
- Télécharger les deux patch (commun + spécifique à l’architecture) :
ftp://oss.sgi.com/projects/kdb/download/latest/
- Extraction des archives :
bzip2 -d kdb-v4.2-2.4.20-common-1.bz2
bzip2 -d kdb-v4.2-2.4.20-i386-1.bz2
- Application des patchs :
patch -p1 <kdb-v4.2-2.4.20-common-1
patch -p1 <kdb-v4.2-2.4.20-i386-1
- Lancer la commande : make menuconfig / xconfig
- Sélectionner l’entrée:
Kernel hacking -> Built-in Kernel Debugger support
CONFIG_KDB_OFF désactive le debuggeur par défaut
CONFIG_FRAME_POINTER s’il y a la présnce des pointeurs de frames
- Recompiler le noyau
- Activation : echo "1" > /proc/sys/kernel/kdb
- Désactivation : echo "0" >/proc/sys/kernel/kdb
FORMATION
LINUX
LINICE
330
 Spécificités :
 Linux PC/x86 platform
 Minimum Pentium class CPU Linux
 kernels 2.4 or 2.6
 Site officiel : http://www.linice.com
 Traduction de symboles :
linsym –t <binary> (génère un fichier <binary>.SYM)
 Chargement de symboles :
linsym –s <symbols.sym>
 Chargement / déchargement du débugeur :
 Chargement du module : linsym –i
 Déchargement du module : linsym –x
http://www.linice.com
http://www.linice.com/Linice.pdf
FORMATION
LINUX
LINICE
331
 Préparation des flags :
 CFLAGS := -gstabs+ $(CPPFLAGS) -Wall -Wstrict-prototypes -Wno-trigraphs -O2 -fno-strict-
aliasing -fno-common -Wno-unused
 AFLAGS := -gstabs -D__ASSEMBLY__ $(CPPFLAGS)
 Génération d’un version de débug après la compilation :
$(LD_VMLINUX) $(LD_VMLINUX_KALLSYMS) -o vmlinux.debug $(STRIP) -S -o vmlinux
vmlinux.debug $(NM) vmlinux | grep -v '(compiled)|(.o$$)|( [aUw])|(..ng$$)|
(LASH[RL]DI)' | sort > System.map
 Génération des symboles du noyau de debug vmlinux.debug :
linsym –t vmlinux.debug
FORMATION
LINUX
GDB / KCORE
332
 Débogage avec GDB en lecture seule sur /proc/kcore
http://www.cs.wm.edu/~kearns/001lab.d/kernel_gdb.html
http://www.linux.com/learn/linux-training/33991-the-kernel-newbie-corner-kernel-and-module-debugging-with-gdb
# gdb vmlinux /proc/kcore (start our debugging session)
... snip ...
(gdb) p jiffies_64 (print the value of jiffies_64)
$1 = 4326692196 (and there it is)
(gdb)
(gdb) p loops_per_jiffy
$2 = 1994923
(gdb)
FORMATION
LINUX
GDB / KCORE
333
 Débogage avec GDB en lecture seule sur /proc/kcore
http://www.cs.wm.edu/~kearns/001lab.d/kernel_gdb.html
http://www.linux.com/learn/linux-training/33991-the-kernel-newbie-corner-kernel-and-module-debugging-with-gdb
# gdb vmlinux /proc/kcore (start our debugging session)
... snip ...
(gdb) p jiffies_64 (print the value of jiffies_64)
$1 = 4326692196 (and there it is)
(gdb)
(gdb) p loops_per_jiffy
$2 = 1994923
(gdb)
FORMATION
LINUX
SYSTEMTAP
334
 SystemTap est un outil permettant d'analyser le fonctionnement d'un
noyau Linux en cours de fonctionnement, à la manière de DTrace. Il
s'utilise en ligne de commande avec un langage de script qui lui est
dédié.
 Le projet est distribué sous licence GPL et développé par Red Hat,
IBM, Intel, Hitachi et Oracle.
 Compiler le noyau avec les options suivantes :
 CONFIG_DEBUG_INFO
 CONFIG_KPROBES
 CONFIG_RELAY
 CONFIG_DEBUG_FS
 CONFIG_MODULES
 CONFIG_MODULES_UNLOAD
 Possède une interface graphique : http://stapgui.sourceforge.net/
http://sourceware.org/systemtap/
http://sourceware.org/systemtap/documentation.html
http://sourceware.org/systemtap/tutorial/
http://sourceware.org/systemtap/SystemTap_Beginners_Guide/
http://sourceware.org/systemtap/langref/
http://sourceware.org/systemtap/archpaper.pdf
http://sourceware.org/systemtap/RH2_Systemtap_OLS_2005.pdf
http://sourceware.org/systemtap/systemtap-ols.pdf
FORMATION
LINUX
Linux Trace Toolkit (LTT) / LTTng
335
http://www.opersys.com/
http://lttng.org/LTT
http://lttng.org/files/lttv-doc/user_guide/
http://lttng.org/cgi-bin/gitweb.cgi?p=lttv.git;a=blob_plain;f=LTTngManual.html
http://lttng.org/content/documentation?q=node/12
/
 LTT est un outil permettant de tracer et d’instrumenter le noyau linux.
 Il est un outil complémentaire au débug.
 Nécessite de patcher le noyau.
Démarrage de l’interface graphique :
$ lttv-gui
L’utilisation du mode texte est aussi
simple :
La liste des plug-ins installés est disponible par la commande suivante :
$ lttv -L /usr/local/lib/lttv/plugins -m textDump --help
FORMATION
LINUX
Linux Trace Toolkit (LTT)
336
 Système de trace des événements noyau
 Datation à la micro-seconde
 Léger coût en performances (< 2.5 %)
 Deux versions :
 LTT historique : http://opersys.com/LTT
• développé par Karim Yaghmour depuis 1999
• plus vraiment maintenu depuis 2002 (mais reste utilisable...)
• abandonné définitivement en 2005
 LTTng : http://ltt.polymtl.ca (réécriture du code source à 100%)
• développé par Mathieu Desnoyers, Ecole Polytechnique de Montréal
• Suis les versions du noyau
• encore un peu jeune...
 LTT est composé :
 « pilote » noyau pour implémenter le buffer de trace (lttng)
 instrumentation du code noyau pour générer les traces (lttng)
 utilitaires de collecte (lttctl)
 utilitaires de visualisation des traces (lttv)
FORMATION
LINUX
Linux Trace Toolkit (LTT)
337
 Voir le QUICKSTART de LTT.
 Télécharger les patches noyau :
 Appliquer les patches au noyau :
 Configurer / compiler le noyau :
 activer les options LTT, mais pas LTT_HEARTBEAT
 Redémarrer la machine sur le noyau LTT
wget ltt.polymtl.ca/lttng/patch2.6.20lttng0.6.77.tar.bz2
tar xvfj patch2.6.20lttng0.6.77.tar.bz2
wget www.kernel.org/pub/linux/kernel/v2.6/linux2.6.20.
tar.bz2
cd linux2.6.20
cat ../patch2.6.20lttng0.6.77*
diff | patch p1
make oldconfig
make
make modules_install install
FORMATION
LINUX
Linux Trace Toolkit (LTT)
338
 Compiler l'application de collecte :
 Compiler l'application de visualisation :
 Monter relayfs :
 Charger les modules LTT :
wget http://ltt.polymtl.ca/lttng/lttcontrol0.3512032007.
tar.gz
cd lttcontrol0.3512032007
./configure
make
make install
wget http://ltt.polymtl.ca/packages/LinuxTraceToolkitViewer0.8.7902032007.
tar.gz
cd LinuxTraceToolkitViewer0.8.7902032007
./configure
make
make install
mkdir /mnt/debugfs
echo "debugfs /mnt/debugfs debugfsfs rw 0 0" > /etc/fstab
mount /mnt/debugfs
modprobe lttcontrol
modprobe lttstatedump
FORMATION
LINUX
Linux Trace Toolkit (LTT)
339
 Mode graphique: lttv-gui
 cliquer sur le feu rouge
 démarrer la trace en cliquant sur start
 arrêter la trace en cliquant sur stop
 visualiser la trace
 Mode texte: lttctl + lttv
 démarrer la trace : lttctl –n trace –d –l /mnt/debugfs/ltt –t /tmp/trace
 arrêter la trace : lttctl –n trace –R
 visualiser la trace : lttv –m textDump –t /tmp/trace
FORMATION
LINUX
ENTREES ET SORTIES
BUT : apprendre à maitriser les entrées & sorties.
 Mode polling et interruptible
 Les gestionnaires d’IRQ
FORMATION
LINUX
Les interruptions, pour quoi faire ?
 Les interruptions internes au processeur sont par exemple utilisées pour l'ordonnancement, nécessaire
au multi-tâche.
 Les interruptions externes sont utiles car la plupart des périphériques internes ou externes sont plus
lents que le processeur. Dans ce cas, mieux vaut ne pas laisser le processeur en attente active sur des
données. Lorsque le périphérique est à nouveau près, il envoie une interruption pour demander
l'attention du processeur.
 Liées à un périphérique (ex: carte, port, timer... )
 Une interruption matérielle peut préempter un processus même s'il est en mode noyau.
 Traitement en deux phases:
 top-half : partie rapide et non interruptible (exemple: acquittement de l'interruption auprès du
périphérique) ; toutes les interruptions sont coupés lors du traitement du handle.
 bottom-half : partie lente placée dans une file de tâches qui sera vidée par l'ordonnanceur ; plus
prioritaire que les processus temps réel.
 (exemple: traitement des données respectives).
 Possibilité de partage d'IRQ.
341
FORMATION
LINUX
INTERRUPTIONS ET EVENEMENTS
 Les évènements d'E/S sont souvent asynchrones et non prédictibles (ex: clavier, arrivée de
paquets réseau etc.)
 Il existe deux méthodes pour superviser les E/S :
 l'attente active/scrutation (polling)
 le traitement par interruptions
 Dans le mode polling, on relâche le CPU avec la fonction schedule() après chaque test infructueux :
 Dans le mode interruptible, le processus appelant est endormi et placé dans une file d'attente.
 C'est le gestionnaire de l'interruption attendue qui sera chargé de le réveiller (ainsi que tous les autres
processus en attente dans la file)
342
for ( ; ; )
{
if (evenement) break;
schedule() ;
}
FORMATION
LINUX
INTERRUPTIONS ET EVENEMENTS
 Les gestionnaires d'interruptions (interrupt handler) :
 doivent être rapides ;
 ne doivent pas appeler des routines qui peuvent endormir le processus (ex: kmalloc() non
atomique)
 Pour ces raisons, la gestion des interruptions est découpée en deux parties :
 une partie rapide et non interruptible (gestionnaire d'interruptions)
 une partie lente placée dans une file de tâches (bottom-half)
 Les bottom-halves ne sont pas obligatoires.
 Un gestionnaire d'interruptions est déclaré grâce à la fonction request_irq()
 Il est libéré grâce à la fonction free_irq()
 Prototypes (<linux/sched.h>, <linux/interrupt.h>) :
 int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned
long flags /* SA_SHIRQ */, const char *device, void *dev_id);
 void free_irq(unsigned int irq, void *dev_id);
343
FORMATION
LINUX
INTERRUPTIONS ET EVENEMENTS
 Quand l'interruption irq survient, la fonction handler() est appelée
 Le champ dev_id sert à identifier les périphériques en cas de partage d'IRQ (SA_SHIRQ)
 Il peut être employé pour transmettre au gestionnaire d'interruptions une structure spécifique au
périphérique
 La liste des IRQ déjà déclarées est disponible dans /proc/interrupts
 Le code de retour du handler doit être IRQ_NONE ou IRQ_HANDLED.
 API modifiée en 2.6.19 :
 – le paramètre pt_regs disparaît
 – récupération possible des registres par get_irq_regs()
 – les flags SA_ sont renommés en IRQF_ (exemple: SA_SHIRQ devient IRQF_SHARED)
344
FORMATION
LINUX
INTERRUPTIONS ET EVENEMENTS
 Les bottom-halves sont des fonctions du noyau utilisées pour la gestion de tâches asynchrones
 Ordonnancés à chaque retour d'appel système, d'exception ou de gestionnaire d'interruption
 Ils peuvent être préemptés par des interruptions

 Deux « implémentations » possibles :
 – tasklets: peuvent s'exécuter sur différents CPU (mais une seule instance à la fois)
 – softirqs: peuvent s'exécuter sur différents CPU (plusieurs instances simultanément)
 Exemple :
345
void ma_routine_bh(unsigned long)
{
/* … code bottomhalf ... */
}
DECLARE_TASKLET(ma_tasklet, ma_routine_bh, 0);
void mon_handler_irq(int irq, void *dev_id, struct pt_regs *regs)
{
...
tasklet_schedule(& ma_tasklet);
...
}
FORMATION
LINUX
Enregistrer un gestionnaire
d'interruption
 Défini dans include/linux/interrupt.h
 Bits pouvant être définis dans irq_flags (combinables)
 SA_INTERRUPT
Gestionnaire d'interruption "rapide". Fonctionne avec les interruptions désactivées. Utilité
limitée à des cas spécifiques (tels que les interruptions timer).
 SA_SHIRQ
Le canal d'interruption peut être partagé par plusieurs périphériques.
 SA_SAMPLE_RANDOM
Les interruptions peuvent être utilisées pour contribuer à l'entropie du système (/dev/random
et /dev/urandom), afin de générer de bons nombres aléatoires. Ne l'utilisez pas si votre
périphérique a un comportement prédictif !
int request_irq(
unsigned int irq, /* canal irq demandé */
irqreturn_t (*handler) (int, void *,
struct pt_regs *), /* gestionnaire d'inter. */
unsigned long irq_flags, /* masque d'options */
const char* devname, /* nom enregistré */
void* dev_id) /* utilisé lorsque l'irq est partagée */
void free_irq(
unsigned int irq,
void *dev_id);
346
FORMATION
LINUX
Quand enregistrer le gestionnaire
 Soit à l'initialisation du pilote : consomme beaucoup de canaux IRQ !
 Ou bien à l'ouverture du fichier de périphériques:
permet de sauver des canaux IRQ libres.
Besoin de compter le nombre de fois où le périphérique est ouvert, pour être capable de libérer les
canaux IRQ lorsque le périphérique n'est plus utilisé.
 Information sur les gestionnaires installés :
 Nombre total d'interruptions :
$ cat /proc/interrupts
CPU0
0: 5616905 XT-PIC timer # Nom enregistré
1: 9828 XT-PIC i8042
2: 0 XT-PIC cascade
3: 1014243 XT-PIC orinoco_cs
7: 184 XT-PIC Intel 82801DB-ICH4
8: 1 XT-PIC rtc
9: 2 XT-PIC acpi
11: 566583 XT-PIC ehci_hcd, uhci_hcd,...
12: 5466 XT-PIC i8042
14: 121043 XT-PIC ide0
15: 200888 XT-PIC ide1
NMI: 0 # Interruptions non masquables
ERR: 0
cat /proc/stat | grep intr
intr 8190767 6092967 10377 0 1102775 5 2 0 196 ...
Nombre total
d'interruptions
Total
IRQ1
IRQ2 IRQ3
...
347
FORMATION
LINUX
Détection du canal
d'interruption
 Certains périphériques annoncent leur canal IRQ dans un registre.
 Certains périphériques ont toujours le même comportement: vous pouvez déduire leur canal IRQ.
 Détection manuelle :
 Enregistrez votre gestionnaire d'inter. pour tous les canaux possibles
 Demander une interruption
 Dans le gestionnaire appelé, enregistrer le numéro d'IRQ dans une variable globale
 Réessayez si aucune interruption n'a été reçue
 Désenregistrez les gestionnaires non utilisés
 Outils de détection du noyau :
 mask = probe_irq_on();
 Activez les interruptions sur le périphérique
 Désactivez les interruptions sur le périphérique
 irq = probe_irq_off(mask);
• > 0: numéro d'IRQ unique trouvé
• = 0: pas d'interruption. Essayez à nouveau !
• < 0: plusieurs interruptions reçues. Essayez à nouveau !
348
FORMATION
LINUX
Le travail du gestionnaire d'interruption
 Acquitter l'interruption au périphérique (sinon plus aucune autre interruption ne sera générée)
 Lire/écrire des donnée du/sur le périphérique
 Réveiller tout processus attendant la fin de l'opération de lecture/écriture:
wake_up_interruptible(&module_queue);
 Contraintes du gestionnaire d'interruptions :
 Ne s'exécute pas dans le contexte utilisateur:
Ne peut pas transférer des donnés de ou vers l'espace utilisateur
 Ne peut pas exécuter d'actions pouvant s'endormir:
Besoin d'allouer de la mémoire avec GFP_ATOMIC
 Ne peut pas appeler schedule()
 Doit terminer son travail suffisamment rapidement:
il ne peut pas bloquer les interruptions trop longtemps.
349
FORMATION
LINUX
Prototype d'un gestionnaire
d'interruption
 Valeur retournée :
 IRQ_HANDLED : interruption reconnue et gérée
 IRQ_NONE : pas sur un périphérique géré par le module. Permet de partager des canaux
d'interruption et/ou de reporter de fausses interruptions au noyau.
irqreturn_t (*handler) (
int, /* Numéro d'irq */
void *dev_id, /* Pointeur utilisé pour garder la trace du device
correspondant. Utile quand plusieurs périphériques
sont gérés par le même module */
struct pt_regs *regs /* snapshot des registres du cpu, rarement
nécessaire */
);
350
FORMATION
LINUX
Traitement parties haute et basse
 Partie haute : le gestionnaire doit se terminer le plus vite que possible. Une fois qu'il a acquitté
l'interruption, il planifie le reste du travail gérant les données et prenant du temps, pour une exécution
future.
 Partie basse : termine le reste du travail du gestionnaire. Traite les données, et ensuite réveille tout les
processus utilisateur en attente. Implémenté au mieux par les tasklets.
 Déclarer la tasklet dans le fichier source du module:
 Planifier la tasklet dans la partie haute du gestionnaire:
DECLARE_TASKLET (module_tasklet, /* nom */
module_do_tasklet, /* fonction */
0 /* données */
);
tasklet_schedule(&module_do_tasklet);
351
FORMATION
LINUX
Résumé de la gestion des interruptions
 Trouver un numéro d'interruption (si
possible)
 Activer les interruptions sur le périphérique
 Détecter le numéro d'interruption utilisé par
le périphérique, en scrutant les différents
possibilités, si nécessaire.
 Enregistrer le gestionnaire d'interruption
avec le numéro d'IRQ identifié.
 Une fois que le gestionnaire d'interruption
est appelé, acquitter l'interruption.
 Dans le gestionnaire, planifier la tasklet
gérant les données
 Dans la tasklet, gérer les données
 Dans la tasklet, réveiller les processus
utilisateur en attente
 Désenregistrer le gestionnaire si le
périphérique est fermé.
352
FORMATION
LINUX
TASKLET : exemple d’usage
353
#include <linux/interrupt.h>
#include <linux/version.h>
#include <linux/ioport.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <asm/io.h>
static char * nom_module = "exemple_10";
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
static irqreturn_t irq_handler(int irq, void * ident, struct pt_regs * unused);
#else
static irqreturn_t irq_handler(int irq, void * ident);
#endif
#ifndef IRQF_SHARED
#define IRQF_SHARED SA_SHIRQ
#endif
static void fonction_tasklet (unsigned long inutile);
static DECLARE_TASKLET(tasklet_exemple, fonction_tasklet, 0);
static int __init chargement (void)
{
int erreur;
if (request_region(0x378, 3, nom_module) == NULL)
return -EBUSY;
erreur = request_irq(7, irq_handler, IRQF_SHARED,
nom_module, nom_module);
if (erreur != 0) {
release_region(0x378, 3);
return erreur;
}
outb(0x10, 0x37A);
return 0;
}
FORMATION
LINUX
TASKLET : exemple d’usage
354
static void __exit dechargement (void)
{
outb(0, 0x37A);
free_irq(7, nom_module);
tasklet_kill(& tasklet_exemple);
release_region(0x378, 3);
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
static irqreturn_t irq_handler(int irq, void * ident, struct pt_regs * unused)
#else
static irqreturn_t irq_handler(int irq, void * ident)
#endif
{
if ((inb(0x379) & 0x40) == 0)
return IRQ_NONE;
tasklet_schedule(& tasklet_exemple);
return IRQ_HANDLED;
}
static void fonction_tasklet(unsigned long inutile)
{
static int valeur = 0;
outb(valeur, 0x378);
valeur = 0xFF - valeur;
}
module_init(chargement);
module_exit(dechargement);
MODULE_LICENSE("GPL");
FORMATION
LINUX
GESTION DES ENTREES ET SORTIES
BUT : apprendre à maitriser la DMA.
 Accès au matériel sous x86
 Accès mémoire
 Exemple d'activation du DMA
 API générique DMA
FORMATION
LINUX
Accès au matériel – ports d’E/S
 Architecture Intel
 Plages d'adresses utilisées par les périphériques présents sur le bus d'E/S (registres de contrôle)
 On accède à ces ports depuis le noyau grâce aux fonctions :
 in{b,w,l}()/out{b,w,l}() : lit/écrit 1, 2 ou 4 octets consécutifs sur un port d'E/S
 in{b,w,l}_p()/out{b,w,l}_p() : lit/écrit 1, 2 ou 4 octets consécutifs sur un port d'E/S et fait
une pause (une instruction)
 ins{b,w,l}()/outs{b,w,l}() : lit/écrit des séquences de 1, 2 ou 4 octets consécutifs sur un
 port d'E/S
 Les pilotes peuvent accéder à des ports d'E/S qui ne leur appartiennent pas (exemple: probing)
 Pour éviter les conflits, le pilote peut réserver des ports auprès du noyau:
 request_region() : réserve une plage de ports d'E/S (si disponible)
 release_region() : libère la plage de ports d'E/S.
 La liste des ports déjà réservés peut être consultée dans /proc/ioports.
356
FORMATION
LINUX
Accès au matériel – ports d’E/S
 Prototypes x86 (<asm/io.h>) :
 unsigned char inb(unsigned short port);
 void outb(unsigned char byte, unsigned short port);
 unsigned char insb(unsigned short port, void *addr, unsigned long count);
 void outsb(unsigned short port, void *addr, unsigned long count);
357
FORMATION
LINUX
Accès au matériel – mémoire d’E/S
 Les périphériques d'E/S peuvent aussi posséder de la mémoire partagée (ex: frame-buffer des cartes
graphiques, buffers des cartes réseau)
 Cette mémoire est accessible comme de la mémoire centrale (contrairement aux ports d'E/S)
 Cependant, le noyau manipule des adresses linéaires virtuelles (et non physiques)
 La mémoire centrale est elle-même mappée à l'adresse PAGE_OFFSET)
 Il faut donc mapper les plages d'adresses d'entrée/sortie dans l'espace linéaire du noyau (donner une
adresse virtuelle aux adresse physiques) :
 ioremap() : mappe une plage d'adresses physiques sur une plage d'adresses virtuelles
(semblable à vmalloc())
 iounmap() : libère une plage préalablement mappée
358
FORMATION
LINUX
Accès au matériel – mémoire d’E/S
 Pour éviter les conflits, le pilote peut réserver des plages mémoire d'E/S auprès du noyau :
 request_mem_region() : réserve une plage d'adresses physiques d'E/S
 release_mem_region() : libère une plage d'E/S
 La liste des plages mémoire d'E/S qui sont déjà réservées apparaît dans /proc/iomem
 Prototypes (<asm/io.h> et <linux/ioport.h>) :
 void *ioremap(unsigned long offset, unsigned long size);
 void iounmap (void *addr);
 struct resource *request_{mem_}region(unsigned long start, unsigned long n, const char
*name);
 void release_{mem_}region(unsigned long start, unsigned long n);
359
FORMATION
LINUX
Accès au matériel – mémoire d’E/S
 On accède ensuite à la mémoire partagée des E/S grâce aux fonctions suivantes :
 read{b,w,l}()/write{b,w,l}() : lit/écrit respectivement 1, 2 ou 4 octets consécutifs dans de la
mémoire d'E/S
 memcpy_{from,to}io() : lit/écrit un bloc d'octets consécutifs dans de la mémoire d'E/S
 memset_io() : remplit une zone de mémoire d'E/S avec une valeur fixe
 virt_to_bus()/bus_to_virt() : traduction entre adresses virtuelles linéaires et adresses réelles
sur le bus.
 Prototypes x86 (<asm/io.h>):
 char readb(void *addr);
 void writeb(char byte, void *addr);
 void * memcpy_{from,to}io(void *dest, const void *src, size_t count);
 void * memset_io(void *addr, int pattern, size_t count);
 unsigned long virt_to_bus(volatile void *addr);
 void * bus_to_virt(unsigned long addr);
360
FORMATION
LINUX
Demander des ports d'E/S
 struct resource *request_region(
unsigned long start,
unsigned long len,
char *name);
Essaie de réserver la région donnée et retourne NULL en cas
d'échec. Exemple:
request_region(0x0170, 8, "ide1");
 void release_region(
unsigned long start,
unsigned long len);
 Regarder include/linux/ioport.h et kernel/resource.c
$ cat /proc/ioports
0000-001f : dma1
0020-0021 : pic1
0040-0043 : timer0
0050-0053 : timer1
0060-006f : keyboard
0070-0077 : rtc
0080-008f : dma page reg
00a0-00a1 : pic2
00c0-00df : dma2
00f0-00ff : fpu
0100-013f : pcmcia_socket0
0170-0177 : ide1
01f0-01f7 : ide0
0376-0376 : ide1
0378-037a : parport0
03c0-03df : vga+
03f6-03f6 : ide0
03f8-03ff : serial
0800-087f : 0000:00:1f.0
0800-0803 : PM1a_EVT_BLK
0804-0805 : PM1a_CNT_BLK
0808-080b : PM_TMR
0820-0820 : PM2_CNT_BLK
0828-082f : GPE0_BLK
...
361
FORMATION
LINUX
Lire / écrire sur les ports d'E/S
 L'implémentation des fonctions suivantes et le type unsigned peuvent varier suivant la plate-forme !
 octets
unsigned inb(unsigned port);
void outb(unsigned char byte, unsigned port);
 mots
unsigned inw(unsigned port);
void outw(unsigned short word, unsigned port);
 "long" integers
unsigned inl(unsigned port);
void outl(unsigned long word, unsigned port);
362
FORMATION
LINUX
Lire / écrire une chaîne sur les ports d'E/S
 Plus efficace que la boucle C correspondante, si le processeur supporte de telles opérations :
 byte strings
void insb(unsigned port, void *addr, unsigned long count);
void outsb(unsigned port, void *addr, unsigned long count);
 word strings
void insw(unsigned port, void *addr, unsigned long count);
void outsw(unsigned port, void *addr, unsigned long count);
 long strings
void inbsl(unsigned port, void *addr, unsigned long count);
void outsl(unsigned port, void *addr, unsigned long count);
363
FORMATION
LINUX
Demander de la mémoire d'E/S
 Fonctions équivalentes avec la même interface
 struct resource *request_mem region(
unsigned long start,
unsigned long len,
char *name);
 void release_mem_region(
unsigned long start,
unsigned long len);
$ cat /proc/iomem
00000000-0009efff : System RAM
0009f000-0009ffff : reserved
000a0000-000bffff : Video RAM area
000c0000-000cffff : Video ROM
000f0000-000fffff : System ROM
00100000-3ffadfff : System RAM
00100000-0030afff : Kernel code
0030b000-003b4bff : Kernel data
3ffae000-3fffffff : reserved
40000000-400003ff : 0000:00:1f.1
40001000-40001fff : 0000:02:01.0
40001000-40001fff : yenta_socket
40002000-40002fff : 0000:02:01.1
40002000-40002fff : yenta_socket
40400000-407fffff : PCI CardBus #03
40800000-40bfffff : PCI CardBus #03
40c00000-40ffffff : PCI CardBus #07
41000000-413fffff : PCI CardBus #07
a0000000-a0000fff : pcmcia_socket0
a0001000-a0001fff : pcmcia_socket1
e0000000-e7ffffff : 0000:00:00.0
e8000000-efffffff : PCI Bus #01
e8000000-efffffff : 0000:01:00.0
...
364
FORMATION
LINUX
DIRECT MEMORY ACCESS (DMA)
BUT : apprendre à maitriser la DMA.
 Caractéristiques du DMA
 Utilisation de la DMA
 Exemple d'activation du DMA
 API générique DMA
FORMATION
LINUX
Caractéristiques du DMA
 A été créé au départ pour rendre la gestion de l'alimentation plus simple. Va maintenant bien au delà
 Utilisé pour représenter l'architecture et l'état du système
 A une représentation dans l'espace utilisateur: sysfs
Désormais c'est l'interface préférée avec l'espace utilisateur (au lieu de /proc)
 Facile à implémenter grâce à l'interface device: include/linux/device.h
 Permet de voir le système depuis différents points de vue :
 Depuis les périphériques existant dans le système: leur état d'alimentation, le bus auquel ils sont
attachés, et le pilote qui en est responsable.
 Depuis la structure du bus système: quel bus est connecté à quel bus (par exemple contrôleur de
bus USB sur le bus PCI), les périphériques existant et ceux potentiellement acceptés (avec leur
pilotes)
 Depuis les pilotes disponibles: quels périphériques et quel types de bus sont supportés.
 Depuis différentes "classes" de périphériques: "input", "net", "sound"... Périphériques existant
pour chaque classe. Permet de trouver tous les périphériques d'entrée sans savoir où ils sont
connectés physiquement.
366
FORMATION
LINUX
Utilisation de la DMA
 Synchrone
 Un processus utilisateur appelle la méthode
de lecture d'un pilote. Celui-ci alloue un
tampon DMA et demande au matériel de
copier ces données. Le processus est placé en
veille.
 Le matériel copie les données et provoque
une interruption à la fin de la copie.
 Le gestionnaire récupère les données du
tampon et réveille le processus en attente.
 Asynchrone
 Le matériel envoie une interruption pour
annoncer de nouvelles données.
 Le gestionnaire alloue un tampon DMA et dit
au matériel où transférer les données.
 Le matériel écris les données et lève une
nouvelle interruption.
 Le gestionnaire récupère les nouvelles
données et réveille les processus nécessaires.
 Contraintes mémoire :
 Besoin d'utiliser de la mémoire contiguë dans l'espace physique
 Peut utiliser n'importe quelle mémoire allouée par kmalloc ou __get_free_pages
 E/S bloc ou réseau: possibilité d'utiliser des tampons spécialisés, conçus pour être compatibles avec la
DMA.
 Ne peut pas utiliser la mémoire vmalloc
(il faudrait configurer la DMA pour chaque page)
 Utiliser la DMA ne supprime pas le besoin de barrières mémoire. Autrement, votre compilateur peut
mélanger l'ordre des lectures et des écritures.
367
FORMATION
LINUX
Exemple d'activation du DMA
 Sur la plupart des distributions "tout-public" (mandriva, suse,...) le DMA est activé par défaut. Le DMA
permet de réduire les temps d’accès au disque dur.
 Vérifiez auparavant que votre disque dur n’utilise pas déjà le DMA. Pour cela tapez la commande
suivante dans la console (dans ce cas, hda correspond au premier disque dur de la première nappe) :
 Si vous utilisez le DMA, vous obtiendez (comme ci dessus) : using_dma = 1 (on)
Ce qui signifie que le DMA est déja activé.
 En outre, si vous obtenez using_dma = 0 (off), alors vous pouvez continuez cet article... :)
Pour l’activez, il suffit de taper cette commande : hdparm -d1 /dev/hda
Normalement, cela suffit à activez le DMA.
$ hdparam /dev/hda
/dev/hda:
multcount = 0 (off)
IO_support = 1 (32-bit)
unmaskirq = 1 (on)
using_dma = 1 (on)
keepsettings = 0 (off)
readonly = 0 (off)
readahead = 256 (on)
geometry = 58140/16/63, sectors = 58605120, start = 0
368
FORMATION
LINUX
Exemple d'activation du DMA
 Si vous obtenez une erreur de ce genre c’est que le mode DMA n’est pas compilé dans le noyau :
setting using_dma to 1 (on)
HDIO_SET_DMA failed: Operation not permitted
using_dma = 0 (off)
 Il va donc vous falloir procéder à une recompilation du noyau :
où XXXXXX est le chipset présent sur votre carte mère.
Recompilez donc le noyau avec les modifications que vous venez d’appliquer, et redémarrez.
Une fois que la machine est redémarrée, tapez la commande : hdparm /dev/hda
puis vérifiez que la ligne using_dma = 1 (on)
est bien a 1(on)
Et voilà, le DMA est désormais actif, ce qui va vous permettre d’avoir un système nettement plus rapide
car moins de transfert sur les bus et entre autre moins de sollicitation du CPU.
CONFIG_BLK_DEV_IDEDMA=y
CONFIG_IDEDMA_PCI_AUTO=y
CONFIG_BLK_DEV_XXXXXX=y
369
FORMATION
LINUX
API générique DMA
 La plupart des sous-systèmes fournissent leur propre API DMA. Suffisant pour la plupart des besoins.
 Documentation/DMA-API.txt
Description de l'API DMA générique Linux, en parallèle avec l'API PCI DMA correspondante.
 Mappages permanents («consistants»)
Alloués pour toute la durée de chargement du module.
 Mappages de flux
Configurés à chaque transfert.
Cela permet de garder libres des registres matériels pour la DMA. Certaines optimisation sont aussi
disponibles.
 Mappages DMA permanents ou de flux :
370
FORMATION
LINUX
PSEUDOFS /PROC et /SYS
BUT : apprendre à maitriser le système de fichiers virtuels .
 Quelques exemple de données dans le ramfs kernel
 Le pseudo système de fichiers sysfs
 Implémentation d’une nouvelle entrée
FORMATION
LINUX
Quelques exemple de données
 Informations générales sur le système :
 /proc/cpuinfo: informations sur le(s) processeur(s)
 /proc/meminfo: état de la mémoire
 /proc/version: information sur la version et la compil.
 /proc/cmdline: ligne de commande du noyau
 Pour chaque processus il y a une entrée par PID :
 /proc/<pid>/environ: environnement d'exécution
 /proc/<pid>/cmdline: ligne de cmd du processus
 Profs est un système de pseudo-système de fichiers utilisé pare le kernel.
 Ce dernier est accessible en lecture et/ou écriture selon les données.
 Il permet Une certain interaction entre l'espace utilisateur et l'espace noyau.
 En effet, une modification d'un paramètre doit être prise en compte par le noyau
En dynamique.
372
FORMATION
LINUX
Le pseudo système de fichiers
sysfs
 Représentation dans l'espace utilisateur du «Modèle de périphérique».
 Configurer par : CONFIG_SYSFS=y (Filesystems -> Pseudo filesystems)
 Monté de la façon suivante : mount -t sysfs /sys /sys
 Outils sysfs :
 http://linux-diag.sourceforge.net/Sysfsutils.html
 libsysfs – Le but de cette librairie est de fournir une interface stable et pratique pour obtenir des
informations sur les périphériques système exportés à travers sysfs. Utilisé par udev (voir plus
loin)
 systool – Un utilitaire bâti au dessus de libsysfs qui liste les périphériques par bus, classe et
topologie.
373
http://www.gnugeneration.com/books/linux/2.6.20/procfs-guide/
http://buffer.antifork.org/linux/procfs-guide.pdf
FORMATION
LINUX
374
Ajout d’une entrée dans /proc
 Exemple de module créant une entrée /proc/perso. A chaque lecture dans ce fichier, un compteur est
incrémenté et sa valeur affichée. Lors de l’écriture d'un nombre décimal dans le fichier, la valeur du
compteur est écrasée.
#include <linux/init.h>
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/vmalloc.h>
#include <linux/module.h>
#include <linux/version.h>
#include <asm/uaccess.h>
#include <linux/proc_fs.h>
static struct proc_dir_entry * entree_proc = NULL;
#define LG_LIGNE 80
static int perso_read_proc (char * page, char ** debut,
off_t offset, int nombre, int * eof, void * data)
{
int * compteur = (int *) data;
if (offset > 0)
return 0;
(* compteur) ++;
snprintf (page, nombre,
"Ca fait %d fois que vous lisez /proc/person",
*compteur );
return 1 + strlen (page);
}
static int perso_write_proc (struct file * file,
const char __user * buffer,
unsigned long nombre, void * data)
{
char ligne[LG_LIGNE];
int n;
int * compteur = (int *) data;
if (nombre >= LG_LIGNE)
return -ENOMEM;
copy_from_user(ligne, buffer, nombre);
ligne[nombre] = '0';
if (sscanf (ligne, "%d", & n) == 1) {
* compteur = n;
printk(KERN_INFO
"Valeur %d ecrite dans /proc/person", n);
return nombre;
}
return -EINVAL;
}
FORMATION
LINUX
Ajout d’une entrée dans /proc
375
static int __init chargement (void)
{
int * compteur;
if (entree_proc != NULL)
return -EBUSY;
compteur = vmalloc(sizeof(int));
if (compteur == NULL)
return -ENOMEM;
* compteur = 0;
entree_proc = create_proc_entry("perso",
S_IFREG | S_IRUGO | S_IWUSR, & proc_root);
if (entree_proc == NULL)
return -1;
entree_proc->owner = THIS_MODULE;
entree_proc->read_proc = perso_read_proc;
entree_proc->write_proc = perso_write_proc;
entree_proc->data = compteur;
printk(KERN_INFO "Chargement du module procfsn");
return 0;
}
static void __exit dechargement (void)
{
void * ptr;
printk (KERN_INFO
"Dechargement du module procfsn");
if (entree_proc == NULL)
return;
ptr = entree_proc->data;
remove_proc_entry("perso", & proc_root);
vfree(ptr);
entree_proc = NULL;
}
module_init(chargement);
module_exit(dechargement);
MODULE_AUTHOR("TG");
MODULE_DESCRIPTION( "Entrée dans /proc" );
MODULE_LICENSE("GPL");
 Fonction de chargement :  Fonction de déchargement :
 Global :
FORMATION
LINUX
CONSEILS ET RESSOURCES
BUT : utiliser l’aide de la communauté.
 Livres de référence
 Liste de liens utiles
 Sites web incontournables
 Carte du noyau linux interactive
 DDK Linux : Drivers Development Kit
FORMATION
LINUX
Livres
et
revues
de
références
377
Ouvrages de référence
FORMATION
LINUX
Livres
et
revues
de
références
378
Ouvrages de référence
FORMATION
LINUX
Ouvrages de référence
379
FORMATION
LINUX
Ouvrages de référence
380
FORMATION
LINUX
Liens
 Carte du noyau interractive : http://www.linuxdriver.co.il/kernel_map ou http://www.makelinux.net/kernel_map
 http://learnlinux.tsf.org.za/courses/build/internals/internals-all.html
 http://howsoftwareisbuilt.com/2007/05/23/linux-kernel-modification-process/
 http://mxi1.wordpress.com/category/linux-kernel/
 http://www.iamexwi.unibe.ch/studenten/schlpbch/linuxScheduling/LinuxScheduling-1.html
 http://en.wikipedia.org/wiki/Linux_kernel
 http://josh.trancesoftware.com/linux/linux_cpu_scheduler.pdf
 http://www.ibm.com/developerworks/linux/library/l-linux-kernel/
 http://www.kernelhq.org/
 http://kerneltrap.org/
 http://www.kernel.org/
 http://kernelnewbies.org/KernelHacking
 http://kernelnewbies.org/Drivers
 http://lwn.net/Kernel/
 http://lwn.net/Kernel/LDD3/
 http://janitor.kernelnewbies.org/
 http://old.lwn.net/2001/features/Timeline/
 http://www.kroah.com/lkn/
 Linux DDK : http://www.kroah.com/log/2006/05/24/#ddk
http://www.kernel.org/pub/linux/kernel/people/gregkh/ddk/
 http://kernelnewbies.org/
 http://www.xenotime.net/linux/mentor/linux-mentoring.pdf
 http://www.linuxdevices.com/articles/AT5340618290.html
 http://www.stardust.webpages.pl/files/handbook/handbook-en-0.3-rc1.pdf
 http://www.opersys.com/LTT/
381
 Moteur de recherche de code
source :
 Krugle.com
 Koders.com
 code.google.com
 www.google.com/linux
 www.google.com/codesearch
 http://lxr.linux.no
FORMATION
LINUX
Liens
 http://www.cs.umd.edu/hcil/millionvis/Treemap_Visualization_of_the_Linux_Kernel_2_5_33.html
 http://www.linuxdevices.com
 http://web.yl.is.s.u-tokyo.ac.jp/~tosh/kml/
 http://www.alcove.com/IMG/pdf/kernel_debugging.pdf
 http://www.ibm.com/developerworks/linux/library/l-initrd.html
 http://www.ibm.com/developerworks/library/l-proc.html
 http://www.ibm.com/developerworks/linux/library/l-linuxboot/
 http://devresources.linux-foundation.org/rddunlap/doc/scale-3x-kj-v5.pdf
 http://www.chear.defense.gouv.fr/fr/think_tank/archives/rstd/64/rstd64p77.pdf
 http://www.trunix.org/programlama/c/kernel-api/index.html
 http://www.ibm.com/developerworks/linux/library/l-linux-filesystem/
 http://docs.huihoo.com/linux/kernel/a1/index.html
 http://lwn.net/Articles/13325/
 http://en.wikipedia.org/wiki/Linux_Kernel_API
 http://kernelbook.sourceforge.net/kernel-api.pdf
 http://kernelbook.sourceforge.net/
 http://kernelnewbies.org/KernelHacking
 http://www.linuxjournal.com/article/5833
 http://www.cs.rochester.edu/~kshen/csc256-spring2005/assignments/xen-programming4.html
 http://www.linux.it/~rubini/docs/ksys/ksys.html
 http://www.cs.pitt.edu/~jmisurda/teaching/cs1550/2077/cs1550-2077-project2.htm
 http://oss.sgi.com/projects/kernprof/
 http://oss.sgi.com/projects/lockmeter/
 http://oss.sgi.com/projects/cpumemsets/
382
FORMATION
LINUX
Liens
 http://linuxdriverproject.org/twiki/bin/view
 http://www.spinics.net/lists/netdev/
 http://linux-mm.org/LinuxMM
 http://kernelnewbies.org/known_regressions
 http://tldp.org/
 http://lea-linux.org/
 http://oss.sgi.com/projects/numa/
 http://oss.sgi.com/projects/sgi_propack/
 http://www.linuxjournal.com/article/5833
 http://www.kernel.org/doc/htmldocs/
383
FORMATION
LINUX
Carte interactive des sources du
noyau
 http://www.linuxdriver.co.il/kernel_map
Carte interactive de la carte du noyau GNU Linux
384
FORMATION
LINUX
Carte du noyau 2.5.33 (version de dev)
 http://www.cs.umd.edu/hcil/millionvis/Treemap_Visualization_of_the_Linux_Kernel_2_5_33.html
385
FORMATION
LINUX
Sites web incontournables
 Linux Weekly News (http://lwn.net/)
 Le résumé hebdomadaire de toutes les sources d'informations pour des logiciels libres et Linux
 Discussions techniques sur le noyau
 Abonnez-vous pour financer les éditeurs ($5 / mois)
 Articles disponibles pour les non abonnés au bout d'une semaine.
 KernelTrap (http://kerneltrap.org/)
 Forum pour les développeurs noyau
 Actualités, articles, discussions, sondages, entretiens.
 Parfait si un résumé ne vous suffit pas.
 FAQ de la liste de diffusion du noyau Linux
(ttp://www.tux.org/lkml/
A lire avant de poser une question à la liste de diffusion !
 Kernel Newbies (http://kernelnewbies.org/)
 Glossaires, articles, présentations, HOWTOs, lectures
recommandées, utilitaires pour les personnes
devenant familières avec le développement
noyau.
 FAQ du noyau Linux: www.tux.org/lkml/
 Résumés des discussions: www.kerneltraffic.org
386
FORMATION
LINUX
La communauté autour du noyau
 Les moyens de communication :
 La Linux Kernel Mailing List (LKML),
 Des mailing lists par sous-système et projet,
 Les archives sur http://vger.kernel.org/vger-lists.html,
 Des canaux IRC (voir les sites d'introduction plus bas)
 Les manifestations :
 RMLL (français)
 Kernel Summit (international)
 FOSDEM (européen)
 L'introduction au développement noyau :
 Kernel Mentors (http://kernelnewbies.org/KernelMentors),
 Kernel Janitors (http://www.kerneljanitors.org/),
 Kernel Newbies (http://kernelnewbies.org/)
 Les outils :
 Un gestionnaire de code pour développement distribué (GIT),
 Un suivi des régressions (http://kernelnewbies.org/known_regressions),
 Bugzilla (diversement utilisé et apprécié)
387
FORMATION
LINUX
Kit de développement officiel
• http://www.kroah.com/log/2006/05/24/#ddk
• http://www.kernel.org/pub/linux/kernel/people/gregkh/ddk/
• http://www.kernel.org/pub/linux/kernel/people/gregkh/ddk/ddk-2.6.16.18.iso.bz2
In coordination with the
FreedomHEC conference
in Seattle, WA, USA.
LSB Driver Development Kit (DDK)
(make LSB-compliant printer and scanner driver packages)
http://www.linux-foundation.org/en/OpenPrinting/WritingA
ndPackagingPrinterDrivers
http://ldn.linuxfoundation.org/how-participate-linux-commu
nity
388
FORMATION
LINUX
DES QUESTIONS ?
389

Formation sur le developpement de drivers dans le noyau GNU/linux

  • 1.
    Formation linux noyau etdrivers © Copyright Eurogiciel – RENNES Thierry GAYET Thierry.Gayet@eurogiciel.fr
  • 2.
    FORMATION LINUX TIMING DE LAFORMATION Timing journalier :  Matin : 09h00-10h30 : première partie 10h30-10h45 : pause 10h45-13h00 : seconde partie  Pause déjeuner  Après-midi : 14h00-15h30 : troisième partie 15h30-15h45 : pause 15h45-17h00 : quatrième partie  Questions libres.  merci de signaler toute contrainte de temps sur cette période dès le début.
  • 3.
    FORMATION LINUX PLAN DE LAFORMATION  Introduction  Generation d’un noyau linux  Execution  Architecture du noyau  Méthodologie  Architecture du noyau  Développement  Kthreads  Synchronisation  Liste chaînée  Queue de travail  /proc et /sys  Mise au point  DMA  Interruptions  Timers et horloges
  • 4.
    FORMATION LINUX INTRODUCTION  Historique : Unix  GNU Linux  Organisation du projet  Métriques & caractéristiques  Nouveautés de la version 2.6  Versioning du noyau  Problématiques de la licence GPL 4 BUT : comprendre le projet GNU Linux
  • 5.
    FORMATION LINUX Origine d’Unix 1969 KenThompson (laboratoires de Bell) écrit la première version de ce qui devait par la suite s'appeler Unix. Le nom "Unix" était à l'origine un calembour sur le système d'exploitation Multics (Multiplexed Information and Computing Service) et a été écrit "Unics" en premier lieu (UNiplexed Information and Computing System). Cette première mouture a fonctionné sur un DEC PDP-7. En 1970, Ken Thompson et Dennis Ritchie l'adaptent au DEC PDP-11/20. Il résultat de cette expérience le premier compilateur C. Le langage C a été conçu spécifiquement pour un OS portable. Ces versions initiales ont été intitulées "la Version n" ou "la Énième Edition ». 1971 La première version d'Unix, avec l'assembleur du PDP-11/20. Incluant les systèmes de fichiers, fork(), roff, ed, elle a été employée comme un outil de traitement de texte pour la préparation de brevets d'invention. La fonction pipe() est apparue pour la première fois dans la V2. 1973 Ritchie et Thompson réécrivent le noyau d'Unix en C. 1974-1977 Le code source d'Unix est distribué librement aux universités (dû, au moins en partie, aux restrictions commerciales des USA à ATT). En conséquence, UNIX a gagné la faveur de la communauté scientifique et universitaire. Il a été ainsi à la base des systèmes d'exploitation des principales universités. 1978 UNIX, 7ème édition. Cette version a été développée expressément pour être portée sur diverses architectures matérielles. En outre, avec la version 7, ATT annonce qu'ils font payer des licences pour accéder aux sources du système. En conséquence, la version 7 forme la base de toutes les versions d'Unix actuellement disponibles. Les écrits de Brian Kernighan et Rob Pike (deux chercheurs des laboratoires Bell fortement impliqués dans le développement d'Unix) présentent la philosophie de conception d'Unix. Commençant par la structure de base d'Unix et son exécution, il conclut avec la programmation du système inférieur en C. Pour beaucoup, c'est le "dernier vrai Unix", "une amélioration sans précédent" [Bourne]. Il a inclus la version complète de K&RC, uucp, Bourne shell. Le noyau V7 avait une taille de seulement 40 Ko ! Voici les fonctions de la V7 : _exit, access, acct, alarm, brk, chdir, chmod, chown, chroot, close, creat, dup, dup2, exec*, exit, fork, fstat, ftime, getegid, geteuid, getgid, getpid, getuid, gtty, indir, ioctl, kill, link, lock, lseek, mknod, mount, mpxcall, nice, open, pause, phys, pipe, pkoff, pkon, profil, ptrace, read, sbrk, setgid, setuid, signal, stat, stime, stty, sync, tell, time, times, umask, umount, unlink, time, ait, write. 1979 L'annonce d'ATT de son intention de commercialiser UNIX a incité l'université de Californie à Berkeley pour créer sa propre variante : BSD UNIX. Les versions les plus répandues de BSD sont la 4.2 (1983) et la 4.3 (1987). Le développement commandité par le DARPA (Defense Advanced Research Projects Agency) d'Internet était basé sur le BSD UNIX. La plupart des premiers constructeurs commerciaux d'Unix (Sun (SunOS), DEC (Ultrix), etc...) se sont en grande partie basés sur le BSD UNIX. De plus beaucoup de plates-formes hardware (de mini à Cray) utilisent le BSD. Le manuel d'administration de système Unix par Nemeth, Snyder et Seebass est publié. Le système V d'ATT y est détaillé. La deuxième édition , éditée en 1995, est une mise à jour qui traite de Solaris 2.4, SunOS 4.1.3, HP-UX 9.0, DEC OSF/1 2.0, IRIX 5.2 et BSDI 1.1. 5
  • 6.
    FORMATION LINUX Origine d’Unix 1983 ATTmet en vente la version commerciale du système V. 1987 Diffusion de X Window, une interface client/serveur graphique développée au MIT (Massachussetts Institute of Technology). La version 3 du système V d'ATT est opérationnelle . C'est la version qui a forcé les constructeurs principaux (HP (HP-UX) et IBM (AIX), a développer un OS propriétaire. C'est également en 1987 que la version 4.3 de BSD a été développée. Et finalement, c'est cette année là qu'ATT et Sun ont choisi conjointement d'unifier le Système V et BSD. 1990 La version 4 du système V d'ATT comporte de nouveaux standard d'unification d'UNIX. C'est le résultat de la coopération entre Sun et ATT. Cependant, d'autres grands constructeurs (en particulier DEC, HP et IBM) se sentant menacés par cette collaboration entre deux des plus grands développeurs d'Unix ont décidés de créer l'OSF(Open Software Foundation). Le Perl, langage de programmation écrit par Larry Wall spécifiquement pour les besoins de gestion d'Unix s'est grandement répandu. Tandis que le C est le langage de choix pour la programmation système d'Unix, le Perl st le langage pour la gestion de systèmes Unix (Majordomo et ftpmail sont juste deux exemples des programmes significatifs écrits en Perl). 1991 OSF-1 .C'est l'année ou les clones d'Unix comme Linux et FreeBSD ont commencé à émerger. 1992 Sun développe son OS, Solaris, un dérivé de la version 4 du système V avec la gestion des threads. Ces versions Vn ont été développées par le Computer Research Group (CRG) des Laboratoires Bell. Un autre groupe, le Unix System Group (USG), était responsable du support. Un troisième groupe aux Laboratoires Bell a été aussi impliqué dans le développement d'Unix, le Programmer's WorkBench (PWB), auquel l'on doit, par exemple, sccs, le nom pipes et d'autres idées importantes. Tous les groupes ont fusionné dans le Laboratoire de Développement de Système Unix en 1983. CB Unix (Columbus Unix) était une autre variante d'Unix de la branche Columbus des Laboratoires Bell, responsables de Systèmes d'Appui d'Opérations. Sa principale contribution fut les parties de SV IPC. Dans les années 1980, le travail sur Unix continua aux Laboratoires Bell. La série V a été poussée plus loin par le CRG (Stroustrup mentionne V10 dans la seconde édition de son livre sur le C++), mais on ne parla pas beaucoup de cela par la suite. La société maintenant responsable d'Unix (le Système V) est appelée Unix System Laboratories (USL) et appartient en majorité à AT&T. Novell a acheté USL (au début de 93) et il a donné des droits à la marque déposée "UNIX" à X/Open (à la fin de 93). Mais des changements sont encore survenus sur Unix en dehors d'AT&T, particulièrement à Berkeley. 6  Le projet alternatif GNU Hurd propose un autre noyau à celui de GNU Linux mais celui-ci n’a jamais eu autant de succès que Linux. http://www.gnu.org/software/hurd/hurd.html
  • 7.
  • 8.
    FORMATION LINUX Petit historique deLinux  1991: Le noyau Linux est écrit à partir de zéro (from scratch) en 6 mois par Linus Torvalds dans sa chambre de l'université d'Helsinki, afin de contourner les limitations de son PC 80386.  1991: Linus distribue son noyau sur Internet. Des programmeurs du monde entier le rejoignent et contribuent au code et aux tests.  1992: Linux est distribué sous la licence GNU GPL  1993 : Première distribution Slackware avec le noyau 0.99  1994: Sortie de Linux 1.0  1994: La société Red Hat est fondée par Bob Young et Marc Ewing, créant ainsi un nouveau modèle économique basé sur une technologie OSS.  1995-: GNU/Linux et les logiciels libres se répandent dans les serveurs Internet.  2001: IBM investit 1 milliard de dollars dans Linux  2002-: L'adoption massive de GNU/Linux démarre dans de nombreux secteurs de l'industrie. 8  Linux 2.6.32 : 12 Millions SLOC
  • 9.
    FORMATION LINUX Petit historique deLinux 9  Crée par Linus Torvalds en 1991 pour ses besoins personnels:  découvrir les entrailles des systèmes d'exploitation  pas de UNIX financièrement accessible à l'époque  insuffisances et inertie de Minix  Choix de l'environnement GNU  outils de développement (compilateur, ...)  outils système (bash, ls, cp...)  Publication des sources sur Internet  Choix de la licence GPL (oblige a redistribuer le code issu des modifications) Linux : LINUs + uniX
  • 10.
    FORMATION LINUX Linux : premiercontact Path: gmdzi!unido!fauern!ira.uka.de!sol.ctr.columbia.edu!zaphod.mps.ohio-state.edu! wupost!uunet!mcsun!news.funet.fi!hydra!klaava!torvalds From: torva...@klaava.Helsinki.FI (Linus Benedict Torvalds) Newsgroups: comp.os.minix Subject: What would you like to see most in minix? Summary: small poll for my new operating system Keywords: 386, preferences Message-ID: <1991Aug25.205708.9541@klaava.Helsinki.FI> Date: 25 Aug 91 20:57:08 GMT Organization: University of Helsinki Lines: 20 Hello everybody out there using minix – I'm doing a (free) operating system (just a hobby, won't be big and professional like gnu) for 386(486) AT clones. This has been brewing since april, and is starting to get ready. I'd like any feedback on things people like/dislike in minix, as my OS resembles it somewhat (same physical layout of the file-system (due to practical reasons) among other things). I've currently ported bash(1.08) and gcc(1.40), and things seem to work. This implies that I'll get something practical within a few months, and I'd like to know what features most people would want. Any suggestions are welcome, but I won't promise I'll implement them :-) Linus (torva...@kruuna.helsinki.fi) PS. Yes - it's free of any minix code, and it has a multi-threaded fs. It is NOT portable (uses 386 task switching etc), and it probably never will support anything other than AT-harddisks, as that's all I have :-(. Premier post effectué par Linux Torvald sur le forum Usenet (newsgroup) : http://www.minix3.org/ 10
  • 11.
  • 12.
    FORMATION LINUX Organisation du développement LinusTORVALD Le décideur et responsable du projet, propriétaire du nom "Linux". Andrew MORTON Adjoint au projet, le numéro 2 Alan COX responsable de la partie réseau Russell KING responsable de l'architecture ARM Andi KLEEN responsable de l'architecture x86-64 Alexander Viro David Miller CORE MAINTENERS Greg Kroah- Hartman SuSE Labs etc … 12
  • 13.
    FORMATION LINUX Gestion et organisationdu projet  http://opensource.mit.edu/papers/dafermoslinux.p df  http://catb.org/~esr/writings/cathedral-bazaar/ Organisation de la gestion du projet GNU Linux à partir de Linus Torvald. 13
  • 14.
  • 15.
    FORMATION LINUX Le processus dedéveloppement  Le code remonte de la base à Linus Torvalds :  Les développeurs de base proposent leurs modifications : • Elles sont débatues sur la LKML (Linux Kernel MailList) ; • Des aller-retours avec les responsables de sous systèmes permettent de les rafiner : Linus Torvalds intervient parfois dès ce stade ;  Les modifications solides et très demandées sont intégrées à l'arbre d'Andrew Morton pour plus de tests (après discussions) :  Plus de visibilité, tests et commentaires, dont ceux de Torvalds,  Le code est intégré s'il est prouvé solide, élégant et utile (Linux Torvalds définit son rôle de décideur comme « le pouvoir de dire non ») ;  Un processus souvent plus chaotique que cette description idéalisée. http://vger.kernel.org/vger-lists.html 15  http://www.kernel.org/pub/linux/docs/lkml/  http://lkml.org/  http://vger.kernel.org/vger-lists.html  http://en.wikipedia.org/wiki/Linux_kernel_mailing_list
  • 16.
    FORMATION LINUX Les développeurs dunoyau " Un travail de longue durée par une équipe de Geeks / Nerds / professionnels passionnés. " 16
  • 17.
    FORMATION LINUX Le processus dedéveloppement  Le développement du noyau « mainline » :  Une fenêtre d'ajouts de fonctionnalités (merge window) : • Durée d'environ 2 semaines, • Clôture officielle par la sortie d'une pré-version -rc1, • Parfois, des oublis contaminent la pré-version suivante ;  Une période de stabilisation : • Seulement des corrections, • Un -rc par semaine environ jusqu'à la stabilité apparente, • Un objectif à 2 mois (en pratique, jusqu'à 3) ;  Sortie de la version officielle :  Cette version est rarement parfaite,  Maintien d'une liste de régressions par Michal Piotrowski (http://kernelnewbies.org/known_regressions).  Quelques chiffres :  Nouvelle release tous les 2 mois et 1/2  2,89 changement par heure  8,2 millions de ligne de code  2000 lignes de code ajoutés tous les jours  2800 lignes modifiés chaque jour 17
  • 18.
    FORMATION LINUX Acteurs professionnels dunoyau Linux http://www.kernel.org/pub/linux/kernel/people/gregkh/kernel_history/ 18 Plus de 3200 développeurs tous les 2 ans et demi
  • 19.
    FORMATION LINUX Croissance du noyauGNU Linux  La version 2.6.32 du noyau a été publiée le 2 décembre 2009 19 10% de croissance 2.89 changements par heure 8.2 million de lignes de code 2000 ligne de code ajoutés chaque jour 2800 ligne de code modifiés chaque jour 7 jours sur 7 et 24 heures sur 24 : linux est un projet mondial en continuelle évolution.
  • 20.
    FORMATION LINUX Quelques branches dedéveloppements  Les architectures alternatives :  ARM : http://www.arm.linux.org.uk/  MIPS : http://www.linux-mips.org/  SH4 : http://sourceforge.net/projects/linuxsh  Power PC : http://penguinppc.org/  uClinux : http://www.uclinux.org/ (destiné aux microcontroleurs)  Quelques branches de développement :  USAGI (IPv6) : http://www.linux-ipv6.org/  les ordonnanceurs expérimentaux : • SD : http://members.optusnet.com.au/ckolivas/kernel/ • CFS : http://people.redhat.com/mingo/cfs-scheduler/  RT-preempt : http://people.redhat.com/~mingo/realtime-preempt/  Des projets comme Google Android ont un clone du repository du noyau linux. 20
  • 21.
    FORMATION LINUX Caractéristiques principales deLinux  Noyau monolitique (pas de micro-noyau) : tout le code du noyau tourne sur le même espace d’adressage. Les briques indépendament les unes des autres.  Multi-tâches (préemptif à partir de 2.6) : possibilité de gérer plusieurs processus en parallèle ;  Réentrant : possibilité d’appels concurrents (entre processeurs sur machines SMP, entre gestionnaire d’IRQ et appels systèmes) ;  Multi-processeurs : support SMP  Multi-utilisateurs : possibilité d’avoir plusieurs utilisateurs connectés en parallèles ;  Multi-plateforme (portabilité et support matériel) : voir liste des processeurs supportés ;  Scalabilité : tourne aussi bien sur des devices embarqués , que sur des super calculateur comme les célèbres CRAY ;  Conformité et interropabilité : avec les standards POSIX, CIFS, etc … ;  Support réseau : pile très complète (issue de BSD) ;  Sécurité : grsecurity, selinux, revues de code (couvertures) ;  Robustesse : code stable et fiable grace au travail de la communauté ;  Licence : logiciel libre mais couvert par la GPL ; code source indépendant des Unix commerciaux ;  Modularité : possibilité de chargement de modules en dynamique. 21
  • 22.
    FORMATION LINUX Portabilité  Il estdéveloppé principalement en langage C (pas de langage objet tel que le C++) avec une légère couche en assembleur. Ce découpage est hérité directement du système MINIX qui a inspiré Linus Torvald dès la version 0.01 du noyau GNU Linux.  Pour les portages sur une nouvelle architecture, il convient donc d'adapter cette dernière.  En résumé, ce qui est propre à une architecture donnée est localisé dans le répertoire arch/ des sources du noyau.  Minimum: processeurs 32 bits avec ou sans MMU (Memory Management Unit)  Architectures 32 bits: alpha, arm, cris, h8300, i386, m68k, m68knommu, mips, parisc, ppc, s390, sh, sparc, um, v850  Architectures 64 bits: ia64, mips64, ppc64, sh64, sparc64, x86_64  Voir arch/README ou Documentation/arch/README pour plus de détails. 22
  • 23.
    FORMATION LINUX Numérotation des versionsdu noyau Linux Les versions sont numérotées : XX.YY.ZZ.KK XX : le numéro majeur définit la version. YY : le numéro mineur de la version :  Avant la version 2.6, ce numéro désignait le type de la version : s’il était impaire la version était de développement et si elle était paire elle était stable ;  Désormais, il faut considérer que toute version doit être stable. Chaque version étant placé en branche avec Z comme numéro de version intermédiaire. Le début du développement est lancé par un premier gel des fonctionalités attendus (features freeze). A la fin de la période de développement, il y a un second gel (code freeze) des développements entrainant un merge vers la branche main ce qui donne une version pre- release. Ce merge lance l’étape de débug et de correction. Cela doit donner lieu à des versions intermédiaire appelés Release Candidate (RC). La version finale est la version dite stable. Cette version servira de référentiel initial pour les patchs successifs. XX.YY : Elle désigne une génération (ou branche) du noyau. ZZ : désigne la version dans la génération actuelle. KK : désigne les corrections de bugs (patchs) depuis XX.YY.ZZ 23 Arbre des versions
  • 24.
    FORMATION LINUX Evolutions des versions Linux 0.01 (août 1991) : La toute première  Linux 0.02 : Annonce officielle  Linux 1.0 (mars 1994)  x86 seulement,  Monolithique  Linux 1.2 (1995)  Ajout d'Alpha et Sparc  Linux 2.0 (mi-1996)  MIPS, Power PC, m68k  Modulaire  Multi-processeur  Linux 2.2 (janvier 1999)  Ultra Sparc et ARM  Linux 2.4 (janvier 2001)  IA64 (Itanium), MIPS64,  IBM S390 et SuperH  support grand systèmes  USB, PnP, hotplug,  firewall stateful  Linux 2.6 (fin 2003) Quelques versions majeures … 24  Linux 1.x / 2.0 / 2.2  Branche plus maintenue.  Linux 2.4  Mûr et exhaustif  Mais les développements sont arrêtés; peu de développeurs voudront apporter leur aide.  Sera définitivement obsolète lorsqu'un nouveau produit sera lancé.  Toujours bien si les sources, outils et support viennent de vendeurs Linux commerciaux.  Tend à devenir obsolète.  Linux 2.6 : la version courante  Supporté par la communauté de développeurs de Linux  Désormais mature et exhaustif. La plupart des pilotes ont été mis à niveau.  Toutes nouvelles fonctionnalités et performances accrues Etat actuelle des versions : http://www.linux-foundation.org/publications/
  • 25.
  • 26.
    FORMATION LINUX Nouveautés du noyau2.6  Un nouvel ordonnanceur de tâches, nommé O(1) a fait son apparition. Celui-ci tient beaucoup mieux la charge quand de nombreuses tâches concurrentes s'exécutent, et privilégie une répartition équitable du temps de calcul entre celles-ci.  Le noyau 2.6 est capable de gérer plus de 4 Go de mémoire physique sur des machines x86 32 bits.  Ce noyau apporte NPTL, une bibliothèque optimisée pour la gestion des threads POSIX et Futexes des sémaphores optimisées pour les processus.  L'interactivité du nouveau noyau a été largement améliorée. Ainsi, des modifications visant à diminuer le temps d'exécution des appels systèmes (patchs low-latency et preempt) ont été intégrés.  Simplification de devfs en udev.  La granularité de l'horloge (tick) est passée de 10 ms à 1 ms.  L'architecture ALSA, qui fournit un système avancé de gestion des cartes sons, a été intégrée au noyau, en lieu et place d'OSS.  Concernant les systèmes de fichiers, de nombreuses optimisations sont disponibles pour ext2/ext3/ext4 : EA, ACL, répertoires indéxés et allocateur Orlov.  Côté périphériques, plus besoin d'émuler un graveur IDE en SCSI pour graver. Notez également le support amélioré de l'USB 2 et de l'ACPI.  Une dernière amélioration très importante est l'incorporation d'un ordonnanceur intelligent des accès aux disques durs. Celui-ci limite très largement les déplacements de la tête de lecture du disque, et apporte des débits élevés en cas d'accès concurrents. 26
  • 27.
    FORMATION LINUX A propos deslogiciels libres  Le système d'exploitation GNU est un système complet de logiciels libres qui a une compatibilité ascendante avec Unix. « GNU » signifie « GNU's Not Unix ». Richard Stallman a fait l'annonce initiale du projet GNU en septembre 1983.  Le noyau GNU Linux est un Logiciel Libre qui a été rattaché à GNU un an après se création à savoir en 1992. La licence GPL2 auquel est rattaché Linux est maintenu et défendu juridiquement par le Free Software Fundation (FSF).  Pas de notions de gratuité mais plutôt de liberté.  Les logiciels Libres donnent à l'utilisateur 4 libertés (ou contraintes) : 1. La liberté d'utiliser le programme, comme bon lui semble ; 2. La liberté d'étudier comment le programme fonctionne, et de l'adapter à ses besoins ; 3. La liberté de redistribuer des copies pour aider les autres ; 4. La liberté d'améliorer le programme, et de distribuer les améliorations au public "Free software is a matter of liberty, not price. To understand the concept, you should think of free as in free speech, not as in free beer." http://www.gnu.org/philosophy/free-sw.html http://www.gnu.org/gnu/gnu-history.fr.html 27
  • 28.
    FORMATION LINUX La GNU GeneralPublic License (GPL)  Les licences Copyleft se reposent sur le droit d'auteur pour exiger que toute version modifiée reste un logiciel libre.  La GNU GPL requiert que les modifications et les travaux dérivés soient aussi placés sous GPL:  Ne s'applique qu'aux logiciels distribués (pas en test ou développement)  Tout programme utilisant du code GPL (lié statiquement ou dynamiquement) est considéré comme une extension de ce code et donc placé sous GPL  Pour plus de détails :  Copyleft: http://www.gnu.org/copyleft/copyleft.html  FAQ GPL: http://www.gnu.org/licenses/gpl-faq.html  Pour plus d'information pratique sur le sujet dans l'Union Européenne, contacter la Fondation pour une Infrastructure de l'Information Libre : http://ffii.org/index.en.html  Au jour d’aujourd’hui, Linux est rattaché à la GPL v2 depuis la version 2.4.0. Linus considère son rattachement à la GPL comme une étape décisive : "best thing I ever did".  Après une remarque d’Alan Cox, une enquête a été lancé en septembre 2006 auprès des développeurs du noyau. Il en a résulté une préférence de la GPLv2 face la version 3 pour des questions de restrictions. Selon les propres termes de Linux : "I think a number of outsiders... believed that I personally was just the odd man out, because I've been so publicly not a huge fan of the GPLv3". 28
  • 29.
    FORMATION LINUX Contraintes de licencesur le noyau Linux Exemple de contraintes au moment de distribuer :  Aucune contrainte avant toute distribution. Vous pouvez partager vos modifications au début dans votre propre intérêt, mais n'y êtes pas obligés !  Pour tout périphérique embarquant Linux et des Logiciels Libres, vous devez distribuer vos sources à l'utilisateur final. Vous n'avez aucune obligation de les distribuer à qui que soit d'autre !  Les modules propriétaires sont tolérés (mais non recommandés) tant qu'ils ne sont pas considérés comme dérivés de code GPL.  Le portage d'un code fonctionnant déjà sous un autre système d'exploitation peut être exempt de contamination avec la GPL.  Les pilotes propriétaires ne peuvent pas être liés statiquement au noyau.  Un pilote écrit de zéro est considéré comme une souche propre non contaminée.  Aucun soucis pour les pilotes disponibles sous une licence compatible avec la GPL (détails dans la partie sur l'écriture de modules)  S'appliquent aussi lorsque vous développez dans des pays libres de brevets. Il se peut que vous ne puissiez pas exporter vos produits.  Pilotes noyau avec brevets: vérifiez toujours la description du pilote dans la configuration du noyau Les problèmes avec des brevets connus sont toujours documentés.  Préférer toujours les alternatives sans brevets (Linux RTAI au lieu de RTLinux, etc.) 29
  • 30.
    FORMATION LINUX Modules binaires deLinux  Une clause supplémentaire à la licence GPL auquel est rattaché Linux permet l’utilisation et la distribution de modules binaires.  Elle doit utiliser uniquement l’interface standard des modules.  Il est cependant impossible de mettre à disposition de clients, des modules binaires compatibles avec toutes les configurations possibles du noyau (Version , patch externes, …. ).  Ce mode est légal juridiquement mais reste très déconseillé car aucune aide, ni de support n’est offert par la communauté. 30
  • 31.
    FORMATION LINUX Génération d’un noyauLinux BUT : savoir configurer et générer un noyau GNU Linux Phases pour la génération d'un noyau :  Récupération du code source du noyau  Vérification de l'intégrité des packages reçus  Application et génération de patchs  Génération d'une configuration  Compilation  Analyse des fichiers résultant  Installation
  • 32.
    FORMATION LINUX Paquets nécessaires pourla compilation  Pour installer le noyau 2.6.x, assurez-vous d'avoir les paquets suivants :  la librairie ncurses-5, certaines distributions l'appellent libncurses5 et libncurses5-dev (ou libncurses5-devel)  l'utilitaire bzip2  l'utilitaire gzip  Gnu gcc 2.95.3 (commande : gcc --version)  Gnu make 3.78 (commande : make --version)  binutils 2.12 (commande : ld -v)  util-linux 2.10 (commande : fdformat --version)  module-init-tools 0.9.10 (commande : depmod -V)  procps 3.1.13 (commande : ps --version)  gpg  Sous GNU Debian ou ubuntu il suffit d’installer le package build-essential 32
  • 33.
    FORMATION LINUX Récupération des sourcesofficiels 33 Plusieurs méthodes via différents protocoles :  HTTP  FTP  NFS  SMB / CIFS  GIT  RSYNC  Packages d’une distribution officielle (RPM, DEB, …. ) serveurs anciennement maintenus par la société Transmeta et gérés désormais par Linux Kernel Organisation (CA/USA). La homepage de kernel.org
  • 34.
    FORMATION LINUX Récupération des sourcesofficiels - http / ftp wget http://kernel.org/pub/linux/kernel/v2.6/linux-2.6.32.tar.bz et wget http://kernel.org/pub/linux/kernel/v2.6/linux-2.6.32.tar.bz.sign 34  Téléchargement des sources via http depuis le site http://www.kernel.org/pub/linux/kernel/v2.6/ : l peut être aussi nécessaire de récupérez une mise à jour (ensemble de correctifs) pour la version  A noter que deux formats sont disponibles : tar.gz et tar.bz2 ; pour chaque type d’archive, il y a une signature Associés. wget ftp://ftp.kernel.org/pub/linux/kernel/v2.6/patch-2.6.32.bz et wget ftp://ftp.kernel.org/pub/linux/kernel/v2.6/patch-2.6.32.bz.sign  Téléchargement des sources via ftp depuis le site ftp ://ftp.kernel.org/pub/linux/kernel/v2.6/ : Pour ce protocole,la méthode est similaire au http. Il vaut mieux utiliser ftp.xx.kernel.org où xx est votre code de pays, par exemple ftp.fr.kernel.org pour la France. Pour extraire les sources dans le répertoire officiel (/usr/src/) : tar -xjvf linux-2.6.32.tar.bz2 -C /usr/src
  • 35.
    FORMATION LINUX Vérification de l'intégritédes sources  Détails sur GnuPG: http://www.gnupg.org/gph/en/manual.html  Détails sur la signature des sources du noyau: http://www.kernel.org/signature.html 35 $ gpg --keyserver wwwkeys.pgp.net --recv-keys 0x517D0F0E gpg: requête de la clé 517D0F0E du serveur hkp wwwkeys.pgp.net gpg: clé 517D0F0E: clé publique « Linux Kernel Archives Verification Key <ftpadmin@kernel.org> » importée gpg: aucune clé de confiance ultime n'a été trouvée gpg: Quantité totale traitée: 1 gpg: importée: 1 $ gpg --verify linux-2.6.32.tar.sign linux-2.6.32.tar.gz gpg: Signature faite le jeu. 03 déc. 2009 07:28:51 CET avec la clé DSA ID 517D0F0E gpg: MAUVAISE signature de « Linux Kernel Archives Verification Key <ftpadmin@kernel.org> » $ gpg --verify linux-2.6.32.tar.gz.sign linux-2.6.32.tar.gz gpg: Signature faite le jeu. 03 déc. 2009 07:28:57 CET avec la clé DSA ID 517D0F0E gpg: Bonne signature de « Linux Kernel Archives Verification Key <ftpadmin@kernel.org> » gpg: ATTENTION: Cette clé n'est pas certifiée avec une signature de confiance ! gpg: Rien ne dit que la signature appartient à son propriétaire.Empreinte de clé principale: C75D C40A 11D7 AF88 9981 ED5B C86B A06A 517D 0F0E  Vérification correcte de l'intégrité de l’archive téléchargé par ftp ou http :  Exemple de vérification incorrecte : Il faudra au préalable importer la clef publique du projet gnu linux kernel :  Cette étape rarement effectuée est pourtant importante pour être sûr de l'intégrité du code source récupéré. Il en va de même pour tout autre package open-source. Elle se doit d’être effectué à la fois pour le code du noyau mais aussi pour les patch.
  • 36.
    FORMATION LINUX Récupération des sourcesofficiels - git 36  Téléchargement des sources via git :  git est un logiciel de gestion de versions décentralisé (comme mercurial) écrits par Linus Torvald en remplacement de bitKeeper qui ne voulait plus proposer de version gratuite de son produit en 2005. http://linux.yyz.us/git-howto.html http://www.kernel.org/pub/software/scm/git/ http://kernel.org/pub/software/scm/git/docs/git-clone.html $ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git linux-2.6  Cela va créer un répertoire linux-2.6 de plus de 300 Mo avec tous les sources du noyau. L’intérêt est d’avoir en une fois toutes les branches, évolution effectué sur le code source du noyau.  Petit memento d’usage de git :  Checkout : git checkout –f  Ajout ou suppression : git add ou git rm  Commit : git commit –a  Suppression les deux derniers commits : git reset HEAD^2  Différentiel depuis le dernier ajout/suppression: git diff  Différentiel depuis le dernier commit : git diff HEAD  Création d’une branche : git checkout –b ma-nouvelle-branch master  Résumé des opérations : git status  Résumé des changements : git log
  • 37.
    FORMATION LINUX Récupération des sourcesofficiels 37 Récupération de paquets officiels :  Mandriva urpmi kernel-headers kernel-source  Fedora yum install kernel-source  Debian apt-get install kernel-headers-$(uname -r) kernel-source-$(uname -r)  Ubuntu apt-get install linux-headers-N°_de_noyau linux-source-$(uname -r)  Slackware installpkg /où_est/kernel-source-2.6.x.tgz /où_est/kernel-headers-2.6.x.tgz  Gentoo emerge gentoo-sources
  • 38.
    FORMATION LINUX Application des patchs Commande patch: utilise la sortie (stdout) de la commande diff pour appliquer un ensemble de changements à une arborescence de fichiers sources.  Utilisation classique de patch :  patch -sp<n> < diff_file  cat diff_file | patch -sp<n>  bzcat diff_file.bz2 | patch -sp<n>  zcat diff_file.gz | patch -sp<n> n: nombre de niveaux de répertoires à sauter  Patches Linux:  Toujours à appliquer sur la version x.y.<z-1>  Toujours prévu pour n=1: patch -sp1 < linux_patch  A noter qu'il est possible d'inverser un patch de la façon suivante : patch -R -sp1 < ../patch-x.y.z  Pour retrouver les patchs ayant échoués : find . -name '*.rej' -print  A noter l’usage du paramètre ‘s’ permettant l’application d’un patch en mode silent ce qui fait gagner 30% de temps.  Pour tester un patch avant application, il suffit d’utiliser l’option –dry-run 38
  • 39.
    FORMATION LINUX Exemple d'application d'unpatch  Dump d'un Patch sur un fichier donné :  Exemple d'utilisation :  Applique dans ce cas les changements au header include/asm-arm/hardware.h. Un patch peut cependant être récursif et toucher donc un ensemble de fichiers. -pnombre : enleve le plus petit préfixe contenant nombre slashs de la tête de chaque nom de fichier trouvé dans le fichier patch. Une séquence d'un ou de plusieurs slashs adjacents compte pour un slash unique. Cela contrôle la façon dont les noms trouvés dans le fichier patch sont traités, au cas où vous conserveriez vos fichiers dans un répertoire différent de celui qui a envoyé le patch. Par exemple, en supposant que le nom du fichier dans le fichier patch était u/howard/src/blurfl/blurfl.c  Spécifier -sp0 donne le nom de fichier entier non modifié, -sp1 donne : u/howard/src/blurfl/blurfl.c  Sans le slash de tête, -sp4 donne : blurfl/blurfl.c  Ne pas spécifier de -sp du tout vous donne blurfl.c. Ce que vous obtenez finalement est recherché soit dans le répertoire courant, soit dans le répertoire spécifié par l'option -d. 39 --- linux-2.6.8.1/include/asm-arm/hardware.h 2004-08-14 12:54:48.000000000 +0200 +++ linux-2.6.8.1_modified/include/asm-arm/hardware.h 2004-08-17 12:42:06.119650556 +0200 @@ -15,13 +15,4 @@ #include <asm/arch/hardware.h> -#ifndef __ASSEMBLY__ - -struct platform_device; - -extern int platform_add_devices(struct platform_device **, int); -extern int platform_add_device(struct platform_device *); - -#endif - #endif $ cd linux-2.6.8.1 $ patch -sp1 < hardware.diff
  • 40.
    FORMATION LINUX Création d'un patchnoyau  Téléchargez la dernière version des sources du noyau sur lequel vous travaillez.  Faites une copie de ces sources : rsync -a linux-2.6.9-rc2/ linux-2.6.9-rc2-patch/  Appliquez vos modifications aux sources copiés et testez les.  Créez un fichier correctif («patch») : diff -Nru linux-2.6.9-rc2/ linux-2.6.9-rc2-patch/ > patchfile  Patchfile doit suivre une charte de nommage rappelant la version du noyau prise comme référence, le(s) bug(s) corrigé(s).  Comparez toujours la structure complète des sources (utilisable par patch -sp1) Nom du fichier correctif: doit rappeler le problème résolu 40 La commande diff effectuant un différentiel récursif entre un ou plusieurs fichiers, les patchs doivent être regénérés pour chaque version de kernel du fait de l'évolution du code source du noyau Linux.
  • 41.
    FORMATION LINUX Utilisation de quilt 41 $tar -zxf linux-2.6.19.tar.gz $ cd linux-2.6.19 $ mkdir patches $ quilt new patch1  Ajout d’un patch Patch patches/patch1 is now on top $ quilt add Makefile  Ajout du Makefileà quilt File Makefile added to patch patches/patch1  Modification du Makefile $ quilt refreshRefreshed patch patches/patch1  Mise à jour du patch cat patches/patch1  Affichage du patch courant Index: linux-2.6.19/Makefile =================================================================== --- linux-2.6.19.orig/Makefile +++ linux-2.6.19/Makefile@@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 19 -EXTRAVERSION = +EXTRAVERSION = -dirty NAME=Crazed Snow-Weasel # *DOCUMENTATION* Modifications successives $ quilt series –v  Affiche la série de patch + patches/patch1 http://linux.die.net/man/1/quilt http://www.suse.de/~agruen/quilt.pdf Démonstration par l’exemple :
  • 42.
    FORMATION LINUX Utilisation de ketchup 42 http://www.selenic.com/ketchup/ Ketchup est un script écrit en python permettant de passer une version linux donnés à une autre en téléchargeant les patchs nécessaires.  Il peut aussi bien avancer dans les versions suivantes que dans les versions précédentes.  Il vérifié aussi les signatures des sources mais aussi des patch. Exemple d’usage :  Se placer dans le répertoire des sources du noyau : $ cd linux-2.6.32  Vérifier la version courante du noyau : $ ketchup –m 2.6.32  Aller à la dernière version : $ ketchup –G 2.6-tip  Aller à une version précédente : $ ketchup –G 2.6.28  L’option –G désactive la vérification des signatures  Le script ketchup doit être présent dans le path courant (/usr/bin/ketchup). De plus, il est nécess Qu’un accès internet soit disponible.
  • 43.
    FORMATION LINUX Remonter un bugdu noyau Linux  Premièrement, assurez vous d'utiliser la dernière version : intérêt de git permettant des différentiel inter-version.  Assurez vous d'avoir creusé le problème autant que possible: voir Documentation/BUG-HUNTING  Assurez vous que le bogue n'a pas encore été signalé. Vérifiez en particulier la base de donnée officielle des bogues Linux(http://bugzilla.kernel.org/).  Si le sous-système pour lequel vous reportez un bogue a une liste de diffusion, utiliser la. Sinon, contactez le mainteneur officiel (voir le fichier MAINTAINERS). Donnez toujours le plus de détails possible.  Ou remplissez un nouveau bogue dans http://bugzilla.kernel.org/ 43
  • 44.
    FORMATION LINUX Configuration du noyau Éditer le Makefile pour définir la version et l'architecture de la cible (si nécessaire) :  La commande uname –r retournera : 2.6.32-montag  Configuration : définir quelles fonctionnalités mettre dans le noyau. Plusieurs méthodes peuvent être utilisées :  Pour récupérer la configuration actuelle d'un noyau 2.6 : Option non disponible par défaut. Seulement si le kernel a été compile avec l'option : CONFIG_IKCONFIG_PROC = y make config mode texte) make menuconfig interface ncurses) make allnoconfig positionne automatiquement toutes les options à no make allyesconfig positionne automatiquement toutes les options à yes make randconfig configure le noyau de façon aléatoire make oldconfig chargement d'une ancienne configuration make xconfig interface X utilisant le librairie graphique Qt/KDE make gconfig interface X utilisant la librairie graphique de GNOME  Il est aussi possible d'éditer la configuration à la main Pour identifier l'image de votre noyau avec d'autres, compilées à partir des même sources, utilisez la variable EXTRAVERSION: VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 7 EXTRAVERSION = -montag sudo zcat /proc/config.gz > /usr/src/linux/.config 44
  • 45.
    FORMATION LINUX Configuration en modetexte  make menuconfig : Interface texte sous ncurses. Pratique également. Vous pouvez aussi éditer le fichier .config à la main ! Attention cependant aux dépendances.  make oldconfig Permet de mettre à jour un fichier de config d'un ancien noyau Mise en garde pour les symboles optionnels Demande les valeurs des nouveaux symboles  make config : mode texte, ou on choisit une à une toutes les options (c'est à dire des centaines !), sans possibilité de retour arrière. Très fastidieux. Déconseillé. 45  Il faudra d'abord installer le paquet libncurses-dev
  • 46.
    FORMATION LINUX Configuration en modegraphique  make xconfig :  qconf: nouvelle interface Qt de configuration pour Linux 2.6. Bien plus facile à utiliser !  Lisez help -> introduction: vous y trouverez des options utiles!  Navigateur de fichiers: plus simple de charger les fichiers de configuration  Il faudra d'abord installer les paquets libqt3-mt-dev et g++  Il faudra d'abord installer le paquet liglade2-dev.  make gconfig : Identique à xconfig, mais avec les bibliothèques graphiques de gnome (GTK). 46
  • 47.
    FORMATION LINUX Fichier de configurationdu noyau 47 ## CD-ROM/DVD Filesystems #CONFIG_ISO9660_FS=m CONFIG_JOLIET=y CONFIG_ZISOFS=y CONFIG_UDF_FS=y CONFIG_UDF_NLS=y ## DOS/FAT/NT Filesystems ## CONFIG_MSDOS_FS is not set # CONFIG_VFAT_FS is not set CONFIG_NTFS_FS=m # CONFIG_NTFS_DEBUG is not set CONFIG_NTFS_RW=y Extrait de fichier .config généré  Tous les nom de paramètres sont préfixés par CONFIG_ Compilé comme un module dans un fichier .ko séparé : Options du drivers : Compilé statiquement dans le noyau :
  • 48.
    FORMATION LINUX Fichier de configurationdu noyau 48  La configuration du noyau inclus un système de dépendances entre les options : Exemple : l’activation d’un driver réseau active la pile réseau  Il existe deux types de dépendances :  Dépendance sur dépendances : une option A dont dépend B reste invisible tant que B n’est pas Activé  Sélection de dépendance : avec une option A dépendant de B, quand A est activé, B est automatiquement activé également.  make xconfig perment d’afficher toutes les options même celles qui ne sont pas active. Dans cette version, les options inactive sont juste grisés.  Optimisations :  Cette phase de configuration est importante pour choisir les drivers à inclure dans le noyau.  Il faut éviter de laisser des drivers inutile car cela augmente la taille du noyau  La part de drivers compilés en statique face aux modules dynamique doit être prise en compte au sujet du temps de chargement du noyau en mémoire. Il en va aussi de l’initialisation.  Trop de drivers compilés en statique inclu une phase de chargement longue sauf si XIP et AXFS sont utilisés (eXecute In Place). http://elinux.org/AXFS http://www.scribd.com/doc/19855245/Application-eXecuteInPlace-XIP-with-Linux-and-AXFS
  • 49.
    FORMATION LINUX Positionner les options Le moment est venu de choisir vos options. Si c'est la première fois que vous compilez le noyau, je vous conseille de les passer toutes en revue les unes après les autres en lisant l'aide qui y est attachée, dans l'ordre, afin de voir si elles s'appliquent à vous ou non.  Dans l'outil de configuration du noyau, chaque question attend une réponse :  'oui' (Y),  'non' (N)  ou éventuellement 'module' (M) pour rendre la fonctionnalité chargeable dynamiquement.  De manière générale, il est bon de modulariser les fonctionnalités qui ne servent pas en permanence (lecteur de CD, carte réseau, clefs USB, ...), mais tout n'est pas possible (enfin... pas simplement :).  Par exemple, vous ne devriez pas mettre en module ce qui est utilisé lors du démarrage de votre ordinateur (pilotes des disques-durs IDE, système de fichiers que vous utilisez pour votre partition /, ou encore le support réseau si votre partition racine est montée par le réseau et NFS dans le cas des stations diskless par exemple, etc). En effet, les modules sont chargés après le noyau, et si les modules IDE sont sur un disque IDE, il faut d'abord les charger avant de pouvoir accéder au disque, mais pour les charger, il faut avoir accès au disque et donc les avoir chargés avant... vous voyez le cercle vicieux ? En fait, il est possible de contourner ce problème grâce à initrd, mais cela dépasserait l'ambition de ce document…  Tout le reste peut être compilé en modules, c'est à dire carte son, carte réseau (sauf si votre racine est déportée sur un serveur NFS comme dit précédemment), le support ppp (pour internet par modem), le CD-ROM, …  Quoi qu'il arrive, dans le doute, il vaut mieux laisser les options par défaut.  Les options correspondent à des fonctionnalités que vous pouvez activer/désactiver dans le noyau suivant vos besoins. Elles sont organisées suivant différentes sections et sous-sections, nous allons ici décrire les principales sections qui existent et en donner une brève description pour vous donner une idée des options qu'elles peuvent contenir.  Il est important de noter que d'une version à l'autre du noyau, les options, sous-sections ou même les sections peuvent changer, mais l'idée générale reste conservée.  Le fichier .config contient un ensemble d’éléments dépendante d’une architecture.  Sans définition particulière, le système de génération du noyau linux génèrera un noyau compatible avec le host 49
  • 50.
    FORMATION LINUX Sections des optionsdu noyau  Les options section par section :  Code maturity level options: Permet de cacher ou de faire apparaître les options qui sont encore en développement et donc considérées comme instables (souvent utile de dire 'oui' ici si l'on veut pouvoir profiter des dernières avancées du noyau).  General setup: Ensemble d'options générales sur votre système (sauf si vous voulez compiler pour des architectures très particulières, vous pouvez le laisser tel quel).  Loadable module support: Options concernant la gestion des modules (le défaut est presque toujours correct pour une utilisation normale).  Block layer: Les entrées/sorties sur votre carte-mère (peut être supprimé pour un usage embarqué)  Processor type and features: Options relatives au(x) processeur(s): type (x86, Sparc, ...), hyper-thread, dual-core, SMP, etc.  Power management options (ACPI, APM): Options concernant l'économie d'énergie, la mise en veille et l'ACPI/APM.  Bus options (PCI, PCMCIA, EISA, MCA, ISA): Gestion de tous les endroits où vous pourriez enficher des cartes (PCI, PCMCIA, ISA, etc).  Executable file formats: La gestion des fichiers exécutable (Le support ELF doit toujours être à 'Y').  Networking: Options concernant les protocoles réseau gérés par votre noyau (le défaut est bien souvent suffisant, mais jetez y un coup d'œil à tout hasard).  Device Drivers: Options concernant tous les pilotes matériel (c'est bien souvent ici que l'on passe le plus de temps).  File systems: Options concernant les systèmes de fichiers gérés par votre noyau (vous aurez à y jeter un coup d'oeil).  Instrumentation Support: Option de profilage du noyau (inutile de l'activer).  Kernel hacking; Options de débogage du noyau (inutile de l'activer sauf si vous avez des envies particulières).  Security options: Options concernant le modèle de sécurité de votre noyau (le défaut est suffisant)  Cryptographic options: Algorithmes cryptographiques pouvant être implantés dans le noyau (le défaut est suffisant).  Library routines: Bibliothèques communes du noyau (le défaut est suffisant) @ 50 Ce listing étant parsé dynamiquement pour l’affichage, toute interrogation sur une option pourra être complété par l’analyse du répertoire associé.
  • 51.
    FORMATION LINUX Connaissance du matériel  PCI: lspci lspci -t ou lspcidrake (sous mandrake) 01:00.0 VGA compatible controller: nVidia Corporation NV34M [GeForce FX Go 5200] (rev a1) (prog-if 00 [VGA]) Subsystem: Samsung Electronics Co Ltd: Unknown device c00f Flags: bus master, 66Mhz, medium devsel, latency 248, IRQ 11 Memory at c8000000 (32-bit, non- prefetchable) [size=16M] Memory at d8000000 (32-bit, prefetchable) [size=128M] Expansion ROM at <unassigned> [disabled] [size=128K] Capabilities: [60] Power Management version 2 Capabilities: [44] AGP version 3.0  DMI (Desktop Management Interface) : dmidecode [...] DMI type 2, 8 bytes. Board Information Block Vendor: ASUSTeK Computer INC. Product: P4S8L Version: REV 1.xx Serial Number: xxxxxxxxxx [...]  Disques IDE : hdparam hdparm -i /dev/hda /dev/hda: Model=FUJITSU MHT2040AT, FwRev=0022, SerialNo=NN77T3C13KB9 Config={ HardSect NotMFM HdSw>15uSec Fixed DTR>10Mbs } RawCHS=16383/16/63, TrkSize=0, SectSize=0, ECCbytes=4 BuffType=DualPortCache, BuffSize=2048kB, MaxMultSect=16, MultSect=16 CurCHS=16383/16/63, CurSects=16514064, LBA=yes, LBAsects=78140160 IORDY=yes, tPIO={min:240,w/IORDY:120}, tDMA={min:120,rec:120} PIO modes: pio0 pio1 pio2 pio3 pio4 DMA modes: mdma0 mdma1 mdma2 UDMA modes: udma0 udma1 udma2 udma3 udma4 *udma5 AdvancedPM=yes: mode=0x80 (128) WriteCache=enabled Drive conforms to: ATA/ATAPI-6 T13 1410D revision 3a: 51 La connaissance de son matériel permet de bien configurer son noyau :
  • 52.
    FORMATION LINUX Connaissance du matériel  PROCESSEUR: cat /proc/cpuinfo  USB : lsusb  HARDWARE : lshw  APCI : cat /proc/acpi/info cat /proc/acpi/battery/BAT1/info cat /proc/acpi/thermal_zone/THRM/temperature /proc/acpi/thermal_zone/THRM/trip_points  Il faut aussi regarder les messages du noyau : dmesg  Quelques liens :  http://rhlinux.redhat.com/kudzu/  http://www.freedesktop.org/wiki/Software/hal  http://www.linux.org/apps/AppId_4812.html  http://ezix.org/project/wiki/HardwareLiSter  http://ezix.sourceforge.net/software/lshw.html  http://smartmontools.sourceforge.net/  http://www.nongnu.org/dmidecode/  http://secure.netroedge.com/~lm78/  http://www.nt.phys.kyushu-u.ac.jp/shimizu/download/download.html 52
  • 53.
    FORMATION LINUX Compilation du noyau Pour une compilation croisée (pour une autre architecture) il faut modifier la plateforme cible par défaut :  Compilation : make  Phase la plus longue (Ex: 45 minutes pour compiler un noyau 2.6.15.4 (38 Mo compressé) sur un portable Pentium 4 3,2 GHz avec 512 Mo de RAM).  Pour compiler depuis un autre répertoire, il est possible de préciser le répertoire : make –C /linuxdir  Possibilité de cumuler plusieurs action sur une seule commande : make && make install ou bien : make ; make install  Nettoyage :  make clean : nettoye les fichiers générés (force la recompilation des drivers)  make mrproper : même action que le make clean mais supprime aussi le .config  make distclean : nettoye toute l’arborescence de fichiers temporaires issue des editeurs et des applications de patch (au lieu de faire soit même : find . -name '*.orig' | xargs rm) (surtout utile pour la création de patchs)  En version 2.4, il fallait faire : make dep && make clean && make bzImage puis make modules  Les commandes suivantes ne sont plus nécessaires en 2.6 : make depends ARCH ?= arm CROSS_COMPILE ?= arm-linux- (préfixe du compilateur croisé) Ou bien définit les variables en même temps que make ARCH=arm CROSS_COMPILE=arm-linux- (Utile quand vous compilez pour différentes plateformes) Voir les commentaires dans les Makefile du noyau Linux pour plus de détails 53
  • 54.
    FORMATION LINUX Installation du noyau Autres commandes du makefile :  make prepare : adapte le fichier version.h et crée un lien symbolique de include/asm vers include/asm-<ARCH>.  make script : compile des outils  make bzImage : crée une image compressée le noyau dans arch/<ARCH>/boot/bzImage  make fdimage : crée une image à destination d’une disquette 1.44 Mo  make modules : lance la compilation des modules (l’option doit avoir été activée).  make isoimage : crée une image ISO pour CDROM bootable dans arch/<ARCH>/boot/image.iso  make uImage : crée une image pour uBoot dans arch/<ARCH>/boot/uImage (nécessite d’avoir le binaire d’uBoot mkimage dans le path ; ce binaire étant utilisé par le scriptscript/mkuboot.sh).  Exemple de compilation d’un noyau pour l’architecture STM (coeur ST40) : make –j5 -C=/tmp/linux_src/ ARCH=sh CROSS_COMPILE=sh4-linux- make –j5 -C=/tmp/linux_src/ ARCH=sh CROSS_COMPILE=sh4-linux- uImage  Installation (en tant que root !) :  sudo make install : install le noyau  sudo make modules_install : install les modules dynamiques dans /lib/`uname -r`/kernel/drivers/  Bien évidemment, pour l’installation, il faut garder les paramètres d’architecture : make ARCH=arm CROSS_COMPILE-arm-linux- install  Pour spécifier un chemin d’installation des modules, il est possible de préciser un path: make INSTALL_MOD_PATH=$ROOTFS_PATH/usr/lib modules_install 54 http://www.denx.de/wiki/DULG/LinuxConfiguration http://pyfourmond.free.fr/Compilation-Noyau-Linux.htm#prerequis
  • 55.
    FORMATION LINUX Optimisation de laphase de compilation  Adapter la configuration de votre noyau en ne choisissant que les modules nécessaires à votre matériel. Cela peut diviser le temps de compilation par 30 et gagner des Mo.  Compiler plusieurs fichiers en parallèle : make -j <nombre> Lance plusieurs compilations en parallèle, autant que possible  make -j 4 Plus rapide même sur les machines uniprocesseur ! Moins de temps perdu à lire ou écrire les fichiers (les autres processus occupent le processeur)  Pas utile de dépasser 4 (trop de changements de contexte)  make -j <4*number_of_processors>  make V=n : pour lancer la compilation en mode détaillée / Verbose (gcc, ld) (n=0 : silencieux et n=1 : détaillé)  make C=n : pour lancer la vérifications des dépendances des codes sources en C (n=1 : vérification normale et n=2 : force la vérification)  Surtout utile sur des machines ayant plusieurs processeurs ou plusieurs core interne au cpu. 55
  • 56.
    FORMATION LINUX Fichiers résultants d’unecompilation  vmlinux  Image brute du noyau Linux au format ELF, non compressée.  Version utilisé entre autre pour le debug ou le profiling (Oprofile)  Habituellement sur les Unix, le noyau s’appelle unix ; avec le développement de la mémoire virtuelle, le préfix « vm » s’est imposé.  Le nom vmlinux est la mutation de vmunix avec vmlinuz. Cependant, le « z » aurait pu sous-entendre qu’il est compressé ce qui n’est justement pas le cas.  Fichier de mapping des symboles System.map  Listes des adresses des symboles des primitives inclues dans le noyau linux compilé  arch/<arch>/boot/zImage  Image du noyau compressée avec l’algorithme zlib.  Depuis la version 2.6.30 les algorithmes de compression LZMA ou BZIP2 sont disponibles.  arch/<arch>/boot/bzImage  Image du noyau compressée aussi avec zlib. Généralement suffisamment petite pour tenir sur une disquette ! Image par défaut sur i386  arch/<arch>/boot/uImage  Image du noyau pour le bootloader uBoot. Si la compilation arrive au bout, les fichiers suivants sont générés : 56
  • 57.
    FORMATION LINUX Le noyau linux: vmlinux  La commande « file vmlinux » donne certaines informations sur le noyau linux : vmlinux: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, not stripped 57  La commande « objdump –dS vmlinux » donne aussi des détail intéressant : vmlinux: file format elf32-i386 Disassembly of section .text.head: c0100000 <_text>: */ .section .text.head,"ax",@progbits ENTRY(startup_32) /* test KEEP_SEGMENTS flag to see if the bootloader is asking us to not reload segments */ testb $(1<<6), BP_loadflags(%esi) c0100000: f6 86 11 02 00 00 40 testb $0x40,0x211(%esi) jnz 2f c0100007: 75 14 jne c010001d <_text+0x1d>  La commande « readelf -h vmlinux » est aussi instructive : ELF Header: Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 Class: ELF32 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: EXEC (Executable file) Machine: Intel 80386 Version: 0x111:31 Entry point address: 0x1000000 Start of program headers: 52 (bytes into file) Start of section headers: 1299456 (bytes into file) Flags: 0x0 Size of this header: 52 (bytes) Size of program headers: 32 (bytes) Number of program headers: 3 Size of section headers: 40 (bytes) Number of section headers: 20 Section header string table index: 17
  • 58.
    FORMATION LINUX Le noyau linux: bzimage 58 ANATOMIE D’UNE IMAGE BZIMAGE Le format bzImage a été crée pour répondre à l’accroissement de la taille du noyau linux au fil des années. En effet, sur certain système l’espace de stockage peut être limité. Le format bzImage contient la concaténation des objets : bootsect.o + setup.o + misc.o + piggy.o piggy.o contient le fichier vmlinux gzippé dans la section data de son entête ELF.
  • 59.
    FORMATION LINUX Le noyau linux: bzimage  Il n’y a pas d’outils spécifique pour décompresser l’image bzImage, mais le script suivant décompresse l’image et en extrait sa configuration : 59 #! /bin/bash -x # extracts .config info from a [b]zImage file # uses: binoffset (new), dd, zcat, strings, grep # $arg1 is [b]zImage filename HDR=`binoffset $1 0x1f 0x8b 0x08 0x0` PID=$$ TMPFILE="$1.vmlin.$PID" # dd if=$1 bs=1 skip=$HDR | zcat - | strings /dev/stdin # | grep "[A-Za-z_0-9]=[ynm]$" | sed "s/^/CONFIG_/" > $1.oldconfig.$PID # exit dd if=$1 bs=1 skip=$HDR | zcat - > $TMPFILE strings $TMPFILE | grep "^[#[:blank:]]*CONFIG_[A-Za-z_0-9]*" > $1.oldconfig.$PID wc $1.oldconfig.$PID rm $TMPFILE $ cd scripts/ $ gcc binoffset.c -o binoffset $ export=`pwd`:$PATH  Il faudra au préalable compiler l’utilitaire binoffset dont le source est dans le répertoire script/  Quelques distribution comme RedHat fournissent une copie du noyau vmlinux dans le répertoire : /usr/lib/debug/lib/modules/`uname -r`/vmlinux
  • 60.
    FORMATION LINUX Le noyau linux: uImage (pour uBoot) 60  Commande pour générer une image uImage non-compressée : mkimage -A arm -O linux -C none -T kernel -a 20008000 -e 20008000 -n linux-2.6 -d arch/arm/boot/Image uImage  Commande pour générer une image uImage non-compressée : mkimage -A arm -O linux -C none -T kernel -a 20008000 -e 20008000 -n linux-2.6 -d arch/arm/boot/zImage uImage  Commandes de génération : http://docs.blackfin.uclinux.org/doku.php?id=bootloaders:u-boot:uimage http://docs.blackfin.uclinux.org/doku.php?id=bootloaders:u-boot:serial_port_loading_files $ gzip -9 vmlinux $ mkimage -A blackfin -O linux -T kernel -C gzip -n 'My Linux Image' -a 0x1000 -e 0x1000 -d vmlinux.gz vmImage  Pour créer une image avec une image compressé avec gzip :
  • 61.
    FORMATION LINUX Fichiers installés  makeinstall /boot/vmlinuz-<version> Image du noyau /boot/System.map-<version> Stocke les adresses des symboles (primitives systèmes) du noyau /boot/initrd-<version>.img Initial RAM disk, contenant les modules nécessaires pour monter le système de fichier root. make install lance mkinitrd si nécessaire. /etc/grub.conf ou /etc/lilo.conf make install met à jour les fichiers de configuration de votre bootloader pour supporter votre nouveau noyau ! Il relance /sbin/lilo si LILO est votre bootloader.  make modules_install /lib/modules/<version>/ Modules noyau et autres fichiers build/ Tout ce qui est nécessaire pour construire des modules pour ce noyau: fichier .config (build/.config), informations sur les symboles des modules(build/module.symVers), headers du noyau (build/include/) kernel/ Fichiers modules .ko (Kernel Object), avec la même structure de répertoires que dans les sources. /lib/modules/<version>/ modules.alias Aliases des modules pour insmod et modprobe. Exemple: alias sound-service-?-0 snd_mixer_oss modules.dep Dépendances des modules pour insmod et modprobe. Aussi utilisé pour ne copier que les modules nécessaires dans un système de fichier minimal. modules.symbols Dit à quel module appartient un symbole donné. 61
  • 62.
    FORMATION LINUX Mapping des symboles $cat System.map 00100000 A phys_startup_32 bfffe400 A __kernel_vsyscall bfffe410 A SYSENTER_RETURN bfffe420 A __kernel_sigreturn bfffe440 A __kernel_rt_sigreturn c0100000 A _text c0100000 T startup_32 c01000a4 T startup_32_smp c0100124 t checkCPUtype c01001a5 t is486 c01001ac t is386 c0100210 t L6 c0100212 t check_x87 c010023a t setup_idt c0100257 t rp_sidt (...) 62  Le fichier System.map est généré à la fin d’un compilation noyau. Il donne l’adresse de chaque symbole (primitive incluse dans le noyau) : La connaissance de ce mapping est utile au debug ; cela pouvait servir pour un piratage de primitive.
  • 63.
    FORMATION LINUX DKMS : DynamicKernel Module Support 63  Sous Linux, les pilotes (le logiciel qui permet au système d'exploitation de communiquer avec le matériel) peuvent soit être directement inclus dans le noyau soit être disponibles sous la forme de modules à charger dans le noyau. Un tel module est compilé pour un noyau particulier et ne peut être utilisé sur un autre.  En ce qui concerne les pilotes libres, cela ne pose en général aucun problème car ils sont soit livrés avec votre noyau, soit compilés en même temps que le noyau que vous compilez vous-même.  Dans le cas de pilotes non libres (comme ceux de nVidia ou ATI) ou de pilotes distribués séparément et que vous compilez à la main, le pilote doit être recompilé à chaque version de noyau, ce qui peut devenir fastidieux.  De plus, si vous souhaitez utiliser les pilotes distribués par votre distributeur Linux, vous devez attendre que les pilotes soient recompilés pour le nouveau noyau, et ne pouvez espérer qu'ils fonctionnent avec un noyau que vous auriez personnalisé.  DKMS (Dynamic Kernel Module Support ou en français Gestion Dynamique des Modules Noyau) est un système très simple conçu par Dell labs et permettant de compiler dynamiquement et facilement les modules noyau pour tous les noyaux de votre système. Ce système est à la base conçu pour faciliter à Dell la distribution de pilotes Linux et de correctifs.  Cela évite à la fois aux éditeurs et aux utilisateurs de devoir passer par des mises à jour du noyau pour une correction sur un pilote particulier et permet de distribuer un pilote supplémentaire sous la forme d'un seul paquetage quel que soit le noyau de l'utilisateur.
  • 64.
    FORMATION LINUX DKMS : DynamicKernel Module Support 64  Workflow utilisé par DKMS : Ajoute Génère Installe Désinstalle installé ajouté construit Pas répertorié  Le principe de DKMS est très simple. A condition que le module soit prévu pour être utilisé avec DKMS (fourniture d'un dkms.conf), l'utilisation d'un nouveau module en passant par DKMS consiste à exécuter les 3 étapes suivantes :  Insertion dans l'arbre DKMS (action add)  Compilation pour le noyau (action build)  Installation avec les autres modules du noyau (action install)  Ces étapes sont séparées et ne sont pas forcement toutes réalisées à la suite. BUILT_MODULE_NAME=vboxdrv DEST_MODULE_LOCATION=/kernel/misc PACKAGE_NAME=vboxdrv PACKAGE_VERSION=3.1.2 AUTOINSTALL=yes POST_BUILD="do_Module.symvers vboxdrv save $dkms_tree/$module/$module_version/build/Module.symvers"  Exemple de fichier dkms.conf utilisé dans le module vboxdrv du projet virtualBox de SUN :
  • 65.
    FORMATION LINUX DKMS : DynamicKernel Module Support 65 Travail sans DKMS  Travail avec DKMS  Utilisation de DKMS chez Mandriva :
  • 66.
    FORMATION LINUX DKMS : DynamicKernel Module Support 66 http://linux.dell.com/dkms/permalink/ http://linux.dell.com/dkms/ http://linux.dell.com/dkms/manpage.html http://www.linuxjournal.com/article.php?sid=6896 http://www.dell.com/downloads/global/power/1q04-ler.pdf http://linux.dell.com/dkms/dkms-ols2004.pdf http://wiki.mandriva.com/fr/DKMS https://wiki.ubuntu.com/IntrepidIbex/TechnicalOverview https://admin.fedoraproject.org/pkgdb/packages/name/dkms http://wiki.centos.org/HowTos/BuildingKernelModules#head-d313bd351f90d4f25a2143b7bbcff73f927731f0  Afin de bien séparer la gestion des différentes versions de module et de la version du noyau, le fonctionnement de DKMS se base sur la présence de 3 arborescences :  Les sources des modules, dans /usr/src  L'arborescence des modules du noyau /lib/modules : DKMS y remplacera ou ajoutera les modules que l'on va lui faire gérer  L'arborescence de DKMS /var/lib/dkms, contenant : • Les répertoires ou seront construits les modules • Les modules originaux sauvegardés • Les modules générés par DKMS  Les chemins indiqués sont ceux par défaut et il est possible de les modifier dans /etc/dkms/framework.conf mais nous supposerons dans le reste que les valeurs par défaut ont été conservées.
  • 67.
    FORMATION LINUX DKMS : DynamicKernel Module Support 67  Mise en oeuvre de DKMS va la commande du même nom : La gestion des modules au sein du système DKMS se fait à l'aide de la commande dkms. Cette commande a une syntaxe très simple : dkms <action> [options] Les actions et les options sont par contre plutôt nombreuses et même si je vous les explique ci-dessous, seules les principales devraient être utiles à la majorité d'entre vous (à savoir: add, build, install, remove en ce qui concerne les actions et -m, -v et --all en ce qui concerne les options). Liste des options génériques :  -m <module> : Le nom du module sur lequel effectuer l'action.  -v <version du module> : La version du module sur laquelle effectuer l'action.  -k <version du noyau> : La version du noyau sur laquelle effectuer l'action. Il est possible pour certaines actions de spécifier plusieurs versions du noyau en utilisant plusieurs fois -k, si l'action spécifiée ne le supporte pas une erreur sera émise.  -a <architecture> : L'architecture pour laquelle effectuer l'action. Si cette option n'est pas précisée, l'architecture choisie est celle indiquée par uname -m. Il est possible de répéter cette option afin d'indiquer plusieurs architectures, mais dans ce cas il doit y avoir exactement autant de -k que de -a. Chaque noyau sera associé à l'architecture de position identique. Par exemple si vous indiquez -k noyau1 -k noyau2 -a i386 -k noyau3 -a i586 -a x86_64, DKMS comprendra que noyau1 est en i386, noyau2 est en i586 et noyau3 est en x86_64.  --all : Indique d'appliquer l'action pour toutes les versions de noyau et toutes les architectures pour lesquelles le module a été compilé. Cela est particulièrement utile pour l'action remove.  --rpm_safe_upgrade : Cette option est nécessaire pour les commandes DKMS appelées à l'intérieur d'un RPM. Cela évite des problèmes lors de mise à jour d'un RPM à un autre contenant la même version du module. Cela évite aussi les problèmes d'interblocage dus au système de verrous de rpm.
  • 68.
    FORMATION LINUX DKMS : DynamicKernel Module Support 68  add : ajoute à l'arbre des sources de DKMS une version d'un module (les options -m et -v sont donc obligatoires, c'est le cas pour la majorité des commandes). Les sources du module doivent être précédemment placées dans /usr/src/<module>-<version du module>/ et contenir un fichier dkms.conf. Si le fichier dkms.conf ne se trouve pas dans /usr/src/<module>-<version du module>/, il faut ajouter l'option -c pour indiquer son chemin. Exemple : $ dkms add -m exemple -v 0.9.0 -c /tmp/dkms.conf Creating symlink /var/lib/dkms/exemple/0.9.0/source -> /usr/src/exemple-0.9.0 DKMS: add Completed.  remove : supprime une version d'un module. Il faut en plus des options -m et -v, soit préciser une version de noyau avec l'option -k, soit demander à supprimer le module de tout les noyaux pour lesquelles cette version avait été compilée, avec l'option --all. Si le module avait été installé, il est d'abord désinstallé (comme si on avait appelé l'action uninstall) et d'éventuelles versions précédentes sont réinstallées. Après un remove, le module n'est plus du tout connu de DKMS et il faut recommencer à l'étape add. Exemple : $ dkms remove -m exemple -v 0.9.0 –all Deleting module version: 0.9.0 completely from the DKMS tree. Done.
  • 69.
    FORMATION LINUX DKMS : DynamicKernel Module Support 69  build : compile une version d'un module pour le noyau indiqué avec l'option -k ou pour le noyau utilisé actuellement si aucun n'est précisé. En cas d'erreurs lors de la compilation, il est utile de savoir que celle- ci se déroule dans /var/lib/dkms/<module>/<version du module>/build/ et que tout ce qui est affiché pendant la compilation est enregistré dans un fichier make.log dans ce même répertoire. La commande build accepte quelques options facultatives :  --config <fichier .config du noyau> : Cette option permet d'indiquer à la commande build ou trouver le fichier .config si celui-ci n'est pas à l'emplacement standard de la distribution ou n'a pas le nom habituel.  --no-prepare-kernel : Cette option demande à DKMS de ne pas préparer les sources du noyau avant de compiler un module pour lui. Il est recommandé de ne pas utiliser cette option si l'on souhaite que les modules soient correctement construits.  --no-clean-kernel : Cette option demande à DKMS de ne pas nettoyer les sources du noyau après avoir compilé un module.  --kernelsourcedir <chemin vers les sources du noyau> : Cette option permet d'indiquer l'emplacement des sources du noyau lorsqu'elles ne se trouvent pas dans /lib/modules/<version du noyau>/build. Exemple : $ dkms build -m slmodem -v 2.9.10 -k 2.6.12-12mdk-i686-up-4GB Preparing kernel 2.6.12-12mdk-i686-up-4GB for module build: (This is not compiling a kernel, only just preparing kernel symbols) Storing current .config to be restored when complete Running Generic preparation routine make mrproper......... using /boot/config-2.6.12-12mdk-i686-up-4GB make oldconfig...... make prepare-all...... Building module: cleaning build area.... make KERNELRELEASE=2.6.12-12mdk-i686-up-4GB KERNEL_DIR=/lib/modules/2.6.12-12mdk-i686-up-4GB/build drivers.... cleaning build area.... cleaning kernel tree (make mrproper)....
  • 70.
    FORMATION LINUX DKMS : DynamicKernel Module Support 70  install : installe une version d'un module dans l'arborescence du noyau indiqué (ou du noyau utilisé actuellement si aucun n'est précisé par l'option -k). Cette version doit précédemment avoir été compilée pour le noyau en question à l'aide de l'action build. Lors de la première installation d'une version d'un module donné sur un noyau donné, DKMS cherche si ce module existait déjà avec ce noyau et le sauvegarde pour pouvoir le réinstaller lorsque l'on demandera à DKMS de désinstaller la nouvelle version. Pour information, la version originale est sauvée dans /var/lib/dkms/<module>/original_module/<version du noyau>/<architecture>/ $ dkms install -m slmodem -v 2.9.10 -k 2.6.12-12mdk-i686-up-4GB Running module version sanity check. slamr.ko.gz: - Original module etc…  uninstall : désinstalle une version d'un module pour une version du noyau (celle précisée par l'option -k ou la version utilisée actuellement si aucune n'est précisée). Cette commande ne gère pas l'option --all donc il vous faudra désinstaller pour chaque noyau séparément. $ dkms uninstall -m slmodem -v 2.9.10 -k 2.6.12-12mdk-i686-up-4GB Uninstall Beginning -------- Module: slmodem Version: 2.9.10 Kernel: 2.6.12-12mdk-i686-up-4GB (i586) etc…
  • 71.
    FORMATION LINUX KSPLICE : miseà jour du noyau sans reboot 71 http://www.ksplice.com/doc/ksplice.pdf Diagramme de synthèse permettant le remplacement de code.  Ksplice est une extension libre du noyau Linux permettant à l'administrateur système d'appliquer "à chaud" des patchs du noyau, sans redémarrage du système. Ksplice fonctionne pour les architectures x86 et x86-64 et est développé par Ksplice, Inc sous GNU General Public License. Détermination de la valeur du symbole à changer à chaud.
  • 72.
    FORMATION LINUX KSPLICE : miseà jour du noyau sans reboot 72  Ksplice indique que l'utilisation de son service Uptrack «accélère grandement les processus de mises à jour et améliore la sécurité du système», tout en sauvant du temps en raison de l'absence d'une interruption ce service ou d'une baisse de performance. Les distributions Linux exigent, rappelle Ksplice, un redémarrage mensuel dans le but de tirer profit des importantes mises à jour de sécurité du noyau.
  • 73.
    FORMATION LINUX EXECUTION  Etapes dudémarrage d'un système GNU Linux  Le bootloader  L’initialisation de l’espace noyau  Le ramfs Initrd  L’initialisation de l’espace utilisateur BUT : comprendre le démarrage d’un système basé sur Linux
  • 74.
    FORMATION LINUX Démarrage d'un systèmeGNU Linux  Le démarrage d’un système Linux peut être résumé à 3 étapes :  Le Boot loader : • Initialise le hardware • Charge le noyau • Transfère le contrôle au noyau  L’initialisation du noyau : • Initialisation et démarrage des sous-systèmes du noyau • Démarrage du multitâches • Montage du système de fichier racine • Passe le contrôle au mode user  L’initialisation en espace user : • Démarrage des services et applications
  • 75.
    FORMATION LINUX 75 Le Boot loader Quand le système démarre (boot ou reboot), le CPU invoque le vecteur de reset de façon à récupérer l'adresse d'un programme localisé à exécuter ; pour un système traditionel, cet emplacement est localisé dans le B.I.O.S. de la carte mère.  Quand un device bootable est trouvé, la première étape consiste en un chargement du boot loader en RAM (MBR).  Le boot loader doit être d'une taille inférieure ou égale à 512 octets (un seul secteur) et son rôle est de charger en RAM puis d'exécuter la seconde étape (GRUB, LILO, …).  Une fois que le boot loader a initialisé le hardware, il doit démarrer le noyau :  Chargement du noyau (depuis une mémoire flash ou le réseau)  Décompression du noyau  Si un disque mémoire initial (initial ram disk = initrd) est requis, il est chargé en mémoire  Initialisation d’une zone mémoire pour passage de paramètres au noyau (avec éventuellement l’adresse de l’image initrd)  Appelle le point d’entrée du noyau  Généralement le noyau pourra récupérer l’espace mémoire du boot loader qui n’est plus utilisé. http://fr.wikipedia.org/wiki/Master_boot_record  Backup du MBR : dd if=/dev/hda of=boot.mbr bs=512 count=1  Restauration du MBR : dd if=boot.mbr of=/dev/hda bs=512 count=1
  • 76.
    FORMATION LINUX Quelques chargeurs dedémarrage  LILO: LInux LOader. Chargeur de démarrage originel de Linux. Toujours utilisé ! http://freshmeat.net/projects/lilo/ Matériel supporté: x86  GRUB: GRand Unified Bootloader de GNU. Plus puissant. http://www.gnu.org/software/grub/ Matériel supporté: x86  CoreBoot (Ex Linux Bios) : Remplaçant du BIOS, basé sur Linux. http://www.coreboot.org/Matériel supporté: x86  sh-boot: Chargeur de démarrage du projet LinuxSH. http://cvs.sourceforge.net/viewcvs.py/linuxsh/sh-boot/ Matériel supporté: sh  LAB: Linux As Bootloader, de Handhelds.org Partie du noyau Linux de Handhelds.org Voir http://handhelds.org/moin/moin.cgi/Linux26ToolsAndSources Matériel supporté: arm (expérimental)  U-Boot: Universal Bootloader. Le plus utilisé sur arm. http://u-boot.sourceforge.net/ Matériel supporté: arm, ppc, mips, x86  RedBoot: Chargeur de démarrage basé sur eCos de Red-Hat. http://sources.redhat.com/redboot/ Matériel supporté: x86, arm, ppc, mips, sh, m68k...  Loadlin : le chargeur de linux (LOADLIN = LOAD LINux) ftp://ftp.sunet.se/pub/Linux/distributions/slackware/slackware-current/kernels/loadlin16c.zip http://en.wikipedia.org/wiki/Loadlin  Syslinux, chargeur utilé pour les clef usb et les liveCD http://www.kernel.org/pub/linux/utils/boot/syslinux/  ISOLINUX : un chargeur pour les cdrom ISO 9660 http://syslinux.zytor.com/iso.php  QI : bootloader minimal utilisé sous OpenMoko pour le portage de Google Android http://gitorious.net/+0xlab/0xlab-bootloader/qi-bootloader 76
  • 77.
    FORMATION LINUX 77 Initialisation du noyau Le démarrage du noyau se fait en plusieurs phases :  Initialisation du hardware (CPU, MMU, caches, stack, etc.)  Analyse des paramètres passés par le boot loader  Si un initrd est utilisé, il est monté comme système de fichiers racine en ramfs. Une fois cette seconde étape de lancée, charge le noyau linux en mémoire vive puis invoque ce dernier. Par le suite il y a commutation entre le rootfs temporaire et celui qui sera utilisé par la suite (réellement).  Autres initialisations :(mémoire virtuelle, interruptions, timers, etc. • Calibration du bogomips • Détection du nouveau matériel  Initialisation des drivers :  Interrogation du bus PCI  Interrogation des slot IDE  Interrogation de la chaine USB  Exécute /linuxrc si présent dans l’initrd  Montage du système de fichiers "maitre" (disque, flash, NFS, etc.), éventuellement en place du système initrd  Exécute en espace user la première application de l’espace utilisateur init ou tout autre process spécifié par le paramètre init. Sous la distribution Ubuntu, /sbin/init est remplacé par upstart : http://upstart.ubuntu.com/
  • 78.
    FORMATION LINUX Ligne de commandedu noyau Exemple (utilisé pour le PDA HP iPAQ h2200) : root=/dev/ram0 rw init=/linuxrc console=ttyS0,115200n8 console=tty0 ramdisk_size=8192 cachepolicy=writethrough ro root=/dev/mapper/vg_workstation-lv_root rhgb quiet SYSFONT=latarcyrheb-sun16 LANG=fr_FR.UTF-8 KEYTABLE=fr 78  Des centaines de paramètres sont décrit dans Documentation/kernel-parameters.txt Le positionnement de init=/bin/bash et avec un accès en lecture et écriture (rw) permet d’obtenir un accès root sur une machine ; cela montre l’importance de la sécurisation d’un bootloader.  Comme la plupart des programmes C, le noyau Linux accepte des arguments en ligne de commande.  La ligne de commande est une chaine de 255 caractères terminé par NULL (/0)  Utile pour configurer le noyau au démarrage, sans avoir à le recompiler. Cette technique est particulièrement utilisé pour initialiser le noyau linux au chargement par le bootloader.  Une fois lancé les paramètres du noyau sont accessible par la commande : cat /proc/cmdline  Les paramètres sont soit pour la partie core du noyau ou pour certain modules compilés en statiques. Les modules dynamiques ont eux aussi leur paramètres.  Exemples : Vous pouvez avoir l'ensemble des options pour le noyau linux sur les pages suivantes : noyau 2.4 : http://lxr.linux.no/source/Documentation/kernel-parameters.txt?v=2.4.26 noyau 2.6 : http://lxr.linux.no/source/Documentation/kernel-parameters.txt?v=2.6.8.1
  • 79.
    FORMATION LINUX Ligne de commandedu noyau 79  Des centaines de paramètres sont décrit dans Documentation/kernel-parameters.txt Le positionnement de init=/bin/bash et avec un accès en lecture et écriture (rw) permet d’obtenir un accès root sur une machine ; cela montre l’importance de la sécurisation d’un bootloader.  Paramètres les plus utilisés : console Console pour les messages de démarrage init Script à exécuter à la fin de l'initialisation du noyau. Par défaut: /sbin/init mem Permet d'indiquer la valeur de mémoire vive présente sur la machine pour le cas ou l'auto- detection échouerait. On peut utiliser des lettres pour cette taille. Par exemple 512M désignera 512 Méga-octets de mémoire. ro / rw Monte le file système root en lecture seule ou bien en lecture/écriture root Permet d'identifier le système de fichier racine vga Sert à changer la résolution d'écran utilisée pendant le démarrage. Utile si celle par défaut n'est pas reconnue par la carte graphique. debug Active ou non le mode debug selinux Active ou non Security Enhanced Linux (SELINUX) ether Définit la carte nic Ethernet (irq,iobase, ,name). Exemple: ether=0,0,eth0 Pour information, si irq=0 et iobase=0 c’est que la détection automatique doit être activé. nousb Désactive la détection des périphériques USB.
  • 80.
    FORMATION LINUX Démarrage d'un systèmeGNU Linux 80  L’initialisation même du noyau comporte elle-même 4 étapes :  Chargement de l’image du noyau  Initialisation de la partie en assembleur : • boot/head.S : initialise les registres, configure la pile noyau, appel de setup_idt() pour remplir l’IDT de gestionnaire d’IRG nuls, appel setup_gdt() pour remplir la GDT, mise en place de la pagination, appel de la fonction start_kernel(). Elle s’appelait main() initialement. Cette fonction est une boucle infinie.  Initialisation de la partie en langage C (init/main.c).  Exécution du processus Init
  • 81.
    FORMATION LINUX Démarrage d'un systèmeGNU Linux 81 Boot d’un noyau Linux bzImage et sa phase de décompression. http://www.ibiblio.org/oswg/oswg-nightly/oswg/en_US.ISO_8859-1/articles/alessandro-rubini/boot/boot/zimage.html
  • 82.
    FORMATION LINUX Initrd (initial RAMDisk) Initrd = Initial RAM disk  Disque mémoire minimaliste temporaire utilisé au démarrage. Il est chargé en RAM.  Utilisé traditionnellement pour minimiser le nombres de pilotes de périphériques compilés dans le noyau. Exemple: le module ext3 qui permet de monter le système de fichier racine final.  Utile aussi pour lancer des scripts d'initialisation complexes  Utile pour charger des modules propriétaires (qui ne peuvent être liés statiquement au noyau)  Pendant la phase d'installation (make install), il y a la création d’une image initrd (init RAM disk) : mkinitrd -o /boot/initrd.img-2.6.32.4 /lib/modules/2.6.32.4.  Pour plus d'information : il suffit de lire Documentation/initrd.txt dans les sources du noyau. Elle couvre aussi le changement de système de fichier racine («pivot_root»). Exemple de création d'une image initrd : mkdir /mnt/initrd dd if=/dev/zero of=initrd.img bs=1k count=2048 mkfs.ext2 -F initrd.img mount -o loop initrd.img /mnt/initrd ( Peut être rempli avec: busybox, les modules, le script linuxrc ) umount /mnt/initrd gzip --best -c initrd.img > initrd  http://www.ibm.com/developerworks/linux/library/l-initrd.html 82
  • 83.
    FORMATION LINUX 83 Initialisation de l’espaceutilisateur  Le processus /sbin/init est exécuté en espace user par le noyau. Il peut être surchargé par le paramètre init.  Le processus init est spécial :  Il ne peut jamais être terminé  Il adopte les processus orphelins (processus fils dont le parent est terminé en premier)  Le noyau informe le processus init de certains événements comme Ctrl-Alt-Del  Le processus init a pour tache de lancer les autres services et applications du système  Généralement, ces actions sont spécifiées dans /etc/inittab  La valeur de initdefault détermine le numéro d’init (runlevel)  Cela déclenche le démarrage des scripts /etc/rc*.d/ associés à la séquence d’init (deamon). Les répertoires /etc/rc*.d ne contiennent pas les scripts de démarrage réels, mais plutôt des liens symboliques vers des scripts situés dans le répertoire /etc/init.d. Ceci permet d’éviter une redondance inutile. La manière dont sont nommés les liens symboliques déterminera l’ordre dans lequel les services seront démarrés : simple, ingénieux et pratique. Les liens symboliques à démarrer commencent par la lettre ‘S’ (Start) et ceux à arrèter par la lettre ‘K’ (Kill). S’en suit un chiffre qui agence l’ordre de lancement (init order). Enfin vient le nom du daemon.  En embarqué, le script exécuté au démarrage est /etc/init.d/rcS. Il lance tout d’abord les scripts du répertoire /etc/rcS.d/, qui ne s’exécutent qu’une fois, au démarrage de la machine. $ ps axfl UID PID PPID STAT TTY TIME COMMAND 0 1 0 S ? 0:03 init La commande pstree permet de confirmer le lien de parenté des processus avec init. La commande « who -r » permet de consulter le run level actuel. 0 : Arrêt 1 : Mode mono-utilisateur (Single) ou maintenance 2 à 5 : dépend du système d'exploitation 6 : Redémarrage
  • 84.
    FORMATION LINUX ARCHITECTURE DU NOYAU Arborescence des sources  Différences vues du noyau  Rôle du noyau  Découpage du noyau  Descriptions des différents composants :  Virtual File System (VFS)  Process Management (PM)  Memory Management (MM)  Gestion des entrées/sorties (I/O)  Network Stack (NS)  System Call Interface (SCI) BUT : comprendre l’architecture du noyau GNU Linux
  • 85.
    FORMATION LINUX Arborescence des sourcesdu noyau  Détail des répertoires :  arch/ Code dépendant de l'architecture  COPYING Conditions de copie de Linux (GNU GPL  CREDITS Contributeurs principaux de Linux  crypto/ Bibliothèques de cryptographie  Documentation/ Documentation du noyau.  drivers/ Pilotes de périphériques (drivers/usb/, etc…)  fs/ Systèmes de fichier (fs/ext3/, etc.)  include/ Entêtes du noyau  include/asm-<arch> Entêtes dépendant de l'architecture  include/linux Entêtes du coeur du noyau Linux  init/ Initialisation de Linux (contient main.c)  ipc/ Code utilisé pour la communication entre processus 85
  • 86.
    FORMATION LINUX Arborescence des sourcesdu noyau kernel/ Coeur du noyau Linux lib/ Bibliothèques diverses (zlib, crc32...) MAINTAINERS Responsables de parties du noyau. Makefile Makefile principal (définit arch et version) mm/ Code de la gestion mémoire net/ Support réseau (pas les pilotes) README Introduction et instructions de compilation REPORTING-BUGS Instructions pour le rapport de bogues scripts/ Scripts utilisés en interne ou en externe security/ Implémentations du modèle de sécurité (selinux...) sound/ Support du son et pilotes usr/ Utilitaires: gen_init_cpio et initramfs_data.S 86
  • 87.
    FORMATION LINUX Répartition du codedans l’arborescence du noyau  87 Répartition du code du noyau Obtenu par la commande : du -s --apparent-size Version 1.2 : 50% de code en langage C et 50% de code en langage assembleur Version 2.0 : 95% de code en langage C et 5% de code en langage assembleur
  • 88.
    FORMATION LINUX  Linux possèdeplusieurs hypergraphes tel que celui-ci ou bien celui représentant les dépendances des paquets quant à l'établissement d'une distribution conforme LSB (même basique).  Vue de l'hypergraphe formé par l'arborescence des sources du noyau 2.4.9  Note : ce schéma n'est pas très lisible mais montre cependant la représentation en oignon (concentrique) du noyau GNU Linux  88 Vue hypergraphe du noyau
  • 89.
    FORMATION LINUX Vue simplifiée d'undiagramme matriciel du noyau GNU Linux  89 Vue simplifiée du noyau
  • 90.
    FORMATION LINUX Vue modulaire dunoyau GNU Linux  90 Vue modulaire du noyau
  • 91.
    FORMATION LINUX Rôle du noyauGNU Linux  GNU (GNU is Not Unix) Linux est le coeur du système. Il fournit une API basse dépendant de l’architecture au hardware et une API haute (SCI) destiné au monde utilisateur.  Il gère aussi l'ordonnacement des tâches rendant ce dernier : • multi-tâches ; • préemptif (davantage en 2.6 qu'en 2.4) ; • multi-utilisateurs  Cependant il n'est pas nativement temps réel. Pour ce faire il faut rajouter un microkernel temps réel tel que RTAI, RTLINUX ou XENOMAI.  En d'autre terme le noyau manage les tâches tant en espace noyau qu'en espace utilisateur.  Vue de l'espace user, le noyau peut être contacté via un ensemble d'appels systèmes référencés dans la librairie C (glibc). 91
  • 92.
    FORMATION LINUX Mode utilisateur etmode noyau  Utilisation de la protection matérielle du microprocesseur  Différence entre les deux mondes :  Espace noyau : où tout est permi même le pire • Espace prévilégie • Accès à toutes les ressources • Utilisé par les entrées et sorties • Espace utilisateur : accès plus restreint • Espace non-privilégié • Accès restreint aux ressources • Pas d’accès aux entrées et sorties  Tout processus au cours de son exécution passe d’un espace à l’autre. La transition se faisant via :  la SCI qui est la frontière entre les deux mondes (c’est l’API publique normalisé par la norme POSIX offerte par le noyau au monde user).  les interruptions issue de timers, entrées et sorties, etc …  Les exceptions issue du processeur (accès illégal à la mémoire, instruction illégale, etc … )  Attention : tout changement de contexte est couteux en temps d’exécution. 92
  • 93.
    FORMATION LINUX Linux et letemps réel http://uuu.enseirb.fr/~kadionik/embedded/linux_realtime/linux_realtime9.html http://en.wikipedia.org/wiki/RTLinux http://en.wikipedia.org/wiki/RTAI http://en.wikipedia.org/wiki/Wind_River_Systems http://fr.wikipedia.org/wiki/Xenomai http://www.xenomai.org/index.php/Main_Page http://fr.wikipedia.org/wiki/Xenomai  Le noyau Linux n'étant pas temps réel en natif il est Cependant possible de le Compléter d'un micro- kernel Temps réel où linux est exécuté Comme sous UML, c'est-à- dire sous la forme d'un process   Le noyau 2.6 n’est préemtable que dans certaines conditions, il existe un patch RT-Prempt pour rendre le noyau préemptable : http://rt.wiki.kernel.org 93
  • 94.
    FORMATION LINUX Découpage du noyauLinux  Le noyau GNU Linux a hérité de l'architecture des UNIX propriétaires.  Il est souvent comparé à un oignon tant il est organisé en couches successives, en partant du matériel, au drivers jusqu'à l'espace utilisateur qui est sa frontière  Espace utilisateur Matériel 94
  • 95.
  • 96.
    FORMATION LINUX VFS : VirtualFile System  Linux n'étant pas monolithique c'est-à- dire qu'il est constitué d'un ensemble de parties comme la pile réseau, la gestion de la mémoire, etc…  VFS est la couche d'abstraction de haut niveau intra-kernel regroupant un ensemble de primitives génériques comme open, close, read, write (au nom près).  S'il s'agit d'écrire un fichier (une fifo ou autre) sur un disque, hé bien l'implémentation dans le kernel sera la même qu'il s'agisse d'un disque avec un système de fichier cramfs, jffs2 ou 3, ext2 ou 3, reizerfs, etc… VFS est la couche virtuelle qui permet de niveler les appels d'un point de vue noyau ou drivers en se souciant pas du système de fichiers réellement utilisé. VFS est donc une sorte de dispatcher de haut niveau vers les module spécifique à chaque système de fichiers. 96
  • 97.
    FORMATION LINUX VFS : VirtualFile System 97 Autres représentations de l’interface VFS :
  • 98.
    FORMATION LINUX Opérations sur lesfichiers La primitive register_chrdev(), permet de déclarer des «file_operations» (appellées fops). Voici ses principales opérations :  loff_t (*llseek) (struct file *, loff_t, int);  ssize_t (*read) (struct file *, char *, size_t, loff_t *);  ssize_t (*write) (struct file *, const char *, size_t, loff_t *);  int (*open) (struct inode *, struct file *);  int (*release) (struct inode *, struct file *);  http://www.ibm.com/developerworks/linux/library/l-linux-filesystem/ 98
  • 99.
    FORMATION LINUX Opérations sur lesfichiers  int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); Utilisée pour envoyer au périphérique des commandes spécifiques, qui ne sont ni des lectures, ni des écritures (ex: formater un disque, changer une configuration).  int (*mmap) (struct file *, struct vm_area_struct); Demande que la mémoire du périphérique soit mappée dans l'espace d'adressage du processus utilisateur  struct module *owner; Utilisée par le noyau pour garder une trace de qui utilise cette structure et compter le nombre d'utilisateurs du module. LFH : http://www.tldp.org/LDP/Linux-Filesystem-Hierarchy/Linux-Filesystem-Hierarc 99
  • 100.
    FORMATION LINUX La structure «file »  Au niveau kernel, VFS fournit la méthode open() pour ouvrir un fichier et retourner un pointeur sur la structure représentant le fichier ouvert.  Les pointeurs vers cette structure sont les "fips".  mode_t f_mode; Mode d'ouverture du fichier (FMODE_READ, FMODE_WRITE)  loff_t f_pos; Position dans le fichier ouvert.  struct file_operations *f_op; Peuvent être changées à la volée.  struct dentry *f_dentry Utilisé pour accéder à l'inode: filp->f_dentry->d_inode. 100
  • 101.
    FORMATION LINUX Table des systèmesde fichiers courants 101 Systèmes de fichiers courants
  • 102.
    FORMATION LINUX Fuse : unsystème de fichier en espace user  Pas mal de qualités :  API simple via la librairie dynamique libfuse  Implémentation d'un système de fichiers en espace user (pas de développement noyau)  Utilisation ne nécessitant pas de patcher le noyau  Implémentation sécurisée  Transfert entre l'espace noyau et l'espace utilisateur optimisé  Ne nécessite pas des droit root  Fonctionne sous GNU Linux 2.4 et 2.6  A prouvé sa stabilité http://fuse.sourceforge.net/ http://fuse.sourceforge.net/wiki/index.php/FileSystems 102
  • 103.
  • 104.
    FORMATION LINUX PM : Process Management Diagrammeétats transition des processus géré par l'ordonnanceur du noyau GNU Linux  104 TACHE ZOMBIE (La tâche est terminée) Tâche existante qui en crée une nouvelle. TACHE INTERRUPTIBLE ou TACHE UNINTERRUPTIBLE (attente) TASK COURANTE (en cours) TASK RUNNING (prête mais pas courante) Tâche crée Tâche se termine via un do_exit() Tache préempeptée par une tâche de priorité supérieure La tâche dort dans une liste d’attente d’un évènement spécifique Le scheduler sélectionne la tâche pour être active : schedule() appel context_switch() Un événement déclenche le réveil d’une tâche et la Place dans la queue des tâche à exécuter
  • 105.
    FORMATION LINUX L’ordonnanceur ou scheduler 105 Dans les systèmes d'exploitation, l’ordonnanceur désigne le composant du noyau du système d'exploitation qui choisit les processus qui vont être exécutés par les processeurs d'un ordinateur. En anglais, l'ordonnanceur est appelé scheduler.  Un processus peut avoir besoin de la ressource processeur pour, par exemple, effectuer des calculs, déclencher une interruption, etc. La plupart des composants matériel, et en particulier le processeur d'un ordinateur, n'est pas capable d'effectuer plusieurs traitements simultanément. Pour la très grande majorité des ordinateurs, avoir un seul processeur implique de ne pouvoir effectuer qu'un traitement à la fois.  A un instant donné, il est possible qu'il y ait plus de processus à exécuter qu'il n'y a de processeurs. Il est courant que de nombreux programmes soient exécutés en parallèle sur une machine mono processeur.  Un des rôles du système d'exploitation, et plus précisément de l'ordonnanceur du noyau, est de permettre à tous ces processus de s'exécuter et d'utiliser le processeur de manière optimale du point de vue de l'utilisateur. Pour arriver à donner l'illusion que plusieurs tâches sont traitées simultanément, l'ordonnanceur du noyau du système s'appuie sur les notions de commutation de contexte et d'ordonnancement.  Pour effectuer ces tâches, l'ordonnanceur procède de la manière suivante : à intervalles réguliers, le système appelle une procédure d'ordonnancement qui élit le processus à exécuter. Si le nouveau processus est différent de l'ancien alors survient un changement de contexte, opération qui consiste à sauvegarder le contexte d'exécution de l'ancienne tâche, comme par exemple, les registres du processeur. Cette structure de données est généralement appelée PCB. Le système d'exploitation restaure le PCB de la nouvelle tâche.
  • 106.
    FORMATION LINUX L’ordonnanceur ou scheduler 106 Multi-tâche préemptif  Le noyau lui même est préemptif (à partir du 2.6) : possibilité de prendre la main dans un driver.  Politique Unix de partage du temps machine entre processus (time slicing)  API POSIX.1b pour le temps réel : priorité FIFO (de 0 à 99)  Linux n'est pas pour autant un noyau temps réel (comprendre ici, qu’il n’y a aucune garantie de terminer une tâche dans un temps déterminée) :  temps d'exécution non prédictif (le noyau est prioritaire face au processus du monde utilisateur)  système non déterministe.  Gestion des priorités (41 niveaux standards + 99 niveaux temps réel).
  • 107.
    FORMATION LINUX L’ordonnanceur ou scheduler 107 Types d'algorithmes : Du choix de l'algorithme d'ordonnancement dépend le comportement du système. Il existe deux grandes classes d'ordonnancement.  L'ordonnancement en temps partagé : Il est présent sur la plupart des ordinateurs « classiques ». Par exemple l'ordonnancement « decay » ; qui est celui par défaut sous Unix. Il consiste en un système de priorités adaptatives, par exemple il privilégie les tâches interactives pour que leur temps de réponse soit bon. Une sous-classe de l'ordonnancement en temps partagé sont les ordonnanceurs dits « proportional share », eux sont plus destinés aux stations de calcul et permettent une gestion rigoureuse des ressources. On peut citer notamment « lottery » et « stride ».  Algorithmes d'ordonnancement :  Round-robin : garantie d’un temps minimum pour l’exécution d’une tâche  Rate-monotonic scheduling (RMS)  Earliest deadline first scheduling (EDF)  FIFO  Shortest job first (SJF, ou SJN -Shortest Job Next-)  Completely Fair Scheduler (CFS) http://kerneltrap.org/node/8059 http://people.redhat.com/mingo/cfs-scheduler/ http://www.ibm.com/developerworks/linux/library/l-cfs/ http://en.wikipedia.org/wiki/Completely_Fair_Scheduler http://en.wikipedia.org/wiki/O%281%29_scheduler http://www.ibm.com/developerworks/linux/library/l-scheduler / http://www.informit.com/articles/article.aspx?p=101760&seq Num=2
  • 108.
    FORMATION LINUX Le scheduler CFS- O(1) (depuis 2.6.23)  Le Completely Fair Scheduler (ordonnanceur complètement équitable en anglais), ou CFS est un ordonnanceur de tâches pour le noyau linux, qui a fait son apparition avec la version 2.6.23 sortie le 9 octobre 2007, remplaçant ainsi le précédent ordonnanceur qui était apparu dans le noyau 2.5.2-pre10 en janvier 2002. Il gère l'allocation de ressource processeur pour l'exécution des processus, en maximisant l'utilisation globale du CPU tout en optimisant l'interactivité. Il a été écrit par Ingo Molnár.  Contrairement au précédent ordonnanceur utilisé par le noyau linux, CFS n'est pas basé sur des files de processus, mais utilise un arbre rouge-noir implémentant une chronologie des futures exécutions des tâches. En effet, l'arbre trie les processus selon une valeur représentative du manque de ces processus en temps d'allocation du processeur, par rapport au temps qu'aurait alloué un processeur dit multitâche idéal, sur lequel tous les processus s'exécuterait en même temps et à la même vitesse. Ainsi, à chaque intervention de l'ordonnanceur, il "suffit" à ce dernier de choisir le processus le plus en manque de temps d'exécution pour tendre au mieux vers le comportement du processeur multitâche idéal. De plus, l'ordonnanceur utilise une granularité temporelle à la nanoseconde, rendant redondante la notion de tranches de temps, les unités atomiques utilisées pour le partage du CPU entre processus. Cette connaissance précise signifie également qu'aucune heuristique (basée sur des statistiques, donc pouvant commettre des erreurs) n'est requise pour déterminer l'interactivité d'un processus.  Plusieurs avancées sont apportées par le nouveau noyau 2.6.25. L'ordonnanceur CFS a été rendu plus agressif dans le déplacement des processus entre les coeurs de calcul. Maintenant, dans le cas d'une compétition entre des tâches temps réel pour accaparer un seul coeur, le noyau migrera plus efficacement certaines tâches vers les autres processeurs afin d'éviter les temps d'attente. D'autre part le verrou global du noyau (big kernel lock) est maintenant préemptible par défaut et l'option permettant de ne pas le rendre préemptible va sans doute disparaître. Les timers à haute résolution peuvent maintenant être utilisés pour calculer les priorités entre les processus ce qui rend l'ordonnanceur plus précis lors de ses allocations de temps. On peut également noter que la fonction d'ordonnancement de groupe, introduite dans le noyau précédent, gagne des fonctions de support du temps réel. 108
  • 109.
    FORMATION LINUX Etat d'attente  L'endormissementest nécessaire lorsqu'un processus utilisateur attend des données qui ne sont pas encore prêtes. Il est alors placé dans une queue/file d'attente.  Déclarer la queue : DECLARE_WAIT_QUEUE_HEAD (module_queue); Plusieurs moyens d'endormir un processus :  sleep_on() Ne peut pas être interrompu !  interruptible_sleep_on() Peut être interrompu par un signal  sleep_on_timeout() interruptible_sleep_on_timeout() Similaire à ci-dessus, mais avec un délai d'expiration.  wait_event() wait_event_interruptible() Dort jusqu'à ce qu'une condition soit vérifiée. Utilisez seulement les commandes interruptibles, les autres sont rarement nécessaires. 109
  • 110.
    FORMATION LINUX Se réveiller  Souventun processus se retrouve à attendre un évènement dans le noyau (exemple: arrivée données)  Plutôt que de faire du polling, le processus se met dans une file d'attente et relâche le CPU  Lorsque l'évènement intervient, le gestionnaire d'interruptions (ou le bottom-half) réveille le ou les processus de la file correspondante.  Les routines de manipulation des files d'attente sont les suivantes:  wait_event{_interruptible}{timeout}() : • endort le processus courant, de façon interruptible ou pas et avec ou sans délais d'expiration, et le place dans une file d'attente jusqu’à ce qu’une condition soit satisfaite.  wake_up{_interruptible}{_nr,_all}() : • réveille un processus (ou x, ou tous) endormi d'une file d'attente et les rend éligibles, c’est à dire ordonnançable. Interruptible : permet de terminer un processus par un signal.  wake_up(&queue); Réveille tous les processus attendant dans la queue donnée  wake_up_interruptible(&queue); Réveille seulement les processus interruptibles (peut être rveillé par un signal).  wake_up_sync(&queue); Ne réordonnance pas lorsque vous savez qu'un autre processus est sur le point de s'endormir, car dans ce cas un réordonnancement va de toute façon se produire. 110
  • 111.
    FORMATION LINUX Se réveiller  Laversion 'interruptible' teste si un signal a été envoyé au processus et renvoie un code d'erreur dans ce cas (ERESTARTSYS), qui doit être propagé en tant que retour de l'appel système.  Initialisation d'une file d'attente (type wait_queue_head_t) :  en statique: DECLARE_WAIT_QUEUE_HEAD(name)  au runtime: init_waitqueue_head()  Exemple : 111 static DECLARE_WAIT_QUEUE_HEAD(ma_file); int fonction_lecture (void *adresse) { ... ret = wait_event_interruptible(&ma_file, readb() != 0); if (ret < 0) return ret; ... } void mon_handler(int irq, void *priv, struct pt_regs *regs) { ... wake_up_interruptible(& ma_file); ...}
  • 112.
    FORMATION LINUX Se réveiller  Prototypes(<linux/wait.h>) :  DECLARE_WAIT_QUEUE_HEAD(name);  void init_waitqueue_head(wait_queue_head_t *wq);  Prototypes (<linux/sched.h>, <linux/wait.h>):  void wait_event(wait_queue_head_t *wq, condition);  int wait_event_interruptible (wait_queue_head_t *wq, condition);  int wait_event_interruptible_timeout(wait_queue_head_t *wq, condition, long timeout);  void wake_up{_interruptible}(wait_queue_head_t *wq);  void wake_up{_interruptible}_nr(wait_queue_head_t *wq, int nr);  void wake_up_all() 112
  • 113.
  • 114.
    FORMATION LINUX Organisation de lamémoire 0 GB 1 GB Mémoire virtuelle Mémoire physique  Il est possible d'étendre l'utilisation de la mémoire au dela des 4 Go Via l'utilisation de la mémoire haute (ZONE_HIGHMEM). ZONE_NORMAL : KERNEL PHYSICAL SPACE KERNEL VIRTUAL SPACE USER VIRTUAL SPACE 0 GB 3 GB 4 GB http://www.informit.com/content/images/0131453483/downloads/gorman_book.pdf 114
  • 115.
    FORMATION LINUX Espace d’adressage 115  Espaced'adressage noyau :  virtuel (pas physique) : adresse logique de 0x0000 à la fin de la ram  vision linéaire de la RAM (pas de segmentation)  pas de protection lors d'accès illégaux  taille maximum en fonction de la mémoire physique  Espace d'adressage utilisateur:  Virtuel : de 0x00 jusqu’à la taille max de la machine  privé pour chaque processus  taille maximum en fonction de l'architecture (gestion du swap)
  • 116.
    FORMATION LINUX Caractéristiques par architecture 116 ARCHITECTUREPAGE_SHIFT PAGE_SIZE en Ko alpha 13 8 arm 12, 14, 15 4, 16, 32 cris 13 8 h8300 12 4 i386 12 4 ia64 12, 13, 14, 16 4, 8, 16, 64 m32r 12 4 m68k 12, 13 4, 8 m68knommu 12 4 mips 12 4 mips64 12 4 parisc 12 4 ppc 12 4 ppc64 12 4 x390 12 4 sh 12 4 sparc 12, 13 4, 8 sparc64 13 8 v850 12 4 X86_64 12 4
  • 117.
    FORMATION LINUX kmalloc et kfree Allocateurs basiques, équivalents noyau des malloc et free de la glibc. kmalloc()/kfree(): alloue / désalloue un bloc de mémoire réelle contiguë dans le noyau (GFP_KERNEL = peut dormir car le noyau est préempté en attendant d’avoir un bloc de disponible, GFP_ATOMIC = atomique, si pas de bloc disponible renvoie NULL) :  static inline void *kmalloc(size_t size, int flags); size: quantité d'octets à allouer flags: priorité  void kfree (const void *objp); Exemple: data = kmalloc(sizeof(*data), GFP_KERNEL); 117 Conversions d'adressage successif.  Adressage logique : utilisé par les instructions du microprocesseur.  Adressage linéaire : entier non-signé de 32 bits (jusqu'à 4 294 967 296 cellules de mémoire).  Adressage : utiliser pour adresser physiquement la mémoire vive via le bus hardware.
  • 118.
    FORMATION LINUX Propriétés de kmalloc Rapide (à moins qu'il ne soit bloqué en attente de pages).  N'initialise pas la zone allouée.  La zone allouée est contiguë en RAM physique.  Allocation par taille de 2n -k (k: quelques octets de gestion) Ne demandez pas 1024 quand vous avez besoin de 1000 ! Vous recevriez 2048 ! 118
  • 119.
    FORMATION LINUX Options pour kmalloc GFP_KERNEL Allocation mémoire standard du noyau. Peut être bloquante. Bien pour la plupart des cas.  GFP_ATOMIC Allocation de RAM depuis les gestionnaires d'interruption ou le code non liés aux processus utilisateurs. Jamais bloquante.  GFP_USER Alloue de la mémoire pour les processus utilisateur. Peut être bloquante. Priorité la plus basse.  GFP_NOIO Peut être bloquante, mais aucune action sur les E/S ne sera exécutée.  GFP_NOFS Peut être bloquante, mais aucune opération sur les systèmes de fichier ne sera lancée.  GFS_HIGHUSER Allocation de pages en mémoire haute en espace utilisateur. Peut être bloquante. Priorité basse. Définis dans le header include/linux/gfp.h (GFP: get_free_pages) 119
  • 120.
    FORMATION LINUX Flags pour kmalloc __GFP_DMA Allocation dans la zone DMA  __GFP_HIGHMEM Allocation en mémoire étendue (x86 et sparc)  __GFP_REPEAT Demande d'essayer plusieurs fois. Peut se bloquer, mais moins probable.  __GFP_NOFAIL Ne doit pas échouer. N'abandonne jamais. Attention: à utiliser qu'en cas de nécessité!  __GFP_NORETRY Si l'allocation échoue, n'essaie pas d'obtenir de page libre. Options supplémentaires (pouvant être ajoutés avec l'opérateur) : 120
  • 121.
    FORMATION LINUX Allocation par pages Plusappropriée que kmalloc pour les grosses tranches de mémoire :  unsigned long get_zeroed_page(int flags); Retourne un pointeur vers une page libre et la remplit avec des zéros  __get_free_pages()/free_pages(): alloue / désalloue un nombre entier (2^n) de pages contiguës de mémoire réelle (idem précédentes mais pour des besoins plus conséquents - limité à 128 ko). Le contenu n'est pas initialisé :  unsigned long __get_free_page(int flags);  unsigned long __get_free_pages(int flags, unsigned long order); Retourne un pointeur sur une zone mémoire de plusieurs pages continues en mémoire physique. order: log2 (nombre_de_pages).  Libérer des pages :  void free_page(unsigned long addr);  void free_pages(unsigned long addr, unsigned long order); Utiliser le même ordre que lors de l'allocation. 121
  • 122.
    FORMATION LINUX Mapper des adressesphysiques  vmalloc et ioremap peuvent être utilisés pour obtenir des zones mémoire continues dans l'espace d'adresse virtuel (même si les pages peuvent ne pas être continues en mémoire physique). vmalloc()/vfree() : alloue / désalloue un bloc de mémoire virtuelle composé de plusieurs blocs discontiguës de mémoire réelle.  void* vmalloc(unsigned long size);  void vfree(void* addr);  void* ioremap(unsigned long phys_addr, unsigned long size); • Ne fait pas d'allocation. • Fait correspondre le segment donné en mémoire physique dans l'espace d'adressage virtuel.  void iounmap(void* address); 122  Transfert de données entre espace utilisateur et noyau et vice et versa :  copy_from_user Copie des données de l'espace utilisateur vers l'espace noyau.  copy_to_user Copie des données de l'espace noyau vers l'espace utilisateur.
  • 123.
    FORMATION LINUX Utilitaires pour lamémoire  void* memset(void* s, int valeur, size_t taille); Remplit une région mémoire avec la valeur donnée.  void* memcpy(void* dest, const void* src, size_t count);  Copie une zone mémoire vers une autre.  Utiliser memmove avec des zones qui se chevauchent.  De nombreuses fonctions équivalentes à celles de la glibc sont définies dans include/linux/string.h 123
  • 124.
    FORMATION LINUX Allocation de mémoire Prototypes des primitives d’allocations :  Headers : • #include <linux/slab.h> • #include <linux/vmalloc.h>  Fonctions : • void *kmalloc (size_t size, int flags); • void kfree (const void *addr); • unsigned long __get_free_pages (int • gfp_mask, unsigned long order); • void free_pages (unsigned long addr, • unsigned long order); • void *vmalloc (unsigned long size); • void vfree (void *addr); 124
  • 125.
    FORMATION LINUX Choix d’un intervalled'E/S  Les limites de la mémoire et des ports d'E/S peuvent être passés comme paramètres de module. Un moyen facile de définir ces paramètre est au travers de /etc/modprobe.conf  Les modules peuvent aussi essayer de trouver des zones libres par eux-mêmes (en faisant plusieurs appels à request_region). 125
  • 126.
    FORMATION LINUX Différences avec lamémoire standard  Écriture et lecture sur la mémoire peuvent être mis en cache.  Le compilateur peut choisir d'écrire la valeur dans un registre du processeur, et ne jamais l'écrire dans la mémoire principale.  Le compilateur peut décider d'optimiser ou réordonner les instructions de lecture / écriture. 126
  • 127.
    FORMATION LINUX Eviter les problèmesd'accès aux E/S  Le cache sur la mémoire et les ports d'E/S est désactivé, soit par le hardware ou par le code d'init Linux.  Linux fournit les Barrières Mémoire pour empêcher le compilateur de réordonnancer les accès: Dépendant de l'architecture #include <asm/system.h> void rmb(void); void wmb(void); void mb(void); Indépendant #include <asm/kernel.h> void barrier(void); 127
  • 128.
    FORMATION LINUX Transferts de mémoire Le noyau utilise de la mémoire virtuelle noyau  Les processus utilisent chacun leur propre espace mémoire virtuel  Besoin de transférer les données de l'espace mémoire noyau vers l'espace mémoire du processus appelant et inversement  Les principales fonctions sont :  {get,put}_user() : transfert d'une variable depuis / vers l'espace mémoire utilisateur (utilisation en lvalue). Souvent utilisé pour le transfert d’une valeur.  copy_{from,to}_user() : transfert d'un buffer depuis / vers l'espace mémoire utilisateur. Utilisé pour le le transfert d’un buffer.  Ces fonctions utilisent la fonction access_ok() qui vérifie la validité des buffers utilisateurs  On peut s'affranchir de cet appel en utilisant les mêmes fonctions préfixées par __ (déconseillé)  Prototypes : #include <asm/uaccess.h> int get_user (lvalue, addr); int put_user (expression, addr); int copy_{to,from}_user (unsigned long dest, unsigned long src, unsigned long len); int access_ok (int type, unsigned long addr, unsigned long size); 128
  • 129.
    FORMATION LINUX Mémoire mappée directement Dans certaines architectures (principalement MIPS), la mémoire d'E/S peut être directement mappée dans l'espace d'adressage physique.  Dans ce cas, les pointeurs d'E/S ne doivent pas être déréférencés.  Pour éviter les problèmes de portabilité à travers les architectures, les fonctions suivantes peuvent être utilisées : unsigned read[b|w|l](address); void writeb[b|w|l](unsigned value, address); void memset_io(address, value, count); void memcpy_fromio(dest, source, num); void memcpy_toio(dest, source, num); 129
  • 130.
    FORMATION LINUX Mapper la mémoired'E/S en mémoire virtuelle  Pour accéder à la mémoire d'E/S, les pilotes ont besoin d'une adresse virtuelle que le processeur peut gérer.  Les fonctions ioremap permettent cela: #include <asm/io.h> void* ioremap(unsigned long phys_addr, unsigned long size); void* ioremap_nocache(unsigned long phys_addr, unsigned long size); void iounmap(void* address);  Attention: vérifiez que ioremap ne retourne pas NULL ! 130
  • 131.
    FORMATION LINUX mmap  Répond auxrequêtes de la fonction mmap de la glibc: void* mmap(void* start, size_t length, int prot, int flags, int fd, off_t offset); int munmap(void *start, size_t length);  Permet aux programmes utilisateurs d'accéder directement à la mémoire du périphérique.  Utilisé par des programmes comme le serveur X-Window ou V4L. Plus rapide que les autres méthodes (comme écrire dans le fichier /dev correspondant) pour les applications utilisateur à fort besoin en bande passante. 131
  • 132.
    FORMATION LINUX Zones de MémoireVirtuelle  Zone de Mémoire Virtuelle (Virtual Memory Areas): zone contiguë dans la mémoire virtuelle d'un processus, avec les mêmes permissions. $ cat /proc/1/maps (processus init) Début fin perm décalage majeur:mineur inode Nom du fichier mappé 00771000-0077f000 r-xp 00000000 03:05 1165839 /lib/libselinux.so.1 0077f000-00781000 rw-p 0000d000 03:05 1165839 /lib/libselinux.so.1 0097d000-00992000 r-xp 00000000 03:05 1158767 /lib/ld-2.3.3.so 00992000-00993000 r--p 00014000 03:05 1158767 /lib/ld-2.3.3.so 00993000-00994000 rw-p 00015000 03:05 1158767 /lib/ld-2.3.3.so 00996000-00aac000 r-xp 00000000 03:05 1158770 /lib/tls/libc-2.3.3.so 00aac000-00aad000 r--p 00116000 03:05 1158770 /lib/tls/libc-2.3.3.so 00aad000-00ab0000 rw-p 00117000 03:05 1158770 /lib/tls/libc-2.3.3.so 00ab0000-00ab2000 rw-p 00ab0000 00:00 0 08048000-08050000 r-xp 00000000 03:05 571452 /sbin/init programme 08050000-08051000 rw-p 00008000 03:05 571452 /sbin/init données, pile 08b43000-08b64000 rw-p 08b43000 00:00 0 f6fdf000-f6fe0000 rw-p f6fdf000 00:00 0 fefd4000-ff000000 rw-p fefd4000 00:00 0 ffffe000-fffff000 ---p 00000000 00:00 0 132
  • 133.
    FORMATION LINUX Zones de MémoireVirtuelle Exemple du serveur X (extrait) : Début fin perm décalage majeur:mineur inode Nom du fichier mappé 08047000-081be000 r-xp 00000000 03:05 310295 /usr/X11R6/bin/Xorg 081be000-081f0000 rw-p 00176000 03:05 310295 /usr/X11R6/bin/Xorg ... f4e08000-f4f09000 rw-s e0000000 03:05 655295 /dev/dri/card0 f4f09000-f4f0b000 rw-s 4281a000 03:05 655295 /dev/dri/card0 f4f0b000-f6f0b000 rw-s e8000000 03:05 652822 /dev/mem f6f0b000-f6f8b000 rw-s fcff0000 03:05 652822 /dev/mem 133
  • 134.
    FORMATION LINUX mmap simple  Pourautoriser les opérations mmap(), le pilote a juste besoin de créer des pages de mémoire mappant une zone physique.  Cela peut être fait avec la fonction suivante (linux/mm.h) à appeler dans une fonction driver_mmap: int remap_page_range( struct vm_area_struct *vma, unsigned long from, /* Virtual */ unsigned long to, /* Physical */ unsigned long size, pgprot_t prot);  Cette fonction est alors à ajouter à la structure file_operations du pilote. Exemple: drivers/char/mem.c 134
  • 135.
  • 136.
    FORMATION LINUX Historique de lapile réseau 136 Le développement de la couche réseau dans le noyau Linux a été orchestré par plusieurs programmeurs indépendants. Le but est d'implémenter un système qui soit au moins aussi performant que les autres tout en restant dans le domaine du logiciel libre. C'est avant tout le protocole TCP/IP qui a été développé avec des primitives de base par Ross Biro. Orest Zborowski produisit la première interface socket BSD pour le noyau GNU Linux. Le code fut ensuite repris par Alan Cox de Red Hat.
  • 137.
    FORMATION LINUX Protocoles supportés 137 Linux gèreune multitude de protocoles réseau : OSI 2 : couche liaison (Driver réseaux) : 1. Ethernet 2. ARP / RARP 3. Tokenring 4. ATM OSI 3 : couche réseau : OSI 4 : couche transport : 1. TCP 2. UDP 3. Netbios 1. IP 2. ICMP 3. IGMP 4. ATM  La pile réseau de GNU Linux peut être considéré comme la plus complète et disponible à ce jour. UNIX Unix domain sockets INET TCP/IP AX25 Amateur radio IPX Novell IPX APPLETALK Appletalk X25 X.25 Etc… (define in include/linux/socket.h)
  • 138.
    FORMATION LINUX Protocoles supportés 138  Disponibilitédes fonctionnalités dans la pile réseau en fonction des versions du noyau Linux 2.2, 2.4 et 2.6 
  • 139.
    FORMATION LINUX Support du réseaudans le noyau 139 Modèle Internet de la pile réseau. Architecture de la pile réseau.  La pile réseau couvre le protocole TCP/IP de la couche liaison (drivers) jusqu'à la couche transport (sockets BSD).  D'un point de vue de Linux, la pile est localisée dans le noyau avec une API (les sockets BSD) pouvant être appelée depuis l'espace utilisateur. Couche matérielle Couche de liaison Couche réseau Couche transport Couche applicative Application utilisateur Driver réseau Protocoles réseaux Interface de diagnostique des devices Interface de diagnostique des protocoles Appels système Carte réseau Application User space Kernel space
  • 140.
    FORMATION LINUX Pile réseau La pileréseau s'interface avec le module VFS et le Process Manager  140
  • 141.
  • 142.
    FORMATION LINUX API des primitivessystème  Les primitives systèmes du noyau son accessible via une API POSIX   L'appel à ces fonctions se faisant via la librairie C standard  142 NOYAU LINUX Implémentation privée Interface SCI publique compatible POSIX.1 Programme en espace utilisateur
  • 143.
    FORMATION LINUX Schéma synthétique d’unappel système libc Interface User/Kernel L'appel d'une primitive du noyau Linux se fait via la librairie libc.so.6  143
  • 144.
    FORMATION LINUX Tout passe parles appels système (syscalls)  déroulement d'une session de login 144 Interface User/Kernel
  • 145.
    FORMATION LINUX Hooking de primitivesystème #include <linux/syscall.h> #include <asm/unistd.h> static void **sys_call_table; extern void *system_utsname; static int locate_sys_call_table(void) { unsigned long *begin; int i; begin=(unsigned long *) &system_utsname; for (i=0;i<1024;i++) { if (*(begin+i)==(unsigned long) sys_socketcall) { sys_call_table=(void *) (begin+i-__NR_socketcall); //are you sure? if (sys_call_table[__NR_exit]==(void *) sys_exit) { printk("success: located sys_call_table: %Xn",(unsigned int) sys_call_table); return(1); } } } return(0); }  La technique consiste à rechercher la table des symboles de façon à pouvoir redéfinir, Intercepter, masquer, espionner Une primitive du noyau. 145 int __init init_exportmodule (void) { if (!locate_sys_call_table()) { // Retourne une erreur } //.....sys_call_table[] fonctionne!! }
  • 146.
    FORMATION LINUX Table des symbolesdes primitives  Anciennement (avec un noyau 2.4), lorsqu'il fallait retrouver une primitive dans le noyau, il suffisait d'utiliser le tableau suivant (issue de System.map) : sys_call_table[__NR_open] = (void*)my_func_ptr;  Cependant, du fait de l'utilisation de cette variable par les RootKit, cette dernière n'est plus exportée.  Désormais, la fonction ‘system_call’ effectue un accès direct à ‘sys_call_table[]’ (arch/i386/kernel/entry.S:240) : call *sys_call_table(,%eax,4)  Sur une machine x86 cela est traduit de la façon suivante : 0xff 0x14 0x85 <addr4> <addr3> <addr2> <addr1> Where the 4 ‘addr’ bytes form the address of ‘sys_call_table[]’. 146
  • 147.
    FORMATION LINUX Table des symbolesdes primitives  System_call n'étant pas exporté non plus, elle est définie quand même comme au niveau système (arch/i386/kernel/traps.c:1195) : set_system_gate(SYSCALL_VECTOR,&system_call);  Sur la plateforme x86, cela signifie que cette adresse est stockée dans une table de descripteur d'interruption (IDT : Interrupt Descriptor Table). L'emplacement de cette table peut être connue via le registre IDT (IDTR) et finalement cette IDTR peut à son tour être retrouvée par l'instruction SIDT.  Résumé :  Récupérer l'IDTR utilisant SIDT  Extraire l'adresse de l'IDT à partir de l'IDTR  Récupérer l'adresse de ‘system_call’ à partir de la 0x80ième entrée de la table IDT. 147
  • 148.
    FORMATION LINUX Code valide avecle noyau 2.6.x // ----------------------------------------------------------------------------- // Sys Call Table Address finder function // ----------------------------------------------------------------------------- unsigned long **find_sys_call_table(void) { unsigned long **sctable; unsigned long ptr; extern int loops_per_jiffy; sctable = NULL; for (ptr = (unsigned long)&unlock_kernel; ptr < (unsigned long)&loops_per_jiffy; ptr += sizeof(void *)) { unsigned long *p; p = (unsigned long *)ptr; if (p[__NR_close] == (unsigned long) sys_close) { sctable = (unsigned long **)p; return &sctable[0]; } } return NULL; } http://www.subversity.net/linux/finding-sys_call_table http://kerneltrap.org/node/6416 http://lwn.net/Articles/339253/ http://lwn.net/Articles/306804/  Listing d'une fonction de recherche de la table de symbole : 148 Note : depuis la version 2.6.30, la sys_call_table a été placé en lecture seule pour des raisons de sécurité. En effet, le risque avec cette table est de remplaçer une primitive par une autre. Une alternative est d’utiliser l’API fanotify (toujours en développement).
  • 149.
    FORMATION LINUX REGLES DE CODAGE Indentation  Briser les lignes longues  Accolades  Nommage  Flags de compilation  Divers  Précepts globaux BUT : maitriser les règles de codage dans le noyau linux
  • 150.
    FORMATION LINUX Règles de codage- indentation 150  Les tabulations sont de 8 caractères.  L'idée derrière l'indentation est de définir clairement les cas où un bloc de contrôle commence et se termine. Surtout quand vous avez été en regardant votre écran pendant 20 heures d'affilée, vous verrez qu'il sera beaucoup plus facile de voir comment l'indentation fonctionne si vous avez de grandes échancrures.  Maintenant, certains prétendent que les gens vont avoir 8-indentations caractère qui fait bouger le code trop loin vers la droite, et il devient difficile à lire à l'écran du terminal de 80 caractères. La réponse à cela est que si vous avez besoin de plus de 3 niveaux d'indentation, tu es vissé quand même, et devrait fixer votre programme.  En bref, 8-tirets char rendre les choses plus faciles à lire, et ont l'avantage supplémentaire de vous avertir lorsque vous êtes nidification vos fonctions trop profonde. Heed that warning. Compte de cet avertissement.  Ne mettez pas de déclarations multiples sur une seule ligne, sauf si vous avez quelque chose à cacher: if (condition) do_this; do_something_everytime; NOK if (condition) do_this; OK do_something_everytime;  En dehors des commentaires, documentation et sauf dans kconfig, les espaces ne sont jamais utilisés pour l'indentation, et l'exemple ci-dessus est délibérément rompu.
  • 151.
    FORMATION LINUX Briser les chaineslongues  La limite sur la longueur des lignes est de 80 colonnes, et c'est une limite dure.  Des déclarations de plus de 80 colonnes doivent être brisées en morceaux sensibles.  La même chose s'applique aux appels de fonction avec une longue liste d'arguments.  De longues files sont ainsi divisées en chaînes plus courtes. void fun(int a, int b, int c) { if (condition) printk(KERN_WARNING "Warning this is a long printk with " "3 paramètres a UB:%:% u" "c:% u n", a, b, c); else autre next_statement; next_statement; } 151
  • 152.
    FORMATION LINUX Les accolades 152 Les accoladespeuvent suivre les règles défini par Kernighan and Ritchie. Exemple : int fonction(void) { char msg[] = "hello worldn"; char *end = msg + sizeof(msg); char *cur; for (cur = msg; cur != end; ++cur) { putchar(*cur); } return 0; }
  • 153.
    FORMATION LINUX Nommage 153  Ne pasutiliser de noms mignons comme ThisVariableIsATemporaryCounter.  Les variables globales sont à proscrire.  Le nom des variables doivent être le plus court possible mais aussi le plus significatif aussi.
  • 154.
    FORMATION LINUX Codes de retour 154 Les codes de retour sont normalisés depuis Posix 1003.1 :  Valeurs négatives d'erreurs définies (positivement) dans <linux/errno.h> et <asm/errno.h>  Valeurs positives ou nulles en cas de fonctionnement correct  Toutes les fonctions du noyau utilisent cette normalisation  Transmission des valeurs d'erreur entre fonctions  Extrait des valeurs : [E2BIG]Argument list too long. [EACCES]Permission denied. [EADDRINUSE]Address in use. [EADDRNOTAVAIL]Address not available. [EAFNOSUPPORT]Address family not supported. [EAGAIN]Resource unavailable, try again (may be the same value as [EWOULDBLOCK]). [EALREADY]Connection already in progress. [EBADF]Bad file descriptor. [EBADMSG]Bad message.f http://www.opengroup.org/onlinepubs/000095399/basedefs/errno.h.html
  • 155.
    FORMATION LINUX Flags de compilation 155 Linux accepte la compilation conditionnelle via le préprocesseur mais il faut respecter la règle suivante : #ifdef condition … #else … #endif Il est important en effet d’avoir les deux closes d’implémentés, pour savoir ce que l’on doit faire si le flag n’est pas positionné.
  • 156.
    FORMATION LINUX Divers  Includes C:vous ne pouvez pas utiliser les fonctions de la bibliothèque C standard (printf(), strcat(), etc.). La bibliothèque C est implémentée au dessus du noyau et non l'inverse.  Linux a quelques fonctions C utiles comme printk(), qui possède une interface similaire à printf().  Donc, seul les fichiers d'entêtes du noyau sont autorisés.  N'utilisez jamais de nombres à virgule flottante dans le code du noyau. Votre code peut être exécuter sur un processeur sans unité de calcul à virgule flottante (comme sur ARM). L'émulation par le noyau est possible mais très lente.  Définissez tous vos symboles en local/statique, hormis ceux qui sont exportés (afin d'éviter la pollution de l'espace de nommage).  Consultez: Documentation/CodingStyle.  Il est toujours bon de connaître, voir d'appliquer, les règles de codage GNU: http://www.gnu.org/prep/standards.html 156
  • 157.
    FORMATION LINUX Precepts  Il fauttoujours essayer de déporter la complexité “algorithmique” en dehors du noyau. Cela implique donc :  Que le noyau doit rester le plus petit possible. Selectionner juste ce qui est nécessaire lors de la configuration du noyau (.config).  Les appels systèmes doivent rester en nombre limité à cause de la latence engendré par le changement de contexte.  La complexité doit résider soit dant la librairie C (libc, uclibc, dietlibc, … ) ou bien dans les applications utilisateurs. 157
  • 158.
    FORMATION LINUX METHODOLOGIES DE DEVELOPPEMENT BUT: maitriser les règles d’usage dans le noyau linux  Pourquoi une méthodologie ?  Plusieurs méthodologie :  Travail en local  Dé/chargement de modules  Travail avec un second noyau via UML  Simulation via un simulateur  Via un second système
  • 159.
    FORMATION LINUX Pourquoi une méthodologie? Un kernel panic du noyau GNU linux  Le noyau GNU Linux est le cœur du système d'exploitation.  Travailler directement au cœur du noyau peut le rendre instable et engendrer un KERNEL PANIC, le rendant donc inutilisable   Avant toute installation d'un nouveau noyau, il est conseillé d'en avoir un autre de référence enregistré au niveau du BOOT loader connu pour ne pas poser de problème lors du démarrage.  Développer et surtout tester un nouveau noyau Linux s'accompagne souvent d'un ensemble de méthodes très utiles. 159
  • 160.
    FORMATION LINUX Travail en local But : cela revient à travailler en local sur un driver et à le (dé)charger manuellement sur le noyau en courant.  Avantage : facile à mettre en place et à utiliser.  Inconvénient : si le noyau devient instable, il peut être nécessaire de rebooter. A préconiser pour de petit drivers mais à déconseiller vivement pour des drivers complexe (réseau ou vfs par exmple). C'est envisageable pour des modules mais s'il est nécessaire de modifier le cœur de même du noyau alors cette technique est à éviter.  Debug / traces : sudo tail -f /proc/kmsg sudo tail -f /var/log/messages dmesg [ -c ] [ -n niveau ] [ -s taille ] syslogd  Pour information, le chargement d'un driver dans le noyau en dynamique revient au chargement d'une librairie dynamique. il y a fusion des symboles du modules avec ceux du noyau. 160
  • 161.
    FORMATION LINUX (Dé)chargement de modules 161 Ce paquet contient un ensemble de programmes pour charger, insérer et supprimer des modules du noyau Linux  Le nom du packages change suivant les version de Linux :  Linux 2.4 : modutils  Linux 2.6 : module-init-tools  Ce package contient les outils suivants :  depmod Crée un fichier de dépendances basé sur les symboles trouvés dans l'ensemble de modules existants ; ce fichier de dépendances est utilisé par modprobe pour charger automatiquement les modules requis  insmod Installe un module chargeable dans le noyau en cours d'exécution  insmod.static Une version compilée statiquement de insmod  lsmod Liste les modules déjà chargés  modinfo Examine un fichier objet associé à un module du noyau et affiche toute information qu'il peut récupérer  modprobe Utilise un fichier de dépendances, créé par depmod, pour charger automatiquement les modules adéquats  rmmod Décharge les modules du noyau en cours d'exécution http://www.kerneltools.org/KernelTools.org
  • 162.
    FORMATION LINUX (Dé)chargement de modules Exemple de listing des modules chargés : $ lsmod … snd_pcm_oss 40384 0 snd_mixer_oss 16096 2 snd_pcm_oss …  En résumé :  insmod snd_pcm_oss : OK  insmod snd_mixer_oss : OK si snd_pcm_oss déjà chargé sinon NOK  modprobe snd_pcm_oss : OK  modprobe snd_mixer_oss : OK chargera snd_pcm_oss si pas chargé  Le raisonnement est le même pour le déchargement. Seule les commandes changent. rmmod <modulename> remplace insmod et modprobe –r <modulename> remplace modprobe. Modprobe –r, déchargera aussi les autres modules dépendant si non utilisés. modinfo <modulename> donne les informations sur un module comme l'auteur, sa licence, ses paramètres. sudo depmod : permet de recréer le cache de la liste des modules (mécanisme similaire à ldconfig). A noter qu'il est possible de rajouter le nom des modules à charger lors d'un boot dans le fichier de configuration /etc/modules.  Dans le listing suivant, snd_pcm_oss n'as pas de dépendances mais par contre snd_mixer_oss a le module snd_pcm_oss comme dépendance ce qui veut dire qu'il est possible de charger le module snd_pcm_oss de façon unitaire et directement alors que le module snd_mixer_oss nécessitera que le module snd_pcm_oss soit chargé au préalable. Pour info lsmod met en forme les informations générés dans /proc/modules 162
  • 163.
    FORMATION LINUX (Dé)chargement de modules insmod ou modprobe rmmod ou modprobe-r  Lors du chargement dynamique d'un module, cela se passe comme pour le chargement d'une librairie dynamique c'est-à-dire que le module est linké au noyau. Les symboles (primitives) du module sont rajouté et peuvent être utilisés dans d'autres modules ou dans le noyau lui-même. 163
  • 164.
    FORMATION LINUX Dépendances de modules Les dépendances des modules n'ont pas à être spécifiées explicitement par le créateur du module.  Elles sont déduites automatiquement lors de la compilation du noyau, grâce aux symboles exportés par le module: module2 dépend de module1 si module2 utilise un symbole exporté par module1.  Les dépendances des modules sont stockées dans : /lib/modules/<version>/modules.dep  Ce fichier est mis à jour (en tant que root) avec : depmod -a [<version>] 164
  • 165.
    FORMATION LINUX Utilisation de UserMode Linux (UML)  User Mode Linux ou UML est un noyau Linux compilé qui peut être exécuté dans l'espace utilisateur comme un simple programme. Il permet donc d'avoir plusieurs systèmes d'exploitation virtuels (principe de virtualisation) sur une seule machine physique hôte exécutant Linux.  Avantages :  Si un User Mode Linux plante, le système hôte n'est pas affecté.  Un utilisateur sera root sur un User Mode Linux, mais pas sur le système hôte.  Au niveau développement, gdb peut servir à débuguer le noyau de dev puisqu'il est considéré comme un processus normal.  Il permet aussi de tester différents paramètres noyaux sans se soucier des conséquences.  Il permet de tester différentes configurations ou compilations du noyau sans avoir à l'installer et redémarrer la machine.  Il permet de mettre en place un réseau complètement virtuel de machines Linux, pouvant communiquer entre elles. Les tests de topologies lourdes d'un point de vue physique peuvent donc être menés aisément ici.  Inconvénients :  Très lent, plutôt conçu pour des tests fonctionnels que pour la performance  Nécessite de patcher le noyau Noyau GNU Linux courant Diagramme d'une architecture UML http://user-mode-linux.sourceforge.net/ http://www.rstack.org/oudot/20022003/7/7_rapport.pdf http://www.ibm.com/developerworks/edu/l-dw-linuxuml-i.html http://www.metz.supelec.fr/metz/personnel/galtier/PagesPerso/TutorielUML/UML_avec_briques_existantes/index.h tml Noyau expérimental ESPACE UTILISATEUR UML 165
  • 166.
    FORMATION LINUX Kernel Mode Linux(KML) http://www.linuxjournal.com/article/6516 http://web.yl.is.s.u-tokyo.ac.jp/~tosh/kml/ http://web.yl.is.s.u-tokyo.ac.jp/~tosh/kml/tosh_master_kml_e.ps http://en.wikipedia.org/wiki/Linux_kernel http://www.ibiblio.org/pub/Linux/docs/HOWTO/translations/fr/pdf/Kernel-HOWTO.pdf  Cette technique réciproque de UML, permet d'exécuter dans le noyau un processus habituellement prévu pour l'espace user.  Tout comme pour UML, cela nécessite de patcher le noyau et d'activer la fonctionnalité lors de la Compilation du noyau.  Les architectures supportées sont : IA-32 et AMD64.  Actuellement, les binaires ne peuvent pas modifier les registres suivants : CS, DS, SS or FS.  Ce système peut être cependant intéressant de façon à diminuer la latence : Latency of System Calls (Unit: CPU cycles) : Original Linux (using sysenter) Kernel Mode Linux Getpid 432 12 Gettimeofday 820 404 166
  • 167.
    FORMATION LINUX Utilisation d’un simulateur Plusieurs architectures existent : QEMU, VMWARE, BOCHS, VirtualBox et bien d'autres permettent de générer une Image bootable permettant d'avoir un système d'exploitation à l'intérieur d'un autre. C'est une autre forme de virtualisation qui peut garantir une sécurité au niveau du système en cours de développement.  Avantages : • Très pratique pour des développment sur le noyau même. • Pas besoin de patcher le noyau comme avec UML.  Inconvénients : • Dépend de la puissance de la machine hôte. • Peut nécessiter de régénérer l'image à chaque fois que l'on souhaite la tester. # Création du rootfs mkdir iso # Création de l'image ISO mkisofs -o rootfs-dev.iso -J -R ./iso # Cela peut être une recopie d'un média dd if=/dev/dvd of=dvd.iso # for dvd dd if=/dev/cdrom of=cd.iso # for cdrom dd if=/dev/scd0 of=cd.iso # if cdrom is scsi # Simulation qemu -boot d -cdrom ./rootfs-dev.iso # Montage sudo modprobe loop sudo mount -o loop rootfs-dev.iso /mnt/disk # Démontage sudo umount mnt/disk http://fabrice.bellard.free.fr/qemu/ http://www.vmware.com/fr/ http://www.virtualbox.org/ http://packages.debian.org/mkinitrd-cd http://packages.debian.org/sid/mkinitrd-cd http://www.mayrhofer.eu.org/mkinitrd-cd http://bochs.sourceforge.net/ 167
  • 168.
    FORMATION LINUX Utilisation d’un secondsystème  De loin la technique la plus adaptée car permet de développer au coeur du noyau ou bien des modules complexes.  Cette technique est de plus adaptée pour un usage embarqué.  Avantages :  Très pratique pour des développement sur le noyau même.  Permet de debuguer via la liaison série ou le réseau le noyau courant du second système en pouvant oser un point d'arrêt.  Inconvénients :  Nécessite de disposer d'une seconde machine. http://kgdb.linsyssoft.com/ http://www.mulix.org/lectures/kernel_oopsing/kernel_oopsing.pdf http://www.alcove.com/IMG/pdf/kernel_debugging.pdf http://www.ibm.com/developerworks/linux/library/l-kdbug/ http://www.ibm.com/developerworks/linux/library/l-debug/  Activation de KDB sur le système de dev : echo "1" >/proc/sys/kernel/kdb Liaison série Liaison ethernet Poste servant aux développements seconde plateforme de développement 168
  • 169.
    FORMATION LINUX En remplacement d'unport série de débug  Sur la plate-forme de développement:  Pas de problème. Vous pouvez utiliser un convertisseur USB<-> série. Bien supporté par Linux. Ce périphérique apparaît en tant que /dev/ttyUSB0 sur la cible:  Vérifiez si vous avez un port IrDA. C'est aussi un port série.  Si vous avez une interface Ethernet, essayez de l'utiliser.  Vous pouvez aussi connecter en JTAG directement les broches série du processeur (vérifiez d'abord les spécifications électriques!) http://www.jtag.com/?gclid=CJrAjLLT7pICFQgNuwodQBgD4w http://www.linux-mips.org/wiki/JTAG http://www.coreboot.org/JTAG/BSDL_Guide http://www.intel.com/design/flcomp/applnots/29218602.PDF http://packages.debian.org/testing/embedded/openwince-jtag http://wiki.openwrt.org/OpenWrtDocs/Customizing/Hardware/JTAG_Cable http://irda.sourceforge.net/ http://www.ibiblio.org/pub/Linux/docs/howto/translations/fr/pdf/Infrared-HOWTO.pdf http://www.hpl.hp.com/personal/Jean_Tourrilhes/IrDA/ http://www.linux-usb.org/ 169
  • 170.
    FORMATION LINUX Quelques editeurs  Listede quelques editeurs recommandés pour le développement noyau :  Ajunta  Eclipse  Kdevelop  Kscope  Netbean  Source navigator  Développer des drivers Linux est plus facile si la machine de dev est native linux. 170
  • 171.
    FORMATION LINUX DEVELOPPEMENT DANS LENOYAU BUT : apprendre à développer des drivers.  Ajout d’un répertoire  Makefile d’un module  Squelettes de drivers  Les pilotes de caractères  Les pilotes de blocs
  • 172.
    FORMATION LINUX Ajout d’un répertoireau noyau  Pour ajouter un répertoire mon_drivers/ aux sources du noyau:  Dans le répertoire parent : • Créer un répertoire mon_drivers/ à l'endroit approprié dans les sources du noyau • Dans le fichier Kconfig, ajouter: source “mon_driver/Kconfig” • Dans le fichier Makefile du répertoire parent, ajouter: “obj-$(CONFIG_MONFLAG) += mon_driver/” (juste 1 condition) or “obj-y += mon_driver/” (plusieurs conditions)  Dans le répertoire mon_drivers/ : • Créer un fichier mon_driver/Kconfig • Créer un fichier mon_driver/Makefile basé sur les variables Kconfig  Lancer make xconfig et utiliser vos nouvelles options !  Lancer make et vos nouveaux fichiers sont compilés !  Regardez Documentation/kbuild/*.txt pour plus de détails 172 obj-y objets à inclure au noyau de façon statique obj-m objets d’un modules dynamique
  • 173.
    FORMATION LINUX Création d’un makefileindépendant 173 obj-m := mondriver.o KDIR := /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) all: make ARCH=sh CROSS_COMPILE=sh4-linux- M=$(PWD) -C $(KDIR) clean: make ARCH=sh CROSS_COMPILE=sh4-linux- M=$(PWD) -C $(KDIR) clean  Il est possible de compiler un drivers séparément du noyau.  Pour ce faire il faut juste renseigner définir quelques variables :  Exemple de makefile permettant la génération d’un module mondriver.ko) :  Utilisation : KDIR Chemin vers les sources du noyau PWD Chemin courant Compilation du module make Nettoyage make clean  Il est à noter que les modules sont seulement compilés et pas linkés, le linkage s'effectuant lors du chargement du drivers dans le noyau Linux.  Anciennement (en 2.4), l'extension des modules étaient .o alors qu'en 2.6 c'est désormais .ko Tabulation (pas d'espaces) ifeq ($PATCHLEVEL, 4) correspond au noyau 2.4
  • 174.
    FORMATION LINUX Dévelopement de modulesnoyau  Les modules: ajoutent une fonctionnalité donnée au noyau (pilotes, support système de fichier, etc...) ;  Ils sont (dé)chargés à tout moment, quand leur fonctionnalité est requise (ou plus). Une fois chargés, ils ont accès à tout le noyau. Aucune protection particulière ;  Ils sont utiles pour garder une image du noyau à une taille minimum (essentiel pour les distributions GNU/Linux pour PCs) ;  Ils permettent de supporter l'incompatibilité entre pilotes (on charge soit l'un ou soit l'autre, mais pas les 2) ;  Ils permettent de fournir des pilotes binaires (mauvaise idée), utilisables sans avoir à recompiler le noyau ;  Ils permettent de développer des pilotes sans redémarrer: chargement, test, déchargement, recompilation, chargement ;  Ils peuvent aussi être compilés statiquement dans le noyau. 174
  • 175.
    FORMATION LINUX Types de drivers 175 Plusieurs types de périphériques :  caractère (char) : lectures et écritures séquentielles, non bufferisés (exemple: carte graphique, souris, lecteur de bande)  bloc (block) : accès aléatoires, par blocs de données, bufferisés et optimisés, utilisé à travers la VFS (exemple: disque dur, CDROM, mémoire flash)  réseau (net) : matériel de communication utilisé à travers les différentes couches réseau, communications faites par paquets sk_buff (exemple: cartes Ethernet, Token Ring).
  • 176.
    FORMATION LINUX Autres types depilotes  Ils n'ont aucune entrée correspondante dans /dev dans laquelle vous pouvez lire ou écrire avec une commande Unix standard :  Les pilotes réseaux Ils sont représentés par un périphérique réseau comme ppp0, eth1, usbnet, irda0 (liste: ifconfig –a)  Les autres pilotes Souvent, ce sont des pilotes intermédiaires servant d'interface avec d'autres. 176
  • 177.
    FORMATION LINUX Squelette de drivers: hello world simple  Dépendance avec d'autres modules : aucun  Chargement : insmod hello1 modprobe hello1 Résultat au chargement : Hello, world  Déchargement : insmod hello1 modprobe -r hello1 Résultat au déchargement : Au revoir…  Les messages peuvent être obtenus via la commande dmesg ou /var/log/messages. 177 #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> MODULE_LICENSE("Dual BSD/GPL"); static int hello_init(void) { printk(KERN_ALERT "Hello, worldn"); return 0; } static void hello_exit(void) { printk(KERN_ALERT "Au revoir...n"); } module_init(hello_init); module_exit(hello_exit); obj-m += hello.o default: make -C /lib/modules/$(shell uname -r)/build/ SUBDIRS=$(PWD) modules  Listing :  Makefile :
  • 178.
    FORMATION LINUX Squelette de drivers 178 Initialisation et libération : #include <linux/init.h>  La fonction d'initialisation doit contenir tout le code nécessaire à l'initialisation du module (allocations, initialisations matérielles, réservation des ressources...) : module_init() : déclaration de la fonction d'initialisation de type int foo(void);  Au contraire, la fonction de libération doit défaire tout ce qui a été fait à l'initialisation (libération de mémoire, désactivation du matériel, libération des ressources...) module_exit() : déclaration de la fonction de libération de type void foo(void);
  • 179.
    FORMATION LINUX Squelette de drivers: compteur d’usage 179  Chaque module possède un compteur d'usage.  Permet d'éviter qu'un module soit déchargé pendant son utilisation.  La gestion du compteur est faite par l'appellant.  Le compteur peut être manipulé grâce à (<linux/module.h>) :  MOD_INC_USE_COUNT : incrémente le compteur  MOD_DEC_USE_COUNT : décrémente le compteur  MOD_IN_USE : indique la valeur du compteur  Le noyau 2.6 fournit à la place (<linux/module.h>) :  try_module_get(THIS_MODULE) : essaye d'incrémenter la valeur du compteur d'utilisation.  module_put(THIS_MODULE) : décremente la valeur du compteur d'utilisation.  module_refcount(THIS_MODULE) : indique la valeur du compteur d'utilisation.
  • 180.
    FORMATION LINUX Squelette de drivers: hello world simple 180  Tout driver doit initialiser son contexte via la fonction spécifié dans module_init().  En revanche, il se doit de libérer tout ce qu’il a initialiser et qui ne sert plus via la fonction module_exit(). Il doit donc libérer toutes les ressources qu’il n’utilises plus.  Ces deux fonctions sont donc les deux points d’entrée et de sortie obligé.  La commande modinfo peut donner un ensemble d’informations sur un module : $ modinfo /lib/modules/2.6.31.12-174.2.19.fc12.i686/kernel/drivers/video/vga16fb.ko filename: /lib/modules/2.6.31.12-174.2.19.fc12.i686/kernel/drivers/video/vga16fb.ko license: GPL description: Legacy VGA framebuffer device driver src version: 220D0B5A68FBFC014886CE0 depends: vgastate vermagic: 2.6.31.12-174.2.19.fc12.i686 SMP mod_unload 686  http://www.tldp.org/LDP/lkmpg/2.6/lkmpg.pdf  http://www.tldp.org/LDP/lki/lki.pdf  http://www.tldp.org/LDP/lpg/index.html  http://www.tldp.org/LDP/khg/HyperNews/get/khg.html  http://tldp.org/LDP/lkmpg/2.6 /html/index.html.org/LDP/tlk/tlk.html  http://tldp.org/LDP/lkmpg/2.4/html/index.html
  • 181.
    FORMATION LINUX Squelette de drivers: hello world + param. 181 #include <linux/init.h>#include <linux/module.h> #include <linux/moduleparam.h> MODULE_LICENSE("GPL");static char *nom= "world";module_param(nom, charp, S_IRUGO); static int nombre= 1;module_param(nombre, int, S_IRUGO);static int hello_init(void){ int i; for (i = 0; i < nombre; i++) printk(KERN_ALERT "(%d) Hello, %sn", i, nom); return 0;}static void hello_exit(void){ printk(KERN_ALERT »Au revoir %sn", nom);} module_init(hello_init);module_exit(hello_exit);  Listing :  Dépendance avec d'autres modules : aucun  Chargement 1 : insmod hello2 Résultat au chargement : (0) Hello, world  Chargement 2 : insmod hello2 nom=toto Résultat au chargement : (0) Hello, toto  Chargement 3 : insmod hello2 nom=toto nombre=2 Résultat au chargement : (0) Hello, toto (1) Hello, toto  Déchargement : insmod hello2 Résultat au déchargement : Au revoir…
  • 182.
    FORMATION LINUX Squelette de drivers: hello world + param.  Déclarer des paramètres utilisable lors du chargement des modules :  module_param(nom, type, perm); • Nom : nom du paramètre • Type : soit byte, short, ushort, int, uint, long, ulong, charp, bool ou invbool (vérifié à la compilation !) • Perm : permissions pour l'entrée correspondante dans /sys/module/<module_name>/<param>. On peut utiliser 0.  module_param_named(nom, valeur, type, perm); Rend la variable nom disponible à l'extérieur du module et lui affecte valeur à l'intérieur.  module_param_string(nom, chaine, taille, perm); Crée une variable nom de type charp, pré-remplie avec la chaîne de longueur taille, typiquement sizeof(string)  module_param_array(name, type, num, perm); Pour déclarer un tableau de paramètres  Le passage de paramètres ne marche pour une compilation statique qu’à partir du 2.6. Avant il fallait passer par la macro __setup(). 182
  • 183.
    FORMATION LINUX Passer des paramètresaux modules  Avec insmod ou modprobe: insmod ./hello_param.ko howmany=2 whom=universe  Avec modprobe en changeant le fichier /etc/modprobe.conf: options hello_param howmany=2 whom=universe  Avec la ligne de commande du noyau, lorsque le module est lié statiquement au noyau : options hello_param.howmany=2 hello_param.whom=universe 183
  • 184.
    FORMATION LINUX License des modules GPL GNU Public License v2 ou supérieure  GPL v2 GNU Public License v2  GPL and additional rights  Dual BSD/GPL Choix entre GNU Public License v2 et BSD  Dual MPL/GPL Choix entre GNU Public License v2 et Mozilla  Propriétaire Produits non libres La liste des licences est détaillée dans include/linux/module.h :  Utilité des licences de module  Utilisées par les développeurs du noyau pour identifier des problèmes venant de pilotes propriétaires, qu'ils n'essaierons pas de résoudre  Permettent aux utilisateurs de vérifier que leur système est à 100% libre.Permettent aux distributeurs GNU/Linux de vérifier la conformité à leur politique de licence.  L’idée est que le coeur doit rester sous licence GPL pure mais que des pilotes sous d’autres licences soient tolérés. 184
  • 185.
    FORMATION LINUX License des modules Les applications qui font des appels systèmes ne sont soumis à la licence GPL  On peut faire du code non GPL dans les cas suivant :  Pas de link statique, uniquement des modules  Le module doit annoncer sa licence (MODULE_LICENCE)  Restreint à une API de haut-niveau (EXPORT_SYMBOL) et pas (EXPORT_SYMBOL_GPL)  Pas de travail dérivé 185
  • 186.
    FORMATION LINUX La structure “device” Déclaration :  La structure de donnée de base est struct device, définie dans include/linux/device.h  En pratique, vous utiliserez plutôt une structure correspondant au bus auquel votre périphérique est attaché: struct pci_dev, struct usb_device...  Enregistrement  Dépend toujours du type de périphérique, des fonctions spécifiques (de)d'(dés)enregistrement sont fournies  Références pour le «Device Model» : La documentation dans les sources du noyau est très utile et très claire :  Documentation/driver-model/ • binding.txt class.txt driver.txt overview.txt porting.txt bus.txt device.txt interface.txt platform.txt  Documentation/filesystems/sysfs.txt 186
  • 187.
    FORMATION LINUX Les attributs dupériphériques peuvent être lus/écrits depuis l'espace utilisateur : Exemple : struct device_attribute { struct attribute attr; ssize_t (*show)(struct device * dev, char * buf, size_t count, loff_t off); ssize_t (*store)(struct device * dev, const char * buf, size_t count, loff_t off); }; #define DEVICE_ATTR(name,mode,show,store)  Ajouter / enlever un fichier : int device_create_file(struct device *device, struct device_attribute * entry); void device_remove_file(struct device * dev, struct device_attribute * attr); /* Créé un fichier nommé "power" avec un mode 0644 (-rw-r--r--) */ DEVICE_ATTR(power,0644,show_power,store_power); device_create_file(dev,&dev_attr_power); device_remove_file(dev,&dev_attr_power); 187 Les attributs de périphériques
  • 188.
    FORMATION LINUX La structure «device_driver» Déclaration : struct device_driver { /* Omitted a few internals */ char *name; struct bus_type *bus; int (*probe) (struct device * dev); int (*remove) (struct device * dev); void (*shutdown) (struct device * dev); int (*suspend) (struct device * dev, u32 state, u32 level); int (*resume) (struct device * dev, u32 level); };  Enregistrement : extern int driver_register(struct device_driver * drv); extern void driver_unregister(struct device_driver * drv);  Attributs : Disponibles de la même manière 188
  • 189.
    FORMATION LINUX Portabilité des drivers Définition des types génériques interne au noyau : u8 unsigned byte (8 bits) u16 unsigned word (16 bits) u32 unsigned 32-bit value u64 unsigned 64-bit value s8 signed byte (8 bits) s16 signed word (16 bits) s32 signed 32-bit value s64 signed 64-bit value  Exemple de fonction issue du bus i2c : s32 i2c_smbus_write_byte(struct i2c_client *client, u8 value); s32 i2c_smbus_read_byte_data(struct i2c_client *client, u8 command); s32 i2c_smbus_write_byte_data(struct i2c_client *client, u8 command, u8 value); Pour des variable pouvant être visible du userspace (ex: ioctl) il est nécessaire d'utiliser cette notation : __u8 unsigned byte (8 bits) __u16 unsigned word (16 bits) __u32 unsigned 32-bit value __u64 unsigned 64-bit value __s8 signed byte (8 bits) __s16 signed word (16 bits) __s32 signed 32-bit value __s64 signed 64-bit value Exemple d'utilisation, lors de l'envoie d'un message de contrôle à un device USB : struct usbdevfs_ctrltransfer { __u8 requesttype; __u8 request; __u16 value; __u16 index; __u16 length; __u32 timeout; /* in milliseconds */ void *data; }; #define USBDEVFS_CONTROL_IOWR('U', 0, struct usbdevfs_ctrltransfer)  Définit dans linux/types.h http://www.xml.com/ldd/chapter/book/ch10.html 189
  • 190.
    FORMATION LINUX Format des octetsen mémoire 190  Deux formats de disposition des octets dans les mots :  « Gros-boutiens » (Big-endian) : les octets de poids fort sont placés avant les octets de poids faible (ex: Motorola 68k)  « Petit-boutiens » (Little-endian) : les octets de poids faible sont placés avant les octets de poids fort (ex: Intel x86)  Certains périphériques peuvent utiliser un format différent de celui de la machine pour la représentation de leurs données internes (bus PCI sur non x86, réseau sur x86 notamment)  Des macros servent à optimiser les conversions entre différents formats (<asm/byteorder.h>) :  cpu_to_{le,be}{16,32,64}() : conversion d'une donnée depuis le format local utilisé par le CPU vers un format déterminé  {le,be}{16,32,64}_to_cpu() : conversion d'une donnée depuis un format déterminé vers le format local utilisé par le CPU  Ces mêmes macros convertissent la donnée in situ quand elles sont suffixées pas un s et la donnée pointée quand elles sont suffixées par un p.
  • 191.
    FORMATION LINUX Export de symbolesentre drivers 191 #include <linux/module.h> #include "export_symbole.h » static int __init chargement (void) { return 0; } static void __exit dechargement (void) { return 0; } void fonction_hello(int numero) { printk (KERN_INFO "Hello, le numero est %dn", numero); } EXPORT_SYMBOL(fonction_hello); MODULE_LICENSE("GPL"); module_init(chargement); module_exit(dechargement);  Listing d’un module avec export de symbole : : #ifndef EXPORT_SYMBOLE_H #define EXPORT_SYMBOLE_H void fonction_hello(int numero); #endif  Header associé : : #include <linux/module.h> #include "export_symbole.h" static int __init chargement (void) { fonction_hello(10); return 0; } static void __exit dechargement (void) { fonction_hello(20); } module_init(chargement); module_exit(dechargement); MODULE_LICENSE("GPL");  Listing d’un module avec import de symbole : :  Pour vérifier la liste des symboles : cat /proc/kallsyms
  • 192.
    FORMATION LINUX PILOTE DE CARACTERES BUT: apprendre à développer un pilote de caractères.  Définition d’un pilote de caractères  Exemple d’usage
  • 193.
    FORMATION LINUX Les pilotes decaractères 193  S'apparentent à des fichiers classiques :  Lectures et écritures séquentielles  Temps d'accès pouvant varier selon la position de la donnée (ex: bandes)  Transferts de données de tailles arbitraires  Exemples: cartes graphiques, bandes, imprimantes..  La déclaration et la libération d'un pilote en mode caractère se font par les fonctions (<linux/fs.h>) : int register_chrdev(unsigned int major, const char *name, struct file_operations *fops); int unregister_chrdev(unsigned int major, const char *name);  Possibilité d'allocation dynamique du majeur en mettant major à 0  Les périphériques et leurs nombres majeurs sont listés dans /proc/devices
  • 194.
    FORMATION LINUX Les pilotes decaractères 194  La structure file_operations (fops) contient des pointeurs sur les fonctions implémentant le fonctionnement du pilote: open(), read(), write(), etc : struct file_operations mondriver_fops= { .owner = THIS_MODULE, .read = mafonction_read, .write = mafonction_write, .ioctl = mafonction_ioctl, .open = mafonction_open, .release = mafonction_release, };  open()/release() :  Appelées à l'ouverture/fermeture du fichier spécial  Ces méthodes peuvent ne pas être déclarées mais le driver ne sera pas averti lors de ces évènements (déconseillé).  Prototypes (<linux/fs.h>) : • int open(struct inode *inode, struct file *file); • int release(struct inode *inode, struct file *file); Méthode d’initialisation d’une structure en nommant les champs.
  • 195.
    FORMATION LINUX Les pilotes decaractères 195  read()/write() :  Utilisées pour lire/écrire des données sur le périphérique  Méthodes les plus couramment implémentées  Prototypes (<linux/fs.h>): • ssize_t read(struct file *file, char *buffer, size_t size, loff_t *offset); Si la valeur de retour est égale à zéro, cela signifie la fin du fichier. Toutes les valeurs entre 1 et size sont correctes Size correspond à la taille maximum à lire. Buffer : adresse dans l’espace utilisateur • ssize_t write(struct file *file, const char *buffer, size_t size, loff_t *offset); Ne peut pas retourner 0.  ioctl() :  Généralement utilisée pour contrôler le périphérique  La plus complète de toutes les méthodes  On peut implémenter toutes les fonctionnalités d'un driver avec des commandes ioctl()  Prototype (<linux/fs.h>) : • int ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
  • 196.
    FORMATION LINUX Les pilotes decaractères 196  Autres méthodes utiles :  llseek() : modifie la position courante de lecture/écriture  poll() : base pour l'implémentation des appels système select() et poll() Select : un kthread regarde un ou plusieurs file descriteur en même temps  mmap() : projette une partie de la mémoire noyau dans l'espace mémoire du processus utilisateur évitant les recopies entre l’espace utilisateur et l’espace noyau.  Améliorations dans le noyau 2.6 :  Modifications pour permettre de gérer l'espace de nommage sur 32 bits  Possibilité de réserver une plage de couples major / minor  Découplage entre la gestion de la plage major / minor et le périphérique en mode caractère
  • 197.
    FORMATION LINUX Les pilotes decaractères 197  Prototypes (<linux/fs.h>) :  int register_chrdev_region(dev_t from, unsigned count, char *name);  int unregister_chrdev_region(dev_t from, unsigned count);  int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, char *name);  struct cdev * cdev_alloc(void);  void cdev_init(struct cdev *cdev, struct file_operations *fops);  int cdev_add(struct cdev *p, dev_t dev, unsigned count);  void cdev_del(struct cdev *p);  void cdev_put(struct cdev *p);
  • 198.
    FORMATION LINUX Les pilotes decaractères : fichiers spéciaux 198  Manipulation des fichiers spéciaux Le fichier /dev/urandom est un fichier spécial représentant un périphérique virtuel en mode caractère, de numéros majeur 1 et mineur 9. Lorsqu'on lit ce fichier, le noyau nous renvoie des octets aléatoirement choisis entre 0 et 255.  Les deux commandes suivantes sont équivalentes : $ hexdump /dev/urandom et $ mknod /dev/alea c 1 9 $ hexdump /dev/alea 1 = /dev/mem Physical memory access 2 = /dev/kmem Kernel virtual memory access 3 = /dev/null Null device 4 = /dev/port I/O port access 5 = /dev/zero Null byte source 6 = /dev/core OBSOLETE - replaced by /proc/kcore 7 = /dev/full Returns ENOSPC on write 8 = /dev/random Nondeterministic random number gen. 9 = /dev/urandom Faster, less secure random number gen. 10 = /dev/aio Asynchronous I/O notification interface 11 = /dev/kmsg Writes to this come out as printk's 12 = /dev/oldmem Used by crashdump kernels to access the memory of the kernel that crashed. (….)  Extrait de la liste des mineurs : :
  • 199.
    FORMATION LINUX Les pilotes decaractères  Communication grâce à un flux séquentiel de caractères individuels  Les pilotes caractère peuvent être identifiés par leur type c (ls –l /dev/) :  Exemples :  Méthode pour développer un driver de caractères :  Définir vos opérations sur fichier (fops)  Définir votre fonction d'init. du module et appeler register_chrdev(): • Donner un numéro majeur, ou 0 (automatique) • Donner vos fops  Définir la fonction de sortie du module, et y appeler la fonction unregister_chrdev()  Charger le module  Trouver le numéro majeur (si nécessaire) et créer l'entrée dans /dev/  http://pficheux.free.fr/articles/lmf/drivers/  http://broux.developpez.com/articles/c/driver-c-linux/  http://ftp.traduc.org/doc-vf/gazette-linux/html/2006/122/lg122-D.ht ml 199 crw-rw---- 1 root uucp 4, 64 Feb 23 2004 /dev/ttyS0 crw--w---- 1 jdoe tty 136, 1 Sep 13 06:51 /dev/pts/1 crw------- 1 root root 13, 32 Feb 23 2004 /dev/input/mouse0 crw-rw-rw- 1 root root 1, 3 Feb 23 2004 /dev/null  bluetoot h  console s,  clavier  souris  port parallèle  irDA  terminaux  etc …
  • 200.
    FORMATION LINUX Les pilotes decaractères : implémentation 200 #include <linux/module.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/slab.h> #include <asm/uaccess.h> #include <asm/semaphore.h> static char * nom_module = "file_msg"; static dev_t dev_file_msg = MKDEV(0, 0); static int numero = 0; module_param(numero, int, 0644); static struct cdev cdev_file_msg; static int read_msg (struct file * filp, char * buffer, size_t length, loff_t * offset); static int write_msg (struct file * filp, const char * buffer, size_t length, loff_t * offset); static struct file_operations fops_file_msg = { .owner = THIS_MODULE, .read = read_msg, .write = write_msg, }; Nom de la file de messages Paramètre pouvant être passé au module lors de son chargement. Structure du device Prototypes des fonctions de lecture et d’écriture. Enregistrement des fonctions  Implémentation pas à pas d’un driver de caractères gérant une file de messages :
  • 201.
    FORMATION LINUX Les pilotes decaractères : implémentation 201 static int __init chargement (void) { int erreur; if (numero == 0) { erreur = alloc_chrdev_region(& dev_file_msg, 0, 1, nom_module); } else { dev_file_msg = MKDEV(numero, 0); erreur = register_chrdev_region(dev_file_msg, 1, nom_module); } if (erreur < 0) return erreur; cdev_init(& cdev_file_msg, & fops_file_msg); erreur = cdev_add(& cdev_file_msg, dev_file_msg, 1); if (erreur != 0) goto out_unregister; erreur = -ENOMEM; cache_message = kmem_cache_create(nom_module, sizeof(message_t), 0, 0, NULL, NULL); if (cache_message == NULL) goto out_cdev_del; return 0; out_cdev_del: cdev_del(& cdev_file_msg); out_unregister: unregister_chrdev_region(dev_file_msg, 1);  Chargement du module : : Création d’un cache pour la file de messages Initialisation et ajout du driver Enregistrement du major/minor en auto si pas passé en paramètre.
  • 202.
    FORMATION LINUX Les pilotes decaractères : implémentation 202 static void __exit dechargement (void) { message_t * suivant; while (premier_message != NULL) { suivant = premier_message- >suivant; kmem_cache_free(cache_message, premier_message); premier_message = suivant; } kmem_cache_destroy(cache_message); cache_message = NULL; cdev_del(& cdev_file_msg); unregister_chrdev_region(dev_file_msg, 1); } Libération de la file de messages Libération du driver #define LG_MESSAGE_MAX 64 typedef struct s_message { char contenu [LG_MESSAGE_MAX]; struct s_message * suivant; } message_t; struct kmem_cache * cache_message = NULL; message_t * premier_message = NULL; DECLARE_MUTEX(mtx_premier_message);  Déchargement du module : :  Données globales au driver : : module_init(chargement); module_exit(dechargement); MODULE_LICENSE("GPL");  Autres déclarations globales :
  • 203.
    FORMATION LINUX Les pilotes decaractères : implémentation 203 static int read_msg(struct file * filp, char * buffer, size_t length, loff_t * offset) { int retour; int longueur; message_t * suivant; if (down_interruptible(& mtx_premier_message) != 0) return -ERESTARTSYS; retour = 0; /* 0 (=EOF), ou -EAGAIN */ if (premier_message == NULL) goto out_up_mtx; longueur = strlen(premier_message->contenu) + 1; retour = -EINVAL; if (length < longueur) goto out_up_mtx; retour = -EFAULT; if (copy_to_user(buffer, premier_message->contenu, longueur) != 0) goto out_up_mtx; retour = longueur; suivant = premier_message->suivant; kmem_cache_free(cache_message, premier_message); premier_message = suivant; ( … ) out_up_mtx: up(& mtx_premier_message); return retour; }  Fonction de lecture : :
  • 204.
    FORMATION LINUX Les pilotes decaractères : implémentation 204 static int write_msg(struct file * filp, const char * buffer, size_t length, loff_t * offset) { int retour; message_t * nouveau; message_t * precedent; if (down_interruptible(& mtx_premier_message) != 0) return -ERESTARTSYS; retour = -EINVAL; if (length >= LG_MESSAGE_MAX) goto out_up_mtx; retour = -ENOMEM; nouveau = kmem_cache_alloc(cache_message, 0); if (nouveau == NULL) goto out_up_mtx; retour = -EFAULT; if (copy_from_user(nouveau->contenu, buffer, length) != 0) { kmem_cache_free(cache_message, nouveau); goto out_up_mtx; } nouveau->contenu[length] = '0'; ( … )  Fonction d’écriture : : nouveau->suivant = NULL; if (premier_message == NULL) premier_message = nouveau; else { for (precedent = premier_message; precedent->suivant != NULL; precedent = precedent->suivant) ; precedent->suivant = nouveau; } retour = length; out_up_mtx: up(& mtx_premier_message); return retour; }
  • 205.
    FORMATION LINUX PILOTE DE BLOCS BUT: apprendre à développer un pilote de blocs.  Définition d’un pilote de blocs  Exemple d’usage
  • 206.
    FORMATION LINUX Les pilotes deblocs  Accès par blocs de données de taille fixe. On peut accéder aux blocs dans n'importe quel ordre.  Les pilotes blocs peuvent être identifiés par leur type b (ls –l /dev) :  Exemples : 206 brw-rw---- 1 root disk 3, 1 Feb 23 2004 /dev/hda1 brw-rw---- 1 jdoe floppy 2, 0 Feb 23 2004 fd0 brw-rw---- 1 root disk 7, 0 Feb 23 2004 loop0 brw-rw---- 1 root disk 1, 1 Feb 23 2004 ram1 brw------- 1 root root 8, 1 Feb 23 2004 sda1 (…)  disques durs  disques mémoire  périphériques de loopback (image de systèmes de fichiers)  etc … RAM disk 0 = /dev/ram0 First RAM disk 1 = /dev/ram1 Second RAM disk ... 250 = /dev/initrd Initial RAM disk.  Extrait de la liste des minors utilisable pour des drivers de blocs : $ ls /sys/block/ dm-0 dm-2 loop0 loop2 ram0 ram2 ram4 ram6 sda dm-1 dm-3 loop1 loop3 ram1 ram3 ram5 ram7  Liste des blocks initialisés :
  • 207.
    FORMATION LINUX Les pilotes deblocs : architecture globale 207
  • 208.
    FORMATION LINUX Les pilotes deblocs : détail de la couche blocs 208
  • 209.
    FORMATION LINUX Les pilotes deblocs : détail de la couche blocs 209
  • 210.
    FORMATION LINUX Les pilotes deblocs : implémentation 210  Détail sur l’implémentation d’un driver de bloc :  Enregistrement du numéro majeur : int register_blkdev(unsigned int major, const char *name); Le numéro majeur peut être égal à zéro ; dans le cas, il est alloué automatiquement. Une fois alloué, il doit apparaître dans /proc/devices Au déchargement, le numéro majeur doit être libéré : void unregister_blkdev(unsigned int major, const char *name); Tous ces prototypes sont enregistrés dans le header suivant : <linux/fs.h>  L'interface entre un pilote de périphériques et les applications se fait par un (ou plusieurs) fichiers spéciaux (device nodes) :  Le pilote définit ses points d'entrée grâce à une structure file_operations (<linux/fs.h>)  Les routines standards d'accès au système de fichiers sont ainsi surchargées par les routines du pilote struct file_operations mondriver_fops={ .owner = THIS_MODULE, .read = mondriver_read, .write = mondriver_write, .open = mondriver_open, .release = mondriver_release, };
  • 211.
    FORMATION LINUX Les pilotes deblocs : les structures de données 211
  • 212.
    FORMATION LINUX Les pilotes deblocs : implémentation 212 #include <linux/config.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> #include <linux/sched.h> #include <linux/kernel.h> /* printk() */ #include <linux/slab.h> /* kmalloc() */ #include <linux/fs.h> /* everything... */ #include <linux/errno.h> /* error codes */ #include <linux/timer.h> #include <linux/types.h> /* size_t */ #include <linux/fcntl.h> /* O_ACCMODE */ #include <linux/hdreg.h> /* HDIO_GETGEO */ #include <linux/kdev_t.h> #include <linux/vmalloc.h> #include <linux/genhd.h> #include <linux/blkdev.h> #include <linux/buffer_head.h> /* invalidate_bdev */ #include <linux/bio.h> MODULE_LICENSE("Dual BSD/GPL"); static int sbull_major = 0; module_param(sbull_major, int, 0); static int hardsect_size = 512; module_param(hardsect_size, int, 0); static int nsectors = 1024; /* How big the drive is */ module_param(nsectors, int, 0); static int ndevices = 4; module_param(ndevices, int, 0); /* Différents Modes utilisables. */ enum { RM_SIMPLE = 0, /* The extra-simple request function */ RM_FULL = 1, /* The full-blown version */ RM_NOQUEUE = 2, /* Use make_request */ }; static int request_mode = RM_SIMPLE; module_param(request_mode, int, 0); /* Nombre mineur et gestion des partition */ #define SBULL_MINORS 16 #define MINOR_SHIFT 4 #define DEVNUM(kdevnum) (MINOR(kdev_t_to_nr(kdevnum)) >> MINOR_SHIFT #define KERNEL_SECTOR_SIZE 512 /* Simulation du changement de media */ #define INVALIDATE_DELAY 30*HZ /* Représention interne du device */ struct sbull_dev { int size; /* Device size in sectors */ u8 *data; /* The data array */ short users; /* How many users */ short media_change; /* Flag a media change? */ spinlock_t lock; /* For mutual exclusion */ struct request_queue *queue; /* The device request queue */ struct gendisk *gd; /* The gendisk structure */ struct timer_list timer; /* For simulated media changes */ };  Exemple de driver de disque :
  • 213.
    FORMATION LINUX Les pilotes deblocs : implémentation 213 /* * Ouverture et fermeture */ static int sbull_open(struct inode *inode, struct file *filp) { struct sbull_dev *dev = inode->i_bdev->bd_disk- >private_data; del_timer_sync(&dev->timer); filp->private_data = dev; spin_lock(&dev->lock); if (! dev->users) check_disk_change(inode->i_bdev); dev->users++; spin_unlock(&dev->lock); return 0; } /* * Structure des opérations disponible */ static struct block_device_operations sbull_ops = { .owner = THIS_MODULE, .open = sbull_open, .release = sbull_release, .media_changed = sbull_media_changed, .revalidate_disk = sbull_revalidate, .ioctl = sbull_ioctl };
  • 214.
    FORMATION LINUX Les pilotes deblocs : implémentation 214 static int __init sbull_init(void) { int i; /* * Enregistrement. */ sbull_major = register_blkdev(sbull_major, "sbull"); if (sbull_major <= 0) { printk(KERN_WARNING "sbull: unable to get major numbern"); return -EBUSY; } /* * Allocation du tableau et l’initialise */ Devices = kmalloc(ndevices*sizeof (struct sbull_dev), GFP_KERNEL); if (Devices == NULL) goto out_unregister; for (i = 0; i < ndevices; i++) setup_device(Devices + i, i); return 0; out_unregister: unregister_blkdev(sbull_major, "sbd"); return -ENOMEM; } static void sbull_exit(void) { int i; for (i = 0; i < ndevices; i++) { struct sbull_dev *dev = Devices + i; del_timer_sync(&dev->timer); if (dev->gd) { del_gendisk(dev- >gd); put_disk(dev->gd); } if (dev->queue) { if (request_mode == RM_NOQUEUE) blk_put_queue(dev->queue); else blk_cleanup_queue(dev->queue); } if (dev->data) vfree(dev->data); } unregister_blkdev(sbull_major, "sbull"); kfree(Devices); }  Fonction de chargement :  Fonction de chargement :
  • 215.
    FORMATION LINUX DRIVERS RESEAUX BUT :apprendre à développer des drivers réseaux.  Architecture des drivers réseaux  Découpage modulaire  Découpage modulaire  Circulation des paquets dans la pile réseau  Netfilter et ses hooks  Références
  • 216.
    FORMATION LINUX DRIVERS RESEAUX :architecture  Un driver réseau est la troisième catégorie de drivers Linux après les drivers de blocs et de caractères.  Le fonctionnement d'une interface réseau au sein du système est assez similaire à un driver de blocs. Un driver de blocs est utilisé par le noyau pour transmettre ou recevoir des blocs de données. D'un point de vue similaire, un driver réseau s'enregistre auprès du noyau de Façon à pouvoir échanger des paquets de données avec l'extérieur.  Il y a cependant une différence avec un driver de blocs qui consiste à ne pas avoir de point d'entrée dans le répertoire dédié aux devices /dev. Il n'est donc pas possible de mettre en application la règle qui veut que sous Unix / GNU Linux tout soit considéré comme un fichier.  La différence la plus importante entre ces deux types de drivers est que le driver de blocs n'est utilisé que lorsque le driver y fait appel tandis qu'un drivers réseau reçoit les paquets réseau de façon asynchrone depuis l'extérieur.  Ainsi, alors qu'un driver de blocs demande avant d'envoyer quelque chose au noyau, le driver réseau demande à pusher des données. 
  • 217.
    FORMATION LINUX DRIVERS RESEAUX :découpage modulaire  http://docs.huihoo.com/linux/kernel/a1/index.html  L'architecture réseau permet au noyau Linux de se connecter à d'autres système via le réseau.  Il existe un certain nombre important de matériel ainsi qu'un nombre important de protocole supportés .  Chaque objet réseau est représenté via une socket. Les sockets sont associées aux process dans le même sens que les i-nodes d'un système de fichiers peuvent être associées.  Une socket peut être partagée par plusieurs processus.  L'architecture réseau utilise le scheduler de process du noyau Linux schedule() pour suspendre ou reprendre un process en état d'attente de données (géré par un système de gestion du contrôle et du flow de données).  De plus, la couche VFS apporte un système de fichiers logique (comme pour le cas de NFS ; il existe des possibilités en mode user via libfuse)
  • 218.
    FORMATION LINUX DRIVERS RESEAUX :liens Interaction entre une carte réseau et le noyau :  Toutes les cartes peuvent interagir avec le noyau de deux façon différentes :  Polling : Le noyau vérifie le status du device à intervalle régulier de façon à vérifier s'il y a quelque chose à faire ;  Interruptions : La carte envoie un signal au noyau sous la forme d'une interruption pour lui indiquer qu'il y a quelque chose à faire. • Matériel : elle accepte les paquets entrant en provenance des interfaces réseaux et les positionne directement en file d'entrée. • Software (NET_RX_SOFTIRQ) : elle exécute le handle de paquets de réception. Elle est responsable de la gestion des protocoles. Les paquets entrant sont gérés par cette interruption et placés dans une file d'attente. Les paquets à forwarder sont placés dans la file de sortie de l'interface de sortie.
  • 219.
    FORMATION LINUX DRIVERS RESEAUX :les buffers sk  Un paquet issu ou à destination du réseau n’est qu’une suite d’octets, un buffer, à émettre/recevoir.  Il est associé dans le noyau Linux à une structure de contrôle de type sk_buff appelés sk_buffers (socket buffer). A cette structure est attaché un bloc mémoire contenant le buffer reçu ou à émettre.  Lorsqu’un paquet doit être émis ou est reçu par la carte réseau, un sk_buff est créé. Cette structure de contrôle se compose notamment de :  structures représentant les couches Ethernet, réseau et transport  pointeurs pour la gestion du sk_buffer dans la liste des sk_buffers  informations sur les périphériques (devices) d’entrée/sortie  informations sur le type de paquet (broadcast, multicast, …)  du buffer contenant le paquet à proprement parlé  Des pointeurs *head, *data, *tail, et *end servent à la gestion du bloc mémoire associé au sk_buffer. head et end pointent respectivement sur le début et la fin du bloc mémoire. Data pointe sur un en-tête du paquet en fonction de l’endroit où le paquet se situe dans la pile de protocoles.  Par exemple un paquet capturé à l’aide d’un hook netfilter aura son pointeur data positionné sur le premier octet de l’en-tête IP. tail pointe sur le premier octet de bourrage du bloc mémoire (le bloc mémoire pouvant être plus grand que le paquet à stocker).
  • 220.
    FORMATION LINUX DRIVERS RESEAUX :les buffers sk  Description d'un bloc mémoire associé à un sk_buffer, l'un vide et l'autre initialisé avec un bloc mémoire initialisé avec un paquet :  Il est possible de déplacer ces pointeurs pour, par exemple, positionner le pointeur data sur un en-tête différent. Il faut cependant garder à l’esprit qu’en mode noyau aucun contrôle n’est effectué sur les accès mémoire et qu’un plantage du noyau peut donc se produire du fait d’une manipulation hasardeuse de pointeur.  Les fonctions pour manipuler les sk_buffers sont définies dans le fichier header linux/skbuff.h.
  • 221.
    FORMATION LINUX DRIVERS RESEAUX :les buffers sk La structure du buffer_sk est géré via une liste doublement chaînée.
  • 222.
    FORMATION LINUX DRIVERS RESEAUX :les buffers sk struct sk_buff_head { /* These two members must be first. */ struct sk_buff * next; struct sk_buff * prev; _ _u32 qlen; spinlock_t lock; }; Structure de données  Init. 
  • 223.
    FORMATION LINUX DRIVERS RESEAUX  Lapile TCP/IP est directement implémentée dans le noyau.  Les trames émises et reçues peuvent être amenées à traverser l’ensemble des couches (matérielles et logicielles) : Emission Réception  Représentation des trames dans le Kernel Space les paquets sont manipulés par le noyau dans des structures de type sk_buffer (évite la recopie des données).  Le parcours d’une trame reçue ou à émettre, le traitement dans la pile IP peut être découpé en phases.
  • 224.
    FORMATION LINUX DRIVERS RESEAUX :circulation des paquets  Le traitement IP comporte 4 grandes phases :  La réception de trame : point d’entrée dans la couche IP pour les trames reçues sur les interfaces réseau.  Le routage : choix de la route à suivre par le paquet (réémission sur une autre interface réseau ou destination locale)  Le forwarding : contrôle du TTL et du MTU avant de passer à la phase de réémission.  L’émission : les paquets à émettre ou à réémettre passent par cette étape. Juste avant de quitter la couche IP l’en-tête Ethernet est complété.
  • 225.
    FORMATION LINUX DRIVERS RESEAUX :circulation des paquets Couche transport OSI #4 Couche réseau OSI #3 Couche liaison OSI #2 Couche physique OSI #1  Cheminement des paquets dans les différentes couches de la stack réseau du kernel GNU Linux   Une carte réseau utilise 2 listes permettant de gérer les paquets entrants (rx_ring) et les paquets sortants (tx_ring) de la ou des interfaces réseaux.  On peut ainsi distinguer la procédure d’émission de la procédure de réception.  Pour les noyaux 2.2 et inférieurs, le traitement des trames est différent (ex : on ne retrouve pas les files tx et rx).
  • 226.
    FORMATION LINUX DRIVERS RESEAUX :le cas d’arp  A l ‘émission, seuls les paquets de type ETH_P_ALL peuvent être capturés.  Il est important de noter que, comme pour le chemin suivi par les trames dans le noyau, les fonctions utilisées dans le packet handling peuvent changer selon la version du noyau utilisé.  Pour récupérer les trames ARP, il suffit d’enregistrer une structure packet_type dans une des listes ptype (ptype_base ou ptype_all) avec la fonction de callback dev_add_pack() (définie dans linux/netdevice.h).  Comme pour les netfilter hooks, il faut supprimer ce hook (packet handling) lorsque le module est retiré du noyau. Ceci se fait grâce à la fonction dev_remove_pack() (linux/netdevice.h).  En enregistrant une fonction pour ETH_P_ALL notre packet type se retrouvera dans la liste ptype_all.  On va ainsi récupérer toutes les trames arrivant (ou à destination) du driver de la carte réseau. Lorsque l’on récupère un sk_buffer avec ce type de hook, c’est en fait une copie du sk_buffer capturé sur laquelle on va travailler. La copie doit être détruite en fin de fonction avec la fonction kfree_skb(). Ce type de hook n’est donc pas destiné à modifier le paquet capturé. Position des hooks de type « packet handling » dans la chaîne de traitement des trames reçues ou à émettre.
  • 227.
    FORMATION LINUX DRIVERS RESEAUX :buffer sk  Allocation :
  • 228.
  • 229.
    FORMATION LINUX DRIVERS RESEAUX :netfilter Patrick McHardy : Team Leader du projet Netfilter . The core Team du projet Netfilter.
  • 230.
    FORMATION LINUX DRIVERS RESEAUX :netfilter  L'intégration de netfilter, le firewall de Linux, se fait au travers de hook, de la façon suivante.  Les différents passages de fonctions s'effectuent via l'appel de NF_HOOK, une constante préprocesseur, avec les paramètres suivants :  protocole du HOOK, exemple : PF_INET pour IPv4 ;  chaîne, exemple : NF_IP_PRE_ROUTING, NF_IP_LOCAL_IN, etc ;  pointeur vers une structure struct sk_buff, qui contient en fait des données relative au paquet ;  interface d'entrée ;  interface de sortie (peut être NULL) ;  la fonction à appeler si le paquet n'est pas supprimé.  Ainsi, si CONFIG_NETFILTER, n'est pas définie, la constante NF_HOOK est définie à : #define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb) se résumant à un simple appel de la fonction okfn, avec le paramètre skb. [1] on peut traduire hook par crochet, ou bien encore intercepteur
  • 231.
    FORMATION LINUX DRIVERS RESEAUX :netfilter  Un hook peut se définir comme un point d’accès dans une chaîne de traitement (par exemple : saisie au clavier, parcours de la pile TCP/IP…).  Netfilter est un ensemble de hooks à l’intérieur du noyau Linux permettant aux modules noyau d’enregistrer des fonctions de callback dans la pile IP.  Les trames ainsi capturées peuvent être analysées, jetées ou modifiées.  Le firewall « natif » de linux iptables n’est qu’un module « sur-couche » de netfilter permettant de définir un système de règles de filtrage et masquerading (translation d’adresse) de trames IP à partir des hooks.
  • 232.
    FORMATION LINUX DRIVERS RESEAUX :hook netfilter  Ecriture d'un driver gérant un hook netfilter : /* Fonction standard de chargement d'un driver sous GNU linux */ int init_module() { nfho_tunnel_in.hook = hook_func_tunnel_in; nfho_tunnel_in.hooknum = NF_IP_PRE_ROUTING; nfho_tunnel_in.pf = PF_INET; nfho_tunnel_in.priority = NF_IP_PRI_FIRST; nf_register_hook(&nfho_tunnel_in); printk("ntNF_HOOK: Module instalenn"); return 0; } /* Fonction standard de déchargement d'un driver sous GNU Linux */ void cleanup_module() { printk("nt NF_HOOK: I'll be back ....nn"); nf_unregister_hook(&nfho_tunnel_in); }
  • 233.
    FORMATION LINUX DRIVERS RESEAUX :hook netfilter unsigned int hook_func_tunnel_in (unsigned int hooknum, struct sk_buff **skb, const struct net_device *in, const struct net_ device *out, int (*okfn)(struct sk_buff *)) { struct sk_buff* sb= *skb; struct iphdr* ip; struct net_device *dev= NULL; struct Qdisc *q; int len; len = sb->len; ip = sb->nh.iph; if((strcmp("eth0", in->name)==0) && (ip->daddr == ip1) ) { affic_skb(sb,0); sb->data -= 14; sb->len = len+ 14; memcpy(sb->data, hd_mac2, 14); dev = dev_get_by_name("eth1"); spin_lock_bh (&(dev->queue_lock)); q = dev->qdisc; q->enqueue(sb,q); qdisc_run(dev); spin_unlock_bh(&(dev->queue_lock)); affic_skb(sb,1); return( NF_STOLEN ); } (SUITE) if((strcmp("eth1", in->name)==0) &&(ip->daddr == ip0)) { affic_skb(sb,0); sb->data -= 14; sb->len = len+14 ; memcpy(sb->data,hd_mac1, 14); dev = dev_get_by_name("eth0"); spin_lock_bh (&(dev->queue_lock)); q = dev->qdisc; q->enqueue(sb,q); qdisc_run(dev); spin_unlock_bh(&(dev- >queue_lock)); return NF_STOLEN; } return( NF_ACCEPT ); } Exemple d'implémentation de la fonction de hook utilisée dans le driver réseau.
  • 234.
    FORMATION LINUX DRIVERS RESEAUX :références  «Essential Linux Device Drivers», chapter 15  «Linux Device Drivers», chapter 17  Documentation/networking/netdevices.txt  Documentation/networking/phy.txt  include/linux/netdevice.h, include/linux/ethtool.h  include/linux/phy.h, include/linux/sk_buff.h  drivers/net/ avec plusieurs implémentation de drivers réseaux  Autres modèle de drivers :  drivers/usb/usb-skeleton.c  drivers/net/isa-skeleton.c  drivers/net/pci-skeleton.c  drivers/pci/hotplug/pcihp_skeleton.c
  • 235.
    FORMATION LINUX DRIVERS PCI BUT :apprendre à développer des drivers PCI.  Les différents standards PCI  Structure d’un drivers PCI  La commande lspci  Structure dans /sys  Enregistrement des devices dans le noyau
  • 236.
    FORMATION LINUX DRIVERS PCI :les standards  PCI 32 bit bus, 33 or 66 MHz  MiniPCI Slots plus petits sur les ordinateurs portables Smaller slot in laptops  CardBus Slot externe sur les ordinateurs portables  PIX Extended (PCI-X) Slot PCI plus large, 64 bits, peut néanmoins accepter une carte PCI standard.  PCI Express (PCIe or PCI-E) Générération courante de PCI. Bus série au lieu de parallèle.  PCI Express Mini Card Remplace miniPCI sur les portables récents  Express Card Remplace les cardbus sur les portables récents Les standards existants :
  • 237.
    FORMATION LINUX DRIVERS PCI  Busle plus répandu sur les architectures supportées par Linux, API simple  Configuration dynamique des ressources à l'initialisation du noyau  Gère les différentes versions et variantes du bus PCI (Hot-plug, CardBus...)  Utilisation de l'outil lspci (lecture de /proc/bus/pci) et /proc/pci pour débogage et informations  Le sous-système PCI repose sur un mécanisme de gestion dynamique des périphériques et de leurs états  Pour implémenter un driver PCI on définit une structure pci_driver qui pointe sur les routines de contrôle du pilote  Exemple : struct pci_driver mon_pci_driver = { .name = "mondriver", .id_table = mondriver_id_table, .probe = mondriver_probe, .remove = mondriver_remove };
  • 238.
    FORMATION LINUX DRIVERS PCI  Lesfonctions pci_{register,unregister}_driver() servent alors à ajouter/supprimer le pilote de la liste des pilotes PCI.  Le tableau mondriver_id_table décrit les périphériques PCI (identifiants standardisés) que supporte le pilote.  A chaque fois qu'un périphérique définit dans le tableau mondriver_id_table change d'état (détection, suppression...), la fonction correspondante de la structure pci_driver est appelée: mondriver_probe(), mondriver_remove()  Exemple : struct pci_device_id mondriver_id_table[] = { {0x10B7, 0x9200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, madata_1}, {0x1105, 0x8400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, madata_2}, {0,} }; MODULE_DEVICE_TABLE(pci, mondriver_id_table);
  • 239.
    FORMATION LINUX DRIVERS PCI  Lafonction mondriver_probe() doit contenir tout le code nécessaire à l'initialisation d'un périphérique (allocations privées, initialisations matérielles, réservation des ressources...)  Au contraire, la fonction mondriver_remove() doit défaire tout ce qui a été fait à l'initialisation (libération des données allouées et des ressources, désactivations matérielles...)  Les fonctions d'initialisation et de libération du pilote ne s'occupent alors que des paramètres globaux du pilote (pilote PCI, nombre majeur, ressources et données globales...)  Les fonctions d'initialisation du pilote sont les suivantes :  pci_{register,unregister}_driver() : enregistrement/désenregistrement du pilote PCI  Prototypes (<linux/pci.h>) :  int pci_register_driver(struct pci_driver *drv) ;  void pci_unregister_driver(struct pci_driver *drv);  int probe(struct pci_dev *dev, const struct pci_device_id *id);  void remove(struct pci_dev *dev);
  • 240.
    FORMATION LINUX DRIVERS PCI  Unensemble de fonctions utilitaires permet de manipuler les ressources et les en-têtes PCI :  pci_{set,get}_drvdata() : attache/récupère une donnée privée (ex: pointeur sur structure privée) sur le descripteur du périphérique  pci_{enable,disable}_device() : active/désactive le périphérique au niveau matériel  pci_{read,write}_config_{byte,word,dword}() : lit/écrit 8, 16 ou 32 bits dans les en-têtes PCI  pci_find_capability() : détermine si le périphérique supporte une fonctionnalité PCI donnée (ex: PCI_CAP_ID_PM)  pci_{request,release}_regions() : réserve/libère automatiquement tous les ports et plages mémoire d'E/S du périphérique  pci_resource_{start,end,len,flags}() : retourne l'adresse de début/fin, la longueur ou les caractéristiques d'une ressource d'E/S (port ou mémoire).
  • 241.
    FORMATION LINUX DRIVERS PCI  Prototypes(<linux/pci.h>) :  void * pci_get_drvdata(struct pci_dev *dev);  void pci_set_drvdata(struct pci_dev *dev, void *data);  int pci_enable_device(struct pci_dev *dev);  void pci_disable_device(struct pci_dev *dev);  int pci_read_config_{byte,word,dword}(struct pci_dev *dev, int addr, u{8,16,32} *val);  int pci_write_config_{byte,word,dword}(struct pci_dev *dev, int addr, u{8,16,32} val);  int pci_find_capability(struct pci_dev *dev, int capability);  int pci_request_regions(struct pci_dev *dev, char *name);  int pci_release_regions(struct pci_dev *dev);  unsigned long pci_resource_{start,end,len,flags}(struct pci_dev *dev, int bar);
  • 242.
  • 243.
  • 244.
    FORMATION LINUX DRIVERS PCI  :Enregistrement des drivers supportés
  • 245.
  • 246.
  • 247.
  • 248.
  • 249.
  • 250.
    FORMATION LINUX DRIVERS USB BUT :apprendre à développer des drivers USB.  Architecture  Standards  Vue d’un device  Implémentation d’un driver
  • 251.
    FORMATION LINUX DRIVERS USB :architecture Device USB
  • 252.
    FORMATION LINUX DRIVERS USB :standard OHCI - Open Host Controller Interface Implémentation de HP/Compaq adopté comme standard pour l’USB 1.0 et 1.1 UHCI - Universal Host Controller Interface. Crée par la société Intel  USB : Universal Serial Bus  Protocole Maître / Esclave  Les deux interfaces HCD (Host Control Device): EHCI - Extended Host Controller Interface : pour les débit plus élevés en USB 2.0 Low-Speed: up to 1.5 MbpsSince USB 1.0 Full-Speed: up to 12 MbpsSince USB 1.1 Hi-Speed: up to 480 MbpsSince USB 2.0  Les débits :
  • 253.
    FORMATION LINUX DRIVERS USB :standard Topologie en arbre
  • 254.
  • 255.
    FORMATION LINUX DRIVERS USB :standard  Un périphérique USB est décrit par :  device descriptor : unique, paramètres globaux du périphérique  configuration descriptor : modifient le comportement global du périphérique (ex: mode d'énergie), une seule configuration active à la fois  interface descriptor : interfaces offertes par le périphérique, plusieurs interfaces peuvent être actives simultanément (et être gérées par des pilotes Linux différents)  alternate settings : modifient le comportement de l'interface  endpoint descriptor : canaux de communication d'une interface (0 pour les transferts de contrôle)  Transferts :  Control : paquets courts prédéfinis (GET_DESCRIPTOR, SET_DESCRIPTOR, GET_CONFIGURATION, SET_CONFIGURATION, GET_INTERFACE, SET_INTERFACE, etc)  Bulk : paquets plus longs au débit max  Interrupt : bulk répétitifs (1-127 ms)  Isochronous : flux avec garantie de bande passante
  • 256.
    FORMATION LINUX DRIVERS USB  Lestransferts se font par des USB Request Blocks  Comportement asynchrone par callback  Les transferts se font par DMA ou non suivant le périphérique et le contrôleur USB  Structure d'un pilote USB (proche d'un pilote PCI) :  déclaration du pilote (usb_register avec en paramètre une structure usb_driver décrivant les callbacks du pilote)  initialisation du périphérique, choix de la configuration, etc.  couplage avec une interface de communication avec le mode utilisateur (pilote char, bloc, réseau etc)  pour la communication (dans read/write etc), allocation d'un URB, envoi de l'URB et attente de complétion asynchrone  Documentation :  Documentation/usb/  Documentation/DocBook  Resources : www.linux-usb.org/  Exemple de pilote :  drivers/usb/usbskeleton.c  drivers/usb/*
  • 257.
    FORMATION LINUX DRIVERS USB :vue d’un device USB
  • 258.
  • 259.
  • 260.
  • 261.
    FORMATION LINUX DRIVERS TTY BUT :comprendre l’architecture d’un driver TTY.  Architecture d’un driver tty
  • 262.
    FORMATION LINUX Pilote gestionnaire detty 262 Exemple de pilote gérant un TTY (terminal en mode caractère sous unix) : TTY est l’abérévation de « TeleTYpe ».
  • 263.
    FORMATION LINUX ENREGISTREMENT DANS /DEV BUT: apprendre à enregistrer des drivers.  Enregistrement manuel :  Les fichiers de périphériques  Enregistrement des périphériques  Périphériques enregistrés  Recherche de numéro majeur libre  Enregistrement automatique :  Hotplug  Udev
  • 264.
    FORMATION LINUX  Nombres majeurset nombres mineurs :  Comme vous pouvez le voir dans l'exemple précédent, les périphériques ont 2 numéros qui leurs sont associés : • Premier numéro: nombre majeur Associé de manière unique à chaque pilote • Second numéro: nombre mineur Associé de manière unique à chaque périphérique / entrée dans /dev  Pour trouver quel pilote correspond à un périphérique, regardez Documentation/devices.txt et <linux/major.h> Les fichiers de périphériques (ou fichiers spéciaux / device node) ne sont pas forcément créés dans /dev (par défaut par convention mais pas obligatoire) lorsqu'un pilote est chargé. Ils doivent être créés par avance : mknod /dev/<device> [c|b] <major> <minor> Exemples : mknod /dev/ttyS0 c 4 64 mknod /dev/hda1 b 3 1 264 Les fichiers de périphériques
  • 265.
    FORMATION LINUX Enregistrement des périphériques Tout d'abord il faut créer la ou les entrée(s) correspondante(s) dans /dev  Initialisation du pilote : enregistrement avec un numéro majeur (c’est le noyau qui donne un numéro de major en retour de la fonction register) ; c’est au drivers de gérer son numéro minor.  Enregistrement (linux/fs.h) : int register_chrdev( unsigned it major, const char *name, struct file_operations *fops); Si le paramètre major est égal à zéro, alors son enregistrement est automatique (appel à alloc_chrdev_region).  Libération du périphérique : int unregister_chrdev( unsigned it major, const char *name);  Si ces fonctions échouent, elles retournent une valeur strictement < 0. 265
  • 266.
    FORMATION LINUX Périphériques enregistrés  Lespériphériques une fois enregistrés sont visibles dans /proc/devices avec leur numéro majeur et leur nom : Character devices: 1 mem 4 /dev/vc/0 4 tty 4 ttyS 5 /dev/tty 5 /dev/console 5 /dev/ptmx 6 lp 7 vcs 10 misc 13 input 14 sound ... Block devices: 1 ramdisk 3 ide0 8 sd 9 md 22 ide1 65 sd 66 sd 67 sd 68 sd 69 sd ... 266
  • 267.
    FORMATION LINUX Trouver un numéromajeur libre  De moins en moins de numéros majeurs sont disponibles  Il n'est pas recommandé d'en prendre un arbitrairement, car il peut rentrer en conflit avec un autre pilote (standard ou spécifique)  Solution: laisser register_chrdev en trouver un libre dynamiquement pour vous ! major = register_chrdev (0, "foo", &name_fops);  Problème: vous ne pouvez pas créer d'entrées /dev par avance !  Exemple de script de chargement de module (se sert de /proc/devices) : module=foo; device=foo insmod $module.ko major=`awk "$2=="$module" {print $1}" /proc/devices` mknod /dev/foo0 c $major 0 267
  • 268.
    FORMATION LINUX Aperçu du hotplug Introduit dans le noyau Linux 2.4. USB a été le pionnier.  Mécanismes noyau pour notifier les programmes de l'espace utilisateur qu'un périphérique a été inséré ou enlevé.  Des scripts dans l'espace utilisateur prennent ensuite soin d'identifier le matériel et d'insérer/enlever les modules requis.  Linux 2.6: l'identification des périphériques est simplifiée grâce à sysfs.  Rend possible le chargement de micrologiciel (firmware).  Permet d'avoir des pilotes en mode utilisateur (par exemple libsane).  Configuration dans le noyau : CONFIG_HOTPLUG=y (section "General setup”) Page du projet et documentation : http://linux-hotplug.sourceforge.net/ Liste de diffusion : http://lists.sourceforge.net/lists/listinfo/linux-hotplug-devel 268
  • 269.
  • 270.
    FORMATION LINUX Exemple de fluxhotplug /sbin/hotplug usb /sys mis à jour Support hotplug du noyau Variables d'environment usb.agent Identifie le périphérique (Dé)charge les modules correspondant ou le pilote en mode utilisateur Appelle / notifie les autres programmes ACTION=add|remove DEVPATH=<sysfs_path> SEQNUM=<num> ACTION=add|remove DEVPATH=<sysfs_path> KERNEL UserSpace 270
  • 271.
    FORMATION LINUX  Le fichierde configuration de udev (/etc/udev/udev.conf) :  Facile à éditer et à configurer  Répertoire des fichiers de périphériques (/udev)  Base de données udev (/dev/.udev.tdb)  Règles udev (/etc/udev/rules.d/) Permissions udev (/etc/udev/permissions.d/)  mode par défaut (0600), utilisateur par défaut (root) et groupe (root), si pas trouvés dans les permissions de udev.  Activation des traces (log) (yes) Les messages de déboguage sont dans /var/log/messages Tire partie à la fois de hotplug et de sysfs : 271 Caractéristiques de udev  Entièrement dans l'espace utilisateur  Créé automatiquement les entrées pour les périphériques (par défaut dans /udev)  Appelé par /sbin/hotplug, utilise les informations de sysfs (notamment les nombres Majeur/Mineur)  Ne requiert aucun changement dans le code du pilote  Petite taille
  • 272.
    FORMATION LINUX Fichiers utilisés parhotplug /lib/modules/*/modules.*map sortie de depmod /proc/sys/kernel/hotplug specifie le chemin du programme hotplug /sbin/hotplug programme hotplug (par défaut) /etc/hotplug/* fichiers hotplug /etc/hotplug/NAME* fichiers spécifiques aux sous-systèmes, pour les agents /etc/hotplug/NAME/DRIVER scripts de configuration des pilotes, invoqués par les agents /etc/hotplug/usb/DRIVER.usermap données pour depmod pour les pilotes en mode utilisateur /etc/hotplug/NAME.agent Agents spécifiques à des sous-systèmes de hotplug. 272
  • 273.
    FORMATION LINUX Problèmes et limitationsde /dev  Sur Red Hat 9, il y avait 18 000 entrées dans le répertoire /dev !!! A l'installation du système, toutes les entrées possibles des périphériques doivent être créées.  Besoin d'une autorité pour assigner les major numbers http://lanana.org/: Linux Assigned Names and Numbers Authority  Pas assez de nombres dans 2.4, la limite a été étendue dans 2.6  L'espace utilisateur ne sait pas quels périphériques sont présents dans le système.  L'espace utilisateur ne sait pas associer une entrée dans /dev avec le périphérique auquel elle se rapporte  Montre seulement les périphériques présents  Mais utilise des noms différents à ceux de /dev, ce qui pose des problèmes dans les scripts.  Mais aucune flexibilité dans le nom des devices (par rapport à /dev/) i.e. le 1er disque IDE s'appelle soit /dev/hda, soit /dev/ide/hd/c0b0t0u0.  Mais ne permet pas l'allocation dynamique des nombres majeur et mineur.  Mais requiert de stocker la politique de nommage des périphériques dans la mémoire du noyau. Ne peut pas être swappée! La solution devfs et ses limitations : 273
  • 274.
    FORMATION LINUX Boîte à outilsde udev  Composants principaux :  udevsend (8KB dans FC 3) Gère les événements de /sbin/hotplug, et les envoie à udevd  udevd (12KB dans FC 3) Réordonne les événements de hotplug, avant d'appeler les instance de udev pour chacun d'eux.  udev (68KB dans FC 3) Créé ou efface les fichiers périphériques et ensuite exécute les programmes dans /etc/dev.d/  Autres utilitaires :  udevinfo (48KB dans FC 3) Permet aux utilisateurs d'interroger la base de données de udev  udevstart (fonctionnalité apportée par udev) Rempli le répertoire initial des périphériques avec des entrées valides trouvées dans l'arbre de périphériques de sysfs.  udevtest <chemin_dev_sysfs> (64KB dans FC 3) Simule une exécution de udev pour tester les règles configurées 274
  • 275.
    FORMATION LINUX Exemple de configuration #Si /sbin/scsi_id retourne "OEM 0815", le périphérique sera appelé disk1 BUS="scsi", PROGRAM="/sbin/scsi_id", RESULT="OEM 0815", NAME="disk1" # Imprimante USB appelée lp_color BUS="usb", SYSFS{serial}="W09090207101241330", NAME="lp_color" # Un disque SCSI avec un numéro de vendeur/modèle spécifique devient boot BUS="scsi", SYSFS{vendor}="IBM", SYSFS{model}="ST336", NAME="boot%n" # La carte son avec l'id 00:0b.0 sur le bus PCI sera appelée dsp BUS="pci", ID="00:0b.0", NAME="dsp" # La souris USB sur le 3ème port du 2nd hub sera appelée mouse1 BUS="usb", PLACE="2.3", NAME="mouse1" # ttyUSB1 doit tjrs être appelé pda et avoir 2 autres liens symboliques KERNEL="ttyUSB1", NAME="pda", SYMLINK="palmtop handheld" # Webcams USB multiples avec des liens appelés webcam0, webcam1, ... BUS="usb", SYSFS{model}="XV3", NAME="video%n", SYMLINK="webcam%n" #name:user:group:mode input/*:root:root:644 ttyUSB1:0:8:0660 video*:root:video:0660 dsp1:::0666 Fichier de permissions udev : Fichier de règles pour udev : 275
  • 276.
    FORMATION LINUX  Les pointde montage dans /etc/dev.d/  Après la création, destruction, renommage des noeuds de périphériques, udev peut appeler des programmes dans l'ordre suivant de priorité:  /etc/dev.d/$(DEVNAME)/*.dev  /etc/dev.d/$(SUBSYSTEM)/*.dev  /etc/dev.d/default/*.dev Les programmes de chaque répertoire sont triés par ordre alphabétique. Cela permet de notifier les applications utilisateurs de changements au niveau des périphériques. • Sources : http://kernel.org/pub/linux/utils/kernel/hotplug/ • Liste de diffusion : linux-hotplug-devel@lists.sourceforge.net • Présentation de udev de Greg Kroah-Hartman : ttp://www.kroah.com/linux/talks/oscon_2004_udev/ • Documentation udev de Greg Kroah-Hartman :http://www.kroah.com/linux/talks/ols_2003_udev_paper/Reprint-Kroah-Hartman-OLS2003.pdf  Le nom des fichiers de périphériques peut être défini :  depuis un label ou un numéro de série  depuis un numéro de périphérique sur le bus  depuis une position dans la topologie du bus  depuis un nom du noyau  udev peut aussi créé des liens symboliques vers d'autres fichiers périphériques 276 Capacités de nommage de udev
  • 277.
    FORMATION LINUX Schéma d'architecture deudev /sbin/hotplug /sys mis à jour Support hotplug du noyau udevsend udevd Lecture fichiers de config Associe périph. et règles Créé / efface les devices udev Programmes /etc/dev.d/ Programmes utilisateur * * * envoie de paramètres par variables d'environnement * * * 277
  • 278.
    FORMATION LINUX THREADS NOYAU BUT :apprendre à utilise des threads dans le noyau.  Définition des thread noyau  Primitives des kthreads  Exemple simple
  • 279.
    FORMATION LINUX Threads noyau  Contexted'exécution semblable à un processus standard  Mais un thread noyau n'a aucune ressource correspondant au mode utilisateur (mémoire, handlers des signaux etc)  Utilisés pour implémenter les daemons noyau, chargés de réaliser des tâches récurrentes (ex: gestion du swap, vidange des caches, gestion du journal de ext3, etc.)  Toute fonction d'API utilisable en contexte processus l'est en contexte kernel thread (sémaphores, allocation GFP_KERNEL, etc)  Création d'une kernel thread :  par la fonction kernel_thread()  après la création il faut emanciper la kernel thread (libération des ressources) : daemonize()  Arrêt d'une kernel thread :  – par la fonction kill_proc()  – la kernel thread doit prendre en compte sa terminaison et sortir de sa fonction main()  – souvent l'appelant doit attendre la fin effective de la kernel thread (appel depuis module_exit()) : utilisation d'une variable de terminaison 279
  • 280.
    FORMATION LINUX Threads noyau  Initialisationd'une variable de terminaison (type struct completion) :  Statique : DECLARE_COMPLETION()  Runtime : init_completion()  Fonctions de terminaison des threads noyau :  wait_for_completion() : attend la terminaison effective du thread  complete() : signale la terminaison du thread  complete_and_exit() : signale la terminaison et termine le thread (atomiquement)  Prototypes (<linux/sched.h>) :  int kernel_thread(int (*kth)(void *), void *arg, unsigned long flags);  void daemonize(void);  int kill_proc(pid_t pid, int sig, int priv);  Prototypes (<linux/completion.h>) :  DECLARE_COMPLETION(name);  void init_completion(struct completion *comp);  void wait_for_completion(struct completion *comp);  void complete(struct completion *comp);  void complete_and_exit(struct completion *comp, long code); 280
  • 281.
    FORMATION LINUX Threads noyau  APIsimplifié à partir du 2.6.14 :  kthread_run(): crée et lance une kernel thread  kthread_stop(): envoie une demande de terminaison à une kernel thread et attend la terminaison effective  kthread_stop_sem(): même comportement que kthread_stop() + up()  kthread_should_stop(): doit être appelée par la kernel thread régulièrement pour prendre en compte les demandes de terminaison, et si la valeur est true, la kernel thread doit se finir.  Prototypes (<linux/kthread.h>) :  struct task_struct *kthread_run(int (*threadfn)(void *data), void *data, const char namefmt[], ...);  void kthread_bind(struct task_struct *k, unsigned int cpu);  int kthread_stop(struct task_struct *k);  int kthread_stop_sem(struct task_struct *k, struct semaphore *s);  int kthread_should_stop(void); 281 ;Verdana;Verdana
  • 282.
    FORMATION LINUX THREADS NOYAU :résumé  start_kthread : Crée un kthread dans le noyau (équivalent de pthread_create). Peut être appelé depuis n'importe quel contexte mais pas par une interruption.  stop_kthread : Arrète un kthread. Peut être appelée depuis n'importe quel contexte mais pas depuis le kthread lui- même. La fonction est blocante.  init_kthread : Configure l'environnement pour un nouveau kthread. Cette fonction peut être appelée en dehors d'un kthread.  exit_kthread : nécessite d'être appelé par thread lui-même à la fin de son exécution http://kernelnewbies.org/Simple_UDP_Server  http://lemmestart.blogspot.com/2007/05/linux-kernel-threads-in-device-drivers_14.html  http://kernelnewbies.org/Simple_UDP_Server  http://www.freeos.com/articles/4051/  http://www.freesoftwaremagazine.com/articles/drivers_linux  http://www.scs.ch/~frey/linux/kernelthreads.html 282
  • 283.
    FORMATION LINUX Threads noyau :exemple simple  Exemple simple: 283 static struct task_struct *th; static int thd(void *data) { do { ... } while (!kthread_should_stop()); return 0; } ... th = kthread_run(thd, NULL, "thd%d", 42); ... kthread_stop(th);
  • 284.
    FORMATION LINUX SYNCHRONISATION BUT : apprendreles techniques de synchonisations.  Présentation des méthodes de synchronisation  Opérations atomiques  Désactivation des interruptions  Sémaphores  Mutexes  Verrous
  • 285.
    FORMATION LINUX Synchronisation 285  Le noyau2.6 est préemptif (capacité d'un système d'exploitation multitâche à exécuter ou stopper une tâche planifiée en cours en faveur d'une tâche de priorité supérieure).  Mais même si on désactive la préemption (ou noyau 2.4) :  un processus en mode noyau peut relâcher le CPU : • volontairement (ex : schedule(), wait_event()...) • involontairement (ex : kmalloc(), {get,put}_user()...)  un processus en mode noyau peut être interrompu par un gestionnaire d'interruptions  un autre processus peut se trouver en mode noyau au même moment mais sur un autre processeur.  Pour toutes ces raisons, on doit protéger les données ou ressources partagées afin d'éviter les accès concurrents.  Plusieurs mécanismes, plus ou moins coûteux, existent dans le noyau pour résoudre ces problèmes :  Opérations atomiques  Désactivation des interruptions  Sémaphores  Verrous  Verrous séquentiels (seqlocks) : utilisable au début et à la fin de l’écriture d’un buffer (compteur avec vérification e cohérence).
  • 286.
    FORMATION LINUX Opérations atomiques 286  Opérationsatomiques sur les bits :  {set,clear,change,test}_bit();  test_and_{set,clear,change}_bit().  Prototypes (<asm/bitops.h>) :  void {set,clear,change}_bit(int nr, volatile void *addr);  int test_*(int nr, volatile void *addr)  Opérations atomiques sur des entiers (type atomic_t) :  atomic_{read,set,add,sub,inc,dec}()  atomic_{inc,dec}_and_test()  Prototypes (<asm/atomic.h>) :  int atomic_read(atomic_t *v);  void atomic_set(atomic_t *v, int i);  void atomic_{add,sub}(int i, volatile atomic_t *v);  void atomic_{inc,dec}(volatile atomic_t *v);  int atomic_{inc,dec}_and_test(volatile atomic_t *v);
  • 287.
    FORMATION LINUX Désactivations des interruptions 287 Protection des ressources en concurrence avec des gestionnaires d'interruptions uniquement :  local_irq_disable()/local_irq_enable() : désactive/active les interruptions sur le processeur courant  local_{save,restore}_flags() : sauvegarde/restore les drapeaux d'interruptions (IF) sur le processeur courant  {disable,enable}_irq( ): désactive/active une seule ligne d'IRQ sur tous les processeurs et pour une IRQ donnée.  Les macros cli()/sti() (applicables à tous les processeurs), présentes en 2.2, ont été dépréciées en 2.4 et enlevées en 2.6.  Prototypes (<asm/system.h> et <asm/irq.h>) :  void local_irq_{enable/disable}(void);  void local_{save,restore}_flags (unsigned long old);  void {enable,disable}_irq(unsigned int irq);  Attention, ne pas utiliser de fonctions qui relâchent le CPU (appel à schedule()) dans une section non interruptible par une IRQ car il y a un risque de blocage.  La macro local_restore_flags() réactive l'état précédent, donc pas besoin de faire un appel à local_irq_enable();
  • 288.
    FORMATION LINUX Désactivations des interruptions 288 Exemple (uniquement pour système mono-processeur) : local_save_flags(old); local_irq_disable(); /* ... accès exclusif à la ressource partagée ... */ local_restore_flags(old);
  • 289.
    FORMATION LINUX SEMAPHORES 289  Mécanisme universelde synchronisation et de protection des ressources partagées  Basé sur un compteur et deux primitives atomiques :  P() : « Puis-je accéder à la ressource ? » - décrémente le compteur et endort le processus si le compteur est inférieur à 0  V() : « Vas-y ! » - incrémente le compteur et débloque le premier processus bloqué sur la ressource.  Il existe des sémaphores pour différentes problématiques :  exclusion mutuelle (mutex)  cohabitation producteurs-consommateurs (semaphore)  cohabitation lecteurs-écrivains (rwsem)  Pour la cohabitation producteursconsommateurs, les consommateurs ne peuvent consommer que ce qui a été produit (sémaphores à compte)  Pour la cohabitation lecteurs-écrivains :  plusieurs lecteurs peuvent lire la ressource simultanément  un seul écrivain peut la modifier
  • 290.
    FORMATION LINUX SEMAPHORES 290  Les fonctionsdown()/up() implémentent les concepts P() et V(). Une analogie possible peut être faite avec un passage à niveau : barrière levée pour UP et barrière baissée pour DOWN.  La fonction down() endort le processus appelant si la ressource n'est pas disponible  Les sémaphores ne sont donc pas utilisables dans un cas de concurrence avec un gestionnaire d'interruptions  Principalement utilisés pour gérer la concurrence dans le code noyau exécuté à la demande de processus utilisateurs (appels système)  Les variantes suivantes sont également utiles :  down_trylock() : permet de ne pas endormir automatiquement le processus si la ressource n'est pas accessible (utilisable dans les gestionnaires d'interruptions)  down_interruptible() : endort le processus si la ressource n'est pas accessible mais peut être réveillé par un signal.  Initialisation d'un mutex ou d'un semaphore (type struct semaphore) :  Statique : DECLARE_MUTEX{_LOCKED}() ou __DECLARE_SEMAPHORE_GENERIC() : sémaphore à compteur  Runtime : init_MUTEX{_LOCKED}() ou sema_init().
  • 291.
    FORMATION LINUX SEMAPHORES 291  Prototypes (<{linux,asm}/semaphore.h>):  DECLARE_MUTEX{_LOCKED}(name);  __DECLARE_SEMAPHORE_GENERIC(name, val);  void init_MUTEX{_LOCKED}(struct semaphore *sem);  void sema_init(struct semaphore *sem, int val);  void {down,up}(struct semaphore *sem);  int down_*(struct semaphore *sem);  Initialisation d'un rwsem (type struct rw_semaphore) :  Statique : DECLARE_RWSEM()  Runtime : init_rwsem()  Prototypes (<{linux,asm}/rwsem.h>) :  DECLARE_RWSEM(name);  void init_rwsem(struct rw_semaphore *sem);  void {down,up}_{read,write}(struct rw_semaphore *sem);
  • 292.
    FORMATION LINUX SEMAPHORES 292  Exemple d'exclusionmutuelle :  Exemple de lecteurs écrivains : static DECLARE_MUTEX(foo_sem); down(&foo_sem); /* ...accès exclusif à la ressource foo en lecture/écriture... */ up(&foo_sem); static DECLARE_RW_SEM(bar_rwsem); down_read(&bar_rwsem); /* ...accès exclusif à la ressource bar enlecture uniquement... */ up_read(&bar_rwsem);
  • 293.
    FORMATION LINUX SEMAPHORES 293  Exemple d'exclusionmutuelle :  Exemple de lecteurs écrivains : C’est au développeur de respecter la lecture/écriture. static DECLARE_MUTEX(foo_sem); down(&foo_sem); /* ...accès exclusif à la ressource foo en lecture/écriture... */ up(&foo_sem); static DECLARE_RW_SEM(bar_rwsem); down_read(&bar_rwsem); /* ...accès exclusif à la ressource bar enlecture uniquement... */ up_read(&bar_rwsem);
  • 294.
    FORMATION LINUX MUTEXES 294  Introduits en2.6.16  Spécialisation des sémaphores, destiné à remplacer les DECLARE_MUTEX()  Utilisables uniquement en contexte processus, une prise de mutex endort le processus appelant si le mutex n'est pas disponible  L'opération P() se fait par mutex_lock()  L'opération V() se fait par mutex_unlock()  Initialisation d'un mutex (type struct mutex) :  statique: DEFINE_MUTEX()  runtime: mutex_init()  Prototypes (<{linux,asm}/mutex.h>) :  DEFINE_MUTEX(name);  void mutex_init(struct mutex *lock);  void mutex_lock(struct mutex *lock);  int mutex_lock_interruptible(struct mutex *lock);  int mutex_trylock(struct mutex *lock);  void mutex_unlock(struct mutex *lock);  int mutex_is_locked(struct mutex *lock);
  • 295.
    FORMATION LINUX VERROUS 295  A utiliserpour les zones critiques utilisés par le systèmes et les handlers d’interruptions.  Les verrous (locks) sont des mécanismes de synchronisation pour les sections critiques intra-noyau  Basés sur des mécanismes d'attente active de la ressource :  en SMP : boucle while(1) try_get_lock(); -> vérouille le scheduler en mode multiprocesseurs  en UP préemptible (en mode mono-processeur) : désactivation de la préemption noyau  en UP non préemptible (en mode mono-proceeseur) : rien  Plus désactivation éventuelle des interruptions dans le cas de concurrence avec un gestionnaire d'interruptions  Il existe des verrous pour différentes problématiques :  exclusion mutuelle (spinlocks)  cohabitation lecteurs-écrivains (rwlocks)  Pour la cohabitation lecteurs-écrivains :  plusieurs lecteurs peuvent lire la ressource simultanément  un seul écrivain peut la modifier
  • 296.
    FORMATION LINUX VERROUS 296  Les fonctionsde manipulation des locks (types spinlock_t ou rwlock_t) sont les suivantes :  spin_{lock,unlock}() : ouverture/fermeture d'un verrou d'exclusion mutuelle  spin_trylock() : essai de fermeture d'un verrou d'exclusion mutuelle  {read,write}_lock() : fermeture d'un verrou par un lecteur/écrivain  {read,write}_unlock() : ouverture d'un verrou par un lecteur/écrivain  Si on veut aussi protéger contre un accès par un gestionnaire d'interruptions, on utilise les fonctions suffixés par :  _irq : blocage/déblocage des interruptions avec les fonctions *_lock()/*_unlock() Exemple: spin_lock_irq  _irqsave : blocage des interruptions et sauvegarde du contexte avec les fonctions *_lock()  _irqrestore : déblocage des interruptions et restauration du contexte avec les fonctions *_unlock()  Initialisation d'un spinlock (type spinlock_t) :  Statique : constante SPIN_LOCK_{UN}LOCKED  Runtime : spin_lock_init()  Initialisation d'un rwlock (type rwlock_t) :  Statique : constante RW_LOCK_{UN}LOCKED  Runtime : rw_lock_init() ;Verdana
  • 297.
    FORMATION LINUX VERROUS 297  Prototypes (<asm/spinlock.h>):  void {spin,rw}_lock_init({spin,rw}lock_t lock);  void {spin,read,write}_{lock,unlock}{_irq}({spin,rw}lock_t lock);  void {spin,read,write}_lock_irqsave({spin,rw}lock_t lock, unsigned long flags);  void {spin,read,write}_unlock_irqrestore({spin, rw}lock_t lock, unsigned long flags);  int spin_trylock(spinlock_t lock);  Exemple de lecteurs-écrivains : ;Verdana rwlock_t foo_rw_lock = RW_LOCK_UNLOCKED; read_lock(&foo_rw_lock); /* ...accès exclusif à la ressource foo en lecture uniquement... */ read_unlock(&foo_rw_lock); [...] write_lock(&foo_rw_lock); /* ...accès exclusif à la ressource foo en lecture/écriture... */ write_unlock(&foo_rw_lock);
  • 298.
    FORMATION LINUX VERROUS 298  Exemple d'exclusionmutuelle: ;Verdana spinlock_t bar_spin_lock = SPIN_LOCK_UNLOCKED; spin_lock(&bar_spin_lock); /* ...accès exclusif à la ressource bar en lecture/écriture... */ spin_unlock(&bar_spin_lock);
  • 299.
    FORMATION LINUX TIMERS BUT : apprendreà maîtriser l’usage des timers.  La variable jiffies et jiffies_64  La mesure du temps  Exemple de timer noyau à 5 secondes  Exemple d’utilisation d’un timer dans un module
  • 300.
    FORMATION LINUX Mesure du temps 300 La variable jiffies représente le nombre de ticks d'horloge depuis le démarrage de la machine (<linux/param.h>, <linux/jiffies.h>)  Le noyau 2.6 introduit jiffies_64 qui est composé de jiffies en poids faible (accès par get_jiffies_64()).  HZ est le nombre de ticks d'horloge par seconde (100 sur plate-forme Intel/2.4, 1000 sur Intel/2.6 : valeur définie lors de la compilation).  Exemple d'attente coopérative de 2 secondes :  La fonction schedule_timeout() permet de réaliser une attente coopérative plus efficace (en ayant pris soin de changer le statut du processus courant avec la macro set_current_state()) ;  Exemple d'attente coopérative de 2 secondes :  Pour des délais plus courts et non coopératifs (ex : synchronisation avec le matériel) on préférera udelay() ou mdelay() (ou ndelay() en 2.6) unsigned long jiffies_fin = jiffies + 2*HZ; while (time_before(jiffies, jiffies_fin)) schedule(); set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(2 * HZ);
  • 301.
    FORMATION LINUX TIMERS 301  Prototypes (<linux/sched.h>et <linux/delay.h>) :  u64 get_jiffies_64 (void);  long schedule_timeout(long timeout);  void set_current_state(int state);  void ndelay(unsigned long nsecs);  void udelay(unsigned long usecs);  void mdelay(unsigned long msecs);  Permettent d'exécuter une fonction donnée à une date (en jiffies) précise dans le futur (one-shot).  Routines de contrôle :  init_timer() : créer un nouveau timer  timer.function=my_func;  timer.data=my_arg ;  mod_timer() : initialise (champ expires) et lance un timer  add_timer() : lance un timer (peu utilisé)  del_timer{_sync}() : destruction du timer avant son expiration.  Prototypes (<linux/timer.h>) :  void init_timer(struct timer_list *timer);  void mod_timer(struct timer_list *timer, unsigned long expires);  void add_timer(struct timer_list *timer);  int del_timer{_sync}(struct timer_list *timer);  int add_timer_on(struct timer_list *timer, int cpu); (2.6 uniquement)
  • 302.
    FORMATION LINUX TIMERS : exemple 302 Exemple de timer noyau à 5 secondes : static struct timer_list mon_timer; init_timer(&mon_timer); mon_timer.function = ma_fonction; mon_timer.data = mon_argument; mod_timer(&mon_timer, jiffies + 5 * HZ);
  • 303.
    FORMATION LINUX TIMERS : exempled’usage dans un module 303 #include <linux/module.h> static void fonction_periodique (unsigned long); static struct timer_list timer; static int __init chargement (void) { init_timer (& timer); timer.function = fonction_periodique; timer.data = 0; /* inutilise */ timer.expires = jiffies + HZ; add_timer(& timer); return 0; } static void __exit dechargement (void) { del_timer(& timer); } static void fonction_periodique(unsigned long inutile) { struct timeval time_of_day; do_gettimeofday(& time_of_day); printk(KERN_INFO "time_of_day: %ld.%06ldn", time_of_day.tv_sec, time_of_day.tv_usec); mod_timer(& timer, jiffies+HZ); } module_init(chargement); module_exit(dechargement); MODULE_LICENSE("GPL"); Déclaration Initialisation et exécution Fonction appelée par le timer
  • 304.
    FORMATION LINUX QUEUE DE TRAVAIL(WORKQUEUE) BUT : apprendre à tes techniques de queue de travail.  Définition des queues de travail  Deux exemples simples  Exemple d’usage d’une queue de travail dans un module
  • 305.
    FORMATION LINUX QUEUE DE TRAVAIL 305 Noyau 2.6 uniquement  Prototypes légèrement modifiés en 2.6.20 (disparition de l'argument data)  Autre façon de reporter certaines exécutions  Permettent d'accumuler des tâches dans une queue puis de les lancer de manière séquentielle à un moment choisi  L'exécution se déroule dans le contexte d'un processus  Possibilité d'utiliser une queue système ou bien définir sa propre queue  Création d'une workqueue (type struct workqueue_struct) :  create_workqueue()  Création d'une tâche (type struct work_struct) :  Statique : DECLARE_WORK()  Runtime : • INIT_WORK() : alloue et initialise une tâche • PREPARE_WORK() : initialise une tâche  Par la suite, si utilisation de la queue système :  schedule_{delayed_}work(): ajoute une tâche  flush_scheduled_work(): attend la fin de toutes les tâches
  • 306.
    FORMATION LINUX QUEUE DE TRAVAIL 306 Si queue autogéréé :  queue_{delayed_}work(): ajoute une tâche  cancel_delayed_work(): annule une tâche  flush_workqueue(): attend la fin de toutes les tâches d'une queue  destroy_workqueue(): détruit la queue  Prototype (<linux/workqueue.h>) :  struct workqueue_struct *create_workqueue(const char *name);  DECLARE_WORK(name, void (*func)(void *), void *data);  {PREPARE,INIT}_WORK(struct work_struct *work, void (*func)(void *), void *data);  int schedule_work(struct work_struct *work);  int schedule_delayed_work(struct work_struct *work, unsigned long delay);  void flush_scheduled_work(void);  int queue_work(struct workqueue_struct *wq, struct work_struct *work);  int queue_delayed_work(struct workqueue_struct *wq, struct work_struct *work, unsigned long delay);  int cancel_delayed_work(struct work_struct *work);  void flush_workqueue(struct workqueue_struct *wq);  void destroy_workqueue(struct workqueue_struct *wq);
  • 307.
    FORMATION LINUX QUEUE DE TRAVAIL: exemples simples 307  Exemple :  Exemple avec queue privée : void handler(void *data) { ... } DECLARE_WORK(ma_tache, handler, NULL); ... schedule_work(ma_tache); ... flush_scheduled_work(); void handler(void *data) { ... } DECLARE_WORK(ma_tache, handler, NULL); ... ma_queue = create_workqueue("ma_queue"); ... queue_work(ma_queue, ma_tache); ... flush_workqueue(ma_queue); destroy_workqueue(ma_queue);
  • 308.
    FORMATION LINUX QUEUE DE TRAVAIL: exemple d’usage 308 #include <linux/interrupt.h> #include <linux/version.h> #include <linux/module.h> #include <linux/ioport.h> #include <linux/cdev.h> #include <linux/fs.h> #include <linux/workqueue.h> #include <asm/io.h> static char * nom_module = "exemple_11"; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) static irqreturn_t irq_handler(int irq, void * ident, struct pt_regs * unused); #else static irqreturn_t irq_handler(int irq, void * ident); #endif #ifndef IRQF_SHARED #define IRQF_SHARED SA_SHIRQ #endif static void fonction_workqueue (struct work_struct * unused); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) static DECLARE_WORK(workqueue_exemple, (void (*) (void *)) fonction_workqueue, NULL); #else static DECLARE_WORK(workqueue_exemple, fonction_workqueue); #endif static int __init chargement (void) { int erreur; if (request_region(0x378, 3, nom_module) == NULL) return -EBUSY; erreur = request_irq(7, irq_handler, IRQF_SHARED, nom_module, nom_module); if (erreur != 0) { release_region(0x378, 3); return erreur; } outb(0x10, 0x37A); return 0; }
  • 309.
    FORMATION LINUX Workqueue : exempled’usage 309 static void __exit dechargement (void) { outb(0, 0x37A); free_irq(7, nom_module); flush_scheduled_work(); release_region(0x378, 3); } #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) static irqreturn_t irq_handler(int irq, void * ident, struct pt_regs * unused) #else static irqreturn_t irq_handler(int irq, void * ident) #endif { if ((inb(0x379) & 0x40) == 0) return IRQ_NONE; schedule_work(& workqueue_exemple); return IRQ_HANDLED; } static void fonction_workqueue(struct work_struct * unused) { static int valeur = 0; outb(valeur, 0x378); valeur = 0xFF - valeur; } module_init(chargement); module_exit(dechargement); MODULE_LICENSE("GPL");
  • 310.
    FORMATION LINUX LISTES CHAINEES BUT :apprendre à utiliser les listes chaînées.  Description des listes chaînées  Exemple d’usage d’une liste chaînée
  • 311.
    FORMATION LINUX Liste chaînée  http://www.linuxgrill.com/anonymous/fire/netfilter/kernel-hacking-HOWTO-5.html311  Listes doublement chaînées et circulaires  Très utilisées dans le noyau  Mécanisme d'encapsulation pour créer ses propres listes  Simplifie les manipulations (parcours, ajout / retrait d'un élément...)  Ajout d'un champ de type struct list_head dans la structure des éléments à chaîner  Initialisation d'une tête de liste (type struct list_head) :  Statique : LIST_HEAD() et LIST_HEAD_INIT()  Runtime : INIT_LIST_HEAD()  Fonctions de manipulation de la liste et des éléments :  list_add{_tail}() : ajoute un élément en tête/queue d'une liste  list_del() : supprime un élément d'une liste  list_entry() : donne accès à un élément d'une liste  list_for_each() : parcours une liste élément par élément  list_splice() : joint deux listes en une seule
  • 312.
    FORMATION LINUX Liste chaînée 312  Prototypes(<linux/list.h>) :  LIST_HEAD{_INIT}(name);  void INIT_LIST_HEAD(struct list_head *head);  void list_add{_tail}(struct list_head *new, struct list_head *head);  void list_del(struct list_head *entry);  type *list_entry(struct list_head *entry, type, member);  void list_for_each(struct list_head *current, struct list_head *head);  void list_splice(struct list_head *list, struct list_head *head); Note : les listes chainées du noyau peuvent aussi servir dans l’espace utilisateur :  http://isis.poly.edu/kulesh/stuff/src/klist/
  • 313.
    FORMATION LINUX Liste chaînée: exempled’usage 313  Définissons une première structure : struct mystruct { int data ; } ;  Création d’une seconde structure struct list_head field : struct mystruct { int data ; struct list_head mylist ; } ;  Création d’un premier élément : Usage de la macro : #define LIST_HEAD_INIT(name) { &(name), &(name) }  et un second élément : struct mystruct first ; first.data = 10 ; first.mylist = LIST_HEAD_INIT(first.mylist) ; struct mystruct second ; second.data = 20 ; INIT_LIST_HEAD( & second.mylist ) ; Macro utilisé : static inline void INIT_LIST_HEAD(struct list_head *list) { list->next = list; list->prev = list; }
  • 314.
    FORMATION LINUX Liste chaînée: exempled’usage  http://www.linuxgrill.com/anonymous/fire/netfilter/kernel-hacking-HOWTO-5.html 314  Variable définissant la tête de la liste :  Ajout de deux éléments :  Itération des éléments : LIST_HEAD(mylinkedlist) ; list_add ( &first.mylist , &mylinkedlist ) ; list_add ( &second.mylist , &mylinkedlist ) ; list_for_each ( position , & mylinkedlist ) { datastructureprt = list_entry ( position, struct mystruct , mylist ); printk ("data = %dn" , datastructureptr->data ); } struct mystruct *datastructureptr = NULL ; list_for_each_entry ( datastructureptr , & mylinkedlist, mylist ) { printk ("data = %dn" , datastructureptr->data ); }
  • 315.
    FORMATION LINUX MISE AU POINT BUT: maitriser les techniques de debug  Printk  Ksymoops  Kprobes  KGDB  Oprofile  LTT / LTTng
  • 316.
    FORMATION LINUX Déboguer avec printk Technique universelle de débogage facile à utiliser.  Prototype : int printk (const char *fmt, ...);  Affiché ou non dans la console ou /var/log/messages suivant la priorité : $ dmesg (Tampon circulaire) $ tail –f /var/log/messages (via le daemon syslogd, entrées kern.*)  Priorités disponibles (include/linux/kernel.h): #define KERN_EMERG "<0>" /* système inutilisable */ #define KERN_ALERT "<1>" /* une action doit être prise de suite */ #define KERN_CRIT "<2>" /* conditions critiques */ #define KERN_ERR "<3>" /* conditions d'erreur */ #define KERN_WARNING "<4>" /* conditions de warning */ #define KERN_NOTICE "<5>" /* condition normale mais significative */ #define KERN_INFO "<6>" /* information */ #define KERN_DEBUG "<7>" /* messages de débogage */  La priorité la plus élevée étant 0. Quand aucun niveau est spécifié, le niveau par défaut DEFAULT_MESSAGE_LOGLEVEL est utilisé (spécifié dans kernel/printk.c). http://ltp.sourceforge.net/documentation/technical_papers/UsingCodeCoverage.pdf 316
  • 317.
    FORMATION LINUX Déboguer avec printk 317 Si le noyau est compiler avec l’option CONFIG_PRINTK_TIME=y, un temps au format seconds.nanoseconds : [337567.060046] Buffer I/O error on device sr0, logical block 0  Les messages printk pouvant être important, il est possible de définir un seuil. Pour ce faire, les deux valeurs suivantes (valeurs en secondes) :  /proc/sys/kernel/printk_ratelimit  /proc/sys/kernel/printk_ratelimit_burst  Niveau de bug peut être modifié, en dynamique dans le noyau  Cela défini une suite de 4 nombres avec la signification suivante :  Niveau de log courant  Niveau de log par défault (DEFAULT_MESSAGE_LOGLEVEL)  Niveau de log minimum (MINIMUM_CONSOLE_LOGLEVEL)  Niveau de bug pour la phase de boot  echo 8 > /proc/sys/kernel/printk  Les messages peut être lu de la façon suivante : $ cat /proc/kmsg <4> ACPI-0352: *** Error: Looking up [Z005] in namespace, AE_NOT_FOUND <4>search_node c14d0440 start_node c14d0440 return_node 00000000 <4> ACPI-1138: *** Error: Method execution failed [_SB_.BAT1._BST] (Node c14d0340), AE_NOT_FOUND  cat /proc/sys/kernel/printk 7 4 1 7
  • 318.
    FORMATION LINUX ksymoops  Pour aiderà décrypter les messages «oops», en convertissant les adresses et le code en informations utiles. Il utilise pour cela la table des symboles system.map.  Facile à utiliser: copiez/collez juste le texte oops dans un fichier.  Exemple d'une ligne de commande : ksymoops --no-ksyms -m System.map -v vmlinux oops.txt  Regardez Documentation/oops-tracing.txt et man ksymoops pour plus de détails.  La table des symboles peut être consultée dans le pseudo-système de fichiers :  /proc/ksyms (Linux 2.4)  /proc/kallsyms (Linux 2.6)  http://tldp.org/HOWTO/Module-HOWTO/index.html 318 $ grep loops_per_jiffy /proc/kallsyms ffffffff815968e0 r __ksymtab_loops_per_jiffy ffffffff815aa295 r __kstrtab_loops_per_jiffy ffffffff815f0420 D loops_per_jiffy $ grep cdev_map /proc/kallsyms (even the static symbols) ffffffff818c25e8 b cdev_map
  • 319.
    FORMATION LINUX Déboguer avec Kprobesd'IBM  Moyen simple d'insérer des points d'arrêt dans les routines du noyau  Contrairement au débogage avec printk, vous n'avez pas besoin de recompiler ni de redémarrer votre noyau. Vous avez juste besoin de compiler et charger un module dédié pour déclarer l'adresse de la routine que vous voulez tester.  Non disruptif, basé sur le gestionnaire d'interruption du noyau  Kprobes permet même de modifier des registres et des structures de données globales. 319  Voir http://www-106.ibm.com/developerworks/library/l-kprobes.html pour une présentation plus complète
  • 320.
    FORMATION LINUX Astuce de débogagedu noyau  Si votre noyau ne démarre pas encore, il est recommandé d'activer le «Low Level debugging» (dans la section «Kernel Hacking» des options du noyau, valable uniquement sur ARM) CONFIG_DEBUG_LL=y  Les codes d'erreur de Linux Essayez de reporter les erreurs avec des numéros aussi précis que possible ! Heureusement, les noms de macros sont explicites et vous pouvez vous en rappeler rapidement.  Codes d'erreur génériques: include/asm-generic/errno-base.h  Codes d'erreur spécifiques à une plate-forme: include/asm/errno.h 320
  • 321.
    FORMATION LINUX Oprofile 321 1. Compiler etinstaller. Utiliser l’option --with-linux pour pointer indiquer le chemin vers les sources du noyau linux.to point (autre option possible --with-kernel-support for 2.6 kernels. 2. Compiler le noyau linux avec les options : CONFIG_PROFILING=y et CONFIG_OPROFILE=y 3. Démarrer le profiler : opcontrol –init opcontrol --setup --ctr0-event=CPU_CLK_UNHALTED --ctr0-count=600000 --vmlinux=/usr/src/linux-2.4.20/vmlinux For RTC mode users, use --rtc-value=2048 # opcontrol --start watch --interval=1 "opcontrol --dump && opreport -l 2>/dev/null | head -30 ; opcontrol --reset" opcontrol --stop/--shutdown/--dump opcontrol –stop 3. Génération d’un rapport : opreport – merge-all -l http://oprofile.sourceforge.net/news/ http://oprofile.sourceforge.net/examples/ http://oprofile.sourceforge.net/doc/index.html http://oprofile.sourceforge.net/doc/internals/index.html http://oprofile.sourceforge.net/examples/ http://oprofile.sourceforge.net/faq/ http://oprofile.sourceforge.net/doc/devel/index.html http://citeseer.ist.psu.edu/700537.html http://www-106.ibm.com/developerworks/linux/library/l-oprof.html (or http://www.ibm.com/developerworks/linux/library/l-oprof.html) http://www.eclipse.org/linuxtools/projectPages/oprofile/ http://www.ece.utexas.edu/~ljohn/wwc/wwc6/ http://people.redhat.com/wcohen/wwc2003/ http://people.redhat.com/wcohen/Oprofile.pdf http://sourceforge.net/projects/oprofile/ http://www.lilax.org/meetings.html http://www.tru64unix.compaq.com/dcpi/ http://www.tru64unix.compaq.com/dcpi/src-tn-1997-016a.html http://prospect.sf.net/  Le noyau 2.6 dispose de oprofile, un analyseur noyau et applicatif plus puissant
  • 322.
    FORMATION LINUX Profiling noyau 322  Possibilitéd'analyser le temps passé dans chaque fonction du noyau :  paramètre de boot: profile=n  informations binaires dans /proc/profile  lecture grâce à l'utilitaire readprofile Le noyau mémorise tous les 2n tick d’horloge, dans quelle fonction il se trouve. Vu que c’est par un mode capture par échantillons, cela inclus une erreur.  Permet de déceler :  des dysfonctionnements structurels  des parties d'un driver à optimiser
  • 323.
    FORMATION LINUX KGDB 323  Le patchkgdb est le nom d'un débogueur du noyau Linux au niveau code source. Un tel débogueur est un outil d'aide au développement de drivers ou de fonctionnalités du noyau, permettant de comprendre précisément ce qui se déroule réellement dans le cœur du système d'exploitation, de le mettre en pas à pas, et d'agir dessus.  Site officiel : http://kgdb.linsyssoft.com  Pour chaque architecture, il y a deux patch à appliquer : o Le patch core indépendant de l’architecture : core-lite.patch o Le patch spécifique à l’architecture choisie : i386.patch  Nécessite d'avoir deux machines :  la cible (target) qui sera déboguée  la machine de développement ayant les sources et le binaire du noyau  reliées entre-elles par câble série (ou réseau)  C'est un logiciel libre développé sous licence GNU GPL par Dave Grothe. Le projet est hébergé par SourceForge.net et son développement est soutenu par la société LinSysSoft, qui en fournit par ailleurs un support professionnel sous le nom de produit KGDB Pro.  Avant les dernières version de linux, il fallait patcher le noyau pour inclure le stub (similaire à gdb server). Dans les versions récente du noyau, Linus Torvald à accepté de l’inclure dans les sources même du noyau.  Après l’usage est similaire à gdb / gdb server (facile à mettre en place) http://kgdb.linsyssoft.com/downloads/kgdb-2/kgdbquickstart-2.4.pdf
  • 324.
    FORMATION LINUX KGDB 324  Deux modesde connexion possible entre la machine de développement & la cible :  un câble série (null-modem)  câble ethernet  La machine de développement :  possède une copie des sources et binaires  (sert souvent à générer les binaires par un processus de compilation croisée)  exécute le déboggueur (cross-déboggueur)  pilote la cible  KGDB permet de :  interrompre l'exécution du noyau  mettre des points d'arrêt (exécution, lecture/écriture)  exécuter le code en mode pas à pas  connaître la pile d'appel (tâche courante, toutes les tâches)  examiner/modifier la mémoire (adresses, variables, listes chaînées etc)  ... toute fonctionnalité de gdb standard ...  L'utilisation d'interfaces graphiques par dessus gdb reste possible (exemple: ddd)
  • 325.
    FORMATION LINUX KGDB 325  KGDB estcomposé de :  un déboggueur gdbtournant sur la machine de dev (presque) standard (diffère de part le système de chargement en module)  un stub gdb intégré au noyau sous forme de patch noyau  Une version modifiée de gdb est nécessaire pour certaines fonctionnalités (exemple: déboggage de modules noyau)  Le stub gdb est disponible pour beaucoup d'architectures sous forme de patch (plusieurs variantes existent...)  Télécharger le stub kgdb (par exemple à http://kgdb.linsyssoft.com/cvs.htm) :  Appliquer le patch kgdb au noyau (attention, le stub kgdb est fait pour une version précise du noyau, des modification manuelles peuvent être nécessaires si la version du noyau est différente) : cvs d:pserver:anonymous@kgdb.cvs.sourceforge.net:/cvsroot/kgdb login cvs z3 d:pserver:anonymous@kgdb.cvs.sourceforge.net:/cvsroot/kgdb co . wget www.kernel.org/pub/linux/kernel/v2.6/linux2.6.17. tar.bz2 tar xvfj linux2.6.17. tar.bz2 cd linux2.6.17 mkdir patches cp ../kgdb2/* patches/ quilt push -a nb : quilt étant un outil d’application d’une pile de patch
  • 326.
    FORMATION LINUX KGDB 326  Configurer lenoyau :  choisir le type de connexion (série ou ethernet)  pour la connexion ethernet il faut avoir activé Netpoll (mode polling pour le debug ; évite de recourir aux interruptions pour le débugger).  Compiler le noyau :  Installer le noyau et ses modules (exemple pour boot par TFTP et montage NFS-root) :  Générer un déboggueur gdb comprenant les modules noyau : cp arch/arm/boot/uImage /tftpboot make modules_install INSTALL_MOD_PATH=/target make make oldconfig wget http://ftp.gnu.org/gnu/gdb/gdb6.4. tar.bz2 tar xvfj gdb6.4. tar.bz2 cd gdb6.4 patch p1 < ../gdb/gdbkgdbmodulenotification. patch ./configure –target=armlinuxuclibc make
  • 327.
    FORMATION LINUX KGDB 327  Générer undéboggueur gdb comprenant les modules noyau:  Sur la cible :  pour liaison (over)ethernet, démarrer avec l'option : kgdboe=@TARGETIP/,@DEVIP/ dans lilo/grub  activer le debug : • dès le boot si option kgdbwait dans lilo/grub • automatiquement si oops noyau • en tapant sysrq+g sur la cible  Sur la machine de développement :  Se positionner dans les sources du noyau linux wget linux-2.6.15.5-kgdb-2.4.tar.bz2 tar -jxvf linux-2.6.15.5-kgdb-2.4.tar.bz2 patch -p1 < ${BASE_DIR}/linux-2.6.15.5-kgdb-2.4/core-lite.patch patch -p1 < ${BASE_DIR}/linux-2.6.15.5-kgdb-2.4/i386.patch  Modifier l’extra-version à -kgdb make xconfig ou make oldconfig Sélectionner l’option dans le menu : Kernel hacking  Kernel Debugging with remote gdb ; Selectionner aussi : « KGDB : Console message through gdb » et « KGDB : On généric serial port : 8250 ». make bImage  le noyau sera crée ici : arch/i386/boot/bzImage gdb ./vmlinux  pour liaison série : (gdb) set remotebaud 115200 (gdb) target remote /dev/ttyS0  pour liaison ethernet : (gdb) target remote udp:TARGETIP:6443
  • 328.
    FORMATION LINUX KGDB 328  Exemple dedébug : # gdb vmlinux (gdb) target remote udp:kgdb:6443 breakpoint () at kernel/kgdb.c:1776 1776 atomic_set(&kgdb_setting_breakpoint, 0); (gdb) b sys_open Breakpoint 1 at 0xc01543c6: file fs/open.c, line 944. (gdb) c Continuing. [New thread 2774] [Switching to thread 2774] Breakpoint 1, sys_open (filename=0x5 <Address 0x5 out of bounds>, flags=5, mode=5) at fs/open.c:944 944 tmp = getname(filename); (gdb) n (gdb) n 946 if (!IS_ERR(tmp)) { (gdb) p tmp $2 = 0xcebcf000 "/etc/ld.so.cache »
  • 329.
    FORMATION LINUX KDB 329  Débogueur noyauembarqué  Développé par SGI : http://oss.sgi.com/projects/kdb/  Débogueur noyau en mode assembleur (pas de mode source)  Pas de préparation spéciale du noyau à déboguer  Ne nécessite pas de machine supplémentaire pour le debug  Débogueur utile mais difficile à exploiter de par sa complexité http://www.ibm.com/developerworks/linux/library/l-kdbug/ http://luv.asn.au/overheads/embedded/kdb.pdf - Télécharger les deux patch (commun + spécifique à l’architecture) : ftp://oss.sgi.com/projects/kdb/download/latest/ - Extraction des archives : bzip2 -d kdb-v4.2-2.4.20-common-1.bz2 bzip2 -d kdb-v4.2-2.4.20-i386-1.bz2 - Application des patchs : patch -p1 <kdb-v4.2-2.4.20-common-1 patch -p1 <kdb-v4.2-2.4.20-i386-1 - Lancer la commande : make menuconfig / xconfig - Sélectionner l’entrée: Kernel hacking -> Built-in Kernel Debugger support CONFIG_KDB_OFF désactive le debuggeur par défaut CONFIG_FRAME_POINTER s’il y a la présnce des pointeurs de frames - Recompiler le noyau - Activation : echo "1" > /proc/sys/kernel/kdb - Désactivation : echo "0" >/proc/sys/kernel/kdb
  • 330.
    FORMATION LINUX LINICE 330  Spécificités : Linux PC/x86 platform  Minimum Pentium class CPU Linux  kernels 2.4 or 2.6  Site officiel : http://www.linice.com  Traduction de symboles : linsym –t <binary> (génère un fichier <binary>.SYM)  Chargement de symboles : linsym –s <symbols.sym>  Chargement / déchargement du débugeur :  Chargement du module : linsym –i  Déchargement du module : linsym –x http://www.linice.com http://www.linice.com/Linice.pdf
  • 331.
    FORMATION LINUX LINICE 331  Préparation desflags :  CFLAGS := -gstabs+ $(CPPFLAGS) -Wall -Wstrict-prototypes -Wno-trigraphs -O2 -fno-strict- aliasing -fno-common -Wno-unused  AFLAGS := -gstabs -D__ASSEMBLY__ $(CPPFLAGS)  Génération d’un version de débug après la compilation : $(LD_VMLINUX) $(LD_VMLINUX_KALLSYMS) -o vmlinux.debug $(STRIP) -S -o vmlinux vmlinux.debug $(NM) vmlinux | grep -v '(compiled)|(.o$$)|( [aUw])|(..ng$$)| (LASH[RL]DI)' | sort > System.map  Génération des symboles du noyau de debug vmlinux.debug : linsym –t vmlinux.debug
  • 332.
    FORMATION LINUX GDB / KCORE 332 Débogage avec GDB en lecture seule sur /proc/kcore http://www.cs.wm.edu/~kearns/001lab.d/kernel_gdb.html http://www.linux.com/learn/linux-training/33991-the-kernel-newbie-corner-kernel-and-module-debugging-with-gdb # gdb vmlinux /proc/kcore (start our debugging session) ... snip ... (gdb) p jiffies_64 (print the value of jiffies_64) $1 = 4326692196 (and there it is) (gdb) (gdb) p loops_per_jiffy $2 = 1994923 (gdb)
  • 333.
    FORMATION LINUX GDB / KCORE 333 Débogage avec GDB en lecture seule sur /proc/kcore http://www.cs.wm.edu/~kearns/001lab.d/kernel_gdb.html http://www.linux.com/learn/linux-training/33991-the-kernel-newbie-corner-kernel-and-module-debugging-with-gdb # gdb vmlinux /proc/kcore (start our debugging session) ... snip ... (gdb) p jiffies_64 (print the value of jiffies_64) $1 = 4326692196 (and there it is) (gdb) (gdb) p loops_per_jiffy $2 = 1994923 (gdb)
  • 334.
    FORMATION LINUX SYSTEMTAP 334  SystemTap estun outil permettant d'analyser le fonctionnement d'un noyau Linux en cours de fonctionnement, à la manière de DTrace. Il s'utilise en ligne de commande avec un langage de script qui lui est dédié.  Le projet est distribué sous licence GPL et développé par Red Hat, IBM, Intel, Hitachi et Oracle.  Compiler le noyau avec les options suivantes :  CONFIG_DEBUG_INFO  CONFIG_KPROBES  CONFIG_RELAY  CONFIG_DEBUG_FS  CONFIG_MODULES  CONFIG_MODULES_UNLOAD  Possède une interface graphique : http://stapgui.sourceforge.net/ http://sourceware.org/systemtap/ http://sourceware.org/systemtap/documentation.html http://sourceware.org/systemtap/tutorial/ http://sourceware.org/systemtap/SystemTap_Beginners_Guide/ http://sourceware.org/systemtap/langref/ http://sourceware.org/systemtap/archpaper.pdf http://sourceware.org/systemtap/RH2_Systemtap_OLS_2005.pdf http://sourceware.org/systemtap/systemtap-ols.pdf
  • 335.
    FORMATION LINUX Linux Trace Toolkit(LTT) / LTTng 335 http://www.opersys.com/ http://lttng.org/LTT http://lttng.org/files/lttv-doc/user_guide/ http://lttng.org/cgi-bin/gitweb.cgi?p=lttv.git;a=blob_plain;f=LTTngManual.html http://lttng.org/content/documentation?q=node/12 /  LTT est un outil permettant de tracer et d’instrumenter le noyau linux.  Il est un outil complémentaire au débug.  Nécessite de patcher le noyau. Démarrage de l’interface graphique : $ lttv-gui L’utilisation du mode texte est aussi simple : La liste des plug-ins installés est disponible par la commande suivante : $ lttv -L /usr/local/lib/lttv/plugins -m textDump --help
  • 336.
    FORMATION LINUX Linux Trace Toolkit(LTT) 336  Système de trace des événements noyau  Datation à la micro-seconde  Léger coût en performances (< 2.5 %)  Deux versions :  LTT historique : http://opersys.com/LTT • développé par Karim Yaghmour depuis 1999 • plus vraiment maintenu depuis 2002 (mais reste utilisable...) • abandonné définitivement en 2005  LTTng : http://ltt.polymtl.ca (réécriture du code source à 100%) • développé par Mathieu Desnoyers, Ecole Polytechnique de Montréal • Suis les versions du noyau • encore un peu jeune...  LTT est composé :  « pilote » noyau pour implémenter le buffer de trace (lttng)  instrumentation du code noyau pour générer les traces (lttng)  utilitaires de collecte (lttctl)  utilitaires de visualisation des traces (lttv)
  • 337.
    FORMATION LINUX Linux Trace Toolkit(LTT) 337  Voir le QUICKSTART de LTT.  Télécharger les patches noyau :  Appliquer les patches au noyau :  Configurer / compiler le noyau :  activer les options LTT, mais pas LTT_HEARTBEAT  Redémarrer la machine sur le noyau LTT wget ltt.polymtl.ca/lttng/patch2.6.20lttng0.6.77.tar.bz2 tar xvfj patch2.6.20lttng0.6.77.tar.bz2 wget www.kernel.org/pub/linux/kernel/v2.6/linux2.6.20. tar.bz2 cd linux2.6.20 cat ../patch2.6.20lttng0.6.77* diff | patch p1 make oldconfig make make modules_install install
  • 338.
    FORMATION LINUX Linux Trace Toolkit(LTT) 338  Compiler l'application de collecte :  Compiler l'application de visualisation :  Monter relayfs :  Charger les modules LTT : wget http://ltt.polymtl.ca/lttng/lttcontrol0.3512032007. tar.gz cd lttcontrol0.3512032007 ./configure make make install wget http://ltt.polymtl.ca/packages/LinuxTraceToolkitViewer0.8.7902032007. tar.gz cd LinuxTraceToolkitViewer0.8.7902032007 ./configure make make install mkdir /mnt/debugfs echo "debugfs /mnt/debugfs debugfsfs rw 0 0" > /etc/fstab mount /mnt/debugfs modprobe lttcontrol modprobe lttstatedump
  • 339.
    FORMATION LINUX Linux Trace Toolkit(LTT) 339  Mode graphique: lttv-gui  cliquer sur le feu rouge  démarrer la trace en cliquant sur start  arrêter la trace en cliquant sur stop  visualiser la trace  Mode texte: lttctl + lttv  démarrer la trace : lttctl –n trace –d –l /mnt/debugfs/ltt –t /tmp/trace  arrêter la trace : lttctl –n trace –R  visualiser la trace : lttv –m textDump –t /tmp/trace
  • 340.
    FORMATION LINUX ENTREES ET SORTIES BUT: apprendre à maitriser les entrées & sorties.  Mode polling et interruptible  Les gestionnaires d’IRQ
  • 341.
    FORMATION LINUX Les interruptions, pourquoi faire ?  Les interruptions internes au processeur sont par exemple utilisées pour l'ordonnancement, nécessaire au multi-tâche.  Les interruptions externes sont utiles car la plupart des périphériques internes ou externes sont plus lents que le processeur. Dans ce cas, mieux vaut ne pas laisser le processeur en attente active sur des données. Lorsque le périphérique est à nouveau près, il envoie une interruption pour demander l'attention du processeur.  Liées à un périphérique (ex: carte, port, timer... )  Une interruption matérielle peut préempter un processus même s'il est en mode noyau.  Traitement en deux phases:  top-half : partie rapide et non interruptible (exemple: acquittement de l'interruption auprès du périphérique) ; toutes les interruptions sont coupés lors du traitement du handle.  bottom-half : partie lente placée dans une file de tâches qui sera vidée par l'ordonnanceur ; plus prioritaire que les processus temps réel.  (exemple: traitement des données respectives).  Possibilité de partage d'IRQ. 341
  • 342.
    FORMATION LINUX INTERRUPTIONS ET EVENEMENTS Les évènements d'E/S sont souvent asynchrones et non prédictibles (ex: clavier, arrivée de paquets réseau etc.)  Il existe deux méthodes pour superviser les E/S :  l'attente active/scrutation (polling)  le traitement par interruptions  Dans le mode polling, on relâche le CPU avec la fonction schedule() après chaque test infructueux :  Dans le mode interruptible, le processus appelant est endormi et placé dans une file d'attente.  C'est le gestionnaire de l'interruption attendue qui sera chargé de le réveiller (ainsi que tous les autres processus en attente dans la file) 342 for ( ; ; ) { if (evenement) break; schedule() ; }
  • 343.
    FORMATION LINUX INTERRUPTIONS ET EVENEMENTS Les gestionnaires d'interruptions (interrupt handler) :  doivent être rapides ;  ne doivent pas appeler des routines qui peuvent endormir le processus (ex: kmalloc() non atomique)  Pour ces raisons, la gestion des interruptions est découpée en deux parties :  une partie rapide et non interruptible (gestionnaire d'interruptions)  une partie lente placée dans une file de tâches (bottom-half)  Les bottom-halves ne sont pas obligatoires.  Un gestionnaire d'interruptions est déclaré grâce à la fonction request_irq()  Il est libéré grâce à la fonction free_irq()  Prototypes (<linux/sched.h>, <linux/interrupt.h>) :  int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long flags /* SA_SHIRQ */, const char *device, void *dev_id);  void free_irq(unsigned int irq, void *dev_id); 343
  • 344.
    FORMATION LINUX INTERRUPTIONS ET EVENEMENTS Quand l'interruption irq survient, la fonction handler() est appelée  Le champ dev_id sert à identifier les périphériques en cas de partage d'IRQ (SA_SHIRQ)  Il peut être employé pour transmettre au gestionnaire d'interruptions une structure spécifique au périphérique  La liste des IRQ déjà déclarées est disponible dans /proc/interrupts  Le code de retour du handler doit être IRQ_NONE ou IRQ_HANDLED.  API modifiée en 2.6.19 :  – le paramètre pt_regs disparaît  – récupération possible des registres par get_irq_regs()  – les flags SA_ sont renommés en IRQF_ (exemple: SA_SHIRQ devient IRQF_SHARED) 344
  • 345.
    FORMATION LINUX INTERRUPTIONS ET EVENEMENTS Les bottom-halves sont des fonctions du noyau utilisées pour la gestion de tâches asynchrones  Ordonnancés à chaque retour d'appel système, d'exception ou de gestionnaire d'interruption  Ils peuvent être préemptés par des interruptions   Deux « implémentations » possibles :  – tasklets: peuvent s'exécuter sur différents CPU (mais une seule instance à la fois)  – softirqs: peuvent s'exécuter sur différents CPU (plusieurs instances simultanément)  Exemple : 345 void ma_routine_bh(unsigned long) { /* … code bottomhalf ... */ } DECLARE_TASKLET(ma_tasklet, ma_routine_bh, 0); void mon_handler_irq(int irq, void *dev_id, struct pt_regs *regs) { ... tasklet_schedule(& ma_tasklet); ... }
  • 346.
    FORMATION LINUX Enregistrer un gestionnaire d'interruption Défini dans include/linux/interrupt.h  Bits pouvant être définis dans irq_flags (combinables)  SA_INTERRUPT Gestionnaire d'interruption "rapide". Fonctionne avec les interruptions désactivées. Utilité limitée à des cas spécifiques (tels que les interruptions timer).  SA_SHIRQ Le canal d'interruption peut être partagé par plusieurs périphériques.  SA_SAMPLE_RANDOM Les interruptions peuvent être utilisées pour contribuer à l'entropie du système (/dev/random et /dev/urandom), afin de générer de bons nombres aléatoires. Ne l'utilisez pas si votre périphérique a un comportement prédictif ! int request_irq( unsigned int irq, /* canal irq demandé */ irqreturn_t (*handler) (int, void *, struct pt_regs *), /* gestionnaire d'inter. */ unsigned long irq_flags, /* masque d'options */ const char* devname, /* nom enregistré */ void* dev_id) /* utilisé lorsque l'irq est partagée */ void free_irq( unsigned int irq, void *dev_id); 346
  • 347.
    FORMATION LINUX Quand enregistrer legestionnaire  Soit à l'initialisation du pilote : consomme beaucoup de canaux IRQ !  Ou bien à l'ouverture du fichier de périphériques: permet de sauver des canaux IRQ libres. Besoin de compter le nombre de fois où le périphérique est ouvert, pour être capable de libérer les canaux IRQ lorsque le périphérique n'est plus utilisé.  Information sur les gestionnaires installés :  Nombre total d'interruptions : $ cat /proc/interrupts CPU0 0: 5616905 XT-PIC timer # Nom enregistré 1: 9828 XT-PIC i8042 2: 0 XT-PIC cascade 3: 1014243 XT-PIC orinoco_cs 7: 184 XT-PIC Intel 82801DB-ICH4 8: 1 XT-PIC rtc 9: 2 XT-PIC acpi 11: 566583 XT-PIC ehci_hcd, uhci_hcd,... 12: 5466 XT-PIC i8042 14: 121043 XT-PIC ide0 15: 200888 XT-PIC ide1 NMI: 0 # Interruptions non masquables ERR: 0 cat /proc/stat | grep intr intr 8190767 6092967 10377 0 1102775 5 2 0 196 ... Nombre total d'interruptions Total IRQ1 IRQ2 IRQ3 ... 347
  • 348.
    FORMATION LINUX Détection du canal d'interruption Certains périphériques annoncent leur canal IRQ dans un registre.  Certains périphériques ont toujours le même comportement: vous pouvez déduire leur canal IRQ.  Détection manuelle :  Enregistrez votre gestionnaire d'inter. pour tous les canaux possibles  Demander une interruption  Dans le gestionnaire appelé, enregistrer le numéro d'IRQ dans une variable globale  Réessayez si aucune interruption n'a été reçue  Désenregistrez les gestionnaires non utilisés  Outils de détection du noyau :  mask = probe_irq_on();  Activez les interruptions sur le périphérique  Désactivez les interruptions sur le périphérique  irq = probe_irq_off(mask); • > 0: numéro d'IRQ unique trouvé • = 0: pas d'interruption. Essayez à nouveau ! • < 0: plusieurs interruptions reçues. Essayez à nouveau ! 348
  • 349.
    FORMATION LINUX Le travail dugestionnaire d'interruption  Acquitter l'interruption au périphérique (sinon plus aucune autre interruption ne sera générée)  Lire/écrire des donnée du/sur le périphérique  Réveiller tout processus attendant la fin de l'opération de lecture/écriture: wake_up_interruptible(&module_queue);  Contraintes du gestionnaire d'interruptions :  Ne s'exécute pas dans le contexte utilisateur: Ne peut pas transférer des donnés de ou vers l'espace utilisateur  Ne peut pas exécuter d'actions pouvant s'endormir: Besoin d'allouer de la mémoire avec GFP_ATOMIC  Ne peut pas appeler schedule()  Doit terminer son travail suffisamment rapidement: il ne peut pas bloquer les interruptions trop longtemps. 349
  • 350.
    FORMATION LINUX Prototype d'un gestionnaire d'interruption Valeur retournée :  IRQ_HANDLED : interruption reconnue et gérée  IRQ_NONE : pas sur un périphérique géré par le module. Permet de partager des canaux d'interruption et/ou de reporter de fausses interruptions au noyau. irqreturn_t (*handler) ( int, /* Numéro d'irq */ void *dev_id, /* Pointeur utilisé pour garder la trace du device correspondant. Utile quand plusieurs périphériques sont gérés par le même module */ struct pt_regs *regs /* snapshot des registres du cpu, rarement nécessaire */ ); 350
  • 351.
    FORMATION LINUX Traitement parties hauteet basse  Partie haute : le gestionnaire doit se terminer le plus vite que possible. Une fois qu'il a acquitté l'interruption, il planifie le reste du travail gérant les données et prenant du temps, pour une exécution future.  Partie basse : termine le reste du travail du gestionnaire. Traite les données, et ensuite réveille tout les processus utilisateur en attente. Implémenté au mieux par les tasklets.  Déclarer la tasklet dans le fichier source du module:  Planifier la tasklet dans la partie haute du gestionnaire: DECLARE_TASKLET (module_tasklet, /* nom */ module_do_tasklet, /* fonction */ 0 /* données */ ); tasklet_schedule(&module_do_tasklet); 351
  • 352.
    FORMATION LINUX Résumé de lagestion des interruptions  Trouver un numéro d'interruption (si possible)  Activer les interruptions sur le périphérique  Détecter le numéro d'interruption utilisé par le périphérique, en scrutant les différents possibilités, si nécessaire.  Enregistrer le gestionnaire d'interruption avec le numéro d'IRQ identifié.  Une fois que le gestionnaire d'interruption est appelé, acquitter l'interruption.  Dans le gestionnaire, planifier la tasklet gérant les données  Dans la tasklet, gérer les données  Dans la tasklet, réveiller les processus utilisateur en attente  Désenregistrer le gestionnaire si le périphérique est fermé. 352
  • 353.
    FORMATION LINUX TASKLET : exempled’usage 353 #include <linux/interrupt.h> #include <linux/version.h> #include <linux/ioport.h> #include <linux/module.h> #include <linux/cdev.h> #include <linux/fs.h> #include <asm/io.h> static char * nom_module = "exemple_10"; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) static irqreturn_t irq_handler(int irq, void * ident, struct pt_regs * unused); #else static irqreturn_t irq_handler(int irq, void * ident); #endif #ifndef IRQF_SHARED #define IRQF_SHARED SA_SHIRQ #endif static void fonction_tasklet (unsigned long inutile); static DECLARE_TASKLET(tasklet_exemple, fonction_tasklet, 0); static int __init chargement (void) { int erreur; if (request_region(0x378, 3, nom_module) == NULL) return -EBUSY; erreur = request_irq(7, irq_handler, IRQF_SHARED, nom_module, nom_module); if (erreur != 0) { release_region(0x378, 3); return erreur; } outb(0x10, 0x37A); return 0; }
  • 354.
    FORMATION LINUX TASKLET : exempled’usage 354 static void __exit dechargement (void) { outb(0, 0x37A); free_irq(7, nom_module); tasklet_kill(& tasklet_exemple); release_region(0x378, 3); } #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) static irqreturn_t irq_handler(int irq, void * ident, struct pt_regs * unused) #else static irqreturn_t irq_handler(int irq, void * ident) #endif { if ((inb(0x379) & 0x40) == 0) return IRQ_NONE; tasklet_schedule(& tasklet_exemple); return IRQ_HANDLED; } static void fonction_tasklet(unsigned long inutile) { static int valeur = 0; outb(valeur, 0x378); valeur = 0xFF - valeur; } module_init(chargement); module_exit(dechargement); MODULE_LICENSE("GPL");
  • 355.
    FORMATION LINUX GESTION DES ENTREESET SORTIES BUT : apprendre à maitriser la DMA.  Accès au matériel sous x86  Accès mémoire  Exemple d'activation du DMA  API générique DMA
  • 356.
    FORMATION LINUX Accès au matériel– ports d’E/S  Architecture Intel  Plages d'adresses utilisées par les périphériques présents sur le bus d'E/S (registres de contrôle)  On accède à ces ports depuis le noyau grâce aux fonctions :  in{b,w,l}()/out{b,w,l}() : lit/écrit 1, 2 ou 4 octets consécutifs sur un port d'E/S  in{b,w,l}_p()/out{b,w,l}_p() : lit/écrit 1, 2 ou 4 octets consécutifs sur un port d'E/S et fait une pause (une instruction)  ins{b,w,l}()/outs{b,w,l}() : lit/écrit des séquences de 1, 2 ou 4 octets consécutifs sur un  port d'E/S  Les pilotes peuvent accéder à des ports d'E/S qui ne leur appartiennent pas (exemple: probing)  Pour éviter les conflits, le pilote peut réserver des ports auprès du noyau:  request_region() : réserve une plage de ports d'E/S (si disponible)  release_region() : libère la plage de ports d'E/S.  La liste des ports déjà réservés peut être consultée dans /proc/ioports. 356
  • 357.
    FORMATION LINUX Accès au matériel– ports d’E/S  Prototypes x86 (<asm/io.h>) :  unsigned char inb(unsigned short port);  void outb(unsigned char byte, unsigned short port);  unsigned char insb(unsigned short port, void *addr, unsigned long count);  void outsb(unsigned short port, void *addr, unsigned long count); 357
  • 358.
    FORMATION LINUX Accès au matériel– mémoire d’E/S  Les périphériques d'E/S peuvent aussi posséder de la mémoire partagée (ex: frame-buffer des cartes graphiques, buffers des cartes réseau)  Cette mémoire est accessible comme de la mémoire centrale (contrairement aux ports d'E/S)  Cependant, le noyau manipule des adresses linéaires virtuelles (et non physiques)  La mémoire centrale est elle-même mappée à l'adresse PAGE_OFFSET)  Il faut donc mapper les plages d'adresses d'entrée/sortie dans l'espace linéaire du noyau (donner une adresse virtuelle aux adresse physiques) :  ioremap() : mappe une plage d'adresses physiques sur une plage d'adresses virtuelles (semblable à vmalloc())  iounmap() : libère une plage préalablement mappée 358
  • 359.
    FORMATION LINUX Accès au matériel– mémoire d’E/S  Pour éviter les conflits, le pilote peut réserver des plages mémoire d'E/S auprès du noyau :  request_mem_region() : réserve une plage d'adresses physiques d'E/S  release_mem_region() : libère une plage d'E/S  La liste des plages mémoire d'E/S qui sont déjà réservées apparaît dans /proc/iomem  Prototypes (<asm/io.h> et <linux/ioport.h>) :  void *ioremap(unsigned long offset, unsigned long size);  void iounmap (void *addr);  struct resource *request_{mem_}region(unsigned long start, unsigned long n, const char *name);  void release_{mem_}region(unsigned long start, unsigned long n); 359
  • 360.
    FORMATION LINUX Accès au matériel– mémoire d’E/S  On accède ensuite à la mémoire partagée des E/S grâce aux fonctions suivantes :  read{b,w,l}()/write{b,w,l}() : lit/écrit respectivement 1, 2 ou 4 octets consécutifs dans de la mémoire d'E/S  memcpy_{from,to}io() : lit/écrit un bloc d'octets consécutifs dans de la mémoire d'E/S  memset_io() : remplit une zone de mémoire d'E/S avec une valeur fixe  virt_to_bus()/bus_to_virt() : traduction entre adresses virtuelles linéaires et adresses réelles sur le bus.  Prototypes x86 (<asm/io.h>):  char readb(void *addr);  void writeb(char byte, void *addr);  void * memcpy_{from,to}io(void *dest, const void *src, size_t count);  void * memset_io(void *addr, int pattern, size_t count);  unsigned long virt_to_bus(volatile void *addr);  void * bus_to_virt(unsigned long addr); 360
  • 361.
    FORMATION LINUX Demander des portsd'E/S  struct resource *request_region( unsigned long start, unsigned long len, char *name); Essaie de réserver la région donnée et retourne NULL en cas d'échec. Exemple: request_region(0x0170, 8, "ide1");  void release_region( unsigned long start, unsigned long len);  Regarder include/linux/ioport.h et kernel/resource.c $ cat /proc/ioports 0000-001f : dma1 0020-0021 : pic1 0040-0043 : timer0 0050-0053 : timer1 0060-006f : keyboard 0070-0077 : rtc 0080-008f : dma page reg 00a0-00a1 : pic2 00c0-00df : dma2 00f0-00ff : fpu 0100-013f : pcmcia_socket0 0170-0177 : ide1 01f0-01f7 : ide0 0376-0376 : ide1 0378-037a : parport0 03c0-03df : vga+ 03f6-03f6 : ide0 03f8-03ff : serial 0800-087f : 0000:00:1f.0 0800-0803 : PM1a_EVT_BLK 0804-0805 : PM1a_CNT_BLK 0808-080b : PM_TMR 0820-0820 : PM2_CNT_BLK 0828-082f : GPE0_BLK ... 361
  • 362.
    FORMATION LINUX Lire / écriresur les ports d'E/S  L'implémentation des fonctions suivantes et le type unsigned peuvent varier suivant la plate-forme !  octets unsigned inb(unsigned port); void outb(unsigned char byte, unsigned port);  mots unsigned inw(unsigned port); void outw(unsigned short word, unsigned port);  "long" integers unsigned inl(unsigned port); void outl(unsigned long word, unsigned port); 362
  • 363.
    FORMATION LINUX Lire / écrireune chaîne sur les ports d'E/S  Plus efficace que la boucle C correspondante, si le processeur supporte de telles opérations :  byte strings void insb(unsigned port, void *addr, unsigned long count); void outsb(unsigned port, void *addr, unsigned long count);  word strings void insw(unsigned port, void *addr, unsigned long count); void outsw(unsigned port, void *addr, unsigned long count);  long strings void inbsl(unsigned port, void *addr, unsigned long count); void outsl(unsigned port, void *addr, unsigned long count); 363
  • 364.
    FORMATION LINUX Demander de lamémoire d'E/S  Fonctions équivalentes avec la même interface  struct resource *request_mem region( unsigned long start, unsigned long len, char *name);  void release_mem_region( unsigned long start, unsigned long len); $ cat /proc/iomem 00000000-0009efff : System RAM 0009f000-0009ffff : reserved 000a0000-000bffff : Video RAM area 000c0000-000cffff : Video ROM 000f0000-000fffff : System ROM 00100000-3ffadfff : System RAM 00100000-0030afff : Kernel code 0030b000-003b4bff : Kernel data 3ffae000-3fffffff : reserved 40000000-400003ff : 0000:00:1f.1 40001000-40001fff : 0000:02:01.0 40001000-40001fff : yenta_socket 40002000-40002fff : 0000:02:01.1 40002000-40002fff : yenta_socket 40400000-407fffff : PCI CardBus #03 40800000-40bfffff : PCI CardBus #03 40c00000-40ffffff : PCI CardBus #07 41000000-413fffff : PCI CardBus #07 a0000000-a0000fff : pcmcia_socket0 a0001000-a0001fff : pcmcia_socket1 e0000000-e7ffffff : 0000:00:00.0 e8000000-efffffff : PCI Bus #01 e8000000-efffffff : 0000:01:00.0 ... 364
  • 365.
    FORMATION LINUX DIRECT MEMORY ACCESS(DMA) BUT : apprendre à maitriser la DMA.  Caractéristiques du DMA  Utilisation de la DMA  Exemple d'activation du DMA  API générique DMA
  • 366.
    FORMATION LINUX Caractéristiques du DMA A été créé au départ pour rendre la gestion de l'alimentation plus simple. Va maintenant bien au delà  Utilisé pour représenter l'architecture et l'état du système  A une représentation dans l'espace utilisateur: sysfs Désormais c'est l'interface préférée avec l'espace utilisateur (au lieu de /proc)  Facile à implémenter grâce à l'interface device: include/linux/device.h  Permet de voir le système depuis différents points de vue :  Depuis les périphériques existant dans le système: leur état d'alimentation, le bus auquel ils sont attachés, et le pilote qui en est responsable.  Depuis la structure du bus système: quel bus est connecté à quel bus (par exemple contrôleur de bus USB sur le bus PCI), les périphériques existant et ceux potentiellement acceptés (avec leur pilotes)  Depuis les pilotes disponibles: quels périphériques et quel types de bus sont supportés.  Depuis différentes "classes" de périphériques: "input", "net", "sound"... Périphériques existant pour chaque classe. Permet de trouver tous les périphériques d'entrée sans savoir où ils sont connectés physiquement. 366
  • 367.
    FORMATION LINUX Utilisation de laDMA  Synchrone  Un processus utilisateur appelle la méthode de lecture d'un pilote. Celui-ci alloue un tampon DMA et demande au matériel de copier ces données. Le processus est placé en veille.  Le matériel copie les données et provoque une interruption à la fin de la copie.  Le gestionnaire récupère les données du tampon et réveille le processus en attente.  Asynchrone  Le matériel envoie une interruption pour annoncer de nouvelles données.  Le gestionnaire alloue un tampon DMA et dit au matériel où transférer les données.  Le matériel écris les données et lève une nouvelle interruption.  Le gestionnaire récupère les nouvelles données et réveille les processus nécessaires.  Contraintes mémoire :  Besoin d'utiliser de la mémoire contiguë dans l'espace physique  Peut utiliser n'importe quelle mémoire allouée par kmalloc ou __get_free_pages  E/S bloc ou réseau: possibilité d'utiliser des tampons spécialisés, conçus pour être compatibles avec la DMA.  Ne peut pas utiliser la mémoire vmalloc (il faudrait configurer la DMA pour chaque page)  Utiliser la DMA ne supprime pas le besoin de barrières mémoire. Autrement, votre compilateur peut mélanger l'ordre des lectures et des écritures. 367
  • 368.
    FORMATION LINUX Exemple d'activation duDMA  Sur la plupart des distributions "tout-public" (mandriva, suse,...) le DMA est activé par défaut. Le DMA permet de réduire les temps d’accès au disque dur.  Vérifiez auparavant que votre disque dur n’utilise pas déjà le DMA. Pour cela tapez la commande suivante dans la console (dans ce cas, hda correspond au premier disque dur de la première nappe) :  Si vous utilisez le DMA, vous obtiendez (comme ci dessus) : using_dma = 1 (on) Ce qui signifie que le DMA est déja activé.  En outre, si vous obtenez using_dma = 0 (off), alors vous pouvez continuez cet article... :) Pour l’activez, il suffit de taper cette commande : hdparm -d1 /dev/hda Normalement, cela suffit à activez le DMA. $ hdparam /dev/hda /dev/hda: multcount = 0 (off) IO_support = 1 (32-bit) unmaskirq = 1 (on) using_dma = 1 (on) keepsettings = 0 (off) readonly = 0 (off) readahead = 256 (on) geometry = 58140/16/63, sectors = 58605120, start = 0 368
  • 369.
    FORMATION LINUX Exemple d'activation duDMA  Si vous obtenez une erreur de ce genre c’est que le mode DMA n’est pas compilé dans le noyau : setting using_dma to 1 (on) HDIO_SET_DMA failed: Operation not permitted using_dma = 0 (off)  Il va donc vous falloir procéder à une recompilation du noyau : où XXXXXX est le chipset présent sur votre carte mère. Recompilez donc le noyau avec les modifications que vous venez d’appliquer, et redémarrez. Une fois que la machine est redémarrée, tapez la commande : hdparm /dev/hda puis vérifiez que la ligne using_dma = 1 (on) est bien a 1(on) Et voilà, le DMA est désormais actif, ce qui va vous permettre d’avoir un système nettement plus rapide car moins de transfert sur les bus et entre autre moins de sollicitation du CPU. CONFIG_BLK_DEV_IDEDMA=y CONFIG_IDEDMA_PCI_AUTO=y CONFIG_BLK_DEV_XXXXXX=y 369
  • 370.
    FORMATION LINUX API générique DMA La plupart des sous-systèmes fournissent leur propre API DMA. Suffisant pour la plupart des besoins.  Documentation/DMA-API.txt Description de l'API DMA générique Linux, en parallèle avec l'API PCI DMA correspondante.  Mappages permanents («consistants») Alloués pour toute la durée de chargement du module.  Mappages de flux Configurés à chaque transfert. Cela permet de garder libres des registres matériels pour la DMA. Certaines optimisation sont aussi disponibles.  Mappages DMA permanents ou de flux : 370
  • 371.
    FORMATION LINUX PSEUDOFS /PROC et/SYS BUT : apprendre à maitriser le système de fichiers virtuels .  Quelques exemple de données dans le ramfs kernel  Le pseudo système de fichiers sysfs  Implémentation d’une nouvelle entrée
  • 372.
    FORMATION LINUX Quelques exemple dedonnées  Informations générales sur le système :  /proc/cpuinfo: informations sur le(s) processeur(s)  /proc/meminfo: état de la mémoire  /proc/version: information sur la version et la compil.  /proc/cmdline: ligne de commande du noyau  Pour chaque processus il y a une entrée par PID :  /proc/<pid>/environ: environnement d'exécution  /proc/<pid>/cmdline: ligne de cmd du processus  Profs est un système de pseudo-système de fichiers utilisé pare le kernel.  Ce dernier est accessible en lecture et/ou écriture selon les données.  Il permet Une certain interaction entre l'espace utilisateur et l'espace noyau.  En effet, une modification d'un paramètre doit être prise en compte par le noyau En dynamique. 372
  • 373.
    FORMATION LINUX Le pseudo systèmede fichiers sysfs  Représentation dans l'espace utilisateur du «Modèle de périphérique».  Configurer par : CONFIG_SYSFS=y (Filesystems -> Pseudo filesystems)  Monté de la façon suivante : mount -t sysfs /sys /sys  Outils sysfs :  http://linux-diag.sourceforge.net/Sysfsutils.html  libsysfs – Le but de cette librairie est de fournir une interface stable et pratique pour obtenir des informations sur les périphériques système exportés à travers sysfs. Utilisé par udev (voir plus loin)  systool – Un utilitaire bâti au dessus de libsysfs qui liste les périphériques par bus, classe et topologie. 373 http://www.gnugeneration.com/books/linux/2.6.20/procfs-guide/ http://buffer.antifork.org/linux/procfs-guide.pdf
  • 374.
    FORMATION LINUX 374 Ajout d’une entréedans /proc  Exemple de module créant une entrée /proc/perso. A chaque lecture dans ce fichier, un compteur est incrémenté et sa valeur affichée. Lors de l’écriture d'un nombre décimal dans le fichier, la valeur du compteur est écrasée. #include <linux/init.h> #include <linux/config.h> #include <linux/kernel.h> #include <linux/vmalloc.h> #include <linux/module.h> #include <linux/version.h> #include <asm/uaccess.h> #include <linux/proc_fs.h> static struct proc_dir_entry * entree_proc = NULL; #define LG_LIGNE 80 static int perso_read_proc (char * page, char ** debut, off_t offset, int nombre, int * eof, void * data) { int * compteur = (int *) data; if (offset > 0) return 0; (* compteur) ++; snprintf (page, nombre, "Ca fait %d fois que vous lisez /proc/person", *compteur ); return 1 + strlen (page); } static int perso_write_proc (struct file * file, const char __user * buffer, unsigned long nombre, void * data) { char ligne[LG_LIGNE]; int n; int * compteur = (int *) data; if (nombre >= LG_LIGNE) return -ENOMEM; copy_from_user(ligne, buffer, nombre); ligne[nombre] = '0'; if (sscanf (ligne, "%d", & n) == 1) { * compteur = n; printk(KERN_INFO "Valeur %d ecrite dans /proc/person", n); return nombre; } return -EINVAL; }
  • 375.
    FORMATION LINUX Ajout d’une entréedans /proc 375 static int __init chargement (void) { int * compteur; if (entree_proc != NULL) return -EBUSY; compteur = vmalloc(sizeof(int)); if (compteur == NULL) return -ENOMEM; * compteur = 0; entree_proc = create_proc_entry("perso", S_IFREG | S_IRUGO | S_IWUSR, & proc_root); if (entree_proc == NULL) return -1; entree_proc->owner = THIS_MODULE; entree_proc->read_proc = perso_read_proc; entree_proc->write_proc = perso_write_proc; entree_proc->data = compteur; printk(KERN_INFO "Chargement du module procfsn"); return 0; } static void __exit dechargement (void) { void * ptr; printk (KERN_INFO "Dechargement du module procfsn"); if (entree_proc == NULL) return; ptr = entree_proc->data; remove_proc_entry("perso", & proc_root); vfree(ptr); entree_proc = NULL; } module_init(chargement); module_exit(dechargement); MODULE_AUTHOR("TG"); MODULE_DESCRIPTION( "Entrée dans /proc" ); MODULE_LICENSE("GPL");  Fonction de chargement :  Fonction de déchargement :  Global :
  • 376.
    FORMATION LINUX CONSEILS ET RESSOURCES BUT: utiliser l’aide de la communauté.  Livres de référence  Liste de liens utiles  Sites web incontournables  Carte du noyau linux interactive  DDK Linux : Drivers Development Kit
  • 377.
  • 378.
  • 379.
  • 380.
  • 381.
    FORMATION LINUX Liens  Carte dunoyau interractive : http://www.linuxdriver.co.il/kernel_map ou http://www.makelinux.net/kernel_map  http://learnlinux.tsf.org.za/courses/build/internals/internals-all.html  http://howsoftwareisbuilt.com/2007/05/23/linux-kernel-modification-process/  http://mxi1.wordpress.com/category/linux-kernel/  http://www.iamexwi.unibe.ch/studenten/schlpbch/linuxScheduling/LinuxScheduling-1.html  http://en.wikipedia.org/wiki/Linux_kernel  http://josh.trancesoftware.com/linux/linux_cpu_scheduler.pdf  http://www.ibm.com/developerworks/linux/library/l-linux-kernel/  http://www.kernelhq.org/  http://kerneltrap.org/  http://www.kernel.org/  http://kernelnewbies.org/KernelHacking  http://kernelnewbies.org/Drivers  http://lwn.net/Kernel/  http://lwn.net/Kernel/LDD3/  http://janitor.kernelnewbies.org/  http://old.lwn.net/2001/features/Timeline/  http://www.kroah.com/lkn/  Linux DDK : http://www.kroah.com/log/2006/05/24/#ddk http://www.kernel.org/pub/linux/kernel/people/gregkh/ddk/  http://kernelnewbies.org/  http://www.xenotime.net/linux/mentor/linux-mentoring.pdf  http://www.linuxdevices.com/articles/AT5340618290.html  http://www.stardust.webpages.pl/files/handbook/handbook-en-0.3-rc1.pdf  http://www.opersys.com/LTT/ 381  Moteur de recherche de code source :  Krugle.com  Koders.com  code.google.com  www.google.com/linux  www.google.com/codesearch  http://lxr.linux.no
  • 382.
    FORMATION LINUX Liens  http://www.cs.umd.edu/hcil/millionvis/Treemap_Visualization_of_the_Linux_Kernel_2_5_33.html  http://www.linuxdevices.com http://web.yl.is.s.u-tokyo.ac.jp/~tosh/kml/  http://www.alcove.com/IMG/pdf/kernel_debugging.pdf  http://www.ibm.com/developerworks/linux/library/l-initrd.html  http://www.ibm.com/developerworks/library/l-proc.html  http://www.ibm.com/developerworks/linux/library/l-linuxboot/  http://devresources.linux-foundation.org/rddunlap/doc/scale-3x-kj-v5.pdf  http://www.chear.defense.gouv.fr/fr/think_tank/archives/rstd/64/rstd64p77.pdf  http://www.trunix.org/programlama/c/kernel-api/index.html  http://www.ibm.com/developerworks/linux/library/l-linux-filesystem/  http://docs.huihoo.com/linux/kernel/a1/index.html  http://lwn.net/Articles/13325/  http://en.wikipedia.org/wiki/Linux_Kernel_API  http://kernelbook.sourceforge.net/kernel-api.pdf  http://kernelbook.sourceforge.net/  http://kernelnewbies.org/KernelHacking  http://www.linuxjournal.com/article/5833  http://www.cs.rochester.edu/~kshen/csc256-spring2005/assignments/xen-programming4.html  http://www.linux.it/~rubini/docs/ksys/ksys.html  http://www.cs.pitt.edu/~jmisurda/teaching/cs1550/2077/cs1550-2077-project2.htm  http://oss.sgi.com/projects/kernprof/  http://oss.sgi.com/projects/lockmeter/  http://oss.sgi.com/projects/cpumemsets/ 382
  • 383.
    FORMATION LINUX Liens  http://linuxdriverproject.org/twiki/bin/view  http://www.spinics.net/lists/netdev/ http://linux-mm.org/LinuxMM  http://kernelnewbies.org/known_regressions  http://tldp.org/  http://lea-linux.org/  http://oss.sgi.com/projects/numa/  http://oss.sgi.com/projects/sgi_propack/  http://www.linuxjournal.com/article/5833  http://www.kernel.org/doc/htmldocs/ 383
  • 384.
    FORMATION LINUX Carte interactive dessources du noyau  http://www.linuxdriver.co.il/kernel_map Carte interactive de la carte du noyau GNU Linux 384
  • 385.
    FORMATION LINUX Carte du noyau2.5.33 (version de dev)  http://www.cs.umd.edu/hcil/millionvis/Treemap_Visualization_of_the_Linux_Kernel_2_5_33.html 385
  • 386.
    FORMATION LINUX Sites web incontournables Linux Weekly News (http://lwn.net/)  Le résumé hebdomadaire de toutes les sources d'informations pour des logiciels libres et Linux  Discussions techniques sur le noyau  Abonnez-vous pour financer les éditeurs ($5 / mois)  Articles disponibles pour les non abonnés au bout d'une semaine.  KernelTrap (http://kerneltrap.org/)  Forum pour les développeurs noyau  Actualités, articles, discussions, sondages, entretiens.  Parfait si un résumé ne vous suffit pas.  FAQ de la liste de diffusion du noyau Linux (ttp://www.tux.org/lkml/ A lire avant de poser une question à la liste de diffusion !  Kernel Newbies (http://kernelnewbies.org/)  Glossaires, articles, présentations, HOWTOs, lectures recommandées, utilitaires pour les personnes devenant familières avec le développement noyau.  FAQ du noyau Linux: www.tux.org/lkml/  Résumés des discussions: www.kerneltraffic.org 386
  • 387.
    FORMATION LINUX La communauté autourdu noyau  Les moyens de communication :  La Linux Kernel Mailing List (LKML),  Des mailing lists par sous-système et projet,  Les archives sur http://vger.kernel.org/vger-lists.html,  Des canaux IRC (voir les sites d'introduction plus bas)  Les manifestations :  RMLL (français)  Kernel Summit (international)  FOSDEM (européen)  L'introduction au développement noyau :  Kernel Mentors (http://kernelnewbies.org/KernelMentors),  Kernel Janitors (http://www.kerneljanitors.org/),  Kernel Newbies (http://kernelnewbies.org/)  Les outils :  Un gestionnaire de code pour développement distribué (GIT),  Un suivi des régressions (http://kernelnewbies.org/known_regressions),  Bugzilla (diversement utilisé et apprécié) 387
  • 388.
    FORMATION LINUX Kit de développementofficiel • http://www.kroah.com/log/2006/05/24/#ddk • http://www.kernel.org/pub/linux/kernel/people/gregkh/ddk/ • http://www.kernel.org/pub/linux/kernel/people/gregkh/ddk/ddk-2.6.16.18.iso.bz2 In coordination with the FreedomHEC conference in Seattle, WA, USA. LSB Driver Development Kit (DDK) (make LSB-compliant printer and scanner driver packages) http://www.linux-foundation.org/en/OpenPrinting/WritingA ndPackagingPrinterDrivers http://ldn.linuxfoundation.org/how-participate-linux-commu nity 388
  • 389.