Lyx OS – Systemarchitektur
Diese Seite beschreibt den Aufbau von Lyx OS: welcher Code in Ring 0 läuft und welcher in Ring 3, wie beide miteinander reden, und wo Prozesse und Treiber dabei sitzen. Dazu die Schichten vom UEFI-Boot bis zum Ring-3-Userspace, das Speicherlayout, die Kernel-Module und das Capability-Routing-Gate.
→ Übersicht · Syscall-ABI · Kernel-Interna · Treibermodell · Prozesse & Ring-3 · Werkzeuge in /bin · Vega
1. Die zwei Ringe
Lyx OS benutzt genau zwei Schutzringe der CPU: Ring 0 für den Kernel, Ring 3 für alles andere. Ring 1 und 2 bleiben ungenutzt — sie tragen auf x86-64 keinen Nutzen, den eine saubere Syscall-Grenze nicht besser erbringt.
┌─────────────────────────────────────────────────────────────┐
│ RING 3 │
│ │
│ Vega-Compositor ← Startziel, preemptiver Scheduler-Faden │
│ ├── term Terminal │
│ ├── taskmgr Aufgabenverwaltung │
│ └── /bin/<werkzeug> als Kind des Terminals │
│ │
│ Tier-1-Treiber: usbhid · i2chid │
│ lyxc (als LBF) │
│ shell.elf Wartungs-Shell (Rückfallebene) │
│ Lyra — noch nicht umgesetzt │
├─────────────────────────────────────────────────────────────┤
│ SYSCALL-GRENZE r3_sc_block + Capability Routing Gate │
├─────────────────────────────────────────────────────────────┤
│ RING 0 — TCB │
│ │
│ Speicher PMM · VMM · Bump-Arena │
│ Ablauf Scheduler (4096 Fäden, ≤ 8 Kerne) · SMP · IDT │
│ Dateien VFS · FAT32 · IOFS · Initrd │
│ Tier-0-Treiber: │
│ Platten ATA · AHCI · NVMe · virtio-blk · RAM · USB-MSC │
│ Netz e1000 · pcnet · rtl8139 · virtio-net + TCP/IP │
│ Bus PCI · ACPI · xHCI · I²C (DesignWare) │
│ Ton HDA · AC97 Eingabe PS/2-Tastatur │
│ Laden ELF64-Loader · LBF-Loader (LYX!) │
├─────────────────────────────────────────────────────────────┤
│ UEFI-Bootloader (boot.asm, PE32+ → BOOTX64.EFI) │
├─────────────────────────────────────────────────────────────┤
│ UEFI-Firmware (OVMF) / PC-Hardware │
└─────────────────────────────────────────────────────────────┘
Mechanismus und Intelligenz sind strikt getrennt: Der TCB enthält kein LLM und ruft keines auf. Lyra (Ring 3) soll das Modell halten, vorschlagen und Capabilities erteilen — erzwingen tut ausschließlich Ring 0.
Was in Ring 0 läuft — und warum
| Bereich | Warum Ring 0 |
|---|---|
| Speicher- und Seitenverwaltung, IDT, SMP | ohne Ring-0-Rechte nicht möglich |
| Scheduler | er schaltet die Kontexte um, die er verwaltet |
| Dateisysteme (VFS, FAT32, IOFS, Initrd) | hängen unmittelbar an den Blocktreibern |
| Tier-0-Treiber | boot- und latenzkritisch: ohne Platte kein Dateisystem, ohne Netzkarte kein Netz. Sie tragen sich in eine Registry ein (kernel/drv.lyx), statt sich über if-Ketten zu verteilen → Treibermodell |
| ELF- und LBF-Loader | sie bauen die Adressräume auf, in denen Ring 3 startet |
Was in Ring 3 läuft
| Was | Wie gestartet | Anmerkung |
|---|---|---|
| Vega-Compositor | vom Kernel als preemptiver Scheduler-Faden (SchedBootCompositor(„/vega.elf“)) | das Startziel: fehlt vega.elf, startet stattdessen shell.elf. Priorität NORMAL mit längerer Zeitscheibe — ein höher priorisierter Compositor würde die Dienstfäden aushungern |
term, taskmgr, uidemo, lbfwin | von Vega | Fenster des Compositors |
42 Werkzeuge in /bin | vom Terminal als Kind | → Werkzeuge in /bin |
Tier-1-Treiber usbhid, i2chid | wie ein gewöhnliches Programm | vollständig in Ring 3; der Kernel stellt nur MMIO, PCI, DMA und den I²C-Bus → Treibermodell |
lyxc | aus dem Terminal | der Compiler läuft als LBF im Userland |
shell.elf | Rückfallebene beim Hochfahren | die Wartungs-Shell, → Shell |
| Lyra | — | noch nicht umgesetzt |
usbhid kostet die Maus, keinen Neustart.
Zwei Wege, einen Ring-3-Prozess zu führen
Historisch gewachsen, und beide sind heute in Gebrauch:
| Fadentabelle des Schedulers | achild-Tabelle |
|
|---|---|---|
| Wo | kernel/sched_types.lyx | kernel/ring3.lyx |
| Größe | MAX_THREADS = 4096, MAX_CPUS = 16 (hochgefahren werden ≤ 8) | ACHILD_MAX = 8 Plätze |
| Zustände | frei, bereit, läuft, blockiert, tot | 0 = frei, 1 = aktiv, -1 = beendet |
| Je Eintrag | vollständiger Fadenzustand, Priorität, Zeitscheibe, Affinität | 64 Byte: RSP, RCX, R11, RBP, CR3, Heap, Status, verbrauchte Ticks |
| Wer benutzt es | Compositor, Dienstfäden, alles preemptiv Geplante | die Kinder, die das Terminal startet |
ps liest die Fadentabelle (Syscalls 206/207), top die achild-Plätze (202). Dass beides nebeneinandersteht, ist kein Entwurf, sondern der Stand: die Ereigniswarteschlangen wurden bereits von den acht slot+2-Kennungen auf die Faden-Kennungen umgestellt (EV_PIDS = 256).
Mehrere Kerne
Der Bootstrap-Kern (BSP) trägt den Compositor. Die übrigen Kerne werden hochgefahren und laufen im Leerlauf; ein fest zugeordneter Rechenfaden auf Kern 1 ist die geprüfte Vorgabe. Das MP3-Dekodieren auf einem eigenen Kern ist gebaut, aber noch nicht die Vorgabe — unter KVM mit vier vCPUs erreicht der Bootlauf die Diagnoseausgabe nicht zuverlässig. Deshalb zeigt top regelmäßig Kern 0 nahe 100 % und die übrigen nahe 0 %.
2. Boot-Ablauf
Der Bootloader (bootloader/boot.asm, NASM, ~2900 Zeilen) ist ein PE32+-Flat-Binary. UEFI lädt es als BOOTX64.EFI und ruft efi_main(ImageHandle, SystemTable) auf (MS x64 ABI).
Schritte:
- Begrüßung über UEFI
ConOut - Kernel laden —
\\kernel.elfvom UEFI SimpleFileSystem lesen - ELF64 parsen —
PT_LOAD-Segmente mappen, BSS nullen - UEFI Memory Map holen,
ExitBootServicesaufrufen - GDT laden (64-Bit Code 0x08, Data 0x10)
- COM1 initialisieren (0x3F8 — serielle Debug-Ausgabe)
- SYSCALL-MSR (
IA32_LSTAR) auf den Ring-0-Einsprungpunkt setzen - Page Tables aufbauen (Identity-Map 4 GB)
- Bump-Allocator ab physisch 0x2000000 (32 MB) initialisieren
- Sprung in Kernel-Entry (
pub fn main(boot_info_ptr: int64)inkernel.lyx)
3. Speicherlayout
| Adressbereich | Inhalt |
|---|---|
0x0000 – 0x0FFF | Null-Page (unmapped, für null-Checks) |
0x1000 – 0x1FFFF | Bootloader-Code (PE32+ Text-Section) |
0x100000 – 0x1FFFFF | Bootloader-Heap / Temporäre Strukturen |
0x200000 – ~ | Kernel-ELF (PT_LOAD-Segmente) |
0x2000000 | Bump-Allocator-Basis (Kernel-Heap) |
0x1800000 (24 MB) | SHELL_PHYS_BASE — Ring-3 ELF-Binary (physisch = virtuell mit Identity-Map) |
0x10000000 (256 MB) | USER_HEAP_BASE — virtueller Basis für user_mmap (wächst aufwärts) |
– 4 GB | Identity-Map (1:1 physisch ↔ virtuell) |
0xFFFF800000000000+ | (Zukünftig: höhere Hälfte Kernel-Space) |
Page-Größen:
- Kernel: 2 MB Huge Pages (
PDEmitPS-Bit) für die ersten 4 GB - Userspace (M5+): 4 KB Seiten für granulare Rechteverwaltung
4. Kernel-Module
Der Kernel besteht aus 25 Lyx-Units, die beim Build einzeln zu .lyu vorkompiliert und dann zu kernel.elf zusammengelinkt werden:
| Modul | Datei | Aufgabe |
|---|---|---|
| Exceptions | exceptions.lyx | IDT (256 Gates), CPU-Fault-Routing, panic/assert |
| PMM | pmm.lyx | Physical Memory Manager — Bitmap-basiert, 4 GB, UEFI-Memory-Map als Basis |
| VMM | vmm.lyx | Virtual Memory Manager — PML4, Huge Pages, per-Prozess CR3, User-Page-Mapping |
| Process | process.lyx | Prozess-Modell: ProcCreate, ProcActivate |
| Sync | sync.lyx | Synchronisations-Primitive: Spinlock, Mutex, Semaphor — → Sync-Primitive |
| SMP | smp.lyx | Symmetric Multiprocessing — LAPIC, Trampoline, AP-Startup, Task-API — → SMP & Tasks |
| ATA | ata.lyx | ATA-Disk-I/O — Legacy (Primary Master) und Multi-Disk (4 Kanäle, vmm_op42-44) |
| Disk | disk.lyx | Disk-Abstraktion — probt alle 4 ATA-Kanäle beim Start, cacht Sektorzahl + Modell |
| MBR | mbr.lyx | MBR-Partition-Tabelle — Lesen und Schreiben von Einträgen (Typ 0x0C FAT32 LBA) |
| FAT32 | fat32.lyx | Vollständige FAT32-Implementierung mit LFN-Lesen und LFN-Schreiben |
| VFS | vfs.lyx | Virtual-Filesystem-Layer — FAT32 + Initrd; open/read/write/stat/seek/mkdir/dir/dup |
| Keyboard | keyboard.lyx | Tastatureingabe (PS/2), Tastaturbelegung (Layout-Index via KbdSetLayout) |
| Initrd | initrd.lyx | In-Memory-Ramdisk (Format: LIXR-Magic + Einträge + 4B-Terminator) |
| Locale | locale.lyx | Internationalisierung — 5 Locales, Zahlen-/Zeit-/Datumsformat, LocaleInit liest /config/locale.cfg |
| Ring-3 | ring3.lyx | ELF64-Loader, SysSpawn, Syscall-Handler, Capability Routing Gate (PLEDGE_*) — → Prozesse & Ring-3 |
| XHCI | xhci.lyx | USB 3.x-Host-Controller-Treiber — Enumerierung, Datentransfer (WP25) → XHCI |
| RAM-Disk | ramdisk.lyx | RAM-Disk-Treiber, Disk-IDs 8–11 (DISK_RAM_BASE = 8, vier Plätze) — Syscalls 153–154 (WP30) → RAM-Disk |
| IOFS-Alloc | iofs_alloc.lyx | Block-Allocator, mkfs, CRC32C, Page-I/O — Syscall 155 (WP01+WP09) |
| IOFS-RW | iofs_rw.lyx | Mount, Read/Write, Checkpoint — Syscalls 156–164 (WP02) |
| IOFS-WAL | iofs_wal.lyx | Write-Ahead-Log — kernel-intern, kein Syscall (WP04) |
| IOFS-Graph | iofs_graph.lyx | Graph-Kanten — Syscalls 165–169 (WP05) |
| IOFS-Traverse | iofs_traverse.lyx | Graph-Traversal BFS/DFS/Reachable/ShortestPath — Syscalls 170–173 (WP06) |
| IOFS-Names | iofs_names.lyx | Named Nodes, Name-Store, GC — Syscalls 174–179 (WP07+GC) → IOFS |
| Net + TCP | net.lyx | E1000-Treiber, DHCP, ARP, TCP — Syscalls 180–184 (WP26, WP16-TCP) → Syscall-ABI |
| Kernel | kernel.lyx | Einstiegspunkt — importiert und initialisiert alle Module |
→ Welche Controller, Busse und Geräteklassen heute bedient werden — und womit man einen eigenen Treiber schreibt: Treibermodell.
Initialisierungsreihenfolge in kernel.lyx:
PMM → VMM → RNG-Seed → SMP → VFS (→ Fat32VolumeInit, MbrInit) → DiskInit
→ FAT32-Mount → LocaleInit → Initrd-Mount → SysSpawn (Ring-3 Shell)
→ Keyboard-Poll → Sync-Tests → Scheduler (ProcInit, ProcActivate)
5. Syscall-Grenze
Ring-3-Code kommuniziert mit dem Kernel über einen gemeinsamen Speicherblock (r3_sc_block) und einen dedizierten Trigger-Mechanismus — kein traditionelles SYSCALL-Register-Layout.
r3_sc_block-Protokoll:
// Shared block (physische Adresse wird bei Boot-Start übergeben)
offset 0: nr — Syscall-Nummer (int64)
offset 8: a0 — Argument 0 (int64)
offset 16: a1 — Argument 1 (int64)
offset 24: a2 — Argument 2 (int64)
offset 32: a3 — Argument 3 (int64)
offset 40: result — Rückgabewert (int64), wird vom Kernel geschrieben
// Ablauf aus Ring-3-Sicht:
var sc: int64 := lyx_get_r3sc(); // einmalig: mmap(0,-5,...) → Blockadresse holen
poke64(sc + 0, NR); // Syscall-Nummer schreiben
poke64(sc + 8, arg0); // Argumente schreiben
lyx_trigger(); // mmap(0,-6,...) → Kernel-Handler aufrufen
var result: int64 := peek64(sc + 40);
lyx_get_r3sc()undlyx_trigger()sind keine echten mmap-Aufrufe — der Bootloader fängt negative Größen alsvmm_op-Sentinel ab (op -5 = Block-Adresse holen, op -6 = Trigger).- User-virtuelle Puffer-Adressen (z.B. Lese-Buffer) werden im Kernel via
VmmPhysFromUserVirt(proc_cr3, vaddr)in physische Adressen übersetzt, bevor sie an VFS-Funktionen weitergegeben werden. - Ring-3-FDs sind VFS-FDs + 3 (fd 0 bleibt für stdin/Keyboard reserviert).
→ Implementierung im Kernel: ring3.lyx (handle_r3_syscall) · Vollständige ABI-Spezifikation: Syscall-Referenz · Prozess-Lebenszyklus: Prozesse & Ring-3
6. Capabilities — alles ist ein fd
Lyx OS kennt keine root-Privileg-Eskalation. Jeder fd ist eine Capability: er kodiert sowohl die Ressource als auch die erlaubten Operationen (Lesen, Schreiben, Mappen, Löschen …). Capabilities können nur eingeschränkt, nie erweitert werden.
| Designprinzip | Konsequenz |
|---|---|
| Kein Root | Kein chmod 4755, kein sudo-Äquivalent |
| CLOEXEC by default | Neue fd werden nicht über sys_spawn vererbt — opt-in mit O_INHERIT |
Ein fd-Typ | fd für Dateien, Sockets, Prozesse, AI-Sessions sind konzeptuell gleich |
Alle Pfad-Syscalls nehmen dir_fd | AT_CWD als Default — keine TOCTOU-Lücken durch absolute Pfade |
PLEDGE_*-Bitmask (implementiert in ring3.lyx):
pub con PLEDGE_STDIO: int64 := 1; // stdin/stdout lesen/schreiben
pub con PLEDGE_VFS: int64 := 2; // sys_open, sys_read, sys_write, stat
pub con PLEDGE_EXEC: int64 := 4; // sys_spawn
pub con PLEDGE_BLOCK: int64 := 8; // Rohzugriff auf Blockgeräte
pub con PLEDGE_NET: int64 := 16; // Netzwerk-Sockets
pub con PLEDGE_PROC: int64 := 32; // Prozessverwaltung (kill, nice …)
pub con PLEDGE_ALL: int64 := 63; // die sechs oben
pub con PLEDGE_DISPLAY: int64 := 65536; // Bildspeicher beanspruchen (sys_fb_map)
pub con PLEDGE_DEVICE: int64 := 131072; // MMIO abbilden, PCI lesen (Tier-1-Treiber)
pub con PLEDGE_CONFIG: int64 := 262144; // persistente Konfiguration SCHREIBEN
SysPledge(PLEDGE_STDIO %%|%% PLEDGE_VFS); // Capabilities einschränken (irreversibel)
PLEDGE_ALList nicht „alles“. Der Wert ist63und deckt damit genau die sechs ursprünglichen Bits ab —PLEDGE_DISPLAY,PLEDGE_DEVICEundPLEDGE_CONFIGkamen später dazu und liegen außerhalb. Wer einem Prozess Geräte- oder Anzeigerechte geben will, muss sie ausdrücklich dazunehmen;PLEDGE_ALLallein genügt nicht.
FürPLEDGE_CONFIGgilt zusätzlich: hier hilft auch „Maske 0 = unbeschränkt„ nicht — das Recht muss im Manifest stehen.
Der Capability Routing Gate in handle_r3_syscall prüft für jede Syscall-Nummer die benötigte Capability-Klasse (syscall_capability_class) gegen die pledge_mask des Prozesses. Verstöße erzeugen ERR_CAPVIOL (Implementierung: WP15).
→ Details: Prozesse & Ring-3
7. Drei-Domänen-Architektur
Perspektivisch teilt Lyx OS den Adressraum in drei Domänen. Zwei davon gibt es, eine ist Entwurf:
| Domäne | Ring | Stand |
|---|---|---|
| TCB (Trusted Computing Base) | Ring 0 | da — deterministisch, vollständiger Hardwarezugriff, ruft nie ein LLM |
| Lyra | Ring 3, privilegiert | Entwurf (WP17): KI-Agent, hält Modell und Compiler, erteilt Capabilities |
| User | Ring 3, minimal | da — Compositor, Terminal, Werkzeuge, Tier-1-Treiber, jeweils mit eigener Maske |
Die frühere Angabe „heute läuft ausschließlich die Shell als Ring-3-Prozess“ ist überholt: In Ring 3 laufen inzwischen der Compositor als Startziel, seine Fenster, 42 Werkzeuge in /bin, zwei Treiber und der Compiler selbst. Die Wartungs-Shell ist die Rückfallebene, nicht mehr der Normalfall.
Was die Trennung heute schon leistet und was nicht: Der Kernel hält jeden Prozess an seiner Maske fest — ein LBF ohne Manifest bekommt nur PLEDGE_STDIO. Was er nicht leistet: das Manifest ist eine Selbstauskunft, und für Tier-1-Treiber wird keine Isolationsgarantie nach außen behauptet. Die Grenzen stehen im Treibermodell.
Letzte Aktualisierung: 2026-08-27 — Abschnitt 1 als „Die zwei Ringe„ neu geschrieben (was in Ring 0 und Ring 3 läuft, die beiden Prozesstabellen, SMP-Rollen); PLEDGE-Liste um DISPLAY/DEVICE/CONFIG ergänzt samt Hinweis, dass PLEDGE_ALL sie nicht enthält; Abschnitt 7 auf den Stand gebracht. Erhoben aus kernel/kernel.lyx, ring3.lyx, sched_ring3.lyx, sched_types.lyx, drv.lyx.
Vorherige Aktualisierung: 2026-06-25
