Files
ft_linux/docs/sujets/little-penguin.md
2026-10-23 11:07:06 +02:00

18 KiB
Raw Permalink Blame History

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
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 http://eudyptula-challenge.org/

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é :

% 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

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.

#include    <linux/module.h>
#include    <linux/kernel.h>
#include    <linux/delay.h>
#include    <linux/slab.h>

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 :

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?

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

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.

#include    <linux/module.h>
#include    <linux/kernel.h>
#include    <linux/init.h>
#include    <linux/miscdevice.h>
#include    <linux/fs.h>
#include    <linux/slab.h>

// Dont have a license, LOL
MODULE_LICENSE("LICENSE");
MODULE_AUTHOR("Louis Solofrizzo <louis@ne02ptzero.me>");
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é :

$> 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.