2 Punkte von GN⁺ 2025-10-26 | Noch keine Kommentare. | Auf WhatsApp teilen
  • Eine technische Erklärung, die den Ablauf vom Drücken des Einschaltknopfs bis zur Ausführung des Linux-Kernels Schritt für Schritt beschreibt
  • Behandelt konkret, wie die CPU im Real Mode startet und in den Protected Mode sowie den Long Mode wechselt
  • Beschreibt detailliert die Rolle und Funktionsweise der einzelnen Schritte, darunter BIOS/UEFI-Firmware, Bootloader (GRUB) sowie Kernel-Dekomprimierung und Adress-Relokation
  • Erläutert die zentralen Konzepte für die Kernel-Initialisierung wie Memory Mapping, Interrupts, Seitentabellen und kASLR anhand knapper Beispiele
  • Vermittelt durch das Verständnis der internen Mechanismen des Linux-Bootvorgangs Einblicke in Systemarchitektur, Sicherheit und Performance-Optimierung

Teil 1 — Vom Einschaltknopf bis zur ersten Ausführung des Kernels

  • Wenn der Einschaltknopf gedrückt wird, wird die CPU in den Real Mode zurückgesetzt und führt die ersten Instruktionen aus

    • Der Real Mode ist ein einfaches Adressschema aus der 8086-Ära, bei dem die physische Adresse aus Segment und Offset berechnet wird
    • Beispiel: physical_address = (segment << 4) + offset
    • Nach dem Reset springt die CPU zur Adresse 0xFFFFFFF0 (Reset-Vektor) und übergibt die Kontrolle an die Firmware
  • Register sind ultraschnelle Speicherplätze innerhalb der CPU, darunter CS (Code Segment), IP (Instruction Pointer) usw.

    • CS gibt die Position des aktuellen Codes an, IP zeigt auf die nächste auszuführende Instruktion

BIOS und UEFI

  • BIOS ist die ältere Firmware, die nach dem POST (Power-On Self Test) die Boot-Reihenfolge prüft und nach einem bootfähigen Datenträger sucht
    • Ein bootfähiger Datenträger ist dadurch markiert, dass die ersten 512 Byte des Sektors mit 0x55AA enden
    • Das BIOS kopiert diesen Sektor an die Adresse 0x7C00 und springt dorthin zur Ausführung
  • UEFI ist die moderne Alternative, die Dateisysteme direkt versteht und größere Boot-Programme laden kann
    • Anders als beim BIOS gibt es keine Beschränkung auf den „ersten Sektor“, und dem Betriebssystem werden umfangreichere Systeminformationen übergeben

Bootloader

  • Der Bootloader ist das Programm, das den Kernel in den Speicher lädt und für die Ausführung vorbereitet
    • Typischerweise wird GRUB verwendet, das Konfigurationsdateien liest und den Kernel sowie die initiale RAM-Disk (initrd) in den Speicher lädt
    • Die Kernel-Datei besteht aus einem kleinen Setup-Programm für den Real Mode und dem komprimierten Kernel-Hauptteil
    • GRUB schreibt Informationen wie Kernel-Position, Kommandozeile und initrd-Position in die Struktur setup header und springt dann in den Kernel-Setup-Code

Setup-Programm (Setup Code)

  • Es sorgt vor der Kernel-Ausführung für einen vorhersagbaren Arbeitsbereich
    • Segmentregister (CS, DS, SS) werden ausgerichtet und das Direction Flag wird gelöscht, damit Speicherkopien konsistent funktionieren
    • Es wird ein Stack angelegt, um temporäre Daten bei Funktionsaufrufen zu speichern
    • Der BSS-Bereich (der Bereich globaler Variablen, die mit dem Anfangswert 0 starten müssen) wird auf 0 initialisiert
  • Wenn die Option earlyprintk gesetzt ist, kann ein serieller Port konfiguriert werden, um frühe Debug-Meldungen auszugeben
  • Von der Firmware wird eine RAM-Map (e820) angefordert, um nutzbare und reservierte Speicherbereiche zu erfassen
  • Nach Abschluss aller Vorbereitungen wird die erste C-Funktion main aufgerufen, danach beginnt die Phase des Moduswechsels

