Inhaltsverzeichnis

Lyx OS – Anwendungen entwickeln

Diese Seite richtet sich an Entwickler, die Programme für Lyx OS schreiben möchten. Voraussetzung: Grundkenntnisse der Lyx-Sprache und ein laufendes LyxOS-System (→ Erste Schritte).

Syscall-Referenz · Architektur · Übersicht


1. Zielplattform: --target=lyxos

Jedes Lyx-Programm für LyxOS wird mit dem Flag –target=lyxos kompiliert. Dieses Target unterscheidet sich wesentlich vom Standard-Linux-Target:

Eigenschaft Linux-Target (default) LyxOS-Target (–target=lyxos)
Laufzeitbibliothek libc (glibc / musl) lyxrt_lyxos.lyu (keine libc)
Ausgabe PrintLn(s) write(1, …) via libc sys_write(FD_STDOUT, …) direkt
Speicher mmap(…) mmap() via libc sys_mmap(…) direkt
Binärformat ELF64 (Linux ABI) ELF64 (LyxOS ABI)
Einstiegspunkt main() via libc-Initialisierung main() direkt (kein CRT0)
Syscall-Nummern Linux-Tabelle LyxOS-Tabelle (doku/syscalls.md)

# Kompilieren für LyxOS
lyxc --target=lyxos meinprogramm.lyx -o meinprogramm.elf

Das Resultat ist ein ELF64-Binary ohne externe Shared-Library-Abhängigkeiten.


2. Basis-Programm

Das einfachste lauffähige LyxOS-Programm:

fn main(): int64 {
    PrintLn("Lyx OS — Ring-3 aktiv!");
    return 0;
}

PrintLn wird vom Compiler auf sys_write(FD_STDOUT, …) abgebildet. return 0 ruft sys_exit(0) auf. Kein import nötig.


3. Ausgabe und Eingabe

Ausgabe

// Einzeiliger String (mit Newline)
PrintLn("Hello LyxOS");

// Ohne Newline
Print("Zähler: ");
PrintLn(IntToStr(42));

// Fehlerausgabe (FD_STDERR)
EPrintLn("Fehler: Ressource nicht verfügbar");

// Formatierte Ausgabe
import std.io;
PrintfSI("User %s hat ID %d", "admin", 1001);

Tastatureingabe (ab M5)

// Zeichen einlesen via sys_read(FD_STDIN, buf, 1)
var buf: [4]uint8 := [];
var n: int64 := 0;
// (n, err) := syscall(SYS_READ, FD_STDIN, ^buf[0] as int64, 1);


4. Dateisystem

Die FAT32-Partition wird als / gemountet. Alle Pfad-Syscalls nehmen einen dir_fd als erstes Argument. AT_CWD = -1 verweist auf das aktuelle Arbeitsverzeichnis.

// Datei öffnen (sys_open, Gruppe 0x0200)
// var fd: int64 := 0;
// var err: int64 := 0;
// (err, fd) := syscall(SYS_OPEN, AT_CWD, "/data/config.txt", O_RDONLY, 0);

// Konventionell über Lyx-Builtins (werden intern gemappt):
import std.fs;
var fd: int64 := open("/data/config.txt", O_RDONLY, 0);
if (fd < 0) {
    EPrintLn("Datei nicht gefunden");
    return 1;
}

var buf: [512]uint8 := [];
var n: int64 := read(fd, ^buf[0] as pchar, 512);
close(fd);

 
Pfad-Konventionen:
LyxOS verwendet Forward-Slashes. Die Wurzel des FAT32-Volumes ist / im VFS. Verzeichnisnamen unterscheiden keine Groß-/Kleinschreibung (FAT32-Einschränkung).

5. Speicherverwaltung

Ring-3 erhält Speicher über sys_mmap. Das Lyx-Builtin mmap wird auf diesen Syscall gemappt:

con PROT_READ:    int64 := 1;
con PROT_WRITE:   int64 := 2;
con MAP_PRIVATE:  int64 := 2;
con MAP_ANONYMOUS: int64 := 32;

// 4096 Byte anonymes Mapping
var buf: int64 := mmap(0, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (buf = 0) {
    EPrintLn("mmap fehlgeschlagen");
    return 1;
}

poke8(buf, 42u8);                  // schreiben
var val: uint8 := peek8(buf);      // lesen

munmap(buf, 4096);

Statische Arrays [N]T und lokale Variablen liegen im Stack (kein explizites Freigeben). mmap/munmap für dynamischen Heap-Speicher.


6. Prozesse und Tasks

Prozess starten (ab M5)

// sys_spawn: neuer Prozess aus ELF-Binary
// Kein fork() — Prozesse werden immer frisch erzeugt
con SYS_SPAWN: int64 := 0x0003;
con AT_CWD:    int64 := -1;

// var err, proc_fd := syscall(SYS_SPAWN, AT_CWD, "/bin/editor", argv, envp, 0);

Task (leichtgewichtig, automatisch parallelisiert)

// sys_task_group: Tasks laufen auf freien Cores ohne Programmierer-Eingriff
con SYS_TASK_GROUP_CREATE: int64 := 0x0B00;
con SYS_TASK_GROUP_ADD:    int64 := 0x0B01;
con SYS_TASK_GROUP_AWAIT:  int64 := 0x0B02;

// var err, group := syscall(SYS_TASK_GROUP_CREATE, 0);
// for i in range 0..8 { syscall(SYS_TASK_GROUP_ADD, group, worker_fn, args[i], 8); }
// syscall(SYS_TASK_GROUP_AWAIT, group, -1);

@parallel-Annotation im Lyx-Code lässt den Compiler dieses Muster automatisch generieren.


7. Fehlerbehandlung

Jeder Syscall gibt rax (Fehlercode) und rdx (Nutzwert) zurück. In Lyx –target=lyxos übersetzt der Compiler diese Zwei-Register-Rückgabe in Tupel-Syntax:

// Zwei-Register-Rückgabe als Lyx-Tupel (ab M5 vollständig unterstützt):
// var (err, fd) := sys_open(AT_CWD, "/config.txt", O_RDONLY, 0);
// if (err != 0) {
//     EPrintLn("Fehler: " + IntToStr(err));   // ERR_NOENT = 2 usw.
//     return err;
// }

// Bis M5: Fehlercheck via Rückgabewert
var fd: int64 := open("/config.txt", O_RDONLY, 0);
if (fd < 0) {
    EPrintLn("open fehlgeschlagen");
    return 1;
}

Vollständige Fehlercode-Tabelle: Syscall-Referenz — Fehlercodes


8. Programm in die Disk-Image integrieren

Bis M5 die Shell fertig ist, muss ein Programm manuell in den Kernel-Startvorgang eingebunden werden. Möglichkeit: direkt in kernel.lyx aufrufen.

// kernel.lyx (nach allen Initialisierungen):
import meinprogramm;

pub fn main(boot_info_ptr: int64): int64 {
    // ... Kernel-Init ...
    return meinprogramm.main();
}

Oder: Binary auf FAT32 kopieren und im Build-Skript hinzufügen:

lyxc --target=lyxos hello.lyx -o hello.elf
mcopy -i bootloader/lyx_boot.img@@1048576 hello.elf ::/hello.elf

Letzte Aktualisierung: 2026-06-09