frostbyte

Ein Hobby-Betriebssystemkern für x86_64, in C und Assembler. Er bootet über Multiboot2, wechselt mit eigenen Seitentabellen in den 64-Bit-Modus, hat einen präemptiven Scheduler und führt Programme in Ring 3 aus - startet tatsächlich in QEMU.

frostbyte
TL;DR

Ein von Grund auf geschriebener Betriebssystemkern - vom Bootloader bis zum Ausführen eigener Programme im Benutzermodus. Er bootet wirklich, in QEMU.

Überblick

frostbyte ist ein hobbyhaft entwickelter x86_64-Kernel, geschrieben in C und Assembler. Das Ziel war nicht, ein "Betriebssystem" im alltäglichen Sinn zu schreiben, sondern den ganzen Weg zu gehen, der normalerweise verborgen bleibt: vom Moment, in dem die Firmware die Kontrolle abgibt, bis zur Ausführung eines eigenen Programms im Benutzermodus, isoliert vom Kernel.

Es ist eine der gnadenlosesten Arten von Projekt, die man sich setzen kann. Es gibt hier keine Bibliotheken, die Ihnen irgendetwas abnehmen, und keine Schicht, die einen Fehler auffängt. Da ist eine nackte CPU, das Architekturhandbuch und Sie. Genau deshalb ist es eine so gute Schule.

In einem gewöhnlichen Programm ist ein Fehler lokal: eine Ausnahme fliegt, Sie bekommen einen Stacktrace, Sie korrigieren eine Zeile. Im Kernel gibt es keine dieser Bequemlichkeiten. Ein falsches Bit in einer Seitentabelle, und die Maschine setzt sich einfach zurück - keine Meldung, kein Log, nichts. Das Debuggen wird zum Lesen von Registern und zum Raten, welcher Ihrer letzten drei Züge der tödliche war.

Diese Härte erzwingt eine andere Arbeitsweise. Jeder Schritt muss einzeln abgeschlossen und isoliert geprüft werden, bevor der nächste hinzukommt, denn sonst lässt sich nicht unterscheiden, welche von zehn Änderungen die ganze Maschine zum Absturz gebracht hat. Disziplin ist hier keine Tugend, sondern die Bedingung, überhaupt vorwärts zu kommen.

Von der Firmware zu Ring 3

Der ganze Weg ist eine Folge von Übergängen zwischen immer höheren Kontrollebenen. Die Firmware lädt den Kernel über Multiboot2 und übergibt eine Speicherkarte. Dann muss der 64-Bit-Modus aktiviert werden, was zuvor ein anfängliches Paging erfordert. Anschließend übernimmt der Kernel den virtuellen Speicher auf eigenen Seitentabellen, startet einen Scheduler, der Aufgaben per Timer-Interrupt umschaltet, und springt erst am Ende zu Ring 3.

1
Boot über Multiboot2

der Bootloader lädt den Kernel und übergibt eine Speicherkarte.

2
Wechsel in den 64-Bit-Modus

das Aktivieren des Long Mode erfordert zuvor ein anfängliches Paging.

3
Eigene Seitentabellen

der Kernel übernimmt die Verwaltung des virtuellen Speichers.

4
Ein präemptiver Scheduler

ein Timer-Interrupt schaltet Aufgaben um, ohne deren Zustimmung.

5
Ring 3

ein Sprung in den Benutzermodus und das Ausführen des ersten eigenen Programms.

Der Weg vom Einschalten zum eigenen Programm

EtappeWas geschiehtModus
Multiboot2die Firmware gibt die Kontrolle ab, eine Speicherkarte existiertring 0
Long ModeEintritt in den 64-Bit-Modusring 0
Seitentabellender Kernel übernimmt den virtuellen Speicherring 0
Schedulerder Timer schaltet Aufgaben ohne Zustimmung umring 0
Ring 3das erste Programm, vom Kernel abgeschnittenring 3

Debuggen, wenn die Maschine einfach verschwindet

Da ein Fehler keine Spur hinterlässt, brauchten wir eine Möglichkeit, wie der Kernel überhaupt etwas sagen kann, bevor er einen Bildschirmtreiber hat. Die Antwort ist QEMU mit Ausgabe auf den seriellen Port: Der Kernel schreibt Logs als Text auf die serielle Schnittstelle, und das geht direkt ins Terminal. So sehen Sie die letzte Zeile vor dem Reset statt eines schwarzen Bildschirms.

run.sh · bash
qemu-system-x86_64 \
  -cdrom frostbyte.iso \
  -m 512M \
  -serial stdio \
  -no-reboot -no-shutdown
!
Achtung

Im Kernelmodus gibt es kein "fast funktioniert". Ein Fehler in einer Speicherzuordnung bringt keine Funktion zum Absturz - er bringt die ganze Maschine zum Absturz. Deshalb wurde jeder Schritt einzeln im Emulator getestet, bevor der nächste hinzukam, und die Flags no-reboot und no-shutdown halten die Maschine bei einem Fehler eingefroren, statt sie in einer Neustartschleife verschwinden zu lassen.

Das Ergebnis: ein System, das wirklich bootet

Heraus kommt ein Kernel, der in QEMU tatsächlich bootet und bis zur Ausführung eines eigenen Programms in Ring 3 gelangt - er bleibt nicht beim Ausgeben von "hello" stehen, sondern geht den ganzen Weg bis zum Benutzermodus. Es ist ein Projekt, gebaut, um den Computer bis auf den Grund zu verstehen, und bis zu dem Punkt gebracht, an dem dieses Verständnis durch Laufen bewiesen ist, nicht durch eine Behauptung.

Weitere Projekte

Weitere Projekte aus derselben Kategorie - sehen Sie, wie wir ähnliche Herausforderungen angehen.

Haben Sie ein ähnliches Projekt?

Melden Sie sich - ein Angebot ist kostenlos und kommt innerhalb einer Stunde.