Interrupts

  • Interrupts sind ein Mechanismus, bei dem die CPU ihre aktuelle Arbeit kurz unterbricht, um dringende Ereignisse zu verarbeiten
    • Typische Beispiele sind Hardware-Ereignisse wie Tastatureingaben oder Timer
    • Maskierbare Interrupts können vorübergehend blockiert werden, NMI (Non-Maskable Interrupt) wird immer verarbeitet
    • Während des Moduswechsels werden sie vorübergehend blockiert, um unerwartete Interrupts zu vermeiden

Teil 2 — Vom Real Mode zu 32 Bit und dann zu 64 Bit

  • Modernes Linux läuft im Long Mode der x86_64-Architektur
    • Dafür ist ein schrittweiser Übergang nötig: Real Mode → Protected Mode → Long Mode

Protected Mode

  • Dies ist ein 32-Bit-Modus, der eingeführt wurde, um die Grenzen der 1980er Jahre zu überwinden, und er besitzt zwei zentrale Strukturen
    • GDT (Global Descriptor Table): definiert Startadresse, Größe und Rechte von Segmenten
      • Linux verwendet das Flat Model, das den gesamten 32-Bit-Adressraum zu einem zusammenhängenden Bereich vereinfacht
    • IDT (Interrupt Descriptor Table): speichert die Adressen der Handler, die bei Interrupts aufgerufen werden
      • Während des Bootvorgangs wird nur eine minimale IDT geladen, die vollständige IDT wird nach der Kernel-Initialisierung eingerichtet

Ablauf des Moduswechsels

  • Der Setup-Code führt zunächst das Deaktivieren von Interrupts, das Stoppen des PIC-Chips, das Aktivieren der A20-Leitung und die Initialisierung des mathematischen Koprozessors aus
    • Die A20-Leitung ist ein historischer Mechanismus zur Behebung des 1-MB-Adress-Wrapping-Problems
  • Danach werden eine minimale GDT und IDT geladen, anschließend wird das PE-Bit im Register CR0 gesetzt und ein Far Jump ausgeführt
    • Damit erfolgt der Eintritt in den Protected Mode, und Segment- sowie Stack-Pointer werden an das neue Adressschema angepasst

Kontrollregister

  • CR0: aktiviert den Protected Mode
  • CR3: speichert die oberste Adresse der Seitentabellen
  • CR4: aktiviert Erweiterungen wie PAE

Vorbereitung auf den Long Mode

  • Für den Wechsel in den 64-Bit-Modus sind zwei Bedingungen erforderlich
    • Paging muss aktiviert sein: Es übernimmt die Zuordnung zwischen virtuellen und physischen Adressen
    • Das LME-Bit (Long Mode Enable) im EFER-Register muss gesetzt werden
  • Seitentabellen mappen Seiten in 4-KB-Einheiten; während des frühen Bootvorgangs wird dies zunächst einfach über eine Identity Map in 2-MB-Einheiten aufgebaut

Aktivierung von Paging

  • Die Funktion PAE wird in CR4 aktiviert, und es wird eine minimale Seitentabelle erstellt, die den niedrigen Adressbereich in 2-MB-Einheiten abdeckt
  • Die Adresse der obersten Tabelle wird in CR3 geschrieben, danach wird Paging aktiviert
  • Anschließend wird das LME-Bit in EFER gesetzt und in 64-Bit-Code gesprungen, womit der Eintritt in den Long Mode erfolgt
  • Mit auf 64 Bit erweiterten Adressen und Registern ist die Ausführung des Kernels vorbereitet

Teil 3 — Kernel-Dekomprimierung, Adressanpassung und Selbstverschiebung

  • Die CPU befindet sich nun im 64-Bit-Modus, und im Speicher liegt ein komprimiertes Kernel-Image
    • Ein kleiner 64-Bit-Stub übernimmt das Entpacken des Kernels und die Adressanpassung

