# Little Penguin — Linux Kernel Development Traduction française du sujet. Le PDF reste la source en cas de doute. Les sorties de commandes, les noms de fichiers et les deux fichiers C sont recopiés. Pour les espaces du code, les figures C4 et C6 restent l’image du PDF. | | | |--|--| | PDF | [originaux/little_penguin_subject.pdf](originaux/little_penguin_subject.pdf) | | Auteurs | Louis Solofrizzo louis@ne02ptzero.me, 42 Staff pedago@42.fr | | Version | 1.1 | | Date du PDF | 9 mai 2025 | | Pages | 20 | | Résumé (anglais) | This entire project is based on the Eudyptula Challenge. All credits go to little@eudyptula-challenge.org | ## Liens | Ancre | Cible | |-------|--------| | `louis@ne02ptzero.me` | mailto | | `pedago@42.fr` | mailto | | URL de la page de titre | | Le livre *Linux Device Drivers, 3rd Edition* est cité à l’assignment 04, chapitre 14 du livre, sans URL dans le PDF. Les chemins `Documentation/...` sont des chemins dans l’arbre des sources du noyau, pas des liens web. --- ## I. Préambule ### I.1 Extrait de `Documentation/CodingStyle` Le PDF ouvre sur le titre « Linux kernel coding style », puis colle un extrait. C’est un court document qui décrit le style de code préféré pour le noyau Linux. Le style est très personnel, et l’auteur ne *forcerait* pas ses vues sur quiconque (le PDF souligne `_force_`), mais c’est le standard de ce qu’il maintient, et il préférerait qu’il s’applique aussi à la plupart des autres projets. Merci au moins de considérer les points faits ici. D’abord, il recommande d’imprimer un exemplaire des GNU coding standards, puis de ne PAS le lire. Le brûler — c’est un beau geste symbolique. Le PDF ajoute, de son cru : « ;) ok, it’s definitely not an eco-responsible move. » Autrement dit : d’accord, ce n’est clairement pas un geste éco-responsable. Bref, commençons. Chapitre 1 : Indentation. Les tabulations font 8 caractères de large, donc les indentations aussi. Il existe des tentatives mal avisées d’indenter sur 4 caractères, voire 2. C’est comme essayer de définir PI comme valant 3. ## II. Introduction Ce « challenge » est une série d’exercices de programmation du noyau Linux, qui commence petit et monte en complexité. Si tout se passe bien, à la fin on sera assez qualifié pour maintenir un sous-système, si on le souhaite. Peut-être pas mainteneur complet, mais assez compétent pour identifier les problèmes causés par son mainteneur préféré. Ce qui peut être encore plus amusant que d’être aux commandes. ## III. Objectifs - Compiler un noyau personnalisé. - Construire et utiliser un module noyau. - Apprendre comment les drivers fonctionnent sous Linux. ## IV. Instructions générales - Ce sujet ressemble à une journée de Piscine. Certaines tâches sont assez difficiles : prendre son temps. - Tout le travail doit être fait sur la distribution Linux personnalisée. Si on n’en a pas, le sujet demande ce qu’on fait là. - Attention. Certaines tâches ne demandent pas de rendre du code, mais une forme de preuve. ## V. Assignment 00 Retirer les petites roues et construire son propre noyau. Plus question de s’appuyer sur des versions précompilées. Pour cette tâche, il faut faire tourner son propre noyau — et utiliser Git. Passionnant, non ? Non ? Bon... d’accord. Le PDF écrit : « Exciting, right? No? Well... okay. » ### À faire - Télécharger le dernier arbre Git de Linus depuis git.kernel.org. Il faut trouver lequel est le sien. Le sujet dit que ce n’est pas dur : se souvenir de son nom de famille. - Le construire, l’installer et booter dessus. La configuration est libre, mais il faut activer `CONFIG_LOCALVERSION_AUTO=y`. ### À rendre - Le fichier de log de boot du noyau. - Le fichier `.config`. ## VI. Assignment 01 ### À faire Créer un module noyau « Hello World » avec le comportement suivant. Bloc recopié : ```text % sudo insmod main.ko % dmesg | tail -1 [Wed May 13 12:59:18 2015] Hello world! % sudo rmmod main.ko % dmesg | tail -1 [Wed May 13 12:59:24 2015] Cleaning up module. % ``` Attention : le module doit compiler sur n’importe quel système. Le PDF marque l’indice ainsi : `(<– version compatibility hint)`. ### À rendre - Makefile et code source. Chaînes exactes : `Hello world!`, `Cleaning up module.`, fichier `main.ko`. ## VII. Assignment 02 ### À faire - Prendre l’arbre Git du noyau de l’assignment 00 et modifier le Makefile pour changer le champ `EXTRAVERSION`. Après modification, reconstruction et reboot, la chaîne de version du noyau qui tourne doit contenir `-thor_kernel`. ### À rendre - Log de boot du noyau. - Un patch du Makefile d’origine, selon les standards de soumission Linux (`Documentation/SubmittingPatches`). ## VIII. Assignment 03 Bien joué d’être arrivé jusque-là. Le sujet espère qu’on s’amuse encore. On s’ennuie un peu, à force de seulement booter et installer des noyaux ? Alors il est temps de quelque chose de plus pédant — histoire de rappeler à quel point ces compilations de noyau sont amusantes. ### À faire - Modifier le fichier C suivant pour qu’il respecte le style de code Linux (voir `Documentation/CodingStyle`). ### À rendre - La version mise à jour du fichier C. Le fichier est sur la page suivante du PDF. ![Listing C sur fond noir, en-tête Little Penguin / Linux Kernel Development](captures/04-little-penguin-assignment-03-11.png) **Fig. C4 — assignment 03, page 10.** En-tête de page : « Little Penguin » à gauche, « Linux Kernel Development » à droite. Aucune autre légende. Interprétation : c’est le fichier C à remettre au style du noyau. Le fond noir et la coloration ne font pas partie du fichier à rendre. La transcription sous l’image reprend le texte. Si un espace diverge, l’image fait foi. ```c #include #include #include #include int do_work(int *my_int, int retval) { int x; int y = *my_int; int z; for (x = 0; x < my_int; ++x) { udelay(10); } if (y < 10) /* That was a long sleep, tell userspace about it */ pr_info("We slept a long time!"); z = x * y; return z; return 1; } int my_init(void) { int x = 10; x = do_work(&x, x); return x; } void my_exit(void) { } module_init(my_init); module_exit(my_exit); ``` Chaîne exacte dans le code : `We slept a long time!` ## IX. Assignment 04 Tu as survécu au chaos du style de code — bien joué. Passons à quelque chose de plus concret, parce que le sujet devine qu’on commence à s’ennuyer. Le PDF met des guillemets à « real ». ### À faire - Modifier le module de l’assignment 01 pour qu’il soit chargé automatiquement quand n’importe quel clavier USB est branché. Le déclencheur est l’outil de hotplug de l’espace utilisateur adapté à la distribution : `depmod`, `kmod`, `udev`, `mdev` ou `systemd`. ### À rendre - Un fichier de règles, adapté au système. - Le code mis à jour. - Une preuve que le module fonctionne comme prévu. Le sujet dit que ça a l’air simple et que c’est un peu piégeux. Indice : chapitre 14 du livre *Linux Device Drivers, 3rd Edition*. Il est librement disponible en ligne, pas besoin de l’acheter. Le PDF écrit : « no purchase required ». ## X. Assignment 05 Bien joué pour le chargement automatique du module. Ces macros de hotplug peuvent être piégeuses, mais les maîtriser est utile, surtout dans du vrai développement noyau. En parlant de vrai développement — écrivons du code digne de ce nom. ### À faire - Reprendre le module de l’assignment 01 et en faire un driver de périphérique caractère `misc`. L’interface misc est un moyen très simple de créer un périphérique caractère sans s’emberlificoter dans sysfs et l’enregistrement de devices. Le sujet demande qu’on le croie : c’est bien plus simple comme ça. Texte du PDF : « Trust me, it’s way easier this way! » - Le device misc est créé avec un numéro mineur dynamique. Inutile de s’acharner à réserver un mineur statique pour un module de test. Ce serait une corvée pour rien. - Implémenter `read` et `write`. - Le nœud doit apparaître dans `/dev/fortytwo`. - En lecture, le device retourne le login étudiant à l’appelant. - En écriture, les données sont comparées au login étudiant. Si ça correspond, l’écriture réussit. Sinon, une erreur « invalid value ». - Enregistrer le device misc au chargement du module, et le désenregistrer au déchargement. ### À rendre - Le code mis à jour. - Une forme de preuve. Libellés exacts : `misc`, `/dev/fortytwo`, `invalid value`. ## XI. Assignment 06 Bien joué pour le driver misc — plutôt propre et simple, non ? Au moment où l’on croyait que le défi ne parlait que de code dans le noyau, on revient à un sujet précédent. Eh oui : reconstruire des noyaux. Ça reflète la réalité. Les développeurs noyau passent souvent plus de temps à recompiler qu’à écrire du code nouveau. Ce n’est pas glorieux, mais c’est une compétence vitale. ### À faire - Télécharger le dernier noyau linux-next. Il change tous les jours : prendre la version la plus récente. Le construire et booter dessus. ### À rendre - Le log de boot du noyau. Qu’est-ce que le noyau linux-next ? Ça fait partie du défi. Premier indice, recopié : consulter l’excellente documentation sur le processus de développement du noyau dans `Documentation/development-process/`, dans l’arbre des sources. C’est une bonne lecture — on y apprend beaucoup sur la façon de travailler des développeurs noyau. Le PDF enchaîne un second indice, presque le même : il faudrait lire l’excellente documentation sur la façon dont le noyau Linux est développé, dans `Documentation/development-process/`, dans les sources elles-mêmes. C’est une très bonne lecture, et elle devrait dire tout ce qu’on n’a jamais voulu savoir sur ce que font les développeurs du noyau Linux, et comment ils le font. ## XII. Assignment 07 On reviendra au noyau linux-next dans une tâche ultérieure, donc ne pas supprimer ce répertoire : on en aura encore besoin. Pour l’instant, assez de compilations de noyau. Écrivons davantage de code. Cette tâche ressemble à l’assignment 05, où l’on a créé un device misc. Cette fois, une autre interface entre l’utilisateur et le noyau : debugfs. La rumeur dit que le créateur de debugfs aurait affirmé que la seule règle est : « Il n’y a pas de règles. » Le PDF écrit : « There are no rules. » Le sujet propose de tester cette théorie. La distribution doit monter debugfs sur `/sys/kernel/debug/`. Sinon, la monter avec la commande recopiée : ```text mount -t debugfs none /sys/kernel/debug/ ``` Il faut que ce soit activé dans le noyau avec l’option `CONFIG_DEBUG_FS`, parce qu’on en aura besoin pour cette tâche. ### À faire - Modifier le module de l’assignment 01 pour créer un sous-répertoire debugfs nommé `fortytwo`. - Dans ce répertoire, trois fichiers virtuels : `id`, `jiffies` et `foo`. - `id` : même comportement que l’assignment 05. Lisible et inscriptible par tous les utilisateurs. - `jiffies` : lecture seule pour n’importe quel utilisateur. La lecture retourne la valeur courante du timer `jiffies` du noyau. - `foo` : inscriptible seulement par root, lisible par tout le monde. Les données écrites sont stockées, jusqu’à une page. La lecture retourne les données stockées. Verrouillage correct pour les lectures et écritures concurrentes. - Au déchargement du module, tous les fichiers debugfs sont nettoyés et la mémoire allouée est libérée. - Note du sujet : le répertoire debug doit être lisible globalement. Comme il n’y a pas d’option pour ça, utiliser le bon vieux `chown`. Le PDF écrit : « use good old chown ». ### À rendre - Le code. - Une preuve que le module fonctionne comme prévu. ## XIII. Assignment 08 Bien joué pour cette tâche debugfs. On ralentit un peu, et on revient au style de code. ### À faire - Prendre le fichier suivant, corriger son style, et corriger son comportement. ### À rendre - Le fichier C mis à jour et conforme au style. ![Page Assignment 08 et encadré bleu : But wait—what is this code supposed to do?](captures/05-little-penguin-assignment-08-17.png) **Fig. C5 — assignment 08, page 16.** L’encadré bleu porte exactement : « But wait—what is this code supposed to do? » En français : mais attends, qu’est-ce que ce code est censé faire ? Interprétation : le sujet ne décrit pas le comportement attendu. La phrase sous l’encadré dit que ça fait partie du défi, et de s’amuser à le découvrir. Le PDF écrit : « That’s part of the challenge. Have fun figuring it out! » ![Listing C du module reverse, fond noir](captures/05-little-penguin-assignment-08-18.png) **Fig. C6 — page 17.** Même en-tête que la fig. C4 : « Little Penguin », « Linux Kernel Development ». Interprétation : c’est le fichier à restyler et à corriger. Le device s’y nomme `reverse`. Le numéro de page imprimé près de `module_init` n’appartient pas au code. Si un espace diverge, l’image fait foi. ```c #include #include #include #include #include #include // Dont have a license, LOL MODULE_LICENSE("LICENSE"); MODULE_AUTHOR("Louis Solofrizzo "); MODULE_DESCRIPTION("Useless module"); static ssize_t myfd_read (struct file *fp, char __user *user, size_t size, loff_t *offs); static ssize_t myfd_write(struct file *fp, const char __user *user, size_t size, loff_t *offs); static struct file_operations myfd_fops = { .owner = THIS_MODULE, .read = &myfd_read, .write = &myfd_write }; static struct miscdevice myfd_device = { .minor = MISC_DYNAMIC_MINOR,.name = "reverse", .fops = &myfd_fops }; char str[PAGE_SIZE]; char *tmp; static int __init myfd_init (void) { int retval; retval = misc_register(&(*(&(myfd_device)))); return 1; } static void __exit myfd_cleanup (void) { } ssize_t myfd_read (struct file *fp, char __user *user, size_t size, loff_t *offs) { size_t t, i; char *tmp2; /*************** * Malloc like a boss ***************/ tmp2 = kmalloc(sizeof(char) * PAGE_SIZE * 2, GFP_KERNEL); tmp = tmp2; for (t = strlen(str) - 1, i = 0; t >= 0; t--, i++) { tmp[i] = str[t]; } tmp[i] = 0x0; return simple_read_from_buffer(user, size, offs, tmp, i); } ssize_t myfd_write (struct file *fp, const char __user *user, size_t size, loff_t *offs) { ssize_t res; res = 0; res = simple_write_to_buffer(str, size, offs, user, size) + 1; // 0x0 = '\0' str[size + 1] = 0x0; return res; } module_init(myfd_init); module_exit(myfd_cleanup); ``` Libellés dans le code, à ne pas « corriger » avant d’avoir lu la capture : `LICENSE`, `Useless module`, `reverse`, `Dont have a license, LOL`, `Malloc like a boss`. Le nom du device dans ce fichier est `reverse`, pas `fortytwo`. ## XIV. Assignment 09 Ouf... Le sujet ne sait pas qui a écrit ce dernier fichier, mais quand même. Bref, on retourne écrire quelque chose de plus sensé. ### À faire - Créer un module qui liste les points de montage du système, avec le nom associé. - Le fichier doit s’appeler `/proc/mymounts`. Exemple recopié : ```text $> cat /proc/mymounts root / sys /sys proc /proc run /run dev /dev ``` ### À rendre - Le code source du module et un Makefile. Ce n’est pas une tâche dure, mais elle peut être piégeuse. Le sujet renvoie à la documentation sur les points de montage, le listage de répertoires, et le parcours de listes chaînées dans le noyau. Et surtout, amuse-toi :) Le PDF écrit : « And above all—have fun :) » ## XV. Rendu et évaluation par les pairs Rendre le projet dans le dépôt Git, comme d’habitude. Seul le contenu du dépôt est pris en compte pendant l’évaluation. Vérifier les noms de dossiers et de fichiers. --- ## Grille de lecture ### Obligatoire Tout se fait sur la distribution personnalisée (celle de ft_linux). | Exercice | Travail | Rendu | |----------|---------|--------| | 00 | Arbre Git de Linus, build, install, boot. `CONFIG_LOCALVERSION_AUTO=y` | log de boot, `.config` | | 01 | Module `main.ko`, messages `Hello world!` et `Cleaning up module.` Compile sur n’importe quel système | Makefile, sources | | 02 | `EXTRAVERSION` tel que la version qui tourne contient `-thor_kernel` | log de boot, patch au format `Documentation/SubmittingPatches` | | 03 | Mettre le fichier C au style `Documentation/CodingStyle` | fichier C | | 04 | Chargement auto du module au branchement d’un clavier USB, via l’outil hotplug de la distro | fichier de règles, code, preuve | | 05 | Device misc `/dev/fortytwo`, mineur dynamique, read = login, write = login ou erreur `invalid value` | code, preuve | | 06 | Dernier linux-next, build et boot | log de boot | | 07 | debugfs `fortytwo` avec `id`, `jiffies`, `foo`. `CONFIG_DEBUG_FS`. Montage `/sys/kernel/debug/` | code, preuve | | 08 | Style et comportement du fichier `reverse` | fichier C | | 09 | `/proc/mymounts` | sources, Makefile | ### Bonus Le PDF n’a pas de chapitre bonus. ### Interdit, ou hors du rendu - Faire le projet ailleurs que sur la distribution personnalisée. - Rendre autre chose que ce qui est dans le dépôt Git. - Pour 00, 02 et 06, le rendu demandé est une preuve (log, config, patch), pas seulement du code. - Inventer le comportement de l’assignment 08 : le sujet le laisse à découvrir. ### Ce que la distro doit déjà savoir faire pour que ces exercices soient possibles Ces points ne sont pas une liste de paquets de ft_linux. Ce sont les besoins écrits dans Little Penguin : - Git, et un moyen de récupérer git.kernel.org puis linux-next. - Compiler, installer et booter un noyau qui n’est pas celui livré avec la distro. - Charger et décharger des modules (`insmod`, `rmmod`, `dmesg`). - Un mécanisme de hotplug parmi `depmod`, `kmod`, `udev`, `mdev`, `systemd`. - USB, au moins pour un clavier. - debugfs compilé et montable, `/proc`, `/dev`, `/sys`. - `sudo` apparaît dans l’exemple de l’assignment 01.