Jeder Prozessor startet nach dem Poweron in einem definiertem Zustand. Je nach Prozessor kann das eine eigene Adresse sein. Einfache Prozessoren wie ein Atmel Atmega beginnen direkt mit der Ausführung von Benutzercode. Arm Prozessoren um die es hier gehen soll führen erstmal ein im Prozessor ROM hinterlegtes Programm aus um die internen Strukturen zu initialisieren. Dieses ROM kann nur vom Prozessorhersteller während der Produktion geschrieben werden. Ist diese erste Initialisierung abgeschlossen kann das Benutzerprogramm geladen werden. Ich möchte hier verschiedene Arm Beispiele wie den BeagleBoneBlack (BBB), BeagleBoneAI (BBAI) und den Exoten Raspberry Pi4 (was das booten angeht) beschreiben.
Der ganze Bootprozess ist immer irgendwie damit vergleichbar, sich selbst am Schopf aus dem Sumpf zu ziehen. Immer ein bischen mehr Möglichkeiten bis es komplett geschafft ist das System zu booten.
Hier soll es um u-boot gehen:
https://github.com/u-boot/u-boot
u-boot ist eine unglaublich flexible Möglichkeit einen Rechner/SBC/SOC zu booten. Es hat momentan eine Sammlung von 1206 Standardkonfigurationen für verschiedene Boards. Allein für den Raspberry Pi4 gibt es 4 Konfigurationen welche gepflegt werden. Der BBB bzw der am335x hat 16 Konfigurationen. Es ist also praktisch unmöglich für mich hier alles aufzuzeigen. Deshalb zeige ich was ich bisher gelernt habe. Insbesondere
https://github.com/u-boot/u-boot/blob/m ... distro.rst
zeigt sehr sehr viel.
Kompilieren ist einfach:
Code: Alles auswählen
git clone https://github.com/u-boot/u-boot
apt install build-essential gcc
git checkout v2022.10
make rpi_arm64_defconfig
make
Standardkonfigurationen:
BBB: https://github.com/u-boot/u-boot/blob/m ... _defconfig
bzw
BBAI: https://github.com/u-boot/u-boot/blob/m ... _defconfig
Hier ist der Bootprozess so wie man sich das eigentlich vorstellt. Die CPU versucht auf den zwei definierten (e)MMC Schnittstellen eine Partitionstabelle im MSDOS Format. Das ist wie geschrieben, nicht spezifisch Arm, das ist spezifisch AM3358/9 bzw. AM57xx. Ist die Partitionstabelle gefunden, wird eine FAT Partition mit einem Bootflag gesucht. Da die Hersteller natürlich keine gigantischen ROMs haben wird hier häufig FAT verwendet. Ein sehr einfach in wenig Code zu implementierendes Filesystem. In diesem Filesystem wird dann MLO gesucht. MLO, das ist der erste Usercode welcher ausgeführt wird. MLO initialisiert den System RAM liest die u-boot.img ein und startet damit den zweiten Bootloader u-boot.img. u-boot.img liest die uboot.env vom selben Filesystem ein. uboot.env ist eine Datei welche in einem Binärformat geschrieben ist und eine feste Größe hat. Diese Größe ist in der u-boot Konfiguration hinterlegt. Hier ist aber schon Wissen über die Hardware notwendig. Devicetrees. Das beschreibe ich später.
Diese Datei enthält Environmentvariablen welche in die Standard Environmentvariablen "gemergt" werden bzw. überschrieben werden. Die Standardwerte sind im Code von u-boot enthalten. Wichtig für unser Beispiel hier ist die distro_bootcmd Variable.
Code: Alles auswählen
CONFIG_BOOTCOMMAND: │
│ │
│ This is the string of commands that will be used as bootcmd and if │
│ AUTOBOOT is set, automatically run. │
│ │
│ Symbol: BOOTCOMMAND [=run distro_bootcmd] │
│ Type : string │
│ Prompt: bootcmd value │
│ Location: │
│ -> Boot options │
│ -> Enable a default value for bootcmd (USE_BOOTCOMMAND [=y]) │
│ Defined at boot/Kconfig:1329 │
Das hängt direkt damit zusammen. Ist das hier auf N, gibt es distro_bootcmd nicht. Es wird für reguläre Distributionen empfohlen das zu verwenden. Damit ist u-boot gut zu configurieren. Für Distributionen und User.
Code: Alles auswählen
│ CONFIG_DISTRO_DEFAULTS: │
│ │
│ Select this to enable various options and commands which are suitable │
│ for building u-boot for booting general purpose Linux distributions. │
│ │
│ Symbol: DISTRO_DEFAULTS [=y] │
│ Type : bool │
│ Prompt: Select defaults suitable for booting general purpose Linux distributions │
│ Location: │
│ -> General setup │
│ Defined at Kconfig:194 │
Was wir bisher haben ist eine Konsole über tty mit der wir den Start kontrollieren können. Nicht sehr schön. Was aber u-boot auch kann ist eine extlinux.conf Datei zu lesen und zuverarbeiten. Das ist dann wir der PC Bootloader syslinux bzw extlinux. Damit u-boot die extlinux.conf liest braucht es diese distro_bootcmd:
Code: Alles auswählen
sysboot usb 0:2 any 0x02400000 /extlinux/extlinux.conf
Meine extlinux.conf sieht so aus beim Raspi:
Code: Alles auswählen
georg@rpi4-ws:~/Dokumente/Entwicklung/u-boot$ cat /boot/extlinux/extlinux.conf
menu title Linux selections
timeout 2
# This is the default label
label default
menu label Default Kernel
kernel /vmlinuz
initrd /initrd.img
fdtdir /fdt
append ro video=HDMI-A-1:1680x1050M@60 console=tty1 root=UUID=3136d973-d911-4f6c-9c80-5ee4fdf08ec5 rootfstype=btrfs rootflags=subvol=rootfs fsck.repair=yes rootwait net.ifnames=0 quiet
Varianten:
Das Image das für die BeagleBoards runter geladen werden kann hat keine Bootpartition! Es hat einen Start der Partition die bischen weiter hinten liegt. MLO, u-boot.img und uboot.env sitzen an festen Sektor Addressen auf der SD bzw. MMC. Ich hab den Maintainer Robert Nelson gefragt, da das "früher" wie oben beschrieben war. Er sagte das viele Leute die Bootpartiton gelöscht hatten um mehr Platz zu bekommen auf der SD aber dabei das Board "gebrickt" hatten. Nicht wirklich tot aber für Anfänger oft unlösbar da ihnen das Verständnis dafür fehlte. Also hat er die Default Config so geändert das die Sektoren verwendet werden (ähnlich wie ganz früher unter den MSDOS Partitionsboot Schemas) da dadurch das vor vielen Leuten verborgen bleibt. Das war "früher" auch schon möglich. Er hat einfach die Imageerstellung geändert.
Kleine Zusammenfassung:
Was ich bis hier geschrieben habe ist auf viele Arm Boards anwendbar. Unterschiedlich ist oft nur der Weg wie u-boot gestartet wird.
Raspberry Pi4
Option 1: Das kennen alle Raspberry Pi User
Das steht ja ausführlich beschrieben unter
https://www.raspberrypi.com/documentati ... g_txt.html
Das kenne ich so nur von der Raspberry Pi Reihe. Ein absoluter Sonderweg.
Option 2: u-boot
Der Boot über u-boot muss auch über die config.txt "umgebogen" werden da ja die Software in der CPU noch nichts von u-boot weis.
Meine config.txt sieht so aus:
Code: Alles auswählen
# Mein Monitor ist ziemlich alt und kann nur 1680x1050 und muss "gezwungen" werden
hdmi_force_hotplug=1
hdmi_group=2
hdmi_mode=58
hdmi_force_mode=1
hdmi_drive=1
# WICHTIG: Sonst funktioniert tty1 nicht um per Serialline u-boot zu konfigurieren
dtoverlay=disable-bt
enable_uart=1
# Ja, 64 Bit bitte
armstub=armstub8-gic.bin
enable_gic=1
arm_64bit=1
dtparam=i2c_arm=on
# Bitte starte u-boot
kernel u-boot.bin
Option 3: UEFI
https://github.com/pftf/RPi4
Ja. Ihr lest richtig! UEFI und arm64. Das soll der neue Standardweg für die Distributionen werden wie sie Booten wollen. Das hat einige Vorteile. Einheitliche API: arm64/amd64 spricht dann dieselbe Sprache (was die API angeht wie mit dem BIOS/UEFI/Systemfirmware gesprochen werden muss).
Hier hab ich ein paar Screenshots wie mein Boot damit aussieht.
Es wird damit möglich diese Firmware auf die Bootpartition zu packen und dann den Pi4 per CDRom/USB Stick wie einen PC zu installieren!
Es gibt momentan noch einen Nachteil: Die GPIOs sind für mich momentan nicht ansprechbar. Auch mit der Konfiguration "APCI + DeviceTree" oder "DeviceTree Only".
DeviceTree
Ursprünglich kommt der DeviceTree aus dem PPC Umfeld und wurde dort benutzt um die Hardware zu beschreiben. Das war so universell nutzbar das es sich auch auf andere Prozessorarchituren ausgebreitet hat. Vor einigen Jahren war der Plan das der DeviceTree Betriebsystem unabhängig ist und bleibt. Frommer Vorsatz der so nicht wahr wurde. Leider ist der Devicetree mittlerweile so im Wandel das er fast als eine eigene Firmware betrachtet werden muss. Als Beispiel: Raspberry Pi4: Man nehme eine alte Installation oder ein altes Image welches immer noch bootet und versuche einen neuen Kernel zu booten. Der Kernel startet zwar aber der Devicetree welcher in der Firmware Partition enthalten ist unterscheidet sich so stark von der neuen Kernel Version bzw. dessen Device Tree das Geräte nicht mehr funktionieren. Auch FreeBSD hat seinen eigenen Device Tree für die Raspis und auch u-boot.
Hier was die Raspis anbelangt .... Von fester Beschreibung der Hardware kann keine Rede sein
Code: Alles auswählen
git hist arch/arm/boot/dts/*rpi*
* 3476ccbd0ae63 2022-07-14 | Merge tag 'arm-soc/for-5.20/devicetree' of https://github.com/Broadcom/stblinux into arm/dt [Arnd Bergmann]
|\
| * 26f2a78b4a60a 2022-06-03 | ARM: dts: bcm2711: Enable V3D [Peter Robinson]
* | b9b6d4c925604 2022-06-15 | ARM: dts: bcm2711-rpi-400: Fix GPIO line names [Stefan Wahren]
|/
* 604319e94fc2a 2022-04-11 | ARM: dts: bcm283x: Align ETH_CLK GPIO line name [Phil Elwell]
* 0b8c9a837cc35 2022-04-11 | ARM: dts: bcm283x: Remove gpio line name NC [Stefan Wahren]
* 97bd8659c1c46 2022-04-11 | ARM: dts: bcm2835-rpi-b: Fix GPIO line names [Stefan Wahren]
* 57f718aa4b933 2022-04-11 | ARM: dts: bcm2837-rpi-3-b-plus: Fix GPIO line name of power LED [Phil Elwell]
* 9fd26fd02749e 2022-04-11 | ARM: dts: bcm2837-rpi-cm3-io3: Fix GPIO line names for SMPS I2C [Phil Elwell]
* 2c663e5e5bbf2 2022-04-11 | ARM: dts: bcm2835-rpi-zero-w: Fix GPIO line name for Wifi/BT [Phil Elwell]
* aa8ea8cc95dec 2022-02-16 | ARM: dts: bcm283x: fix ethernet node name [Oleksij Rempel]
* 21f9efbc5e981 2022-02-01 | ARM: dts: Add Raspberry Pi Zero 2 W [Stefan Wahren]
* 5e8c1bf1a0a5c 2021-11-30 | ARM: dts: bcm2711-rpi-4-b: Add gpio offsets to line name array [Uwe Kleine-König]
* 6375b90837858 2021-10-20 | Merge tag 'arm-soc/for-5.15/devicetree' of https://github.com/Broadcom/stblinux into arm/dt [Arnd Bergmann]
|\
| * 3f32472854614 2021-08-31 | ARM: dts: bcm2711-rpi-4-b: Fix usb's unit address [Nicolas Saenz Julienne]
| * 13dbc954b3c9a 2021-08-31 | ARM: dts: bcm2711-rpi-4-b: Fix pcie0's unit address formatting [Nicolas Saenz Julienne]
| * b55ec7528879a 2021-08-07 | ARM: dts: bcm2711-rpi-4-b: fix sd_io_1v8_reg regulator states [Stefan Wahren]
* | ea93ada05c9e3 2021-08-07 | ARM: dts: Add Raspberry Pi Compute Module 4 IO Board [Stefan Wahren]
* | d1b2237b2871b 2021-08-07 | ARM: dts: Add Raspberry Pi Compute Module 4 [Stefan Wahren]
* | ec8524968d163 2021-08-07 | ARM: dts: bcm283x-rpi: Move Wifi/BT into separate dtsi [Stefan Wahren]
|/
* 1c701accecf21 2021-06-06 | ARM: dts: Add Raspberry Pi 400 support [Stefan Wahren]
* 5f30dacf37bc9 2021-06-06 | ARM: dts: bcm283x: Fix up GPIO LED node names [Stefan Wahren]
* 9dda8d9aa86ab 2021-06-06 | ARM: dts: Move BCM2711 RPi specific into separate dtsi [Stefan Wahren]
* 77daceabedb42 2021-05-29 | Revert "ARM: dts: bcm283x: increase dwc2's RX FIFO size" [Stefan Wahren]
* 6b4233f70a914 2021-01-12 | ARM: dts: bcm2711: Add reserved memory template to hold firmware configuration [Nicolas Saenz Julienne]
* 278407a53c3b3 2020-11-20 | ARM: dts: bcm283x: increase dwc2's RX FIFO size [Pavel Hofman]
* 358afb8b746d4 2020-10-29 | ARM: dts: rpi-4: disable wifi frequencies [Maxime Ripard]
* e533cda12d8f0 2020-10-24 | Merge tag 'armsoc-dt' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc [Linus Torvalds]
|\
| * 4564363351e26 2020-09-03 | ARM: dts: bcm2711: Enable the display pipeline [Maxime Ripard]
* | 168ae5a74b4a9 2020-10-05 | Merge 5.9-rc8 into usb-next [Greg Kroah-Hartman]
|\ \
| * | 6a7548305a04a 2020-09-24 | ARM: dts: bcm2835: Change firmware compatible from simple-bus to simple-mfd [Maxime Ripard]
| |/
* | 258f92d2f840b 2020-06-29 | ARM: dts: bcm2711: Add reset controller to xHCI node [Nicolas Saenz Julienne]
* | b03300db06bed 2020-06-29 | ARM: dts: bcm2711: Add firmware usb reset node [Nicolas Saenz Julienne]
|/
* 63e58f2bb9d8e 2020-06-15 | ARM: dts: bcm2711: Add firmware clocks node [Maxime Ripard]
* 9d71d3cd9ef04 2020-06-04 | Merge tag 'arm-dt-5.8' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc [Linus Torvalds]
|\
| * c380981efbcdb 2020-05-21 | Merge tag 'arm-soc/for-5.8/devicetree' of https://github.com/Broadcom/stblinux into arm/dt [Arnd Bergmann]
| |\
| | * 460227c329e5b 2020-04-13 | Merge tag 'tags/bcm2835-dt-next-2020-03-27' into devicetree/next [Florian Fainelli]
| | |\
| | | * 3ac395a5b3f3b 2020-03-03 | ARM: dts: bcm283x: Use firmware PM driver for V3D [Nicolas Saenz Julienne]
| | | * 8f7a54a74d72c 2020-03-06 | ARM: dts: bcm2711: Add vmmc regulator in emmc2 [Nicolas Saenz Julienne]
Da in meinem Setup u-boot als "echte Firmware" behandelt wird ändere ich auch nicht die dtb auf der Firmware Partition. Auch ändere ich u-boot nicht, nur die Symlinks zur aktiven Kernel Version.
Code: Alles auswählen
georg@rpi4-ws:~/Dokumente/Entwicklung/buildroot/kernel/linux-2.6$ ls -la /boot/
insgesamt 78564
drwxr-xr-x 9 root root 4096 17. Dez 09:17 .
drwxr-xr-x 1 root root 394 8. Dez 18:32 ..
-rw-r--r-- 1 root root 283231 1. Dez 07:42 config-6.0.0-5-arm64
drwxr-xr-x 2 root root 4096 24. Nov 18:00 EFI
drwxr-xr-x 2 root root 4096 8. Dez 15:58 extlinux
lrwxrwxrwx 1 root root 30 8. Dez 18:08 fdt -> fdts/linux-image-6.0.0-5-arm64
drwxr-xr-x 3 root root 4096 8. Dez 18:32 fdts
drwxr-xr-x 4 root root 16384 1. Jan 1970 firmware
drwxr-xr-x 5 root root 4096 24. Nov 20:16 grub
-rw-r--r-- 1 root root 15241 24. Nov 18:56 grub-4x3.png
lrwxrwxrwx 1 root root 24 8. Dez 18:08 initrd.img -> initrd.img-6.0.0-5-arm64
-rw-r--r-- 1 root root 48947055 17. Dez 08:30 initrd.img-6.0.0-5-arm64
drwx------ 2 root root 16384 19. Okt 15:18 lost+found
drwxr-xr-x 2 root root 4096 15. Aug 17:39 overlays
-rw-r--r-- 1 root root 83 1. Dez 07:42 System.map-6.0.0-5-arm64
lrwxrwxrwx 1 root root 21 8. Dez 18:08 vmlinuz -> vmlinuz-6.0.0-5-arm64
-rw-r--r-- 1 root root 31135680 1. Dez 07:42 vmlinuz-6.0.0-5-arm64
/etc/kernel/postinst.d/fdt-boot
Code: Alles auswählen
#!/bin/sh -e
version="$1"
bootopt=""
# passing the kernel version is required
if [ -z "${version}" ]; then
echo >&2 "W: fdt-boot: ${DPKG_MAINTSCRIPT_PACKAGE:-kernel package} did not pass a version number"
exit 2
fi
# avoid running multiple times
if [ -n "$DEB_MAINT_PARAMS" ]; then
eval set -- "$DEB_MAINT_PARAMS"
if [ -z "$1" ] || [ "$1" != "configure" ]; then
exit 0
fi
fi
# we're good - copy fdt directory
# shellcheck disable=SC2086
echo "fdt-boot (post-inst): Version=${version}"
cp -r "/usr/lib/linux-image-${version}" /boot/fdts/.
# update the vmlinuz,initrd.img and fdt link in the boot partition
latest_kernel=`ls /boot/vmlinuz-* | cut -d'-' -f 2- | sort -rV | head -n1`
if [ -z "${latest_kernel}" ]; then
echo "W: fdt-boot (post-inst): no kernel found"
exit 2
fi
rm -f /boot/vmlinuz
rm -f /boot/initrd.img
rm -f /boot/fdt
cd /boot
ln -s "vmlinuz-${latest_kernel}" vmlinuz
ln -s "initrd.img-${latest_kernel}" initrd.img
ln -s "fdts/linux-image-${latest_kernel}" fdt
Code: Alles auswählen
#!/bin/sh -e
version="$1"
bootopt=""
# passing the kernel version is required
if [ -z "${version}" ]; then
echo >&2 "W: fdt-boot: ${DPKG_MAINTSCRIPT_PACKAGE:-kernel package} did not pass a version number"
exit 2
fi
# we're good - copy fdt directory
# shellcheck disable=SC2086
echo "fdt-boot (postrm): Version=${version}"
rm -rf "/boot/fdts/linux-image-${version}"