Files
LinuxEmbarque/Tp3.md
2024-10-28 11:10:37 +01:00

20 KiB
Raw Permalink Blame History

Travail Pratique 3

Objectif

Le but du travail est de manipuler le source d'un noyeau linux en le patchant et en le compilant avec notre chaine de compilation croisée pour le mettre sur notre carte

Preparation

[Q1] : Quelle est la version du noyau sur votre machine de développement ?

Sur ma machine perso je suis sur macos mais sur la machine virtuelle X86 que j'ai mise en place pour ces TP on peut faire la commande uname -ir

Et on a ce resultat

uname -ir
6.8.0-45-generic x86_64

J'ai donc une version stable du kernel linux 6.8.0

Obtenir les sources du noyau Linux

[Q2] : Quelle est la dernière version stable du noyau Linux selon le site officiel (indiquez la date de consultation) ?

La dernière version stable au moment ou je regarde sur www.kernel.org le 10 octobre 2024 est la 6.11.3

[Q3] : Quelle est la dernière version stable longterm du noyau Linux possédant la plus longue EOL (End Of Life) ? Quelle est sa EOL (indiquez la date de consultation) ?

Les versions long term support au moment ou je regarde sur www.kernel.org le 10 octobre 2024 sont:

  • la 6.6.56 Support jusqu'à Décembre 2026
  • la 6.1.112 Support jusqu'à Décembre 2026
  • la 5.15.167 Support jusqu'à Décembre 2026
  • la 5.10.226 Support jusqu'à Décembre 2026

Elles expirent donc toutes en décembre 2026... bizarre mais bon on va prendre la plus récente quand même qui dans notre cas es la 6.6.56

Pour accèder à toutes les versions de linux disponibles et pas juste celles qui sont mises en avance sur kernel.org on peut aller sur https://www.kernel.org/pub/linux/kernel/ et voir directement chaque version.

Dans notre cas on veut la mainline 6.5

wget https://mirrors.edge.kernel.org/pub/linux/kernel/v6.x/linux-6.5.tar.xz

[Q4] : Est-ce que la combinaison de cette version du noyau et votre chaîne de compilation croisée risque de poser problème ? Justifiez en développant votre réponse.

j'ai trouvé la version des headers de notre version de chaine de compilation et c'est la 4.19.315pour trouver cette info il suffit de retourner sur le site de bootlin ou on a telechargé cette dernière.

On peut donc voir que nos headers sont bien plus vieux que notre noyeau linux et c'est bien car les noyeaux sont rétrocompatibles. Le problème aurait été si notre chaine de compilation était plus récente que notre noyeau et la ca aurait été problematique.

[Q5] : Quel est le nombre total de fichiers sources (.c, .h, et .S) du noyau que vous venez de télécharger ? Déterminer cette valeur en utilisant seulement une seule exécution de la commande find (astuces : find accepte largument -o pour réaliser un “ou” logique et pensez à utiliser pipe sur la sortie de find avec le compteur de lignes wc -l).

find ./ \( -name "*.h" -o -name "*.c" -o -name "*.S" \) | wc -l

Avec cette commande on peut chercher plusieurs noms de fichiers différents. Dans le cas présent je me suis posé à la racine du kernel.

-name permet de spécifier que l'on veut filtrer sur le nom du fichier

-o permet d'indiquer un OR pour dire que on chercher plusieurs noms de fichiers possibles

Le résultat est : 56888 fichiers c'est un peu abusé mais bon ca comprend toutes les architetures possibles drivers etc...

[Q6] : Quels fichiers patch devez vous donc télécharger ?

Pour rappel, on a pas telechargé la version 6.6.56 mais la version mainline 6.5 pour permettre de s'amuser avec les patchs. Mais évidemment si on devait le faire pour de vrai en perdant le moins de temps possible on utiliserait juste git ou on prendrait tout simplement la dernière version directement sur kernel.org

Si on rergarde la nomenclature de notre version 6.6.56 et 6.1.112 on peut voir que la version téléchargée est 5 versions mineures derrière la version cible.

Pour patcher notre kernel on doit donc passer par deux étapes :

1: passer à la version Mainline (ici passer de 6.5 à 6.6) 2: passer de la version Mainline à la version longterm avec les différentes modifications (ici de passer de 6.6 à 6.6.112)

