4 Punkte von GN⁺ 2025-10-27 | Noch keine Kommentare. | Auf WhatsApp teilen
  • Erklärt Schritt für Schritt, wie man durch direktes Bauen des Linux-Kernels und das Einrichten eines minimalen User Space eine „Mikro-Linux-Distribution“ erstellt
  • Behandelt von Grund auf die Rolle des Betriebssystem-Kernels, die Bestandteile einer Linux-Distribution und die Beziehung zwischen Kernel und User Space
  • Verwendet als Beispiel die RISC-V-Architektur (QEMUs Maschine riscv64 virt), aber dieselben Prinzipien lassen sich auch auf andere Architekturen wie x86 anwenden
  • Baut eine minimal lauffähige Linux-Umgebung auf, einschließlich des init-Prozesses, initramfs und einer einfachen in Go geschriebenen Shell
  • Stellt zum Schluss mithilfe des Projekts u-root vor, wie man eine tatsächlich nützliche Mikro-Distribution erstellt, und endet als Einführungshandbuch zum Verständnis des gesamten Aufbaus eines Linux-Systems

Was ist ein Betriebssystem-Kernel?

  • Der Kernel ist die Kernkomponente des Betriebssystems, die für die Verwaltung von Hardware-Ressourcen und die Steuerung der Programmausführung zuständig ist
    • Er bietet Multitasking-Verwaltung, sodass es auch in einer Single-Core-Umgebung so aussieht, als liefen mehrere Programme gleichzeitig
  • Der Kernel abstrahiert die Steuerung von Ein-/Ausgabegeräten, damit Anwendungen nicht direkt mit Hardware-Adressen oder Registerwerten arbeiten müssen
    • Ein Programm fordert zum Beispiel einfach an, „eine Nachricht auf die Standardausgabe zu schreiben“, und der Kernel übernimmt die tatsächliche Interaktion mit der Hardware
  • Über die Dateisystem-Schnittstelle stellt er eine höherwertige Form des Datenzugriffs bereit
    • Dateien sind nicht nur Daten auf einem Datenträger, sondern fungieren als logische Schnittstelle zur Kommunikation mit dem Kernel
  • Der Kernel stellt Modelle zur Isolation und Kommunikation zwischen Prozessen bereit, sodass Anwendungen unabhängig voneinander laufen oder zusammenarbeiten können
  • Der Linux-Kernel ist Open Source, läuft auf vielen verschiedenen Architekturen und ist weltweit einer der am weitesten verbreiteten Kernel

Was ist eine Linux-Distribution?

  • Mit dem Linux-Kernel allein können Benutzer weder einen Webbrowser noch GUI-Apps ausführen; es braucht mehrere Schichten von Software-Infrastruktur über dem Kernel
  • Dinge wie Netzwerkkonfiguration, IP-Zuweisung und VPN-Verwaltung werden nicht vom Kernel, sondern von übergeordneten Programmen im User Space übernommen
  • Daher wird eine Linux-Distribution als Kombination aus Kernel + User-Space-Infrastruktur definiert
  • Eine Distribution umfasst zusätzlich zu den Grundfunktionen des Kernels Pakete, Werkzeuge, Konfigurationen und den Initialisierungsprozess (init)
  • Die Komplexität von Distributionen ist sehr unterschiedlich: von minimalistischen Setups wie Arch Linux bis zu benutzerfreundlichen Varianten wie Ubuntu

Infrastruktur außerhalb des Kernels: User Space und der init-Prozess

  • Sobald der Kernel den Bootvorgang abgeschlossen hat, startet er zuerst den init-Prozess mit PID 1
    • init ist der Vorfahr aller späteren User-Space-Prozesse und startet der Reihe nach die Dienste und Werkzeuge des Systems
  • Die Gesamtheit der Prozesse und Werkzeuge, die von init gestartet werden, bildet den eigentlichen inhaltlichen Kern einer Linux-Distribution
  • Je komplexer eine Distribution wird, desto eher sammelt sie unnötige Funktionen an und wird deshalb manchmal als „bloated“ kritisiert
  • Umgekehrt lässt sich mit einer angepassten Mikro-Distribution ein schlankes System aufbauen, das nur die nötigsten Funktionen enthält

Einen Linux-Kernel für RISC-V bauen

  • In einer x86-Umgebung wird mithilfe einer Cross-Compile-Toolchain ein Kernel für RISC-V gebaut
    • Nach dem Herunterladen des Quellcodes linux-6.5.2.tar.xz von kernel.org wird make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- defconfig ausgeführt
  • Mit menuconfig lassen sich die Kernel-Einstellungen visuell bearbeiten
  • Nach einem parallelen Build mit make -j16 wird arch/riscv/boot/Image erzeugt
  • In QEMU wird mit qemu-system-riscv64 -machine virt -kernel arch/riscv/boot/Image gebootet
    • Im Boot-Log lassen sich Meldungen wie Erkennung der SBI-Schicht, UART-Initialisierung und Aktivierung von printk prüfen

