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
 
Ein Treiber in Ring 3 ist kein Widerspruch zum Rest. Der Unterschied ist nicht „wichtig gegen unwichtig„, sondern wann er gebraucht wird: Was zum Hochfahren nötig ist, muss in Ring 0 liegen; alles Übrige kann darüber laufen und mit einem Fehler nur sich selbst mitreißen. Ein abgestürztes 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:

  1. Begrüßung über UEFI ConOut
  2. Kernel laden\\kernel.elf vom UEFI SimpleFileSystem lesen
  3. ELF64 parsenPT_LOAD-Segmente mappen, BSS nullen
  4. UEFI Memory Map holen, ExitBootServices aufrufen
  5. GDT laden (64-Bit Code 0x08, Data 0x10)
  6. COM1 initialisieren (0x3F8 — serielle Debug-Ausgabe)
  7. SYSCALL-MSR (IA32_LSTAR) auf den Ring-0-Einsprungpunkt setzen
  8. Page Tables aufbauen (Identity-Map 4 GB)
  9. Bump-Allocator ab physisch 0x2000000 (32 MB) initialisieren
  10. Sprung in Kernel-Entry (pub fn main(boot_info_ptr: int64) in kernel.lyx)

3. Speicherlayout

Adressbereich Inhalt
0x00000x0FFF Null-Page (unmapped, für null-Checks)
0x10000x1FFFF Bootloader-Code (PE32+ Text-Section)
0x1000000x1FFFFF 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 (PDE mit PS-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() und lyx_trigger() sind keine echten mmap-Aufrufe — der Bootloader fängt negative Größen als vmm_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_ALL ist nicht „alles“. Der Wert ist 63 und deckt damit genau die sechs ursprünglichen Bits ab — PLEDGE_DISPLAY, PLEDGE_DEVICE und PLEDGE_CONFIG kamen später dazu und liegen außerhalb. Wer einem Prozess Geräte- oder Anzeigerechte geben will, muss sie ausdrücklich dazunehmen; PLEDGE_ALL allein genügt nicht.

Für PLEDGE_CONFIG gilt 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