So sieht's innen aus
Vom Einschalten bis zum Prompt – und wer mit wem redet.
Der Start
nb – der Bootloader
Eine kleine UEFI-Anwendung (boot/nb.c, ohne libc). Sie fragt den Bildschirm ab (GOP), liest
\nullos\nk.elf von der Startpartition, legt die Teile des Kernels an ihre Adressen, holt die
Speicherkarte, verabschiedet sich von UEFI und springt in den Kernel. Alles Wichtige bekommt der Kernel in
einer Struktur mit: Speicher, Bildschirm, ACPI.
nk – der Kernel
Portables C in kernel/, alles Maschinenabhängige in arch/x86_64/. Er läuft in der
oberen Hälfte des Adressraums, Programme bekommen die ganze untere. Was er kann:
- Prozesse:
spawn, fork, exec, wait, Signale (auch Strg+C), Rohre.
- Netz: eigener TCP/IP-Stapel, IPv6 und IPv4 gleichwertig, über virtio-net und e1000. Dazu Unix-Sockets.
- Planer: Threads im Rundlauf, 10-ms-Scheiben, Zeitgeber 100 Hz.
- Speicher: eigene Seitentabellen je Prozess, Schutz gegen Schreiben und Ausführen, Stapel wächst bei Bedarf.
- Programme: statische ELF64, auch positionsunabhängig (PIE).
- Dateien: ein virtuelles Dateisystem;
/ ist ein RAM-Dateisystem aus init.img,
/boot die Startpartition (FAT, nur lesen), dazu /dev/null, /dev/zero, /dev/random …
- Konsole: Bildschirm mit eigener Linienschrift plus serielle Schnittstelle, Zeilenbearbeitung, wichtige ANSI-Folgen.
- Abstürze lesbar: Panik mit Namen, Registern und Aufrufkette.
Mehrere Kerne, Schreiben auf Platten: kommt noch Welche Hardware geht: Treiber.
Die Schichten
Systemaufrufe
Absichtlich klein: 62 Aufrufe (alle umgesetzt und getestet), davon 16 für Sockets, festgeschrieben in docs/syscalls.md und
include/nullos/sys.h. Auf x86_64 per syscall, Nummer in rax, Argumente
wie bei Linux. Fehler kommen als negative Zahl zurück. Nummern werden nie umgedeutet, nur ergänzt.
Programme sind statische ELF64-Dateien, ohne Bibliotheken zur Laufzeit. Später kommt noch ein
schneller Ring für viele Aufträge auf einmal dazu.
Werkzeuge schreiben gegen eine kleine ABI
Damit hunderte Werkzeuge gleichzeitig entstehen konnten, obwohl der Kernel noch nicht fertig ist, schreiben
alle nur gegen eine knappe Liste von C-Funktionen (docs/abi.md): Strings, Speicher, Dateien,
Ordner, Zeit, Prozesse. Dieselbe Quelle läuft auf dem Mac und unverändert auf nullos.
libc – die eigene C-Bibliothek
Von Grund auf neu (musl und PDCLib nur als Lesestoff). Ein portabler Teil – Zeichenketten, malloc,
stdio, printf, Zeit, Mathe – und darunter eine dünne Schicht von rund 70 Funktionen zum Kern. Davon gibt es zwei:
eine für nullos und eine für macOS, die ganz ohne Apples libc auskommt (Systemaufrufe direkt).
- printf und strtod rechnen exakt und geben Byte für Byte dasselbe aus wie die macOS-libc – getestet mit
5000 Zufallszahlen.
- Mathe nach fdlibm-Art: höchstens 1–3 Einheiten in der letzten Stelle daneben, gemessen.
- Fehlertexte auf Deutsch.
- Probe aufs Exempel: 226 Werkzeuge bestehen ihre Tests mit dieser libc auf dem Mac – ohne eine einzige Funktion der macOS-libc.
- Fehlt noch: Gebietsschemata außer „C“, breite Zeichen, Fäden.
cc – der eigene C-Compiler
Ein C11-Compiler in C11, komplett mit eigenem Assembler und eigenem ELF-Linker. Die großen Momente:
- Er übersetzt sich selbst. cc → cc2 → cc3, und cc2 und cc3 erzeugen genau dasselbe.
- Er übersetzt alle Werkzeuge aus
cmd/, und ihre Tests laufen grün.
- Er baut ganz nullos – Kernel, libc und 280 Werkzeuge –, und das bootet in QEMU, alle Tests grün.
- Er läuft auf nullos selbst und übersetzt sich dort noch einmal: cc2 entsteht auf nullos und übersetzt
richtig.
- Die ELF-Objekte seines Assemblers gleichen Byte für Byte denen von clang.
Codeerzeugung gibt's für x86_64, ARM64 und RISC-V 64 (die beiden letzten getestet in QEMU). RISC-V 32 für die kleinen ESP32 und Xtensa sollen folgen. kommt noch