GNU/Hurd Internals Guide

De HurdFr_Wiki
(Redirigé depuis HIG)
Aller à : Navigation, rechercher

Le principe du GNU/Hurd Internals Guide est simple : c'est une sorte de wikibook décrivant le fonctionnement interne de GNU/Hurd en détail. Son intérêt est multiple :


  • Motiver les adhérents à choisir un sujet précis du Hurd (plus ou moins large, selon qu'il s'agit d'une partie, sous-partie, sous-sous-partie), et à travailler, seul ou en groupe, à la comprendre, en se plongeant dans la documentation, les archives des listes, le code source ;
  • Donner lieu à des présentations informelles lors de réunions, permettant de discuter, tester ses connaissances, informer, et améliorer le contenu de la partie choisie ;
  • Obtenir un document de référence sur le fonctionnement de GNU/Hurd, et non seulement sur les interfaces.


Pour cela, un effort de rédaction considérable est nécessaire.

La rédaction du guide s'effectuera en deux étapes :

  • D'abord la création d'une table des matières plus ou moins grossière, destinée à évoluer ;
  • Puis, la rédaction du contenu, petit à petit, qui aménera à changer la table des matières.


Nous en sommes actuellement à l'étape 1 : rédaction de la table des matières. Cependant, pour commencer, nous aborderons le Hurd composant par composant, en suivant les noms des répertoires présents dans les sources du Hurd.


Voici quelques règles à suivre pour la rédaction :

  • Les parties doivent être sectionnées de cette manière

= Chapitre =

== Partie ==

=== Sous-Partie ===


  • Marquez les mots importants, avec du gras
  • Si vous donnez des références, ou exemples, utilisez de l'italique

Sur ce, bonne rédaction !


Sommaire


Remarques générales

Démarrage de GNU/Hurd

FIXME : notes générales.

Grub

GNU Mach

Quand Grub passe la main à GNU Mach, tout commence dans <i386/i386at/boothdr.S:boot_entry> qui positionne la pile d'interruptions et appelle immédiatement <i386/i386at/model_dep.c:c_boot_entry ()>. Elle réalise d'abord les initialisations diverses nécessaires au démarrage, via la fonction i386at_init () : PTE, GDT, IDT, LDT, TSS, ... Elle initialise ensuite les différents sous-systèmes dont GNU Mach est composé : IPC, VM, scheduler, pilotes Linux, task et thread, via setup_main (). Cette fonction appelle ensuite start_kernel_threads (), qui crée :

  1. un idle thread par CPU
  2. un thread chargé de la destructions des threads en espace utilisateur (reaper)
  3. un thread chargé de mettre en mémoire principale les threads à exécuter (swapin)
  4. un thread pour l'ordonnanceur (sched)

Il initialise ensuite le support pour les périphériques, soit :

  1. net_io pour la gestion du réseau (drivers et réception des paquets), ainsi qu'un thread dédié à la réception de paquets
  2. pager pour la gestion des memory objects et de la pagination
  3. chario pour la gestion des TTY
  4. un thread pour réaliser le nettoyage automatique lorsque les opérations d'entrée/sortie sont terminées

Une fois ces initialisations terminées, GNU Mach se charge d'amorcer le reste du système. Ceci se passe dans la fonction <kern/bootstrap.c:bootstrap_create ()>, qui analyse les lignes module passées par Grub pour appeler les fonctions précisées en ligne de commande (task-create, task-resume) et substituer les variables entre ${} (kernel-command-line, host-port, ...). Une fois cette analyse faite, chaque ligne est exécutée dans la fonction <kern/boot_script.c:boot_script_exec ()> via la fonction <kern/bootstrap.c:boot_script_exec_cmd ()>, qui crée un thread pour chaque chargement de module. Ce thread crée une tâche, charge l'exécutable ELF (obtenu en lisant à l'adresse indiquée par Grub via multiboot) à l'emplacement indiqué (fonction <kern/elf-load.c:exec_load ()>), met en place leur pile avec les arguments indiqués en ligne de commande puis la suspend (task_suspend ()).

Quand le chargement de la tâche est fini, chaque thread noyau chargé de lancer un module appelle <i386/i386/locore.S:thread_bootstrap_return>, qui passe de la pile du noyau à la pile contenue dans le PCB (Process Control Block) puis passe en espace utilisateur pour démarrer chacune des tâches.

Le Hurd

ext2fs : chargé via Grub, invoqué par le noyau. Sait qu'il doit se charger du lancement du système parce qu'il s'est vu passer l'argument --multiboot-command-line.



Notes :
- exec_tid est fourni par --exec-server-task


init : charge tout d'abord auth et proc, retransmet le contrôle au serveur de fichiers et reprend la main pour finir la phase de boot.

                                                    main ()
                                                         |
        file_exec ('/hurd/proc')------|---- file_exec ('/hurd/auth')
                            |                            |                         |
        ext2fs (lecture et exécution)   |                      ext2fs (lecture et exécution)
                            |                            |                          |
        proc (initialisation)                  |                      auth (initialisation)
                            |                            |                          |
        startup_procinit                      |                      startup_authinit ()   
                            |                            |                          |
                            |---------------|--------------|
                                                         |
                                          launch_core_servers () -------- |--  proc_child (proc, bootfs) (déclare le système de fichiers de démarrage à proc)
                                                                                                |--  proc_child (proc, auth) (déclare auth à proc)
                                                                                                |
                                                                                                |-- fsys_init (bootfs, proc_handle, auth_handle)

Draft par KiBi, à améliorer/terminer :

retour à ext2fs :

 diskfs_S_fsys_init () ------|-- proc_child (proc, exec)
                                             |
                                             |-- exec_init ()
                                             |
                                             |-- startup_essential_task ('exec')

retour à init :

 S_startup_essential_task -----|-- attente de l'appel de startup_essential_task () par auth et proc'.
                                                   |
             ---------------------|
             |
  launch_system ()
             |
  launch_something ()
             |
  file_exec ('/libexec/runsystem') || file_exec (/bin/sh) | file_exec (/bin/shd)
             

/libexec/runsystem : ce script est censé tourner sans s'arrêter. Lorsqu'il s'arrête, init considère qu'il s'agit là d'une condition d'erreur grave et lance un shell à la place, comme dans le mode single user.

Son premier rôle est d'analyse les options données sur la ligne de commande du noyau, que init lui passe en argument. S'il y trouve l'option -s, son rôle est principalement de lancer un shell. Dans tous les cas, il exécute programme runttys, auquel il envoie successivement les signaux TERM, INT, HUP et TSTP. Ce programme lit le contenu de /etc/ttys et lance en fonction les commandes destinées à mettre en place la console. Si -s n'est pas présent, il passe le relai à /libexec/rc, avec l'argument autoboot par défaut, sans si -f est ajouté.

/libexec/rc fait office de script de démarrage unique, faute d'une solution meilleure comme DMD. Il lance donc mach-defpager, ajoute les partitions d'échange, lance fsck, nettoie /tmp, puis lance syslogd, inetd et sendmail. À ce moment, le système est entièrement démarré.

Le Hurd

Les serveurs de base

auth

auth est le serveur d'authentification du Hurd. Il agit comme l'autorité de confiance que les serveurs utilisent pour vérifier les permissions dont dispose le serveur avec lequel elle entreprend une communication. Il tourne en root. Actuellement, auth ne gère que les UIDs POSIX (avec la différence qu'à chaque processus est attaché un jeu d'UIDs et de GIDs et non un seul), et la façon d'obtenir ces jetons (il s'agit en fait d'un port sur auth, renvoyé par auth_makeauth ()) est l'héritage par le parent ou l'utilisateur du serveur password. Cependant, le concept est extensible à tout jeton et toute méthode d'authentification. Reportez-vous à cette présentation pour des informations plus détaillées.

Ce serveur est un des deux seuls du Hurd à ne pas être un translator : on communique avec lui à travers un port spécial hérité par son parent et récupérable par la fonction getauth (). En effet, c'est à ce port sur le serveur auth que sont associées les permissions dont dispose la tâche. Ce serveur implémente le sous-système MiG `auth' (25000). Il est disponible dans $(HURD)/auth.

password

password est le serveur de mot de passes. Il implémente le sous-système password (38000), qui contient deux appels : password_check_user (), qui vérifie à l'aide de getpass () que le mot de passe fourni est bien celui de l'utilisateur demandé (correspondance dans /etc/shadow) ; si c'est le cas, il renvoie un port sur auth avec les droits correspondants. L'appel password_check_group () réalise la même opération pour un groupe, en vérifiant le mot de passe avec /etc/gshadow.

password est un translator, puisqu'il écoute par défaut sur /servers/password. Il n'implémente pas les fonctions habituelles du système de fichiers, pour lesquelles il renvoie systématiquement EOPNOTSUPP'. Son code se trouve dans trans/password.c.

boot

boot est le serveur de bootstrapping. Il n'est pas utilisé au démarrage de GNU/Hurd, mais pour démarrer un sous-Hurd ou un co-Hurd, c'est à dire démarrer de nouvelles instances des serveurs du Hurd. Ceci permet de tester sans redémarrer des modifications sur des serveurs, notamment. Cette possibilité nécessite de disposer des droits root, dans la mesure où elle nécessite l'accès à des ports privilégiés de GNU Mach (master device & host port). Pour plus d'informations, voir le Hurd Reference Manual.

boot implémente les sous-systèmes io (21000) et term (28000) et les sous-systèmes noyau device (2800) et notify (64).

init

init est le serveur qui est chargé de lancer les serveurs principaux au démarrage du Hurd. Lancé par le système de fichiers de démarrage (voir chapitre sur le démarrage de GNU/Hurd), il se charge de lancer les serveurs proc et auth, s'assure que exec a bien été lancé et passe ensuite la main à la tâche suivante, généralement /libexec/runsystem (ou /bin/sh à défaut).

console

console est la partie serveur de la console en espace utilisateur du Hurd. C'est elle qui fournit les consoles virtuelles (en nombre illimité) utilisées ensuite par le serveur term (par le moyen des ioctls de la classe `t', c'est à dire les TIO*). Il permet de s'attacher ou de se détacher de n'importe quelle console virtuelle à n'importe quel moment, supporte tous les encodages supportés par iconv (il utilise Unicode en interne et UTF-8 est son encodage par défaut). Il est installé comme /hurd/console et écoute habituellement sur /dev/vcs, où il fournit une interface I/O classique par l'intermédiaire de netfs.

Son client, aussi dénommé console (répertoire console-client), mais installé comme /bin/console, se charge de toutes les entrées/sorties liées à la console, en relation avec le serveur de console. Il est entièrement extensible puisqu'il utilise des modules chargés dynamiquement, précisés en ligne de commande via l'option -d. Actuellement, ces modules se divisent principalement en deux catégories : les plugins de sortie (vga en console, ncursesw dans un terminal ou via SSH, mais également generic_speaker pour l'utilisation du speaker PC) et d'entrée (pc_kbd pour un support basique du clavier, xkb pour un support utilisant les keymaps gérés par l'extension X11 XKEYBOARD (xkb), pc_mouse pour un support de la souris). Le client console agit également comme répétiteur pour les autres programmes pouvant nécessiter un accès direct au matériel, comme Xorg. Pour ce faire, il écoute sur un nÅ“ud précisé en ligne de commande (/dev/cons par défaut) où il fournit les fichiers kbd et mouse, à l'aide de netfs.

term

term est le translator d'émulation de terminal. Il implémente principalement les interfaces term (28000), tioctl (156000) et les interfaces standards pour le système de fichiers. On communique avec lui principalement via les TIO* pour les contrôles et les appels I/O classiques pour le reste, qu'il traduit soit en appels à Mach lorsqu'il est précisé qu'il doit écrire sur un device (backend devio), soit en agissant comme un proxy évolué lorsqu'il est rattaché à une console virtuelle fournie par console (backend hurdio), soit en utilisant les interfaces spécifiques pour les pseudo-tty (backend ptyio).

mach-defpager

mach-defpager est le pagineur par défaut du Hurd, en espace utilisateur. Il implémente le sous-système default_pager (2275) et se charge de passer sur une partition de swap les objets que Mach décide d'évincer de la mémoire principale. Son code est réparti entre le répertoire $(HURD)/mach-defpager et le répertoire $(HURD)/serverboot.

exec

exec est le serveur d'exécution. C'est lui qui crée la tâche (espace d'adressage) Mach, qui crée les ports correspondants (ports sur proc, auth, port de bootstrap), gère l'héritage de privilèges, l'enregistre auprès de proc et analyse le fichier pour lancer l'intérpréteur au besoin (présence d'un hashbang ou non), et réalise le chargement de l'exécutable ELF dans l'espace d'adressage pour lui passer la main ensuite.

proc

proc est le serveur de gestion des processus. Il implémente principalement l'interface process (24000). Ce serveur est un élément clé de la personnalité POSIX du Hurd, puisque Mach ne connaît pas le concept de processus mais seulement celui de tâche (un espace d'adressage qui contient des ressources, comme des threads et des ports). Les processus sont donc, pour proc, des tâches Mach accompagnées de tous les renseignements POSIX :

  • PID, avant tout
  • permissions attachées (UIDs, GIDs)
  • place dans la hiérarchie : processus parent, processi enfants
  • informations sur les groupes de processus et les sessions
  • environnements (envp), arguments (argv)
  • ...

Les interfaces fournies par proc permettent soit la création et gestion des processus (proc_child (), proc_task2proc (), proc_wait (), ...), soit d'obtenir des informations sur ces processus (proc_getprocinfo (), proc_get_procenv (), ...), soit de manipuler les concepts plus généraux de sessions ou de groupes de processus (proc_getsid (), proc_setpgrp ()). proc dispose d'informations sur toutes les tâches du système, puisque leur enregistrement est semi-automatique. En effet, lors de l'appel à proc_task2proc () ou à proc_getallpids (), proc récupère l'ensemble des tâches par l'appel noyau processor_set_tasks (). Il leur assigne automatiquement une entrée dans proc (et un pid). Cependant, c'est proc_child () qui assure l'enregistrement réel d'un processus auprès de proc, puisqu'il permet de l'insérer dans la hiérarchie et d'en déduire ses permissions et ses groupes de processus. Ces appels sont réalisés automatiquement par les fonctions POSIX de la GNU C Library, fork (). Ainsi, en n'utilisant pas ces fonctions, il est possible de créer des tâches en dehors du sous-système POSIX du Hurd.

Les programmes standard n'ont habituellement pas à utiliser proc : pour la gestion des processus, les fonctions POSIX standard suffisent généralement, et pour la récupération d'informations sur les processus, ils peuvent utiliser libps.

proc, comme auth, est un serveur et non un translator. Chaque processus lancé par exec hérite d'un port sur proc auquel est associée son entrée dans ce serveur.

pfinet

pfinet est le translator qui fournit la pile TCP/IP du Hurd. La pile à proprement parler est constituée par le code presque verbatim de la pile de Linux 2.2.12. Ce code est interfacé avec le reste du système par l'ajout d'un netdevice (périphérique réseau) par lequel pfinet transmet les paquets reçus par Mach et envoie à Mach les paquets traités par la pile.

pfinet implémente principalement trois interfaces :

  1. socket (26000) pour la création, la destruction des sockets et toutes les opérations spécifiques à ceux-ci : bind (), listen (), mais aussi recv () et send () ;
  2. io (21000) pour permettre aux applications d'utiliser les fonctions d'entrée/sortie standards (read (), write (), ...) sur les sockets[1]
  3. iioctl (ioctls de la classe `i', 112000) pour les ioctls permettant de manipuler l'état des interfaces réseau ; les ioctls choisies sont celles de Linux. Il s'agit notamment d'appels pour changer le masque de sous-réseau, les flags d'une interface, etc.

Elle implémente également l'interface pfinet (37000) par lequel transitent les ioctls par lesquelles transitent des données de taille variable. En effet, l'implémentation du Hurd de la fonction ioctl () ne permet que de passer des données en inline (à l'intérieur du message Mach), ce qui nécessite d'en connaître la taille au moment de la définition de l'ioctl ; les ioctls nécessitant un passage de donnée en out-of-line (à l'extérieur du message, ce dernier ne contenant qu'un pointeur vers les données) doivent faire l'objet d'une déclaration dans la GNU C Library, qui transmet alors les données au serveur via un RPC. Ces RPCs sont définis, pour pfinet, dans l'interface pfinet. Un exemple d'une telle interface est SIOCGIFCONF, qui retourne la liste des interfaces réseau.

pfinet écoute sur le noeud /servers/socket/2, 2 étant le code pour la famille de protocoles IP (PF_INET). C'est ainsi que la GNU C Library sait où contacter pfinet, puisqu'elle contacte le serveur écoutant sur /servers/socket/ suivi du numéro de la famille de protocoles. Ainsi, le futur pfinet6 devrait écouter par défaut sur /servers/socket/26, pour permettre aux applications utilisant les appels POSIX de fonctionner en IPv6.

Enfin, pfinet récupère ses paquets par l'intermédiaire de l'interface Mach device_set_filter (), qu'il est seul à utiliser de tous les serveurs du Hurd. Cette interface permet de positionner un filtre indiquant quels paquets doivent être envoyés sur un port précisé dans l'appel. Dans le cas des interfaces réseau, les filtres sont au format BPF ou NETF. L'utilisation de cette interface, plutôt que l'habituel device_read () permet de fonctionner paquet par paquet (un message est envoyé par paquet) plutôt que bloc par bloc, ce qui nécessiterait de recomposer les paquets reçus en plusieurs appels. pfinet positionne donc un filtre lui permettant de récupérer tous les paquets.

storeio

storeio est un translator très simple et pourtant fondamental. Son rôle est de traduire les appels I/O standards, obtenus via trivfs, en appels à des stores (via la bibliothèque libstore). Ainsi, un io_read est traduit en store_read, etc. storeio permet également de garder un cache de données, afin d'éviter les lectures bloquantes sur les stores correspondants.

storeio est particulièrement utilisé pour le store device, qui permet d'accéder à des périphériques Mach. Ainsi, /dev/hd0 est un fichier où écouter storeio, qui a pour charge de transmettre les opérations sur ce fichier au périphérique Mach correspondant. Cependant, il est également utilisé avec le store partition pour les /dev/hdXsY et peut être utilisé pour tous les types de store.

Les bibliothèques pour les translators

trivfs

netfs

diskfs

Les systèmes de fichiers

ext2fs

ext2fs est le principal serveur de fichiers du Hurd, celui qui implémente le système de fichiers ext2.

ufs

fatfs

fatfs est un translator permettant d'utiliser des systèmes de fichiers de type FAT.

isofs

isofs est le translator permettant d'utiliser des systèmes de fichiers de type ISO 9660 (CDs de données).

nfs & nfsd

Les translators annexes

ftpfs

ftpfs est un translator simple permettant d'accéder à un serveur FTP de façon transparente, via le système de fichiers.

hostmux

hostmux est un serveur qui permet de se greffer par dessus un translator prenant en argument un nom d'hôte (ftpfs ou httpfs, par exemple), afin de faire lui-même le multiplexage par hôte. Il fournit en effet un répertoire (via netfs) où l'accès à un fichier (tout appel résultant en un netfs_lookup_node) l'amène à vérifier que l'hôte est valide (qu'il résout bien), et si c'est le cas à lancer le translator fourni en argument sur cet hôte. Voir la page Translators pour un exemple concret.

usermux

tmpfs

fakeroot

fifo

ifsock

crash

magic

null

streamio

symlink

firmlink

fwd

Les bibliothèques utilitaires

libports

libthreads

libpager

libps

libstore

libfshelp

libiohelp

libihash

Les utilitaires

FIXME: utils/* sutils/* en triant.

GNU Mach


Erreur de référence : Des balises <ref> existent, mais aucune balise <references/> n’a été trouvée.
Outils personnels
Espaces de noms

Variantes
Actions
Navigation
Outils