Aus Linux-Magazin 12/2016

Kernel- und Treiberprogrammierung mit dem Linux-Kernel – Folge 89

© psdesign1, Fotolia

Die Raspberry Pi Foundation sorgt dafür, dass auf der Version 3 ihres Minirechners ein 32-Bit-Linux startet – und das, obwohl der neue Raspberry eine reinrassige 64-Bit-CPU besitzt. Echte Linux-Kern-Techniker lässt die angezogene Handbremse nicht ruhen.

Als die Raspberry Pi Foundation Ende Februar 2016 das Model 3 ihres so erfolgreichen Minicomputers vorstellte, war die Freunde groß: Das neue Modell ist mit einer schnellen 64-Bit-ARMv8-CPU ausgestattet. Der Schwenk von 32-Bit- auf die 64-Bit-Betriebssysteme und -Anwendungen schien eingeleitet. Doch weit gefehlt: Zur großen Überraschung der meisten Raspi-Fans und -Entwickler reizt die neue 64-Bit-Hardware ihre Möglichkeiten überhaupt nicht aus und arbeitet rein 32-bittig (siehe Kasten “Die CPU des Raspberry Pi 3”).

Die Zurückhaltung geht so weit, dass ein Raspberry Pi 3 im vorgesehenen 32-Bit-Modus vorgibt, eine ARMv7-Architektur zu besitzen, obwohl auf ihm ein ARMv8 sitzt (Abbildung 1): Egal ob in den Bootmeldungen oder ob in der Ausgabe von »cat /proc/cpuinfo« – Kernel und Betriebssystem geben sich als Teil der BCM2709-Familie aus, tatsächlich sind sie Mitglieder der BCM2710-Familie.

Mit etwas Abstand wird die technologische Verzagtheit der Raspberry Pi Foundation dennoch nachvollziehbar:

  • Der Raspberry Pi 3 ist mit 1 GByte RAM bestückt – zu wenig, um vom erweiterten Adressbereich des ARMv8 zu profitieren.
  • Spürbarer Gewinn an Performance durch 64-Bit-Instruktionen ist nicht zu erwarten.
  • Die neue CPU ist selbst im 32-Bit-Modus der ARMv7-Architektur des alten Raspberry Pi deutlich überlegen.
  • Das mit der neuen Architektur einhergehende Fertigungsverfahren erlaubt höhere Taktfrequenzen.

Der gravierende Vorteil des 32-Bit-Betriebs ergibt sich aus dem Umstand, dass die Besitzer der Platinen ihr vorhandenes Raspbian-Userland unverändert weiter verwenden dürfen.

Abbildung 1: Der Raspberry Pi 3 verleugnet seine moderne Architektur und tarnt sich als 32-Bit-SoC.

Abbildung 1: Der Raspberry Pi 3 verleugnet seine moderne Architektur und tarnt sich als 32-Bit-SoC.

Die CPU des Raspberry Pi 3

Auf dem Raspberry Pi 3 sitzt als System on Chip ein Broadcom BCM2837, der zur Familie BCM2710 gehört. Es handelt sich um die Weiterentwicklung des BCM2836 (BCM2709) des Raspberry Pi 2, bei dem die ARMv7-CPU durch eine Quadcore-ARMv8-CPU vom Typ Cortex A 53 ersetzt wurde. Die CPU kann sowohl im 32-Bit- (AArch32) als auch im 64-Bit-Modus (AArch64) arbeiten, wobei der Raspi 3 als Default die 32-Bit-Variante wählt.

Hardwaretechnisch trumpft der Raspberry Pi mit einem Bluetooth- und einem WLAN-Modul auf. Allerdings ist der serienmäßige Bluetooth-Baustein mit dem ersten seriellen Port gekoppelt, sodass es bei Nutzung der seriellen Schnittstelle – zum Beispiel als Konsole – zu Kompatibilitätsproblemen kommt.

