x86-Programmierung und -Betriebsarten (Teil 5)

12.02.2004 von Hans-Peter Messmer und Klaus Dembowski
Die sechsteilige Artikelserie behandelt die Speicheradressierung und die x86-Betriebsarten. Im fünften Teil der Serie beschäftigen wir uns ausführlich mit dem Paging.

Eine wesentliche Erweiterung der 32-Bit-CPUs gegenüber dem 80286 neben der 32-Bit-Architektur war die Integration einer Paging-Unit in der Speicherverwaltungseinheit. Was es mit Paging auf sich hat und welche neuen Möglichkeiten sich damit auftun, erfahren Sie in den nächsten Abschnitten.

Serie: x86-Programmierung und -Betriebsarten

Teil 1

Code-/Datensegment, Befehlszähler und Stack

Teil 2

Adressierungsarten und Befehlsdekodierung sowie Real Mode

Teil 3

Interrupts und Exceptions

Teil 4

Der Protected Mode

Teil 5

Paging

Teil 6

Der Virtual-8086-Modus

Die Artikelserie basiert auf dem Kapitel 6 des "PC Hardwarebuch" von Addison-Wesley. In unserem Buch-Shop können Sie das über 1200 Seiten starke Kompendium bestellen oder als eBook downloaden.

Logische, lineare, physikalische Adressen und Paging

Durch die 32-Bit-Offset-Register und die 16-Bit-Segmentregister besitzt bereits der 80386 einen logischen Adressraum von 64 TByte je Task. Da die Basisadresse in den Segmentdeskriptoren 32 Bits breit ist, werden diese 64 TByte auf einen Adressraum mit einer Größe von maximal 4 GByte abgebildet. Die Kombination von Basisadresse eines Segments und Offsets innerhalb des Segments im Adressaddierer führt zu einer so genannten linearen Adresse. Dies bedeutet, dass die Adresse die Stelle eines Speicherobjekts in linearer Weise angibt, bei einer größeren Adresse finden Sie das Speicherobjekt auch weiter oben im Speicher.

Die Segmentnummer, das heißt der Segmentselektor, sagt dagegen hierüber nichts aus. Ein größerer Selektor kann ohne Weiteres auf ein Segment weit unten im Speicher zeigen. Die Abbildung der 64 TByte auf die 4 GByte ist möglich, da nicht alle Segmente der 64 TByte auch tatsächlich vorhanden sein müssen (P-Bit der Segmentdeskriptoren). Der Rest kann beispielsweise auf die Festplatte ausgelagert sein.

Werden alle 32 Adressleitungen benutzt, so kann diese lineare 32-Bit-Adresse in eine physikalische Adresse umgesetzt werden, die ebenfalls 32 Bits umfasst. Jeder Adresse im logischen Adressraum von 4 GByte entspricht dann ein Speicherobjekt in einem der Speicherchips.

Probleme der Segmentierung

Eine Möglichkeit, den virtuellen Adressraum größer als den tatsächlich vorhandenen physikalischen Speicher zu machen, haben wir bereits beim Protected Mode und den damit verbundenen Segmentdeskriptoren kennen gelernt. In den Segmentdeskriptoren ist ein Bit P (Present) vorhanden, das angibt, ob sich das Segment auch tatsächlich im Speicher befindet. Versucht der Prozessor ein Segment anzusprechen, dessen P-Bit gelöscht ist - das heißt es befindet sich nicht im Speicher - so wird die Exception "Segment nicht vorhanden" ausgelöst. Das Betriebssystem kann das fragliche Segment nun in den Speicher laden und dem Befehl erneut die Chance geben, auf das Segment zuzugreifen. Damit ist es möglich, für ein Programm mehr Segmente zu erzeugen als auf einmal in den Speicher passen. Die ausgelagerten Segmente werden bei Bedarf einfach eingelesen. Ist im Speicher nicht mehr genügend Platz vorhanden, so müssen ein oder mehrere andere Segmente ausgelagert werden, um Raum für das neu eingelesene zu schaffen.

