Skip to content

5. Kernel Compilen

Übersicht zu Komponenten und Versionen

NameVersionLink
Ubuntu22.04 LTSlink
Raspberry Pi OSRaspberry Pi OS Litelink
Linux Kernelrpi-6.6.ylink
ARM gcc Toolchain13.2.Rel1link
Virtualbox7.0.18link
Buildroot2024.02.2link

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 Version 13.2.Rel1.

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

Wechseln zuerst Sie in das Verzeichnis ~/esl. Validieren Sie, dass die Toolchain 13.2.Rel1 im Ordner ~/Downloads heruntergeladen worden ist (arm-gnu-toolchain-13.2.Rel1-x86_64-arm-none-linux-gnueabihf).

bash
cd ~/esl

# ohne symbolic link gcc aufrufen
~/Downloads/arm-gnu-toolchain-13.2.Rel1-x86_64-arm-none-linux-gnueabihf/bin/arm-none-linux-gnueabihf-gcc -v

# symbolic link auf die toolchain im working directory
# dies kürzt den Aufruf des compilers nochmals ab
ln -s ~/Downloads/arm-gnu-toolchain-13.2.Rel1-x86_64-arm-none-linux-gnueabihf toolchain

# mit symbolic link gcc aufrufen
~/esl/toolchain/bin/arm-none-linux-gnueabihf-gcc -v

# das toolchain präfix (alles vor gcc) ist in dem fall also
# ~/esl/toolchain/bin/arm-none-linux-gnueabihf-


# 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 einem älteren 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 ~/esl/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=~/esl/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=~/esl/toolchain/bin/arm-none-linux-gnueabihf-
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 ~/esl. Verwenden Sie für <branch> rpi-6.6.y

bash
# linux-rpi: lokales verzeichnis
git clone --depth=1 --branch rpi-6.6.y https://github.com/raspberrypi/linux

Ohne depth=1 und --branch rpi-6.6.y würden wir den ganzen Kernel Source mit allen commits und versionen clonen. Da wir nur am aktuellen stable release interessiert sind, sparen wir uns so etwas Speicherplatz (Transfer ca. 240 MiB, entpackt ca. 1.8 GB).

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 ~/esl/linux-rpi.

Installieren Sie noch folgende Pakete:

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

Zuerst laden wir die defconfig für unseren SoC:

bash
make bcm2711_defconfig

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.

menuconfig

Die Menuconfig ist ein Terminal basiertes Tool, hier ein Screenshot aus einer älteren Kernelversion:

XZ komprimierte Module

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

Wechseln Sie ins Verzeichnis des Kernels und suchen Sie mit ? nach dem SHT4x Sensor.

Lesen Sie an dieser Stelle nach, wie Sie beim Raspberry Pi den SHT40 einbinden könnten: https://github.com/raspberrypi/firmware/blob/master/boot/overlays/README.

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 / Kernelbinaries

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.