Die CPU verwendet einen modernisierten Befehlssatz, sie besitzt 31 64-Bit-Register statt der bisherigen 15 32-bittigen. Register 31 (Program Counter) liefert grundsätzlich Null beim Lesen. In der 64-Bit-Variante passieren Gleitkomma-Operationen grundsätzlich mit 128 Bit (Datentyp »long double« ). Des Weiteren unterstützt die CPU standardmäßig ARMs Multimedia- und Signalverarbeitungs-Erweiterung Neon, eine 128-Bit-SMID-Architektur (Single Instruction, Multiple Data). Zudem verarbeitet der Prozessor diverse Verschlüsselungsalgorithmen (AES, SHA-1, SHA-256) direkt im Silizium.

Technik muss begeistern

Auch wenn die 64 Bit beim Raspi 3 bestenfalls marginale Geschwindigkeitsvorteile bringen, kann es den Technik-begeisterten Linux-Entwickler nicht auf Dauer zufriedenstellen, bei den Hardwaremeldungen einen Wolf im Schafspelz zu halten und einen 64-Bit-Controller mit 32 Bit zu langweilen. Daher haben sich direkt nach Veröffentlichung des Raspberry Pi 3 Entwickler daran gemacht, den 64-Bit-Betrieb zu ermöglichen. Dazu mussten sie an der Firmware, am Kernel und am Userland Hand anlegen.

Die Firmware muss den Controller des Raspberry Pi 3 nämlich direkt beim Booten in den 64-Bit-Modus schalten. Immerhin sieht die Board-eigene Firmware das bereits vor. Dazu ist in der Datei »config.txt« auf der Bootpartition die Variable »arm-control« auf »0x200« zu setzen, wie diese Kern-Technik es später auch tun wird. Inzwischen soll eine neue Firmware sogar in der Lage sein, aus eigener Kraft einen 64-Bit-Kernel zu laden. Das haben die Kern-Technik-Autoren jedoch nicht ausprobiert.

Das U-Boot lädt nach

Der vorgeschlagene Weg besteht in der Verwendung der leistungsfähigen Bootsoftware “Das U-Boot”, welche die Standardfirmware anstelle eines Linux-Kernels lädt. Nötig ist die 64-Bit-Version von U-Boot, die das neue Bootkommando »booti« kennt. Booti hilft einen 64-Bit-ARM-Kernel zu laden, der einen spezifischen Header hat. Die Details nachzulesen gibt es in der Kerneldokumentation »Documentation/arm64/booting.txt« [1]. Mit diesem Header und noch anderen, von Linux festgelegten Randbedingungen, muss der Bootloader entsprechend umgehen können.

Wegen der überbordenden Vielfalt: Tree of Live

Der Kernel selbst muss natürlich ebenfalls für die 64-Bit-ARMv8-Architektur übersetzt sein. Dieser wiederum benötigt einen passenden Device Tree [2], also eine Datei, welche die Hardwaredetails beschreibt. In viel größerem Maße als die x86-Welt ist der ARM-Hardwarezoo deutlich artenreicher und verwendet für die Peripheriekomponenten unterschiedliche Adresslagen. Während in den Anfangstagen von ARM-Linux die Entwickler für jede unterstützte Hardware einen eigenen Kernel mit den jeweils passenden Adressen programmieren und übersetzen mussten, lesen heutige Kernel beim Booten den im Hauptspeicher bereitliegenden Device Tree live ein. Treiber bringen bei ihrer Aktivierung die Adresslagen über den Kernel in Erfahrung. Die Device-Tree-Unterstützung ist mittlerweile ausgereift und für ARM-Architekturen obligatorisch.

Fehlt nur noch das Root-Filesystem (mit dem Userland) selbst. Hier bietet Debian ein ARM64-System an, das sich beispielsweise per Debootstrap [3] installieren lässt. Aber bevor der Raspi-3-Besitzer jetzt mühsam versucht alle Teile des Puzzles selbst zu generieren und zusammenzustellen, macht er die ersten ARM64-Schritte besser mit einem vorkonfektionierten und getesteten 64-Bit-System aus dem Internet Abbildung 2 zeigt die Fundstelle des Artefakts, das hier Verwendung findet.