Damit beginnen aber nun schon die Probleme. Die Daten können nur segmentweise ausgelagert und eingelesen werden und zudem stimmt die Größe der Segmente mit der Größe der Datenstrukturen überein, die sie enthalten. Das Datensegment für eine umfangreiche Zeichnung oder das Codesegment für ein leistungsstarkes Programmmodul können sehr groß sein. Demgegenüber ist ein Datensegment, das nur eine Anredefloskel für einen Brief enthält oder ein Codesegment, das eine einfache Prozedur speichert, meist sehr klein. Soll nun ein großes Segment von Festplatte in den Speicher geladen werden, ist möglicherweise eine Vielzahl kleinerer Segmente auszulagern. Besonders ärgerlich wird die ganze Angelegenheit, wenn in dem eingelesenen Segment nur ein einziges Byte oder Wort angesprochen werden muss, aber anschließend sofort ein Zugriff auf den Code oder die Daten in einem der ausgelagerten Segmente erfolgen soll: das Segment also erneut auslagern, das Codesegment einlesen. Benötigt das Programm nochmals Daten vom jetzt erneut ausgelagerten Datensegment, nochmals alles von vorne - und so weiter.

Ein weiteres Problem tritt bei sparsamem Speicherausbau auf: Für das Datenbanksegment bleibt vom physikalischen Hauptspeicher nur der Platz, den Betriebssystem, Treiber, Systemtabellen und wenigstens ein Codesegment des aktuellen Programms übriggelassen haben. Ist das ausgelagerte Segment nun größer als dieser restliche Speicher, so kann es nicht eingelesen werden. Stehen beispielsweise maximal 990 KByte zur Verfügung, besitzt das Datenbanksegment aber eine Größe von 1 MByte, so kann das Segment nicht eingelesen und das Programm damit nicht ausgeführt werden.

Das Betriebssystem muss daher eine ganz ordentliche Menge an Arbeit leisten: ermitteln, welches Segment denn am besten ausgelagert wird, ob der jetzt freie Speicher ausreicht, gegebenenfalls ein weiteres Segment auslagern et cetera. Entsprechend zäh kann der Swap-Vorgang ablaufen, was Sie unter Windows an der unentwegten Beschäftigung der Festplatte vernehmen können. Es gibt aber eine bessere Möglichkeit: Paging.

Da sich alle Segmente im vorhandenen physikalischen Speicher befinden müssen, der kleiner als 4 GByte ist, liegen auch die Basisadressen aller Segmente bisher innerhalb des Adressbereichs des physikalischen Speichers. Bei einem älteren PC-System mit einem Hauptspeicher von beispielsweise nur 4 MByte sind damit alle Basisadressen kleiner als 4 MByte, das heißt der gesamte lineare Adressbereich von 4M bis 4G wird nicht benutzt. Mit anderen Worten - zirka 99,9 Prozent des linearen Adressbereichs sind ungenutzt. Eine Menge Speicher für viele, viele Segmente!

Das Paging-Prinzip

Beim Paging wird ein sehr großer virtueller Adressraum auf einen viel kleineren physikalischen Adressraum des Hauptspeichers sowie den großen Adressraum eines externen Massenspeichers (im Allgemeinen eine Festplatte) abgebildet. Diese Abbildung erfolgt in "Portionen" fester Größe, die eben als Pages (Seiten) bezeichnet werden. Ab dem 80386 ist eine Page-Größe von 4 KByte festgelegt. Diese Größe ist durch Prozessor-Hardware definiert und kann nicht verändert werden. Der gesamte virtuelle Adressraum beim 80386 besteht also aus einer Million Pages. Meistens sind natürlich bei weitem nicht alle auch tatsächlich von Daten belegt. Die von Daten belegten Pages befinden sich entweder im Speicher oder sind auf die Festplatte ausgelagert.

Ob der Prozessor diese Paging-Mechanismen tatsächlich benutzt, wird durch das PG-Bit des CR0-Registers bestimmt. Ist PG gesetzt, so findet Paging statt, ansonsten nicht. Da das Betriebssystem die Pages verwalten und gegebenenfalls auslagern oder einlesen muss, ist es mit dem gesetzten PG-Bit allein nicht getan. Die CPU-Hardware unterstützt Paging vielmehr in ähnlicher Weise wie die Protection- und Task-Switch-Mechanismen. Das Betriebssystem muss die Paging-Exceptions abfangen und entsprechend bedienen, die ausgelagerten Pages suchen und wieder einlesen et cetera.

