Mandalex

Um Traps zu behandeln, werden hier zuerst ein paar allgemeine Erklärungen aufgeführt, denn bei anderen Prozessoren heissen bestimmte Dinge wieder anders und allgemein kann man sowieso nicht definieren, was genau was sein soll.

Nebst Traps (Fallen) gibt es auch Interrupts (Unterbrechungen) und Exceptions (Ausnahmen) und sie haben alle eine Gemeinsamkeit: Sie treten auf, wenn ein dringendes Problem erledigt werden soll. Dies kann beispielsweise sein: Eine Taste auf der Tastatur wurde gedrückt, und jetzt muss der zugehörige Code ermittelt werden; das Modem hat Daten empfangen und will jetzt, dass sich der Prozessor dieser annimmt; ein unsorgfältiger Programmierer hat es geschafft, dass der Prozessor eine Zahl durch Null dividieren soll; bei einem Function-Call wurde bemerkt, dass kein freies Register-Window mehr vorhanden ist; ins Log soll ein Text ausgegeben werden; das Modem soll Daten ins Internet schicken.

Hierbei kann man zwischen 3 Typen unterscheiden:
Irgendeine Hardware hat ein dringendes Bedürfnis (Taste, Modem-Empfang).
Während der Ausführung des Programmes ist ein Fehler aufgetreten (Null-Division, Register-Window).
Ein bestimmter Teil des Systems oder der Hardware soll etwas ausführen (Log, Modem-Send).

Der erste Typ wird allgemein als ein Hardware-Interrupt oder event oder gar surprise bezeichnet. Tatsächlich besitzt der Prozessor einen Pin, an dem sozusagen ein Klingelsignal gesendet werden kann, wenn irgendein Hardware-Stück ein Problem oder eine Mitteilung an den Prozessor hat. Empfängt der Prozessor also auf diesem Pin ein solches Signal, so unterbricht (Interrupt) er den Programmablauf, schaut nach, welches Teil dieses Signal sendete und springt dann zu der zuständigen Behandlungsroutine. Die richtige Routine findet er aufgrund einer IRQ-Nummer (Interrupt Request), welche vom betroffenen Hardwareteil (genaugenommen ist es der Interrupt-Controller) gesendet wird.

Der zweite Typ wird wohl eher als Exception bezeichnet. Darunter fallen alle Ereignisse, die der Prozessor nicht selbst lösen kann, sondern eine "Rettungs"-Routine aufgerufen werden muss. Die zugehörigen Routinen findet der Prozessor wiederum mittels einer Nummer, die er aber selbst fest auf dem Prozessor eingebrannt hat.

Der dritte Typ sei hier definiert als der Trap, ist jedoch genauso bekannt unter der Bezeichnung Software-Interrupt, was soviel bedeutet, dass das laufende Programm selbst will, dass es unterbrochen wird, damit etwas Wichtiges erledigt werden kann. Die verlangte Routine wird direkt über eine Nummer im Programmcode angegeben.

Sobald sich der Prozessor in diese für alle drei Typen notwendigen Behandlungs-Routinen (Trap-Handler, Interrupt-Handler) eingeklinkt hat, wird diese abgelaufen, und nach Beendigung derselben zum ursprünglichen Programm zurückgekehrt.

Traps bezeichnen eigentlich einfach allgemein alle diese Typen, genauso, wie alle diese Typen beim Intel-Prozessor Interrupts heissen. Das menschliche Sprachverständnis lässt beim Wort Trap (Falle) vielleicht noch folgende Definition zu: Wenn bereits eine Behandlungsroutine am laufen ist, und dann nochmals eine solche Störung kommt, dann steht der Prozessor vor einem mächtigen Problem, denn dann hat die Fehlerbehebungsroutine selbst einen Fehler. Das wäre dann ein Trap, der Prozessor ist gefangen und hat als einzigen Ausweg den Reset (Oder einen Bluescreen unter Windows 95). Um solche Traps zu vermeiden, ist das Betriebssystem zuständig, dieses sollte so programmiert sein, das sowas niemals vorkommen kann. Im folgenden werden die fettgedruckten Definitionen weitergeführt.

Normale Programme laufen im sogenannten User-Mode. In diesem Modus hat der Programmierer nicht Zugriff auf das gesamte System, sondern hat strikte Einschränkungen (Viren belegen manchmal auch das Gegenteil). Die Handler der Traps (und Exceptions und Interrupts) laufen jedoch genauso wie das Betriebssystem im Supervisor-Mode. In diesem Modus hat man den kompletten Zugriff auf alles, was einen interessiert. Bei den Intel-Prozessoren gibt es ab dem 80386 sogar 4 solche Schutzebenen, wovon mittlerweile jedoch ebenfalls hauptsächlich nur noch zwei davon benutzt werden.

In den Supervisor-Mode kann ein Programmierer nicht so einfach wechseln (genaugenommen eigentlich gar nicht), er kann jedoch über Traps (werden in dieser Funktion auch Gates (Tor oder Brücke zum System) genannt) bestimmte Funktionen vom System ausführen lassen, so also mit dem kritischen Kern kommunizieren. Im User-Mode können einige Befehle nicht ausgeführt werden, welche im Supervisor-Mode beispielsweise zur Steuerung des Memory-Managers dienen. Auch können im User-Mode nicht alle Register des Prozessors angesprochen werden.