Dazu lädt er von [4] eine Imagedatei herunter, die er unter Linux per »dd« auf eine Mikro-SD-Karte schreibt. Er achtet dabei darauf, dass die Mikro-SD-Karte beim Beschreiben nicht eingehängt ist. Wenn die so aufmunitionierte SD-Karte im Raspberry Pi steckt und das System startet, erscheint auf einem angeschlossenen Monitor bereits nach wenigen Sekunden der Login. Der Pi-Besitzer loggt sich mit dem Usernamen »root« und dem Passwort »raspberry« ein.

Abbildung 2: Mitte April 2016 stellte User Xylnao ein fertiges 64-Bit-Image für den Raspberry Pi 3 bereit.

Abbildung 2: Mitte April 2016 stellte User Xylnao ein fertiges 64-Bit-Image für den Raspberry Pi 3 bereit.

Tatsächlich: Breitbit

Es gibt diverse Möglichkeiten, um festzustellen, dass hier ein 64-Bit-Linux läuft: »dmesg« beispielsweise gibt Bootmeldungen aus. Gleich in den ersten vier Zeilen verrät Linux die Architektur. »cat /proc/cpuinfo« plaudert zumindest aus, dass es sich um den ARMv8-Befehlssatz handelt, und »uname -a« zeigt an, dass der Kernel 64-bittig ist.

Wer ganz sicher gehen will, tippt den C-Quellcode von Listing 1 ab. Doch steht auf dem Test-Minisystem hierfür als Editor zunächst nur »vim« bereit. Wer damit nicht zurechtkommt und einen anderen Editor wie etwa den »nano« oder den »joe« benötigt, muss erst das Netzwerk aktivieren und danach den Editor nachinstallieren:

dhclient -i eth0
apt-get install joe nano

Das modifizierte “Hello World” gibt nach dem Start die Bitbreite von Zeigervariablen, den Pointern, aus. Nur auf einem 64-Bit-System sind diese auch 64 Bit breit. Zum Kompilieren des Quellcodes sollte es ausreichen, im Quellcodeverzeichnis »make hello« einzugeben, das Binary aufzurufen gelingt mit »./hello« (Abbildung 3).

Das 64-Bit-Linux für den Raspberry Pi ist zwar abgespeckt, ansonsten aber voll funktionsfähig. Auch die Konfiguration ist rudimentär, das Netzwerk beispielsweise nicht per Default aktiviert. Das System lässt sich – falls es mit dem Netzwerk verbunden und das Netzwerk aktiviert ist – updaten und beliebig erweitern. Debian hält hierfür bekanntlich einen reichen Schatz an Paketen bereit.

Abbildung 3: Anders als die Foundation vorsieht, lässt sich der Raspberry Pi 3 als 64-Bit-System nutzen.

Abbildung 3: Anders als die Foundation vorsieht, lässt sich der Raspberry Pi 3 als 64-Bit-System nutzen.

Listing 1

hello.c bestimmt die Architekturbreite

01 #include <stdio.h>
02
03 int main( int argc, char **argv, char **envp )
04 {
05     printf("Hello World\n");
06     printf("Es handelt sich um eine %d-Bit-Architektur\n",
07         sizeof(int *)*8);
08     return 0;
09 }

Quellen finden und selber einen Kernel herstellen

Aufregend wird es, einen eigenen, aktuellen 64-Bit-Kernel zu kompilieren. Auf dem Raspberry Pi 3 selbst ist das ein zeitraubender Vorgang. Schneller geht es als Cross-Entwicklung von einem PC aus [5]. Auf einem aktuellen Ubuntu sind die dazu benötigten Cross-Entwicklungswerkzeuge als Paket »gcc-aarch64-linux-gnu« problemlos zu installieren. Der Quellcode des Linux-Kernels ist ohnehin fürs Cross-Übersetzen vorbereitet. Dafür nötig sind die Kernelquellen aus dem Raspberry-Pi-Archiv, die sich zwar nur wenig vom Vanilla-Linux-Kernel unterscheiden, aber der Garant fürs fehlerfreie Übersetzen sind. Insbesondere bringt das Archiv der Foundation die für 64 Bit benötigte Default-Konfiguration »bcmrpi3_defconfig« mit, die dem Original noch fehlt. Der Quellcode selbst lässt sich beispielsweise im Verzeichnisbaum unterhalb von »/usr/src/arm« mit Hilfe von »git clone« ablegen. Das Git-Archiv enthält alle Kernelversionen, sodass der Entwickler noch lokal die aktuelle Kernel-Version (4.8) auschecken muss.