Im Prozessor findet somit eine zweifache Adressenabbildung statt: Einmal werden Segment und Offset eines Speicherobjekts zu einer linearen Adresse im linearen Adressraum von 4 GByte entsprechend einer Million Pages kombiniert. Anschließend werden die eine Million Pages entsprechend der linearen Adresse in eine physikalische Adresse oder eine Exception "Page nicht vorhanden" zum Einlesen der betreffenden Page umgesetzt.

Page Directory, Page Tables und Page Frames

Für die Ermittlung einer linearen Adresse aus Segment und Offset muss bekannt sein, wo das betreffende Segment beginnt. Diese Information wird in den Deskriptortabellen abgelegt. Dabei gibt es zwei Ebenen solcher Tabellen: die globale Deskriptortabelle GDT bildet das "Stammverzeichnis", in dem die lokalen Deskriptortabellen LDT als "Unterverzeichnisse" auftreten können. Die Adresse der Deskriptortabellen wird im GDTR beziehungsweise LDTR abgelegt. Mit den darin abgelegten Informationen können Segment und Offset zu einer linearen 32-Bit-Adresse kombiniert werden, die in unveränderter Weise als physikalische Adresse verwendet wird. Wegen der besseren Übersichtlichkeit zum Beispiel ein älterer PC mit 4 MByte Hauptspeicher:

Das Segment beginnt bei 1b0000h, der Offset beträgt d23a0h. Damit lautet die lineare Adresse 2823a0h. Es wird damit das Byte mit der Nummer 2 630 560 beziehungsweise 0000 0000 0010 1000 0010 0011 1010 0000b adressiert. Da der Hauptspeicher nur auf 4 MByte ausgebaut ist, sind die zehn höchstwertigen Adressbits stets gleich 0, das heißt die Adresse lautet immer 0000 0000 00xx xxxx xxxx xxxx xxxx xxxx. An der Stelle der x steht eine Binärzahl von 0 bis 1.

In ähnlicher Weise wird auch die Abbildung von linearer auf physikalische Adresse durch ein zweistufiges Verzeichnis und ein Register, das das "Stammverzeichnis" angibt, implementiert.

Eine Tabelle definiert die Abbildung zwischen linearer und physikalischer Adresse. Hierzu ist aber eine andere Interpretation der linearen Adresse notwendig (siehe Bild "Umsetzung").

Bei aktivem Paging geben die zehn höchstwertigen Bits der linearen Adresse die Nummer der betreffenden Page Table im Page Directory an, die der aktuellen linearen Adresse entspricht. Die nächsten zehn Bits definieren die Nummer der Page in der festgelegten Page Table. Schließlich geben die zwölf niederwertigsten Bits in unveränderter Weise den Offset innerhalb der so definierten Page an. Sie reichen aus, weil eine Page ja nur 212=4096 Bits umfasst, für ein Segment ist dagegen ein 32-Bit-Offset notwendig. Damit wird eine lineare Adresse auf eine physikalische Adresse abgebildet, indem durch DIR eine Page Table, durch Page eine Page in dieser Page Table und schließlich durch Offset ein Offset innerhalb dieser Page angegeben wird (siehe Bild "Prinzip"). Nach Kombination von Segment und Offset zu einer linearen Adresse wird die so erhaltene lineare Adresse bei aktivem Paging in eine 10-Bit-Page Directory-Adresse, eine 10-Bit-Page-Adresse und einen 12-Bit-Offset aufgespaltet. Jede Page ist 4 KByte groß, sodass der gesamte Adressraum beim Paging in 4-KByte-Blöcke unterteilt wird.

Man könnte das auch folgendermaßen ausdrücken: Durch Paging werden die 20 höchstwertigen Adressbits auf neue Werte abgebildet, während die zwölf niederwertigsten Adressbits als Offset unverändert übernommen werden.

Page Table

Der Sinn zweier solcher Ebenen von Page Tables ist unschwer zu erkennen. Jeder Page-Table-Eintrag ist vier Byte lang (siehe Bild "Page Table"). Würde jede Page (zu 4 KByte) des linearen Adressraums von 4 GByte entsprechend einer Million Pages durch eine einzelne Page Table im Speicher abgebildet, so wären hierzu 4 MByte Speicher allein für die Page Tables notwendig. Die Bildung zweier Ebenen erlaubt es aber nun, die Page Tables niedrigerer Ebene wie Pages selbst zu verwalten, da sie wie eine "normale" Page 4 KByte groß sind. Die Page Tables zweiter Ebene können damit wie normale Pages ein- und ausgelagert werden. Nur das Page Directory mit 4 KByte muss also ständig im Speicher gehalten werden. Dessen Basisadresse wird im CR3-Register gespeichert.

