Die Implementierung der MMU im OS9 Level 2 ist eine katastrophale Bastelei.
Der Code wird direkt im Kernal Sourcecode gepatched.
Keine Auslagerung in ein Modul oder Treiber.
Nicht mal eine Auslagerung in Include Dateien.
Die haben wohl für jede unterschiedliche Hardware einen eigenen Kernal entwickelt!
Im NitrOS9 gibt es eigentlich nur noch zwei Ziel Plattformen:
Beide Plattformen eignen sich leider nicht gut als Basis für meine SBC-MMU Hardware.
Aber es gibt ein wunderschöne, uralte Hardware, die fast ident ist zu meiner SBC-MMU Hardware.
Und es gibt eine OS9 Implementierung für diese Plattform ...
Der Positron 9000 ist eine sensationelle Maschine!
Das Ding ist einfach unglaublich!
Nun habe ich mich mit dem Positron 9000 Kernal intensiv auseinander gesetzt.
Das hat meine verklärte Sicht auf die Motorola MMU 6829 etwas erschüttert.
Die schöne Welt, die im "OS9 L2 System Designer Guide" beschrieben wird, die hat auch Schattenseiten:
Die MMU 6829 bietet "System Schutz" und echte 64K für jeden Task (protected Mode).
Dafür zahlt man jedoch einen sehr hohen Preis!!
Jeder Usertask hat seine eigenen 64K vollständig zur Verfügung.
Der Code läuft in einer Sandbox die absolut sicher ist.
Etwas das sonst nur viel neuere Systeme bieten können.
Das funktioniert deswegen, weil die MMU 6829 erkennt, dass die CPU einen Interrupt oder SWI Befehl ausführt.
Die MMU wartet, bis die CPU alle Register Werte auf den Stack gelegt hat.
Genau zu diesem Zeitpunkt schaltet die MMU in die System Map und aktiviert den Superuser Modus.
Die CPU fetched nun den entsprechenden System Vektor (in der System MAP!!) und springt zu dem System Code.
Soweit so gut, klingt alles wunderschön.
Doch nun fangen die Probleme an.
Leider wollte man OS9 L2 binär kompatibel mit L1 machen, damit alte Programme einfach so laufen können.
OS9 System Funktionen ruft man mit einem SWI Befehl auf.
Dem SWI Befehl folgt der Funktionscode.
Für L1 ist das keine große Sache.
Die Systemfunktion holt sich den PC (program counter) und liest das Byte nach dem SWI Befehl (Funktionscode).
Dann die der PC am Stack inkrementiert, damit nach der Rückkehr aus der Systemfunktion der folgende Befehl ausgeführt wird.
Der Funktionscode wird als "übersprungen".
Für L2 ist das selbe eine Schwerarbeit:
- um den Inhalt des PC vor dem Aufruf zu kriegen, muss man den User Stack zugreifen
- der Userstack liegt in der User Map, und man weiß ja nur die logische Stack Adresse in der User Map
- also logische Adresse in der User Map umrechnen in Page Nummer und Page Adresse
- die Page temporär in der System Map einblenden und den Wert des PC auslesen
- der PC Wert um eins inkrementieren
- nun ist auch der Wert des PC nur eine logische Adresse ...
- also logische Adresse in der User Map umrechnen in Page Nummer und Page Adresse
- die Page temporär in der System Map einblenden und den Wert des PC auslesen (Funktionscode)
Alles in allem recht komplexer Code, einige hundert Befehle ...
Die erzwungene L2 Kompatibilität ist sehr, sehr teuer!
Im Falle eines Interrupt ist der L2 Mehraufwand nicht so schlimm.
Aber natürlich sind praktisch alle Adressen 24 Bit lang statt nur 16 Bit.
Und man muss ggf. eine Page einblenden um Modulcode ausführen zu können.
Zugriffe in User Buffer Bereiche sind auch viel komplexer.
Es müssen immer entsprechende Mappings gemacht werden und die neuen Offset Adressen errechnet werden.
Fazit:
Die Kosten für die Sprengung der 64K Begrenzung sind hoch.
L2 läuft definitiv um einiges langsamer als L1.
Aber es ist die Sache schon wert.
Speziell dann, wenn man Multi User Betrieb anbietet wie die Positron 9000 Maschine.
Die Stabilität ist halt dadurch wirklich extrem gut.
Keine Seiteneffekte durch andere Software.
Kaum noch Begrenzungen durch Speicher und andere Ressourcen.