Ist der Kernel ausgecheckt, kann es losgehen. Als erstes sind zwei Environment-Variablen zu setzen, die das Kernel-Buildsystem anweisen nicht den Hostcompiler »gcc« , sondern den Crosscompiler »aarch64-linux-gnu-gcc« zu verwenden. Vor dem Start der Generierung ist der Kernel für den Raspberry Pi 3 zu konfigurieren. Ein »make -j 4 Image dtbs modules« startet den Build. Die Option »-j 4« erlaubt es, Make bis zu vier Prozesse parallel laufen zu lassen.

Das Übersetzen des Kernels, der Module und des Device Tree kann schon mal – abhängig von der eingesetzten Hardware – ein Stündchen dauern. Die genauen Kommandos vom Download des Quellcodes bis zum Generieren aller Komponenten fasst Listing 2 mit Kommentaren versehen zusammen.

Listing 2

ARM64-Kernel cross-kompilieren

01 sudo su
02
03 # Cross-Compiler installieren
04 #
05 apt-get install gcc-aarch64-linux-gnu
06
07 # Kernelquellcode fuer den Raspberry Pi downloaden
08 #
09 mkdir -p /usr/src/arm/
10 cd /usr/src/arm
11 git clone https://github.com/raspberrypi/linux.git
12 cd linux
13
14 # im Git-Archiv vorhandenen Versionen anzeigen
15 # und eine aktuelle Version auschecken
16
17 git branch -a
18 git checkout rpi-4.8.y
19
20 # Cross-Generierung des Kernels
21 #
22 export CROSS_COMPILE=aarch64-linux-gnu-
23 export ARCH=arm64
24 make bcmrpi3_defconfig
25 make -j 4 Image dtbs modules

Die Karte ausspielen

Die Installation von Kernel, Modulen und Device Tree wird etwas komplizierter. Als Grundlage nimmt diese Kern-Technik eine mit dem System aus [4] präparierte Micro-SD-Karte, die in den Entwicklungsrechner gesteckt wird. Ein auf dem Entwicklungs-PC laufendes Ubuntu wird die beiden Partitionen der Karte (Boot und Root) automatisch unterhalb von »/media/Username/« einhängen (Kommando »lsblk« in Abbildung 4).

Abbildung 4: Die Varinate für Ungeduldige: Bei ! hat Ubuntu die Micro-SD-Karte eingehängt. " Der »cp«-Befehl kopiert nur den selbst übersetzten Kernel als Datei »Image« auf die Bootpartition. Bei § hängt der Entwickler die Boot- und Root-Partitionen wieder aus.

Abbildung 4: Die Varinate für Ungeduldige: Bei ! hat Ubuntu die Micro-SD-Karte eingehängt. ” Der »cp«-Befehl kopiert nur den selbst übersetzten Kernel als Datei »Image« auf die Bootpartition. Bei § hängt der Entwickler die Boot- und Root-Partitionen wieder aus.

Zum Einspielen des eigenen Kernels bieten sich zwei Möglichkeiten an: Die Variante für Ungeduldige und die professionelle Variante. Ungeduldige kopieren nur den selbst kompilierten Kernel »arch/arm64/boot/Image« auf die Bootpartition (Abbildung 4). Das auf der Bootpartition befindliche U-Boot-Skript erwartet ihn nämlich dort unter dem Namen »Image« , sodass keine Änderung der Konfiguration notwendig ist.

Wer auf Nummer sicher gehen will, rettet den auf der SD-Karte unter gleichem Namen liegenden 64-Bit-Kernel, bevor er ihn mit dem eigenen Kernel überschreibt. Für einen ersten Test eignet sich der auf der SD-Karte ebenfalls schon vorhandene Device Tree. Der Tester hängt also die Karte direkt nach dem Kopieren des Kernels aus und steckt sie in den Raspberry Pi. Mit Strom versorgt sollte dieser nun den selbst generierten Kernel booten.

