Buildroot Image mit QEMU booten
14. Juni 2019
Will man Linux auf Mikroprozessoren zum Laufen bringen, dann kommt man mit den 0815 Linux-Distributionen nicht weit. Wenn es nicht schon an der Architektur scheitert, scheitert es i.d.R. an den zu generischen und damit zu großen Paketen (Programme, Bibliotheken). Eingebettete Systeme bringen nun mal nicht sonderlich viele Resourcen mit. Folglich muss man sich sein Linux-Betriebssystem selber bauen. Dazu bieten sich mehrere Möglichkeiten kann:
- OpenWrt wurde hauptsächlich entwickelt, um ein freies Betriebssystem für den eigenen Router zu haben. Die genutzten Skripte wären auch auf andere Hardware anpassbar, aber es gibt angenehmere Alternativen.
- Yocto wurde von Intel gepusht, um im Embedded-Bereich Fuß zu fassen und der Vorherrschaft von ARM Paroli zu bieten. Das Tool ist zweifelsohne mächtig, aber die Konfiguration ist alles andere als selbsterklärend und einfach.
- ELBE nimmt ein stabiles Debian und verschlankt das System so weit wie möglich (z.B.
rm -rf /usr/share/doc). Um einen Bootloader kümmert es sich nicht und das Gesamtsystem kann nie so klein sein, wie wenn das System für eine spezifische Hardware gebaut wird. Allerdings werden die verwendeten Pakete weltweit verwendet, d.h. es gibt unzählig viele Testsystem und Debian kümmert sich bereits um Sicherheitsprobleme. Entwickelt wird ELBE von Linutronix. - PTXdist erstellt ein Linuxsystem mit Bootloader und wird von Pengutronix entwickelt. Die Konfiguration wirkt nicht so selbsterklärend wie bei der nächsten Option und weiterhin finden sich im Netz kaum Anleitungen.
- Buildroot erstellt ebenfalls ein komplettes Linuxsystem inkl. Bootloader. Im Netz finden sich einige Anleitungen und Vorträge und ist daher meine erste Wahl.
Grundvoraussetzungen
Damit überhaupt Programme kompiliert werden können, braucht es ein Bündel an Programmen und Bibliotheken. Unter auf Debian basierenden Distributionen installiert man diese für gewöhnlich folgendermaßen.
$ sudo apt install build-essential
Weiterhin wird später noch QEMU verwendet werden, das gleich mitinstalliert werden kann.
$ sudo apt install qemu-system-arm
buildroot vorbereiten
In Anleitungen (Offizielle Dokumentation) findet sich häufig folgender Aufruf,
$ git clone git://git.buildroot.net/buildroot
aber das Repository scheint verschoben worden zu sein.
$ git clone git://git.busybox.net/buildroot
Standardmäßig wird der master Branch ausgecheckt, der nicht als stabil angesehen werden kann.
Deshalb checkt man ein Release aus.
Eine Liste der vorhandenen Releases bekommt man mit
$ git tag -l
..
2018.11.1
2018.11.2
2018.11.3
2018.11.4
2019.02
2019.02-rc1
2019.02-rc2
2019.02-rc3
2019.02.1
2019.02.2
2019.05
2019.05-rc1
2019.05-rc2
2019.05-rc3
und ausgecheckt werden sie so:
$ git checkout -b NeuerArbeitsBranch 2019.05
Switched to a new branch 'NeuerArbeitsBranch'
Wenn man sich nicht sicher ist, ob nicht schon Einstellungen vorgenommen wurden, kann man diese mit
$ make clean
$ make distclean
zurücksetzen.
Dabei entfernt clean alle von buildroot angelegten Dateien und distclean alle Konfigurationsdateien.
buildroot anschmeißen
Zur Konfiguration werde ich mich an anderer Stelle detaillierter äußern, um erst einmal loslegen zu können, genügt ein Rückgriff auf eine vorhandene Standardkonfiguration.
Im Falle von ARM ist es die qemu_arm_versatile_defconfig für einen arm926t und qemu_arm_vexpress_defconfig für einen Cortex-A9.
Um mehrere Konfigurationen gleichzeitig nebeneinander verwalten zu können, bedarf es verschiedener Build-Ordner.
Dafür muss man einzig den Parameter O= setzen.
Aus
$ make qemu_arm_versatile_defconfig
wird so
$ make O=../QemuArmVersatile qemu_arm_versatile_defconfig
Der Befehl kopiert nur die Konfigurationsdatei .config in den angegebenen Ordner.
Mit
$ make O=../QemuArmVersatile
wird der Buildprozess gestartet.
Aus
$ make qemu_arm_vexpress_defconfig
wird so
$ make O=../QemuArmVexpress qemu_arm_vexpress_defconfig
Der Befehl kopiert nur die Konfigurationsdatei .config in den angegebenen Ordner.
Mit
$ make O=../QemuArmVexpress
wird der Buildprozess gestartet.
Das kann etwas dauern, da in dieser Konfiguration z.B. der Compiler (gcc) explizit übersetzt wird und nicht auf einen eventuell vorhandenen Cross-Compiler des Host-Systems zurückgegriffen wird.
Nach dem erfolgreichen Durchlauf sieht der Ordner QemuArmVersatile (bzw. der Ordner QemuArmVexpress) folgendermaßen aus.
$ tree -L 2
.
├── build
│ ├── buildroot-config
│ ├── buildroot-fs
│ ├── build-time.log
│ ├── busybox-1.30.1
│ ├── host-acl-2.2.53
│ ├── host-attr-2.4.48
│ ├── host-autoconf-2.69
│ ├── host-automake-1.15.1
│ ├── host-binutils-2.31.1
│ ├── host-bison-3.0.4
│ ├── host-e2fsprogs-1.44.5
│ ├── host-fakeroot-1.20.2
│ ├── host-flex-2.6.4
│ ├── host-gcc-final-7.4.0
│ ├── host-gcc-initial-7.4.0
│ ├── host-gettext
│ ├── host-gettext-tiny-c6dcdcdef801127549d3906d153c061880d25a73
│ ├── host-gmp-6.1.2
│ ├── host-kmod-25
│ ├── host-libtool-2.4.6
│ ├── host-libzlib-1.2.11
│ ├── host-m4-1.4.18
│ ├── host-makedevs
│ ├── host-mpc-1.1.0
│ ├── host-mpfr-4.0.2
│ ├── host-patchelf-0.9
│ ├── host-pkgconf-1.6.1
│ ├── host-skeleton
│ ├── host-tar-1.29
│ ├── host-util-linux-2.33
│ ├── host-zlib
│ ├── ifupdown-scripts
│ ├── initscripts
│ ├── linux-4.19.16
│ ├── linux-headers-4.19.16
│ ├── locales.nopurge
│ ├── packages-file-list-host.txt
│ ├── packages-file-list-staging.txt
│ ├── packages-file-list.txt
│ ├── qemu_arm_versatile
│ ├── skeleton
│ ├── skeleton-init-common
│ ├── skeleton-init-sysv
│ ├── toolchain
│ ├── toolchain-buildroot
│ └── uclibc-1.0.31
├── host
│ ├── arm-buildroot-linux-uclibcgnueabi
│ ├── bin
│ ├── etc
│ ├── include
│ ├── lib
│ ├── lib64 -> lib
│ ├── libexec
│ ├── sbin
│ ├── share
│ └── usr -> .
├── images
│ ├── rootfs.ext2
│ ├── versatile-pb.dtb
│ └── zImage
├── Makefile
├── staging -> host/arm-buildroot-linux-uclibcgnueabi/sysroot
└── target
├── bin
├── dev
├── etc
├── lib
├── lib32 -> lib
├── linuxrc -> bin/busybox
├── media
├── mnt
├── opt
├── proc
├── root
├── run
├── sbin
├── sys
├── THIS_IS_NOT_YOUR_ROOT_FILESYSTEM
├── tmp
├── usr
└── var
72 directories, 11 files
Von Interesse sind in erster Linie die Dateien Ordner images.
Dort liegt das Dateisystem rootfs.ext, der device tree versatile-pb.dtb (bzw. vexpress-v2p-ca9.dtb) in seiner kompilierten Form und der Kernel zImage.
QEMU starten
Das eben erstellte Image kann nun mit QEMU ausgeführt werden. Da QEMU einige Parameter übergeben werden müssen, packt man den Aufruf der Einfachheit halber in ein Skript.
Dieses Skript legt man außerhalb von QemuArmVersatile ab, schließlich kann und wird sich am Image noch etwas ändern.
#!/bin/sh
qemu-system-arm \
-M versatilepb \
-kernel QemuArmVersatile/images/zImage \
-dtb QemuArmVersatile/images/versatile-pb.dtb \
-drive file=QemuArmVersatile/images/rootfs.ext2,if=scsi,format=raw \
-append "root=/dev/sda console=ttyAMA0,115200" \
-serial stdio \
-net nic,model=rtl8139 -net user \
-name Versatile_ARM_EXT2
Führt man das Skript aus, so sollte der Bootvorgang starten und folgende Ausgaben erscheinen.
Dieses Skript legt man außerhalb von QemuArmVexpress ab, schließlich kann und wird sich am Image noch etwas ändern.
#!/bin/sh
qemu-system-arm \
-M vexpress-a9 \
-kernel QemuArmVexpress/images/zImage \
-dtb QemuArmVexpress/images/vexpress-v2p-ca9.dtb \
-drive file=QemuArmVexpress/images/rootfs.ext2,if=sd,format=raw \
-append "rw console=ttyAMA0 console=tty root=/dev/mmcblk0" \
-cpu cortex-a9 \
-m 32 \
-serial stdio \
-net nic,model=lan9118 \
-net user \
-name Vexpress_ARM
Führt man das Skript aus, so sollte der Bootvorgang starten und folgende Ausgaben erscheinen.
Das System funktioniert, fehlt noch das Einspielen und Debuggen der eigenen Applikation, was in einem separaten Beitrag behandelt wird.