Mach 30: Die Programmierung des MC68030, Teil 3

Zu den interessantesten, aber auch am schwersten zu beherrschenden Neuerungen des MC68030 gehört die MMII (»Memory Management Unit«). Sie ermöglicht virtuellen Speicher und brauchbare Speicherschutzmechanismen, wie sie bisher nur Workstations oder Mainframes Vorbehalten waren.

Da kommen die Pioniere der ersten Stunde der ST-Linie bereits ins Rentenalter - mindestens aber in ihre erste Midlifecrisis, während Töchter und Söhne nach einem Rechner schreien, der mit Hilfe einer programmierbaren MMU (»memory management unit») endlich virtuellen Speicher unterstützt und einen brauchbaren Speicherschutzmechanismus bietet. Haben sie ihre Kinder trotz des aufmüpfigen, DOS-pubertären Alters bei den Atari-Rechnern halten können, verweisen sie auf die integrierte MMU des MC68030 beim TT. Doch wozu dient die MMU, bislang ging's doch ganz gut ohne sie?

MMU als Ordnungshüter

Multitasking-Betriebssysteme, wie das von Atari angekündigte »MultiTOS«, deren Vorteile in der parallelen Abarbeitung mehrerer Prozesse liegen, verlangen nach neuen Schutzmechanismen der einzelnen Tasks. Befindet sich nämlich unter den aktiven Prozessen ein fehlerhaftes Programm, droht nicht mehr nur dieser Task abzustürzen, sondern das komplette System - mit all seinen laufenden Prozessen. Durch einen MMU-Begleitschutz lassen sich Speichermanipulationsangriffe eines fremden Prozesses wirkungsvoll aus dem Weg räumen.

Bild 1. Alle Register der MMU im Überblick. Novum für den 68030er: die ersten 64-Bit-Register CRP und SRP

Versucht ein Programm, sich unerlaubter Weise in einen anderen Prozeß einzumischen, setzt der »Scheduler« (zuständig für die Prozeßverwaltung) den Unbefugten auf die Strafbank in eine Warteposition oder verweist ihn gleich des Feldes und bricht den Prozeß komplett ab.

Eine weitere wichtige Anwendung der MMU ist die virtuelle Speicherverwaltung. Diese täuscht dem Betriebssystem eine größere RAM-Ausstattung vor. Dazu lagert die Speicherverwaltung nicht benötigte RAM-Bereiche vorübergehend auf Festplatte aus und stellt die freien Plätze dem System wieder zur Verfügung, jetzt aber mit einer höheren, weiter fortlaufenden Adresse.

Dreh- und Angelpunkt für diese Vorgehensweise ist ein Mechanismus, der physikalischen Speicherbereichen beliebige Adressen zuweisen kann. Man spricht auch von logischen oder relativen und physikalischen Adressen. Dazu der genauere Ablauf eines Speicherzugriffes: Der Prozessor bezieht sich bei all seinen Speicheranforderungen auf relative Adressen. In einer Tabelle führt die MMU eine Übersetzungsliste (»Address Translation Table«) mit den korrespondierenden absoluten Adressen. Wenn nun eine relative Adresse physikalisch nicht existiert, löst der Prozessor einen Busfehler-Interrupt aus. Die Interrupt-Service-Routine speichert dann einen im Moment nicht benötigten RAM-Bereich auf Festplatte und modifiziert die Adressübersetzungstabelle derart, daß die relative Adresse auf den eben gesicherten physikalischen RAM-Bereich zeigt.

Bild 2. Die drei wichtigsten Register der MMU sind das Translation Control (TC) Register und die beiden Translation Table Root Pointer CRP und SRP

Die CPU spricht den auf einer Festplatte reservierten Platz wie gewöhnliches RAM an. Dazu läßt man den Prozessor und das System nur im Glauben, es stehe wesentlich mehr RAM zur Verfügung, als physikalisch vorhanden ist.

Die letzte Aufgabe der MMU besteht darin, dem prozessorinternen und eventuell vorhandenen externen Caches [1] mitzuteilen, welche Speicherbereiche in den Cache gelangen dürfen und welche von diesem fernzuhalten sind. Hardware-Adressen, die sich ohne Zutun des Prozessors ändern, würden im Cache nur für Verwirrung sorgen.

