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.
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.
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.
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).
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
- Will Deacon, “Booting AArch64 Linux”: http://lxr.free-electrons.com/source/Documentation/arm64/booting.txt
- Quade, Kunst, “Kern-Technik” – Folge 68 (Device Tree): Linux-Magazin 06/13, S. 76, https://www.linux-magazin.de/Ausgaben/2013/06/Kern-Technik
- Debian-Wiki, “Debootstrap”: https://wiki.debian.org/de/Debootstrap
- Vorbereitetes 64-Bit-Image für den Raspberry Pi 3: http://www.tom-yam.or.jp/rpi3/rpi3-arm64-debian-20160414.img.xz
- 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
- 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