Quand on se balade sur https://www.kernel.org/pub/linux/kernel/ que en plsu des distributions on peut tomber sur des patchs. Le premier qui nous intéresse est le patch nommé patch-6.6.xz c'est le patch implicite qui permet de passer de la version 6.5 à la version 6.6 ce qui est exactement ce que l'on cherche.

Ensuite pour finir on peut prendre le patch patch-6.6.56.xz qui nous permettras de passer de la 6.6 à la 6.6.56. J'avoue que c'était pas hyper clair mais dans le repertoire incr on a des patchs de 6.6.50 vers 6.6.51 et ils sont très petits alors que la le patch 6.6.56 fait 3m ce qui est énorme donc je pense que c'est bien pour passer de mainline à 56

Maintenant on a bien installé notre kernel version 6.5 et no patchs 6.6 et 6.6.56

Pour les appliquer on peut utiliser les commandes

xz -d patch-6.6.xz pour décompresser les patchs deja

patch -p1 --dry-run < ../patch-6.6

Le -p1 indique qu'il faut skip le premier nom de directory pour taper directement dans le bon directory. Dans notre cas 1 suffit car on est déja à la racine de notre kernel

--dry-run permet de ne pas faire de modifs si il y a une erreur. La dans notre cas tout se fait sans erreur donc on peut refaire le patch sans le --dry-run

Ca prend quelques secondes et on a plein de texte qui fuse mais normalement aucune erreur et après cette commande on a donc un linux kernel mainline 6.6

Il faut donc désormais appliquer le patch 6.6.56

patch -p1 --dry-run < ../patch-6.6.56

et ensuite sans le --dry-run

et voila, normalement on devrait avoir un linux 6.6.56 prêt à être compilé.

On peut verifier avec la commande make kernelversion

make kernelversion
6.6.56

Préparation à la compilation croisée du noyau

On n'oublie pas de mettre notre variable d'environnement ARCH sur arm

echo $ARCH
arm

C'est important ensuite pour la compilation croisée

Configuration du noyau

J'ai voulu faire un make help mais j'ai eu des erreurs bizarre alors j'ai fait un make mrproper et ensuite le make help a fonctionné

Dans une des lignes de make help on peut lire

sama5_defconfig - Build for sama5

[Q7] : Quelle configuration avez-vous choisie ?

Dans une des lignes de make help on peut lire

sama5_defconfig - Build for sama5

Il faudrait donc utiliser sama5_defconfig

make sama5_defconfig

[Q8] : Comment pouvez-vous vous assurez avec une assez bonne certitude quil sagit de la bonne configuration ?

make menuconfig

On peut y voir des mentions de ARM, de AT91 que la target est 32 bits que l'on a un MMU

Bon après je vois nulle part mention du CPU exact que l'on a mais c'est déja pas mal

Compilation croisée du noyau

make

Bon chez moi ca prend un certain temps car la machine virtuelle est pas au top

Après genre 5min de compilation pouf erreur "certs/extract-cert.c:21:10: fatal error: openssl/bio.h: No such file or directory 21 | #include <openssl/bio.h>" par ce que sinon c'est pas drole

On va donc installer les bons outils et essayer à nouveau.

sudo apt install libssl-dev

La compilation est vraiment lente sur ma machine il faudrait la rendre multithreadée et peut-être la faire sur une machine x86 native la prochaine fois.

J'ai retenté une seconde fois avec -j ce qui permet de profiter des différents coeurs de la machine et à la fin de compilation on recoit

make -j
  CALL    scripts/checksyscalls.sh
  Kernel: arch/arm/boot/Image is ready
  Kernel: arch/arm/boot/zImage is ready

Ce qui devrait nous donner des indices sur ou se trouvent les inmages compilées

[Q9] : Une fois la compilation du noyau terminée, où se trouve le noyau compilé et quelle est sa taille ?

On peut aller regarder sous arch/arm/boot/

à l'intérieur on peur voir

Image  Makefile  bootp  compressed  deflate_xip_data.sh  dts  install.sh  zImage

On a donc une image et une zImage

du -sh Image
12M	Image

et pour la zimage

du -sh zImage
5.5M	zImage