Das erste Hindernis: kein Root-Dateisystem

  • Während des Kernel-Boots tritt durch den Fehler VFS: Unable to mount root fs eine Kernel Panic auf
    • Ursache: Es wurde kein Root-Dateisystem (initramfs) bereitgestellt
  • Ein Dateisystem kann nicht nur auf einem Datenträger, sondern auch RAM-basiert (initramfs) aufgebaut sein
  • initramfs wird im cpio-Format paketiert und kann in QEMU mit der Option -initrd geladen werden

initramfs aufbauen und „Hello world“ ausführen

  • Die minimale Voraussetzung ist das Vorhandensein eines /init-Binärprogramms
    • Nach dem Schreiben von init.c wird es statisch gelinkt (-static) gebaut
    • Mit cpio -o -H newc < file_list.txt > initramfs.cpio wird es paketiert
  • Beim Start in QEMU wird „Hello world“ ausgegeben, danach führt das Beenden von init erneut zu einer Kernel Panic
    • Lösung: Eine Endlosschleife hinzufügen, damit init nicht beendet wird

Eine einfache in Go geschriebene Shell hinzufügen

  • init startet mit fork und execl die /little_shell
  • little_shell.go ist eine einfache Shell, die Benutzereingaben annimmt und die Befehle per Echo ausgibt
    • Mit GOOS=linux GOARCH=riscv64 go build little_shell.go wird sie für RISC-V gebaut
  • Sowohl init als auch little_shell teilen sich die Ausgabe über UART
    • Standard-Ein- und -Ausgabe werden über File-Handles verwaltet und bei fork vererbt
  • Das Ergebnis ist eine grundlegende Linux-Umgebung, in der „Hello from init“ und die Shell-Eingaben abwechselnd ausgegeben werden

Zusammenfassung der Rolle des Kernels

  • Hardware-Abstraktion: User-Programme können Ausgaben erzeugen, ohne Details zu UART oder Geräten zu kennen
  • Bereitstellung höherwertiger Schnittstellen: Zugriff auf andere Binärdateien (little_shell) über das Dateisystem
  • Prozess-Isolation: init und die Shell laufen in getrennten Speicherbereichen
  • Der Kernel bietet auf komplexer Hardware eine stabile und hoch portable Ausführungsgrundlage

Definition eines Betriebssystems

  • Man kann entweder nur den Kernel als Betriebssystem betrachten oder die gesamte Distribution als Betriebssystem
  • Wichtig ist, die Grenzen der Rollen und die Interaktionsstruktur von Kernel und User Space zu verstehen

Mit u-root eine tatsächlich nützliche Mikro-Distribution bauen

  • Das u-root-Projekt stellt ein Go-basiertes Set von User-Space-Werkzeugen bereit
    • u-root umfasst einen im User Space laufenden Bootloader und eine Shell-Umgebung auf dem Linux-Kernel
  • Nach der Installation erstellt der Befehl GOOS=linux GOARCH=riscv64 u-root automatisch ein initramfs
    • Die Datei /tmp/initramfs.linux_riscv64.cpio kann in QEMU ausgeführt werden
  • Beim Booten erscheint zusammen mit dem Banner „Welcome to u-root!“ eine Standard-Shell-Eingabeaufforderung
    • Unterstützt grundlegende Befehle wie ls, pwd, echo sowie Tab-Vervollständigung

Netzwerkanbindung praktisch ausprobieren

  • Zu QEMU werden die Geräte virtio-net-device und virtio-rng-pci hinzugefügt
    • Verwendet werden die Optionen -device virtio-net-device,netdev=usernet -netdev user,id=usernet
  • Mit dhclient aus u-root wird per DHCP automatisch eine IP-Adresse zugewiesen
    • Beispiel: eth0 erhält 10.0.2.15/24
  • Mit wget http://google.com gelingt der Zugriff auf das externe Netzwerk, und der Download von index.html lässt sich bestätigen

Die Bedeutung von Paketmanager und init

  • Allgemeine Distributionen installieren und aktualisieren Software dynamisch über einen Paketmanager
    • Diese praktische Übung folgt dagegen einem Embedded-Ansatz, bei dem das gesamte Image neu gebaut werden muss
  • init ist nicht bloß ein einfacher Prozessstarter, sondern eine Kernkomponente für Geräteinitialisierung, Dienstverwaltung und Steuerung des Systemstarts
    • Im init-Quellcode von u-root lassen sich verschiedene Schritte zur Einrichtung von Geräten (/dev) nachvollziehen

GitHub-Repository

  • Der vollständige Code und die Beispiele aus diesem Leitfaden sind unter popovicu/linux-micro-distro verfügbar
    • Dort lassen sich initramfs-Images bauen und die Übungen nachvollziehen

Noch keine Kommentare.

Noch keine Kommentare.