Arch Linux auf einem Banana Pro mit einer nur lesbar gemounteten SD-Karte zu installieren, ist ganz einfach.

Einige Warnungen zuvor: Diese Anleitung geht davon aus, dass der Leser ein wenig Vorkenntnis besitzt. Arch Linux on ARM (ALARM) ist ein Rolling-Release-System und unterstützt das Banana Pro offiziell nicht. Daher hat dieser Artikel vermutlich eine geringe Haltbarkeit.

Im Vergleich zu anderen Distributionen für Einplatinencomputer ist das Schöne an ALARM, dass das Basis-Image sehr minimal ist. Daher muss beim Umbau auf ein read-only Root-Dateisystem wenig beachtet werden. Außerdem sind die serielle Konsole und SSH-Zugriff per Default aktiviert.

Installation von Arch Linux

Wer ALARM schon installiert hat, kann diesen Abschnitt überspringen und weiter unten direkt zum Umbau auf read-only Root übergehen. Zur Installation folgte ich der Anleitung im Arch Linux Wiki für das Banana Pi. Ich nullte gemäß Anleitung die ersten 8 MB der SD-Karte aus:

dd if=/dev/zero of=/dev/sdX bs=1M count=8

Das muss man vermutlich nicht. Ich habe es auch mit Zufallszahlen probiert, kann aber auch nur zufällig geklappt haben.

Ich habe dann mit fdisk die gesamte SD-Karte als eine große Partition für "Linux" erstellt (Tastenfolge o,n,p,<CR>,<CR>,<CR>,w). Dann ein ext4-Dateisystem in dieser Partition, bei dem explizit die Metadaten-Checksumme deaktiviert ist.

mkfs.ext4 -O "^metadata_csum" /dev/sdX1

Die Original-Anleitung verlang auch noch ^64bit. Das impliziert (siehe man ext4), dass das Dateisystem bei einer Karte mit 512B Blockgröße maximal 2 TB haben kann. Da komme ich aber bei weitem nicht ran. Frühere Versionen von U-Boot konnten ext4 mit diesem Feature nicht lesen. Das LeMaker Wiki tut das auch nicht, andererseits haben die eine eigene Bootpartition mit FAT. ^metadata_csum ist auch nur wichtig, wenn man irgend wann einmal von U-Boot aus in die Partition schreiben will.

Als nächstes baute ich den Bootloader U-Boot:

git clone https://gitlab.denx.de/u-boot/u-boot.git
cd u-boot
make ARCH=arm CROSS_COMPILE=arm-none-eabi- Bananapro_defconfig
make ARCH=arm CROSS_COMPILE=arm-none-eabi-

Das benötigt den Crosscompiler arm-none-eabi-gcc sowie die Programme dtc und swig. Außerdem braucht man später das Paket uboot-tools mit mkimage.

Die Datei u-boot-sunxi-with-spl.bin habe ich nun gemäß Anleitung an Stelle 8 kB mitten in die SD-Karte geflasht:

dd if=u-boot-sunxi-with-spl.bin of=/dev/sdX bs=1024 seek=8

Wieso das dann alles mit der Partitionstabelle gehen soll, war mir nicht klar, aber hier die Erklärung: Der MBR mit seiner Partitionstabelle ist nur 512 Byte groß. fdisk behandelt aber die ersten 2048 Sektoren als reserviert. Die eigentliche Partition startet also erst bei einem Offset von 1 MB. Es ist also genügend Platz für das 500 kB große Bootloader-Image.

Das ext4-Dateisystem habe ich dann als root/ eingehängt und das Image von http://archlinuxarm.org/os/ArchLinuxARM-armv7-latest.tar.gz drauf extrahiert.

tar -xvpf ArchLinuxARM-armv7-latest.tar.gz -C root/

Wichtig ist, dass man bei tar den Schalter -p verwendet ("preserve attributes"). Danach allgemein unbedingt ein sync -f auf die Dateien in der Karte machen. Meine Karte ist etwas langsam, daher hat es ewig gebraucht, bis die Daten aus dem Dateisystem-Cache waren.

Dann habe ich das Boot-Script boot.cmd aus dem Arch-Wiki kopiert:

part uuid ${devtype} ${devnum}:${bootpart} uuid
setenv bootargs console=${console} root=PARTUUID=${uuid} rw rootwait

if load ${devtype} ${devnum}:${bootpart} ${kernel_addr_r} /boot/zImage; then
  if load ${devtype} ${devnum}:${bootpart} ${fdt_addr_r} /boot/dtbs/${fdtfile}; then
    if load ${devtype} ${devnum}:${bootpart} ${ramdisk_addr_r} /boot/initramfs-linux.img; then
      bootz ${kernel_addr_r} ${ramdisk_addr_r}:${filesize} ${fdt_addr_r};
    else
      bootz ${kernel_addr_r} - ${fdt_addr_r};
    fi;
  fi;
fi

if load ${devtype} ${devnum}:${bootpart} 0x48000000 /boot/uImage; then
  if load ${devtype} ${devnum}:${bootpart} 0x43000000 /boot/script.bin; then
    setenv bootm_boot_mode sec;
    bootm 0x48000000;
  fi;
fi