Sowohl Page Directory als auch Page Table weisen jeweils 1024 (1k) Page Table-Einträge mit einer Länge von jeweils 4 Byte auf. Im Bild "Page Table" ist der Aufbau eines solchen Page-Table-Eintrags angegeben.

Das P-Bit (Page Present) gibt an, ob sich die betreffende Page auch tatsächlich im Speicher befindet (P=1) oder ausgelagert ist (P=0). In letzterem Fall enthalten die restlichen 31 Bit des Page-Table-Eintrags Informationen darüber, wo die Page auf der Festplatte oder einem anderen Massenspeicher zu finden ist. Die nachfolgend aufgeführten Einträge besitzen dann keine Bedeutung.

Page Frames

Befindet sich die Page im Speicher, das heißt ist P=1, so geben die 20 höchstwertigen Bit die Adresse des Page Frames an. Als Page Frame bezeichnet man in diesem Zusammenhang einen Speicherbereich in der Größe einer Page (4 KByte), der die Daten einer Page aufnimmt. Die Adressen solcher Page Frames sind stets ganzzahlige Vielfache von 4096 (1000h): 0, 4096, 8192, ... beziehungsweise 0000h, 1000h, 2000h, ... Sie können sich das ruhig bildlich als Page-Rahmen vorstellen: Wie man ein Blatt Papier (Page) mit Informationen in einen Rahmen einlegen kann, so "legt" der Paging-Mechanismus Pages mit verschiedenem Inhalt in die Page Frames ein. Die Rahmen bleiben gleich (und hängen sehr bildlich ausgedrückt an derselben Wand), die Information wird ausgetauscht.

Damit werden in der physikalischen 32-Bit-Adresse die 20 höher wertigen Adressbits vom Paging-Mechanismus durch diese 20 Bits der Page-Frame-Adresse ersetzt. Die zwölf niederwertigen Bits der physikalischen Adresse geben den Offset des Speicherobjekts innerhalb der Page an. Im Page-Table-Eintrag dienen die zwölf niederwertigen Bits dagegen zur Verwaltung der Page. Ist Paging aktiv, so fügt der Prozessor die 20 Bits der Page-Frame-Adresse und die zwölf Offsetbits der physikalischen Adresse zu einer physikalischen 32-Bit-Adresse zusammen. Ist die Page ausgelagert (P=0), so löst die CPU eine Exception "Page-Fehler" entsprechend Interrupt 0eh aus. Damit kann die Paging-Routine des Betriebssystems die erforderliche Page in einen freien Page-Frame laden.

Dieses über die Page-Fehler-Exception getriggerte Ein- und Auslagern von Pages funktioniert auch dann, wenn ein Speicherobjekt, wie zum Beispiel ein Doppelwort, nicht mehr vollständig in eine Page passt und auf zwei Pages verteilt ist.

Beispiel: ein Doppelwort (4 Bytes) mit Offset fffdh (dezimal 4094). Die zwei niederwertigen Bytes des Doppelworts sind in den zwei höchstwertigen Bytes der Page abgelegt. Die beiden höherwertigen Bytes des Doppelworts befinden sich aber bereits in einer anderen Page, die möglicherweise sogar ausgelagert ist.

Vorteile von Paging

Ein 32-Bit-Prozessor spricht den Speicher im Allgemeinen physikalisch stets an den Doppelwortadressen 0, 4, 8, ... an. Beginnt ein Doppelwort nicht an einer solchen Doppelwortgrenze, so führt der Prozessor zwei Speicherzugriffe aus, die jeweils an einer Doppelwortgrenze beginnen. Im oben angegebenen Beispiel werden damit zuerst die letzten vier Bytes der Page angesprochen, in denen sich die zwei höherwertigen Bytes des Doppelworts befinden. Anschließend greift der Prozessor auf die ersten vier Bytes der nächsten Page zu. Befindet sich diese Page nicht im Speicher, so wird sie nachgeladen. Damit kann der Prozessor auch die zwei niederwertigen Bytes des Doppelworts ansprechen.