[Q10] : Aussi, quel est le fichier de Device Tree Blob (binaire) pour votre carte Sama5D3 Xplained et quelle est sa taille ?

Le fichier device tree blob se trouve lui un peu plus bas dans arch/arm/boot/dts/microchip la on a une liste assez enorme de board mais parmis ces dernières on peut trouver une qui se nomme

ls | grep sama5d3_xplained
at91-sama5d3_xplained.dtb
at91-sama5d3_xplained.dts

Et dans ces noms on veut le blob binaire et donc on peut prendre le fichier qui finit en .dtb

du -sh at91-sama5d3_xplained.dtb
40K	at91-sama5d3_xplained.dtb

Elle fait donc 40kb

Le fichier DTS est le fichier lisible par un humain avec tous les peripheriques et memoires de notre carte en particulier.

[Q11] : Quelle est la nouvelle taille du noyau et quel pourcentage de taille en espace disque avez-vous ainsi gagné par rapport au noyau précédent ?

Il va ici falloir retourner dans notre configuration

make menuconfig

et ensuite à partir de la on peut recompiler notre kernel

make -j

Et on retourne sous arch/arm/boot/ pour voir notre noyeau nouvellement compilé.

du -sh zImage
3.9M	zImage

On gagne un peu de place par rapport à Gzip mais comparé aux 12mb originaux on gagne pas mal de place

Chargement et boot du noyau avec U-Boot

Comme ma

On va charger le noyeau à l'addresse 0x21000000

tftp 0x21000000 192.168.1.240:zImage

=> tftp 0x21000000 192.168.1.240:zImage
ethernet@f0028000: PHY present at 7
ethernet@f0028000: Starting autonegotiation...
ethernet@f0028000: Autonegotiation complete
ethernet@f0028000: link up, 1000Mbps full-duplex (lpa: 0x7800)
Using ethernet@f0028000 device
TFTP from server 192.168.1.240; our IP address is 192.168.1.201
Filename 'zImage'.
Load address: 0x21000000
Loading: #################################################################
	 #################################################################
	 #################################################################
	 #################################################################
	 ##################
	 720.7 KiB/s
done
Bytes transferred = 4076944 (3e3590 hex)

letsgooo (au cas ou note pour plus tard, le dossier partagé par le serveur macos tftp se trouve à /private/tftp)

ensuite pour le device tree blob à l'adresse 0x22000000

tftp 0x22000000 192.168.1.240:device_tree.dtb

=> tftp 0x22000000 192.168.1.240:device_tree.dtb
ethernet@f0028000: PHY present at 7
ethernet@f0028000: Starting autonegotiation...
ethernet@f0028000: Autonegotiation complete
ethernet@f0028000: link up, 1000Mbps full-duplex (lpa: 0x7800)
Using ethernet@f0028000 device
TFTP from server 192.168.1.240; our IP address is 192.168.1.201
Filename 'device_tree.dtb'.
Load address: 0x22000000
Loading: ###
	 7.8 KiB/s
done
Bytes transferred = 40674 (9ee2 hex)

On se rend pas compte mais ca m'a pris tellement de temps de faire fonctionner le tftp entre ma VM -> mon laptop -> sama5d3 que la de voir que ca fonctionne ca me rend heureux

[Q12] : Indiquez la séquence de commandes vous ayant permis de charger noyau et DTB et booter dessus.

Je suis allé chercher sur google et je suis tombé sur ce site https://docs.u-boot.org/en/stable/usage/cmd/bootz.html qui est la doc de la commande bootz

on peut donc créér la commande suivante

bootz 0x21000000 - 0x22000000

0x21... c'est l'addresse du kernel

"-" c'est par ce que on a pas d'infos sur la taille de la ram que l'on veut utiliser etc...

0x22... c'est l'addresse de notre DTB

Mais c'est bizarre... Quand j'utilise la commande bootz il ne se passe absolument rien... Pas d'erreur rien. Comme si j'avais entré une string vide que dalle.

Je regarde dans la doc et je peux voir que pour faire fonctionner bootz il faut que dans la config ca soit autorisé. Mais quand je verifier mon .config de u-boot

grep CONFIG_CMD_BOOTZ .config
CONFIG_CMD_BOOTZ=y

Tout a l'air ok donc je comprends pas trop

