Neben dem Erkennen und Laden des Kernelimages ist U-Boot dafür verantwortlich dem Kernel das richtige Device der Rootpartition zu übergeben. Die in Abschnitt 3.2 beschriebene Methode schlägt u.U. fehl, wenn sich Anzahl und/oder Reihenfolge der von U-Boot bzw. Kernel erkannten Speichermedien unterscheiden37. Solche Vermittlungsprobleme lassen sich ausschließen, indem der Kernel veranlasst wird, die Rootpartition anhand eindeutiger Merkmale eigenständig zu erkennen. Diese sind:
UUID oder Label des Dateisystems auf der Rootpartition. Um diese beim Booten zu erkennen ist der Kernel auf eine initial ramdisk angewiesen.
PARTUUID oder PARTLABEL der Rootpartition. Diese stehen nur dann zur Verfügung wenn der USB-Stick über eine GUID-Partitionstabelle (GPT) verfügt. Bei Angabe der PARTUUID ist eine initial ramdisk nicht erforderlich.
Beide Möglichkeiten werden nachfolgend beschrieben. Um die Bootloaderkonfiguration auch von Arch Linux ARM aus durchführen zu können, wird das Paket uboot-tools
benötigt. In /etc/fw_env.config
ist anschließend die Raute vor dem Eintrag für den DockStar zu entfernen.
#/etc/fw_env.config
# segate dockstar:
/dev/mtd0 0xc0000 0x20000 0x20000
Normalerweise wird eine initrd benötigt, um die zum Mounten der Rootpartition benötigten Treiber für Datenträger und Dateisysteme zur Verfügung zu stellen. Diese sind bei Arch Linux ARM jedoch fest in den Kernel integriert, weshalb das Kernelpaket keine initrd bereitstellt. Sie muss folglich nachträglich erstellt werden.
Unter Arch Linux (i686/x86_64) wird anstelle von initrd der Nachfolger initramfs genutzt, das mit mkinitcpio konfiguriert wird. Es werden nur zwei Hooks benötigt:
#/etc/mkinitcpio.conf
HOOKS="base udev"
Das initramfs für den laufenden Kernel (andernfalls Option -k nutzen) wird wie folgt generiert:
[root@alarm ~]# mkinitcpio -v -g /tmp/initramfs-linux.img
Es kann unter Arch Linux ARM nicht direkt genutzt werden, mit mkimage
(aus dem Paket uboot-tools
) lässt sich daraus aber die eigentliche initial ramdisk erstellen:
[root@alarm ~]# mkimage -A arm -O linux -T ramdisk -C gzip -a 0x00000000 -e 0x00000000 -n initramfs -d /tmp/initramfs-linux.img /boot/uInitrd
Die Datei /boot/uInitrd
wird von U-Boot ohne weitere Konfiguration erkannt und eingebunden. Sodann sorgt udev
für das Anlegen eines dem Label der Rootpartition (hier: root
) entsprechenden Links unter /dev/disk/by-label/
, der als Kernelparameter genutzt werden kann. Außerdem setze ich rootwait
anstelle von rootdelay
ein:
[root@alarm ~]# fw_setenv usb_set_bootargs 'setenv bootargs console=$console root=/dev/disk/by-label/root rootwait rootfstype=ext4 $mtdparts $usb_custom_params'
Alternativ kann auch wie in einem Blog beschrieben usb_init
angepasst werden. Anstelle des Labels sollte sich auch die UUID über den Link unter /dev/disk/by-uuid/
nutzen lassen, ich habe dies jedoch nicht ausprobiert. Problematisch ist dagegen die Verwendung der Schreibweisen root=LABEL=...
und root=UUID=...
. Beide haben nicht zuverlässig funktioniert, näheres im Forum.
Speichermedien mit GPT können vom Linux Kernel ab Version 2.6.37 genutzt werden. Die notwendige Option CONFIG_EFI_PARTITION=y
ist im ARCH-Kernel aktiviert und sollte natürlich ggf. auch bei einem Custom-Kernel ausgewählt sein.
Zum Anlegen einer GPT dient das Programm gdisk
. Wurde der Stick bereits mit fdisk
formatiert, kann gdisk
die GPT unter Verwendung der im MBR vorhandenen Partitionstabelle auch nachträglich anlegen. Die notwendigen Schritte habe ich an meinem Linux-PC durchgeführt. Wie schon in Abschnitt 2.1 verwende ich wieder sdx
stellvertretend als Device des USB-Sticks (von dem ich zuvor sicherheitshalber ein Backup angelegt habe).
[root@linux ~]# gdisk /dev/sdx
Warnhinweise sollte man beachten und das Programm ggf. mit 'q'
abbrechen. Insgesamt gab es zwei Hürden zu nehmen, die ich hier genauer beschreibe:
Aus Redundanzgründen beansprucht die GPT auch einen Bereich am Ende des Speichermediums, der jedoch bereits Bestandteil der dritten Partition ist. Folglich vermeldet gdisk
zunächst:
Warning! Secondary partition table overlaps the last partition by
33 blocks!
You will need to delete this partition or resize it in another utility.
Es war also erforderlich zunächst die letzte (dritte) Partition um 33 Blöcke (gemeint sind Sektoren á 512 Byte) zu verkürzen. Dazu muss zunächst das auf der Partition befindliche Dateisystem mit resize2fs
verkleinert werden. Dabei ist die Blockgröße des Dateisystems zu berücksichtigen:
[root@linux ~]# dumpe2fs /dev/sdx3|grep "^Block"
dumpe2fs 1.41.14 (22-Dec-2010)
Block count: 3590912
Block size: 4096
Blocks per group: 32768
Die Anzahl der Dateisystemblöcke muss folglich um 33*512/4096, also mindestens 5 reduziert werden. Es schadet aber nichts, das Dateisystem zunächst stärker als nötig zu verkleinern (s.u.). In jedem Fall muss es vorher mit e2fsck
einer Prüfung unterzogen werden.
[root@linux ~]# e2fsck -f /dev/sdx3
[root@linux ~]# resize2fs /dev/sdx3 3590907
[root@linux ~]# fdisk /dev/sdx
Das Verkleinern der Partition erfolgt mit fdisk
einfach durch Löschen und erneutes Anlegen (d-3-n-p-3). Der vorgeschlagene Startsektor kann übernommen werden, der letzte Sektor ist jedoch um 33 auf 31252446 zu verringern, vgl. Abschnitt 2.1.
Optional lässt sich das Dateisystem mit resize2fs
dann wieder automatisch auf die durch die neue Partitionsgröße vorgegebene maximale Größe erweitern. Bei der beschriebenen Vorgehensweise erübrigt sich dies:
[root@linux ~]# resize2fs /dev/sdx3
resize2fs 1.41.14 (22-Dec-2010)
Das Dateisystem ist schon 3590907 Blöcke groß. Nichts zu tun!
Zuletzt genügt ein erneuter Aufruf von gdisk /dev/sdx
zur Umwandlung des MBR in eine GPT. Sollten keine Warnungen erscheinen, beendet man dazu einfach mit 'w'
.
Der Versuch den so manipulierten Stick nun testweise wieder am DockStar zu booten schlug fehl. Vermittels netcat
stellte sich heraus, dass U-Boot die Partitionen das Sticks nicht mehr zu lesen vermochte:
Loading file "/boot/uImage" from usb device 1:1 (usbdb1)
Failed to mount ext2 filesystem...
** Bad ext2 partition or disk - usb 1:1 **
Abhilfe sollte laut eines Forumsbeitrags das Erstellen eines hybriden MBR bringen38, der nur die Bootpartition als erste Partition enhält. Hier die genaue Vorgehensweise mit gdisk
unter Zuhilfenahmen der GPT Dokumentation.
Command (? for help): r
Recovery/transformation command (? for help): h
WARNING! Hybrid MBRs are flaky and dangerous! If you decide not to use one,
just hit the Enter key at the below prompt and your MBR partition table will
be untouched.
Type from one to three GPT partition numbers, separated by spaces, to be
added to the hybrid MBR, in sequence: 1
Place EFI GPT (0xEE) partition first in MBR (good for GRUB)? (Y/N): n
Creating entry for GPT partition #1 (MBR partition #1)
Enter an MBR hex code (default 83):
Set the bootable flag? (Y/N): y
Unused partition space(s) found. Use one to protect more partitions? (Y/N): n
Recovery/transformation command (? for help): w
Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING
PARTITIONS!!
Do you want to proceed? (Y/N): y
OK; writing new GUID partition table (GPT).
The operation has completed successfully.
Erfreulicherweise erkannte U-Boot den Stick nun wie bisher. Um den Vorteil der GPT zu nutzen brauchen wir noch die “Partition unique GUID” der Rootpartition. Diese bringt - unter Arch Linux ARM - ein erneuter Aufruf von gdisk
nach Eingabe von 'i'
und Partitionsnummer zu Vorschein:
Command (? for help): i
Partition number (1-3): 2
Partition GUID code: 8EC76FBA-2272-45AF-A844-94ED164A1B86 (Unknown)
Partition unique GUID: 43152BE8-EA6D-47EE-A014-59C52C383DE0
First sector: 67584 (at 33.0 MiB)
Last sector: 2525183 (at 1.2 GiB)
Partition size: 2457600 sectors (1.2 GiB)
Attribute flags: 0000000000000000
Partition name: Linux filesystem
Mit dieser Information kann die Bootvariable wie folgt angepasst werden:
[root@alarm ~]# fw_setenv usb_set_bootargs 'setenv bootargs console=$console root=PARTUUID=43152BE8-EA6D-47EE-A014-59C52C383DE0 rootwait rootfstype=ext4 $mtdparts $usb_custom_params'
Vor dem Reboot sollte man eine etwaig vorhandene /boot/uInitrd
wieder löschen oder umbenennen. Andernfalls wird der Bootvorgang nach Laden des Kernels nicht fortgesetzt.
Die PARTUUID kann mit gdisk
auch auf einen bestimmten Wert eingestellt werden (x-c-2). So lässt sich etwa ein Backup-USB-Stick mit identischer PARTUUID herstellen, von dem ohne erneute Anpassung des Bootmanagers ersatzweise gebootet werden kann.
Nachdem ich jüngst eine der speziell für den Betrieb am oberen USB-Anschluss der DockStar vorgesehenen 2,5" Festplatten “FreeAgent Go” erworben hatte, musste ich mittels Netzkonsole festellen, dass diese von U-Boot nicht zuverlässig erkannt wurde: War beispielsweise neben der Festplatte nur der USB-Stick angeschlossen, wurde dieser von U-Boot als erstes/einziges Device erkannt und gemäß Abschnitt
3.2 folglich sda2
als Rootpartition übermittelt. Aus Kernelsicht stellte sda
jedoch die Festplatte dar, so dass der Bootvorgang nicht fortgesetzt werden konnte.
↩
Mit Mainline U-Boot erübrigt sich die Erstellung eines hybriden MBR. ↩