7 jours d'essai offerts
Cet ouvrage et des milliers d'autres sont disponibles en abonnement pour 8,99€/mois
ou
Achetez pour : 31,99 €

Lecture en ligne + Téléchargement

Format(s) : PDF

sans DRM

Vous aimerez aussi

Pokémon GO 100% non officiel

de editions-eyrolles

J'arrête la malbouffe !

de editions-eyrolles

Le pouvoir des gentils

de editions-eyrolles

suivant

Conception
de systèmes
d’exploitation
Le casLinuxCHEZ LE MÊME ÉDITEUR
C. BLAESS. – Scripts sous Linux. Shell Bash, Sed, Awk, Perl, Tcl, Tk, Python, Ruby...
N°11405, 2004, 784 pages.
C. BLAESS. – Programmation système en C sous Linux.
Signaux, processus, threads, IPC et sockets. N°11054, 2000, 960 pages.
P. FICHEUX. – Linux embarqué.
N°11024, 2002, 326 pages.
Ouvrages d’administration
eB. BOUTHERIN, B. DELAUNAY. – Sécuriser un réseau Linux, 2 édition.
N°11445, 2004, 200 pages.
E. DREYFUS. – BSD, 2e édition (coll. Cahiers de l’Admin).
N°11463, 2004, 300 pages.
C. HUNT. – Serveurs réseau Linux.
N°11229, 2003, 650 pages.
V. STANFIELD & R..W. SMITH – Guide de l’administrateur Linux.
N°11263, 2003, 654 pages.
A. BERLAT, J.-F. BOUCHAUDY, G. GOUBET. – Unix Utilisateur.
eN°11319, 2 édition, 2003, 350 pages.
A. BERLAT, J.-F. BOUCHAUDY, G. GOUBET. – Unix Shell.
eN°11147, 2 édition, 2002, 412 pages.
J.-F. BOUCHAUDY, G. GOUBET. – Unix Administration.
eN°11053, 2 édition, 2002, 580 pages.
J.-F. BOUCHAUDY, G. GOUBET. – Linux Administration.
eN°11505, 4 édition 2004, 936 pages.Patrick Cegielski
Conception
de systèmes
d’exploitation
Le casLinux
Deuxième éditionÉDITIONS EYROLLES
61, bd Saint-Germain
75240 Paris Cedex 05
www.editions-eyrolles.com
Avec la contribution de Mathieu Ropert, Sébastien Blondeel et Florence Henry.
erLe code de la propriété intellectuelle du 1 juillet 1992 interdit en effet expressément la
photocopie à usage collectif sans autorisation des ayants droit. Or, cette pratique s’est
généralisée notamment dans les établissements d’enseignement, provoquant une baisse
brutale des achats de livres, au point que la possibilité même pour les auteurs de créer des
œuvres nouvelles et de les faire éditer correctement est aujourd’hui menacée.
En application de la loi du 11 mars 1957, il est interdit de reproduire intégralement ou
partiellement le présent ouvrage, sur quelque support que ce soit, sans l’autorisation de l’Éditeur ou
du Centre Français d’exploitation du droit de copie, 20, rue des Grands Augustins, 75006 Paris.
© Groupe Eyrolles, 2003, 2004, ISBN : 2-212-11479-6Pour IrŁne et MariePrØface
Le but de ce livre est de faire comprendre comment on con oit un systŁme d’exploitation en
illustrant notre propos sur un cas concret dont nous commentons les sources complŁtement.
Le choix s’est portØ tout naturellement sur le premier noyau Linux, ce que nous justi ons au
chapitre 3.
En prØrequis, nous supposons que le lecteur conna t la notion de systŁme d’exploitation en tant
qu’utilisateur, pour des systŁmes d’exploitation tels que MS-DOS, Unix, MacOs ou Windows
(95, 98, 2000, NT ou XP), un langage d’assemblage pour les microprocesseurs Intel 80x86 et
qu’il sache programmer en langage C.
On peut distinguer cinq niveaux de rapports avec un systŁme d’exploitation :
le niveau utilisateur : le but principal consiste essentiellement ? charger les logiciels que l’on
veut utiliser et de manipuler quelque peu les chiers ; on se sert pour cela de l’interprØteur
de commandes (et de ses commandes telles que copy, rename...) ;
le niveau administrateur : cela consiste ? paramØtrer le systŁme et ? le tenir ? jour ; il est
indispensable pour les systŁmes d’exploitation capables d’accueillir plusieurs utilisateurs ;
le niveau Øcriture de scripts pour automatiser certaines sØquences rØpØtitives de commandes ;
le niveau programmation systŁme : cette programmation se fait pour Linux en langage C en
utilisant les appels systŁme ;
le niveau conception du systŁme, et plus particuliŁrement du noyau.
Nous allons nous intØresser ici ? la conception du systŁme d’exploitation, en illustrant nos
propos par Linux, plus particuliŁrement par le tout premier noyau 0.01. L’intØrŒt de choisir
Linux est que le code est di usØ.
Ce livre n’a d’autre but que de publier en un seul volume les aspects suivants de la conception
d’un systŁme d’exploitation :
les concepts gØnØraux sous-jacents ? l’implØmentation d’un systŁme d’exploitation, tels qu’on
les trouve dans [TAN-87] dont nous nous inspirons fortement ;
les concepts d’un systŁme d’exploitation de type Unix, en suivant le plus possible la norme
Posix ;
de la documentation sur le microprocesseur Intel 80386 ; celle-ci exigeant un ouvrage de la
taille de celui-ci, nous en supposons connue au moins une partie, celle qui concerne le mode
dit rØel ;
la documentation sur les contr leurs de pØriphØriques et leur implØmentation sur un compa-
tible PC, nØcessaire ? la programmation d’un systŁme d’exploitation ;
une prØsentation des choix faits pour l’implØmentation de Linux 0.01, suivie d’extraits de
chiers sources, repØrables facilement par l’indication Linux 0.01 situØe en marge, puis para-
phrasØs en fran ais ; ces paraphrases, commen ant presque toujours par autrement dit , neiv PrØface
sont pas thØoriquement indispensables mais sont souvent apprØciables ; comme nous l’avons
dØj dit, tout le source est commentØ, mŒme si pour des raisons logiques il est dispersØ tout
au long de l’ouvrage.
Chemin faisant, nous montrons ainsi une mØthode pour Øtudier les sources d’autres systŁmes
d’exploitation.
L’index fait rØfØrences aux concepts mais aussi ? tous les noms apparaissant dans les chiers
source, ce qui permet de se rendre directement au commentaire de la partie qui intØresse le
lecteur.
PrØface ? la seconde Ødition
Dans cette seconde Ødition, paraissant dix mois aprŁs la premiŁre, le corps du texte principal
n’a pas changØ, ? part la correction d’une coquille. En revanche, chaque chapitre se conclut
dØsormais par une section Øvolution du noyau renforcØe, prenant en compte la version 2.6.0
de ce dernier. Nous conseillons de lire le livre sans tenir compte de ces sections puis d’y revenir
dans un deuxiŁme temps.
Nous expliquons au chapitre 3 pourquoi il est prØfØrable, dans un premier temps, de s’attacher
au tout premier noyau. Je pense que pour les a cionados du tout dernier noyau en date, ces
derniŁres sections seront utiles.
Remerciements
Je tiens ? remercier tout particuliŁrement Mathieu Ropert, Øtudiant de l’I.U.T. de Fontaine-
bleau en 2001 2003, pour sa relecture trŁs attentive du manuscrit.Table des matiŁres
PrØface ............................................ iii 2.2 Les pilotes de pØriphØriques ................ 19
2.3 Logiciel d’entrØe-sortie indØpendant du
matØriel .................................. 19PREMI¨RE PARTIE :
2.4 Logiciels d’entrØe-sortie faisant partie dePRINCIPES DE CONCEPTION DES SYST¨MES
l’espace de l’utilisateur .................... 21D’EXPLOITATION 1
Chapitre 3 Le systŁme Linux ØtudiØ ............... 23Chapitre 1 Structure d’un systŁme d’exploitation .. 3
1 Le systŁme Linux ? Øtudier ....................... 231 Les trois grandes fonctions....................... 3
1.1 Noyau et distribution ...................... 231.1 Chargement des programmes ............... 3
1.2 Noyau minimal ............................ 231.2 Le systŁme d’exploitation en tant que
1.3 Obtention des sources ..................... 24machine virtuelle .......................... 4
1.4 Programmation Linux ..................... 241.3 Le systŁme d’exploitation en tant que
1.5 Versions du noyau Linux ................... 24gestionnaire de ressources .................. 4
2 Les sources du noyau 0.01 ....................... 252 CaractØristiques d’un systŁme d’exploitation ....... 5
2.1 Vue d’ensemble sur l’arborescence .......... 252.1 SystŁmes multi-t ches ..................... 5
2.2 L’arborescence dØtaillØe .................... 252.2 multi-utilisateurs ................. 7
3 Vue d’ensemble sur l’implØmentation ............. 323 Structure externe d’un systŁme d’exploitation...... 9
3.1 CaractØristiques ........................... 323.1 Noyau et utilitaires ........................ 9
3.2 tapes de l’implØmentation ................ 323.2 Le gestionnaire de t ches .................. 9
4 volution du noyau ............................. 343.3 Le de mØmoire ................ 9
4.1 Cas du noyau 2.4.18 ....................... 343.4 Le gestionnaire de chiers .................. 9
4.2 Aide au parcours du code source ........... 353.5 Le de pØriphØriques ............ 10
4.3 Cas du noyau 2.6.0 ........................ 353.6 Le chargeur du systŁme d’exploitation ....... 10
3.7 L’interprØteur de commandes ............... 10
DEUXI¨ME PARTIE :4 Structure interne d’un systŁme d’exploitation ...... 10
UTILISATION DU MICRO-PROCESSEUR4.1 Les systŁmes monolithiques ................ 11
INTEL 374.2 SystŁmes ? modes noyau et utilisateur ...... 11
4.3 ? couches ....................... 11 Chapitre 4 Prise en compte de la mØmoire Intel ... 39
4.4 SystŁmes ? micro-noyau ................... 12 1 La segmentation sous Intel....................... 39
4.5 ? modules ....................... 13 1.1 Notion ................................... 39
5 Mise en uvre .................................. 14 1.2 La segmentation en mode protØgØ sur Intel .. 39
5.1 Les appels systŁme ........................ 14 2 La sous Linux...................... 45
5.2 Les signaux ............................... 14 2.1 Mode noyau et mode utilisateur ............ 45
2.2 Segmentation en mode noyau .............. 46Chapitre 2 Principe de traitement des entrØes-
2.3 AccŁs ? la mØmoire vive ................... 50sorties ................................. 15
3 volution du noyau ............................. 511 Principe du matØriel d’entrØe-sortie ............... 15
3.1 Prise en compte d’autres micro-processeurs .. 511.1 Les pØriphØriquesrtie ............ 15
3.2 AccŁs ? la mØmoire vive ................... 521.2 Les contr leurs de pØriphØriques ............ 16
3.3 Utilisation de la segmentation .............. 521.3 Transferts synchrones et asynchrones ....... 17
1.4 PØriphØriques partagØs et dØdiØs ............ 18 Chapitre 5 Adaptation des entrØes-sorties et des
2 Principe des logiciels d’entrØe-sortie .............. 18 interruptions Intel ..................... 55
2.1 Objectifs des logiciels des entrØes-sorties .... 18 1 AccŁs aux ports d’entrØe-sortie ................... 55vi Table des matiŁres
1.1 AccŁs aux ports d’entrØe-sortie sous 80x86 .. 55 1.13 Informations sur les chiers utilisØs ......... 89
1.2 Encapsulation des accŁs aux ports d’entrØe- 1.14 Table locale de descripteurs ................ 90
sortie sous Linux .......................... 55 1.15 Segment d’Øtat de t che ................... 90
2 Les interruptions sous Linux ..................... 56 2 T che initiale ................................... 94
2.1 Rappels sur les vecteurs d’interruption d’Intel 56 3 Table des processus ............................. 97
2.2 Adaptations sous Linux .................... 60 3.1 Stockage des descripteurs de processus ...... 98
3 Initialisation des exceptions ...................... 61 3.2 ImplØmentation de la table des processus .... 99
3.1 Initialisation provisoire ..................... 61 3.3 RepØrage d’un descripteur de processus ..... 99
3.4 La t che en cours ......................... 993.2 dØ nitive ..................... 62
4 volution du noyau ............................. 1004 Initialisation des interruptions matØrielles.......... 64
4.1 Structure du descripteur de processus ....... 1004.1 Un problŁme de conception ................ 64
4.2 Table des processus ....................... 1024.2 Contr leur d’interruptions programmable .... 65
4.3 Programmation des registres de contr le Chapitre 7 Description du systŁme de chiers ..... 103
d’initialisation du PIC ..................... 66 1 tude gØnØrale ................................. 103
4.4 des registres de contr le 1.1 Notion de chiers ......................... 103
des opØrations du PIC ..................... 68 1.2 Gestion des chiers ........................ 104
4.5 Reprogrammation du PIC dans le cas de 1.3 Les chiers du point de vue utilisateur ...... 104
Linux .................................... 70 1.4 La conception des systŁmes de chiers ...... 106
4.6 Gestionnaires des interruptions matØrielles ... 71
2 CaractØristiques d’un chier ...................... 109
4.7 Manipulation des ... 72
2.1 Types de chiers .......................... 109
5 Initialisation de l’interruption logicielle ............ 72 2.2 Droits d’accŁs d’un chier sous Unix ....... 110
6 volution du noyau ............................. 73 2.3 Mode d’un chier sous Unix ............... 111
6.1 AccŁs aux ports d’entrØe-sortie ............. 73 3 Notion de tampon de disque dur ................. 111
6.2 Insertion des portes d’interruption .......... 73 4 Structure d’un disque Minix..................... 112
6.3 Initialisation des exceptions ................ 74 4.1 Bloc sous Minix et Linux ................. 112
6.4 des interruptions matØrielles .... 76 4.2 Structure gØnØrale d’un disque Minix ....... 112
6.5 Manipulation des ... 76 4.3 Les n uds d’information sur disque ......... 113
4.4 Le super bloc ............................. 115
TROISI¨ME PARTIE : 5 SystŁme de chiers Minix chargØ en mØmoire ..... 116
LES GRANDES STRUCTURES 5.1 AntØmØmoire ............................. 116
DE DONN ES 79 5.2 Les descripteurs de n ud d’information ..... 119
Chapitre 6 Les structures de donnØes concernant 5.3 Table des super-blocs ...................... 121
les processus .......................... 81 5.4 Les descripteurs de chiers ................. 122
6 Fichiers de pØriphØriques......................... 1231 Descripteur de processus......................... 81
1.1 Structure du descripteur de processus ....... 81 6.1 CaractØristiques ........................... 123
1.2 Aspects structurels ........................ 82 6.2 RepØrage des chiers de pØriphØriques ...... 124
1.3 tat d’un processus ....................... 82 7 volution du noyau ............................. 124
1.4 PrioritØ d’un processus .................... 83 7.1 Prise en charge de plusieurs systŁmes de
1.5 Signaux .................................. 84 chiers ................................... 124
1.6 Code de statut ............................ 85 7.2 Cas de Posix ............................ 125
1.7 Espace d’adressage ........................ 85 7.3 SystŁme de chiers virtuel ................. 125
1.8 Identi cateurs du processus ................ 85 7.4 Super-bloc ............................... 126
1.9 HiØrarchie des processus ................... 86 7.5 N ud d’information ....................... 128
1.10 PropriØtaire d’un processus ................. 87 7.6 Descripteur de chier ...................... 129
1.11 Informations temporelles ................... 88 7.7 RØpertoire ................................ 130
1.12 Utilisation du coprocesseur mathØmatique ... 89 7.8 Types de chiers .......................... 131Table des matiŁres vii
7.9 DØclaration d’un systŁme de chiers ........ 131 2.1 L’horloge temps rØel des PC ............... 194
7.10 Descripteur de tampon .................... 131 2.2 Minuteur pØriodique programmable ......... 196
3 Programmation du minuteur sous Linux........... 198Chapitre 8 Les terminaux sous Linux .............. 133
3.1 Initialisation du .................. 1991 Les terminaux .................................. 133
3.2 Variable de sauvegarde du temps ........... 1991.1 Notion de terminal ........................ 133
3.3 Gestionnaire de l’interruption d’horloge ...... 1991.2 Les terminaux du point de vue matØriel ..... 133
3.4 La comptabilisation du processus en cours ... 2001.3 Le pilote de terminal ...................... 139
4 Maintien de la date et de l’heure sous Linux ....... 2011.4 Les di Ørents terminaux et les normes ....... 139
4.1 Variable structurØe de conservation du temps 2011.5 ModØlisation en voies de communication .... 140
4.2 Initialisation de la variable structurØe ....... 2022 ParamØtrage des voies de ......... 140
5 volution du noyau ............................. 2042.1 Principe .................................. 140
2.2 La structure de paramØtrisation ............ 141 Chapitre 11 Le gestionnaire des t ches ............. 209
2.3 ParamØtrage des modes d’entrØe ........... 141 1 Commutation de processus ...................... 209
2.4 Pa des modes de sortie ........... 143 1.1 Notion gØnØrale ........................... 209
2.5 Le tableau des caractŁres de contr le ....... 145 1.2 Gestion du coprocesseur arithmØtique ....... 209
2.6 ParamØtrage des modes locaux ............. 148 1.3 Cas de Linux ............................. 209
2.7 ParamØtrages des modes de contr le ........ 150 2 Ordonnancement des processus .................. 210
3 ImplØmentation des voies de communication....... 151 2.1 Politique d’ordonnancement ................ 211
3.1 d’un tampon d’entrØe ou 2.2 Algorithme d’o .............. 212
de sortie ................................. 151 3 Initialisation du gestionnaire des t ches ........... 215
3.2 ImplØmentation des voies de communication . 153 4 volution du noyau ............................. 215
4 du terminal...................... 154 Chapitre 12 Les signaux sous Linux ................. 221
4.1 DØ nition du ..................... 154 1 Notion gØnØrale de signal ........................ 221
4.2 Les caractŁres de contr le .................. 155 2 Liste et signi cation des signaux ................. 221
4.3 CaractØristiques de la console .............. 155 3 Vue d’ensemble de manipulation des signaux ...... 223
4.4 Ca des liaisons sØrie ........... 156 4 ImplØmentation des deux appels systŁme .......... 224
4.5 Les tampons du terminal .................. 156 4.1 de l’appel d’envoi
5 volution du noyau ............................. 156 d’un signal ............................... 224
4.2 ImplØmentation de l’appel systŁme de
QUATRI¨ME PARTIE : dØroutement .............................. 225
ASPECT DYNAMIQUE SANS AFFICHAGE 163 5 ImplØmentation du traitement des signaux ........ 225
6 Fonction de gestion de signal par dØfaut .......... 227Chapitre 9 ImplØmentation des appels systŁme
7 volution du noyau ............................. 227sous Linux ............................. 165
1 Principe........................................ 165
1.1 DØ nition des appels systŁme .............. 165 CINQUI¨ME PARTIE :
1.2 Notion de code d’erreur ................... 168 AFFICHAGE 231
1.3 Insertion et exØcution des appels systŁme .... 169 Chapitre 13 Le pilote d’Øcran sous Linux ............ 233
1.4 Fonction d’appel .......................... 171
1 A chage brut .................................. 233
2 Liste des codes d’erreur ......................... 172 1.1 Rappels sur l’a chage texte sur l’IBM-PC ... 233
3 Liste des appels systŁme......................... 174 1.2 ImplØmentation sous Linux ................. 234
4 volution du noyau ............................. 178 2 Notion d’a chage structurØ ..................... 237
Chapitre 10 Mesure du temps sous Linux ........... 189 2.1 Principe du logiciel d’a chage structurØ .... 237
1 Les horloges .................................... 189 2.2 Cas de Linux ............................. 238
1.1 Le matØriel de l’horloge .................... 190 3 Les suites d’Øchappement ECMA-48 .............. 238
1.2 Le logiciel des horloges .................... 191 3.1 Syntaxe .................................. 238
2 Horloges matØrielles des PC...................... 194 3.2 SØmantique ............................... 239viii Table des matiŁres
4 Le pilote d’Øcran sous Linux ..................... 240 2.5 Les macros auxiliaires ..................... 296
4.1 Prise en compte des caractØristiques 3 La routine int3()............................. 296
ECMA-48 ................................ 240 4 La routine device_not_available() ...... 297
4.2 Fonction d’Øcriture sur la console ........... 241 4.1 La routine principale ...................... 297
4.3 Traitement des cas spØciaux ............... 245 4.2 La fonction math_state_restore() .. 298
5 volution du noyau ............................. 254
5 volution du noyau ............................. 298
5.1 A chage graphique et a chage console .... 254
Chapitre 17 MØmoire virtuelle sous Linux ........... 301
5.2 CaractØristiques de l’Øcran ................. 254
1 tude gØnØrale ................................. 301
5.3 Les consoles .............................. 259
1.1 MØmoire virtuelle ......................... 301
Chapitre 14 L’a chage des caractŁres sous Linux ... 263
1.2 Mise en place de la mØmoire virtuelle ....... 301
1 Traitement des caractŁres........................ 263
2 Pagination ..................................... 302
1.1 Les caractŁres ............................ 263
2.1 Notion ................................... 302
1.2 Classi cation primaire des caractŁres ........ 263
2.2 Pagination ? plusieurs niveaux .............. 302
1.3 Fonctions de classi cation des caractŁres .... 264
2.3 Protection ................................ 304
1.4 F de conversion ................... 265
3 La pagination sous Intel 80386 ................. 304
2 criture sur une voie de communication ........... 266
3.1 Taille des pages ........................... 304
2.1 Description ............................... 266
3.2 Structure des entrØes des tables ............ 305
2.2 ImplØmentation ........................... 266
3.3 Activation de la pagination ................. 306
2.3 Attente du vidage du tampon d’Øcriture ..... 267
3.4 Structure d’une adresse virtuelle ............ 306
2.4 Traitement des processus en attente ........ 268
3.5 MØcanisme de protection matØrielle ......... 306
3 volution du noyau ............................. 269
4 La pagination sous Linux ........................ 3063.1 Traitement des caractŁres .................. 269
4.1 Mise en place des ØlØments ................ 3063.2 criture sur une voie de communication ..... 269
4.2 Initialisation de la pagination ............... 307
Chapitre 15 L’a chage formatØ du noyau .......... 273
4.3 Zone xe et zone de mØmoire dynamique .... 308
1 Nombre variable d’arguments .................... 273
4.4 Structures de gestion des tables de pages .... 309
1.1 L’apport du C standard .................... 273
4.5 Obtention d’un cadre de page libre ......... 310
1.2 ImplØmentation de stdarg.h sous Linux .. 274
4.6 LibØration d’un cadre de page .............. 311
2 Formatage ..................................... 275
5 Traitement de l’exception de dØfaut de page....... 311
2.1 La fonction sprintf() .................. 275
5.1 Le code principal .......................... 312
2.2 Structure des formats ..................... 275
5.2 Exception d’essai d’Øcriture sur une page en
2.3 Le cas de Linux 0.01 ...................... 277
lecture seule .............................. 313
2.4 ImplØmentation de vsprintf() sous Linux 277
5.3 Exception de page non prØsente ............ 314
2.5 Les fonctions auxiliaires .................... 280
6 volution du noyau ............................. 315
3 La fonction printk() ......................... 283
4 La panic() .......................... 284
SEPTI¨ME PARTIE :5 volution du noyau ............................. 284
FICHIERS R GULIERS 325
Chapitre 18 Le pilote du disque dur ................ 327SIXI¨ME PARTIE :
ASPECT DYNAMIQUE AVEC AFFICHAGE 289 1 GØomØtrie des disques durs ...................... 327
1.1 Description gØnØrale ....................... 327Chapitre 16 Gestionnaires des exceptions ........... 291
1.2 Prise en charge par Linux .................. 3281 Traitement des exceptions sous Linux ............. 291
2 Le contr leur de disque dur IDE .................. 3302 Structure gØnØrale des routines................... 292
2.1 Les registres IDE .......................... 3302.1 DØ nitions des gestionnaires ............... 292
2.2 Les commandes du contr leur IDE .......... 3342.2 Structure d’un gestionnaire ................ 292
2.3 Les fonctions de traitement du code d’erreur 293 3 Prise en charge du contr leur par Linux ........... 341
2.4 Les C des gestionnaires par dØfaut . 294 3.1 Constantes liØes au contr leur .............. 341Table des matiŁres ix
3.2 Routine d’interruption matØrielle du disque 4.3 CrØation d’un descripteur de tampon ........ 377
dur ...................................... 342 4.4 Lecture d’un tampon ...................... 379
3.3 Passage des commandes ................... 344 5 volution du noyau ............................. 379
3.4 Fonction d’attente du contr leur ........... 345
Chapitre 20 Les pØriphØriques bloc ................. 385
3.5 RØcupØration des erreurs ................... 345
1 Vue d’ensemble ................................. 385
4 Partitionnement du disque dur ................... 346
2 AccŁs ? bas niveau .............................. 386
4.1 Un choix d’IBM ........................... 346
2.1 DØtermination des pØriphØriques bloc ....... 386
4.2 Utilisation par Linux ....................... 348
2.2 Table des pilotes de bas niveau ............. 387
5 RequŒtes ? un disque dur ........................ 348
2.3 Fonction d’accŁs ? bas niveau .............. 387
5.1 Notion de requŒte ......................... 348
3 Les fonctions de lecture et d’Øcriture de bloc ...... 388
5.2 Structure des requŒtes ..................... 348
3.1 Fonction d’Øcriture ........................ 388
5.3 Tableau des listes de requŒtes .............. 349
3.2 F de lecture ........................ 389
5.4 Initialisation du disque dur ................. 349
4 volution du noyau ............................. 391
5.5 RequŒte de lecture ou d’Øcriture ............ 350
Chapitre 21 Gestion des n uds d’information ....... 3955.6 Gestion des tampons ...................... 351
5.7 Ajout d’une requŒte ....................... 353 1 Chargement d’un super-bloc ..................... 395
5.8 Traitement des requŒtes ................... 355 2 Gestion des tables de bits des donnØes ............ 395
5.9 Le gestionnaire d’interruption en cas 2.1 Recherche d’un bloc de libre ....... 395
d’Øcriture ................................. 356 2.2 Macros auxiliaires ......................... 397
5.10 RØinitialisation du disque dur ............... 357 2.3 LibØration d’un bloc de donnØes ............ 398
5.11 Le gestionnaire d’interruption en cas de
3 Les fonctions internes des n uds d’information .... 399
lecture ................................... 359
3.1 Verrouillage d’un descripteur de n ud ...... 399
6 Pilote du disque dur............................. 359 3.2 DØverrouillage d’un de n ud .... 399
7 volution du noyau ............................. 360 3.3 Fonction d’attente de dØverrouillage ........ 400
7.1 PØriphØriques bloc ......................... 360 3.4 criture d’un n ud d’information sur disque . 400
7.2 GØomØtrie d’un disque dur ................. 363 3.5 Lecture d’un n ud d’info sur disque . 401
7.3 Initialisation d’un disque dur traditionnel .... 363 4 Gestion des blocs sur noeud d’information......... 402
7.4 Contr leur de disque dur ................... 366 4.1 DØtermination du numØro de bloc physique .. 402
7.5 Interruption matØrielle d’un disque dur ...... 368 4.2 AgrØgation d’un bloc physique ............. 402
7.6 Passage des commandes ................... 369 4.3 ImplØmentation de la fonction auxiliaire ..... 403
7.7 Partitionnement des disques durs ........... 369
5 Mise ? zØro d’un n ud d’information sur disque ... 405
7.8 RequŒtes ? un disque dur .................. 370
5.1 Mise ? zØro d’un bloc d’indirection simple ... 405
Chapitre 19 Gestion de l’antØmØmoire .............. 373 5.2 Mise ? zØro d’un bloc double ... 406
1 Description des fonctions ........................ 373 5.3 ImplØmentation ........................... 407
1.1 Gestion des listes de tampons .............. 373 6 Fonctions de service des n uds d’information ..... 407
1.2 Fonctions d’accŁs aux tampons ............. 374 6.1 Synchronisation des n uds d’info .... 408
1.3 RØØcriture des tampons modi Øs ........... 374 6.2 Recherche d’un nouveau descripteur de
2 ImplØmentation des fonctions de gestion de listes .. 374 n ud d’information ....................... 408
2.1 Fonctions de hachage ..................... 374 6.3 Remplissage d’une zone de mØmoire ........ 409
2.2 Insertion dans les listes .................... 374 6.4 LibØration d’un n ud d’information en
2.3 Suppression des listes ...................... 375 table des bits ............................. 410
2.4 Recherche d’un descripteur de tampon ...... 375 6.5 Rel chement d’un n ud d’information ...... 411
3 RØØcriture sur un disque donnØ................... 376 6.6 Recherche d’un n ud d’info libre
sur disque ................................ 4124 Les fonctions de manipulation des tampons ....... 376
6.7 Chargement d’un n ud d’information ....... 4134.1 Rel chement d’un tampon ................. 376
4.2 DØtermination d’un descripteur de tampon .. 377 7 volution du noyau ............................. 414x Table des matiŁres
Chapitre 22 Gestion interne des chiers rØguliers 6 volution du noyau ............................. 472
et des rØpertoires ...................... 419 Chapitre 24 Les liaisons sØrie ....................... 477
1 Montage d’un systŁme de chiers ................ 419 1 tude gØnØrale ................................. 477
1.1 Chargement d’un super-bloc ............... 419 1.1 Communication sØrie asynchrone ........... 477
1.2 Initialisation du systŁme de chiers ......... 421 1.2 sØrie synchrone ............ 482
1.3 Lecture de la table des partitions ........... 422 1.3 Le standard d’interface sØrie RS-232 ........ 484
2 Gestion des rØpertoires .......................... 423 2 L’UART PC16550D ............................. 484
2.1 tude gØnØrale des rØpertoires .............. 423
2.1 Le brochage .............................. 485
2.2 Les chiers rØpertoire sous Linux ........... 427 2.2 L’ensemble de registres .................... 485
2.3 Fonctions internes de gestion des rØpertoires . 428 2.3 Programmation de l’UART ................ 489
3 Gestion interne des chiers rØguliers .............. 433 3 Cas de Linux ................................... 489
3.1 Gestion des noms de chiers ............... 433 3.1 Initialisation des liaisons sØrie .............. 489
3.2 Lecture et Øcriture dans un chier rØgulier ... 438 3.2 Gestionnaires d’interruption ................ 491
4 volution du noyau ............................. 440 4 volution du noyau ............................. 495
4.1 Montage d’un systŁme de chiers ........... 441
Chapitre 25 Les pØriphØriques caractŁre ............ 501
4.2 Gestion des rØpertoires et des chiers ....... 444
1 Fonctions de lecture/Øcriture. .................... 501
1.1 Fonction d’accŁs de haut niveau ............ 501
HUITI¨ME PARTIE :
1.2 Fonctions de bas niveau ............ 501
P RIPH RIQUES CARACT¨RE 449
1.3 ImplØmentation de la fonction d’accŁs de
Chapitre 23 Le clavier ............................. 451 haut niveau ............................... 502
1 Principe du logiciel de lecture au clavier........... 451 2 Fonctions d’accŁs de bas niveau des terminaux .... 503
1.1 Modes brut et structurØ ................... 451 2.1 Cas d’un terminal quelconque .............. 503
1.2 Tampon de lecture ........................ 451 2.2 Cas du en cours .................. 503
1.3 Quelques problŁmes pour le pilote .......... 453 3 volution du noyau ............................. 503
2 Interface du clavier sur l’IBM-PC ................. 453
2.1 Aspect physique .......................... 453
NEUVI¨ME PARTIE :
2.2 Make-code et break-code .................. 454
COMMUNICATION PAR TUBES 507
2.3 Les registres du contr leur de clavier ........ 454
Chapitre 26 Communication par tubes sous Linux ... 509
2.4 Principe de lecture des scan codes .......... 457
1 tude gØnØrale ................................. 509
2.5 Le port 61h .............................. 457
1.1 Notion ................................... 509
3 Principe du traitement du clavier sous Linux....... 457
1.2 Types de tubes de communication .......... 510
3.1 Le gestionnaire du clavier .................. 458
2 Gestion interne sous Linux ....................... 510
3.2 Initialisation du gestionnaire de clavier ...... 458
2.1 Descripteur de n ud d’information d’un tube 510
3.3 Grandes Øtapes du de clavier ... 458
2.2 OpØrations d’entrØe-sortie .................. 511
4 Traitement du mode donnØes brutes .............. 459
3 volution du noyau ............................. 513
4.1 Grandes Øtapes ........................... 459
4.2 DØtermination de la fonction de traitement .. 460
DIXI¨ME PARTIE :4.3 Cas des touches prØ xielles ................. 461
LE MODE UTILISATEUR 517
4.4 Cas d’une touche normale ................. 463
4.5 Les touches de dØplacement du curseur ..... 466 Chapitre 27 Appels systŁme du systŁme de chiers . 519
4.6 Les de fonction .................... 467 1 Points de vue utilisateur et programmeur.......... 519
4.7 La touche moins .......................... 468 1.1 Les chiers du point de vue utilisateur ...... 519
4.8 Mise en tampon brut du clavier ............ 468 1.2 Les chiers du point de vue du programmeur 521
5 Traitement du mode structurØ ................... 469 2 EntrØes-sorties Unix sur chier .................. 522
5.1 Appel .................................... 469 2.1 Ouverture et fermeture de chiers .......... 522
5.2 Passage du tampon brut au tampon structurØ 470 2.2 Lecture et Øcriture de donnØes .............. 525Table des matiŁres xi
2.3 Positionnement dans un chier ............. 528 5.2 ImplØmentation ........................... 601
2.4 Sauvegarde des donnØes modi Øes .......... 529 6 Autres appels systŁme ........................... 603
6.1 L’appel break() ................ 6033 ImplØmentation Linux des entrØes-sorties .......... 529
6.2 L’appel systŁme acct() .................. 6033.1 Appel systŁme d’ouverture ................. 529
7 volution du noyau ............................. 6033.2 Appel de crØation ................. 533
3.3 Appel systŁme de fermeture ................ 534 Chapitre 29 Les autres appels systŁme sous Linux ... 609
3.4 Appel de lecture des donnØes ....... 534 1 Appels systŁme de mesure du temps .............. 609
3.5 Appel systŁme d’Øcriture des ....... 537 1.1 Liste ..................................... 609
3.6 Appel de positionnement ........... 538 1.2 ImplØmentation ........................... 610
3.7 Appel systŁme de sauvegarde des donnØes ... 539 2 Appels systŁme liØs ? l’ordonnancement ........... 611
4 Liens et chiers partagØs ........................ 539 2.1 PrioritØ des processus ...................... 611
4.1 tude gØnØrale ............................ 539 2.2 Contr le de l’exØcution d’un processus ...... 612
4.2 CrØation de liens symboliques sous Unix .... 541 3 Appels systŁme concernant les signaux ............ 612
4.3 ImplØmentation sous Linux ................. 542 3.1 mission d’un signal ....................... 612
5 Manipulations des chiers ....................... 544 3.2 DØroutement d’un signal ................... 613
5.1 Les appels systŁme Unix .................. 544 3.3 Attente d’un signal ........................ 614
5.2 ImplØmentation sous Linux ................. 546 4 Appels systŁme concernant les pØriphØriques....... 615
6 Gestion des rØpertoires .......................... 550 4.1 CrØation d’un chier spØcial ................ 615
6.1 Les appels systŁme Unix .................. 550 4.2 OpØrations de contr le d’un pØriphØrique .... 616
6.2 ImplØmentation ........................... 552 5 Appels systŁme concernant la mØmoire............ 618
7 Autres appels systŁme ........................... 558 5.1 Structure de la mØmoire utilisateur ......... 618
7.1 Duplication de descripteur d’entrØe-sortie .... 558 5.2 Changement de la taille du segment des
7.2 RØcupØration des attributs des chiers ...... 559 donnØes .................................. 619
7.3 Dates associØes aux chiers ................ 562 5.3 AccŁs ? une adresse physique .............. 620
7.4 PropriØtØs des chiers ouverts .............. 563 6 Tubes de communication ........................ 620
7.5 Montage et dØmontage de systŁmes de 6.1 Description ............................... 620
chiers ................................... 565 6.2 ImplØmentation ........................... 621
7 Autres appels systŁme ........................... 6228 volution du noyau ............................. 566
8 volution du noyau ............................. 623
Chapitre 28 Appels systŁme concernant les
Chapitre 30 Fonctions de la bibliothŁque C ......... 625processus .............................. 569
1 La fonction printf() ......................... 6251 CrØation des processus .......................... 569
1.1 Description ............................... 6251.1 Description des appels systŁme ............. 569
1.2 ImplØmentation ........................... 6251.2 ImplØmentation de fork() ............... 572
2 Fonction concernant les signaux .................. 6261.3 Le format d’exØcutable a.out ............. 577
2.1 Description ............................... 6261.4 de execve() ............ 583
2.2 ImplØmentation ........................... 6262 Gestion des attributs ............................ 592
3 Fonctions sur les cha nes de caractŁres ............ 6262.1 Description des appels systŁme ............. 592
4 volution du noyau ............................. 6312.2 ImplØmentation ........................... 593
3 Gestion des groupes et des sessions de processus... 594
ONZI¨ME PARTIE :3.1 Description des appels systŁme ............. 594
D MARRAGE DU SYST¨ME 6333.2 ImplØmentation ........................... 595
4 Terminaison du processus en cours ............... 596 Chapitre 31 DØmarrage du systŁme Linux .......... 635
4.1 Description de l’appel systŁme ............. 596 1 Source et grandes Øtapes ........................ 635
4.2 ImplØmentation ........................... 597 1.1 Fichiers sources concernØs ................. 635
5 Attente de la n d’un processus ls ............... 600 1.2 DØbut de l’amor age ...................... 635
5.1 Les appels systŁme ........................ 600 2 Le chargeur d’amor age ......................... 636xii Table des matiŁres
2.1 Les grandes Øtapes ........................ 636 4.4 Initialisation provisoire de la table des
2.2 Transfert du code d’amor age .............. 637 interruptions .............................. 646
2.3 Con guration de la pile en mode rØel ....... 637 4.5 Initialisation de la table globale des
2.4 A chage d’un message de chargement ...... 638 descripteurs .............................. 647
2.5 Chargement de l’image du noyau ........... 638 4.6 Valeurs nales des registres de segment de
3 Passage au mode protØgØ ........................ 642 donnØes et de pile ......................... 648
3.1 Les grandes Øtapes ........................ 642 4.7 VØri cation de l’activation de la broche A20 649
3.2 Sauvegarde de la position du curseur 4.8 de la prØsence du coprocesseur
graphique ................................ 643 arithmØtique .............................. 649
3.3 Inhibition des interruptions matØrielles ...... 643 4.9 Mise en place de la pagination ............. 649
3.4 Transfert du code du systŁme .............. 643 4.10 Passage ? la fonction start_kernel() .. 649
3.5 Chargement de tables provisoires de 5 La fonction start_kernel() ................ 650
descripteurs .............................. 644 5.1 Les grandes Øtapes ........................ 650
3.6 Activation de la broche A20 ............... 644 5.2 Initialisation du terminal ................... 651
3.7 Reprogrammation du PIC .................. 645 5.3 Passage au mode utilisateur ................ 652
3.8 Passage au mode protØgØ .................. 645 5.4 Le processus 1 : init ....................... 653
4 La fonction startup_32() ................... 645
6 volution du noyau ............................. 654
4.1 Les grandes Øtapes ........................ 645
Bibliographie ....................................... 659
4.2 Initialisation des registres de segmentation ... 646
Index .............................................. 6694.3 Con guration de la pile en mode noyau ..... 646Table des gures
1.1 Processus .................................... 6 10.1 Horloge programmable......................... 190
10.2 Maintien de l’heure courante ................... 1911.2 Minix ....................................... 12
10.3 Traitement des alarmes ........................ 193
4.1 Segmentation ................................. 40
13.1 CaractŁres ASCII modi Øs ...................... 2354.2 SØlection ..................................... 44
4.3 Choix d’un descripteur ......................... 45
17.1 Pagination.................................... 303
17.2 Table de pages ? deux niveaux ................. 304
6.1 Structure du TSS ............................. 91
6.2 Sauvegarde de l’Øtat du coprocesseur arithmØtique 93
20.1 PØriphØrique bloc.............................. 385
6.3 Stockage du descripteur et de la pile noyau ...... 98
22.1 CP/M........................................ 425
7.1 Arborescence de chiers ....................... 106 22.2 MS-DOS ..................................... 426
7.2 Liste cha nØe et table de bits ................... 107 22.3 Unix ........................................ 427
7.3 SystŁme de chiers Minix ..................... 112 22.4 RØpertoire .................................... 428
23.1 Tampon de caractŁres ......................... 4528.1 Un des premiers terminaux ..................... 134
23.2 Scan codes ................................... 4558.2 Le terminal M40 .............................. 135
8.3 Classi cation des terminaux .................... 135
24.1 Niveaux logiques .............................. 478
8.4 Terminal RS-232 .............................. 136
24.2 Port sØrie simple .............................. 479
8.5 Terminal mappØ en mØmoire ................... 138
24.3 RØception .................................... 481
8.6 cran de l’IBM-PC ............................ 139
24.4 Synchronisation ............................... 482
8.7 Gestion d’une voie de communication ........... 140
8.8 CaractŁres de contr le d’Unix ................. 145 26.1 Tube de communication ....................... 509PremiŁre partie
Principes de conception des systŁmes
d’exploitationChapitre 1
Structure d’un systŁme d’exploitation
Nous supposons que le lecteur a vu Linux en tant qu’utilisateur de ce systŁme d’exploitation
et aussi, Øventuellement, en tant qu’administrateur systŁme, en particulier pour les systŁmes
individuels. Nous allons passer ? l’Øtape suivante : la fa on dont ce systŁme d’exploitation est
con u.
On peut s’intØresser ? la conception de Linux pour quatre raisons : par curiositØ intellectuelle,
pour comprendre comment on con oit un systŁme d’exploitation, pour participer au dØvelop-
pement du noyau Linux, ou pour s’en inspirer pour dØvelopper un autre systŁme d’exploi-
tation. Notre but est surtout de satisfaire les deux premiŁres motivations, mais cet ouvrage
pourra Øgalement servir pour les deux autres.
L’intØrŒt de Linux est que les sources sont publiques et que, au-del des grands principes, nous
pourrons visualiser la mise en place des fonctionnalitØs du systŁme ? partir de ces sources et
faire des expØriences en changeant telle ou telle implØmentation.
Dans ce chapitre, nous allons rappeler ce qu’est un systŁme d’exploitation du point de vue de
l’utilisateur et quelles sont les grandes parties d’un tel systŁme. Dans les chapitres suivants,
nous verrons comment mettre en place chacune de ces fonctions.
1 Les trois grandes fonctions d’un systŁme d’exploitation
Un systŁme d’exploitation e ectue fondamentalement trois t ches indØpendantes : il permet
de charger les programmes les uns aprŁs les autres, il Ømule une machine virtuelle et il gŁre les
ressources. PrØcisons chacune de ces t ches.
1.1 Chargement des programmes
Les premiers micro-ordinateurs Øtaient fournis sans systŁme d’exploitation. Les tous premiers
micro-ordinateurs n’avaient qu’un seul programme : un interprØteur du langage BASIC qui
Øtait contenu en mØmoire ROM. Lors de l’apparition des lecteurs de cassettes puis, de fa on
plus able, des lecteurs de disquettes, cela commen a ? changer : si une disquette exØcutable
Øtait placØe dans le lecteur de ce programme Øtait exØcutØ (il fallait Øventuellement
ensuite remplacer cette disquette par une disquette de donnØes), sinon l’interprØteur BASIC
reprenait la main.
Avec cette fa on de faire, chaque changement de programme exigeait le redØmarrage du micro-
ordinateur avec la disquette du programme dØsirØ dans le lecteur de disquettes. C’Øtait le cas
en particulier de l’Apple II.4 PremiŁre partie : Principes de conception des systŁmes d’exploitation
Les micro-ordinateurs furent ensuite, en option, fournis avec un systŁme d’exploitation. Celui-
ci, contenu sur disquette ou en mØmoire RAM, a chait une invite ? l’Øcran. On pouvait alors
remplacer la systŁme de dØmarrage par une disquette contenant le programme dØ-
sirØ : en Øcrivant le nom du programme sur la ligne de commande et en appuyant sur la touche
Retour, le programme Øtait chargØ et exØcutØ. ? la n de l’exØcution de ce programme, on
pouvait charger un nouveau programme, sans devoir redØmarrer le systŁme. Ceci permet, par
exemple, d’Øcrire un texte avec un traitement de texte puis d’appeler un autre programme
pour l’imprimer.
1.2 Le systŁme d’exploitation en tant que machine virtuelle
Notion d’API La gestion d’un systŁme informatique donnØ, par exemple l’IBM-PC, se fait a priori en lan-
gage machine. Ceci est primaire et lourd ? gØrer pour la plupart des ordinateurs, en particulier
en ce qui concerne les entrØes-sorties. Bien peu de programmes seraient dØveloppØs si chaque
programmeur devait conna tre le fonctionnement, par exemple, de tel ou tel disque dur et
toutes les erreurs qui peuvent appara tre lors de la lecture d’un bloc. Il a donc fallu trouver
un moyen de libØrer les programmeurs de la complexitØ du matØriel. Cela consiste ? enrober le
matØriel avec une couche de logiciel qui gŁre l’ensemble du systŁme. Il faut prØsenter au pro-
grammeur une API (pour l’anglais Application Programming interface, interface de program-
mation d’application), ce qui correspond ? une machine virtuelle plus facile ? comprendre
et ? programmer.
Cas du
ConsidØrons par exemple la programmation des entrØes-sorties des disques durs au moyen du
disque dur
contr leur IDE utilisØ sur l’IBM-PC.
Nous verrons au chapitre 18 que le contr leur IDE possŁde 8 commandes principales qui
consistent toutes ? charger entre 1 et 5 octets dans ses registres. Ces commandes permettent
de lire et d’Øcrire des donnØes, de dØplacer le bras du disque, de formater le disque ainsi que
d’initialiser, de tester, de restaurer et de recalibrer le contr leur et les disques.
Les commandes fondamentales sont la lecture et l’Øcriture, chacune demandant sept para-
mŁtres regroupØs dans six octets. Ces paramŁtres spØci ent les ØlØments tels que l’adresse
du premier secteur ? lire ou ? Øcrire, le nombre de secteurs ? lire ou ? Øcrire, ou si l’on doit
essayer de corriger les erreurs. ? la n de l’opØration, le contr leur retourne 14 champs d’Øtat
et d’erreur regroupØs dans 7 octets.
La plupart des programmeurs ne veulent pas se soucier de la programmation des disques durs.
Ils veulent une abstraction simple de haut niveau : considØrer par exemple que le disque
contient des chiers nommØs ; chaque chier peut Œtre ouvert en lecture ou en Øcriture ; il
sera lu ou Øcrit, et nalement fermØ. La partie machine virtuelle des systŁmes d’exploitation
soustrait le matØriel au regard du programmeur et o re une vue simple et agrØable de chiers
nommØs qui peuvent Œtre lus et Øcrits.
1.3 Le systŁme d’exploitation en tant que gestionnaire de ressources
Les ordinateurs modernes se composent de processeurs, de mØmoires, d’horloges, de disques,
de moniteurs, d’interfaces rØseau, d’imprimantes, et d’autres pØriphØriques qui peuvent Œtre
utilisØs par plusieurs utilisateurs en mŒme temps. Le travail du systŁme d’exploitation consisteChapitre 1. Structure d’un systŁme d’exploitation 5
? ordonner et contr ler l’allocation des processeurs, des mØmoires et des pØriphØriques entre
les di Ørents programmes qui y font appel.
Imaginez ce qui se produirait si trois programmes qui s’exØcutent sur un ordinateur essayaient
simultanØment d’imprimer leurs rØsultats sur la mŒme imprimante. Les premiŁres lignes impri-
mØes pourraient provenir du programme 1, les suivantes du programme 2, puis du programme
3 et ainsi de suite. Il en rØsulterait le dØsordre le plus total. Le systŁme d’exploitation peut
Øviter ce chaos potentiel en transfØrant les rØsultats ? imprimer dans un chier tampon sur
le disque. Lorsqu’une impression se termine, le systŁme d’exploitation peut alors imprimer un
des chiers se trouvant dans le tampon. SimultanØment, un autre programme peut continuer ?
gØnØrer des rØsultats sans se rendre compte qu’il ne les envoie pas (encore) ? l’imprimante.
2 CaractØristiques d’un systŁme d’exploitation
2.1 SystŁmes multi-t ches
La plupart des systŁmes d’exploitation modernes permettent l’exØcution de plusieurs t ches
? la fois : un ordinateur peut, pendant qu’il exØcute le programme d’un utilisateur, lire les
donnØes d’un disque ou a cher des rØsultats sur un terminal ou une imprimante. On parle de
systŁme d’exploitation multi-t ches ou multi-programmØ dans ce cas.
Processus
La notion fondamentale des systŁmes d’exploitation multi-t ches est celle de processus. La
notion de programme ne su t pas. Rien n’empŒche que le mŒme programme soit exØcutØ
plusieurs fois en mŒme temps : on peut vouloir, par exemple, deux fenŒtres emacs ou deux
fenŒtres gv pour comparer des textes.
Un processus est une instance de programme en train de s’exØcuter.
Un processus est reprØsentØ par un programme (le code), mais Øgalement par ses donnØes et
par les paramŁtres indiquant oø il en est, lui permettant ainsi de continuer s’il est interrompu
(pile d’exØcution, compteur ordinal...). On parle de l’environnement du programme.
Un processus s’appelle aussi t che (task en anglais) dans le cas de Linux. Linux
Temps partagØ
La plupart des systŁmes d’exploitation multi-t ches sont implØmentØs sur un ordinateur ayant
un seul micro-processeur. Celui-ci, ? un instant donnØ, n’exØcute rØellement qu’un seul pro-
gramme, mais le systŁme peut le faire passer d’un programme ? un autre en exØcutant chaque
programme pendant quelques dizaines de millisecondes ; ceci donne aux utilisateurs l’impres-
sion que tous les programmes sont exØcutØs en mŒme temps. On parle alors de systŁme ?
temps partagØ.
Certains quali ent de pseudo-parallØlisme cette commutation trŁs rapide du processeur d’un
programme ? un autre, pour la di Ørencier du vrai parallØlisme qui se produit au niveau du
matØriel lorsque le processeur travaille en mŒme temps que certains pØriphØriques d’entrØe-
sortie.6 PremiŁre partie : Principes de conception des systŁmes d’exploitation
Abstraction du dØroulement
Conceptuellement, chaque processus a son propre processeur virtuel. Bien sßr, le vrai pro-
cesseur commute entre plusieurs processus. Mais, pour bien comprendre le systŁme, il est prØ-
fØrable de penser ? un ensemble de processus qui s’exØcutent en (pseudo-) parallØlisme plut t
qu’ l’allocation du processeur entre di Ørents processus. Cette commutation rapide est appe-
lØe multi-programmation.
La gure 1.1 ([TAN-87], p. 56) montre quatre processus s’exØcutant en mŒme temps. La -
gure (b) prØsente une abstraction de cette situation. Les quatre programmes deviennent quatre
processus indØpendants disposant chacun de leur propre contr le de ux (c’est- -dire leur
compteur ordinal). ? la gure (c), on peut constater que, sur un intervalle de temps assez
grand, tous les processus ont progressØ, mais qu’ un instant donnØ, il n’y a qu’un seul proces-
sus actif.
Figure 1.1 : Processus
Variables d’environnement
Comme nous l’avons dØj dit, la donnØe du programme est insu sante pour la dØtermination
d’un processus. Il faut lui indiquer toute une sØrie de variables d’environnement : les -
chiers sur lesquels il opŁre, oø en est le compteur ordinal, etc. Ces variables d’environnement
sont nØcessaires pour deux raisons :
La premiŁre est que deux processus peuvent utiliser le mŒme code (deux fenŒtres emacs par
exemple) mais les chiers concernØs peuvent Œtre di Ørents, le compteur ordinal ne pas en
Œtre au mŒme endroit...
La seconde est due au caractŁre multi-t ches, traitØ par pseudo-parallØlisme. PØriodique-
ment, le systŁme d’exploitation dØcide d’interrompre un processus en cours a n de dØmarrer
l’exØcution d’un autre processus. Lorsqu’un processus est temporairement suspendu de cette
maniŁre, il doit pouvoir retrouver plus tard exactement l’Øtat dans lequel il se trouvait au
moment de sa suspension. Il faut donc que toutes les informations dont il a besoin soient
sauvegardØes quelque part pendant sa mise en attente. S’il possŁde, par exemple, plusieurs
chiers ouverts, les positions dans ces chiers doivent Œtre mØmorisØes.Chapitre 1. Structure d’un systŁme d’exploitation 7
La liste des variables d’environnement dØpend du systŁme d’exploitation en question, et mŒme
de sa version. Elle se trouve dans le descripteur du processus (en anglais process descrip-
tor).
Espace mØmoire d’un processus
Dans de nombreux systŁmes d’exploitation, chaque processus possŁde son propre espace mØ-
moire, non accessible aux autres processus. On parle de l’espace d’adressage du processus.
Incidence sur le traitement des durØes
Puisque le processeur commute entre les processus, la vitesse d’exØcution d’un processus ne
sera pas uniforme et variera vraisemblablement si les mŒmes processus sont exØcutØs ? nou-
veau. Il ne faut donc pas que les processus fassent une quelconque prØsomption sur le facteur
temps.
ConsidØrons le cas d’un processus d’entrØe-sortie qui met en marche le moteur d’un lecteur de
disquettes, exØcute 1 000 fois une boucle pour que la vitesse de la disquette se stabilise, puis
demande la lecture du premier enregistrement. Si le processeur a aussi ØtØ allouØ ? un autre
processus pendant l’exØcution de la boucle, le processus d’entrØe-sortie risque d’Œtre rØactivØ
trop tard, c’est- -dire aprŁs le passage du premier enregistrement devant la tŒte de lecture.
Lorsqu’un processus a besoin de mesurer des durØes avec prØcision, c’est- -dire lorsque certains
ØvØnements doivent absolument se produire au bout de quelques millisecondes, il faut prendre
des mesures particuliŁres pour s’en assurer. On utilise alors des minuteurs, comme nous le
verrons.
Cependant, la plupart des processus ne sont pas a ectØs par la multi-programmation du pro-
cesseur et par les di Ørences de vitesse d’exØcution qui existent entre eux.
2.2 SystŁmes multi-utilisateurs
Un systŁme multi-utilisateurs est capable d’exØcuter de fa on (pseudo-) concurrente et
indØpendante des applications appartenant ? plusieurs utilisateurs.
Concurrente signi e que les applications peuvent Œtre actives au mŒme moment et se dis-
puter l’accŁs ? di Ørentes ressources comme le processeur, la mØmoire, les disques durs...
IndØpendante signi e que chaque application peut rØaliser son travail sans se prØoccuper
de ce que font les applications des autres utilisateurs.
Un systŁme multi-utilisateurs est nØcessairement multi-t ches mais la rØciproque est fausse : le
systŁme d’exploitation MS-DOS est mono-utilisateur et mono-t che ; les systŁmes MacOS 6.1
et Windows 3.1 sont mono-utilisateurs mais multi-t ches ; Unix et Windows NT sont multi-
utilisateurs.
Mise en place
Comme pour les systŁmes multi-t ches, la multi-utilisation est ØmulØe en attribuant des laps
de temps ? chaque utilisateur. Naturellement, le fait de basculer d’une application ? l’autre
ralentit chacune d’entre elles et a ecte le temps de rØponse per u par les utilisateurs.8 PremiŁre partie : Principes de conception des systŁmes d’exploitation
MØcanismes associØs
Lorsqu’ils permettent la multi-utilisation, les systŁmes d’exploitation doivent prØvoir un cer-
tain nombre de mØcanismes :
un mØcanisme d’authenti cation permettant de vØri er l’identitØ de l’utilisateur ;
un de protection contre les programmes utilisateur erronØs, qui pourraient
bloquer les autres applications en cours d’exØcution sur le systŁme, ou mal intentionnØs, qui
pourraient perturber ou espionner les activitØs des autres utilisateurs ;
un mØcanisme de comptabilitØ pour limiter le volume des ressources allouØes ? chaque
utilisateur.
Utilisateurs
Dans un systŁme multi-utilisateurs, chaque utilisateur possŁde un espace privØ sur la machine :
gØnØralement, il possŁde un certain quota de l’espace disque pour enregistrer ses chiers, il
re oit des courriers Ølectroniques privØs, etc. Le systŁme d’exploitation doit assurer que la
partie privØe de l’espace d’un utilisateur ne puisse Œtre visible que par son propriØtaire. Il doit,
en particulier, assurer qu’aucun ne puisse utiliser une application du systŁme dans
le but de violer l’espace privØ d’un autre utilisateur.
Chaque utilisateur est identi Ø par un numØro unique, appelØ l’identi ant de l’utilisateur,
ou UID (pour l’anglais User IDenti er ). En gØnØral, seul un nombre limitØ de personnes est
autorisØ ? utiliser un systŁme informatique. Lorsque l’un de ces utilisateurs commence une
session de travail, le d’exploitation lui demande un nom d’utilisateur et un mot
de passe. Si l’utilisateur ne rØpond pas par des informations valides, l’accŁs lui est refusØ.
Groupe d’utilisateurs
Pour pouvoir partager de fa on sØlective le matØriel avec d’autres, chaque utilisateur peut Œtre
membre d’un ou de plusieurs groupes d’utilisateurs. Un groupe est Øgalement identi Ø par
un numØro unique dØnommØ identi ant de groupe, ou GID (pour l’anglais Group IDenti-
er ). Par exemple, chaque chier est associØ ? un et un seul groupe. Sous Unix, il est possible
par exemple de limiter l’accŁs en lecture et en Øcriture au seul possesseur d’un chier, en lec-
ture au groupe, et d’interdire tout accŁs aux autres utilisateurs.
Super-utilisateur
Un systŁme d’exploitation multi-utilisateurs prØvoit un utilisateur particulier appelØ super-
utilisateur ou superviseur (root en anglais). L’administrateur du systŁme doit se connec-
ter en temps que super-utilisateur pour gØrer les comptes des utilisateurs et rØaliser les t ches
de maintenance telles que les sauvegardes et les mises ? jour des programmes. Le super-
utilisateur peut faire pratiquement n’importe quoi dans la mesure oø le systŁme d’exploitation
ne lui applique jamais les mØcanismes de protection, ceux-ci ne concernant que les autres uti-
lisateurs, appelØs utilisateurs ordinaires. Le super-utilisateur peut, en particulier, accØder
? tous les chiers du systŁme et interfØrer sur l’activitØ de n’importe quel processus en cours
d’exØcution. Il ne peut pas, en revanche, accØder aux ports d’entrØe-sortie qui n’ont pas ØtØ
prØvus par le noyau, comme nous le verrons.Chapitre 1. Structure d’un systŁme d’exploitation 9
3 Structure externe d’un systŁme d’exploitation
3.1 Noyau et utilitaires
Le systŁme d’exploitation comporte un certain nombre de routines (sous-programmes). Les
plus importantes constituent le noyau (kernel en anglais). Celui-ci est chargØ en mØmoire
vive ? l’initialisation du systŁme et contient de nombreuses procØdures nØcessaires au bon
fonctionnement du systŁme. Les autres routines, moins critiques, sont appelØes des utilitaires.
Le noyau d’un systŁme d’exploitation se compose de quatre parties principales : le gestion-
naire de t ches (ou des processus), le gestionnaire de mØmoire, le gestionnaire de chiers et le
gestionnaire de pØriphØriques d’entrØe-sortie. Il possŁde Øgalement deux parties auxiliaires : le
chargeur du systŁme d’exploitation et l’interprØteur de commandes.
3.2 Le gestionnaire de t ches
Sur un systŁme ? temps partagØ, l’une des parties les plus importantes du systŁme d’exploita-
tion est le gestionnaire de t ches (en anglais scheduler) ou ordonnanceur. Sur un systŁme
? un seul processeur, il divise le temps en laps de temps (en anglais slices, tranches). PØrio-
diquement, le de t ches dØcide d’interrompre le processus en cours et de dØmarrer
(ou reprendre) l’exØcution d’un autre, soit parce que le premier a ØpuisØ son temps d’allocation
du processus soit qu’il est bloquØ (en attente d’une donnØe d’un des pØriphØriques).
Le contr le de plusieurs activitØs parallŁles est un travail di cile. C’est pourquoi les concep-
teurs des systŁmes d’exploitation ont constamment, au l des ans, amØliorØ le modŁle de pa-
rallØlisme pour le rendre plus simple d’emploi.
Certains systŁmes permettent uniquement des processus non prØemptifs, ce
qui signi e que le gestionnaire des t ches n’est invoquØ que lorsqu’un processus cŁde volontai-
rement le processeur. Mais les processus d’un systŁme multi-utilisateur doivent Œtre prØemptifs.
3.3 Le gestionnaire de mØmoire
La mØmoire est une ressource importante qui doit Œtre gØrØe avec prudence. Le moindre micro-
ordinateur a, dŁs la n des annØes 1980, dix fois plus de mØmoire que l’IBM 7094, l’ordinateur
le plus puissant du dØbut des annØes soixante. Mais la taille des programmes augmente tout
aussi vite que celle des mØmoires.
La gestion de la mØmoire est du ressort du gestionnaire de mØmoire. Celui-ci doit conna tre
les parties libres et les parties occupØes de la mØmoire, allouer de la mØmoire aux processus
qui en ont besoin, rØcupØrer la mØmoire utilisØe par un processus lorsque celui-ci se termine
et traiter le va-et-vient (swapping en anglais, ou pagination) entre le disque et la mØmoire
principale lorsque cette derniŁre ne peut pas contenir tous les processus.
3.4 Le gestionnaire de chiers
Comme nous l’avons dØj dit, une des t ches fondamentales du systŁme d’exploitation est de
masquer les spØci citØs des disques et des autres pØriphØriques d’entrØe-sortie et d’o rir au
programmeur un modŁle agrØable et facile d’emploi. Ceci se fait ? travers la notion de chier.10 PremiŁre partie : Principes de conception des systŁmes d’exploitation
3.5 Le gestionnaire de pØriphØriques
Le contr le des pØriphØriques d’entrØe-sortie (E/S) de l’ordinateur est l’une des fonctions pri-
mordiales d’un systŁme d’exploitation. Ce dernier doit envoyer les commandes aux pØriphØ-
riques, intercepter les interruptions, et traiter les erreurs. Il doit aussi fournir une interface
simple et facile d’emploi entre les pØriphØriques et le reste du systŁme qui doit Œtre, dans la
mesure du possible, la mŒme pour tous les pØriphØriques, c’est- -dire indØpendante du pØri-
phØrique utilisØ. Le code des entrØes-sorties reprØsente une part importante de l’ensemble d’un
systŁme d’exploitation.
De nombreux systŁmes d’exploitation o rent un niveau d’abstraction qui permet aux utilisa-
teurs de rØaliser des entrØes-sorties sans entrer dans le dØtail du matØriel. Ce niveau d’abs-
traction fait appara tre chaque pØriphØrique comme un chier spØcial, qui permettent de
traiter les pØriphØriques d’entrØe-sortie comme des chiers. C’est le cas d’Unix. Dans ce cas,
on appelle chier rØgulier tout chier situØ en mØmoire de masse.
3.6 Le chargeur du systŁme d’exploitation
En gØnØral, de nos jours, lorsque l’ordinateur (compatible PC ou Mac) est mis sous tension, il
exØcute un logiciel appelØ BIOS (pour Basic Input Output System) placØ ? une adresse bien
dØterminØe et contenu en mØmoire RAM. Ce logiciel initialise les pØriphØriques, charge un
secteur d’un disque, et exØcute ce qui y est placØ. Lors de la conception d’un systŁme d’exploi-
tation, on place sur ce secteur le chargeur du systŁme d’exploitation ou, plus exactement, le
chargeur du chargeur du systŁme d’exploitation (ou prØ-chargeur) puisque le contenu d’un
secteur est insu sant pour le chargeur lui-mŒme.
La conception du chargeur et du prØ-chargeur est indispensable, mŒme si ceux-ci ne font pas
explicitement partie du systŁme d’exploitation.
3.7 L’interprØteur de commandes
Le systŁme d’exploitation proprement dit est le code qui permet de dØ nir les appels systŁme.
Les programmes systŁme tels que les Øditeurs de texte, les compilateurs, les assembleurs, les
Øditeurs de liens et les interprØteurs de commandes ne font pas partie du systŁme d’exploi-
tation. Cependant l’interprØteur de (shell en anglais) est souvent considØrØ
comme en faisant partie.
Sous sa forme la plus rudimentaire, l’interprØteur de commandes exØcute une boucle in nie qui
a che une invite (montrant par l que l’on attend quelque chose), lit le nom du programme
saisi par l’utilisateur ? ce moment-l et l’exØcute.
4 Structure interne d’un systŁme d’exploitation
AprŁs avoir examinØ un systŁme d’exploitation de l’extØrieur (du point de vue de l’interface
prØsentØe ? l’utilisateur et au programmeur), nous allons examiner son fonctionnement interne.Chapitre 1. Structure d’un systŁme d’exploitation 11
4.1 Les systŁmes monolithiques
Andrew Tanenbaum appelle systŁme monolithique (d’un seul bloc) un systŁme d’exploita-
tion qui est une collection de procØdures, chacune pouvant ? tout moment appeler n’importe
quelle autre procØdure, en remarquant que c’est l’organisation (plut t chaotique) la plus rØ-
pandue.
Pour construire le code objet du systŁme d’exploitation, il faut compiler toutes les procØdures,
ou les chiers qui les contiennent, puis les rØunir au moyen d’un Øditeur de liens. Dans un
systŁme monolithique, il n’y a aucun masquage de l’information : chaque procØdure est visible
de toutes les autres, par opposition aux structures constituØes de modules ou d’unitØs de pro-
grammes et dans lesquelles les informations sont locales aux modules et oø il existe des points
de passage obligØs pour accØder aux modules.
MS-DOS est un exemple d’un tel systŁme.
4.2 SystŁmes ? modes noyau et utilisateur
Dans beaucoup de systŁmes d’exploitation, il existe deux modes : le mode noyau et le mode
utilisateur. Le systŁme d’exploitation dØmarre en mode noyau, ce qui permet d’initialiser les
pØriphØriques et de mettre en place les routines de service pour les appels systŁme, et commute
ensuite en mode utilisateur. En mode utilisateur, on ne peut pas avoir accŁs directement aux
p : on doit utiliser ce qu’on appelle des appels systŁme pour avoir accŁs ? ce
qui a ØtØ prØvu par le systŁme : le noyau re oit cet appel systŁme, vØri e qu’il s’agit d’une
demande valable (en particulier du point de vue des droits d’accŁs), l’exØcute, puis renvoie
au mode utilisateur. Le mode noyau ne peut Œtre changØ que par une compilation du noyau ;
mŒme le super-utilisateur agit en mode utilisateur.
Unix et Windows (tout au moins depuis Windows 95) sont de tels systŁmes. Ceci explique
pourquoi on ne peut pas tout programmer sur un tel systŁme.
Les micro-processeurs modernes aident ? la mise en place de tels systŁmes. C’est l’origine Aide
du mode protØgØ des micro-processeurs d’Intel depuis le 80286 : il existe plusieurs niveaux
de privilŁges avec une vØri cation matØrielle, et non plus seulement logicielle, des rŁgles de
passage d’un niveau ? l’autre.
4.3 SystŁmes ? couches
Les systŁmes prØcØdents peuvent Œtre considØrØs comme des systŁmes ? deux couches et Œtre
gØnØralisØs en systŁmes ? plusieurs couches : chaque couche s’appuie sur celle qui lui est im-
mØdiatement infØrieure.
Le premier systŁme ? utiliser cette technique a ØtØ le systŁme THE dØveloppØ au Technische
Hogeschool d’Eindhoven (d’oø son nom) aux Pays-Bas par Diskstra (1968) et ses ØlŁves. Le
systŁme d’exploitation Multics, ? l’origine d’Unix, Øtait aussi un systŁme ? couches.
Le systŁme Minix de Tanenbaum, schØmatisØ sur la gure 1.2 ([TAN-87],
p.100), qui inspira Linux, est un systŁme ? quatre couches :
La couche 1, la plus basse, traite les interruptions et les dØroutements (traps en anglais) et
fournit aux couches du dessus un modŁle constituØ de processus sØquentiels indØpendants qui12 PremiŁre partie : Principes de conception des systŁmes d’exploitation
Figure 1.2 : Minix
communiquent au moyen de messages. Le code de cette couche a deux fonctions majeures :
la premiŁre est le traitement des interruptions et des dØroutements ; la deuxiŁme est liØe au
mØcanisme des messages. La partie de cette couche qui traite des interruptions est Øcrite en
langage d’assemblage ; les autres fonctions de la couche, ainsi que les couches supØrieures,
sont Øcrites en langage C.
La couche 2 contient les pilotes de pØriphØriques (device drivers en anglais), un par type
de pØriphØrique (disque, horloge, terminal...). Elle contient de plus une t che particuliŁre, la
t che systŁme.
Toutes les t ches de la couche 2 et tout le code de la couche 1 ne forment qu’un seul pro-
gramme binaire, appelØ le noyau (kernel en anglais). Les t ches de la couche 2 sont tota-
lement indØpendantes bien qu’elles fassent partie d’un mŒme programme objet : elles sont
sØlectionnØes indØpendamment les unes des autres et communiquent par envoi de messages.
Elles sont regroupØes en un seul code binaire pour faciliter l’intØgration de Minix ? des
machines ? deux modes.
La couche 3 renferme deux gestionnaires qui fournissent des services aux processus des utili-
sateurs. Le gestionnaire de mØmoire (MM pour l’anglais Memory Manager) traite tous
les appels systŁme de Minix, tels que fork(), exec() et brk(), qui concernent la gestion
de la mØmoire. Le systŁme de chiers (FS pour l’anglais File System) se charge des appels
systŁme du systŁme de chiers, tels que read(), mount() et chdir().
La couche 4 contient en n tous les processus des utilisateurs : interprØteurs de commandes,
Øditeurs de texte, compilateurs, et programmes Øcrits par les utilisateurs.
Linux s’inspirera de cette division en couches, bien qu’on n’y trouve o ciellement que deux
couches : le mode noyau et le mode utilisateur.
4.4 SystŁmes ? micro-noyau
Les systŁmes d’exploitation ? base de micro-noyau ne possŁdent que quelques fonctions, en
gØnØral quelques primitives de synchronisation, un gestionnaire des t ches simple, et un mØ-
canisme de communication entre processus. Des processus systŁme s’exØcutent au-dessus du
micro-noyau pour implØmenter les autres fonctions d’un systŁme d’exploitation, comme l’allo-
cation mØmoire, les gestionnaires de pØriphØriques, les gestionnaires d’appels systŁme, etc.
Le systŁme d’exploitation Amoeba de Tanenbaum fut l’un des premiers systŁmes ? micro-
noyau.Chapitre 1. Structure d’un systŁme d’exploitation 13
Ce type de systŁmes d’exploitation promettait beaucoup ; malheureusement ils se sont rØvØlØs
plus lents que les systŁmes monolithiques, du fait du coßt des passages de messages entre les
di Ørentes couches du systŁme d’exploitation.
Pourtant, les micro-noyaux prØsentent des avantages thØoriques sur les systŁmes monoli-
thiques. Ils nØcessitent par exemple de la part de leurs concepteurs une approche modulaire,
dans la mesure oø chaque couche du systŁme est un programme relativement indØpendant qui
doit interagir avec les autres couches via une interface logicielle propre et bien Øtablie. De plus,
un systŁme ? base de micro-noyau peut Œtre portØ assez aisØment sur d’autres architectures
dans la mesure oø toutes les composantes dØpendantes du matØriel sont en gØnØral localisØes
dans le code du micro-noyau. En n, les systŁmes ? base de micro-noyau ont tendance ? mieux
utiliser la mØmoire vive que les systŁmes monolithiques.
4.5 SystŁmes ? modules
Un module est un chier objet dont le code peut Œtre liØ au noyau (et en Œtre supprimØ)
en cours d’exØcution. Ce code objet est en gØnØral constituØ d’un ensemble de fonctions qui
implØmente un systŁme de chiers, un pilote de pØriphØrique, ou tout autre fonctionnalitØ
de haut niveau d’un systŁme d’exploitation. Le module, contrairement aux couches externes
d’un systŁme ? base de micro-noyau, ne s’exØcute pas dans un processus spØci que. Il est au
contraire exØcutØ en mode noyau au nom du processus courant, comme toute fonction liØe
statiquement dans le noyau.
La notion de module reprØsente une fonctionnalitØ du noyau qui o re bon nombre des avan- IntØrŒt
tages thØoriques d’un micro-noyau sans pØnaliser les performances. Parmi les avantages des
modules, citons :
Une approche modulaire : puisque chaque module peut Œtre liØ et dØliØ en cours d’exØcution
du systŁme, les programmeurs ont dß introduire des interfaces logicielles trŁs claires permet-
tant d’accØder aux structures de donnØes gØrØes par les modules. Cela rend le dØveloppement
de nouveaux modules plus simple.
IndØpendance vis- -vis de la plateforme : mŒme s’il doit se baser sur des caractØristiques bien
dØ nies du matØriel, un module ne dØpend pas d’une plateforme particuliŁre. Ainsi, un pilote
de disque basØ sur le standard SCSI fonctionne aussi bien sur un ordinateur compatible IBM
que sur un Alpha.
Utilisation Øconomique de la mØmoire : un module peut Œtre insØrØ dans le noyau lorsque les
fonctionnalitØs qu’il apporte sont requises et en Œtre supprimØ lorsqu’elles ne le sont plus.
De plus, ce mØcanisme peut Œtre rendu transparent ? l’utilisateur puisqu’il peut Œtre rØalisØ
automatiquement par le noyau.
Aucune perte de performances : une fois insØrØ dans le noyau, le code d’un module est Øqui-
valent au code liØ statiquement au noyau. De ce fait, aucun passage de message n’est nØ-
cessaire lorsque les fonctions du module sont invoquØes. Bien entendu, une petite perte de
performance est causØe par le chargement et la suppression des modules. Cependant, cette
perte est comparable ? celle dont sont responsables la crØation et la destruction du processus
d’un systŁme ? base de micro-noyau.14 PremiŁre partie : Principes de conception des systŁmes d’exploitation
5 Mise en uvre
5.1 Les appels systŁme
L’interface entre le systŁme d’exploitation et les programmes de l’utilisateur est constituØe
d’un ensemble d’ instructions Øtendues fournies par le systŁme d’exploitation, quali Øes
d’appels systŁme.
Les appels crØent, dØtruisent et utilisent divers objets logiciels gØrØs par le systŁme
d’exploitation, dont les plus importants sont les processus et les chiers.
5.2 Les signaux
Les processus s’exØcutant indØpendamment les uns des autres, il s’agit de pseudo-parallØlisme.
Il faut cependant quelquefois fournir de l’information ? un processus. Comment le systŁme
d’exploitation procŁde-t-il ? On a imaginØ une mØthode analogue ? celle des interruptions logi-
cielles pour les micro-processeurs, appelØe signal.
ConsidØrons, par exemple, le cas de l’envoi d’un message. Pour empŒcher la perte des mes-
sages, on convient que le rØcepteur envoie lui-mŒme un acquittement dŁs qu’il re oit une par-
tie du message (d’une taille dØterminØe) ; on envoie ? nouveau cette partie si l’acquittement
ne parvient pas dans un temps dØterminØ. Pour mettre en place un tel envoi, on utilisera un
processus : il envoie une partie du message, demande ? son systŁme d’exploitation de l’avertir
lorsqu’un certain temps est ØcoulØ, il vØri e alors qu’il a re u l’acquittement du message et
sinon l’envoie ? nouveau.
Lorsque le systŁme d’exploitation envoie un signal ? un processus, ce signal provoque la sus-
pension temporaire du travail en cours, la sauvegarde des registres dans la pile et l’exØcution
d’une procØdure particuliŁre de traitement du signal re u. ? la n de la procØdure de traite-
ment du signal, le processus est redØmarrØ dans l’Øtat oø il se trouvait juste avant la rØception
du signal.
Conclusion
Nous venons de rappeler les trois fonctions principales d’un systŁme d’exploitation, ses carac-
tØristiques, sa structure externe, sa structure interne, et la fa on de le mettre en uvre. Les
trois notions essentielles y sont les processus, les chiers, et les appels systŁme. C’est ? celles-
ci qu’on doit s’attacher pour bien comprendre la suite. Nous allons aborder dans le chapitre
suivant la fa on dont le micro-processeur communique avec l’extØrieur et ses incidences sur les
systŁmes d’exploitation, avant d’aborder le systŁme Linux ? proprement parler.Chapitre 2
Principe de traitement des
entrØes-sorties
Nous allons prØsenter dans ce chapitre le principe des entrØes-sorties ? la fois du point de vue
matØriel et du point de vue logiciel, ce dernier aspect nous intØressant plus particuliŁrement.
1 Principe du matØriel d’entrØe-sortie
On peut considØrer le matØriel qui permet les entrØes-sorties de diverses maniŁres. Les ingØ-
nieurs en ØlectricitØ y voient des circuits intØgrØs, des circuits Ølectriques, des moteurs et des
composants physiques. Les programmeurs sont plus sensibles ? l’interface que le matØriel o re
? leurs programmes : les commandes qu’il accepte, les fonctions qu’il exØcute, et les erreurs
qu’il signale. On s’attache, lorsqu’on s’occupe de la conception d’un systŁme d’exploitation, ?
la programmation du matØriel et non ? sa conception, construction, ou entretien. Nous exami-
nerons donc la programmation du matØriel et non son fonctionnement interne. NØanmoins, ces
deux aspects sont souvent intimement liØs. C’est pourquoi nous prØsentons dans le paragraphe
suivant quelques aspects du matØriel concernant les entrØes-sorties qui in uent directement sur
sa programmation.
1.1 Les pØriphØriques d’entrØe-sortie
Les pØriphØriques d’entrØe-sortie se rØpartissent, du point de vue matØriel, en deux grandes
catØgories : les pØriphØriques bloc et les pØriphØriques caractŁre :
PØriphØrique bloc. Un pØriphØrique bloc mØmorise les informations dans des blocs de
taille xe, chaque bloc ayant une adresse propre. La propriØtØ fondamentale de ces pØ-
riphØriques est qu’ils permettent de lire ou d’Øcrire un bloc indØpendamment de tous les
autres. Les disques sont des pØriphØriques bloc.
La frontiŁre entre les pØriphØriques bloc et les autres n’est pas toujours bien dØ nie. Tout
le monde s’accorde ? dire qu’un disque est un pØriphØrique bloc car on peut toujours
accØder ? un autre cylindre et atteindre le bloc requis quelle que soit la position initiale
du bras. ConsidØrons ? prØsent une bande magnØtique qui contient des blocs de 1 Ko. Si
l’on souhaite lire le bloc N, le dØrouleur peut rembobiner la bande et se positionner sur
ce bloc N. Cette opØration est analogue ? une recherche sur un disque mais le temps mis
est beaucoup plus long. De plus, on ne peut pas toujours rØØcrire un bloc au milieu d’une
bande. Les bandes magnØtiques peuvent donc Œtre utilisØes comme des pØriphØriques bloc,
mais c’est un cas extrŒme : elles ne sont normalement pas utilisØes de cette maniŁre.16 PremiŁre partie : Principes de conception des systŁmes d’exploitation
PØriphØrique caractŁre. Le deuxiŁme type de pØriphØrique d’entrØe-sortie, du point de vue
matØriel, est le pØriphØrique caractŁre. Un tel pØriphØrique accepte un ot de carac-
tŁres sans se soucier d’une quelconque structure en blocs. On ne peut pas y accØder gr ce
? un index et il ne possŁde pas de fonction de recherche. Les terminaux, les imprimantes,
les bandes de papier, les cartes perforØes, les interfaces rØseau, les souris et la plupart des
pØriphØriques qui ne se comportent pas comme des disques peuvent Œtre considØrØs comme
des p caractŁre.
Cette classi cation n’est pas parfaite. Quelques pØriphØriques n’appartiennent ? aucune de ces
deux catØgories. Les horloges ne possŁdent pas de blocs et n’acceptent pas non plus de ux
de caractŁres. Elles ne font que gØnØrer des interruptions ? intervalles rØguliers. Le modŁle
des pØriphØriques bloc et caractŁre est quand mŒme assez gØnØral et peut servir de base pour
rendre une partie du logiciel de traitement des interruptions indØpendante des pØriphØriques.
1.2 Les contr leurs de pØriphØriques
Notion de contr leur
Les unitØs d’entrØe-sortie sont constituØes de composants mØcaniques et de composants Ølec-
troniques. On peut souvent dissocier ces deux types de composants pour avoir une vue plus
modulaire et plus gØnØrale. Les composants Ølectroniques sont appelØs contr leurs de pØri-
phØriques ou adaptateurs.
Cette distinction entre le contr leur et le pØriphØrique proprement dit est importante pour le
systŁme d’exploitation car celui-ci communique pratiquement toujours avec le contr leur, et
non avec le pØriphØrique.
Un contr leur pour plusieurs pØriphØriques
La carte d’un contr leur possŁde en gØnØral un connecteur qui permet de la relier ? la partie
mØcanique du pØriphØrique. De nombreux contr leurs acceptent deux, quatre ou huit pØriphØ-
riques identiques. Si l’interface entre le contr leur et le pØriphØrique est normalisØe (interface
ANSI, IEEE ou ISO) ou largement rØpandue (standard de fait), les fabricants de contr leurs
et de pØriphØriques peuvent s’y conformer. De nombreuses rmes fabriquent, par exemple, des
disques qui acceptent le contr leur de disques d’IBM.
Interface entre contr leur et pØriphØrique
L’interface entre le contr leur et le pØriphØrique est souvent de trŁs bas niveau.
Un disque dur peut, par exemple, Œtre formatØ en pistes de 8 secteurs de 512 octets. Un secteur
est, physiquement, une sØrie de bits constituØs d’un prØambule, de 4096 bits de donnØes et
d’octets constituant un code correcteur d’erreur (en anglais error-correcting code ou ECC).
Le prØambule est Øcrit lors du formatage du disque et contient les numØros de cylindre et de
secteur, la taille des secteurs et d’autres donnØes de ce type. Le travail du contr leur est de
regrouper ce ot de bits en sØrie dans un bloc d’octets en corrigeant les erreurs si nØcessaire.
Le bloc d’octets est constituØ, bit aprŁs bit, dans un tampon du contr leur. Puis, si aucune
erreur n’est dØtectØe, et aprŁs vØri cation du code correcteur d’erreur, il est copiØ en mØmoire
vive.Chapitre 2. Principe de traitement des entrØes-sorties 17
Interface entre contr leur et micro-processeur
Chaque contr leur communique avec le processeur par l’intermØdiaire de quelques cellules mØ-
moire situØes sur le contr leur, appelØes registres du contr leur.
Le micro-processeur accŁde ? ces registres de l’une des deux fa ons suivantes :
Sur certains processeurs, les registres des contr leurs sont accessibles via l’espace mØmoire
adressable. Cette con guration est appelØe entrØes-sorties mappØes en mØmoire. Le
micro-processeur 680x0, par exemple, utilise cette mØthode.
D’autres processeurs utilisent un espace mØmoire particulier pour les entrØes-sorties et al-
louent ? chaque contr leur une partie de cet espace. On parle d’entrØe-sortie par port. C’est
le cas du micro-processeur 80x86.
L’a ectation des adresses d’entrØe-sortie aux pØriphØriques, qu’il s’agisse d’adresses de la mØ-
moire vive ou de ports, s’e ectue matØriellement lors du c blage.
Programmation des contr leurs
Nous avons dØj vu que, par exemple, le contr leur des disques durs IDE accepte un certain
nombre de commandes et que de nombreuses commandes ont des paramŁtres. De fa on gØnØ-
rale, le pilotage s’e ectue en trois phases :
Passage des commandes. On passe les commandes et les paramŁtres au contr leur via les
registres du contr leur.
ExØcution. DŁs qu’une commande est acceptØe, le micro-processeur peut e ectuer un autre
travail, le contr leur s’acquittant seul de la commande.
Phase des rØsultats. Lorsque la commande est exØcutØe, le contr leur envoie une inter-
ruption matØrielle pour permettre au systŁme d’exploitation de rØquisitionner le micro-
processeur a n de tester les rØsultats de l’opØration. Le micro-processeur obtient ces rØ-
sultats ainsi que l’Øtat du pØriphØrique en lisant un ou plusieurs octets via les registres du
contr leur.
1.3 Transferts synchrones et asynchrones
La distinction entre les transferts synchrones (bloquants) et les transferts asynchrones (gØrØs
par interruption) est importante :
Transfert asynchrone. La plupart des entrØes-sorties physiques sont asynchrones : le pro-
cessus dØmarre une t che et e ectue un autre travail en attendant l’arrivØe d’une inter-
ruption matØrielle.
Transfert synchrone. Cependant, les programmes des utilisateurs sont bien plus simples ?
Øcrire si les opØrations d’entrØe-sortie sont bloquantes : le programme est automatique-
ment suspendu aprŁs une opØration de lecture jusqu’ ce que les donnØes arrivent dans le
tampon.
Le systŁme d’exploitation doit quelquefois donner aux programmes des utilisateurs l’impres-
sion que les opØrations (qui sont en fait gØrØes par interruption) sont bloquantes.18 PremiŁre partie : Principes de conception des systŁmes d’exploitation
1.4 PØriphØriques partagØs et dØdiØs
On peut distinguer deux types de pØriphØriques suivant qu’ils peuvent Œtre utilisØs par plu-
sieurs utilisateurs simultanØment ou non :
PØriphØrique partagØ. De nombreux pØriphØriques, comme les disques, peuvent Œtre utilisØs
simultanØment par plusieurs utilisateurs. Plusieurs chiers appartenant ? des utilisateurs
di Ørents peuvent, par exemple, Œtre ouverts sur un disque au mŒme moment. On parle
alors de pØriphØriques partagØs.
PØriphØrique dØdiØ. D’autres pØriphØriques, comme les imprimantes, ne peuvent Œtre utili-
sØs que par un seul utilisateur jusqu’ ce qu’il termine son travail. Cinq utilisateurs ne
peuvent pas imprimer leurs chiers en mŒme temps. On parle alors de pØriphØriques
dØdiØs.
Les pØriphØriques dØdiØs conduisent ? de nombreux problŁmes comme les interblocages. Le
systŁme d’exploitation doit prendre en compte la nature des pØriphØriques, dØdiØe ou partagØe,
pour Øviter les con its.
2 Principe des logiciels d’entrØe-sortie
Regardons la structure des logiciels concernant les entrØes-sorties. Leurs objectifs principaux
sont faciles ? cerner. L’idØe directrice est de dØcomposer ces logiciels en une sØrie de couches,
les plus basses se chargeant de masquer les particularitØs du matØriel aux yeux des couches les
plus ØlevØes. Ces derniŁres o rent aux utilisateurs une interface agrØable, bien dØ nie et facile
d’emploi. PrØsentons ces objectifs et la maniŁre de les atteindre.
2.1 Objectifs des logiciels des entrØes-sorties
Les objectifs des logiciels concernant les entrØes-sorties sont l’indØpendance vis- -vis du matØ-
riel, l’uniformisation des noms et la gestion des erreurs :
IndØpendance vis- -vis du matØriel. Un point clØ de la philosophie de la conception des
logiciels concernant les entrØes-sorties est l’indØpendance vis- -vis du matØriel. L’uti-
lisateur doit pouvoir Øcrire des programmes qui s’exØcutent sans aucune modi cation, que
ses chiers se trouvent sur une disquette ou sur un disque dur. Il faudrait mŒme pouvoir
dØplacer les programmes sans avoir ? les recompiler. Un commande comme :
# sort < entree > sortie
doit pouvoir Œtre exØcutØe correctement, indØpendamment des entrØes-sorties qui peuvent
se faire sur une disquette, un disque dur, ou mŒme un terminal. C’est au systŁme d’ex-
ploitation de rØsoudre les problŁmes engendrØs par les di Ørences qui existent entre ces
pØriphØriques, chacun nØcessitant un pilote spØci que.
Uniformisation des noms. L’objectif d’uniformisation des noms est en relation Øtroite
avec celui d’indØpendance vis- -vis du matØriel. Le nom d’un chier ou d’un pØriphØrique
doit Œtre une cha ne de caractŁres ou un entier qui ne dØpend absolument pas du pØri-
phØrique. Sous Unix, tous les disques peuvent Œtre montØs ? n’importe quel niveau de
la hiØrarchie du systŁme de chiers. L’utilisateur n’a pas ? se soucier de la correspon-
dance entre les noms et les pØriphØriques. Par exemple, un lecteur de disquettes peutChapitre 2. Principe de traitement des entrØes-sorties 19
Œtre montØ sur /usr/ast/sauvegarde de sorte que la copie d’un chier dans /usr/ast/
sauvegarde/lundi copie le chier sur la disquette. Tous les chiers et les pØriphØriques
sont ainsi dØsignØs de la mŒme maniŁre : par un chemin d’accŁs.
Gestion des erreurs. La gestion des erreurs est une autre caractØristique importante du lo-
giciel des entrØes-sorties. D’une maniŁre gØnØrale, ces erreurs doivent Œtre traitØes ? un
niveau aussi proche que possible du matØriel. Un contr leur qui constate une erreur au
cours d’une lecture doit essayer de la corriger par lui-mŒme. S’il ne peut pas le faire, le
pilote du pØriphØrique doit essayer de la ? son tour, ne serait-ce tout simplement
qu’en demandant la relecture du bloc : de nombreuses erreurs sont passagŁres, comme les
erreurs de lecture provoquØes par de la poussiŁre qui s’est dØposØe sur la tŒte de lecture ;
elles dispara tront ? la tentative suivante. Les couches ØlevØes ne doivent Œtre prØvenues
que si les plus basses n’arrivent pas ? rØsoudre le problŁme. La plupart du temps, la cor-
rection des erreurs peut Œtre traitØe de maniŁre transparente par les couches basses.
2.2 Les pilotes de pØriphØriques
Le code qui dØpend des p est reportØ dans ce qu’on appelle les pilotes de pØri-
phØriques (device drivers en anglais). Chaque pilote de pØriphØrique traite un type de pØri- ou des pØriphØriques trŁs proches.
On a, par exemple, un seul pilote de pØriphØrique pour tous les disques durs IDE. Il serait,
par ailleurs, souhaitable de n’avoir qu’un seul pilote pour tous les terminaux connectØs au
systŁme. Malheureusement, un terminal ØlØmentaire et un terminal graphique intelligent dotØ
d’une souris di Łrent trop et ne peuvent pas avoir un seul et mŒme pilote.
Nous avons vu plus haut que chaque contr leur possŁde un ou plusieurs registres de com-
mandes. Les pilotes de pØriphØriques envoient ces commandes et vØri ent leur bon achemi-
nement. Le pilote de disque, par exemple, doit Œtre la seule partie du systŁme d’exploitation
qui connaisse les registres d’un contr leur de disque donnØ et leur utilisation. Il est le seul ?
conna tre les secteurs, les pistes, les cylindres, les tŒtes, le dØplacement du bras, le facteur d’en-
trelacement, les moteurs, le temps de positionnement des tŒtes et tous les autres mØcanismes
qui permettent le bon fonctionnement du disque. D’une maniŁre gØnØrale, un pilote de pØri-
phØriques doit traiter les requŒtes de plus haut niveau qui Ømanent du logiciel (indØpendant
du matØriel) situØ au-dessus de lui.
2.3 Logiciel d’entrØe-sortie indØpendant du matØriel
Une petite partie seulement du logiciel des entrØes-sorties dØpend du matØriel. La frontiŁre
exacte entre les pilotes de pØriphØriques et le logiciel indØpendant du matØriel varie en fonction
du systŁme utilisØ. En e et, certaines fonctions qui pourraient Œtre implØmentØes de maniŁre
indØpendante du matØriel sont parfois rØalisØes dans les pilotes pour une question d’e cacitØ.
Les fonctions prØsentØes ci-dessous devraient Œtre rØalisØes par la partie du logiciel qui ne dØ-
pend pas du matØriel :
adressage des pØriphØriques par leurs noms ;
protection des p ;
tailles de bloc indØpendante du pØriphØrique ;
fourniture de tampons ;20 PremiŁre partie : Principes de conception des systŁmes d’exploitation
allocation de l’espace de sauvegarde pour les pØriphØriques bloc ;
allocation et libØration des pØriphØriques dØdiØs ;
signalisation des erreurs.
La fonction principale du logiciel indØpendant du matØriel est d’e ectuer les fonctions d’entrØe-
sortie communes ? tous les pØriphØriques et de fournir une interface uniforme au logiciel des
utilisateurs :
DØsignation. La dØsignation des objets tels que les chiers et les pØriphØriques d’entrØe-
sortie est un point important dans un systŁme d’exploitation. Le logiciel indØpendant du
matØriel crØe un lien entre les noms symboliques des pØriphØriques et les pØriphØriques
eux-mŒmes. Le nom d’un pØriphØrique Unix, comme /dev/tty0, dØsigne d’une maniŁre
unique le n ud d’information d’un chier spØcial. Ce n ud d’information contient le nu-
mØro de pØriphØrique majeur qui permet de localiser le pilote de pØriphØrique correspon-
dant. Il contient aussi le numØro de pØriphØrique mineur qui est passØ en paramŁtre au
pilote de pØriphØrique pour spØci er l’unitØ oø il faut lire et Øcrire.
Protection. La protection dØpend Øtroitement de la maniŁre dont les objets sont nommØs.
Comment le systŁme empŒche-t-il les utilisateurs d’accØder ? des pØriphØriques pour les-
quels ils n’ont pas d’autorisation d’accŁs ? Dans un systŁme tel que MS-DOS, il n’y a
aucune protection. Chaque processus peut faire ce que bon lui semble. Dans les systŁmes
d’exploitation pour gros ordinateurs, l’accŁs direct aux pØriphØriques d’entrØe-sortie est
strictement interdit aux processus des utilisateurs. Unix adopte une approche moins ri-
gide : les chiers spØciaux des pØriphØriques des entrØes-sorties sont protØgØs par les bits
rwx habituels ; l’administrateur du systŁme peut alors Øtablir les protections particuliŁres
? chaque pØriphØrique.
Taille de bloc. La taille des secteurs peut varier d’un disque ? un autre. Le logiciel indØpen-
dant du matØriel doit masquer ces di Ørences et fournir aux couches supØrieures une taille
de bloc unique en traitant, par exemple, plusieurs secteurs comme un seul bloc logique.
De cette fa on, les couches supØrieures ne voient que des pØriphØriques abstraits qui ont
tous la mŒme taille de bloc logique, indØpendante de la taille des secteurs du disque. De
mŒme, la taille des donnØes fournies par certains pØriphØriques caractŁre est d’un octet
(par exemple les lecteurs de bandes), alors qu’elle est supØrieure pour d’autres pØriphØ-
riques (par exemple les lecteurs de cartes). Ces di Ørences doivent aussi Œtre masquØes.
Tampons. L’utilisation de tampons pour les pØriphØriques bloc et caractŁre est un autre
point important. Le matØriel, dans le cas des p bloc, impose la lecture ou
l’Øcriture de blocs entiers, alors que les processus des utilisateurs peuvent lire ou Øcrire
un nombre quelconque d’octets. Si le processus d’un utilisateur Øcrit la moitiØ d’un bloc,
le systŁme d’exploitation mØmorise les donnØes jusqu’ ce que le reste du bloc soit Øcrit,
puis il transfŁre tout le bloc sur le disque. Les pØriphØriques caractŁre doivent aussi avoir
des tampons, car les utilisateurs peuvent envoyer des donnØes au systŁme plus vite qu’il
ne peut les traiter. Par exemple, les caractŁres entrØs au clavier peuvent Œtre tapØs plus
t t que prØvu et doivent de ce fait Œtre placØs dans un tampon.
Espace de sauvegarde. Il faut allouer aux nouveaux chiers des blocs sur le disque. Le sys-
tŁme a donc besoin d’une liste des blocs libres de chaque disque. L’algorithme de recherche
d’un bloc libre est indØpendant du pØriphØrique et peut Œtre implantØ dans une couche au-
dessus du pilote.Chapitre 2. Principe de traitement des entrØes-sorties 21
Allocation et libØration des pØriphØriques. Quelques pØriphØriques ne peuvent Œtre uti-
lisØs que par un seul processus ? la fois : c’est le cas des dØrouleurs de bandes magnØ-
tiques. Le systŁme d’exploitation doit donc examiner les requŒtes qui concernent ces pØ-
riphØriques avant de les accepter (ou de les mettre en attente si le pØriphØrique demandØ
n’est pas disponible). Pour e ectuer ce contr le, on peut obliger les processus ? e ectuer
une demande d’ouverture sur les chiers spØciaux des pØriphØriques. Si le pØriphØrique
demandØ n’est pas libre, cet appel systŁme Øchoue. La fermeture d’un chier spØcial libŁre
le pØriphØrique correspondant.
Traitement des erreurs. Le traitement des erreurs est pratiquement entiŁrement reportØ
dans les pilotes. La plupart des erreurs dØpendent Øtroitement du pØriphØrique utilisØ et,
de ce fait, seul le pilote sait les traiter (soit en e ectuant une nouvelle tentative, soit en
les ignorant, soit en signalant une erreur). S’il se produit, par exemple, une erreur lors de
la lecture d’un bloc endommagØ, le pilote essaie de lire ce bloc un certain nombre de fois.
S’il n’y arrive pas, il abandonne et signale l’erreur au logiciel indØpendant du matØriel. Si
l’erreur appara t au cours de la lecture du chier d’un utilisateur, il su t de le signaler
? l’appelant. Si, en revanche, elle se produit pendant la lecture de donnØes critiques pour
le systŁme, telles que la liste des blocs libres du disque, le systŁme d’exploitation est
contraint d’a cher un message d’erreur et de s’arrŒter.
2.4 Logiciels d’entrØe-sortie faisant partie de l’espace de l’utilisateur
Bien que la majeure partie du logiciel des entrØes-sorties fasse partie du systŁme d’exploitation,
une faible partie se dØroule au niveau des utilisateurs :
Appel systŁme et fonction de bibliothŁque. Les appels systŁme, et notamment ceux re-
latifs aux entrØes-sorties, sont habituellement e ectuØs par des procØdures de bibliothŁque.
Par exemple si un programme C contient l’instruction :
octets_lus = write(descripteur_fich, tampon, nombre_octets);
la procØdure de bibliothŁque write() ne fait que placer les paramŁtres de l’appel systŁme
? certaines adresses. D’autres procØdures e ectuent un travail plus complet. En parti-
culier, le formatage des donnØes en entrØe et en sortie est e ectuØ par des procØdures de
bibliothŁque. Par exemple printf(), en langage C, prend en paramŁtre une cha ne de for-
mat et quelques variables, construit une cha ne de caractŁres ASCII et appelle write()
pour a cher cette cha ne.
DØmons. Tout le logiciel des entrØes-sorties au niveau des utilisateurs n’est pas constituØ de
procØdures de bibliothŁque. Le systŁme de spoule (en anglais spool), par exemple, n’en
fait pas partie. Le spoule permet de traiter les pØriphØriques d’entrØe-sortie dØdiØs dans
un systŁme multi-programmØ. ConsidØrons un pØriphØrique type qui utilise le spoule :
l’imprimante. Lorsqu’un processus e ectue une opØration d’ouverture sur le chier spØcial
dete, il peut ne rien imprimer pendant des heures. Il bloque ainsi tous les
autres processus, qui ne peuvent plus imprimer.
On crØe donc un processus particulier, appelØ dØmon (en anglais daemon), et un rØ-
pertoire spØcial, le rØpertoire de spoule. Pour imprimer un chier, un processus doit
d’abord crØer le chier ? imprimer, puis le placer dans le rØpertoire de spoule. Le dØmon,
qui est le seul processus autorisØ ? accØder au chier spØcial de l’imprimante, imprime les22 PremiŁre partie : Principes de conception des systŁmes d’exploitation
chiers de ce rØpertoire. On empŒche ainsi les utilisateurs de monopoliser l’imprimante en
gardant son chier spØcial ouvert trop longtemps.
Le spoule n’est pas utilisØ que pour l’imprimante. Le transfert de chiers sur un rØseau
utilise souvent un dØmon de rØseau. Pour envoyer un chier, il faut commencer par le
mettre dans le rØpertoire de spoule du rØseau. Le dØmon le cherche dans ce rØpertoire et
le transmet plus tard.
Conclusion
D’un point de vue matØriel, le micro-processeur, piŁce essentielle d’un ordinateur, communique
avec l’extØrieur gr ce ? un grand nombre d’autres puces Ølectroniques, qui lui sont reliØes
sur la carte mŁre ou sur les cartes adaptatrices. Les systŁmes d’exploitation modØlisent les
enchevrŒtements de ces nombreuses cartes sous la forme de pØriphØriques . Ils rØpartissent
ces derniers en deux types : caractŁre et bloc. Il faut concevoir des pilotes de pØriphØriques
pour chacun d’entre eux. Nous en verrons deux exemples dØtaillØs au chapitre 18, consacrØ au
disque dur, et au chapitre 23, consacrØ au clavier. Avant cela, il faut Øtudier la maniŁre dont
le systŁme d’exploitation gŁre un certain nombre d’actions internes, non visibles directement ?
l’extØrieur.Chapitre 3
Le systŁme Linux ØtudiØ
La plupart des articles et des livres consacrØs au noyau Linux prennent toujours en exemple la
derniŁre version disponible au moment oø ils sont Øcrits, qui n’est dØj plus la derniŁre version
au moment oø ils paraissent. De plus, comme le source est alors d’une taille trŁs importante,
une seule partie de celui-ci est ØtudiØe. Je ne pense pas que ce soit une bonne idØe. Si nous
voulons vraiment comprendre la structure d’un systŁme d’exploitation, nous avons intØrŒt ?
considØrer le systŁme le plus simple possible et ? l’Øtudier en entier. C’est pourquoi j’ai choisi
la toute premiŁre version du noyau Linux : le noyau 0.01. Je donnerai cependant quelques
indications sur l’Øvolution du noyau, mais ce n’est pas le but essentiel.
1 Le systŁme Linux ? Øtudier
1.1 Noyau et distribution
Le systŁme d’exploitation Linux est un gros logiciel et, comme tel, di cile ? apprØhender par
une seule personne. Mais, en fait, il faut distinguer plusieurs niveaux.
Ce que l’on entend par Linux, le plus souvent, concerne une distribution, telle que Red Hat,
Suse, Mandrake, Debian... Une distribution comprend le systŁme d’exploitation proprement
dit, plus exactement le noyau, les utilitaires traditionnellement associØs ? Unix (un Øditeur de
1texte, un compilateur C...), l’interface graphique X Window System et beaucoup de logiciels
utilisateur.
Notre but, dans ce livre, est uniquement d’Øtudier le noyau Linux.
1.2 Noyau minimal
MŒme pour le seul noyau, les sources ont une taille non nØgligeable : 58 Mo pour la version
2.2.18, par exemple. Ceci s’explique, en particulier, par le grand nombre de pØriphØriques pris
en compte. Il est Øvidemment inutile de s’occuper de tous les pØriphØriques et de tous les types
de tels pØriphØriques du point de vue pØdagogique. Nous Øtudierons donc un noyau minimal,
ne mettant pas nØcessairement toutes les activitØs en application et ne contenant que quelques
pØriphØriques ? titre d’exemple.
Linux 0.01Le noyau Linux 0.01 est intØressant du point de vue pØdagogique. Il ne concerne que le micro-
processeur Intel 80386 (et ses successeurs), il ne prend en compte qu’un nombre trŁs limitØ de
1On utilise souvent, ? tort, le terme X Window. Le consortium X, auteur du programme, recommande plut t
d’employer les termes X ou X Window System pour Øvoquer ce produit.24 PremiŁre partie : Principes de conception des systŁmes d’exploitation
pØriphØriques, qu’un seul systŁme de chiers et qu’un seul type d’exØcutables, mais ces dØfauts
pour l’utilisateur deviennent un avantage lorsqu’on veut Øtudier les sources en entier.
1.3 Obtention des sources
L’ensemble des sources des noyaux de Linux, depuis le tout premier jusqu’au dernier, se trouve
sur le site : http://ftp.cdut.edu.cn/pub/linux/kernel/history/
Nous Øtudierons, dans une premiŁre Øtape, les sources du tout premier noyau, nettement moins
Linux 0.01 imposant et contenant Øvidemment l’essentiel. Les sources du noyau 0.01 se trouvent Øgale-
ment ? l’adresse suivante : http://www.kernel.org/pub/linux/kernel/Historic/
1.4 Programmation Linux
L’obtention du noyau Linux et la comprØhension des chiers source nous entra nent ? faire un
dØtour par la programmation sous Linux.
A priori, nous ne devrions rien ? avoir ? dire sur la programmation. Que ce soit Linux ou un
autre systŁme d’exploitation, nous devrions avoir des sources portables. En fait, ce n’est pas
le cas pour des raisons historiques dues ? certains choix initiaux de Linus Torvalds, jamais
remis en cause ensuite.
Les sources reposent sur des chiers make (un outil pour gØrer les grands logiciels rØpartis
sur de nombreux chiers), sur des chiers en langage C non standard (il s’agit du langage
C de GCC avec quelques utilisations de particularitØs de ce compilateur), sur des chiers en
langage d’assemblage, pour Intel 80386 pour ce qui nous concerne et, en n, sur des scripts
bash modi Øs. La syntaxe du langage d’assemblage ne suit pas celle de l’assembleur MASM de
Microsoft (qui fut longtemps la rØfØrence) mais celle de gas dans un style dit ATT.
1.5 Versions du noyau Linux
Linux distingue les noyaux stables des noyaux en dØveloppement avec un systŁme de numØro-
tation simple. Chaque version est caractØrisØe par trois nombres entiers sØparØs par des points.
Les deux premiers identi ent la version, le troisiŁme la parution (release en anglais).
Un second numØro pair identi e un noyau stable ; impair, il dØnote un noyau de dØveloppe-
ment. Les nouvelles parutions d’une version stable visent essentiellement ? corriger des erreurs
signalØes par les utilisateurs ; les algorithmes principaux et les structures de donnØes du noyau
ne sont pas modi Øs.
Les versions de dØveloppement, en revanche, peuvent di Ører les unes des autres de fa on
importante. Les dØveloppeurs du noyau sont libres d’expØrimenter di Ørentes solutions qui
peuvent Øventuellement conduire ? des changements drastiques du noyau.
La notation de la version 0.01 ne suit pas le principe de la numØrotation dØcrit ci-dessus avec
trois nombres entiers sØparØs par des points. Linus Torvalds voulant seulement indiquer que
nous sommes trŁs loin d’une version stable, qui porterait le numØro 1.0, il a choisi le numØro
0.01 pour laisser de la place pour encore d’autres versions intermØdiaires.Chapitre 3. Le systŁme Linux ØtudiØ 25
2 Les sources du noyau 0.01
2.1 Vue d’ensemble sur l’arborescence
Les sources du noyau 0.01 occupent 230 Ko, comportent 11 dossiers et 88 chiers.
Le premier niveau de l’arborescence du source est simple :
/boot Linux 0.01
/fs
/include
/init
/kernel
/lib
/mm
/tools
Elle s’inspire de l’arborescence du source de Minix ([TAN-87], p. 104). Nous avons vu que les
systŁmes d’exploitation se composent de quatre parties principales : le gestionnaire des proces-
sus, le gestionnaire de la mØmoire, le gestionnaire des chiers et le des pØriphØ-
riques d’entrØe-sortie. Le rØpertoirekernel correspond aux couches 1 et 2 de Minix (processus
et pØriphØriques d’entrØe-sortie). Les procØdures des bibliothŁques standard C utilisØes par le
noyau (open(), read(),...) se trouvent dans le rØpertoire lib (pour LIBrary). Les rØpertoires
mm (pour Memory Management) et fs (pour File System) comportent le code du gestionnaire
de mØmoire et du gestionnaire de chiers.
Le rØpertoire include contient les chiers d’en-tŒtes nØcessaires au systŁme Linux. Il sert ? la
constitution du noyau, mais Øgalement ? la programmation Linux une fois le noyau constituØ.
Les trois derniers rØpertoires contiennent les outils de mise en place : le rØpertoire boot per-
met de dØmarrer le systŁme ; le rØpertoire init d’initialiser le systŁme (il ne contient que la
fonction principale main()) ; le rØp tools permet de construire le noyau.
2.2 L’arborescence dØtaillØe
Le rØpertoire boot
Pour le noyau 0.01, ce rØpertoire ne contient que deux chiers en langage d’assemblage :
boot.s et head.s. Voici les fonctions des ces deux chiers :
boot.s contient le code du secteur d’amor age de la disquette ? partir de laquelle on dØ-
marre Linux, de l’initialisation des pØriphØriques de l’ordinateur, de la con guration de l’en-
vironnement pour pouvoir passer en mode protØgØ des micro-processeurs Intel et, en n, du
passage au mode protØgØ ;
il donne ensuite la main au code startup_32() contenu dans le chier suivant :
Linux 0.01| boot.s
|
| boot.s is loaded at 0x7c00 by the bios-startup routines, and moves itself
| out of the way to address 0x90000, and jumps there.
|
| It then loads the system at 0x10000, using BIOS interrupts. Thereafter
| it disables all interrupts, moves the system down to 0x0000, changes
| to protected mode, and calls the start of system. System then must
| RE-initialize the protected mode in its own tables, and enable
| interrupts as needed.26 PremiŁre partie : Principes de conception des systŁmes d’exploitation
head.s permet de con gurer l’environnement d’exØcution pour le premier processus Linux
(processus 0) puis de passer ? la fonction start_kernel(), qui est la fonction principale du
code C :
Linux 0.01 /*
* head.s contains the 32-bit startup code.
*
* NOTE!!! Startup happens at absolute address 0x00000000, which is also
* where the page directory will exist. The startup code will be
* overwritten by the page directory.
*/
Le rØpertoire init
Le rØpertoire init contient un seul chier : le chier main.c qui, comme son nom l’indique,
contient la fonction principale du code C. Cette fonction initialise les pØriphØriques (en mode
protØgØ) puis fait appel au processus 1.
Le rØpertoire include
Le rØpertoire est Øvidemment le rØpertoire par dØfaut des chiers d’en-tŒtes C qui ne
font pas partie de la bibliothŁque C standard. Il s’agit des chiers d’en-tŒtes qui sont propres
? Linux (propres ? Unix pour la plupart) ou, faisant partie de la bibliothŁque C standard, qui
doivent Œtre implØmentØs suivant le systŁme. Ces chiers se trouvent soit dans le rØpertoire
lui-mŒme, soit dans l’un des trois sous-rØpertoires :
asm contient des chiers d’en-tŒtes dont le code est Øcrit en langage d’assemblage ;
linux contient des chiers propres ? Linux (n’existant pas sur les autres distribu-
tions Unix) ;
sys est un sous-rØpertoire classique d’Unix, contenant les chiers d’en-tŒtes concernant le
systŁme.
Le rØpertoire lui-mŒme contient d’abord des chiers d’en-tŒtes faisant partie de la biblio-
thŁque standard C mais qu’il faut implØmenter suivant le systŁme (voir [PLAU-92] pour
plus de dØtails) :
ctype.h (pour Character TYPEs) permet le traitement des caractŁres en distinguant
des classes de caractŁres (chi re, alphabØtique, espace...) ;
errno.h (pour ERRor NumerO) permet d’associer un numØro ? des constantes symbo-
liques reprØsentant les erreurs rencontrØes ;
signal.h dØ nit les valeurs de code d’un ensemble de signaux ;
stdarg.h (pour STandarD ARGument) dØ nit des macros permettant d’accØder aux
arguments d’une fonction, telle la fonction printf(), acceptant une liste variable d’ar-
guments ;
stddef.h (pour STandarD DEFinitions) contient un certain nombre de dØ nitions stan-
dard (sic) ;
string.h contient des fonctions permettant de manipuler les cha nes de caractŁres ;
time.h concerne les calculs sur l’heure et la date.
Il contient ensuite des chiers d’en-tŒtes propres ? Unix :
a.out.h contient le format propre au type d’exØcutable a.out, qui Øtait le plus utilisØ
avant l’arrivØe du format ELF ;Chapitre 3. Le systŁme Linux ØtudiØ 27
const.h contient diverses valeurs de constantes ;
fcntl.h contient les fonctions permettant de manipuler les descripteurs de chiers ;
termios.h contient les constantes et les fonctions concernant les terminaux ;
unistd.h (pour UNIx STandarD) contient les constantes et les fonctions standard
d’Unix ;
utime.h (pour User TIME) permet de changer la date et l’heure d’un n ud d’informa-
tion.
Le sous-rØpertoire asm contient quatre chiers :
io.h (pour Input/Output) contient la dØ nition des macros, en langage d’assemblage,
permettant d’accØder aux ports d’entrØe-sortie ;
memory.h contient la dØ nition de la macro memcpy();
segment.h contient la des fonctions en ligne d’Øcriture et de lecture d’un
octet, d’un mot ou d’un mot double ;
system.h contient la dØ nition de fonctions nØcessaires ? l’initialisation.
Le sous-rØpertoire linux contient neuf chiers :
config.h contient les donnØes nØcessaires au dØmarrage du systŁme (concernant la ca-
pacitØ mØmoire et le disque dur) ;
fs.h (pour File System) contient les dØ nitions des tableaux de structures pour les
chiers ;
hdreg.h (pour Hard Disk REGisters) contient des dØ nitions pour le contr leur de
disque dur de l’IBM PC-AT ;
head.h contient des constantes nØcessaires pour le chier head.s;
kernel.h contient la dØclaration de fonctions nØcessaires pour le mode noyau (comme
la fonction printk()) ;
mm.h (pour Memory Management) contient la dØclaration de fonctions de manipulation
de la mØmoire ;
sched.h (pour SCHEDuler) contient la dØ nition des structures et la dØclaration des
fonctions nØcessaires ? la manipulation des processus ;
sys.h (pour SYStem call) contient la dØclaration des appels systŁme ;
tty.h contient la dØ nition de structures et la dØclaration de fonctions concernant le
terminal (tty pour TeleTYpe), nØcessaires pour le chier tty_io.c ci-dessous.
Le sous-rØpertoire sys contient cinq chiers :
stat.h contient la dØclaration des fonctions renvoyant les informations sur les chiers ;
times.h contient la de la fonction renvoyant le nombre de tops d’horloge
ØcoulØs depuis le dØmarrage du systŁme ;
types.h contient la dØ nition d’un certain nombre de types ;
utsname.h contient la dØclaration de la fonction donnant le nom et des informations
sur le noyau ;
wait.h contient la dØclaration des fonctions permettant de suspendre l’exØcution du
processus en cours jusqu’ ce un processus ls se termine ou qu’un signal soit envoyØ.28 PremiŁre partie : Principes de conception des systŁmes d’exploitation
Le rØpertoire kernel
Il contient dix-sept chiers, outre le chier Makefile :
asm.s contient les routines de service de la plupart des 32 premiŁres interruptions, c’est- -
dire de celles qui sont rØservØes par Intel :
Linux 0.01 /*
* asm.s contains the low-level code for most hardware faults.
* page_exception is handled by the mm, so that isn’t here. This
* file also handles (hopefully) fpu-exceptions due to TS-bit, as
* the fpu must be properly saved/resored. This hasn’t been tested.
*/
console.c contient les paramŁtres, les variables et les fonctions nØcessaires ? l’a chage sur
le moniteur (nØcessite les structures dØ nissant un terminal) :
Linux 0.01 /*
* console.c
*
* This module implements the console io functions
* ’void con_init(void)’
* con_write(struct tty_queue * queue)’
* Hopefully this will be a rather complete VT102 implementation.
*
*/
exit.c contient les fonctions nØcessaires pour quitter un processus autrement que par
return;
fork.c contient les fonctions nØcessaires pour crØer un processus ls :
Linux 0.01 /*
* ’fork.c’ contains the help-routines for the ’fork’ system call
* (see also system_call.s), and some misc functions (’verify_area’).
* Fork is rather simple, once you get the hang of it, but the memory
* management can be a bitch. See ’mm/mm.c’: ’copy_page_tables()’
*/
hd.c contient le pilote du disque dur :
Linux 0.01 /*
* This code handles all hd-interrupts, and read/write requests to
* the hard-disk. It is relatively straigthforward (not obvious maybe,
* but interrupts never are), while still being efficient, and never
* disabling interrupts (except to overcome possible race-condition).
* The elevator block-seek algorithm doesn’t need to disable interrupts
* due to clever programming.
*/
keyboard.s contient la routine de service associØe ? IRQ1, c’est- -dire ? l’interruption ma-
tØrielle provenant du clavier ;
mktime.c contient la fonction permettant de transformer la date exprimØe en secondes de-
puis 1970 en annØe, mois, jour, heure, minute et seconde :
Linux 0.01 /*
* This isn’t the library routine, it is only used in the kernel.
* as such, we don’t care about years<1970 etc, but assume everything
* is ok. Similarly, TZ etc is happily ignored. We just do
* as easily as possible. Let’s find something public for the library
* routines (although I think minix times is public).
*/
/*
* PS. I hate whoever though up the year 1970 - couldn’t they have gotten
* a leap-year instead? I also hate Gregorius, pope or no. I’m grumpy.
*/Chapitre 3. Le systŁme Linux ØtudiØ 29
panic.c contient une fonction utilisØe par le noyau pour indiquer un problŁme grave :
Linux 0.01/*
* This function is used through-out the kernel (includeinh mm and fs)
* to indicate a major problem.
*/
printk.c contient une fonction analogue ? la fonction printf() du langage C mais qui
peut Œtre utilisØe par le noyau :
Linux 0.01/*
* When in kernel-mode, we cannot use printf, as fs is liable to
* point to ’interesting’ things. Make a printf with fs-saving, and
* all is well.
*/
rs_io.c contient la routine de service associØe aux interruptions matØrielles des ports sØrie
(rs rappelant la norme RS232) :
Linux 0.01/*
* rs_io.s
*
* This module implements the rs232 io interrupts.
*/
sched.c contient le sØquenceur (scheduler en anglais) qui permet de changer de processus
pour rendre le systŁme d’exploitation multi-t ches :
Linux 0.01/*
* ’sched.c’ is the main kernel file. It contains scheduling primitives
* (sleep_on, wakeup, schedule etc) as well as a number of simple system
* call functions (type getpid(), which just extracts a field from
* current-task
*/
serial.c contient l’implØmentation de deux fonctions servant aux ports sØrie :
/* Linux 0.01
* serial.c
*
* This module implements the rs232 io functions
* void rs_write(struct tty_struct * queue);
* rs_init(void);
* and all interrupts pertaining to serial IO.
*/
sys.c contient la dØ nition de beaucoup de fonctions de code sys_XX() d’appels systŁme ;
system_call.s contient du code en langage d’assemblage permettant d’implØmenter les ap-
pels systŁme :
Linux 0.01/*
* system_call.s contains the system-call low-level handling routines.
* This also contains the timer-interrupt handler, as some of the code is
* the same. The hd-interrupt is also here.
*
* NOTE: This code handles signal-recognition, which happens every time
* after a timer-interrupt and after each system call. Ordinary interrupts
* don’t handle signal-recognition, as that would clutter them up totally
* unnecessarily.
*
* ------------------------------------------------------------------------
*/30 PremiŁre partie : Principes de conception des systŁmes d’exploitation
traps.c contient le code en langage C des routines de service associØes aux 32 premiŁres
interruptions, c’est- -dire celles rØservØes par Intel :
Linux 0.01 /*
* ’Traps.c’ handles hardware traps and faults after we have saved some
* state in ’asm.s’. Currently mostly a debugging-aid, will be extended
* to mainly kill the offending process (probably by giving it a signal,
* but possibly by killing it outright if necessary).
*/
tty_io.c contient les fonctions nØcessaires au fonctionnement du terminal :
Linux 0.01 /*
* ’tty_io.c’ gives an orthogonal feeling to tty’s, be they consoles
* or rs-channels. It also implements echoing, cooked mode etc (well,
* not currently, but ...)
*/
vsprintf.c contient le code permettant de dØ nir ? la fois les fonctions printk() et
printf() :
Linux 0.01 /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
/*
* Wirzenius wrote this portably, Torvalds fucked it up:-)
*/
Le rØpertoire lib
Le rØpertoire lib contient onze chiers, outre le chier Makefile :
_exit.c contient la dØ nition de la fonction associØe ? l’appel systŁme de terminaison d’un
processus _exit();
close.c contient la dØ nition de la fonction associØe ? l’appel systŁme de fermeture d’un
chier close();
ctype.c contient la dØ nition du tableau de dØ nition des types de chacun des 256 carac-
tŁres (majuscule, chi re...) ;
dup.c contient la dØ nition de la fonction associØe ? l’appel systŁme dup();
errno.c contient la dØclaration de la variable errno;
execv.c contient la dØ nition de la fonction associØe ? l’appel systŁme execv();
open.c contient la de la associØe ? l’appel d’ouverture d’un -
chier open();
setsid.c contient la dØ nition de la fonction associØe ? l’appel systŁme setsid();
string.c contient des directives de compilation ;
wait.c contient la dØ nition de la fonction associØe ? l’appel systŁme wait();
write.c contient la de la fonction associØe ? l’appel systŁme d’Øcriture sur un
chier write().
Le rØpertoire fs
Le rØpertoire fs contient dix-huit chiers, outre le chier Makefile :
bitmap.c contient le code permettant de gØrer les tables de bits d’utilisation des n uds
d’information et des blocs :
Linux 0.01 /* bitmap.c contains the code that handles the inode and block bitmaps */Chapitre 3. Le systŁme Linux ØtudiØ 31
block_dev.c contient le code permettant de gØrer les pØriphØriques bloc ;
buffer.c contient le code permettant de gØrer l’antØmØmoire de blocs :
Linux 0.01/*
* ’buffer.c’ implements the buffer-cache functions. Race-conditions have
* been avoided by NEVER letting an interrupt change a buffer (except for
* the data, of course), but instead letting the caller do it. NOTE! As
* interrupts can wake up a caller, some cli-sti sequences are needed to
* check for sleep-on-calls. These should be extremely quick, though
* (I hope).
*/
char_dev.c contient le code permettant de gØrer les pØriphØriques caractŁre ;
exec.c contient le code permettant d’exØcuter un nouveau programme ;
fcntl.c contient le code pt de manipuler les descripteurs de chiers ;
file_dev.c contient les fonctions d’Øcriture et de lecture dans un chier ordinaire ;
file_table.c contient la dØclaration de la table des chiers ;
inode.c contient la dØclaration de la table des n uds d’information en mØmoire ainsi que
les fonctions permettant de la gØrer ;
ioctl.c contient la dØclaration de la table ioctl[] et quelques fonctions associØes ;
namei.c (pour NAME I-node) contient les fonctions permettant de nommer les chiers ;
open.c contient les fonctions permettant d’ouvrir et de changer les droits d’accŁs d’un -
chier ;
pipe.c permet de mettre en place les tubes de communication ;
read_write.c contient les fonctions permettant de se positionner, de lire et d’Øcrire sur un
chier ;
stat.c contient les fonctions permettant d’obtenir des informations sur un chier ;
super.c contient les dØ nitions et les fonctions concernant les super-blocs ;
truncate.c contient les fonctions permettant d’e acer un chier ;
tty_ioctl.c contient les pt de paramØtrer un terminal.
Le rØpertoire mm
Le rØpertoire mm contient deux chiers, outre le chier Makefile :
memory.c contient les fonctions concernant la gestion des pages ;
page.s contient la routine de service de l’interruption matØrielle concernant le dØfaut de
page :
/* Linux 0.01
* page.s contains the low-level page-exception code.
* the real work is done in mm.c
*/
Le rØpertoire tools
Le rØpertoire tools contient un seul chier : build.c. Il s’agit d’un programme C indØpen-
dant qui permet de construire l’image du noyau.32 PremiŁre partie : Principes de conception des systŁmes d’exploitation
3 Vue d’ensemble sur l’implØmentation
3.1 CaractØristiques
La version 0.01 de Linux n’a pas pour but d’Œtre ØvoluØe :
Architecture. Elle ne supporte que les micro-processeurs 80386 d’Intel et ses descendants,
gr ce ? la compatibilitØ ascendante de ceux-ci. Elle ne gŁre Øvidemment que les systŁmes
? un seul micro-processeur.
MØmoire. Elle gŁre la mØmoire gr ce au mØcanisme de pagination. La mØmoire physique est
limitØe ? 8 Mo, ce qui Øtait dØj Ønorme pour 1991. Cette limitation peut cependant Œtre
Øtendue sans trop de modi cations. La capacitØ de la mØmoire physique n’est pas dØtectØe
par le noyau, il faut la con gurer manuellement.
Disque dur. On ne peut utiliser que des disques IDE et seul le premier contr leur est pris
en charge. Comme pour la mØmoire, les paramŁtres des disques durs doivent Œtre entrØs
avant la compilation.
PØriphØriques. La version 0.01 ne gŁre que deux disques durs, la console (clavier et Øcran
texte) et deux modems (via deux ports sØrie). Elle ne gŁre ni le lecteur de disquettes, ni
le port parallŁle (donc pas d’imprimante), ni la souris, ni les cartes graphiques (autres que
texte), ni les cartes son ou autres pØriphØriques (ISA, PCI ou autre). Elle n’utilise pas la
DMA (Direct Memory Access).
Gestion des processus. Linux 0.01 est multi-t ches et multi-utilisateurs. Il peut gØrer 64
t ches simultanØes (ce nombre est aisØment extensible) et 65 536 utilisateurs. Aucun uti-
litaire gØrant les utilisateurs (login, su, passwd,...) n’est fourni et une seule console est
implØmentØe.
SystŁme de chiers. Le systŁme de chiers utilisØ par Linux 0.01 est celui de la premiŁre
version de Minix. Il gŁre des chiers avec des noms de 14 caractŁres au plus et une taille
maximale de 64 Mo par chier.
RØseau. Le support rØseau n’Øtait pas implØmentØ sur Linux 0.01.
La toute premiŁre version est donc rudimentaire du point de vue de l’utilisation mais elle
est su sante ? titre pØdagogique pour Øtudier le principe de l’implØmentation d’un systŁme
d’exploitation.
3.2 tapes de l’implØmentation
Linus Torvalds ne donne aucune indication sur l’implØmentation de son systŁme. L’Øtude des
sources nous conduit ? distinguer les Øtapes suivantes, ce qui correspondra au plan de notre
Øtude.
Le systŁme d’exploitation est presque entiŁrement Øcrit en langage C, mais il existe quelques
chiers et quelques portions de chiers Øcrits en langage d’assemblage, et ceci pour deux rai-
sons : soit pour piloter les pØriphØriques, soit pour tenir compte des particularitØs du micro-
processeur Intel 86386. Ces particularitØs sont encapsulØes dans des macros ou des fonctions
C. La seconde partie de notre Øtude consiste ? Øtudier ces particularitØs.
Dans le chapitre 4, nous voyons comment l’accŁs ? la mØmoire vive est encapsulØe dans des
macros et comment la segmentation est utilisØe sous Linux. L’Øtude de la pagination est repor-
tØe au chapitre 17 sur l’utilisation de la mØmoire virtuelle sous Linux. Dans le chapitre 5, nousChapitre 3. Le systŁme Linux ØtudiØ 33
voyons comment l’accŁs aux ports d’entrØe-sortie est encapsulØ dans des macros et comment
les interruptions, que ce soit les exceptions rØservØes par Intel, les interruptions matØrielles ou
la seule interruption logicielle de Linux sont initialisØes sous Linux, sans Øtudier, pour l’instant,
les gestionnaires associØs.
La troisiŁme partie de notre Øtude est consacrØe aux grandes structures de donnØes utilisØes
par Linux. Dans le chapitre 6, nous Øtudions en dØtail la structure des descripteurs de pro-
cessus, la table des processus et la t che initiale, c’est- -dire ce qui concerne l’aspect statique
des processus en mode noyau. Dans le chapitre 7, nous Øtudions la mise en place des chiers,
c’est- -dire ce qui concerne l’aspect statique des chiers en mode noyau, plus exactement nous
entreprenons une Øtude gØnØrale des chiers dans les divers types de systŁmes d’exploitation,
les caractØristiques des chiers sous Unix, la structure d’un disque Minix (qui est le seul sys-
tŁme de chiers acceptØ par le noyau 0.01 de Linux), les structures de donnØes liØes aux chiers
en mode noyau (antØmØmoire, n uds d’information, super-blocs et descripteurs de chiers) et,
en n, la fa on dont on dØsigne les chiers de pØriphØriques sous Linux. Dans le chapitre 8,
nous Øtudions la mise en place des terminaux ? haut niveau, ceci regroupant ? la fois l’encap-
sulation du clavier, de l’a chage sur le moniteur et des deux liaisons sØrie. Nous n’entrons pas,
dans ce chapitre, dans le dØtail des pilotes pour ces trois types de pØriphØriques.
La quatriŁme partie est consacrØe ? la mise en place de l’aspect dynamique du mode noyau
qui ne donne pas lieu ? a chage en cas d’erreur (tout simplement parce que nous n’avons pas
vu comment celui-ci est mis en place). Dans le chapitre 9, nous voyons comment les appels
systŁme sont mis en place, sans les Øtudier un par un pour l’instant. Dans le chapitre 10,
nous Øtudions la mise en place de la mesure du temps, que ce soit l’horloge temps rØel ou les
minuteurs. Dans le chapitre 11, nous Øtudions la commutation des t ches et l’ordonnancement
des processus. Dans le chapitre 12, nous Øtudions la notion gØnØrale de signal puis la mise en
place des signaux sous Linux.
La cinquiŁme partie est consacrØe ? l’a chage. Dans le chapitre 14, nous Øtudions la mise
en place du pilote d’Øcran sous Linux. Dans le chapitre 15, nous Øtudions la mise en place de
l’a chage formatØ, ce qui nous conduit ? Øtudier la mise en place des fonctions de bibliothŁque
ayant un nombre variable d’arguments.
La sixiŁme partie est consacrØe ? la mise en place de l’aspect dynamique du mode noyau fai-
sant intervenir l’a chage de messages d’erreur. Dans le chapitre 16, nous Øtudions les gestion-
naires des exceptions sauf celui concernant le dØfaut de page, reportØ dans le chapitre suivant.
Dans le chapitre 17, nous Øtudions la notion de mØmoire virtuelle de fa on gØnØrale puis sa
mise en place sous Linux.
La septiŁme partie est consacrØe ? l’Øtude des chiers rØguliers. Dans le chapitre 19, nous
Øtudions la notion de cache du disque dur et sa mise en place sous Linux. Dans le chapitre 18,
nous Øtudions la mise en place du pilote du disque dur, c’est- -dire l’accŁs au disque dur ?
bas niveau. Dans le chapitre 20, nous Øtudions la mise en place des pØriphØriques bloc, c’est-
-dire l’accŁs au disque dur ? haut niveau. Dans le chapitre 21, nous Øtudions la gestion des
n uds d’information. Dans le chapitre 22, nous Øtudions la gestion des chiers rØguliers et des
rØpertoires.
La huitiŁme partie est consacrØe ? l’Øtude des pØriphØriques caractŁre. Dans le chapitre 23,
nous Øtudions le pilote du clavier. Dans le chapitre 24, nous Øtudions le pilote des liaisons
sØrie. Dans le chapitre 25, nous Øtudions les pØriphØriques caractŁre.34 PremiŁre partie : Principes de conception des systŁmes d’exploitation
La neuviŁme partie, ? chapitre unique 26, est consacrØe ? l’Øtude de la communication par
tubes entre processus.
La dixiŁme partie est consacrØe ? la mise en place du mode utilisateur, c’est- -dire ? la mise
en place des appels systŁme et des fonctions de bibliothŁques. Dans le chapitre 27, les appels
systŁme concernant le systŁme de chiers sont mis en place. Dans le c 28, les appelst les processus sont mis en place. Dans le chapitre 29, les autres appels
systŁme sont mis en place. Dans le chapitre 30, les fonctions de la bibliothŁque C sont mises
en place.
La onziŁme partie, ? chapitre unique 31, est consacrØe au dØmarrage du systŁme.
4 volution du noyau
Linux 2.2.18 Les sources du noyau 2.2.18 occupent 4 500 chiers de C et de langage d’assemblage contenus
dans prŁs de 270 sous-rØpertoires ; elles totalisent quelques deux millions de lignes de code
reprØsentant prŁs de 58 Mo.
4.1 Cas du noyau 2.4.18
Linux 2.4.18 Les sources du noyau 2.4.18 occupent 122 Mo. Le premier niveau de l’arborescence est aussi
simple que dans le cas du premier noyau :
/arch concerne tout ce qui dØpend de l’architecture de la puce, Linux ayant ØtØ adaptØ ?
plusieurs micro-processeurs ; c’est dans ce rØpertoire qu’on retrouve ce qui a trait au dØmar-
rage ;
/Documentation contient de la documentation, en particulier sur les pØriphØriques pris en
compte ;
/drivers renferme les divers pilotes de pØriphØriques ;
/fs contient ce qui concerne les systŁmes de chiers, plusieurs systŁmes de chiers Øtant pris
en compte et non plus seulement Minix ;
/include renferme les chiers d’en-tŒtes, dont beaucoup dØpendent d’une architecture de
micro-processeur donnØe ;
/init ne contient toujours qu’un seul chier main.c;
/ipc renferme la mise en place d’un mode de communication entre processus qui n’Øtait pas
pris en compte lors du noyau 0.01 ;
/kernel a un contenu assez proche de ce qui s’y trouvait pour le noyau 0.01 ;
/lib a toujours la mŒme fonction ;
/mm Øgalement, mais compte un peu plus de chiers ;
/net concerne la mise en place des rØseaux, principalement de TCP/IP, thŁmes non abordØs
lors du noyau 0.01 ;
/scripts renferme un certain nombre de scripts.
Le contenu des rØpertoires /boot et /tools est passØ dans le rØpertoire /arch.Chapitre 3. Le systŁme Linux ØtudiØ 35
4.2 Aide au parcours du code source
Il n’est pas toujours facile de s’y retrouver dans le code source, en particulier pour savoir oø
telle constante ou telle fonction est dØ nie. Un bon outil est le site Internet Cross-Referencing
Linux : http://lxr.linux.no/ en cliquant sur Browse the code ou, plus lent, Linux
Cross Reference : http://www.iglu.org.il/lxr/
4.3 Cas du noyau 2.6.0
Donnons le premier niveau de l’arborescence des sources du noyau 2.6.0, qui comporte Linux 2.6.0
5 929 913 lignes de code pour 212 Mo :
/Documentation;
/arch;
/crypto est un nouveau rØpertoire qui concerne la cryptographie ;
/drivers;
/fs ;
/include;
/init;
/ipc ;
/kernel;
/lib ;
/mm ;
/net ;
/scripts;
/security est un nouveau rØpertoire relatif ? la sØcuritØ ;
/sound est un nouveau rØpertoire traitant du son ;
/usr est un nouveau rØpertoire pour les chiers auxiliaires.
On y trouve donc quatre nouveaux rØpertoires : deux d’entre eux (sound et usr) permettent
de mieux structurer les sources ; les deux autres (crypto et security) prennent en compte
un thŁme trŁs ? la mode.
Conclusion
Il existe de trŁs nombreux systŁmes d’exploitation. Les versions successives de chacun d’eux
permettent d’une part d’amØliorer ce que l’on peut appeler le micro-noyau du systŁme et,
d’autre part, de prendre en compte les changements essentiels dans le matØriel (par exemple
les rØseaux ou les pØriphØriques USB). Nous avons expliquØ pourquoi il vaut mieux s’intØresser,
dans une premiŁre Øtape, au tout premier noyau, la version 0.01 de Linux, pour encha ner sur
ses Øvolutions (il en est actuellement ? sa version 2.6). Nous verrons dans les deux chapitres
suivants en quoi un systŁme d’exploitation dØpend du micro-processeur.DeuxiŁme partie
Utilisation du micro-processeur IntelChapitre 4
Prise en compte de la mØmoire Intel
Nous avons vu qu’un systŁme d’exploitation comprend quatre parties : un gestionnaire de la
mØmoire, un gestionnaire des processus, un gestionnaire des chiers, et un des
entrØes-sorties. Certaines de ces ressources sont dØj prises en compte par le micro-processeur.
Nous allons voir dans cette partie comment Linux adapte ces primitives de prise en compte.
Il s’agit de la mØmoire vive et des entrØes-sorties (y compris les interruptions matØrielles). Rien
n’est prØvu pour les chiers sur un micro-processeur. Il existe un traitement des processus, que
nous verrons au chapitre 6.
Nous allons Øtudier dans ce chapitre la fa on dont Linux adapte la gestion de la mØmoire prise
en compte par les micro-processeurs Intel. Celle-ci s’e ectue ? la fois gr ce ? la segmentation et
? la pagination. Linux trouve ces deux mØthodes redondantes et prØfŁre utiliser essentiellement
la deuxiŁme, ne gardant que ce qui est nØcessaire de la premiŁre. Nous Øtudierons la pagination
au chapitre 17. Nous allons Øtudier la segmentation dans ce chapitre.
1 La segmentation sous Intel
1.1 Notion
Sur certaines architectures de micro-processeurs, l’accŁs ? la mØmoire vive est facilitØe en uti-
lisant des segments. Une adresse est, dans ce cas, composØe de deux ØlØments ? placer dans
deux registres du micro-processeur : un identi cateur de segment et un dØplacement
(o set en anglais) dans ce segment. Le micro-processeur combine l’adresse du segment et le
dØplacement pour obtenir une adresse linØaire. La gure 4.1 illustre la conversion d’une
adresse composØe d’un identi cateur de segment et d’un dØplacement de segment.
Tous les micro-processeurs Intel, depuis le 8086, utilisent la segmentation pour des raisons de Cas de Intel
compatibilitØ avec le micro-processeur prØcØdent 8080.
1.2 La segmentation en mode protØgØ sur Intel
Pour des raisons de protection, on n’utilise pas, pour une t che donnØe, l’espace physique
adressable en son entier, mais seulement une portion de celui-ci, appelØe segment. ? la limite
le segment peut Œtre constituØ de toute la mØmoire physique si l’on y tient, mais c’est rarement
le cas.40 DeuxiŁme partie : Utilisation du micro-processeur Intel
Figure 4.1 : Segmentation
Indexation ? l’intØrieur d’un segment : dØcalage
On peut parcourir un segment gr ce ? un index, appelØ dØcalage (o set en anglais). L’adresse
physique est la somme de l’adresse de base du segment et du dØcalage.
Nous avons bien dit que l’adresse physique est la somme de l’adresse de base et du dØcalage
et non de 16 fois le dØcalage comme en mode rØel. En e et, on n’a plus besoin de cette mul-
tiplication par seize car l’adresse de base ou le dØcalage peuvent varier de 0 ? 4 Go moins
un.
Lors de l’utilisation d’un dØcalage, le micro-processeur vØri e qu’il ne dØborde pas de la portion
de mØmoire permise pour une t che donnØe. Le programme est interrompu et une interruption,
dite de protection gØnØrale, est dØclenchØe si ce n’est pas le cas.
CaractØristiques d’un segment
Un segment est constituØ d’une portion connexe de mØmoire. Son emplacement est donc entiŁ-
rement caractØrisØ par son adresse de base, qui est l’adresse physique du premier octet de la
zone, et par sa taille. Sa taille moins un est appelØe sa limite.Chapitre 4. Prise en compte de la mØmoire Intel 41
L’index varie de 0 ? limite, d’oø son nom de dØcalage (l’adresse physique Øtant la somme de
l’adresse de base et du dØcalage).
Pour des raisons liØes ? la protection des t ches, un segment n’est pas uniquement caractØrisØ
par son emplacement, mais Øgalement par ses droits d’accŁs.
Les caractØristiques d’un segment sont dØcrites par un descripteur (descriptor en anglais).
Structure d’un descripteur
Le tableau ci-dessous montre le format d’un descripteur ? partir du 80386 (celui-ci est un peu
di Ørent pour le 80286) :
7 Base (B24-B31) G D 0 AVL Limite (L16-L19) 6
5 Droits d’accŁs Base (B23-B16) 4
3 Base (B15-B0) 2
1 Limite (L15-L0) 0
Un descripteur a une taille de 8 octets. Commentons les di Ørents champs :
L’adresse de base est la partie du descripteur qui indique le dØbut de l’emplacement mØ-
moire du segment. Cette adresse (physique) occupe 32 bits ; le du segment peut donc
Œtre n’importe quel emplacement des 4 Go possible de la mØmoire.
La limite du segment contient l’adresse du dernier dØcalage du segment. Par exemple, si
un segment commence ? l’adresse F00000h et se termine ? l’adresse F000FFh, l’adresse de
base est 00F00000h et la limite du segment est 000FFh. La limite a une taille de 20 bits :
la taille d’un segment est comprise entre 1 octet et un Mo, par pas de un octet, ou entre
4 Ko et 4 Go, par pas de 4 Ko, suivant la granularitØ, qui est une des caractØristiques d’un
segment (dØterminØe par le champ dØcrit ci-aprŁs).
Le bit G (pour Granularity) est le bit de granularitØ. Si G = 0, la limite spØci e un segment
dont la limite est comprise entre 00000h et FFFFFh. Si G = 1, la valeur de cette limite est
multipliØe par 4 Ko (c’est- -dire que l’on compte en pages).
Le bit AVL (pour l’anglais AVaiLable) est laissØ ? la libre interprØtation Øventuelle du sys-
tŁme d’exploitation. Il indique par exemple, dans le cadre de l’Øchange (swap) entre la mØ-
moire et le disque, que le segment est disponible en mØmoire centrale (AV = 1) ou non
disponible (AV = 0), et qu’il se trouve donc sur le disque.
Linux 0.01Ce bit n’est pas utilisØ pour le noyau 0.01 de Linux.
Le bit D pour les descripteurs des segments de code (pour Default register size) indique la
taille par dØfaut, 32 bits ou 16 bits, des registres et de la mØmoire ? laquelle les instructions
ont accŁs. Si D = 0, les registres ont une taille par dØfaut de 16 bits, compatibles avec le
micro-processeur 8086; ce mode est appelØ mode d’instructions 16 bits. Si D = 1 on se
trouve alors dans le mode d’instructions 32 bits qui suppose, par dØfaut, que tous les
dØcalages et tous les registres sont de 32 bits. Nous reviendrons plus tard sur cette caractØ-
ristique.42 DeuxiŁme partie : Utilisation du micro-processeur Intel
Ce bit est appelØ bit B dans le cas d’un descripteur de segment de donnØes.
Lorsqu’on se trouve dans un mode donnØ, par exemple le mode 32 bits, et que l’on veut faire
rØfØrence ? un contenu mØmoire de l’autre mode, ici 16 bits, il faut faire appel ? un prØ xe,
par exemple ptr word pour MASM.
L’octet des droits d’accŁs, l’octet 5, contr le l’accŁs au segment de mØmoire en mode
protØgØ. Sa structure dØpend du type de descripteur.
Types de descripteur
Il existe essentiellement deux types de descripteurs :
Les descripteurs de segment dØ nissent les segments de donnØes, de pile et de code.
Les systŁme donnent des informations sur les tables du systŁme, les t ches et
les portes.
Octet des droits d’accŁs d’un descripteur de segment
Le tableau ci-dessous montre la structure complŁte d’un descripteur de segment, y compris
celle de son octet des droits d’accŁs :
7 Base (B24-B31) G D 0 AVL Limite (L16-L19) 6
5 P DPL S E X RW A Base (B23-B16) 4
3 Base (B15-B0) 2
1 Limite (L15-L0) 0
Le bit 7 de l’octet des droits d’accŁs, notØ P (pour Present), indique si le descripteur n’est pas
dØ ni (P = 0) ou s’il contient une base et une limite valides (P = 1). Si P = 0 et qu’on essaie
d’y accØder via un descripteur, une interruption interne de type 11 (segment non prØsent)
est dØclenchØe.
Les bits 5 et 6, notØs DPL, indiquent le niveau de privilŁge du descripteur (Descriptor Pri-
vilege Level en anglais), oø 00b est le privilŁge le plus ØlevØ et 11b le moins ØlevØ. Ceci est
utilisØ pour protØger l’accŁs au segment. Si l’on essaie d’accØder ? un segment alors qu’on a
un niveau de privilŁge moins ØlevØ (donc un numØro plus ØlevØ) que son DPL, une interrup-
tion interne de violation de privilŁge (protection gØnØrale) est dØclenchØe.
Le bit 4, notØ S (pour Segment ou System), permet de savoir s’il s’agit d’un descripteur
systŁme (S = 0) ou d’un descripteur de segment (S = 1).
Dans la suite nous supposons que S a la valeur 1, puisque nous ne nous intØressons ici qu’aux
descripteurs de segment.
Le bit 3 (notØ E pour Executable) donne la nature du segment : E = 0 pour un segment
de donnØes ou de pile ; E = 1 pour un segment de code. Ce bit dØ nit les fonctions des deux
bits suivants (X et RW).
Le bit 2 est notØ X (pour eXpansion).Chapitre 4. Prise en compte de la mØmoire Intel 43
Si E = 0, ce bit indique le sens d’accroissement des adresses : pour X = 0, les adresses du
segment sont incrØmentØes (cas d’un segment de donnØes) ; pour X = 1, elles sont dØcrØ-
mentØes (cas d’un segment de pile).
Si E = 1 alors X indique si l’on ignore le niveau de privilŁge du descripteur (X = 0) ou si
l’on en tient compte (X = 1).
Le bit 1 est notØ R/W (pour Read/Write).
Pour E = 0, si R/W = 0, on ne peut plus Øcrire (autrement dit surcharger les donnØes) alors
que si R/W = 1, on le peut.
Pour E = 1, si R/W = 0, le segment de code ne peut pas Œtre lu, si R/W = 1 on peut le lire.
Le bit 0, notØ A (pour Accessed), indique si l’on a eu accŁs au segment (A = 1) ou non (A
= 0). Ce bit est quelquefois utilisØ par le systŁme d’exploitation pour garder une trace des
segments auxquels on a eu accŁs.
Tables de descripteurs
Les descripteurs sont situØs dans des tables de descripteurs. Pour une t che donnØe, on ne
peut utiliser que deux tables de descripteurs : la table globale de descripteurs contient les
dØ nitions des segments qui s’appliquent ? tous les programmes alors que la table locale de
descripteurs contient les dØ nitions des segments utilisØs par une application donnØe.
On parle aussi de descripteurs systŁme pour ceux de la premiŁre table (mais pas dans le
mŒme sens que ci-dessus) et de descripteurs d’application pour ceux de la seconde table.
13Chaque table de descripteur peut contenir jusqu’ 2 = 8 192 descripteurs, l’index d’un des-
cripteur Øtant codØ sur 13 bits. Il y a donc 16 384 segments de mØmoire disponibles pour
chaque application. Un descripteur ayant une taille de 8 octets, la taille d’une table de des-
cripteurs est de 64 Ko au plus.
Puisque chaque segment peut avoir une taille de 4 Go au plus, ceci permet d’accØder ? une
mØmoire virtuelle de 64 To (1 To = 1 024 Go). Bien entendu, la mØmoire rØelle est au plus de
4 Go pour un 80386; cependant si un programme nØcessite plus de 4 Go ? la fois, la mØmoire
peut Œtre ØchangØe entre la mØmoire vive et le disque, comme nous le verrons au chapitre 17.
Le descripteur de numØro 0 d’une table de descripteurs ne peut pas Œtre utilisØ pour accØ-
der ? la mØmoire. Il s’agit d’un descripteur par dØfaut, non valide par mesure de protection
supplØmentaire. On parle du nul car tous ses champs sont Øgaux ? zØro.
AccŁs aux descripteurs : sØlecteurs
Les descripteurs sont choisis dans une des deux tables de descripteurs en pla ant dans l’un des
registres de segment (cs ? gs) un sØlecteur (selector en anglais), qui est un mot de 16 bits.
La structure d’un sØlecteur est montrØe dans le tableau ci-dessous :
15 3 2 1 0
index TI RPL
le champ de 13 bits (les bits 3 ? 15) appelØ index permet de choisir l’un des 8 192 descrip-
teurs de la table ;44 DeuxiŁme partie : Utilisation du micro-processeur Intel
le bit 2 (notØ TI pour Table Indicator) permet de choisir la table : la table globale des
descripteurs si TI = 0, la table locale des descripteurs si TI = 1 ;
les bits 0 et 1 (notØs RPL pour l’anglais Resquested Privilege Level) indiquent le niveau
de privilŁge requis pour accØder ? ce descripteur. Lors d’un essai d’accŁs au segment, si le
RPL est supØrieur ou Øgal au niveau de privilŁge DPL du descripteur, l’accŁs sera accordØ ;
sinon, le systŁme indiquera un essai de violation de privilŁge via une interruption interne de
protection gØnØrale.
Utilisation des descripteurs et des sØlecteurs
La gure 4.2 montre comment le micro-processeur 80386 accŁde ? un segment de mØmoire en
mode protØgØ en utilisant un sØlecteur et son descripteur associØ.
Figure 4.2 : SØlection
Les registres de segment ne sont en gØnØral manipulables qu’au niveau de privilŁge 0 (c’est ?
ce niveau qu’on le dØcide, en tous les cas). Heureusement d’ailleurs, vu leur complexitØ.
La gure 4.3 montre comment on choisit un descripteur gr ce au segment de registre ds, dont
la valeur est 0008h. On a RPL = 0, donc tous les droits. On a TI = 0, donc on choisit un
descripteur de la table globale des descripteurs. L’index est Øgal ? 1, on choisit donc le premier de la table. Admettons que ce descripteur ait la valeur 00 00 92 10 00 00 00
FFh. L’adresse de base est alors 00 10 00 00h et la limite Øgale ? 0 00 FFh. Ainsi le micro-
processeur utilisera-t-il les emplacements mØmoire 00100000h-001000FFh.
AccŁs au dØcalage
Le dØcalage, de 32 bits, est prØcisØ par l’un quelconque des registres gØnØraux Øtendus (eax,
ebx, ecx, edx, ebp, edi et esi). Il permet d’accØder ? des donnØes dans un segment de taille
pouvant aller jusqu’ 4 Go.Chapitre 4. Prise en compte de la mØmoire Intel 45
Figure 4.3 : Choix d’un descripteur
2 La segmentation sous Linux
2.1 Mode noyau et mode utilisateur
Le micro-processeur Intel permet de distinguer quatre niveaux de privilŁges. Le systŁme d’ex-
ploitation Linux n’en utilise que deux : le mode noyau correspond au niveau de privilŁge 0
et le mode utilisateur au niveau de privilŁge 3.
Linux n’utilise le mØcanisme de segmentation que pour sØparer les zones mØmoire allouØes au
noyau et aux processus. Pour le noyau 0.01, Linux utilise : Linux 0.01
un segment de code noyau ;
unt de donnØes noyau ;
une table de descripteurs locale par processus, qui rØfØrence un segment de code utilisateur
et un segment de donnØes utilisateur ;
un segment d’Øtat de t che par processus.
Les segments noyaux ne sont accessibles que dans le mode noyau. De cette fa on le code et les
donnØes du noyau sont protØgØs des accŁs erronØs ou mal intentionnØs de la part de processus46 DeuxiŁme partie : Utilisation du micro-processeur Intel
en mode utilisateur. Les segments utilisateur sont utilisØs en mode utilisateur, certes, mais
Øgalement en mode noyau (pour pouvoir transmettre de l’information).
Les registres de segment cs et ds du micro-processeur pointent, en mode utilisateur, sur les
deux segments utilisateur et, en mode noyau, sur les deux segments du noyau. La modi cation
de la valeur de ces registres de segments est e ectuØe lors du changement de mode d’exØcu-
tion, lorsqu’un processus passe en mode noyau pour exØcuter un appel systŁme, par exemple.
De plus, ce passage en mode noyau provoque la modi cation du registre de segment fs. Ce
registre pointe sur le segment de donnØes du processus appelant, a n de permettre au noyau
de lire et d’Øcrire dans l’espace d’adressage de ce processus, via des fonctions spØcialisØes.
2.2 Segmentation en mode noyau
La table globale des descripteurs
La table globale des contient essentiellement deux descripteurs.
DØ nition de la GDT. La table globale des descripteurs, appelØe _gdt dans le cas de Linux
0.01, est dØ nie dans le chier boot/head.s :
Linux 0.01 .globl _idt,_gdt,_pg_dir
------------------------
_gdt: .quad 0x0000000000000000 /* NULL descriptor */ 0x00c09a00000007ff /* 8Mb */
.quad 0x00c09200000007ff /* 8Mb */ /* TEMPORARY - don’t use */
.fill 252,8,0 /* space for LDT’s and TSS’s etc */
Elle comprend le descripteur nul, le descripteur du segment de code noyau, le descripteur
du segment de donnØes noyau, un temporaire et de la place pour les LDT et les
TSS de chacun des processus.
Segment de code noyau. La valeur du descripteur du segment de code noyau est
0x00c09a00000007ff donc :
une base Øgale ? 0 ;
GB0A Øgal ? Ch, soit ? 1100b, donc G Øgal ? 1 pour une granularitØ par page, B Øgal ? 1
pour des adresses de dØplacement sur 32 bits, AVL Øgal ? 0 (ce bit, qui peut Œtre utilisØ
par le systŁme d’exploitation, ne l’est pas par Linux) ;
une limite de 7FFh, soit une capacitØ de 2 048 4 Ko, ou 8 Mo ;
1/DPL/S Øgal ? 9, soit ? 1001b, donc S Øgal ? 1, pour un descripteur qui n’est pas un
descripteur systŁme, et DPL Øgal ? 0, pour le mode noyau ;
le type est Øgal ? Ah pour un segment de code qui peut Œtre lu et exØcutØ.
Son sØlecteur est 8.
Segment de donnØes noyau. La valeur du descripteur du segment de donnØes noyau est
0x00c09200000007ff donc :
une base Øgale ? 0 ;
GB0A Øgal ? Ch, soit ? 1100b, donc G Øgal ? 1 pour une granularitØ par page, B Øgal ? 1
pour des adresses de dØplacement sur 32 bits, AVL Øgal ? 0 (ce bit, qui peut Œtre utilisØ
par le systŁme d’exploitation, ne l’est pas par Linux) ;
une limite de 7FFh, soit une capacitØ de 2 048 4 Ko, ou 8 Mo ;Chapitre 4. Prise en compte de la mØmoire Intel 47
1/DPL/S Øgal ? 9, soit ? 1001b, donc S Øgal ? 1, pour un descripteur qui n’est pas un
descripteur systŁme, et DPL Øgal ? 0, pour le mode noyau ;
le type est Øgal ? 2h pour un segment de donnØes qui peut Œtre lu et Øcrit.
Ce segment est donc presque identique au prØcØdent : les deux segments se chevauchent.
Son sØlecteur est 10h.
Segments utilisateur
? tout processus sont associØs deux segments : un segment d’Øtat de t che TSS (pour Task
State Segment) et une table locale de descripteurs LDT (pour Local Descriptor Table). L’index
dans la GDT du TSS du processus numØro n est 4+2 n et celui de sa LDT est 4+2 n+1.
Ceci est dØcrit dans le chier include/linux/sched.h :
/* Linux 0.01
* Entry into gdt where to find first TSS. 0-nul, 1-cs, 2-ds, 3-syscall
* 4-TSS0, 5-LDT0, 6-TSS1 etc ...
*/
Le TSS d’un processus et sa table locale des descripteurs sont dØ nis dans la structure des
processus, comme nous le verrons ? propos de l’Øtude des descripteurs de processus.
Les deux macros :
_TSS(n)
_LDT(n)
renvoient, respectivement, le dØcalage en octets du TSS et de la LDT du processus numØro n
dans la GDT.
Elles sont implØmentØes dans le mŒme chier :
Linux 0.01#define FIRST_TSS_ENTRY 4 FIRST_LDT_ENTRY (FIRST_TSS_ENTRY+1)
#define _TSS(n) ((((unsigned long) n)<<4)+(FIRST_TSS_ENTRY<<3)) _LDT(n))+(FIRST_LDT_ENTRY)
Remarquons que pour obtenir l’adresse e ective on multiplie l’index par 8, puisque chaque
descripteur occupe 8 octets.
Placement des segments utilisateur dans la GDT
Les deux macros :
set_tss_desc(n,addr)
set_ldt_desc)
permettent de placer dans la GDT le descripteur de segment dont l’adresse de base est addr
comme descripteur de TSS (respectivement de LDT) d’index n.
Elles sont dØ nies dans le chier include/asm/system.h :
#define _set_tssldt_desc(n,addr,type) \ Linux 0.01
__asm__ ("movw $104,%1\n\t" \
"movw %%ax,%2\n\t" \
"rorl $16,%%eax\n\t" \
"movb %%al,%3\n\t" \ $" type ",%4\n\t" \
"movb $0x00,%5\n\t" \ %%ah,%6\n\t" \
"rorl $16,%%eax" \48 DeuxiŁme partie : Utilisation du micro-processeur Intel
::"a" (addr), "m" (*(n)), "m" (*(n+2)), "m" (*(n+4)), \
"m" (*(n+5)), "m" (*(n+6)), "m" (*(n+7)) \
)
#define set_tss_desc(n,addr) _set_tssldt_desc(((char *) (n)),addr,"0x89") set_ldt_desc( *) (n)x82")
Autrement dit :
le zØroiŁme mot du descripteur, c’est- -dire la partie basse de la limite, prend la valeur 104
(puisqu’un TSS occupe 104 octets comme nous le verrons au chapitre 6 ; nous verrons dans
ce mŒme chapitre que la LDT ne contient que trois descripteurs sous Linux, qui ne nØcessite
donc que 24 octets) ;
le premier mot du descripteur, c’est- -dire le premier mot de l’adresse de base, prend comme
valeur le mot de poids faible de l’adresse addr;
le quatriŁme octet du descripteur, c’est- -dire le troisiŁme octet de l’adresse de base, prend
comme valeur l’octet de poids faible du mot de poids fort de l’adresse addr;
le cinquiŁme octet du descripteur, c’est- -dire l’octet des droits d’accŁs, prend comme valeur
le type du segment :
89h pour un TSS, soit 1000 1001b, c’est- -dire P = 1 pour prØsent, DPL Øgal ? 0, 0 et
1001b pour TSS 386 disponible (nous dØcrirons la structure des droits d’accŁs au cha-
pitre 6) ;
82h pour une LDT (qui n’est rien d’autre qu’un segment de donnØes), soit 1000 0010b,
c’est- -dire P = 1 pour prØsent, DPL Øgal ? 0, 0 pour descripteur systŁme, E = 0 pour
segment de donnØes, X = 0 pour adresses en ordre croissant, W = 1 pour qu’on puisse
surcharger les donnØes et A = 0 puisqu’on n’a pas pas encore eu l’occasion d’accØder aux
donnØes ;
le sixiŁme octet du descripteur prend la valeur 0, pour G = 0, granularitØ indiquant que la
limite doit Œtre comptØe en octets, B = 0 pour des adresses de dØplacement sur seize bits,
AVL = 0 (bit ? la disposition du systŁme d’exploitation, non utilisØ par Linux) et la partie
haute de la limite Øgale ? 0 ;
le septiŁme et dernier octet du descripteur prend la valeur du quatriŁme octet de l’adresse
de base.
Initialisation de la TSS et de la LDT
Rappel 80386 Pour un processus donnØ, il faut initialiser les registres TR de TSS gr ce ? l’instruction ltr
du micro-processeur Intel et LDTR de la LDT gr ce ? l’instruction lldt. Linux encapsule ces
instructions dans des macros pour ne pas rester au niveau assembleur.
Les macros :
ltr(n)
lldt(n)
permettent, respectivement, de charger la TSS et la LDT du processus numØro n.
Elles sont dØ nies dans le chier include/linux/sched.h :
Linux 0.01 #define ltr(n) __asm__("ltr %%ax"::"a" (_TSS(n))) lldt(n)("lldt %%ax"::"a" (_LDT(n)))Chapitre 4. Prise en compte de la mØmoire Intel 49
Stockage du registre de t che
On a quelquefois besoin de dØplacer le contenu du registre de t che TR. L’instruction str ax Rappel 80386
du langage d’assemblage MASM permet de placer le contenu de TR dans le registre ax. Linux
encapsule cette instruction dans une macro.
La macro str(n) permet de stocker le registre de t che du processus numØro n dans le registre
ax. Elle est dØ nie dans le chier include/linux/sched.h :
#define str(n) \ Linux 0.01
__asm__("str %%ax\n\t" \
"subl %2,%%eax\n\t" \
"shrl $4,%%eax" \
:"=a" (n) \
:"a" (0),"i" (FIRST_TSS_ENTRY<<3))
Positionnement de la limite et de la base d’un segment
On a vu comment initialiser la LDT de chaque processus, avec une limite qui n’est pas adaptØe.
Linux fournit des macros pour changer la limite et la base de celle-ci, ainsi que pour rØcupØrer
ces valeurs.
Les macros suivantes permettent, respectivement, de positionner la base et la limite d’une LDT
et de rØcupØrer celles-ci :
set_base(ldt,base)
set_limit(ldt,limit)
get_base(ldt)
get_limit(segment)
Elles sont dØ nies dans le chier include/linux/sched.h :
#define _set_base(addr,base) \ Linux 0.01
__asm__("movw %%dx,%0\n\t" \
"rorl $16,%%edx\n\t" \
"movb %%dl,%1\n\t" \ %%dh,%2" \
::"m" (*((addr)+2)), \
"m"+4)), \
"m" (*((addr)+7)), \
"d" (base) \
:"dx")
#define _set_limit(addr,limit) \
__asm__("movw %%dx,%0\n\t" \
"rorl $16,%%edx\n\t" \
"movb %1,%%dh\n\t" \
"andb $0xf0,%%dh\n\t" \
"orb %%dh,%%dl\n\t" \
"movb %%dl,%1" \
::"m" (*(addr)), \
"m" (*((addr)+6)), \
"d" (limit) \
:"dx")
#define set_base(ldt,base) _set_base( ((char *)&(ldt)) , base ) set_limit(ldt,limit) _set_limit( ((char *)&(ldt)) , (limit-1)>>12 )
#define _get_base(addr) ({\
unsigned long __base; \
__asm__("movb %3,%%dh\n\t" \
"movb %2,%%dl\n\t" \
"shll $16,%%edx\n\t" \
"movw %1,%%dx" \
:"=d" (__base) \50 DeuxiŁme partie : Utilisation du micro-processeur Intel
:"m" (*((addr)+2)), \
"m" (*((addr)+4)), \
"m")+7))); \
__base;})
#define get_base(ldt) _get_base( ((char *)&(ldt)) )
#define get_limit(segment) ({ \
unsigned long __limit; \
__asm__("lsll %1,%0\n\tincl %0":"=r" (__limit):"r" (segment)); \
__limit;})
2.3 AccŁs ? la mØmoire vive
L’accŁs aux entitØs ØlØmentaires de la mØmoire vive (octet, mot et mot double) se fait gr ce ?
des variantes de l’instruction mov sur les micro-processeurs Intel. Linux encapsule ces variantes
dans des fonctions C.
Les six :
Linux 0.01 #include <asm/segment.h>
unsigned char get_fs_byte(const char * addr); short get_fs_word unsigned short * addr); long get_fs_long(const long * addr);
void put_fs_byte(char val,char * addr); put_fs_word(short val,short * addr);
void put_fs_long(unsigned long val,unsigned long * addr);
permettent respectivement de rØcupØrer un octet, un mot ou un mot double depuis l’empla-
cement mØmoire indiquØ par l’adresse et de placer un octet, un mot ou un mot double ?
l’emplacement mØmoire indiquØ par l’adresse.
L’argument addr correspond ? la valeur du dØplacement dans le segment repØrØ par le registre
de segment fs.
Ces six fonctions sont dØ nies comme fonctions en ligne dans le chier include/asm/
segment.h :
Linux 0.01 extern inline unsigned char get_fs_byte(const char * addr)
{
unsigned register char _v;
__asm__ ("movb %%fs:%1,%0":"=r" (_v):"m" (*addr));
return _v;
}
extern inline unsigned short get_fs_word(const unsigned short *addr)
{
unsigned short _v;
__asm__ ("movw %%fs:%1,%0":"=r" (_v):"m" (*addr));
return _v;
}
extern inline unsigned long get_fs_long(const unsigned long *addr)
{
unsigned long _v;
__asm__ ("movl %%fs:%1,%0":"=r" (_v):"m" (*addr)); \
return _v;
}Chapitre 4. Prise en compte de la mØmoire Intel 51
extern inline void put_fs_byte(char val,char *addr)
{
__asm__ ("movb %0,%%fs:%1"::"r" (val),"m" (*addr));
}
extern inline void put_fs_word(short val,short * addr)
{
__asm__ ("movw %0,%%fs:%1"::"r" (val),"m" (*addr));
}
extern inline void put_fs_long(unsigned long val,unsigned long * addr)
{
__asm__ ("movl %0,%%fs:%1"::"r" (val),"m" (*addr));
}
RemarqueOn remarquera le signe de continuation de ligne prØsent dans la dØ nition de la fonction get_
fs_long() qui n’a pas lieu d’Œtre. Il ne se retrouve pas d’ailleurs dans les autres dØ nitions.
3 volution du noyau
3.1 Prise en compte d’autres micro-processeurs
Linux fut dŁs le dØpart con u de fa on modulaire. Ainsi, lorsque Linus Torvalds eut ? sa
disposition un DEC alpha, il lui fut facile d’adapter son systŁme d’exploitation pour ce micro-
processeur ([TOR-01], p. 168). Depuis, le systŁme d’exploitation a ØtØ portØ pour un grand
nombre de micro-processeurs. Tout ce qui est propre ? l’un d’entre eux se trouve dans le rØper-
toire arch sous le sous-rØpertoire adØquat, par exemple arch/i386 pour le micro-processeur
Intel 80386 et ses successeurs.
Donnons la structure du rØpertoire /arch dans le cas du noyau 2.6.0 pour montrer la diversitØ Linux 2.6.0
des micro-processeurs pris en compte :
/alpha pour le DEC alpha, qui demeure l’un des meilleurs micro-processeurs (un vrai
64 bits) mŒme si celui-ci n’a plus connu d’Øvolution depuis 1993 (il sera remplacØ par
l’Itanium d’Intel lorsque ce dernier sera au point) ;
/arm pour le cØlŁbre micro-processeur britannique, rachetØ par Intel, prØsent dans les PDA
(agendas Ølectroniques), qui exigent une version de Linux occupant peu de mØmoire ;
/arm26 pour la version de ce micro-processeur avec un adressage sur 26 bits ;
/cris pour le micro-processeur ETRAX 100 LX, con u pour les systŁmes embarquØs ;
/h8300 pour lecesseur 8 bits H8/300, Øgalement pour les systŁmes embarquØs ;
/i386 pour les micro-processeurs Intel 32 bits ;
/ia64 pour l’Itanium d’Intel ;
/m68k pour les micro-processeurs 68000 de Motorola et leurs successeurs, utilisØ en particu-
lier par Apple avant de passer au Power PC puis au G3 ;
/m68knommu pour la version des micro-processeurs prØcØdents sans gestion de la mØmoire,
con ue Øgalement pour les systŁmes embarquØs ;
/mips pour le micro-processeur MPIS de Silicon Graphics, utilisØ ? la fois pour les systŁmes
embarquØs et pour des stations de travail haut de gamme ;
/parisc pour le micro-processeur PA-RISC de HP utilisØ pour les stations de travail du
mŒme constructeur ;