Deshalb sind Bereiche der Hardware-Adressen ausgeblendet. Dazu führt die Adressübersetzungstabelle zu jedem Eintrag noch weitere Flags, die man als verschiedene Attribute der RAM-Bereiche interpretiert. Die MMU kennt gleich mehrere dieser Attribute, wie zum Beispiel Schreibschutz, Zugriffsberechtigung nur im Supervisor-Modus, Zugriff auf Speicherbereiche seit der Erstellung der Übersetzungstabelle und Test auf deren Änderung. Gerade die letzten beiden Attribute erleichtern dem virtuellen Speichermanager die Entscheidung erheblich, welche Speicherbereiche der Prozessor selten benötigt und somit bevorzugt auf Festplatte auszulagern sind. Wenn ein Speicherbereich nicht modifiziert wurde, kann sich der Treiber ein nochmaliges Sichern auf Festplatte sogar sparen.

MMU - die Vermittlungsstelle

Die MMU steht also genau zwischen dem Prozessor und dem RAM-Speicher. Sie entscheidet, welche Speicherzelle bei einem Zugriff der CPU gemeint ist, ob der Prozessor in diesem Moment zugriffsberechtigt ist (Schreibschutz, Supervisor-Modus, ...) und ob diese Speicherzelle dann auch in den Cache darf.

Da die Zeit für die Adressübersetzung der MMU natürlich dem Prozessor hinterher fehlt, empfiehlt sich eine besonders einfache wie schnelle Methode. Dazu teilt man den Speicher in gleich große Blöcke, die sich Speicherseiten nennen (»memory page«), und ordnet nur noch jeder Page einen Eintrag in der Übersetzungstabelle zu. Die Page-Größe läßt sich im Falle der MMU des 68030 in Zweierpotenzschritten von 256 Byte bis 32 KByte über das »Translation Control«-Register (TC, Bild 1 und 2) einstellen. Da je nach Speicherseitengröße die Tabelle anders aussieht, muß diese Einstellung vor dem Anlegen der Tabelle bereits feststehen, sie wird also noch während des Bootens vom Betriebssystem des Rechners erstellt. Das TT-TOS benutzt hier ungewöhnlich große Speicherseiten (32 KByte), doch müßte man einigen Aufwand treiben, diese Größe nachträglich zu ändern.

Bild 3. Mit den beiden Transparent Translation Registern lassen sich mehrere 16-MByte-Bereiche von der Adressübersetzung ausblenden
Bild 4. Vernachlässigt man die Function Codes, läuft die Adressübersetzung nach obigem Muster ab
Bild 5. Jeder Deskriptor-Eintrag zeigt entweder auf eine weitere Deskriptor-Tabelle oder aber auf den Beginn einer Speicherseite

Die Benutzung von Speicherseiten schränkt jedoch die freie Adressverteilung etwas ein. Die niederwertigen Adressbits, die die genaue Position innerhalb einer Page bestimmen, lassen sich nicht mehr ändern. Man kann also nur noch ganze Speicherseiten untereinander vertauschen, aber nicht mehr jedem beliebigen Byte eine neue Adresse zuweisen. Die Berechnung von logischer zu physikalischer Adresse läuft dabei wie folgt ab: Die MMU teilt die logische Adresse durch die Page-Größe und benutzt diesen Wert als Index, um den korrespondierenden Tabelleneintrag (»Descriptor«) in der Übersetzungstabelle zu bestimmen. Dieser Deskriptor enthält dann in den oberen Bits die neue Adresse. Zu dieser Adresse zählt die MMU den Rest der Division wieder hinzu und schon steht die physikalische Adresse fest. Jeder Eintrag der Übersetzungstabelle enthält also einen Zeiger auf die Speicherseite. Diese speziellen Einträge heißen auch Seitendeskriptoren (»Page Descriptor«).

Die unteren Bits der Einträge in der Übersetzungstabelle, die die Seiten umspannen (15 Bits für 32 KByte Pages), sind also für die Adressberechnung bedeutungslos. Durch die vorgegebene Mindestseitengröße von 256 Byte pro Seite sind auf jeden Fall die unteren 8 Bit frei. In diesen stehen die Seitenattribute.

Kapriolen

Eigentlich könnte das schon die ganze Arbeit der MMU gewesen sein, hätte Motorola durch Einführung mehrerer Ebenen von Deskriptortabellen sich und allen anderen das Leben nicht unnötig schwer gemacht. Doch Jammern hilft auch nicht weiter, kämpfen wir uns also durch das Gestrüpp der bis zu fünf Deskriptorebenen.