en fait j'ai redémarré ma board entre le moment ou j'ai tftp mes fichiers et du coup l'info a été perdue. Et la commande bootz a été codée visiblement pour ne rien dire...

Bref maintenant voici le résultat

=> bootz 0x21000000 - 0x22000000
## Flattened Device Tree blob at 22000000
   Booting using the fdt blob at 0x22000000
   Loading Device Tree to 2fb29000, end 2fb35ee1 ... OK

Starting kernel ...

[Q13] : Après avoir lu les messages d'erreur du noyau, expliquez aussi simplement que possible, quelle est la raison de la “panique” (ou crash) du noyau ?

---[ end Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,253) ]---

Voici l'erreur que on a quand on essaie de booter sur le kernel.

Le kernel n'est pas content car il n'arrive pas à charger le rootfs

[Q14] : Donnez le “code” U-Boot que vous avez écrit pour réaliser ce boot automatique.

setenv bootmenu_2 'Boot from local =echo "booting from local"'

voici le code d'exemple pour ajouter une troisème entrée de bootmenu qui fait un simple echo..

setenv bootmenu_3 'Boot from tftp=tftp 0x21000000 192.168.100.240:zImage && tftp 0x22000000 192.168.100.240:device_tree.dtb && bootz 0x21000000 - 0x22000000'

Grâce à cette commande j'ai ajouté un nouveau menu qui quand on le selectionne va directement récupèrer tous les fichiers depuis notre machine et va ensuite lancer le kernel

## Flasher le noyau et le Device Tree dans la NAND

[Q15] : Quelle sont les tailles, en bytes et KBytes, réservées dans la flash NAND au noyau et au Device Tree ?

On peut voir dans le resultat de la commande TFTP que le kernel fait 4076944 bytes ou à peu près 4mb.

Cela veut dire qu'il est stocké entre les addresses 0x21000000 et 0x213e3590

Pour ce qui est du DTB, 40674 bytes ou 40kb sont utilisés et il est donc stocké entre les addresses 0x22000000 et 0x22009ee2

[Q16] : Comment pouvez-vous vous assurer que la NAND a bien été effacée ?

Pour effacer de la nand on peut utiliser la commande nand erase [start] [size]

Dans notre cas si on suit le diagramme on peut voir que on va écrire le kernel entre les addresses 0x160000 et 0x700000 et le DTB entre les addresses 0x700000 et 0x720000

Donc on va nand erase 0x160000 0x720000

=> nand erase 0x160000 0x720000

NAND erase: device 0 offset 0x160000, size 0x720000
Erasing at 0x860000 -- 100% complete.
OK

pour verifier que la NAND a bien été clean à ces addresses on peut faire un nand dump 0x160000 0x100 pour avoir un apercu de l'état de la NAND à cette addresse

=> nand dump 0x160000 0x100
Page 00160000 dump:
	ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff
	ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff
	ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff
	ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff
	ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff
	ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff
	ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff
	ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff
	ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff
	ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff
	ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff
	ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff
	ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff
	ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff
	ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff
	ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff...

On peut voir que cette zone de la NAND a bien été remplie avec des 0xFF

[Q17] : Donnez le contenu des scripts update_kernel et update_dtb.

Pour flasher le contenu de ce qui se trouve dans notre flash dans notre nand on peut utiliser nand write x y z

x indique l'addresse dans la flash ou commencent les infos que on veut flasher y indique l'addresse dans la NAND ou on doit flasher le contenu de notre flash z indique la taille de l'information que on va écrire

Pour notre kernel on a donc

nand write 0x21000000 0x160000 0x3e3590

=> nand write 0x21000000 0x160000 0x3e3590

NAND write: device 0 offset 0x160000, size 0x3e3590
 4076944 bytes written: OK
=>

Pour le DTB

nand write 0x22000000 0x700000 0x9ee2

=> nand write 0x22000000 0x700000 0x9ee2

NAND write: device 0 offset 0x700000, size 0x9ee2
 40674 bytes written: OK

Pour créér des scripts on peut utiliser cette commande

setenv monscript 'command;command...'

Le script update_kernel doit faire deux choses que l'on sait deja faire :

  1. Load le kernel depuis notre machine de développement dans la RAM en utilisant tftp
  2. Erase la NAND aux bonnes addresses et flasher notre nouveau kernel et DTB dedans