Frühes Aufräumen und Einrichten von Sicherheitsmechanismen

  • Der Stub berechnet seine tatsächliche Ausführungsposition und verschiebt sich bei Überlappungen per Self-Relocation an eine sichere Stelle
  • Er initialisiert seinen BSS-Bereich und lädt eine einfache IDT (einschließlich Handlern für Page Faults und NMI)
    • Tritt ein Page Fault auf, wird die fehlende Zuordnung sofort ergänzt, um die Ausführung wiederherzustellen
  • Für benötigte Bereiche wie Kernel, Boot-Parameter und Kommandozeilenpuffer wird ein Identity Mapping erzeugt

Kernel-Dekomprimierung

  • Die Funktion extract_kernel wird ausgeführt und entpackt den Kernel
    • Unterstützt werden verschiedene Kompressionsalgorithmen wie gzip, xz, zstd und lzo
    • Nach dem Entpacken wird der ELF-Header gelesen, um Code- und Datenabschnitte an die korrekten Adressen zu kopieren
  • Wenn sich die Build-Adresse des Kernels von der tatsächlich geladenen Adresse unterscheidet, wird eine Relokation durchgeführt
    • Dabei werden Instruktionen oder Pointer mit eingebetteten Adressen an die tatsächliche Speicherposition angepasst
  • Sind alle Vorbereitungen abgeschlossen, erfolgt der Sprung in die Funktion start_kernel, womit die eigentliche Kernel-Initialisierung beginnt

Selbstverschiebung des Kernels (kASLR)

  • kASLR (Kernel Address Space Layout Randomization) randomisiert die physischen und virtuellen Adressen des Kernels und erhöht damit die Schwierigkeit von Angriffen
    • Beim Booten werden zwei Basiswerte zufällig gewählt
      • Physische Basis: die RAM-Adresse, an der sich der Kernel tatsächlich befindet
      • Virtuelle Basis: die Startadresse des virtuellen Adressraums, den der Kernel verwendet
  • Ablauf der Auswahl
    • Es wird eine Liste der zu schützenden Bereiche erstellt, darunter Bootloader, initrd und Kommandozeilenpuffer
    • Die Speicherkarte der Firmware wird nach ausreichend großen freien Bereichen durchsucht
    • Mithilfe von Entropie, etwa aus Hardware-Zufallsinstruktionen, wird ein zufälliger Slot ausgewählt
  • Falls kein geeigneter Bereich gefunden wird, wird auf die Standardadresse zurückgefallen; mit der Option nokaslr wird die Randomisierung deaktiviert

Begriffe im Überblick

  • Hexadecimal (Hexadezimal): mit dem Präfix 0x gekennzeichnet; praktisch für Hardware-Bitstrukturen und Alignment
  • Register: temporärer Speicher innerhalb der CPU (CS, DS, SS, IP, SP usw.)
  • Segment/Offset: Adressberechnung im Real Mode (segment * 16 + offset)
  • BIOS/UEFI: Firmware für Systeminitialisierung und das Laden des Boot-Programms
  • Bootloader (GRUB): lädt den Kernel und übergibt Systeminformationen
  • Stack/BSS: temporärer Funktionsspeicher bzw. Bereich globaler Variablen, die mit 0 initialisiert sind
  • Interrupt/NMI: Mechanismus zur Verarbeitung von Hardware- und Software-Ereignissen
  • GDT/IDT: Tabellen zur Definition von Segmenten und Interrupts
  • A20-Leitung: Schalter zur Vermeidung des 1-MB-Adress-Wrappings
  • Protected Mode/Long Mode: 32-Bit- und 64-Bit-Ausführungsmodi
  • Paging/Seitentabellen: Zuordnung zwischen virtuellen und physischen Adressen

Noch keine Kommentare.

Noch keine Kommentare.