{"id":3974,"date":"2014-03-06T16:02:51","date_gmt":"2014-03-06T15:02:51","guid":{"rendered":"http:\/\/www.blaess.fr\/christophe\/?p=3974"},"modified":"2014-03-06T18:27:59","modified_gmt":"2014-03-06T17:27:59","slug":"compilation-native-de-modules-kernel-sur-raspberry-pi","status":"publish","type":"post","link":"https:\/\/www.blaess.fr\/christophe\/2014\/03\/06\/compilation-native-de-modules-kernel-sur-raspberry-pi\/","title":{"rendered":"Compilation native de modules kernel sur Raspberry Pi"},"content":{"rendered":"<p style=\"text-align: justify;\"><a href=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2014\/03\/2014-03-06.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignright size-full wp-image-3990\" alt=\"2014-03-06\" src=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2014\/03\/2014-03-06.png\" width=\"200\" height=\"144\" \/><\/a>On m&rsquo;a demand\u00e9 \u00e0 plusieurs reprises comment compiler les modules pour le noyau du Raspberry Pi que j&rsquo;ai pr\u00e9sent\u00e9 dans diff\u00e9rents articles ou ceux que je propose en illustration de mes sessions de formation. J&#8217;emploie g\u00e9n\u00e9ralement une <em>cross-compilation<\/em>, c&rsquo;est \u00e0 dire un compilateur sp\u00e9cifique install\u00e9 sur un PC pour produire du code pour le processeur \u00e0 c\u0153ur ARM du Raspberry Pi. J&rsquo;ai d\u00e9j\u00e0 pr\u00e9sent\u00e9 cette solution dans plusieurs articles (par exemple <a title=\"Toolchain Buildroot pour Raspberry Pi\" href=\"http:\/\/www.blaess.fr\/christophe\/2012\/10\/12\/toolchain-buildroot-pour-raspberry-pi\/\">celui-ci<\/a>, <a title=\"Toolchain crosstool-NG pour Raspberry Pi\" href=\"http:\/\/www.blaess.fr\/christophe\/2012\/10\/19\/toolchain-crosstool-ng-pour-raspberry-pi\/\">celui-ci<\/a> ou <a title=\"Raspberry Pi from scratch\" href=\"http:\/\/www.blaess.fr\/christophe\/2013\/09\/10\/raspberry-pi-from-scratch-2\/\">la s\u00e9rie d&rsquo;articles<\/a> pour Linux Magazine).<\/p>\n<p style=\"text-align: justify;\">Il existe toutefois une autre solution plus simple&nbsp;: la <strong>compilation native<\/strong> en utilisant une distribution courante pour Raspberry Pi.<br \/>\n<!--more-->\n<\/p>\n<h1>Probl\u00e9matique<\/h1>\n<p style=\"text-align: justify;\">Pour pouvoir compiler un module du noyau, il est indispensable de disposer des fichiers d&rsquo;en-t\u00eate et de configuration du noyau cible. Pour une plate-forme embarqu\u00e9e, cela signifie g\u00e9n\u00e9ralement que l&rsquo;on r\u00e9alise la compilation des modules suppl\u00e9mentaires sur la m\u00eame machine que celle qui a servi \u00e0 produire le noyau.<\/p>\n<p style=\"text-align: justify;\">Lorsque le noyau pr\u00e9compil\u00e9 est livr\u00e9 avec le mat\u00e9riel, la mise en \u0153uvre de modules personnalis\u00e9s peut devenir un v\u00e9ritable casse-t\u00eate pour l&rsquo;int\u00e9grateur qui se retrouve pris en sandwich entre diff\u00e9rents fournisseurs. C&rsquo;est pour cela que je pr\u00e9conise toujours d&rsquo;essayer de disposer de toute la solution de compilation lors de l&rsquo;industrialisation d&rsquo;un syst\u00e8me embarqu\u00e9.<\/p>\n<p style=\"text-align: justify;\">Quand nous souhaitons compiler un nouveau module pour un noyau fourni par une distribution Linux, par exemple sur un PC, aucun souci&nbsp;: il suffit d&rsquo;installer le package contenant les fichiers d&rsquo;en-t\u00eate et de configuration n\u00e9cessaires (<code>linux-headers<\/code> sur Debian et d\u00e9riv\u00e9s, <code>kernel-devel<\/code> sur RedHat, etc.) et d&rsquo;utiliser les outils de compilation standards.<\/p>\n<p style=\"text-align: justify;\">Le probl\u00e8me qui se pose avec les principales distributions pour le Raspberry Pi, notamment la Raspbian que je prendrai en exemple dans cet article, est qu&rsquo;elles ne fournissent pas les packages n\u00e9cessaires \u00e0 la compilation des modules. Il est possible d&rsquo;installer des packages \u00ab\u00a0alternatifs\u00a0\u00bb fournis par des sources non-officielles, mais tant qu&rsquo;\u00e0 faire, autant re-g\u00e9n\u00e9rer le noyau et disposer d&rsquo;un environnement de compilation de modules parfaitement sain. Cela va prendre un temps de calcul assez cons\u00e9quent (une dizaine d&rsquo;heures), mais est \u00e0 la port\u00e9e de n&rsquo;importe quel utilisateur du Raspberry Pi.<\/p>\n<h1>Compilation d&rsquo;un noyau pour Raspbian<\/h1>\n<p style=\"text-align: justify;\">J&rsquo;ai t\u00e9l\u00e9charg\u00e9 la derni\u00e8re version de <a title=\"La distribution Rasbian\" href=\"http:\/\/www.raspbian.org\/\" target=\"_blank\">la distribution Raspbian<\/a> disponible \u00e0 ce jour (<em>2014-01-07-wheezy<\/em>), mais je pense que les manipulations d\u00e9crites ci-dessous doivent \u00eatre r\u00e9alisables sur toute distribution qui propose l&rsquo;ensemble des outils de compilation (<code>make<\/code>, <code>gcc<\/code>, etc.) natifs sur le Raspberry Pi.<\/p>\n<h2>T\u00e9l\u00e9chargement des sources modifi\u00e9es pour Raspberry Pi<\/h2>\n<p style=\"text-align: justify;\">Tout d&rsquo;abord, r\u00e9cup\u00e9rons les sources de Linux incluant les patches sp\u00e9cifiques pour le Raspberry. Attention, il faudra disposer d&rsquo;environ 2 Go de libre sur la carte SD pour la compilation du noyau. Il peut donc \u00eatre n\u00e9cessaire de faire un peu de m\u00e9nage avant de commencer. Personnellement, j&rsquo;ai retir\u00e9 les packages de l&rsquo;environnement X-Window car sur mon Raspberry Pi de test, je ne me connecte qu&rsquo;en liaison s\u00e9rie ou par le r\u00e9seau (avec\u00a0<code>ssh<\/code>).<\/p>\n<p style=\"text-align: justify;\">Le t\u00e9l\u00e9chargement s&rsquo;effectue ainsi&nbsp;:<\/p>\n<pre>[~]$ <strong>git clone http:\/\/github.com\/raspberrypi\/linux rpi-kernel<\/strong>\n  [...]\n[~]$<\/pre>\n<p style=\"text-align: justify;\">Le transfert (1.6 Go) prend environ une heure.<\/p>\n<pre>[~]$ <strong>cd rpi-kernel<\/strong>\n[rpi-kernel]$<\/pre>\n<h2>Configuration du noyau<\/h2>\n<p style=\"text-align: justify;\">V\u00e9rifions le num\u00e9ro de version du noyau t\u00e9l\u00e9charg\u00e9.<\/p>\n<pre>[rpi-kernel]$ <strong>head Makefile<\/strong>\nVERSION = 3\nPATCHLEVEL = 10\nSUBLEVEL = 32\n  [...]\n[rpi-kernel]$ <strong>uname -r<\/strong>\n3.10.25+\n[rpi-kernel]$<\/pre>\n<p style=\"text-align: justify;\">Le noyau t\u00e9l\u00e9charg\u00e9 et celui fourni par Raspbian sont tous les deux de la branche 3.10. Il est donc possible d&rsquo;utiliser la configuration de notre noyau courant pour compiler le nouveau.<\/p>\n<pre>[rpi-kernel]$ <strong>zcat \/proc\/config.gz &gt; .\/.config<\/strong>\n[rpi-kernel]$<\/pre>\n<p style=\"text-align: justify;\">Une autre solution serait de prendre la configuration par d\u00e9faut pour le Raspberry Pi avec&nbsp;:<\/p>\n<pre>[rpi-kernel]$ <strong>make bcmrpi_defconfig<\/strong>\n  [...]\n[rpi-kernel]$<\/pre>\n<p style=\"text-align: justify;\">Pour observer et ajuster \u00e9ventuellement la configuration (notamment en modifiant <code>General Setup -&gt; Local version<\/code> pour ajouter nos initiales), il nous faut installer le package <em>ncurses-devel<\/em> afin de profiter des menus semi-graphiques. Toutefois, ce package porte un nom diff\u00e9rent dans les distributions Debian\/Raspbian.<\/p>\n<pre>[rpi-kernel]$ <strong>sudo apt-get install libncurses5-dev<\/strong>\n  [...]\n[rpi-kernel]$ <strong>make menuconfig<\/strong><\/pre>\n<h2>Compilation<\/h2>\n<p style=\"text-align: justify;\">La compilation n\u00e9cessite l&rsquo;utilitaire <code>bc<\/code> non install\u00e9 par d\u00e9faut sur Raspbian. Ajoutons-le&nbsp;:<\/p>\n<pre>[rpi-kernel]$ <strong>sudo apt-get install bc<\/strong>\n  [...]\n[rpi-kernel]$<\/pre>\n<p style=\"text-align: justify;\">Une fois la configuration fignol\u00e9e, on lance la compilation.<\/p>\n<pre>[rpi-kernel]$ <strong>make<\/strong><\/pre>\n<p style=\"text-align: justify;\">Comptez entre <strong>8 et 10 heures de compilation<\/strong> en fonction de ce que vous avez ajout\u00e9 ou retir\u00e9 du noyau, ainsi que de la rapidit\u00e9 de votre carte SD&#8230;<\/p>\n<h2>Installation<\/h2>\n<p style=\"text-align: justify;\">Le lendemain matin, nous finalisons l&rsquo;installation.<\/p>\n<pre>[rpi-kernel]$ <strong>sudo make modules_install<\/strong>\n  [...]<\/pre>\n<p style=\"text-align: justify;\">On voit alors appara\u00eetre l&rsquo;arborescence <code>\/lib\/modules\/3.10.32<\/code> contenant les modules du kernel.<\/p>\n<p style=\"text-align: justify;\">Puis installons le nouveau noyau en prenant garde de conserver le pr\u00e9c\u00e9dent au cas o\u00f9&#8230;<\/p>\n<pre>[rpi-kernel]$ <strong>sudo cp \/boot\/kernel.img \/boot\/kernel.bkup<\/strong>\n[rpi-kernel]$ <strong>sudo cp arch\/arm\/boot\/zImage \/boot\/kernel.img<\/strong>\n[rpi-kernel]$ <strong>sudo reboot<\/strong><\/pre>\n<h1>Essai de l&rsquo;environnement de compilation<\/h1>\n<p style=\"text-align: justify;\">Apr\u00e8s avoir red\u00e9marr\u00e9, nous v\u00e9rifions que le noyau soit bien celui que nous avons g\u00e9n\u00e9r\u00e9.<\/p>\n<pre>[rpi-kernel]$ <strong>uname -r<\/strong>\n3.10.32+\n[rpi-kernel]$<\/pre>\n<h2>Compilation d&rsquo;un module personnalis\u00e9<\/h2>\n<p style=\"text-align: justify;\">Copions le fichier suivant dans notre r\u00e9pertoire personnel sur le Raspberry Pi. Il s&rsquo;agit d&rsquo;une sorte de \u00ab\u00a0<em>Hello World<\/em>\u00a0\u00bb pour le noyau, c&rsquo;est le premier exemple que je pr\u00e9sente dans mes formations sur la programmation de drivers Linux.<\/p>\n<pre><strong><a title=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2014-03-06\/khello.c\" href=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2014-03-06\/khello.c\">khello.c<\/a>:<\/strong>\n#include &lt;linux\/module.h&gt;\n\nstatic int __init khello_init (void)\n{\n        printk(KERN_INFO \"%s : HELLO\\n\", THIS_MODULE-&gt;name);\n        return 0; \n}\n\nstatic void __exit khello_exit (void)\n{\n        printk(KERN_INFO \"%s : BYE!\\n\", THIS_MODULE-&gt;name);\n}\n\nmodule_init(khello_init);\nmodule_exit(khello_exit);\nMODULE_LICENSE(\"GPL\");<\/pre>\n<p style=\"text-align: justify;\">Dans le m\u00eame r\u00e9pertoire, copions le Makefile suivant. Attention, il est important de respecter les tabulations en d\u00e9but de ligne, il faut s&rsquo;assurer qu&rsquo;elles ne sont pas remplac\u00e9es par des espaces.<\/p>\n<pre><strong><a title=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2014-03-06\/Makefile\" href=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2014-03-06\/Makefile\">Makefile<\/a>:<\/strong>\nifneq (${KERNELRELEASE},)\n        obj-m  = khello.o\nelse\n        KERNEL_DIR ?= \/lib\/modules\/$(shell uname -r)\/build\n        MODULE_DIR := $(shell pwd)\n\n.PHONY: all\n\nall: modules\n\n.PHONY:modules\n\nmodules:\n        ${MAKE} -C ${KERNEL_DIR} SUBDIRS=${MODULE_DIR}  modules\n\nclean:\n        rm -f *.o *.ko *.mod.c .*.o .*.ko .*.mod.c .*.cmd *~\n        rm -f Module.symvers Module.markers modules.order\n        rm -rf .tmp_versions\nendif<\/pre>\n<p style=\"text-align: justify;\">Nous pouvons \u00e0 pr\u00e9sent compiler notre module.<\/p>\n<pre>[~]$ <strong>make<\/strong>\nmake -C \/lib\/modules\/3.10.32-perso+\/build SUBDIRS=\/home\/pi  modules\nmake[1]: Entering directory `\/home\/pi\/rpi-kernel'\n  CC [M]  \/home\/pi\/khello.o\n  Building modules, stage 2.\n  MODPOST 1 modules\n  CC      \/home\/pi\/khello.mod.o\n  LD [M]  \/home\/pi\/khello.ko\nmake[1]: Leaving directory `\/home\/pi\/rpi-kernel'\n[~]$ <strong>ls<\/strong>\nkhello.c   khello.mod.c  khello.o  modules.order   rpi-kernel\nkhello.ko  khello.mod.o  Makefile  Module.symvers\n[~]$<\/pre>\n<h2>Essai du module<\/h2>\n<p style=\"text-align: justify;\">Le module est bien pr\u00e9sent, chargeons-le:<\/p>\n<pre>[~]$ <strong>sudo insmod khello.ko<\/strong>\n[~]$ <strong>lsmod<\/strong>\nModule                  Size  Used by\nkhello                   683  0\nsnd_bcm2835            16118  0\nsnd_soc_bcm2708_i2s     5462  0\nregmap_mmio             2778  1 snd_soc_bcm2708_i2s\nsnd_soc_core          132437  1 snd_soc_bcm2708_i2s\n  [...]\n[~]$<\/pre>\n<p style=\"text-align: justify;\">Le module est bien charg\u00e9 dans le kernel, v\u00e9rifions si son message d&rsquo;initialisation est visible.<\/p>\n<pre>[~]$ <strong>dmesg |tail<\/strong>\n[    3.029926] smsc95xx v1.0.4\n[    3.108995] smsc95xx 1-1.1:1.0 eth0: register 'smsc95xx' at usb-bcm2708_usb-1.1, smsc95xx USB 2.0 Ethernet, b8:27:eb:c9:e5:8d\n[    3.953891] udevd[157]: starting version 175\n[    6.215100] bcm2708-i2s bcm2708-i2s.0: Failed to create debugfs directory\n[   11.279103] EXT4-fs (mmcblk0p2): re-mounted. Opts: (null)\n[   11.765049] EXT4-fs (mmcblk0p2): re-mounted. Opts: (null)\n[   20.017728] smsc95xx 1-1.1:1.0 eth0: hardware isn't capable of remote wakeup\n[   21.550910] smsc95xx 1-1.1:1.0 eth0: link up, 100Mbps, full-duplex, lpa 0x45E1\n[   24.950826] Adding 102396k swap on \/var\/swap.  Priority:-1 extents:1 across:102396k SSFS\n[ 5697.509567] khello : HELLO\n[~]$<\/pre>\n<p style=\"text-align: justify;\">Nous allons retirer le module de la m\u00e9moire du kernel.<\/p>\n<pre>[~]$ <strong>sudo rmmod khello<\/strong>\npi@raspberrypi:~$ <strong>dmesg |tail<\/strong>\n[    3.108995] smsc95xx 1-1.1:1.0 eth0: register 'smsc95xx' at usb-bcm2708_usb-1.1, smsc95xx USB 2.0 Ethernet, b8:27:eb:c9:e5:8d\n[    3.953891] udevd[157]: starting version 175\n[    6.215100] bcm2708-i2s bcm2708-i2s.0: Failed to create debugfs directory\n[   11.279103] EXT4-fs (mmcblk0p2): re-mounted. Opts: (null)\n[   11.765049] EXT4-fs (mmcblk0p2): re-mounted. Opts: (null)\n[   20.017728] smsc95xx 1-1.1:1.0 eth0: hardware isn't capable of remote wakeup\n[   21.550910] smsc95xx 1-1.1:1.0 eth0: link up, 100Mbps, full-duplex, lpa 0x45E1\n[   24.950826] Adding 102396k swap on \/var\/swap.  Priority:-1 extents:1 across:102396k SSFS\n[ 5697.509567] khello : HELLO\n[ 5760.410545] khello : BYE!\n[~]$<\/pre>\n<h1>Conclusion<\/h1>\n<p style=\"text-align: justify;\">Nous voyons qu&rsquo;il est tout \u00e0 fait possible d&rsquo;utiliser un Raspberry Pi pour r\u00e9aliser des compilations natives de modules du noyau. Cela r\u00e9clame un temps de calcul important, mais rien ne nous oblige \u00e0 rester \u00e0 proximit\u00e9. L&rsquo;int\u00e9r\u00eat est alors de disposer d&rsquo;une petite plate-forme embarqu\u00e9e conviviale (gr\u00e2ce \u00e0 l&rsquo;ensemble des applications fournies par la distribution) que nous pouvons utiliser pour d\u00e9velopper facilement nos propres modules noyau.<\/p>","protected":false},"excerpt":{"rendered":"<p>On m&rsquo;a demand&eacute; &agrave; plusieurs reprises comment compiler les modules pour le noyau du Raspberry Pi que j&rsquo;ai pr&eacute;sent&eacute; dans diff&eacute;rents articles ou ceux que je propose en illustration de mes sessions de formation. J&rsquo;emploie g&eacute;n&eacute;ralement une cross-compilation, c&rsquo;est &agrave; dire un compilateur sp&eacute;cifique install&eacute; sur un PC pour produire du code pour le processeur [&hellip;]<\/p>","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5,8,11],"tags":[],"class_list":["post-3974","post","type-post","status-publish","format-standard","hentry","category-embarque","category-linux-2","category-raspberry-pi"],"_links":{"self":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts\/3974","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/comments?post=3974"}],"version-history":[{"count":15,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts\/3974\/revisions"}],"predecessor-version":[{"id":3976,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts\/3974\/revisions\/3976"}],"wp:attachment":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/media?parent=3974"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/categories?post=3974"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/tags?post=3974"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}