Skip to content
On this page

5. Kernel Compilen

Linux Kernel

Der Linux kernel wird vom Kernel Team über git verwaltet. Versionen und das Repository sind unter https://www.kernel.org/ ersichtlich.

Für das Raspberry Pi existiert ein eigenes Git Repository https://github.com/raspberrypi/linux, in welchem die Raspberry Pi foundation ihren eigenen vom Vanilla abgeleiteten Kernel zur Verfügung stellt. Allgemein gilt: weil der Kernel unter GPL lizenziert ist, muss der Source Code des Kernels inklusive allen Änderungen für User unter der GPL verfügbar sein.

Für unsere Versuche basieren wir auf dem LTS Release Branch rpi-6.6.y.

Frage

Welchen Kernel haben wir mit Buildroot verwendet? Kann dies im laufenden Betrieb des Targets ermittelt werden?

Toolchain aufsetzen

In Buildroot haben wir den Kernel bereits mit der Toolchain (von Buildroot heruntergeladen) kompiliert und auf die Bootpartition deployt.

Produkte des Kernels sind:

  • self extracting Kernel Image zImage (je nach Bootloader z.T. uImage)
  • Kernelmodule welche nicht statisch gelinkt sind (*.ko)
  • Device Tree Binding .dtb für das Raspberry Pi
  • Device Tree Overlays für peripherie *.dto.

Um den Kernel für das Target kompilieren zu können, hat Buildroot für uns die passende Toolchain verwendet.

Wir laden nun einen aktuellen Release der arm Toolchain für unser Hostsystem und das Linux Arm 32 Target herunter.

Besuchen Sie hierfür https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads und suchen Sie die passende Toolchain aus. Welche wird wohl am besten zu unserem Target passen?

Auswahl für die Versuche

Verwenden Sie arm-gnu-toolchain-13.2.rel1-x86_64-arm-none-linux-gnueabihf.tar.xz.

Entpacken Sie die Toolchain im Downloads folder und erstellen Sie einen Symbolischen link mit ln auf den Folder

Wechseln zuerst Sie in das Verzeichnis ~/embedded-linux. Validieren Sie, dass die Toolchain arm-gnu-toolchain-13.2.rel1-x86_64-arm-none-linux-gnueabihf.tar.xz im Ordner ~/Downloads heruntergeladen worden ist.

bash
# symbolic link auf die toolchain im working directory
ln -s ~/Downloads/<hier-das-toolchain-directory> 

# ls -al sollte nun einen symbolischen link auf die toolchain zeigen
ls -al

Probleme beim Kompilieren

Es kann sein, dass mit einer sehr aktuellen Toolchain Probleme beim Compilen entstehen, wie z.B.

