# 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 le style (espaces, retours), les captures C4 et C6 font foi : l’extraction texte aplatit une partie de l’indentation, et c’est justement ce style qu’il faudra corriger.
| | |
|--|--|
| Fichier d’origine à la racine | `little_pinguin sujet.pdf` |
| Copie de travail | [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 |
Visuels : [C1](captures/01-couverture-42.png), [C2](captures/02-habillage-page.png), [C4](captures/04-little-penguin-assignment-03-11.png), [C5](captures/05-little-penguin-assignment-08-17.png), [C6](captures/05-little-penguin-assignment-08-18.png).
## Liens
| Ancre | Cible |
|-------|--------|
| `louis@ne02ptzero.me` | mailto |
| `pedago@42.fr` | mailto |
| URL de la page de titre | |
`Linux Device Drivers, 3rd Edition` est cité au chapitre 14, 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 colle un extrait du style de code du noyau Linux.
Le style est personnel. L’auteur de ce document ne force pas ses vues, mais c’est le standard de ce qu’il maintient, et il préférerait qu’il s’applique à la plupart des autres projets. Au moins considérer ces points.
D’abord, imprimer les GNU coding standards, puis ne pas les lire. Les brûler — c’est un beau geste symbolique.
Le PDF ajoute : « ;) ok, it’s definitely not an eco-responsible move. »
Chapitre 1 : Indentation.
Les tabulations font 8 caractères de large, donc les indentations aussi. Des tentatives utilisent 4, voire 2 caractères. Le texte compare ça à 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, lancer son propre noyau — et utiliser Git.
### À 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.
%
```
Le module doit compiler sur n’importe quel système. Le sujet signale que c’est un indice de compatibilité de version.
### À 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
Modifier le fichier C suivant pour qu’il respecte le style de code Linux (`Documentation/CodingStyle`).
### À rendre
- La version mise à jour du fichier C.
Capture [C4](captures/04-little-penguin-assignment-03-11.png). Transcription (l’indentation du PDF est la référence visuelle) :
```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
### À 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*, disponible gratuitement en ligne.
## X. Assignment 05
### À faire
- Reprendre le module de l’assignment 01 et en faire un driver de périphérique caractère `misc`. L’interface misc est présentée comme un moyen simple de créer un périphérique caractère sans entrer dans sysfs et l’enregistrement de devices.
- Le device misc est créé avec un numéro mineur dynamique. Pas de mineur statique réservé.
- 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
### À 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.
Le sujet ne définit pas linux-next dans l’énoncé. C’est une partie du défi.
Indice : la documentation du processus de développement dans `Documentation/development-process/`, dans l’arbre des sources. Le PDF répète cet indice une seconde fois, en plus long : cette lecture doit 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 à linux-next dans une tâche ultérieure : ne pas supprimer ce répertoire. (Dans ce PDF, aucune tâche après celle-ci ne revient explicitement à linux-next. Assignment 08 et 09 n’en parlent pas. La phrase est quand même dans le sujet.)
Cette tâche ressemble à l’assignment 05. L’interface cette fois est debugfs.
Le sujet rapporte une rumeur : le créateur de debugfs aurait dit que la seule règle est « There are no rules. »
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/
```
L’option `CONFIG_DEBUG_FS` doit être activée dans le noyau.
### À 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 `chown`.
### À rendre
- Le code.
- Une preuve que le module fonctionne comme prévu.
## XIII. Assignment 08
Revenir 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.
Encadré [C5](captures/05-little-penguin-assignment-08-17.png) : « But wait—what is this code supposed to do? »
Suite : « That’s part of the challenge. Have fun figuring it out! »
Capture du code [C6](captures/05-little-penguin-assignment-08-18.png). Transcription :
```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
### À 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.
Le sujet dit que ce n’est pas dur, mais que ça peut être piégeux. Il renvoie à la documentation sur les points de montage, le listage de répertoires, et le parcours de listes chaînées dans le noyau.
## 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.