Die Vorteile gegenüber einer Auslagerung von kompletten Segmenten bestehen darin, dass sich die kleinen Portionen zu 4 KByte schnell einlesen oder speichern lassen. Außerdem greifen Programme meist auf relativ eng beieinander liegende Daten zu. Damit ist trotz der relativ geringen Größe von 4 KByte gegenüber einem virtuellen Adressraum von 4 GByte, das heißt einem Faktor 1 Million, die Wahrscheinlichkeit groß, dass sich die Daten im Speicher befinden und nicht ausgelagert sind. Bei großen Segmenten müssen nur die Bruchstücke geladen sein, die gerade bearbeitet werden. Eine komplette Auslagerung und das sofortige erneute Einlesen, wie eingangs beschrieben, tritt damit bei Paging nicht auf - der Computer arbeitet dadurch schneller.

Man könnte nun meinen, dass die zusätzliche Adressenumsetzung beim Paging zusätzlich zur Bildung der linearen Adresse aus Segment und Offset zu Verzögerungen bei der Adressenberechnung führt. Das trifft in den meisten Fällen jedoch nicht zu, da bereits der 80386 einen Cache-Speicher aufweist, in dem die zuletzt benutzten Page-Table-Einträge gespeichert sind. Dieser Cache-Speicher wird als Translation Lookaside Buffer (TLB) bezeichnet. Nur wenn ein Page-Table-Eintrag benutzt werden soll, der sich noch nicht im TLB befindet und somit erst aus dem Speicher gelesen werden muss, verzögert sich die Adressenumsetzung durch den Speicherzugriff etwas. Ist die Page Table mit dem Eintrag allerdings auf Platte ausgelagert, dauert der Zugriff erheblich länger, da die Page Table erst in den Speicher und der Eintrag von diesem in den Prozessor gelesen werden muss. Durch intelligente Algorithmen für die Verwaltung von Page Tables und deren Einträgen durch das Betriebssystem ist dieser Fall aber glücklicherweise relativ selten und führt also nur zu sehr geringen Verzögerungen. Der Gewinn eines sehr großen virtuellen Adressraums gegenüber einem kleinen physikalischen Adressraum durch Paging ist überaus groß.

Für die Verwaltung der Pages und Page Tables der zweiten Ebene sind mehrere Bits in den Page-Table-Einträgen reserviert (siehe Bild "Page Table"). Hat der Prozessor einmal auf eine Page zugegriffen, das heißt Daten gelesen oder geschrieben, so wird das A-Bit (Accessed) im zugehörigen Page-Table-Eintrag gesetzt. Löscht das Betriebssystem in regelmäßigem Abstand diese A-Bits, so kann es erkennen, welche Pages häufig benutzt werden. Es lagert dann nur die weniger häufig benutzten Pages aus, um möglichst wenig Schreib- und Lesezugriffe der Festplatte zu verursachen. Damit läuft das Paging fast ohne Verzögerung ab.

Das D-Bit (Dirty-Bit) kennzeichnet Pages, deren Inhalt verändert - überschrieben - wurde. Ist das Bit gelöscht, so muss die Page beim Auslagern nicht auf die Festplatte geschrieben werden, da sich auf dieser ja noch die unveränderte alte Kopie befindet. Ist das D-Bit jedoch gesetzt, so erkennt das Betriebssystem eine Veränderung der Daten und schreibt neben den Informationen, die dazu dienen, die Page später wiederzufinden, auch die Daten der Page selbst auf Platte.

Schutzfunktionen

Ähnlich wie Segmente können auch Pages vor einem Zugriff durch Programme geschützt werden. Im Gegensatz zu den Segmenten, für die vier Privilegierungsebenen von 0 bis 3 zur Verfügung stehen, kennt der Schutzmechanismus für Paging derer nur zwei: User und Supervisor. Programme mit den Privilegierungsstufen CPL=0 bis CPL=2, das heißt Betriebssystem, Einheitentreiber und Betriebssystemerweiterungen, besitzen die Stufe Supervisor. Anwendungsprogramme dagegen die Stufe User. Die Privilegierungsstufe von Pages wird durch das U/S-Bit (User/ Supervisor) angegeben. U/S=0 gilt damit für Betriebssystem, System-Software et cetera (CPL=0, 1, 2), U/S=1 für Applikationscode und -daten (CPL=3).