drivers/media/i2c/msp3400-driver.c:421:17: internal compiler error: Illegal instruction
  421 |                 msp3400c_set_carrier(client, MSP_CARRIER(10.7),

Hier ein Beispiel eines Fehlers mit gcc-arm-11.2-2022.02-x86_64-arm-none-linux-gnueabihf. https://community.arm.com/support-forums/f/compilers-and-libraries-forum/52623/gcc-11-2-arm-none-eabi-internal-compiler-error-illegal-instruction/176970

Environment Variablen setzen

Für das Compilen müssen noch folgende Variablen gesetzt sein: ARCH=arm und CROSS_COMPILE soll den ganzen Prefix von ARM-gcc inklusive absolutem Pfad beinhalten.

In unserem Fall wäre das /home/$USER/embedded-linux/toolchain/bin/arm-none-linux-gnueabihf-. Wichtig ist das - am Ende des Pfades.

Mit export können die Variablen ins environment aufgenommen werden. Führen Sie also im Terminal aus:

export CROSS_COMPILE=/home/$USER/embedded-linux/toolchain/bin/arm-none-linux-gnueabihf- und export ARCH=arm.

Kontrollieren Sie ob die Pfade stimmen mit

bash
echo $CROSS_COMPILE
echo $ARCH

Achtung: neues Terminal

Sobald Sie das Terminal verlassen gehen die Variablen verloren!

Sie können dieses Setup allerdings auch in einem Shell Script (z.B. envsetup.sh) durchführen. Damit die Änderungen am Environment auch ausserhalb des Scripts übernommen werden, müssen Sie dieses allerdings mit source aufrufen.

bash
#!/usr/bin/bash

# file envsetup.sh
export ARCH=arm
export CROSS_COMPILE=<toolchain-prefix>
bash
# env aufsetzen mit

source envsetup.sh

# alternativ mit

. envsetup.sh

Setup Testen

Falls alles geklappt hat wird dieser Command ARM GCC aufrufen:

bash
${CROSS_COMPILE}gcc -v

Kernel Sources via git herunterladen

Wir laden die Kernel Sources von dem Raspberry Pi git repository herunter. Mit git clone können wir entweder den ganzen Tree mit der ganzen Kernel History herunterladen oder alternativ nur den aktuellen branch verwenden:

Wechseln Sie ins Verzeichnis ~/embedded-linux. Verwenden Sie für <branch> rpi-6.6.y

bash
# linux-rpi: lokales verzeichnis
git clone --depth 1 --single-branch --branch <branch> https://github.com/raspberrypi/linux.git linux-rpi

Kernel kompilieren

Ein typischer Vorgang für das kompilieren und deployen eines Kernels sieht so aus:

  1. Kernel herunterladen
  2. Toolchain einreichten
  3. ggf. Kernel patchen
  4. Board defconfig nach .config kopieren.
  5. Menuconfig ausführen und Treiber auswählen mit make menuconfig
  6. make zImage
  7. make modules
  8. make dtbs
  9. zImage und dtb kopieren und Bootloader konfigurieren für neues image.
  10. .ko modules ins RFS kopieren unter entsprechendem Folder.
  11. DT Overlays in die Boot Partition kopieren und Bootloader konfigurieren.

Wechseln Sie in das Verzeichnis des Kernel Sources embedded-linux/linux-rpi.

Zuerst laden wir die defconfig für unseren SoC:

bash
make bcm2711_defconfig

Installieren Sie noch folgende Pakete:

sudo apt install libmpc-dev \
flex bison openssl libssl-dev

Für den Moment patchen wir den Kernel nicht und selektieren neu IIO Treiber und linken dies statisch dem Kernel hinzu (in menuconfig mit [*]).

Führen Sie make menuconfig aus um die Menuconfig zu starten.

XZ komprimierte Module

Suchen Sie in der Config nach der Option MODULE_COMPRESS_XZ und setzen Sie diese auf n.

Wechseln Sie ins Verzeichnis des Kernels und suchen Sie mit ? nach IIO und aktivieren Sie die Treiber für den Pressure Sensor und Humidity Sensor, den Sie hier finden https://pinout.xyz/pinout/sense_hat. Verwenden Sie wieder ? in der menuconfig um die Sensormodelle zu finden.

Verlassen Sie das Menü und speichern Sie die Config.

Compile

Kompilieren Sie den Kernel mit make zImage dtbs modules.

Das kompilieren wird eine Zeit dauern. Als Referenz auf einem 16 Thread Ryzen CPU dauert es ca 10 Minuten mit 15 Threads.

Mit -j15 können so bei make mehrere Threads verwendet werden. Um die Zeit zu messen können Sie mit time den make Command aufrufen:

bash
# -jX: X am besten Anzahl Threads der CPU - 1
time make -j15 zImage dtbs modules

Deploy

Kopieren Sie die Produkte des Kernels an die entsprechenden Orte auf dem Target

SourcePartitionDestination
arch/arm/boot/zImageKernelBootzImage
arch/arm/boot/dts/broadcom/bcm2711-rpi-4-b.dtbDevice Tree BlobBootbcm2711-rpi-4-b.dtb
arch/arm/boot/dts/overlays/*.dtb*Overlay TreeBootoverlays
*.koKernelmoduleRFS/lib/modules/**

Für die Kernelmodule *.ko verwenden wir make, da auch Unterverzeichnissen erstellt werden:

bash
# Pfad für rootfs ggf. anpassen
sudo make ARCH=arm INSTALL_MOD_PATH=/media/$USER/rootfs/ modules_install

Nach dem kopieren können Sie die SD-Karte unmounten und das Raspberry Pi neu starten. Kontrollieren Sie mit cat /proc/version, dass Sie den neuen Kernel richtig installiert haben.