Die Bezeichnung Gestrüpp trifft die Situation schon recht gut, bilden doch die verschiedenen Ebenen eine Baumstruktur mit den genannten »fünf« Verschachtelungstiefen. In der untersten Ebene, den Blättern also, stehen dann die bereits ausführlich beschriebenen Seitendeskriptoren. Doch zuerst hangelt sich die MMU durch vier Tabellendeskriptoren (»Table Descriptors«) zu den Blättern vor. Mit dem TC-Register teilt man die logische Adresse in maximal sechs Bitfelder (IS, TIA, TIB, TIC, TID und PS) auf. »IS« enthält die Anzahl der höchstwertigen Bits, die die MMU ignoriert, weil man wohl selten 4 GByte Adressraum benötigt. Mit »TIA«, »TIB«, »TIC« und »TID« unterteilt man die Adresse, beim höchstwertigen Bit beginnend, in bis zu vier Bereiche. Ist eines dieser Felder Null, müssen auch alle nachfolgenden Felder Nullen enthalten. In diesem Fall reduziertsich dann die Anzahl der Tabellenebenen. »PS« schließlich bestimmt die Seitengröße, jetzt aber in Bit (8 für eine 256-Byte-Seite).

Mit TIA beginnend stellt jetzt jedes Bitfeld die Nummer des Deskriptoreintrags dar, wobei dieser Deskriptor dann auf die Tabelle der zweiten Ebene zeigt. Aus der zweiten Tabelle nimmt man dann das Element der Nummer aus dem zweiten Bitfeld usw. Bild 4 zeigt die genaue Vorgehensweise und Bild 5 die Deskriptortabellen der verschiedenen Ebenen. Für nachträgliche Änderungen kommt erschwerend hinzu, daß mehrere Tabellendeskriptoren auf ein und dieselbe Tabelle einer tieferen Ebene zeigen können. Mit dem Limit-Feld der Tabellendeskriptoren (Bild 7) begrenzt man zusätzlich die Anzahl der Einträge der nächsten Ebene. Es dürfen also Speichersegmente nach oben hin begrenzt sein. Doch nicht nur nach oben. Da Motorola an wirklich alles gedacht hat, läßt sich über das L/U-Bit der Deskriptoren die nächste Tabellenebene auch als absteigende Liste von Deskriptoren definieren. In diesem Fall enthält das Limit-Feld dann den kleinsten erlaubten Wert eines Bitfeldes. Dadurch ließe sich ein dynamisch größer werdender Stack realisieren, der ja bekanntlich nach unten hin wächst. Das ist für den Atari jedoch unbedeutend; da jedes Programm selbst für genügend Stack sorgen muß, bliebe also für eine derartige Behandlung nur noch der Systemstack übrig.

Bild 6. Je nach Level der Translation-Tabelle dürfen die Deskriptoren verschiedene Formate besitzen

Die Position der ersten Tabelle erfährt die MMU von einem der beiden Tabellen wurzelzeigern (»Translation table root pointer»), dem CRP-(»CPU Root Pointer«) oder dem SRP-Register (»Super Root Pointer«). Setzt man das SRE-Bit des TC-Registers, unterscheidet die MMU zwischen Zugriffen im User- und im Supervisor-Modus und beginnt mit dem CRP-bzw. SRP-Register, andernfalls beginnt sie immer mit dem CRP-Register. In zweien der 64 Bits des Wurzelzeigers (DT-Bits) legt man darüber hinaus fest, ob die Tabelleneinträge im langen oder kurzen Format vorliegen.

Eine weitere Besonderheit tritt ein, wenn das FCL-Bit des TC-Registers gesetzt ist. Hier ist nicht TIA der Index der ersten Tabellenebene, sondern der »Function Code« [2]. Die erste Tabelle hat dann entsprechend der Kombinationen der drei Function Code Bits immer acht Einträge. Danach geht's wie gewohnt weiter.