Durch das R/W-Bit (Read/Write) werden Pages als nur-lesbar (R/W=0) oder als les- und überschreibbar (R/W=1) gekennzeichnet. Eine Verletzung, zum Beispiel ein Schreibzugriff auf eine nur-lesbare Page (R/W=0), führt zu einer Exception "Page-Fehler". Der Segmentierungsmechanismus schützt im Protected Mode die Daten dagegen auf einer Segmentbasis. Eine Verletzung der Paging-Schutzmechanismen, zum Beispiel durch einen Schreibzugriff auf eine nur-lesbare Page (R/ W=0) oder einen User-Zugriff auf eine Supervisor-Page, führt ebenfalls zur Exception "Page-Fehler" und damit zu einem Interrupt 0eh. Die drei Bits AVAIL stehen dem Betriebssystem für die Verwaltung der Pages zur Verfügung, alle anderen Bits sind reserviert.

Segmentierung und Paging bewirken damit eine zweifache Adressenumsetzung. Bei der Segmentierung wird anhand der Deskriptortabellen und Segmentdeskriptoren die Basisadresse des Segments bestimmt und durch Addition des Offsets eine lineare Adresse in einem großen virtuellen Adressraum gebildet. Paging setzt diese lineare Adresse in eine physikalische Adresse des sehr viel kleineren physikalischen Adressraums oder eine Exception "Page-Fehler" um. Dieser Vorgang ist im Bild "Doppelt" dargestellt. Durch die Segmentdeskriptor-Cache-Register und den Translation-Lookaside-Puffer erfolgt diese Umsetzung in den meisten Fällen ohne Zeitverzögerung.

Die Testregister TR6 und TR7

Weil die beiden Testregister TR6 und TR7 ausschließlich zum Prüfen des Translation Lookaside Buffer (TLB) implementiert sind, möchten wir sie zusammen mit dem TLB selbst an dieser Stelle erläutern.

Der TLB ist als 4-Wege-Set-Assoziativspeicher implementiert und verwendet eine Random-Ersetzungsstrategie für seine Einträge. Er ist einschließlich der Cache-Steuerung bereits vollständig auf dem 80386-Chip integriert und benötigt somit keinen externen SRAM-Speicher. Ähnlich wie bei anderen Cache-Speichern auch umfasst jeder Eintrag in den vier Sets 0 bis 3 ein 24-Bit-Tag und den eigentlichen 12-Bit-Cache-Wert. Jedes Set umfasst acht Einträge, der ganze TLB kann also 32 Einträge aufnehmen und ist insgesamt 144 Bytes groß. 32 Einträge für jeweils eine 4-KByte-Page bedeuten, dass 128 KByte Speicher vom TLB abgedeckt wird. Jedes Tag (zu 24 Bits) speichert die 20 höherwertigen Bits der linearen Adresse (also DIR- und Page-Anteil), ein Gültigkeitsbit und drei Attributbits. Der Dateneintrag enthält die 12 höherwertigen Bits der zugeordneten physikalischen Adresse.

Wenn bei einem Page-Table-Zugriff die physikalische Adresse des Page Frame bereits im TLB gespeichert ist, verwendet der Prozessor sie intern, um die physikalische 32-Bit-Adresse zu erzeugen. Ansonsten muss der Prozessor den Page-Table-Eintrag erst aus dem Speicher einlesen. Für den TLB gibt Intel beim 80386 eine 98-prozentige Trefferwahrscheinlichkeit an, das heißt 98 Prozent aller Speicherzugriffe auf Code und Daten referieren eine Page, deren Frame-Adresse vom TLB bereitgehalten wird. Zur Prüfung des Translation-Lookaside-Buffers sind die zwei Testregister TR6 und TR7 vorhanden. Sie werden als Test-Command-Register (TR6) und Testdatenregister (TR7) bezeichnet. Im Bild "Testregister" sehen Sie deren Struktur.

Die TLB-Prüfung unterteilt sich in zwei Vorgänge: Einträge in den TLB schreiben und TLB-Einträge lesen (TLB-Lookup ausführen). Die Einträge in den Testregistern haben dabei folgende Bedeutung.

Das Bit C im Test-Command-Register gibt an, ob ein Schreiben in den TLB (C=0) oder ein TLB-Lookup (C=1) ausgeführt werden soll.

