---
> Der Boot oben ist eine echte Serial-Console-Aufnahme von FlashOS
> beim Booten auf echter Raspberry-Pi-4B-Hardware bis zum
> `login:`-Prompt; die anschließende `fsh`-Session — `help`, `ls` und
> `sysinfo` — spielt die echte Ausgabe der Shell in einer lesbaren Kadenz ab,
> bevor ein abschließendes `reboot` die Demo zurück zum Boot schleift.
## About
FlashOS ist ein Bare-Metal-AArch64-Kernel, der auf Raspberry-Pi-4B-
Hardware und unter QEMU bootet. Der Kernel-Core ist in
[Flash](https://github.com/ajhahnde/Flash) geschrieben — einer
Systemsprache, die zu Zig transpiliert — mit dem Boot-Pfad, den
Exception-Vektoren und dem Context Switch in AArch64-Assembly. Der
Build wird vollständig von `build.zig` gesteuert, das die
`.flash`-Module durch einen gepinnten `flashc` transpiliert.
Der aktuelle Release liefert einen vollständigen Uniprozessor-
Lebenszyklus (`fork`, `exec`, `exit`, `wait`, `kill`), leckfrei über
Stress-Zyklen hinweg, geprüft durch ein kernelinternes
`[TEST]/[PASS]/[FAIL]`-Harness und eine host-seitige Unit-Test-Suite.
## Spezifikationen
| | |
| :-------------- | :------------------------------------------------------------------------------------ |
| **Hardware** | Raspberry Pi 4 Model B (BCM2711) |
| **Architektur** | AArch64 (ARMv8-A) |
| **Sprachen** | Flash (zu Zig transpiliert) + AArch64-Assembly |
| **Toolchain** | `flashc` (gepinnt) + Zig 0.16.0 +`aarch64-elf`-binutils |
| **Targets** | RPi 4B-Hardware,`qemu-system-aarch64 -M raspi4b`, _und_ `qemu-system-aarch64 -M virt` |
## Features
- **Zweistufiger Boot.** Der EL3-armstub konfiguriert die GIC und
`eret` in den Kernel auf EL1 (Pi). Auf QEMU `-M virt` führt `boot.S`
den EL3→EL1-Drop selbst aus.
- **Dual-Target-Build.** `-Dboard=rpi4b` oder `-Dboard=virt` schaltet
zur Compile-Zeit das pro-Board-Treiberbündel (`uart`, `gpio`,
`timer`, `irq`), das Linker-Skript und die Boot-Eigenheiten um.
- **Vierstufige MMU.** Identity Map für das frühe Bring-up, lineare
High Map für den Kernel, bedarfsweise allozierte User-Pages mit
pro-Region-Flags (text RX, data/heap/stack RW+UXN).
- **Priority-Round-Robin-Scheduler** mit timergesteuerter Preemption.
- **Prozess-Lebenszyklus.** `fork` / `exec` / `exit` / `wait` / `kill`,
Zombie-Reap-Pfad, leckfrei über Stress-Zyklen hinweg.
- **ELF64-Loader.** `sys_execve` löst einen Pfad über das VFS auf,
streamt jedes PT_LOAD-Segment mit den richtigen Berechtigungen in
einen frisch gebauten Adressraum und mappt eifrig die oberste
Stack-Page, bevor der argv-Block auf den neuen User-Stack kopiert
wird.
- **Userland-Mini-libc (`flibc`).** SVC-Wrapper, `printf` über
`sys_writeConsole`, Bump-Allocator über `brk` / `sbrk`,
`fork` / `wait` / `exit` / `execve`. Vom Build in die ELF-Demos
gelinkt, abgelegt unter `user_space/lib/flibc/`.
- **Heap über `sys_brk` / `sys_sbrk`.** Pages werden vom
Page-Fault-Pfad innerhalb von `[HEAP_BASE, brk)` bedarfsweise
alloziert; ein Schrumpfen unmappt und gibt frei.
- **Regionsbewusstes Page-Fault-Dispatch.** `do_data_abort`
klassifiziert nach User-VA-Region (heap / stack / stack-guard / text
/ wild) und panict-und-zombiet bei Zugriff außerhalb der Region; das
`sys_wait` des Elternteils reapt den Übeltäter, sodass das Harness
weiterläuft.
- **Stack Guard.** Eine 1-Page große ungemappte Region unterhalb des
legalen Stack-Bereichs verwandelt eine außer Kontrolle geratene
Rekursion in eine `[KERN] stack overflow`-Diagnose statt in
Speicherkorruption.
- **Vereinheitlichte File Descriptors.** Eine einzige getaggte
`fds`-Tabelle pro Task (`console` / `pipe` / `file`) hinter einer
einzigen `read` / `write` / `close` / `dup2`-ABI; fd 0/1/2 sind
vorinstallierte Console-Slots, `fork` erbt die Tabelle und `execve`
bewahrt sie, sodass eine Shell einem Kind umgeleitetes stdio
übergeben kann. Anonyme Pipes (`sys_pipe`) nutzen dieselbe Tabelle.
- **Interaktive Shell (`fsh`).** Eine Userland-REPL unter `/bin/fsh`
über einer Mini-libc (`flibc`): ein `readline`-Zeileneditor mit
TAB-Vervollständigung (Doppel-TAB listet die Kandidaten auf), ein
Tokenizer mit einer einzelnen `|`-Pipe-Stufe, In-Process-Built-ins
(`cd` / `pwd` / `exit` / `logout` / `help` / `free` / `whoami` /
`reboot`), ein Unix-artiger `#`/`$`-Privileg-Prompt und `fork` +
`execvp` (`/bin/`-Auflösung) für externe Programme — dazu
`/bin/echo`, `/bin/cat`, `/bin/ls` (der zustandslose
`sys_readdir`-Konsument), `/bin/grep` (literale Zeilensuche),
`/bin/cp` / `/bin/mv` / `/bin/rm` (FAT32-Dateiverwaltung über die
create/unlink/rename-Syscalls), `/bin/meminfo`, `/bin/forkbomb` (eine
gedeckelte Leak-Probe), `/bin/sysinfo` (eine Key/Value-System-
Zusammenfassung), `/bin/cpuinfo` (CPU-Temperatur + Takt),
`/bin/uptime` (Zeit seit Boot), `/bin/less` (ein Full-Screen-Pager),
`/bin/edit` (ein Full-Screen-Texteditor), `/bin/clear` (eine
Bildschirmlöschung) und `/bin/passwd`. Liest beim Start
`/etc/fshrc`; `sys_chdir` gibt jedem Task ein Arbeitsverzeichnis. Die
coreutils nutzen fest dimensionierte stack/static-Puffer; der
Userland-Heap (`brk`/`sbrk` hinter flibcs Bump-`malloc`) hat seinen
ersten Konsumenten im wachsbaren Puffer von `/bin/edit`.
- **Prozess-Identität, Login & Berechtigungen.** Jeder Task
trägt reale + effektive uid/gid (über `fork` vererbt, über `execve`
bewahrt) hinter einer ABI der `getuid`/`setuid`-Familie, und jede
Datei trägt mode/uid/gid-Metadaten, die an der open/write/exec-
Syscall-Grenze durchgesetzt werden (`-EACCES`, root umgeht sie). Der
Boot führt `/bin/login` als Session-Supervisor aus: der Kernel
verifiziert das Passwort mit PBKDF2-HMAC-SHA256 + einem
konstant-zeitigen Vergleich (`sys_authenticate` — die KDF verlässt
nie den Kernel), dann forkt login ein Kind, das Privilegien ablegt und
die Shell des Users per exec startet; `exit` kehrt zum `login:`-Prompt zurück.
Passwörter liegen in einem beschreibbaren `/mnt/shadow` auf der
SD-Karte (durch ein FAT32-Permission-Overlay auf `0600 root:root`
geschützt, mit dem read-only-initramfs-Seed als stets bootfähigem
Fallback) und werden mit `passwd` / `sys_passwd` geändert — frisch
kernel-generiertes Salt, splice-sicheres In-Place-Rewrite. Der
Passwort-Echo wird über `SYS_SET_CONSOLE_MODE` unterdrückt. Die
Seed-Accounts nutzen feste öffentliche Salts (Build-
Reproduzierbarkeit); rotierte Records bekommen zufällige Salts.
- **Syscalls** werden über `svc` und eine indizierte Tabelle dispatcht
— siehe
[Dokumentation §5](DOCUMENTATION.md#5-syscalls--ausnahmen).
- **USB-C-Gadget-Konsole.** Der USB-C-Port des Pi enumeriert als
CDC-ACM-Serial-Gerät (BCM2711 DWC2 OTG — Full-Speed, polled,
Slave/PIO): ein einzelnes C-zu-C-Kabel zu einem Mac überträgt sowohl
Strom als auch die interaktive `fsh`-Konsole
(`/dev/tty.usbmodem…`, keine Treiberinstallation). Die User-/Shell-
Ausgabe wechselt zu USB, sobald enumeriert, und fällt andernfalls
auf die Mini-UART zurück.
- **Zwei UARTs.** Mini-UART (UART1) für den Console-Fallback +
Kernel-Diagnose, dedizierte PL011 für einen Out-of-Band-Trace-Kanal.
- **Kernel-Symboltabelle**, generiert durch einen zweiphasigen
`populate-syms`-Schritt und konsumiert vom Function-Entry-Tracer
(Laufzeit intakt, aber derzeit inert — Zig hat noch kein Äquivalent
zu `-fpatchable-function-entry=2`).
- **Kernelinternes Test-Harness** (`[TEST]/[PASS]/[FAIL]` + Bilanz, 30
Szenarien) plus eine host-seitige `zig build test`-Suite (468
Host-Tests über 41 Module).
## Schnellstart
Die Toolchain installieren:
```bash
brew install zig aarch64-elf-binutils qemu
```
Die Source-Module von FlashOS sind in
[Flash](https://github.com/ajhahnde/Flash) geschrieben und werden zur
Build-Zeit von `flashc` zu Zig transpiliert. Den gepinnten Compiler
einmal bauen — `build.zig` sucht ihn standardmäßig unter
`~/Flash/zig-out/bin/flashc-stage1` (mit `-Dflashc=`
überschreiben):
```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
```
Alles für den Pi bauen (`kernel8.img` + `armstub8.bin` landen in
`zig-out/`):
```bash
zig build # default: -Dboard=rpi4b
```
Oder für QEMU `-M virt` bauen (kein armstub):
```bash
zig build -Dboard=virt
```
Den Kernel unter QEMU ausführen:
```bash
zig build -Dboard=rpi4b run # raspi4b machine (Pi 4 model)
```
```bash
zig build -Dboard=virt run-virt # generic ARMv8 virt machine
```
Host-seitige Unit-Tests ausführen (Page Allocator + ELF-Parser):
```bash
zig build test
```
Für den vollständigen Hardware-Ablauf (zweiphasiger Build mit
Symboltabellen-Befüllung und einem interaktiven `deploy`-Prompt):
```bash
./build.sh
```
Siehe [Setup](SETUP.md) für das SD-Karten-Layout, die Firmware-Dateien
und das Setup der seriellen Konsole.
## Build-Schritte
| Schritt | Was er tut |
| :----------------------------------- | :-------------------------------------------------------------------- |
| `zig build` (oder `-Dboard=rpi4b`) | Default — Pi:`kernel8.img` + `armstub8.bin` |
| `zig build -Dboard=virt` | virt:`kernel8.img` only (no armstub) |
| `zig build kernel` | Nur Kernel-Image |
| `zig build armstub` (rpi4b only) | Nur Armstub |
| `zig build populate-syms` | `src/symbol_area.S` aus der gelinkten ELF neu generieren |
| `zig build deploy` (rpi4b only) | Artefakte + RPi-Firmware nach `$SD_BOOT` kopieren |
| `zig build -Dboard=rpi4b run` | Boot unter `qemu-system-aarch64 -M raspi4b` |
| `zig build -Dboard=virt run-virt` | Boot unter `qemu-system-aarch64 -M virt` |
| `zig build -Dboard=virt test-virt` | virt booten, watchdog prüft, dass der Boot den fsh-Prompt erreicht |
| `zig build -Dboard=rpi4b test-rpi4b` | raspi4b booten, watchdog prüft, dass der Boot den fsh-Prompt erreicht |
| `zig build -Dboard=virt iso` | Eine GRUB-EFI-Rescue-ISO bauen (nur virt) |
| `zig build test` | Host-seitige Unit-Tests (468 tests, 41 modules) |
| `zig build clean` | `.zig-cache/` und `zig-out/` entfernen |
Der Standard-Optimierungsmodus ist `ReleaseSmall`. Mit
`-Doptimize=ReleaseSafe` (oder `Debug`, `ReleaseFast`) überschreiben.
## Repository-Layout
```text
src/ kernel core (Flash + AArch64 assembly)
src/board// per-board driver bag (rpi4b / virt) + linker script
user_space/ PID 1 image + in-kernel test harness
user_space/lib/flibc/ userland mini-libc for ELF demos
lib/ shared kernel↔user constants (syscall IDs)
tools/ hand-rolled ELF demos (hello, stackbomb, flibc_demo)
tests/ host-side unit tests
armstub/ EL3 → EL1 bootstrap shim (Pi only)
scripts/ symbol-table generation, iso, QEMU test watchdog,
Pi-baseline verifier
assets/ logo and visual assets
build.zig the only build entry point
build.sh two-pass build orchestrator + deploy prompt
flash-toolchain.lock pinned flashc revision (Flash→Zig transpiler)
config.txt RPi 4 firmware configuration
```
Ein tieferer Durchgang durch jedes Subsystem findet sich in der
[Dokumentation](DOCUMENTATION.md).
## Versionierung
`v[MAJOR].[MINOR].[PATCH]`. Pro-Tag-Notizen finden sich auf der
[Releases-Seite](https://github.com/ajhahnde/FlashOS/releases).
## KI-Unterstützung
Die Prosa-Docs in diesem Repo (README, DOCUMENTATION, CHANGELOG, PORT)
sind LLM-entworfen unter meiner Durchsicht. Ehrlich gehalten werden sie
durch den Build, nicht durch Vertrauen: das OS wird verifiziert, indem
man es bootet, nicht indem man es beschreibt.
- Bootet von derselben Kernel-ABI in eine Login-Shell auf QEMU `virt`
und Raspberry Pi 4B
- `-Dboot-selftest=true` führt das kernelinterne `[TEST]`-Harness als
PID 1 vor dem Login-Prompt aus — Prozess-, Dateisystem-, Memory-Fault-
und Geräte-Szenarien, jeweils von Free-Page-Checkpoints eingeklammert,
um Leaks sichtbar zu machen
- Der Kernel ist in Flash geschrieben und über den Schwester-Compiler
`flashc` zu Zig transpiliert — gepinnt in `flash-toolchain.lock`
Wenn ein Doc behauptet, ein Subsystem funktioniere, dann ist es der
Boot-Pfad, der es ausübt.
Die Docs werden außerdem durch eine automatisierte Drift-Prüfung aktuell
gehalten, die die darin zitierten Contract-Werte — Version,
Boot-Contract-Zahlen, ABI-Konstanten — mit dem Live-Tree synchron hält,
sodass eine veraltete Kopie erkannt statt ausgeliefert wird.
Der Source-Code (`src/*.flash`, die Zig-Treiber, die AArch64-Assembly)
ist von mir verfasst.
## Lizenz
Apache License, Version 2.0. Siehe [Lizenz](../../LICENSE.md).
## Siehe auch
- **[Flash](https://github.com/ajhahnde/Flash)** — eine Systemsprache und Zig-Transpiler.
- **[eeco](https://github.com/ajhahnde/eeco)** — selbstwartendes Workflow-Ökosystem.
- **[the-way-out](https://github.com/ajhahnde/the-way-out)** — Top-down-Pixel-Art-Escape-Room-Shooter.
- **[Theria](https://github.com/ajhahnde/Theria)** — 2.5D-MOBA, gebaut in Godot 4.
---
[Als Nächstes: Dokumentation →](DOCUMENTATION.md)