FlashOS

Setup

Host-Toolchain, SD-Karten-Layout, serielle Konsole, QEMU und der Test-Runner.

README · Dokumentation · Setup · Port · Versionierung · Changelog · Lizenz

English · Deutsch

--- Diese Seite behandelt die Host-Toolchain, das SD-Karten-Layout, das der Raspberry Pi 4 erwartet, die serielle Konsole, QEMU und den Test-Runner. Referenz: [BCM2711 ARM Peripherals (RPi 4)](https://pip-assets.raspberrypi.com/categories/545-raspberry-pi-4-model-b/documents/RP-008248-DS-1-bcm2711-peripherals.pdf?disposition=inline). ## Inhalt 1. [Host-Toolchain](#1-host-toolchain) 2. [Bauen](#2-bauen) 3. [Ausführen unter QEMU](#3-ausführen-unter-qemu) 4. [SD-Karten-Layout](#4-sd-karten-layout) 5. [Serielle Konsole](#5-serielle-konsole) 6. [Hilfs-Shell-Funktionen](#6-hilfs-shell-funktionen) 7. [Host-seitige Unit-Tests](#7-host-seitige-unit-tests) ## 1. Host-Toolchain | Tool | Mindestversion | Zweck | | :------------------------- | :-------------- | :---------------------------------------- | | Zig | 0.16.0 | Zig + Assembly kompilieren, `build.zig` ausführen | | `flashc` | pinned | Flash-Quellen (`.flash`) nach Zig transpilieren | | `aarch64-elf-objcopy` | 2.40+ | ELF → Roh-Binary | | `aarch64-elf-nm` | 2.40+ | Symbol-Extraktion für `populate-syms` | | `qemu-system-aarch64` | 11.0.0+ | Den kernel unter QEMU ausführen | | `screen` (oder Äquivalent) | – | Serielle Konsole für den Pi | Unter macOS: ```bash brew install zig aarch64-elf-binutils qemu ``` ### Flash-Compiler (`flashc`) Die Source-Module von FlashOS sind in [Flash](https://github.com/ajhahnde/Flash) geschrieben und werden zur Build-Zeit nach Zig transpiliert. `build.zig` löst das `flashc`-Binary standardmäßig unter `~/Flash/zig-out/bin/flashc-stage1` auf; überschreibe den Pfad mit `-Dflashc=`. Flash veröffentlicht keine vorgebauten Binaries, also baue den gepinnten, selbst-gehosteten Compiler aus dem Source — führe dies aus dem FlashOS-Checkout aus, damit der Pin aus `flash-toolchain.lock` gelesen wird: ```bash git clone https://github.com/ajhahnde/Flash.git ~/Flash git -C ~/Flash checkout "$(grep -oE '[0-9a-f]{40}' flash-toolchain.lock)" ( cd ~/Flash && zig build stage1 ) # → ~/Flash/zig-out/bin/flashc-stage1 ``` `zig build stage1` — nicht das bloße `zig build`, das nur den stage0-Bootstrap-Seed `flashc` ausgibt — erzeugt `flashc-stage1`, die in `flash-toolchain.lock` gepinnte Revision. Baue es nur dann neu, wenn sich dieser Pin verschiebt. ## 2. Bauen Jeder Build transpiliert die `.flash`-Source-Module mit `flashc`, also baue ihn zuerst (siehe §1). ```bash zig build # default: kernel8.img + armstub8.bin → zig-out/ ``` ```bash ./build.sh # full two-pass build with optional deploy ``` `build.sh` ruft `zig build`, `zig build populate-syms` und dann erneut `zig build` auf, prüft per Diff, dass das Symbol-Layout konvergiert ist, und führt optional `zig build deploy` aus. ## 3. Ausführen unter QEMU Zwei QEMU-Maschinen sind verdrahtet; Auswahl über `-Dboard=`: ```bash zig build -Dboard=rpi4b run # Pi 4 model (raspi4b) zig build -Dboard=virt run-virt # generic ARMv8 (virt) ``` Für einen selbstvalidierenden Lauf, der mit 0 endet, wenn der Boot den interaktiven `fsh`-Prompt erreicht (die dritte Homescreen-Markierung `type 'help' for commands` — siehe unten) ohne `[FAIL]` / `ERROR CAUGHT` und mit den erwarteten Free-Page-Checkpoints, und mit 1 bei einem Fehler oder einem watchdog-Timeout (keine manuelle QEMU-Überwachung): ```bash zig build -Dboard=virt test-virt zig build -Dboard=rpi4b test-rpi4b # (matches run) ``` Um die Byte-Identitäts-Baseline des Pi vor dem Flashen der SD-Karte zu verifizieren (legt `src/symbol_area.S` beiseite, säubert, baut neu, vergleicht per Diff gegen `scripts/pi_baseline.sha256`): ```bash scripts/verify_pi_baseline.sh ``` `run` ruft `qemu-system-aarch64 -M raspi4b -serial null -serial stdio -kernel zig-out/kernel8.img` auf — die Mini-UART (UART1) wird auf das Host-stdio geleitet, sodass die Ausgabe des kernel und die `[TEST]/[PASS]/[FAIL]`-Zeilen des Test-Harness direkt im steuernden Terminal erscheinen. `run-virt` verwendet `-M virt,gic-version=3 -cpu cortex-a72 -m 1G -nographic`, mit der auf das Host-stdio geleiteten PL011. Ein grüner Lauf auf beiden Boards landet bei `30/30 passed`, 34 Free-Page-Checkpoints pro Szenario (`0xbbff2` auf rpi4b, `0x3be46` auf virt) plus der passenden Boot-Baseline (`0xbc000` / `0x3be54`) und 0 `ERROR CAUGHT`. Der Boot übergibt dann an `/bin/login` → `/bin/fsh`; mit dem Login-Lifecycle erscheint die Homescreen-Markierung von fsh (`type 'help' for commands`) dreimal (zwei skriptgesteuerte `[TEST] login`-Sitzungen + der echte Boot-Login), und der CI-watchdog (`scripts/run_qemu_test.sh`) zählt genau das. Die Free-Page-Invarianten sind in [Dokumentation §8](DOCUMENTATION.md#free-page-invarianten) dokumentiert. QEMU ist das maßgebliche Signal der inneren Schleife. Der Boot-Pfad stimmt Byte für Byte mit echter Hardware überein, abgesehen vom Timing. ## 4. SD-Karten-Layout Der Raspberry Pi 4 bootet von einer FAT32-formatierten Karte, deren Root-Verzeichnis mindestens Folgendes enthalten muss: ```text config.txt # ships in this repo kernel8.img # built by `zig build` armstub8.bin # built by `zig build` bcm2711-rpi-4-b.dtb # bundled in this repo start4.elf # bundled in this repo fixup4.dat # bundled in this repo overlays/miniuart-bt.dtbo ``` Die firmware-Blobs sind in diesem Repo unter `firmware/` (`bcm2711-rpi-4-b.dtb`, `start4.elf`, `fixup4.dat`, `overlays/miniuart-bt.dtbo`) gebündelt. Sie stammen aus dem offiziellen [raspberrypi/firmware](https://github.com/raspberrypi/firmware/tree/master/boot)-Projekt und werden hier der Bequemlichkeit sowie der Lizenz-/Credit-Klarheit halber mitgeführt. Der Deploy-Schritt verweist standardmäßig auf dieses Verzeichnis: ```bash SD_BOOT=/Volumes/BOOT FIRMWARE=firmware zig build deploy ``` Der Deploy-Schritt liest zwei Umgebungsvariablen: | Variable | Default | Zweck | | :----------- | :---------------- | :------------------------------------------------ | | `SD_BOOT` | `/Volumes/BOOT` | SD-Karten-Mountpunkt unter macOS | | `FIRMWARE` | `firmware` | Verzeichnis mit den gebündelten RPi-firmware-Dateien | ## 5. Serielle Konsole Der kernel hat auf dem Pi drei Konsolen-/Debug-Kanäle: - **Mini-UART (UART1)** an GPIO 14 / 15 — Hauptkonsole (und Fallback, wenn USB nicht enumeriert wird). - **PL011 (UART4)** an GPIO 8 / 9 — dedizierter Trace-Kanal. - **USB-C-Gadget-Konsole** — die interaktive `fsh`-Konsole über den USB-C-Port des Pi; kein Adapter oder Jumper-Kabel (siehe unten). GPIO 14/15 wird absichtlich mit der firmware geteilt. `config.txt` aktiviert `uart_2ndstage=1` und `dtoverlay=miniuart-bt`, was das PL011_0 der firmware auf GPIO 14/15 leitet, sodass die `MESS:…`-Zeilen von `start4.elf` auf demselben Kabel sichtbar sind. Sobald der kernel läuft, konfiguriert `mini_uart_init` (`src/board/rpi4b/uart.flash`) die Pins auf alt5 (Mini-UART) um — der letzte Schreibzugriff auf den GPIO-Funktionsselektor gewinnt, sodass das firmware-seitige PL011_0-Routing stillschweigend ersetzt wird. Dies ist eine sequentielle Übergabe, kein Konflikt. ### UART1-Pinout (RPi 4 → USB-TTL-Adapter) | RPi-Pin | Funktion | USB-TTL-Pin | | :------ | :------------ | :---------- | | Pin 6 | GND | GND | | Pin 8 | TXD (GPIO 14) | RXD | | Pin 10 | RXD (GPIO 15) | TXD | Verbinde **nicht** VCC, wenn der Pi unabhängig mit Strom versorgt wird. ### Verbinden unter macOS Der PL2303G-Chip wird nativ unterstützt. Finde den Device-Node und öffne eine Sitzung mit 115200 Baud: ```bash ls /dev/cu.usbserial-* ``` ```bash screen /dev/cu.usbserial-XXXX 115200 ``` Beende `screen` mit `Ctrl-A`, dann `K`, bestätigt mit `y`. Um eine abgetrennte `picapture`-Sitzung von einem zweiten Terminal zu beenden, führe `piquit` aus (siehe §6). ### USB-C-Konsole (einzelnes C-zu-C-Kabel) Der eigene USB-C-Port des Pi dient zugleich als Konsole. Der kernel bringt den DWC2-OTG-Controller des BCM2711 als **CDC-ACM-USB-Gerät** (`src/board/rpi4b/usb.flash`) hoch, sodass ein USB-C-↔-USB-C-Kabel zum Mac sowohl **Strom als auch die interaktive `fsh`-Konsole** überträgt. macOS bindet seinen eingebauten `AppleUSBCDCACM`-Treiber — nichts zu installieren. ```bash ls /dev/cu.usbmodem* # node appears once the gadget enumerates ``` ```bash screen /dev/cu.usbmodem00011 115200 ``` Sobald enumeriert, wechselt die Ausgabe von user/`fsh` (der `# ` / `$ `-Prompt, Befehlsausgaben) automatisch von der Mini-UART zur USB-Konsole; die `[Debug]`-Ausgaben des kernel und der eigene Bring-up-Trace des USB-Treibers bleiben auf der Mini-UART. Wenn das Gadget nie enumeriert (kein Host angeschlossen, oder unter QEMU, das den DWC2-Gerätepfad nicht emuliert), fällt die Konsole auf die Mini-UART zurück, und der oben beschriebene GPIO-Ablauf funktioniert unverändert. Die Baudrate ist kosmetisch — hinter dem USB-Gerät steckt keine physische UART; jede Rate funktioniert. In `screen` getippte Tastenanschläge erreichen `fsh` über USB-Bulk-OUT; die Härtung von Replug / Re-Enumeration ist ein bekannter Arbeitsposten; wenn die Konsole nach dem erneuten Einstecken des Kabels also hängt, mache einen Power-Cycle des Pi. ## 6. Hilfs-Shell-Funktionen Das Repo liefert [`flashos.env.zsh`](../../flashos.env.zsh) mit einer Handvoll Helfern, bereitgestellt als zwei Verb-Dispatcher — `pi ` (serielle Konsole) und `run ` (bauen, emulieren oder verbinden) — plus `build` und `flashos`. Source es aus `~/.zshrc` (`source ~/FlashOS/flashos.env.zsh`), um sie in jeder Shell verfügbar zu machen. Die alten flachen Namen (`picapture`, `piconnect`, `piquit`, `pilist`) bleiben als dünne Aliase für die entsprechenden `pi`-Verben erhalten. - **`picapture [usb|mu]`** — führt den kanonischen Boot-Capture-Ablauf aus und protokolliert die Sitzung in `boot.log` im Root-Verzeichnis des Repos (unabhängig vom aktuellen Verzeichnis; abgedeckt durch die `.gitignore` des Repos). - `usb` (default): wartet, bis das CDC-Gadget auf `/dev/cu.usbmodem*` enumeriert (das Einstecken des C-zu-C-Kabels versorgt den Pi mit Strom, sodass das Erscheinen des Nodes selbst das erste Boot-Signal ist), und fragt dann die Konsole einmal pro Sekunde ab, bis die Boot-Markierung `type 'help' for commands` erscheint (fsh hat seine interaktive REPL erreicht). - `mu`: erfasst den Mini-UART-Trace-Adapter (`/dev/cu.usbserial-*`), bis `type 'help' for commands` (der Boot hat die Shell über den MU-Fallback erreicht — kein USB-Host angeschlossen) oder `ERROR CAUGHT` erscheint. Mache einen Power-Cycle des Pi, wenn dazu aufgefordert. - kernel-Faults werden ausschließlich auf dem MU-Adapter ausgegeben — verwende den `mu`-Modus (Trace-Adapter + externe Stromversorgung) zur Fault-Diagnose. - **`piconnect [usb|mu]`** — öffnet eine interaktive `screen`-Sitzung auf der Pi-Konsole mit 115200 Baud. Ohne Argument wählt es automatisch die USB-CDC-Konsole (`fsh`), wenn vorhanden, sonst den MU-Trace-Adapter; `usb` / `mu` erzwingen einen bestimmten Kanal. - **`piquit`** — beendet die abgetrennte `pi_capture`-screen-Sitzung, die von `picapture` gestartet wurde. Von einem zweiten Terminal verwenden. - **`pilist`** — listet die angeschlossenen Konsolengeräte auf: die USB-CDC-Konsole (`/dev/cu.usbmodem*`) und alle USB-Serial-Adapter (`/dev/cu.usbserial-*`, MU-Trace). - **`pi log`** — zeigt die letzte `boot.log`-Aufzeichnung im Pager an. - **`pi tail [N]`** — folgt `boot.log` live (letzte `N` Zeilen, default 40) und übersteht die Log-Rotation der nächsten Aufzeichnung. - **`build`** — führt `./build.sh` aus dem Root-Verzeichnis des Repos aus (funktioniert aus jedem Verzeichnis): clean, Link-Pass 1, `populate-syms`, Link-Pass 2, Diff-Prüfung des Symbol-Layouts, optional `deploy`. `BOARD=virt build` wählt das virt-Board (deploy wird übersprungen); `NM=llvm-nm build` überschreibt das Symbol-Dump-Binary. - **`run `** — baut und startet ein Board, fährt den Boot-Watchdog oder verbindet sich mit Hardware. `run qemu` (Alias `auto`) baut und startet das rpi4b-Modell in QEMU; `run virt` macht dasselbe für das virt-Board; `run test` führt die Host-Unit-Tests aus (`run test --NAME` filtert nach Name); `run hw` verbindet sich über die serielle Konsole mit dem Pi (`--trace` wählt den MU-Adapter). - **`run watchdog [virt|rpi4b]`** — fährt den unbeaufsichtigten Boot-Watchdog mit den erforderlichen Flags `-Dci-login-seed=true` und `-Dboot-selftest=true` automatisch gesetzt; default ist das virt-Board (`rpi4b` ist ein langsamerer TCG-Lauf). - **`flashos`** — listet die in [`flashos.env.zsh`](../../flashos.env.zsh) definierten Shell-Helfer und die verfügbaren `zig build`-Schritte auf — eine schnelle Inventur der Targets. Der MU-Trace-Adapter wird automatisch aus `/dev/cu.usbserial-*` erkannt und die USB-CDC-Konsole aus `/dev/cu.usbmodem*`; überschreibe mit `PI_SERIAL_DEVICE=/dev/cu.usbserial-XXXX` / `PI_USB_CONSOLE_DEVICE=/dev/cu.usbmodemXXXX`, wenn mehrere Geräte angeschlossen sind. Die `picapture`-Timeouts liegen bei 120 s (gesamt) und 30 s (Prompt-Probe); überschreibe mit `PI_CAPTURE_TIMEOUT` / `PI_PROBE_TIMEOUT`. ### Auto-Source bei `cd` (optional) Um `flashos.env.zsh` automatisch zu laden, sobald die Shell `~/FlashOS` betritt, hänge einen `chpwd`-Hook an `~/.zshrc` an. Der folgende Befehl ist idempotent: ```bash grep -q '_FLASHOS_LOADED' ~/.zshrc || cat >> ~/.zshrc <<'EOF' # --- FlashOS auto-source on cd --- autoload -Uz add-zsh-hook load_flashos_env() { if [[ "$PWD" == "$HOME/FlashOS"* && -z "$_FLASHOS_LOADED" ]]; then [[ -f "$HOME/FlashOS/flashos.env.zsh" ]] && source "$HOME/FlashOS/flashos.env.zsh" && typeset -g _FLASHOS_LOADED=1 fi } add-zsh-hook chpwd load_flashos_env load_flashos_env EOF ``` Öffne eine neue Shell oder führe `source ~/.zshrc` aus, um zu aktivieren. Setzt voraus, dass das Repo unter `~/FlashOS` liegt. ## 7. Host-seitige Unit-Tests ```bash zig build test ``` Führt die host-seitigen Unit-Tests gegen Pure-Logic-kernel-Module aus. Jedes Modul mit Tests bildet seinen eigenen Test-Root, gelinkt gegen `tests/host_stubs.zig` (Stubs für reine Assembly-Externs). Die aktuelle Suite deckt 41 Module ab (468 Host-Tests); sie ist weit unter einer Sekunde fertig und ist das schnellste Signal dafür, dass die Kernlogik des kernel weiterhin hält. --- [← Zurück: Dokumentation](DOCUMENTATION.md) · [Als Nächstes: Port →](../../PORT.md)