Die lineare Adresse stellt das Tag-Feld des TLBs dar. Bei einem Schreiben in den TLB wird dieser linearen Adresse ein TLB-Eintrag zugeordnet, und dem so zugeordneten Eintrag wird der Inhalt von TR6 und TR7 übergeben. Bei einem TLB-Lookup prüft die Testlogik, ob diese lineare Adresse und die Attributbits mit genau einem TLB-Eintrag übereinstimmen. Ist das der Fall, werden die restlichen Felder von TR6 und das Testregister TR7 aus dem ermittelten Eintrag im TLB geladen.

Die Bedeutung von PL ist abhängig von C unterschiedlich. Wird ein Eintrag des TLBs geschrieben (C=0) und ist PL=1, dann legt REP den Assoziativblock des TLBs fest, der beschrieben wird. Ist PL in diesem Fall gelöscht (PL=0), so wählt ein interner Zeiger in der Paging Unit den zu schreibenden TLB-Block aus. Bei einem TLB-Lookup (C=1) gibt der Wert von PL an, ob der Lookup zu einem Treffer (PL=1) oder Fehltreffer (PL=0) geführt hat.

V ist das Gültigkeitsbit für den TLB-Eintrag. Ein gesetztes V-Bit gibt an, dass der Eintrag gültig, ein gelöschtes, dass der Eintrag ungültig ist. Die restlichen Bits des TR6-Registers entsprechen den Attributbits eines Page-Table-Eintrags. D, D stellen das Dirty-Bit, U, U das User/Supervisor-Bit und W, W das Schreibschutzbit für den entsprechenden TLB-Eintrag dar. Die drei Bits sind in normaler und komplementärer Form angegeben (siehe Tabelle). Man erhält dadurch bei Table-Lookups zum Beispiel die Möglichkeit, die Testlogik anzuweisen, den Wert der Bits für einen Lookup zu ignorieren (wenn beide gesetzt sind, findet die Logik immer eine Übereinstimmung). Sind nämlich sowohl das Attributbit als auch das dazu komplementäre gesetzt (=1), dann ermittelt die Logik für das entsprechende Attribut stets einen Treffer. Anders ausgedrückt ist der Attributwert in diesem Fall unerheblich.

Die Prüfung des TLBs erfolgt durch Schreiben und Lesen (TLB-Lookup) der Testregister TR6 und TR7. Um einen TLB-Eintrag für einen Test zu setzen, müssen Sie zunächst TR7 mit den Werten für die physikalische Adresse, PL=1 und REP laden. Anschließend müssen Sie TR6 mit geeigneten Werten für die lineare Adresse und die Attributbits schreiben und das Command-Bit C löschen. Um ein TLB-Lookup auszuführen (das heißt einen TLB-Eintrag zu lesen), laden Sie TR6 mit der entsprechenden linearen Adresse und setzen C. Anschließend lesen Sie die beiden Testregister TR6 und TR7. Das PL-Bit zeigt an, ob ein Treffer (PL=1) oder Fehltreffer (PL=0) erfolgt ist. Im ersten Fall spiegeln die Testregisterwerte den Inhalt des zugehörigen TLB-Eintrags wider. Bei einem Fehltreffer enthalten sie dagegen ungültige Werte.

Ausblick

Im letzten Teil der Artikelserie erfahren Sie, was es mit dem Virtual-8086-Modus auf sich hat, der mit dem 80386 eingeführt wurde.

Serie: x86-Programmierung und -Betriebsarten

Teil 1

Code-/Datensegment, Befehlszähler und Stack

Teil 2

Adressierungsarten und Befehlsdekodierung sowie Real Mode

Teil 3

Interrupts und Exceptions

Teil 4

Der Protected Mode

Teil 5

Paging

Teil 6

Der Virtual-8086-Modus

Diese Artikelserie basiert auf dem Kapitel 6 des "PC Hardwarebuch" von Addison- Wesley. Sie können in unserem Buch-Shop das über 1200 Seiten starke Kompendium bestellen oder als eBook downloaden.

tecCHANNEL Buch-Shop

Weitere Literatur zum Thema Hardware

Titelauswahl

Titel von Pearson Education

Bücher

PDF-Titel (50% billiger als Buch)

Downloads