====== Lyx OS – Kernel-Interna ====== Diese Seite richtet sich an Beitragende, die den Kernel weiterentwickeln möchten: Build-Ablauf, Modul-Interaktion, Initialisierungsreihenfolge und praktische Debugging-Techniken. → [[lyxos:architektur|Architektur]] · [[lyxos:syscalls|Syscall-ABI]] · [[lyxos:start|Übersicht]] ---- ===== 1. Verzeichnisstruktur ===== lyx-os/ ├── bootloader/ │ ├── boot.asm ← UEFI-Bootloader (~2900 Zeilen NASM) │ ├── build.sh ← Build-Skript (Assemble + Compile + Image) │ └── run.sh ← QEMU-Startskript ├── kernel/ │ ├── kernel.lyx ← Kernel-Einstiegspunkt; importiert alle Module │ ├── exceptions.lyx ← IDT (256 Gates), CPU-Fault-Routing │ ├── pmm.lyx ← Physical Memory Manager (Bitmap) │ ├── vmm.lyx ← Virtual Memory Manager (PML4, Huge Pages) │ ├── process.lyx ← Prozessmodell, Scheduler-Bootstrap │ ├── sync.lyx ← Mutex, Semaphor, Spinlock │ ├── smp.lyx ← SMP, LAPIC, AP-Trampoline │ ├── ata.lyx ← ATA-Disk-I/O (sektorweise) │ ├── fat32.lyx ← FAT32-Implementierung (~795 Zeilen) │ ├── vfs.lyx ← Virtual-Filesystem-Layer │ ├── keyboard.lyx ← PS/2-Tastatureingabe │ └── ring3.lyx ← Ring-3-Sprungmodul (ELF-Loader + Syscall-Gate) ├── shell/ │ └── shell.lyx ← Minimale Ring-3-Shell └── doku/ ├── syscalls.md ← Syscall-ABI-Spezifikation └── fahrplan.md ← Meilenstein-Plan ---- ===== 2. Build-Ablauf ===== bash bootloader/build.sh Das Skript führt vier Phasen aus: - **Bootloader assemblieren** — ''nasm -f bin boot.asm -o BOOTX64.EFI'' - **Kernel kompilieren** — ''lyxc --target=lyxos'' für jeden ''.lyx''-Kernel-File, dann Linken zu ''kernel.elf'' - **Disk-Image aufbauen** — 128-MB-GPT-Image mit FAT32-EFI-Partition - **ESP befüllen** — ''BOOTX64.EFI'' nach ''/EFI/BOOT/'', ''kernel.elf'' in die Wurzel Einzelne Module neu kompilieren (ohne Full-Build): lyxc --target=lyxos kernel/fat32.lyx -o kernel/fat32.lyu Die ''.lyu''-Dateien sind vorkompilierte Units, die beim Link-Schritt zusammengefasst werden. ---- ===== 3. Kernel-Einstiegspunkt ===== Der Bootloader springt in ''pub fn main(boot_info_ptr: int64)'' in ''kernel.lyx''. Das Argument ist ein Zeiger auf eine ''BootInfo''-Struktur, die der Bootloader vor dem ''ExitBootServices''-Aufruf aufgebaut hat: // BootInfo-Layout (boot_info_ptr ist der Zeiger) // Offset 0: mmap_ptr — Zeiger auf UEFI-Memory-Map // Offset 8: mmap_size — Größe der Memory-Map in Bytes // Offset 16: desc_size — Größe eines Memory-Deskriptors // Offset 24: kernel_end — Physische Endadresse des Kernels // Offset 32: bump_ptr_addr — Adresse des Bump-Allocator-Zeigers pub fn main(boot_info_ptr: int64): int64 { var mmap_ptr: int64 := peek64(boot_info_ptr); var mmap_size: int64 := peek64(boot_info_ptr + 8); var desc_size: int64 := peek64(boot_info_ptr + 16); var kernel_end: int64 := peek64(boot_info_ptr + 24); var bump_ptr_addr: int64 := peek64(boot_info_ptr + 32); // ... } ---- ===== 4. Initialisierungsreihenfolge ===== Die Reihenfolge ist durch Abhängigkeiten erzwungen — sie darf nicht geändert werden ohne die Konsequenzen zu prüfen: 1. PMM — Bitmap-Allocator für physische Pages (braucht UEFI-Memory-Map) 2. VMM — PML4-Page-Tables, CR3 laden (braucht PMM für Page-Allokationen) 3. RNG-Seed — rdtsc() → RandomSeed() (braucht VMM für mmap) 4. Exceptions — IDT mit 256 Gates laden (braucht funktionierende Page-Tables) 5. SMP — LAPIC init, AP-Trampoline, INIT+SIPI senden 6. ATA — ATA-Controller initialisieren (PIO-Modus) 7. FAT32 — BPB lesen, Root-Cluster bestimmen 8. VFS — Virtuellen Filesystem-Layer aufbauen, FAT32 als Root mounten 9. Keyboard — PS/2-Controller initialisieren 10. Scheduler — ProcInit(), ProcActivate() → ab hier preemptiv (100 Hz) 11. Ring-3 — ring3.SysSpawn("shell.elf") → Userspace gestartet > **Wichtig für Beitragende:** Module dürfen ''mmap'', ''peek64'', ''poke64'' und ''PrintLn'' erst nach VMM-Init aufrufen. Vor ''VfsInit()'' darf kein Code auf Dateien zugreifen. ---- ===== 5. Module: Aufgaben und Schnittstellen ===== ==== PMM (pmm.lyx) ==== Bitmap-basierter Physical Memory Manager. 4 GB Adressraum, 4-KB-Pages. PmmInit(mmap_ptr, mmap_size, desc_size, kernel_end); // UEFI-Map parsen var page: int64 := PmmAllocPage(); // Eine Page allozieren PmmFreePage(page); // Page zurückgeben var free: int64 := PmmFreeCount(); // Anzahl freier Pages Physische Adressen die von UEFI als ''EfiConventionalMemory'' markiert sind, werden als frei eingetragen. Kernel-Code und Bootloader-Bereich werden explizit reserviert. ==== VMM (vmm.lyx) ==== Verwaltet die PML4-Page-Table-Hierarchie. Alle 4 GB werden als Identity-Map (1:1 physisch ↔ virtuell) mit 2-MB-Huge-Pages eingetragen. VmmInit(); // PML4 aufbauen und CR3 laden var cr3: int64 := VmmGetCr3(); // Aktuellen CR3 lesen Zukünftig (M5): 4-KB-Seiten für Ring-3 mit separaten Page-Tables pro Prozess. ==== Exceptions (exceptions.lyx) ==== IDT mit 256 Gates. CPU-Exceptions werden auf ''panic()'' oder Fault-Handler weitergeleitet. ExceptionsInit(); // Wird implizit von VMM aufgerufen; kein manueller Aufruf nötig ==== SMP (smp.lyx) ==== LAPIC-Init, AP-Trampoline bei physisch ''0x8000'', INIT+SIPI-Sequenz. var ncpu: int64 := GetCpuCount(); // CPUID → Anzahl logischer CPUs var ap_stack: int64 := mmap(0, 8192, 3, 34, -1, 0); SmpPrepareTrampoline(ap_stack + 8192); // Trampoline schreiben SmpStartAp(1); // SIPI an LAPIC-ID 1 var ready: int64 := GetApStartedCount(); // Wieviele APs sind hochgefahren? ==== Sync (sync.lyx) ==== Kernel-seitige Synchronisationsprimitive für Ring-0-Code. var mx: int64 := MutexCreate(MUTEX_PLAIN); MutexLock(mx); // kritischer Abschnitt MutexUnlock(mx); var sem: int64 := SemCreate(1, 0); SemWait(sem); SemPost(sem); var sl: int64 := GetPrintSpinlockAddr(); SpinlockAcquire(sl); SpinlockRelease(sl); ==== ATA (ata.lyx) ==== PIO-Mode-Disk-I/O. Sektorweises Lesen und Schreiben. Kein DMA in M1-M4. // ATA wird implizit von VfsMountFat32 genutzt // Direktzugriff (für Kernel-Code): AtaRead(lba, sector_count, buf_addr); AtaWrite(lba, sector_count, buf_addr); ==== FAT32 (fat32.lyx) ==== Vollständige FAT32-Implementierung. Cluster-Ketten, BPB-Parsing, Verzeichnis-Einträge (inkl. LFN-Unterstützung). var root_cluster: int64 := Fat32GetRootCluster(); var n: int64 := Fat32ListDir(root_cluster); // Root-Verzeichnis auflisten ==== VFS (vfs.lyx) ==== Abstraktionsschicht über FAT32. Exportiert das Linux-ähnliche ''open/read/write/close''-Interface für Kernel-Code. VfsInit(); VfsMountFat32(2048); // Partition ab LBA 2048 mounten var fd: int64 := VfsOpen(AT_CWD, "shell.elf", O_READ); var n: int64 := VfsRead(fd, buf, 4096); VfsClose(fd); // Weitere Operationen: VfsWrite(fd, buf, n); VfsStat(AT_CWD, "test.txt", statbuf); VfsMkdir(AT_CWD, "mydir"); VfsRename(AT_CWD, "old.txt", AT_CWD, "new.txt"); VfsUnlink(AT_CWD, "old.txt", 0); var dfd: int64 := VfsOpenDir(AT_CWD, "."); VfsReadDir(dfd, dbuf, 20); ==== Ring-3 (ring3.lyx) ==== ELF64-Loader und Userspace-Sprungmodul. Lädt ein ELF-Binary aus dem VFS, setzt Ring-3-Page-Tables auf und springt in ''main()''. var exit_code: int64 := ring3.SysSpawn("shell.elf"); ---- ===== 6. Neues Kernel-Modul hinzufügen ===== - Neue Datei ''kernel/meinmodul.lyx'' anlegen - ''import meinmodul;'' am Anfang von ''kernel.lyx'' eintragen - Initialisierungsfunktion (z.B. ''MeinModulInit()'') an der richtigen Stelle in ''kernel.lyx'' aufrufen - Im Build-Skript ''build.sh'' den Compile-Schritt für das neue Modul ergänzen: lyxc --target=lyxos kernel/meinmodul.lyx -o kernel/meinmodul.lyu Konventionen für Kernel-Module: * Alle exportierten Funktionen beginnen mit dem Modul-Präfix (z.B. ''PmmAllocPage'', ''VfsOpen'') * Kein Ring-3-Syscall-Interface direkt im Modul — Syscall-Handler werden in ''ring3.lyx'' registriert * ''PrintLn'' / ''PrintStr'' für Debug-Ausgaben; nicht im Release-Build verwenden wenn möglich * Kein globaler State außerhalb des Moduls; alle Zustandsvariablen als modul-lokale ''var'' deklarieren ---- ===== 7. Debugging-Techniken ===== ==== Serielle Ausgabe ==== ''PrintLn'', ''PrintStr'' und ''PrintInt'' schreiben sowohl auf COM1 (serielle Konsole) als auch auf den QEMU-Debug-Port (''0xE9 / debugcon''). Beides erscheint im Terminal wenn ''run.sh'' mit ''--headless'' gestartet wird. bash bootloader/run.sh --headless 2>&1 | tee kernel_log.txt ==== Debug-Konsole ==== tail -f /tmp/lyx_debugcon.txt ==== QEMU-Monitor ==== Im laufenden QEMU ''Ctrl-Alt-2'' drücken: info registers # CPU-Registerstand aller VCPUs info mem # Page-Table-Dump x/10i $rip # Disassembly ab aktuellem Instruction Pointer xp /10gx 0x200000 # Physischer Speicher-Dump ab Kernel-Basis ==== Kernel-Panic und assert ==== // In Kernel-Code: assert(condition, "Fehlermeldung"); // Hält die Maschine an wenn condition false panic("Unbekannter Zustand"); // Sofortiger Halt mit Debug-Ausgabe Beim Panic wird der Registerstand auf COM1 ausgegeben, bevor die CPU in eine Endlosschleife geht (''hlt''-Loop). QEMU-Monitor zeigt dann den letzten Stand. ==== GDB über QEMU ==== # run.sh mit GDB-Server starten bash bootloader/run.sh --gdb # wartet auf Port 1234 # In zweitem Terminal: gdb kernel/kernel.elf (gdb) target remote :1234 (gdb) break PmmAllocPage (gdb) continue ---- ===== 8. Prozessmodell (M1–M4) ===== Im aktuellen Stand (M1-M4) ist das Prozessmodell minimal: * ''ProcInit()'' initialisiert den 100-Hz-Preemptiv-Scheduler * ''ProcCreate(fn_idx)'' erzeugt einen Kernel-Thread (Ring-0, nicht Ring-3) * ''ProcActivate()'' startet den Scheduler; ab hier ist der Kernel preemptiv * ''TaskSpawn(fn_idx, arg)'' erzeugt einen leichtgewichtigen Task im Kernel-Kontext * ''TaskAwait(task_id)'' wartet auf Task-Abschluss und gibt den Rückgabewert zurück * ''TaskRunPending()'' führt auf Single-Core alle ausstehenden Tasks synchron aus (BSP-Fallback) Ab M5: vollständige Ring-3-Prozesse mit separaten Adressräumen, ''sys_spawn''-Syscall und ELF-Loader über VFS. ---- ===== 9. Meilenstein-Übersicht ===== ^ Meilenstein ^ Inhalt ^ Status ^ | M1 — Boot & Bare-Metal | UEFI-Bootloader, ELF-Loader | ✅ | | M2 — Kernel-Kern | PMM, VMM, IDT, SMP | ✅ | | M3 — Runtime & Scheduler | Laufzeit, Mutex, Semaphor, Prozessmodell | ✅ | | M4 — I/O | ATA, FAT32, VFS, Keyboard, Ring-3-Shell | ✅ | | M5 — Ring-3 & Shell | Vollständige Userspace-Shell, sys_spawn, ELF-Loader | Offen | | M6 — Netzwerk | TCP/IP-Stack, Syscall-Gruppe 0x0600 | Offen | | M7 — Lyra-Agent | Kernel-KI-Subsystem (kernel/ai.lyx), Lyra-Basisschicht | Offen | | M8–M10 | Semantic OS Layer, Aerospace Safety, Distribution | Offen | Der vollständige Fahrplan mit Work-Package-Details liegt unter ''doku/fahrplan.md'' im Repository. Letzte Aktualisierung: 2026-06-09