Aufgabe 7: Anwendung
Unser StuBS hat nun alle notwendigen grundlegenden Funktionen eines Betriebssystems.
Toll.
Was können wir nun damit machen?
Nun, Olaf Spinczyk, der StuBS mit aus der Taufe gehoben hat, hat mit seinem Text-mode basierten Pacmänchen schon scheinbar die Antwort gefunden: Spiele spielen. Und StuBS war Ausgangsbasis für viele weitere Spielesysteme: Michael Meier nutzte 2003 einen eigenen Zeichensatz, um ein schönes grafisches Puzzlespiel umzusetzen, dass er "Stupidgame" nannte. Über die Tastatursteuerung kann man einen Block mit einem seiner Nachbarn tauschen, und sobald drei gleiche Blöcke horizontal oder vertikal nebeneinander liegen, verschwinden diese und man bekommt Punkte. Die Pong-Implementierung von Daniel Brinkers ist bereits multiplayerfähig, es kann mittels Nullmodemkabel über Rechnergrenzen hinweg gespielt werden kann. Aber auch weitere Klassiker wurden in StuBS umgesetzt, wie der "Worms" getaufte Snakeklon von Bernd Schroebel. Ab 2009 wurde dann der grafische Modus mehr verwendet, so auch in Fractal Explorer, einer Visualisierung der Mandelbrotmenge vom späteren BS Übungsleiter Gabor Drescher sowie Demian Kellerman. Und gleich komplett mit Fenstermanager und Mausunterstützung hat Andreas Kaufmann ein Tetris entwickelt – inklusive Sound. 2013 war Flappy Bird eine der populärsten Apps auf mobilen Endgeräten, Felix Dreissig und Tilman Adler haben dies auch im selben Jahr für StuBS adaptiert. Aber statt ein Spiel selbst neu zu schreiben, kann man auch existierende Spiele auf StuBS portieren – wie Gabor Drescher mit einem kompletten NetHack Port demonstriert hat.
Damit hätten wir die Möglichkeiten geklärt – sie sind fast unbegrenzt. Bleibt die Frage: Wie anfangen?
Wir haben für euch einiges zusammen gepackt: Die Vorgabe von Aufgabe 7 kommt mit einem Pseudozufallszahlengenerator auf Basis eines Mersenne-Twisters. Außerdem hat es ein Minix Dateisystem, welches von Linux geklaut wurde, und euch die typischen Schnittstellen wie open
, read
& write
anbietet, inklusive Ordner versteht sich. Zudem könnt ihr einen Grafikmodus nutzen. Und um einfach schöne Sprites einbinden zu können, haben wir auch noch eine PNG Bibliothek für euch portiert.
Ein kleines Beispiel, genannt "Devils Cat" wird auch mitgeliefert: Während unser Lehrstuhllogo ein mit GIMP als C-Struktur exportierte Bitmap ist, sind die anderen Grafiken PNG Bilder, welche vom Dateisystem geladen werden. Die Katze besteht dabei aus einer Bilddatei mit mehreren Einzelbildern, es wird nur der gezeigte Ausschnitte immer wieder gewechselt. Der Dämon im Feuer zeigt die Transparenzeffekte. Das Feuer wird dynamisch generiert, es basiert auf einem relativ einfachen Algorithmus, welcher aus den benachbarten Pixeln den nächsten Farbpixel berechnet. Oben links ist ein PC zu sehen, der die Tastatureingaben anzeigt. Dafür haben wir auch verschiedene Pixelschriftarten aus Linux geklaut, in verschiedenen Formen und Größen, wie beim Titel zu sehen ist. Je nachdem welche der optionalen Aufgaben ihr so im Semester noch implementiert habt, könnt ihr auch einfach weitere Funktionalitäten nutzen, wie zum Beispiel den Maussupport. Oder rechts unten in der Ecke wird die Real Time Clock mit einer kleinen Analoguhr demonstriert.
Das einzige, was ihr programmieren müsst, ist eine dynamische Speicherverwaltung mit den Funktionen malloc()
und free()
. Sie kann wie in der Halde aus Systemprogrammierung (SP) auf einen vordefinierten Speicherbereich arbeiten, welcher beim Einsatz von vielen PNG Bildern schon eine ausreichende Größe von mehreren Megabytes brauchen kann, ich verwende dazu für die Demo beispielsweise 16 MB statisch allokierten Speicher.
Der Grafikmodus wird über die VESA BIOS Erweiterungen eingestellt, und das geht nur im Real Mode. Ein Absteigen vom 64 bit Long Mode über den 32 bit Protected Mode zu dem 16 bit Real Mode ist allerdings keineswegs schön, deshalb lassen wir das inzwischen dem Bootloader machen: In der config.inc Datei im Ordner boot/**multiboot** kann die gewünschte Auflösung und Farbtiefe eingestellt werden, der GRUB Bootloader wird dann versuchen diese auszuwählen.
Hierbei gibt es zwei Sachen zu Beachten: Zum einen hat Qemu keine vollständige Multibootimplementierung, weist uns in dem Fall aber auch darauf hin, das es die VESA Bios Extensions nicht versteht. Stattdessen müssen wir eine ISO bauen, welche den GRUB integriert und diese dann in Qemu booten. Zum anderen ist auch nicht garantiert, dass die gewünschte Auflösung wirklich unterstützt wird – GRUB kann sich für eine andere Auflösung entscheiden. Am besten ihr programmiert eure Anwendung etwas toleranter, und versucht Fehler abzufangen.
Auch wenn es der Lesbarkeit nicht unbedingt guttut, dies ist eines der sinnvollen Einsatzgebiete für C++ Templates: Da je nach verwendeter Farbtiefe und Anordnung der Farbbits unterschiedliche Zugriffe notwendig sind, kann der Übersetzer jeweils spezifischen Code generieren und entsprechende Optimierungen fahren, denn bei Grafikoperationen ist die Geschwindigkeit durchaus relevant. Wir haben hier also die ganzen Framebuffermethoden für die 5 häufigsten Videomodi bereits integriert.
Um eine saubere Bildausgabe zu ermöglichen, sollte am besten eine Doppelpufferung verwendet werden. Das bedeutet, das im Frontbuffer das Bild liegt, was gerade am Monitor angezeigt werden soll, während wir im Backbuffer bereits das nächste Bild aufmalen. Sobald wir damit fertig sind, wechseln wir es. Die Ausgabe des Frontbuffers kann zum Beispiel regelmäßig bei der Timerunterbrechung, also in der Watch
, geschehen.
Die einzelnen Elemente des Devils-Cat-Beispiels sind in der Vorgabe fein säuberlich aufgeteilt, die Animation der Katze ist nur wenige Zeilen lang und der Titel wird beispielsweise aus einer Textdatei gelesen und an eine fixe Position am Bildschirm geschrieben.
Aber wie kommen wir zum Dateisystem? Dieses wird als Abbild über die initiale Ramdisk geladen, ihr könnt also lesend und schreibend darauf zugreifen, aber die Änderungen werden nirgends gespeichert, gehen also verloren. Einen Zugriff auf die echte Festplatte wollen wir aus organisatorischen Gründen eher nicht. Da es zumindest im CIP aufgrund fehlender Berechtigungen gar nicht so einfach ist, ein Abbild mit Minix Dateisystem zu mounten, haben wir für euch ein Tool implementiert. Damit könnt ihr interaktiv ein Abbild bearbeiten, alternativ wird es im Makefile verwendet, um den Inhalt des initrd Ordners in das Abbild zu kopieren. Weitere – ausführlichere – Details findet ihr wie immer auf der Aufgabenwebseite.
Außerdem findet ihr dort in der Ruhmeshalle die eingangs gezeigten Beispiel, alle in eine ISO gepackt. Da insbesondere die älteren Beispiele zum Teil noch für 32 bit Systeme ohne Mehrkernbetrieb entwickelt wurden, und auch noch fehlerhafte APIC Implementierungen haben, kann es sein, dass die Qemu Parameter zum Start etwas variiert werden müssen. Das gilt auch für unsere Testkisten: Dort gibt es ebenfalls einen Bootloadereintrag Ruhmeshalle, aber auch hier funktionieren leider nicht mehr alle Werke.
Falls ihr irgendwann selbst etwas fertig gebaut habt: Sagt uns Bescheid! Wenn es uns gefällt, dann werdet auch ihr in die Ruhmeshalle verewigt. Diese Aufgabe ist natürlich vollkommen freiwillig, und es gibt auch keine Zeitbegrenzung. Wenn ihr erst nächstes Jahr die Zeit habt – auch gut. Hauptsache ihr habt viel Spaß damit!
Auf dem Weg zu einem vollwertigen modernen Betriebssystem fehlen unserem StuBS noch Isolationsmechanismen. Sofern ihr Lust darauf habt, werden wir das in Betriebssystemtechnik im nächsten Sommersemester implementieren, direkt aufsetzend auf unser StuBS nach Aufgabe 6. Zuerst werden wir den privilegierten Ring 0 verlassen und die Anwendungen im Benutzermodus auf Ring 3 ausführen. Damit diese Benutzeranwendungen nun noch die von StuBS angebotenen Funktionen nutzen können, brauchen wir eine echte Systemaufrufschnittstelle. Und damit die Anwendungen sich nicht gegenseitig stören können, bekommen sie mittels Paging einen eigenen virtuellen Adressraum.
Schlussendlich lösen wir die Benutzeranwendungen gänzlich vom Kernel und lassen sie separat als eigene Einheiten übersetzen, übergeben sie über die initiale Ramdisk und starten sie über einen Lader im Betriebssystem. Sie bekommen anschließend durch Funktionen wie getpid
, fork
und map
Möglichkeiten zur Prozess- und Speicherverwaltung, was dann auch ein ordentliches malloc
und free
für unsere Anwendungen ermöglicht. Damit diese Benutzeranwendungen auch untereinander Interagieren können, wollen wir außerdem noch ein Verfahren zum Nachrichtenaustausch implementieren, eine sogenannte Interprozesskommunikation (IPC) ermöglichen. Und für bessere Performance werden wir dann noch unnötigen Kopieroperationen bei Fork und IPC durch Copy-On-Write ersetzen,
Im Gegensatz zu dieser Veranstaltung wird es dann für die einzelnen Aufgaben keine zusätzlichen Vorgaben mehr geben, das heißt ihr programmiert komplett frei, dürft also alle Schnittstellen selbst designen. Falls wir damit euer Interesse geweckt haben: Wir würden uns freuen euch nächstes Semester in BST wieder zu sehen!