Diese Seite beantwortet zwei Fragen: welche Controller, Busse und Geräteklassen Lyx OS heute bedient — und womit man einen eigenen Treiber schreibt.
→ Lyx OS · Architektur · Geräte-Verzeichnis · lsdrv · lspci · XHCI-Treiber · Syscall-ABI
| Stufe | Wo der Treiber läuft | Wofür |
|---|---|---|
| Tier-0 | in Ring 0, in den Kernel einkompiliert | boot- und latenzkritisch: Platten, Netzkarte, USB-Host, I²C-Bus |
| Tier-1 | in Ring 3, als gewöhnliches Programm | alles Übrige — heute die HID-Treiber usbhid und i2chid |
Tier-0 heißt nicht „fest verdrahtet„: Die Treiber tragen sich in eine Tabelle ein (kernel/drv.lyx), statt sich über if-Ketten in disk.lyx, vfs.lyx und kernel.lyx zu verteilen. Ein neuer Blocktreiber ist damit ein Registrierungsaufruf, keine Änderung an drei Stellen.
Die Zuordnung läuft über eine Frage an den Treiber — „gehört dir diese Gerätenummer?“ — statt über fest verdrahtete Nummernbereiche. Welche Geräte eine Maschine hat und in welcher Reihenfolge, darf den Ablauf nicht bestimmen.
| Bus | Kennung | Unit | Anmerkung |
|---|---|---|---|
| ATA (PIO) | DISK_BUS_ATA = 0 | kernel/ata.lyx | der Rückfallweg, funktioniert überall |
| SATA / AHCI | DISK_BUS_AHCI = 1 | kernel/ata.lyx | je Anschluss eigene Strukturen; die Gerätenummer ist nicht der AHCI-Port-Index |
| NVMe | DISK_BUS_NVME = 2 | kernel/nvme.lyx | Blockgröße kommt aus dem Namensraum (4Kn möglich), nicht fest 512 |
| virtio-blk | DISK_BUS_VIRTIO = 3 | kernel/virtio_blk.lyx | der vierte Bus, für Virtualisierung |
| RAM-Disk | Nummern 8–11 | kernel/ramdisk.lyx | → RAM-Disk |
| USB-Massenspeicher | Nummer 12 | kernel/xhci.lyx | Bulk-Only Transport + SCSI über den xHCI-Treiber |
Acht Plattenplätze (0–7) für physische Laufwerke, vier RAM-Disks, ein USB-Speicher. Die Registrierung als Blocktreiber erfolgt für ata, ramdisk und usb; NVMe und virtio-blk hängen im Plattenverwalter am Bus-Feld.
| Karte | Kennung | Unit | Wo sie typisch steckt |
|---|---|---|---|
| virtio-net | PCI\VEN_1AF4&DEV_1000 | kernel/virtio_net.lyx | KVM/QEMU — wird zuerst geprüft, weil dort am schnellsten |
| Intel E1000 | PCI\VEN_8086&DEV_100E | kernel/e1000.lyx | QEMU-Vorgabe |
| AMD PCnet | PCI\VEN_1022&DEV_2000 | kernel/pcnet.lyx | VirtualBox |
| Realtek RTL8139 | PCI\VEN_10EC&DEV_8139 | kernel/rtl8139.lyx | verbreitete Emulation |
Darüber liegt kernel/nic.lyx als eine Schnittstelle: der Netzstapel (net.lyx) kennt keine Karte mehr. Vorher rief er E1000Send/E1000Recv unmittelbar auf — damit hatte Lyx OS in VirtualBox schlicht kein Netz.
e1000.
| Was | Unit | Stand |
|---|---|---|
| xHCI-Host-Controller | kernel/xhci.lyx | Enumerierung und Datentransfer; ein Klassentreiber bedient alle (PCI\CC_0C0330) |
| USB-Massenspeicher | kernel/xhci.lyx | Bulk-Only Transport mit SCSI, zwei Bulk-Endpoints je Gerät |
| USB-HID | bin/usbhid.lyx | Tier-1, läuft vollständig in Ring 3 |
| Was | Unit | Stand |
|---|---|---|
| DesignWare-I²C-Controller | kernel/i2c.lyx, kernel/i2c_dw.lyx | über ACPI gefunden; MMIO, IRQ und Version stehen im Geräte-Verzeichnis |
| I²C-HID (Trackpad) | bin/i2chid.lyx | Tier-1: der Kernel stellt nur den Bus (248) und die ACPI-Liste (249/250) |
| Gerät | Kennung | Unit | Ladeart |
|---|---|---|---|
| Intel HD Audio | PCI\CC_040300 | kernel/hda.lyx | bei Bedarf — erst beim ersten Tonaufruf |
| AC97 | PCI\CC_040100 | kernel/ac97.lyx | bei Bedarf |
Der Grund für „bei Bedarf„ steht im Manifest: AC97 und HDA fassen beim Hochfahren PCI, Anschlüsse und DMA an — und genau das hat auf echter Hardware Eingabe und Platte gestört. Ins Geräte-Verzeichnis kommt deshalb nur, was steckt; die Auswahl fällt beim ersten Ton.
| Weg | Wo |
|---|---|
| PS/2-Tastatur | kernel/keyboard.lyx — der Grundweg, der immer da ist |
| USB-HID | bin/usbhid.lyx (Tier-1) meldet Tasten und Maus über 246/247 an den Kernel |
| I²C-HID | bin/i2chid.lyx (Tier-1), gleicher Rückweg |
Jeder Treiber hat eine Datei unter /lib/drivers (im Baum: drivers/*.mf). Sie sagt, wofür er zuständig ist und wann er geladen wird:
# Manifest: USB-Controller (xHCI)
name xhci
treiber eingebaut
laden sofort
abi 1
match PCI\CC_0C0330
| Feld | Bedeutung |
|---|---|
name | Treibername, wie ihn lsdrv anzeigt |
treiber | eingebaut = Tier-0 im Kernel |
laden | sofort, beimStart (der Plattenverwalter fragt ihn im Hochfahren) oder beiBedarf |
abi | Fassung der Treiberschnittstelle |
match | Schlüssel, auf den er passt — mehrfach erlaubt (i2c.mf hat zwei) |
Geprüft wird vom genauesten zum allgemeinsten; der erste Treffer gewinnt. So kommt ein auf das Modell zugeschnittener Treiber vor einem, der nur die Chipfamilie kennt:
| Stufe | Form | Beispiel |
|---|---|---|
| 0 | PCI\VEN_xxxx&DEV_xxxx&SUBSYS_xxxxxxxx&REV_xx | PCI\VEN_8086&DEV_1E31&SUBSYS_00000000&REV_04 |
| 1 | PCI\VEN_xxxx&DEV_xxxx | PCI\VEN_1AF4&DEV_1001 |
| 2 | PCI\CC_xxxxxx (Klasse, Unterklasse, Schnittstelle) | PCI\CC_0C0330 |
| 3 | PCI\CC_xxxx (nur Klasse und Unterklasse) | PCI\CC_0C80 |
lsdrv hält die Manifeste gegen die tatsächlich gefundenen Geräte und zeigt IST gegen SOLL; lyxdevd bindet danach wirklich.
Ein Ring-3-Treiber braucht genau zwei Dinge, um überhaupt anzufangen: seinen MMIO-Bereich im eigenen Adressraum und Zugriff auf die PCI-Konfiguration. Alles Weitere kommt in Stufen dazu:
| Nr | Aufruf | Paket | Wofür |
|---|---|---|---|
| 230 | sys_map_device(phys, size) | DRV-3 | Geräteregister in den eigenen Adressraum abbilden |
| 232 | sys_pci_cfg_read(bdf, reg) | DRV-3 | PCI-Konfiguration lesen |
| 233 | sys_pci_cfg_write(bdf, reg, val) | DRV-3 | PCI-Konfiguration schreiben (Gerät einschalten) |
| 234 | sys_dma_alloc(size) | DRV-4 | DMA-Puffer anfordern, gibt eine Kennung |
| 235 | sys_dma_addr(id) | DRV-4 | die abgebildete Adresse des Puffers |
| 236 | sys_dma_program(id, mmio, offset, width) | DRV-4 | der Kernel trägt die physische Adresse ins Geräteregister ein |
| 237 | sys_notify_create() | DRV-5 | Benachrichtigungsschlange anlegen |
| 238 | sys_notify_post(id) | DRV-5 | melden |
| 239 | sys_notify_wait(id) | DRV-5 | blockierend warten |
| 240 | sys_irq_bind(bdf, notify_id) | DRV-5 | Interrupt des Geräts auf die Schlange legen |
| 241 / 242 | sys_hid_claim(slot, notify_id) / sys_hid_release(slot) | DRV-6 | ein HID-Gerät übernehmen und wieder freigeben |
| 243 / 244 | sys_usb_dev_count() / sys_usb_dev_info(idx, out) | DRV-6 | die enumerierten USB-Geräte durchgehen |
| 245 | sys_hid_claim_dma(slot, notify_id, dma_id) | DRV-6 | dasselbe mit eigenem DMA-Puffer |
| 246 / 247 | sys_input_key(ascii) / sys_input_mouse(dx, dy, btn) | DRV-6 | Eingaben an den Kernel zurückmelden |
| 248 | sys_i2c_xfer(bus, wbuf, lens, rbuf) | I²C | Übertragung auf dem I²C-Bus |
| 249 / 250 | sys_i2c_hid_info(idx, out) / sys_i2c_hid_count() | I²C | die von ACPI genannten Geräte |
Der Treiber bekommt nie eine rohe physische Adresse. Er sagt „DMA in meinen Puffer der Größe N“, bekommt eine Kennung und den Puffer in seinen Adressraum abgebildet — die Adresse ins Geräteregister trägt der Kernel ein, nach Bereichsprüfung. Damit ist die naheliegendste Fußangel („beliebiger physischer Schreibzugriff„) schon in Fassung 1 weg.
Bis 2026-08 fragten die Treiber ihre Geräte ab: USB-HID mit 100 Hz aus dem vsync-Pfad, der Netzempfang in jeder Warteschleife. Das kostet Rechenzeit, meldet spät — und hängt daran, dass jemand die Abfrage überhaupt ruft. Genau daran war USB-HID im Desktop schon einmal tot, weil vsync_wait niemand mehr rief.
Die Verteilung selbst steht in kernel/irq.lyx (Vektor → Lyx-Handler, Rahmen drv_irq_common für 0x50–0x5F mit LAPIC-EOI und drv_pic_common für 32–47 mit PIC-EOI) — siehe Kernel-Interna.
MsiBindVector(bdf, vektor) ergänzt msi.lyx um eine Bindung mit freier Vektorwahl. MsiBind vergibt fest 0x60+notify_id — gedacht für Ring-3-Treiber; ein Treiber im Kernel will seinen eigenen Vektor aus der Verteilung.XhciIrqAttach(idx, vektor) trägt erst den Handler ein, bindet dann MSI/MSI-X und schaltet zuletzt den Interrupter scharf. Andersherum könnte der erste Interrupt eintreffen, bevor jemand zuständig ist. QEMU (–usbhid): Vektor 0x50 (MSI-X).XhciTick(): ohne Interruptbetrieb die alte Abfrage, mit Interrupt nur noch ~1×/s als Sicherheitsnetz, damit ein verlorenes Ereignis nicht dauerhaft hängen bleibt.0xFFFFFFFF nach 0x00D0 mit dem Kommentar „IMC: alle Interrupts maskieren„ — beim 82540EM ist 0x00D0 aber IMS (Maske setzen), IMC liegt auf 0x00D8. Folgenlos, solange kein Handler gebunden war, an drei Stellen korrigiert.NicIrqAttach(vektor) richtet den Empfangs-Interrupt ein, mit zwei Wegen: MSI bevorzugt (kein Routing, keine geteilte Leitung) und INTx als Rückfall — QEMUs 82540EM hat gar keine MSI-Capability, meldet sich aber über eine klassische Leitung (Konfigurationsraum 0x3C); Vektor = 32 + Leitung, eingehängt über op117. Belegt in QEMU: Leitung 11 → Vektor 43.
Der geplante Umbau der AHCI/NVMe-Fertigmeldung auf Interrupt unterblieb — die Messung davor fiel eindeutig aus: disk Wartezeit bis hier: 0 ms in 0 Zugriffen. Der QEMU-Boot liest überhaupt nicht von der Platte; Kernel, Initrd, Schriften und Hintergrund kommen aus der Initrd im Arbeitsspeicher.
Auch bei Zugriffen wäre der Gewinn klein: NVMe wartet in cq_wait auf ein Phase-Bit in der per DMA gefüllten Completion Queue (Rechenzeit, aber keine teuren Gerätezugriffe), AHCI pollt PxCI per MMIO aus dem Bootloader-Assembler. Und der ganze Pfad (DiskRead → fat32 → vfs → Syscall) ist synchron: der Wartende kann nicht schlafen. Ein Interrupt, der eine Marke setzt, ersetzt die Warteschleife nicht, er ändert nur ihr Ziel. Der Gewinn entstünde erst mit asynchronem Disk-I/O.
Die Messung selbst bleibt (zwei TSC-Lesungen je Zugriff) und beantwortet die Frage künftig sofort — auch dort, wo tatsächlich von Platte gelesen wird. Ausgegeben wird sie nur, wenn es Zugriffe gab.
Offen: der Nachweis, dass die Zähler unter Last steigen (Netz), und dass die Zeichen aus dem USB-Interruptpfad im Terminal ankommen — im Prüflauf war der Desktop nicht oben. Anbindung und Stabilität sind belegt (20 s ohne Interrupt-Sturm, PIC-Maske zeigt genau Leitung 9 (SCI) und 11 (Netz) offen), die Wirksamkeit noch nicht.
| Sicherheitsmodus | Wirkung |
|---|---|
| aus (Vorgabe) | eine Rechtemaske von 0 heißt unbeschränkt. Normale ELF-Programme tragen keine, können also auf Geräte zugreifen — der Entwicklungsstand |
| an | ohne Manifest kein Gerätezugriff. Nur Programme mit ausdrücklicher Rechtemaske — also LBF-Dateien, deren Manifest sie trägt — dürfen MMIO abbilden oder PCI anfassen |
Der Kernel meldet den Stand beim Hochfahren: drv Sicherheitsmodus: AN — Geraetezugriff nur mit Manifest (LBF).
Was das Modell ausdrücklich nicht behauptet. Die Quelltexte benennen die Grenzen selbst, und die Doku übernimmt sie unverändert:
* Das Manifest ist eine Selbstauskunft. Es sagt, was ein Treiber anfassen will, und der Kernel hält ihn daran fest — es beweist nicht, dass der Treiber vertrauenswürdig ist. Dafür braucht es Signaturen (Fassung 2).
* Tier-1 ist heute ausschließlich eigener Code. Eine Isolationsgarantie nach außen wird nicht behauptet.
* Der Schutz beisys_map_deviceverhindert nur das Grobe: Bereiche, die sicher kein Gerätespeicher sind (Kernel-Abbild und Bump-Arena unterhalb 160 MB), werden abgelehnt; höchstens 16 MB je Aufruf. Eine echte Grenze zieht erst die IOMMU (Fassung 2).
* Deskriptorketten bleiben offen. Geräte, die vom Treiber geschriebene Ketten im Speicher ablaufen (NVMe-PRP-Listen, Scatter-Gather-Ringe), folgen Zeigern, die der Treiber selbst gesetzt hat. Auch diese Lücke schließt erst die IOMMU.
| Frage | Werkzeug |
|---|---|
| Was steckt überhaupt im Rechner? | lspci (jede PCI-Funktion), sysinfo (was beim Hochfahren gefunden wurde) |
| Welcher Treiber ist zuständig — und hat er sich gemeldet? | lsdrv (IST gegen SOLL) |
| Geräte tatsächlich binden | lyxdevd |
| Welche Platten gibt es? | diskinfo |
| Netzschnittstelle | ifconfig |
| Was hat die Hardware beim Lauf gemeldet? | hwreport — schreibt Prozessor, Speicher, Grafik, Geräte-Verzeichnis und das vollständige Boot-Protokoll in eine Datei (Vorgabe /hwreport.txt) |
Letzte Aktualisierung: 2026-08-29 — Abschnitt 5 „Interrupts statt Abfragen“ ergänzt (WP-DRV-3, USB-HID über MSI-X, Netz-RX über INTx, e1000-Registerfehler, Disk-Messung); erhoben aus kernel/irq.lyx, kernel/acpi_pm.lyx, kernel/xhci.lyx und kernel/nic.lyx.
Vorherige Aktualisierung: 2026-08-27 — Seite neu angelegt; aus drivers/*.mf, kernel/drv.lyx, kernel/disk.lyx, kernel/nic.lyx, kernel/ring3.lyx (DRV-3…DRV-6) und kernel/xhci.lyx erhoben.