setenv update_kernel 'tftp 0x21000000 192.168.100.240:zImage && nand erase 0x160000 0x700000 && nand write 0x21000000 0x160000 0x3e3590'

setenv update_dtb 'tftp 0x22000000 192.168.100.240:device_tree.dtb && nand erase 0x700000 0x720000 && nand write 0x22000000 0x700000 0x9ee2'

Ci dessus est le script qui devrait faire tout ce qui a été mentionné

on peut les run en faisant

run update_kernel

run update_dtb

Booter le noyau depuis la NAND

[Q18] : Donner les commandes U-Boot que vous avez écrites par accomplir ceci.

Pour booter depuis la NAND il faut charger le contenu de la NAND dans la memoire flash.

Donc pour commencer on peut faire un reset de la carte pour être sûr que la flash est bien vide.

Pour verifier :

=> bootz 0x21000000 - 0x22000000
=>

Ensuite la syntaxe pour lire dans la NAND est la même que pour l'écrire

nand read x y z

x est l'addresse en ram dans laquelle on va mettre ce que on lit

y est l'addresse en NAND ou se trouve notre data

z est la taille du kernel ou DTB à lire

nand read 0x21000000 0x160000 0x3e3590

nand read 0x22000000 0x700000 0x9ee2

et ensuite on peut faire bootz 0x21000000 - 0x22000000

on peut mettre tout ca dans un petit script

setenv boot_kernel 'nand read 0x21000000 0x160000 0x3e3590 && nand read 0x22000000 0x700000 0x9ee2 && bootz 0x21000000 - 0x22000000'

Et quand on le lance :

=> run boot_kernel

NAND read: device 0 offset 0x160000, size 0x3e3590
 4076944 bytes read: OK

NAND read: device 0 offset 0x700000, size 0x9ee2
 40674 bytes read: OK
## Flattened Device Tree blob at 22000000
   Booting using the fdt blob at 0x22000000
   Loading Device Tree to 2fb29000, end 2fb35ee1 ... OK

Starting kernel ...

Maintenant on créée un bootmenu

setenv bootmenu_4 'Boot from NAND=run boot_kernel'

Pour faire en sorte que ce soit cette dernière qui soit appelée après le timeout (ici 4 car c'est le quatrième bootmenu)

setenv bootmenu_default 4

Et on peut configurer le timeout de la sorte (ici cinq secondes)

setenv bootdelay 5

et pour rappel, toujours utiliser saveenv avant de reboot

Et maintenant on peut simplement reboot la carte et voir que on va boot automatiquement après cinq secondes sur le kernel stocké en NAND

[Q19] : Donnez le contenu de vos scripts permettant de ne flasher que lespace nécessaire dans la NAND de votre carte.

Dans les variables d'environnement on peut voir une variable nommée filesize

On peut donc ajouter une petite routine dans nos scripts pour faire en sorte que la valeur de taille du fichier ne soit pas hard codée

Voici le script update_kernel final

setenv update_kernel 'tftp 0x21000000 192.168.100.240:zImage && nand erase 0x160000 ${kernel_size} && setenv kernel_size ${filesize} && nand write 0x21000000 0x160000 0x3e3590'

(avant de run ce script pour la première fois il faut faire un premier tftp du kernel puis setenv kernel_size ${filesize} car le script a besoin que cette variable soit set au moins une fois)

voici le script update_dtb

setenv update_dtb 'tftp 0x22000000 192.168.100.240:device_tree.dtb && nand erase 0x700000 ${dtb_size} && setenv dtb_size ${filesize} && nand write 0x22000000 0x700000 0x9ee2'

(avant de run ce script pour la première fois il faut faire un premier tftp du dtb puis setenv dtb_size ${filesize} car le script a besoin que cette variables soit set au moins une fois)

Pour faire simple dans ces deux scripts on commence par tftp le nouveau kernel, si et seulement si cela marche alors on supprime le contenu de la NAND de la taille de l'ancien kernel (important de sauvegarder la valeur de l'ancien kernel car le tftp va overwrite l'ancienne valeur de filesize) ensuite on sauve la taille de ce nouveau kernel et on va le flasher dans la NAND.