Profis konfigurieren U-Boot

Die professionelle Installation sieht vor, den Kernel unter einem eigenen Namen auf die Micro-SD-Karte zu kopieren, den richtigen Device Tree zu verwenden und vor allem die Kernelmodule auf die Rootpartition zu platzieren. Durch die neuen Namen für Kernel und Device Tree muss der Entwickler außerdem die Bootloader-Konfiguration von U-Boot anpassen [6]. Listing 3 zeigt die U-Boot-Skriptdatei dafür, die mit Hilfe des Programms »mkimage« einen U-Boot-Header erhält (Listing 4). Das Tool »mkimage« ist übrigens im Paket »u-boot-utils« enthalten. Ist alles so weit vorbereitet, hängt man die beiden Partitionen wieder aus und das System ist funktionsfähig.

Der U-Boot-Bootloader ist übrigens ähnlich leicht als 64-Bit-Variante zu generieren wie der Kernel. Dazu holt man per Git den Quellcode auf die heimische Maschine und setzt die Cross-Generierungsvariablen »ARCH« und »CROSS_COMPILE« , konfiguriert U-Boot für den Raspberry Pi 3 und lässt das Boot schließlich per »make« vom Stapel.

Listing 3

boot.txt

01 fatload mmc 0:1 ${fdt_addr_r} bcm2710-rpi-3-b.dtb
02 fatload mmc 0:1 ${kernel_addr_r} Image.4.8
03 setenv bootargs console=ttyS0,115200 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait rw
04 booti ${kernel_addr_r} - ${fdt_addr_r}

Listing 4

Eigenen Kernel (professionell) installieren

01 sudo su
02 cd /usr/src/arm/linux
03
04 # Installation von Kernel und Device Tree
05 #
06 cp arch/arm64/boot/Image /media/quade/A828-120E/Image.4.8
07 cp arch/arm64/boot/dts/broadcom/bcm2710-rpi-3-b.dtb \
08   /media/quade/A828-120E/
09
10 # Installation der Kernelmodule
11 #
12 make CROSS_COMPILE=aarch64-linux-gnu- ARCH=arm64 \
13   INSTALL_MOD_PATH=/media/quade/efcb352e-67ea-4eea-9ba4-205be4000670/ \
14   modules_install
15
16 # Anlegen des U-Boot-Skripts
17 #
18 cd /media/quade/A828-120E
19 vim boot.txt
20 apt-get install u-boot-tools
21 mkimage -A arm64 -O linux -T script -C none -d boot.txt boot.scr.uimg

Nach der Generierung findet sich unter anderem die Datei »u-boot.bin« im Quellcodeverzeichnis des Bootloaders, die das fertige 64-Bit-Executable darstellt. Zur Installation kopiert der Entwickler die Datei auf die Bootpartition der Micro-SD-Karte (Tabelle 1). Außerdem muss er die Datei »config.txt« anpassen (Listing 5), die in der vorhandenen Version »u-boot-stubbed.bin« lädt. Die Kommandos dazu sind in Listing 6 notiert.

Wer seinen Raspberry Pi dauerhaft mit dem 64 Bit laufen lassen will, muss sich Gedanken machen, wie er den ab und zu anfallenden Kernelpatches Geltung verschafft. Steht die hier beschriebene Build-Chain, geht das zum Glück einigermaßen simpel, indem der Raspi-Besitzer bei einem anstehenden Update das erwähnte Repository mit »git pull« anzapft und dem Kernel neu cross-kompiliert.

Tabelle 1

Startdateien auf der Bootpartition

Datei Bedeutung
botcode.bin Original-Rapberry-Bootloader
config.txt siehe Listing 5
bcm2710-rpi-3-b.dtb Device Tree
Image 64-Bit-Kernel 4.5
Image.4.8 64-Bit-Kernel 4.8
boot.scr.uimg Bootloader-Skript zum Laden von Kernel und Device Tree
uboot.bin 64-Bit-Bootloader

Listing 5