Hier steht schon der Kernel-Parameter rw, den ich später zu ro ändern werde.

Mit mkimage erzeugte ich daraus ein von U-Boot interpretierbares Boot-Script, das sofort auf die SD-Karte geschrieben wurde:

mkimage -A arm -O linux -T script -C none -a 0 -e 0 -n "Banana Pro boot script" -d boot.cmd root/boot/boot.scr

In diesem Zustand ist die SD-Karte bootbar.

Erster Start

Ich benutze meist eine USB-UART-Bridge, aber auch der Zugang per mit mkimage SSH (Standard-Hostname alarm) ist möglich. Über die serielle Schnittstelle begrüßt mich das Banana Pro mit einem Stacktrace - wie gesagt, ist es nicht offiziell von ALARM unterstützt. Der Benutzername ist alarm, Passwort alarm, dann Zugriff per su mit Passwort root. Login als root ist als Default deaktiviert.

Als allererstes habe ich den Schlüsselbund initialisiert und das System geupdatet:

pacman-key --init
pacman-key --populate archlinuxarm
pacman -Syyuu
reboot

Tip: Der linke Knopf fährt das Banana Pro normal herunter, ähnlich wie ein Strg+Alt+Entf. Der rechte Knopf macht einen harten Reset und fährt es so wieder hoch. Ist das Banana Pro heruntergefahren, erlischt die rote LED.

Read-Only Boot

Ich habe schon einige Versuche gemacht, Armbian readonly booten zu lassen. Das mache ich immer so: Bei einigen Dingen weiß ich schon, wie ich sie umbauen muss. Dann boote ich mit Option ro und sehe zu, was alles abstürzt. Diese Sachen repariere ich dann noch, bis ich fehlerfrei booten kann. Bei Armbian, das eine etwas größere Standardinstallation bietet, habe ich das nie hundertprozentig hingebracht. Deshalb jetzt der Versuch mit ALARM.

Das erste Problem ist immer /var/log und /var/tmp. Die Logfiles will ich nicht abspeichern müssen. Daher entfernte ich zunächst /var/tmp und erstellte dafür mit ln -s einen Symlink /var/tmp -> /tmp. /var/log wird dann ein Link auf /var/tmp/log. Damit dieses Directory beim Start auch vorhanden ist, erstellte ich ein File /etc/tmpfiles.d/000readonly.conf mit dem Inhalt (siehe man tmpfiles.d)

d /var/tmp/log 0755 - - -

Als Editor ist vi vorinstalliert.

Weiterhin ist systemd-random-seed immer ein Problem. Dieser Service hilft normalerweise dabei, beim Start die Entropie von Zufallszahlen aus /dev/urandom zu erhöhen. Er lädt dazu die Datei /var/lib/systemd/random-seed. Beim Herunterfahren wird eine Zufallszahl in die Datei geschrieben, außerdem wird die Datei auch beim Boot schon irgendwie berührt. Ganz gefährlich wäre es, die Datei einfach so stehen zu lassen, wie sie jetzt ist, denn so werden die Zufallszahlen unter Umständen vorhersehbar. Oft sehe ich die Methode, diese Datei durch einen Symlink auf eine Datei unter /tmp zu ersetzen. Dann wird sie beim Start von systemd-random-seed erstellt. Sie bringt dann nur nichts mehr, also braucht man sie eigentlich auch nicht zu erstellen. Ich entfernte also die Datei und maskierte den Service (er lässt sich nicht einfach deaktivieren):

systemctl stop systemd-random-seed.service
systemctl mask systemd-random-seed.service
rm -f /var/lib/systemd/random-seed

Nun startete ich selbst schon mit read-only Root, was aber noch Probleme aufzeigte. Der Service systemd-timesyncd synchronisiert per NTP die Uhr. Das ist auf dem Banana Pro sehr wichtig, hat es doch keine RTC. Er möchte aber bei jedem Synchronisieren die Datei /var/lib/systemd/timesync/clock schreiben. Noch schlimmer, er macht sogar Probleme, wenn clock oder das timesync-Directory ein Link sind. Daher erstellte ich für diesen Pfad einen Eintrag in der /etc/fstab. Mit tmpfs-Mounts will ich eigentlich sparsam umgehen, aber hier ein zusätzliches tmpfs mit maximal 1 Kilobyte Größe:

tmpfs  /var/lib/systemd/timesync  tmpfs  auto,noatime,size=1k,mode=0755,uid=systemd-timesync,gid=systemd-timesync  0  0

Als letzten Schritt bearbeitete ich das Skript boot.cmd, ersetzte das rw-Flag durch ro und compilierte das boot.scr erneut auf die SD-Karte. Damit ist die Installation fertig gestellt. Zur Sicherheit empfiehlt es sich immer wieder, mit journalctl -p4 nachzusehen, ob Dienste Probleme damit bekommen, dass / nur lesbar eingehängt ist. Bei der Installation von neuer Software muss man sich immer informieren, wo diese schreiben möchte, und welche Daten wirklich persistent sein müssen. Für diese Programme kann man dann Speicherplatz auf einem USB-Stick oder einer SATA-Platte zur Verfügung stellen. So zum Beispiel könnte auch der random-seed verwendet werden.

Previous Post