eudyptula/README.md

435 lines
15 KiB
Markdown
Raw Normal View History

2023-01-22 03:04:28 +01:00
# Eudyptula Challenge
2023-01-23 01:16:29 +01:00
Le challenge étant fermé, je m'appuie sur les questions trouvables sur des
dépôts Github.
2024-02-01 00:48:07 +01:00
Vous pouvez trouver des réponses (ainsi que des questions) [sur
Github](https://github.com/search?q=Eudyptula). Le fichier `TASKS.txt` contient
la liste des taches, reprises du dépot de
[agelastic](https://github.com/agelastic/eudyptula).
2023-01-23 01:16:29 +01:00
2023-01-23 17:13:12 +01:00
À noter que j'utilise la commande `indent -linux` pour pouvoir indenter et
formater les fichiers sources selon la convention du kernel Linux.
2023-01-23 18:53:31 +01:00
J'utilise aussi le script `checkpatch.pl -f` pour pouvoir vérifier plus en
profondeur si mes fichiers sources suivent bien la convention (cf. tâche 4).
2023-01-23 01:16:29 +01:00
## Compilation
La version utilisée et testée a varié durant la réalisation de ce challenge.
Voici la liste des challenges et de la version de Linux utilisée. À noter que
je n'ai pas prit le temps de tester ces challenges sur d'autres versions.
- tâches 1 à 7: 6.1.1, GCC 12
- tâches 8 à ... : 6.6.6, GCC 13
2023-05-13 23:45:59 +02:00
Il vous faut les fichiers d'en-têtes du kernel Linux (`linux-headers` sur les
distributions basées Debian et apt pilulé).
2023-01-23 01:16:29 +01:00
Il suffit ensuite d'aller dans le dossier de votre choix et faire `make`.
Parfois, d'autres commandes sont nécessaires. Lisez la partie réponse pour
avoir ces dernières.
2023-01-23 01:16:29 +01:00
2024-01-23 20:18:30 +01:00
## Tâches non faites
- 2 : je configure et compile moi-même mon kernel
- 7 : pas spécialement envie de compiler le next, je ne vois pas l'intérêt de
le faire
- 10 : je trouve la tache intéressante, mais je n'ai pas le temps pour le
faire ni l'envie d'envoyer des patchs faits par un débutant à des personnes
surchargées. À voir dans le futur cependant.
2023-01-23 01:16:29 +01:00
## Réponses
L'Eudyptula challenge demande souvent des preuves de notre réussite. Vous
pouvez retrouver les commandes et leur résultat ici. Si une tâche n'est pas
2023-05-13 23:45:59 +02:00
indiquée, cela veut surement dire qu'elle n'est pas assez intéressante ou trop
triviale (cf. tâche 7).
2023-01-23 01:16:45 +01:00
2023-05-13 23:45:59 +02:00
### Tâche 1
2023-01-23 01:16:45 +01:00
Pour montrer que mon module marche bien, on regarde les logs du kernel avec la
commande `dmesg`.
```text
2023-01-23 01:16:45 +01:00
# après insmod hello.ko
[102102.117958] Coucou le gens !!!!
# après rmmod hello
[102108.046104] Tschuss !!!
```
2023-01-23 17:13:51 +01:00
2023-01-27 17:59:44 +01:00
* [The Linux Kernel Module Programming Guide](https://sysprog21.github.io/lkmpg)
2023-05-13 23:45:59 +02:00
### Tâche 3
2023-01-23 17:14:08 +01:00
Patch basé sur la version `v6.2-rc5` du kernel Linux, créé avec la commande
`git format-patch -1 HEAD`.
```diff
2023-01-23 17:14:08 +01:00
From 6f41b705dbde5b42167c03b8d14ae695b226cb86 Mon Sep 17 00:00:00 2001
From: rick <rick@gnous.eu>
Date: Mon, 23 Jan 2023 16:49:42 +0100
Subject: [PATCH] custom extraversion
---
Makefile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Makefile b/Makefile
index c1ead4cd2342..d67f2f5eb831 100644
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
VERSION = 6
PATCHLEVEL = 2
SUBLEVEL = 0
-EXTRAVERSION = -rc5
+EXTRAVERSION = -eudyptula
NAME = Hurr durr I'ma ninja sloth
# *DOCUMENTATION*
--
2.39.1
```
2023-01-23 18:54:18 +01:00
2023-05-13 23:45:59 +02:00
### Tâche 4
2023-01-23 18:54:18 +01:00
2023-05-13 23:45:59 +02:00
Je n'ai pas mis les fichiers corrigés. Il suffit d'utiliser la commande
2023-01-23 18:54:18 +01:00
`indent` pour pouvoir bien indenter le code dans un premier temps. Il faut
ensuite utiliser le script `scripts/checkpatch.pl` sur les fichiers pour
trouver les derniers soucis.
2023-01-27 17:59:44 +01:00
* [Les conventions de code (Documentation Kernel)](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/process/coding-style.rst)
2023-05-13 23:45:59 +02:00
### Tâche 5
2023-01-27 17:59:44 +01:00
Il faut dans un premier temps générer l'alias du module. Cela va permettre de
lier les périphériques disponibles pour le module avec.
2 façons:
* `depmod $(uname -r) $(pwd)/task_5/my-usb-detect.ko` en étant à la racine du
dépôt git. **Cela va cependant réécrire le fichier
`/lib/modules/$(uname -r)/modules.alias`, ce qui peut casser votre
installation Linux.** Faites un backup de votre dossier avant.
* `cp task_5/my-usb-detect.ko /lib/modules/$(uname -r)/ && depmod -A`
La deuxième méthode est la plus recommandée. Je l'ai trouvé après avoir écrit
le module sans réussir à le charger. Le blog de Nihaal explique de manière
détaillée le fonctionnement des modules et de la détection de périphériques.
```text
2023-01-27 17:59:44 +01:00
# on branche le clavier
[ 6712.426017 ] usb 2-3: new full-speed USB device number 4 using xhci_hcd
[ 6712.569813 ] usb 2-3: New USB device found, idVendor=046d, idProduct=c52b, bcdDevice=24.01
[ 6712.569826 ] usb 2-3: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[ 6712.569830 ] usb 2-3: Product: USB Receiver
[ 6712.569833 ] usb 2-3: Manufacturer: Logitech
[ 6712.575345 ] input: Logitech USB Receiver as /devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0/0003:046D:C52B.0007/input/input32
[ 6712.629923 ] hid-generic 0003:046D:C52B.0007: input,hidraw0: USB HID v1.11 Keyboard [Logitech USB Receiver] on usb-0000:00:14.0-3/input0
[ 6712.634279 ] input: Logitech USB Receiver Mouse as /devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.1/0003:046D:C52B.0008/input/input33
[ 6712.634743 ] input: Logitech USB Receiver Consumer Control as /devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.1/0003:046D:C52B.0008/input/input34
[ 6712.689561 ] input: Logitech USB Receiver System Control as /devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.1/0003:046D:C52B.0008/input/input35
[ 6712.689844 ] hid-generic 0003:046D:C52B.0008: input,hiddev96,hidraw1: USB HID v1.11 Mouse [Logitech USB Receiver] on usb-0000:00:14.0-3/input1
[ 6712.693283 ] hid-generic 0003:046D:C52B.0009: hiddev97,hidraw2: USB HID v1.11 Device [Logitech USB Receiver] on usb-0000:00:14.0-3/input2
# notre module s'est chargé tout seul !!
[ 6713.143767 ] Coucou le gens !!!!
[ 6713.259818 ] elogind-daemon[3774]: Watching system buttons on /dev/input/event18 (Logitech USB Receiver Consumer Control)
[ 6713.260009 ] elogind-daemon[3774]: Watching system buttons on /dev/input/event19 (Logitech USB Receiver System Control)
[ 6713.663077 ] elogind-daemon[3774]: Watching system buttons on /dev/input/event16 (Logitech USB Receiver)
# le clavier est débranché et notre module n'est pas déchargé.
[ 6716.982578 ] usb 2-3: USB disconnect, device number 4
```
Il faut le décharger à la main avec `rmmod`.
* [Writing USB Device Drivers (Documentation Kernel)](https://www.kernel.org/doc/html/latest/driver-api/usb/writing_usb_driver.html)
* [USB hotplugging/USB Modutils Support (Documentation Kernel)](https://www.kernel.org/doc/html/latest/driver-api/usb/hotplug.html#usb-modutils-support)
* [usb-skeleton.c (Code Kernel)](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/usb/usb-skeleton.c)
* [Nihaal - Eudyptula Challenge Task 5](https://nihaal.me/post/ec5/)
2023-05-13 23:45:59 +02:00
## Tâche 6
2023-01-30 02:00:23 +01:00
Il existe plusieurs façons pour créer un nouveau fichier dans `/dev`. J'ai
cependant décidé d'implémenter qu'une seule manière pour l'instant.
Pour pouvoir créer un fichier dans `/dev`, il faut créer le périphérique à la
main. Il faut connaitre le numéro majeur du driver, ce qui se fait ou en
regardant dans le fichier `/proc/devices` ou en regardant le journal du kernel.
Il suffit de taper la commande suivante pour créer le fichier :
`mknod /dev/eudyptula c <majeur> 0`. N'oubliez pas de changer les droits si
vous souhaitez écrire dedans !
**Je n'ai pas suivi les consignes à la lettre, en effet je n'utilise pas un
*misc char device* mais un *char device*.** C'est pour ça qu'il faut créer à
la main le device. Je l'ai codé directement comme ça, ne trouvant pas beaucoup
d'informations sur les *misc char devices*. En lisant des codes sources ainsi
2023-05-13 23:45:59 +02:00
que la documentation, je comprends mieux comment en faire, mais j'ai décidé de
ne pas changer tout le code que j'avais fait. Cepebdant, je le modifierai si
2023-01-30 02:00:23 +01:00
l'on doit faire un *char device* plus tard.
Lorsqu'on ouvre le device, on reçoit la chaine `coucou c'est rick`. Si l'on
souhaite écrire dans le fichier, il faut taper `congruent`, sinon un message
d'erreur est retourné.
```bash
cat /dev/eudyptula
# coucou c'est rick
echo "congruent" > /dev/eudyptula
# aucune réponse, $? vaut 0
echo "bonjour12" > /dev/eudyptula
2023-01-30 02:06:36 +01:00
# -bash: echo: erreur d'écriture : Argument invalide
2023-01-30 02:00:23 +01:00
# $? vaut 1
```
* [Chapitre 3, Linux Device Drivers, 3rd Edition](https://lwn.net/Kernel/LDD3/)
* [Linux Kernel Labs - Character device drivers](https://linux-kernel-labs.github.io/refs/heads/master/labs/device_drivers.html#read-and-write)
* [Nihall - Misc character devices](https://nihaal.me/post/misc_char_devices/)
2024-01-10 00:06:10 +01:00
## Tache 8
L'ajout d'une nouvelle string dans le fichier ne supprime l'entièreté du
contenu du fichier. J'ai testé les sémaphores avec des `msleep`
(`<linux/delay.h>`) rajouté dans le code. Il est possible de tester en
décommentant le premier `define`.
```bash
ls -l /sys/kernel/debug/eudyptula/
# total 0
# -rw-rw-r-- 1 root root 0 Jan 9 22:46 foo
# -rw-rw-rw- 1 root root 0 Jan 9 22:44 id
# -r--r--r-- 1 root root 0 Jan 9 22:45 jiffies
echo pouet > /sys/kernel/debug/eudyptula/foo
cat /sys/kernel/debug/eudyptula/foo
# pouet
echo coucou ! > /sys/kernel/debug/eudyptula/foo
cat /sys/kernel/debug/eudyptula/foo
# coucou !
cat /sys/kernel/debug/eudyptula/id
# pouetpouet
echo congruent > /sys/kernel/debug/eudyptula/id
echo $?
# 0
echo pouet > /sys/kernel/debug/eudyptula/id
# bash: echo: write error: Invalid argument
echo $?
# 1
echo pouet > /sys/kernel/debug/eudyptula/jiffies
# bash: echo: write error: Permission denied
cat /sys/kernel/debug/eudyptula/jiffies
# 4345895105
cat /sys/kernel/debug/eudyptula/jiffies
# 4345895338
echo pouet > /sys/kernel/debug/eudyptula/foo &
cat /sys/kernel/debug/eudyptula/foo
# cat: /sys/kernel/debug/eudyptula/foo: Invalid argument
cat /sys/kernel/debug/eudyptula/foo &
cat /sys/kernel/debug/eudyptula/foo &
echo pouet > /sys/kernel/debug/eudyptula/foo
# bash: echo: write error: Invalid argument
rmmod hello
ls -l /sys/kernel/debug/eudyptula/
# ls: cannot access '/sys/kernel/debug/eudyptula/': No such file or directory
```
* [DebugFS (Documentation kernel)](https://docs.kernel.org/filesystems/debugfs.html)
* [Chapitre 3, Linux Device Drivers, 3rd Edition](https://lwn.net/Kernel/LDD3/)
* [Jiffies, Linux Kernel Development 2nd Edition](https://litux.nl/mirror/kerneldevelopment/0672327201/ch10lev1sec3.html)
2024-01-23 20:08:20 +01:00
### Tache 9
Idem que la tache 8 pour tester les sémaphores.
```bash
ls -l /sys/eudyptula/
# total 0
# -rw-r--r-- 1 root root 4096 Jan 23 18:42 foo
# -rw-rw-rw- 1 root root 4096 Jan 23 18:42 id
# -r--r--r-- 1 root root 4096 Jan 23 18:42 jiffies
echo pouet > /sys/eudyptula/foo
cat /sys/eudyptula/foo
# pouet
echo coucou ! > /sys/eudyptula/foo
cat /sys/eudyptula/foo
# coucou !
cat /sys/eudyptula/id
# pouetpouet
echo -n congruent > /sys/eudyptula/id
echo $?
# 0
echo pouet > /sys/eudyptula/id
# bash: echo: write error: Invalid argument
echo $?
# 1
echo pouet > /sys/eudyptula/jiffies
# bash: /sys/eudyptula/jiffies: Permission denied
cat /sys/eudyptula/jiffies
# 4344413015
cat /sys/eudyptula/jiffies
# 4344413465
echo pouet > /sys/eudyptula/foo &
cat /sys/eudyptula/foo
# cat: /sys/eudyptula/foo: Invalid argument
cat /sys/eudyptula/foo &
cat /sys/eudyptula/foo &
echo pouet > /sys/eudyptula/foo
# bash: echo: write error: Invalid argument
rmmod sysfs
ls -l /sys/eudyptula/
# ls: cannot access '/sys/eudyptula/': No such file or directory
```
* [The zen of kobjects](https://lwn.net/Articles/51437/) : un peu vieux, certaines fonctions pas
à jour
* [kobjects and sysfs](https://lwn.net/Articles/54651/) : idem
* [Everything you never wanted to know about kobjects, ksets, and
ktypes](https://docs.kernel.org/core-api/kobject.html) (documentation noyau)
* [Exemple de code pour
`kobject`](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/samples/kobject)
* [Chapitre 14, Linux Device Drivers, 3rd Edition](https://lwn.net/Kernel/LDD3/)
2024-02-04 15:41:23 +01:00
### Tache 12
Il suffit de charger le menu et de lire les messages noyaux pour voir le bon
fonctionnement. J'ai repris le `main` donné dans l'ennoncé sans le modifier
plus que ça :
```
[1220142.976299] Coucou le gens !!!!
[1220142.976340] id 3 = Dave
[1220142.976346] id 42 not found
[1220148.124624] Tschuss !!!
```
* [Chapitre 11, Linux Device Drivers, 3rd Edition](https://lwn.net/Kernel/LDD3/)
2024-02-04 23:07:41 +01:00
### Tache 13
Il faut mettre un constructeur de manière exceptionnel. Cela permet de l'afficher séparemment dans le fichier `/proc/slabinfo`, sinon Linux va optimiser ça en le regroupant avec un autre cache.
Voici le patch :
```diff
From 4b55e26775647e71c86164aed41d82beeb17febe Mon Sep 17 00:00:00 2001
From: rick <rick@gnous.eu>
Date: Sun, 4 Feb 2024 23:02:32 +0100
Subject: [PATCH] add task 13
---
task_12/list.c | 28 ++++++++++++++++++++++++----
1 file changed, 24 insertions(+), 4 deletions(-)
diff --git a/task_12/list.c b/task_12/list.c
index b5fa8fa..a7989be 100644
--- a/task_12/list.c
+++ b/task_12/list.c
@@ -4,6 +4,7 @@
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/module.h>
+#include <linux/slab.h>
#include <linux/string.h>
#define NAME_SIZE 20
@@ -16,11 +17,13 @@ struct identity {
};
static struct list_head identity_list;
+static struct kmem_cache *cache;
static int identity_create(char *name, int id)
{
int ret = 0;
- struct identity *new = kmalloc(sizeof(*new), GFP_KERNEL);
+ struct identity *new = (struct identity *)kmem_cache_alloc(cache,
+ GFP_KERNEL);
if (!new) {
ret = -ENOMEM;
@@ -63,15 +66,31 @@ static void identity_destroy(int id)
if (tmp) {
list_del(&tmp->list);
- kfree(tmp);
+ kmem_cache_free(cache, tmp);
}
}
+/*
+ * juste pour pouvoir être dans le slabinfo, sinon Linux le fusionne avec un
+ * autre qui a des propriétés similaires.
+ */
+static void my_constructor(void *ptr)
+{
+ memset(ptr, 0, sizeof(struct identity));
+}
+
static int __init my_init(void)
{
struct identity *temp;
pr_info("Coucou le gens !!!!\n");
+ cache =
+ kmem_cache_create("eudyptula_identity", sizeof(struct identity), 0,
+ SLAB_HWCACHE_ALIGN, my_constructor);
+
+ if (!cache)
+ return -ENOMEM;
+
INIT_LIST_HEAD(&identity_list);
if (identity_create("Alice", 1))
@@ -86,8 +105,8 @@ static int __init my_init(void)
temp = identity_find(3);
if (!temp)
pr_info("id 3 not found\n");
- else
- pr_info("id 3 = %s\n", temp->name);
+ else
+ pr_info("id 3 = %s\n", temp->name);
temp = identity_find(42);
if (!temp)
@@ -103,6 +122,7 @@ static int __init my_init(void)
static void __exit my_exit(void)
{
+ kmem_cache_destroy(cache);
pr_info("Tschuss !!!\n");
}
--
2.43.0
```
Et la sortie :
```bash
insmod list.ko
grep eud /proc/slabinfo
# eudyptula_identity 64 64 64 64 1 : tunables 0 0 0 : slabdata 1 1 0
dmesg
# [1246412.478052] Coucou le gens !!!!
# [1246412.478108] id 3 = Dave
# [1246412.478112] id 42 not found
# [1246450.284783] Tschuss !!!
```
* [Chapitre 8, Linux Device Drivers, 3rd Edition](https://lwn.net/Kernel/LDD3/)
## Informations diverses
Je liste dans cette section quelques informations que j'ai pu découvrir en
lisant des ressources histoire de pouvoir les retrouver rapidement dans le
futur.
### /proc
2023-01-30 02:06:36 +01:00
* `devices` : On peut retrouver la liste des drivers avec leur numéro majeur,
le tout découpé entre les *character devices* et les *block devices*.
2023-05-13 23:36:19 +02:00
### Les *devices*
* *character devices*: on ne lit qu'un caractère dans ce type de device, c'est
comme ça que fonctionne un clavier par exemple
* *block devices*: on va lire le device uniquement par "block" (`char *` ou
`char[]`), le disque dur par exemple