config.txt

01 enable_uart=1
02 # CPU in den 64-Bit-Modus schalten:
03 arm_control=0x200
04 kernel_old=1
05 kernel=uboot-stubbed.bin
06 # Selbst generierter Bootloader:
07 #kernel=u-boot.bin
08 disable_commandline_tags=1
09
10 # set display Mode to 1920x1080
11 #hdmi_group=2
12 #hdmi_mode=82

Listing 6

Bootloader cross-übersetzen und installieren

01 export CROSS_COMPILE=aarch64-linux-gnu-
02 export ARCH=arm64
03 git clone git://git.denx.de/u-boot.git
04 cd u-boot
05 make rpi_3_defconfig
06 make
07 cp u-boot.bin /media/quade/A828-120E/
08 vi /media/quade/A828-120E/config.txt
09     #kernel=u-boot-stubbed.bin
10     kernel=uboot.bin

Erfahrungen und Fazit

Der Raspberry Pi 3 im nicht vorgesehenen 64-Bit-Modus fühlt sich im ersten Testbetrieb gut und auf der Kommandozeile sehr responsiv an. Abseits des guten Gefühls zeigen aber einige (ebenso einfache wie nicht repräsentative und ohne Optimierung durchgeführte) Benchmarks keine Geschwindigkeitsvorteile. Das ist natürlich einerseits bedauerlich, entspricht aber andererseits der ursprünglichen Annahme.

Dennoch erscheint der 64-Bit-Betrieb des neuesten Raspberry Pi sinnvoll, und zwar nicht nur für Admins, die sich an falschen Meldungen (ARMv7 anstelle von ARMv8) stören, sondern auch für Software-Entwickler, welche die Funktionstüchtigkeit einer Minicomputer-Applikation auf 64 Bit testen wollen. Denn Rückwärtskompatibilität hin, wenig Speicher her: Irgendwann wird auch die Foundation ein eigenes 64-Bit-System präsentieren, möglicherweise aber erst für den Raspberry Pi 5.

Infos

  1. Will Deacon, “Booting AArch64 Linux”: http://lxr.free-electrons.com/source/Documentation/arm64/booting.txt
  2. Quade, Kunst, “Kern-Technik” – Folge 68 (Device Tree): Linux-Magazin 06/13, S. 76, https://www.linux-magazin.de/Ausgaben/2013/06/Kern-Technik
  3. Debian-Wiki, “Debootstrap”: https://wiki.debian.org/de/Debootstrap
  4. Vorbereitetes 64-Bit-Image für den Raspberry Pi 3: http://www.tom-yam.or.jp/rpi3/rpi3-arm64-debian-20160414.img.xz
  5. Quade, Kunst, “Kern-Technik” – Folge 69 (Kernel für den Raspberry Pi): Linux-Magazin 08/13, S. 86, https://www.linux-magazin.de/Ausgaben/2013/08/Kern-Technik
  6. Quade, Kunst, “Kern-Technik” – Folge 71 (Das U-Boot): Linux-Magazin 12/13, S. 90, https://www.linux-magazin.de/Ausgaben/2013/12/Kern-Technik

Der Autor

Eva-Katharina Kunst ist seit den Anfängen von Linux Fan von Open Source. Jürgen Quade, Professor an der Hochschule Niederrhein, hat mit “Embedded Linux lernen mit dem Raspberry Pi” 2014 sein drittes Linux-Buch veröffentlicht. Das gemeinsame Buch “Linux-Treiber entwickeln” ist jüngst in vierter Auflage erschienen.

DIESEN ARTIKEL ALS PDF KAUFEN
EXPRESS-KAUF ALS PDFUmfang: 5 HeftseitenPreis €0,99
(inkl. 19% MwSt.)
LINUX-MAGAZIN KAUFEN
EINZELNE AUSGABE Print-Ausgaben Digitale Ausgaben
ABONNEMENTS Print-Abos Digitales Abo
TABLET & SMARTPHONE APPS Readly Logo
E-Mail Benachrichtigung
Benachrichtige mich zu:
0 Kommentare
Älteste
Neuste Beste Bewertung
Nach oben