Um der Geschichte mit den Ebenen noch halbwegs einen Sinn zu geben, unterstützt die MMU drei weitere Deskriptortypen: den ungültigen (»invalid«), den indirekten (»indirect«) und den Abbruchdeskriptor (»Early Termination Deskriptor«), Stößt die MMU auf einen ungültigen Deskriptor, löst sie einen Busfehler aus. Bei virtuellem Speicher bedeutet das, daß dieser Bereich auf Festplatte ausgelagert wurde. Die Busfehlerroutine weiß dann hoffentlich, was zu tun ist. Indirekte Deskriptoren sind nur in der untersten Ebene erlaubt. Sie zeigen dann auf einen weiteren Deskriptor und nicht wie erwartet auf eine Speicherseite. Extrem geschmeidig sind die Abbruchdeskriptoren. Hier bricht die MMU ab und addiert zur Adresse des Deskriptors die verbliebenen (noch nicht ausgewerteten) Bits der logischen Adresse. Somit lassen sich verschiedene RAM-Bereiche verschieden grob segmentieren und nebenbei fallen so die Ubersetzungstabellen kleiner aus.

Bild 7. Je nach Level der Translation-Tabelle dürfen die Deskriptoren verschiedene Formate besitzen (s. Seite 78)

Der kleine Unterschied: logisch - physikalisch

Steht nun endlich der komplette MMU-Baum, ist immer noch nicht gewiß, ob denn alles so klappt wie gedacht, denn über die beiden Transparent Translation Register TTO und TT1 (Bild 3) lassen sich mehrere Speicherbereiche von der Adress Übersetzung ausblenden. Für diese Bereiche gilt: logisch gleich physikalisch.

Um externe Speicherzugriffe des Prozessors wie der MMU auf ein Minimum zu reduzieren, besitzt der Prozessor die in [2] vorgestellten Daten- und Befehls-Caches und die MMU einen zusätzlichen »Address Translation Cache« (ATC). Dieser enthält die 24 zuletzt verwendeten Tabelleneinträge. Dieser Cache ist recht einfach gehalten, so merkt er zum Beispiel nicht, wenn man Einträge der Übersetzungstabelle ändert. Um die Verwirrung zu komplettieren, sei erwähnt, daß ein neuer Tabelleneintrag dafür aber in den Daten-Cache des Prozessors gelangt. Kurz und gut, eine entsprechende Meldung in Richtung MMU, die entsprechenden Tabelleneinträge gefälligst im Cache zu löschen, ist unumgänglich, womit wir bei den MMU-Befehlen sind (Bild 8). Dabei versteht es sich von selbst, daß derart schwerwiegende Eingriffe in das System, wie man es mit MMU-Befehlen tut, nur im Supervisor-Modus erlaubt sind. Über bescheidene vier Befehle erreichen wir die MMU. »PFLUSH« löst das eben angesprochene Problem der Cacheverwaltung. Dieser Befehl löscht wahlweise den ganzen Cache oder aber nur die Deskriptoren, die die MMU zur Berechnung einer anzugebenden Addresse hernimmt.

Die Befehle »PTEST« und »PLOAD« dienen mehr oder weniger zum Testen der Integrität der Deskriptortabellen. Sie simulieren Lese- bzw. Schreibzugriffe. Der PLOAD-Befehl lädt dabei die benötigten Deskriptoren in den Cache und paßt sie gegebenenfalls an (Memory page used or modified), während »PTEST« nicht einmal das macht, sondern eine Addresse lediglich bis zu einem bestimmten Tabellenlevel übersetzt und entsprechend das MMUSR-Register setzt. Mit »PMOVE« erreichen wir schließlich alle MMU-Register. Da die Register CRP und SRP 64 Bit lang sind, begrenzen sich die erlaubten Adressierungsarten auf jene mit Speicheradressangaben. (ah)

Literaturhinweise:

[1] Jürgen Lietzow: »Mach 30 - Teil 2«, S.68ff.. TOS-Magazin 9/92, ICP-Verlag

[21 Jürgen Lietzow: »Mach 30 - Teil 1«, S.88ff., TOS-Magazin 8/92, ICP-Verlag

[3] Steve Williams: »68030 Assembly Language Reverence«, Addison-Wesley, 1. Auflage vom August 1989, S. 537 ff.

Bild 8. Zur weiteren Steuerung gibt es nur vier MMU-Befehle. Diese Befehle setzen dann das MMUSR (MMU-Statusregister).

Kursübersicht

Teil 1: Adressierungsarten, Stack-Aufbau, neue Befehle und Register
Teil 2: Cache-Register und -Verwaltung
Teil 3: Die integrierte MMU des 68030
Teil 4: Der Coprozessor 68881/68882


Jürgen Lietzow
Aus: TOS 10 / 1992, Seite 74

Links

Copyright-Bestimmungen: siehe Über diese Seite