\input{confighandout} \subsection{Der Linux-Boot-Prozess} \subsubsection{Aufgaben des Bootloaders} Hauptaufgabe des Bootloaders ist die rudiment"are Initialisierung der Hardware, so dass mindestens das RAM benutzt werden kann. Dazu ist auf den meisten Boards die Initialisierung eines (S)DRAM-Controllers erforderlich. Soll das Board aus einem NAND-Flash booten k"onnen, so muss auch dessen Controller initialisiert werden. Viele Prozessoren beinhalten PLLs, die aus dem Prozessortakt andere Clocks f"ur verschiedene Peripherie-Einheiten generieren. Auch diese m"ussen initialisiert werden. Anschlie\ss end m"ussen die Peripherie-Einheiten initialisiert werden, die der Bootloader ben"otigt, um den Kernel laden zu k"onnen. F"ur TFTP-Boot w"are dies beispielsweise der Netzwerk-Chip. Meist ist es auch erw"unscht, dass der Bootloader eine serielle Schnittstelle initialisiert. Dies erm"oglicht nicht nur hilfreiche Meldungen aus dem Bootloader, es erm"oglicht auch dem Kernel bereits im fr"uhen Stadium des Bootvorgangs die Ausgabe von Meldungen (und nicht erst nach dem Laden seines UART-Treibers und der Konsole). Viele Bootloader bieten ausserdem eine Art Monitorprogramm, mit dem man mit Hilfe eines Terminalprogramms interaktiv Einstellungen "andern oder Speicher lesen und schreiben kann. Nach erfolgreicher Initialisierung l"adt der Bootloader von der gew"ahlten Quelle das komprimierte Kernel-Image ins RAM. Am Anfang eines komprimierten zImage steht (nat"urlich unkomprimiert) der Dekompressor-Code. Der Bootloader springt diese Adresse an und hat damit seine Arbeit beendet. Alles weitere l"auft im Kernel ab. \subsubsection{G"angige Bootloader} Die Wahl des Bootloaders ist weitgehend eine Geschmacksfrage. Die verbreiteten Bootloader U-Boot und Redboot bieten im Wesentlichen die gleiche Funktionalit"at. Die Bedienung unterscheidet sich zwar deutlich, aber der ohnehin n"otige Einarbeitungsaufwand d"urfte bei beiden etwa gleich sein. Auch beim Kompilieren dieser Bootloader sind die Unterschiede nicht gross. Beide zeichnen sich durch schwer durchschaubaren Sourcecode und ein eigenwilliges Buildsystem aus. Es gibt aber auch die M"oglichkeit, ganz auf einen derartigen Bootloader zu verzichten. Statt dessen verwendet man einen minimalen \emph{Initial Program Loader (IPL)}, der lediglich die rudiment"aren Initialisierungsaufgaben erf"ullt und danach einen minimalen Bootkernel l"adt und ausf"uhrt. Dieser l"adt wiederum den eigentlichen Produktiv-Kernel nach. Vorteile der letztgenannten Vorgehensweise sind hohe Flexibilit"at und die Tatsache, dass man im Bootkernel schon nach wenigen hundert Millisekunden jeden gew"unschten Treiber zur Verf"ugung hat. Dadurch k"onnen in elegante Weise Anforderungen wie das Anzeigen eines Bildes auf einem TFT (500 Millisekunden nach dem Einschalten) gel"ost werden. Wollte man dies mit einem der oben erw"ahnten Bootloader erreichen, m"usste man zun"achst die f"ur das TFT ben"otigten Treiber vom Kernel in den Bootloader portieren und dort zum Laufen bringen. "Ahnliches gilt f"ur andere g"angige Forderungen, wie das Booten von einem USB-Stick. Es erscheint als "uberfl"ussige M"uhe, einen im Kernel bereits funktionierenden Treiber in den Bootloader portieren zu m"ussen. Mit IPL und Bootkernel sind ausserdem komplexe Aufgaben w"ahrend des Bootvorgangs, beispielsweise automatisierte und sichere Firmware-Updates leicht realisierbar. \subsubsection{Bootprobleme: Im Bootloader} W"ahrend der Entwicklungsphase sind Probleme im Bootloader besonders unangenehm. Falls dieser bereits abst"urzt, ehe er die serielle Schnittstelle initialisieren konnte, so sieht man schlichtweg gar nichts. Aber auch bei sp"ateren Fehlern ist der Entwicklungszyklus m"uhsam, da man den Bootloader meist erst mit einem JTAG-Adapter oder "ahnlichen Werkzeugen ins Flash des Boards bef"ordern muss, bevor man den n"achsten Versuch machen kann. Bei "Anderungen am Bootloader-Code ist daher gro\ss e Sorgfalt geboten. Wenn m"oglich, sollte man zu zweit an solchem Code arbeiten und sich st"andig gegenseitig kontrollieren. H"aufige Problemquellen im Bootloader sind beispielsweise: \begin{itemize} \item Der Bootloader wurde nicht korrekt ins Flash geschrieben. In einem Fall passierte dies beispielsweise, wenn der Compiler ein Binary mit ungerader L"ange erzeugte. Aber auch falsche Konfiguration des JTAGer kann zu solchen Problemen f"uhren. \item Im Bootloader wurden die Timings f"ur Bus-Schnittstellen wie RAM oder Flash nicht korrekt eingestellt. Gerade wenn die Timings nicht ganz falsch, sondern nur grenzwertig sind, kann es zu schwer reproduzierbaren Bootproblemen kommen. \item Die Ladeadresse f"ur den Kernel ist nicht korrekt. Bei manchen Bootloadern kann es leicht zu Verwechslungen zwischen physikalischen und virtuellen Adressen kommen. Weder U-Boot noch Redboot melden einen Fehler, wenn man den Kernel an eine Adresse l"adt, an der sich "uberhaupt kein RAM befindet... \item Beim Laden des Kernels per TFTP kann es zus"atzlich weitere Probleme geben, die mit dem Netzwerk zusammenh"angen. Diese reichen von falsch aufgesetzten TFTP-Servern "uber falsch konfigurierte DHCP-Server oder falschen IP-Adressen bis hin zu Treiber- oder Hardware-Problemen. \end{itemize} \subsubsection{Bootprobleme: Im Kernel} Bootprobleme im Kernel sind vergleichsweise einfach zu finden, sobald man eine Konsole auf der seriellen Schnittstelle hat. Der Kernel gibt meist recht aussagekr"aftige Fehlermeldungen und bietet viele zus"atzliche Debug-Funktionen, die man in der Kernel-Konfiguration aktivieren kann. Falls sich der Kernel bereits fr"uher aufh"angt, so dass man nach der Meldung \cmd{Uncompressing Linux.....} "uberhaupt nichts mehr sieht, dann wird es schwieriger. Man sollte zun"achst "uberpr"ufen, ob die im Bootloader vorgegebene Commandline f"ur den Kernel korrekt ist, insbesondere die Einstellung der f"ur die Konsole verwendeten seriellen Schnittstelle (\cmd{console=tty...}). Ein weiteres g"angiges Problem ist, dass der Kernel am Ende des Bootvorgangs kein Root-Filesystem mounten kann. Dies kann daran liegen, dass man bei der Kernelkonfiguration vergessen hat, dass \emph{alle} f"ur das Rootfs n"otigen Hardware- und Dateisystem-Treiber in den Kernel einkompiliert sein m"ussen und nicht etwa als Module gebaut wurden. Bei Medien, die erst detektiert werden m"ussen (z.B. SD-Karten) kann es passieren, dass das Medium noch nicht bereit ist, wenn der Kernel es mounten will. In diesem Fall hilft der Parameter \cmd{rootwait}. Falls der Kernel zwar das Rootfs mounten kann, aber danach mit einer Fehlermeldung h"angen bleibt, anstatt \cmd{/sbin/init} zu starten, dann liegt dies oft an fehlenden Device-Nodes im Verzeichnis \cmd{/dev}. "Uberpr"ufen Sie dies. \subsubsection{Bootprobleme: In den Startskripten} Wenn der Kernel erfolgreich das Rootfs mounten und \cmd{/sbin/init} starten konnte, wird letzteres versuchen, die in \cmd{/etc/inittab} angegebenen Anweisungen auszuf"uhren. Dies ist normalerweise zun"achst der Aufruf eines Startskripts, das in der Regel weitere Skripte und Programme aufruft. Je nach Art der aufgerufenen Programme kann es hier zu weiteren Problemen kommen. Dazu geh"oren etwa fehlerhafte Konfigurationsdateien, fehlende Device-Nodes oder "Ahnliches. Ausserdem kommt es bei Startskripten vor, dass diese nicht auf jede Situation sauber und fehlertolerant reagieren. Man sollte vermeiden, dass sich das Skript zur Konfiguration des Netzwerks aufh"angt, wenn kein DHCP-Server gefunden wurde oder kein Netzwerkkabel eingesteckt ist. Des weiteren sollte das Skript selber erkennen, wenn "uber die Netzwerkschnittstelle das Rootfs per NFS gemountet wurde, und dann eine Neukonfiguration tunlichst unterlassen. \input{tailhandout}