Ein Beispiel eines Befehls, welcher nur im Supervisor-Mode funktioniert, ist lda. Dieser bewirkt eine Ansteuerung eines Speicherblockes, der nicht zum eigenen Programm dazugehört. Diese Unterteilung des RAMs wird beim Sparc "Alternativer Adressraum" genannt (Annäherung an Paging). Dazu gehören folgende 4 Segmente:

0x08 User-Programmcode
0x09 Supervisor-Programmcode
0x0a User-Daten
0x0b Supervisor-Daten

Wenn ein Programm im User-Mode läuft, so greift es für die Daten automatisch auf das Segment 0x0a zu, läuft es im Supervisor-Mode, so ist es das Segment 0x0b. Um nun im Supervisor-Mode explizit auf andere Segmente zuzugreifen, gibt es folgende Befehle:

lda    sta    Lade/Speichere von/in alternative Adresse
ldsha  stha   Lade/Speichere signed halfword von/in alternative Adresse
ldda   stda   Lade/Speichere double word von/in alternative Adresse

Traps können mit den Trap-Befehlen aufgerufen werden (Beispielsweise ta, tle, ...). Dadurch wird der entsprechende Trap-Handler aufgerufen, von welchem mittels dem Befehl rett wieder zum ursprünglichen Programm zurückgekehrt wird. Befindet sich der Prozessor dann in einem Traphandler, so wird mittels des Trap-Enable-Bits im %psr jeder weitere Trap unterdrückt. Sobald wieder beim normalen Programm weitergefahren wird, können wieder Traps entstehen.

Es können insgesamt 256 Traps implementiert werden. die Trap-Nummern 0x00 bis 0x7f sind dabei für die Hardware-Interrupts reserviert. Die Nummern 0x80 bis 0xff können für Software-Traps verwendet werden. Alle Traps haben eine fest vordefinierte Priorität und nur wenn diese Proirität grösser ist als die PIL im %psr, werden die Traps auch ausgeführt (Ausser IRL 15: Division durch Null, dieser Fehler ist tatsächlich so schwerwiegend, dass niemand unter keinen Umständen einen solchen Fehler an sich vorbeiziehen lassen kann). Werden Traps aus einem solchen Grund nicht abgearbeitet, so bleiben sie trotzdem noch aktiv, bis dass sie irgendwann bearbeitet werden (oder allenfalls verlorengehen?).

Wenn nun ein Trap ausgeführt wird, löscht der Prozessor zuallererst das TrapEnable-Bit, damit keine weiteren Traps auftreten können. Dann speichert er den aktuellen Modus (User/Supervisor) im PS-Bit und setzt dass das Supervisor-Bit auf 1. Sodann findet ein Window-Switch statt, ohne dass auf Window-Overflow überprüft wird (ein Window wird immer für Traps freigehalten). Der Aktuelle %pc wird im %l1 und der %npc im %l2 gespeichert. Sodann wird im TT-Feld des %tbr die passende Trap-Nummer eingetragen. Nun wird noch der %pc auf %tbr gesetzt und %npc auf %tbr+4 (Beim Reset-Trap wird %pc = 0 und %npc = 4) und dann kann es mit dem Trap-Handling endlich losgehen.

Bei Interrupts und auch in den meisten anderen Traps muss nun das %psr gesichert werden (Normalerweise in %l0), denn nach Beendigung des Traps möchte man mit dem ursprünglichen Programm fortfahren, als sei nichts gewesen. Jede Aktion, die den Aufruf einer Sub-Routine betrifft muss nun vollständig manuell erledigt werden, denn jede Window-Switch-Aktion könnte einen weiteren Trap auslösen, was zum automatischen Reset des Prozessors führen würde. Interrupts müssen das Window so oder so speichern, denn Interrupts sind keine Exceptions und können selbst solche hervorrufen (Beispielsweise liest das Modem so viele Daten ein, dass ein neuer Speicherblock reserviert werden muss), das EnableTrap-Bit muss also nach Speichern des Windows wieder gesetzt werden.

Wenn ein Trap soweit fertig abgearbeitet ist, steht am Schluss der Befehl jmpl, gefolgt vom Befehl rett mit einer Adressangabe. Durch diese Befehle setzt der Prozessor das eigens für den Trap benutzte Window wieder zurück und setzt den %pc und den %npc auf die angegebene Adresse (weiter unten mehr dazu). Sodann wird das Supervisor-Bit wieder auf den im PS-Bit zwischengespeicherten Wert zurückgesetzt und das EnableTrap-Bit wird wieder gesetzt. Der Trap-Handler ist selbst dafür verantwortlich, dass eventuell das %psr oder die Register-Windows wieder richtig gesetzt wurden; Interrupts müssen stets alles wieder so zurückgeben, wie sie es bekommen haben.

Manche Traps verlangen, dass der Befehl, welcher den Trap auslöste, nochmals ausgeführt wird. Dazu müssen folgende beide Befehle geschrieben werden (ähnlich wie der Rücksprung aus einer Leaf-Prozedur):

jmpl %l1, %g0
rett %l2

Soll auf den Befehl nach dem fehlerhaften gesprungen werden, so gibt man folgende Zeilen ein:

jmpl %l2, %g0
rett %l2+4

Von diesen beiden Möglichkeiten sollte nur im Spezialfall abgewichen werden.