Dockers DEV Site


Updates · Faq · Home 

3.3 Call- und Task- Gates

Einleitung

Bei normalen Unterprogrammaufrufen ohne Wechsel der Privilegstufe werden die Rücksprungadresse und eventuelle Parameter auf dem Stack abgelegt, der Sprung zur eigentlichen Routine ausgeführt und nach dem Rücksprung das Programm fortgesetzt. Das Schutzkonzept des Protected Mode verbietet es jedoch, auf diese Weise Routinen in anderen Privilegstufen aufzurufen. Für diesen Zweck existieren Call-Gates, die, wie bereits weiter oben erwähnt wurde, einen Einsprungspunkt in eine höher privilegierte Routine definieren.

Dabei tritt jedoch das folgende Problem auf:

Angenommen, eine in Ring 3 laufende Anwendung versucht, über ein Call-Gate eine Routine des Betriebsystems (im Ring 0) aufzurufen. Wird das Call-Gate aktiviert, "legt" der Prozessor die Rücksprungadresse auf den Stack der aufrufenden Routine (in einem ungeschützten Speicherbereich in Ring3 !), ändert die aktuelle Privilegstufe und führt anschließend den Sprung aus. Das Problem liegt nun darin, daß der Stack im Ring 3 nur wenig gegenüber anderen Anwendungen geschützt ist bzw. nicht entfernte Stackelemente der Betriebsystemroutine nach dem Aufruf der Routine noch gelesen werden könnten. Ein klarer Verstoß gegen das Schutzkonzept.

Call-Gate

Die Lösung des oben genannten Problems besteht nun darin, im Call-Gate festzulegen, wieviele Parameter vom Stack der Anwendung auf den Stack der Betriebsystemroutine (bzw. der jeweils höher privilegierten Routine) kopiert werden soll. Dadurch ist es möglich, alle Stackbehandlungen im geschützten Bereich der Betriebssystemroutine durchzuführen. Daraus ergibt sich jedoch auch, daß jeder Task so viele separate Stacksegmente definieren muß, wie es Privilegstufen im System gibt. Da der Prozessor im Normalfall jedoch nur einen Stack adressieren kann (über SS:ESP), übernehmen die Einträge SSn:ESPn des TSS-Segmentes die Aufgabe, die entsprechenden Stacksegmente zu verwalten. Nur der jeweils aktive Stack wird durch SS:ESP adressiert. Ein Stackeintrag im TSS für die Privilegstufe 3 wird nicht benötigt, da es keine Routine gibt, die niedriger als eine Routine in Ring 3 privilegiert ist.

Tritt ein Privilegstufenwechsel über ein Call-Gate auf, wird zunächst die Privilegstufe des Gates (DPL) mit der aktuellen Privilegstufe (CPL) verglichen. Wenn das aufrufende Programm mindestens die Privilegstufe des Gates besitzt, kann mit weiteren Prüfungen fortgesetzt werden. Ist das nicht der Fall, wird die Exception 13 ausgelöst. Nachdem festgestellt wurde, daß sich das Call-Gate im Speicher befindet ("Present"-Bit gesetzt), ändert der Prozessor die CPL und springt an die im Gate angegebene Adresse. Dabei wird die im Call-Gate angegebene Anzahl 32-Bit Werte vom Stack der Anwendung auf den durch die entsprechende Privilegstufe ausgewählten Stack kopiert. Insgesamt lassen sich dabei 31 Werte auf den Stack kopieren (Vgl. Abb. 3.9 - Aufbau des Call-Gates).

Call-Gate
Abb. 3.9: Aufbau des Call-Gate

Da das Call-Gate selbst die komplette Adresse der beschriebenen Routine beinhaltet, wird die beim Aufruf des Gates angegebene Offsetadresse ignoriert (Abb. 3.10 zeigt die Umsetzung eines Gate-Aufrufes zur eigentlichen Adresse der Routine).

Call-Gate Aufruf
Abb. 3.10: Aufruf eines Call-Gate

Bei dieser Umsetzung wird der Zugriff auf eine Routine durch zwei Privilegprüfungen kontrolliert. DPL1 in Abbildung 3.10 definiert, wer auf das Gate zugreifen darf. Dieser Zugriff ist nur möglich, wenn die aktuelle Privilegstufe (CPL) des aufrufenden Programmes numerisch höher oder gleich (d.h. entsprechend niedriger oder gleich privilegiert) dem Wert des Feldes DPL1 im Call-Gate ist.

DPL2 im Codesegment-Deskriptor kann den Zugriff auf das beschriebene Codesegment weiter einschränken. Wird es auf eine Privilegstufe kleiner als DPL1 gesetzt, kann unter Umständen zwar auf das Call-Gate zugegriffen werden, die Ausführung der eigentlichen Routine löst jedoch eine Exception aus.

Anmerkung: Call-Gates können auch von JMP-Befehlen aufgerufen werden. Dabei ist jedoch zu beachten, daß bei der Ausführung von JMP kein Privilegstufenwechsel durchgeführt werden kann. Call-Gates können über den JMP-Befehl nur aufgerufen werden, wenn sich die beschriebene Routine auf der gleichen Privilegstufe wie die aufrufende Routine befindet.

Task-Gates

Task-Gates entsprechen in ihrem Aufbau den Call-Gates (Vgl. Abb. 3.11), definieren aber keine Einsprungsadresse in eine Routine, sondern lösen einen Taskwechsel aus. Der im Task-Gate angegebene Selektor muß aus diesem Grund nicht auf einen Codesegment-Deskriptor zeigen, sondern einen TSS-Deskriptor festlegen.

Task-Gate
Abb. 3.11: Task-Gate

Die DPL des angesprochenen Tasks wird beim Aufruf über ein Task-Gate nicht überprüft. Nur die DPL des Task-Gates entscheidet darüber, ob ein Zugriff auf den TSS-Deskriptor möglich ist. Im Gegensatz zu TSS-Deskriptoren, die sich nur in der GDT befinden dürfen, können Task-Gates in der LDT des Prozesses gespeichert werden. Auch Interrupts und Exceptions können einen Task-Wechsel auslösen. Task-Gates werden dazu in die Interrupt Deskriptor Tabelle (IDT) eingetragen. Dadurch kann erreicht werden, daß bei einer Interrupt-Behandlung ein eigener Task gestartet wird. Dieser Task kann dann unabhängig vom Programm, das die Exception auslöste, eine Fehlerbehandlung durchführen.

Beispielprogramm pm_04.asm benutzt einen Task, um ein Protected Mode Programm auszuführen. Dabei wurde der bisherige, lineare Programmablauf der Beispielprogramme pm_01.asm bis pm_03.asm abgeändert und die eigentliche Protected Mode Initialisierung in das externe Modul pm.asm verlagert.

Die Routine pm_init im Modul pm.asm muß von einem Programm im Realmode über einen FAR-Call aktiviert werden. "pm_init" führt nun alle nötigen Vorbereitungen aus, um in den Protected Mode zu schalten. Dabei legt die Routine zwei TS-Segmente und die dazugehörigen TSS-Deskriptoren an. Ein TSS wird für die Routine pm_init verwendet. Das andere TSS wird für die Routine, die pm_init aufgerufen hat, benutzt.
"pm_init" führt, nachdem sich der Prozessor im Protected Mode befindet, einen Task-Wechsel (FAR-JMP) zum aufrufenden Programm aus. Im Register AX befindet sich danach ein Selektor auf das erste TSS. Das Anwendungsprogramm ist mit einem Sprung zu diesem, im Register AX übergebenen Selektor in der Lage, seinen Task zu beenden und die Kontrolle an pm_init abzugeben. "pm_init" schaltet nach der Rückehr aus dem ausgeführten Task den Protected Mode wieder aus, aktiviert den Realmode und kehrt zu DOS zurück.

Beispielprogramm pm_04.asm ist ein Beispiel, wie kooperatives Multitasking im Protected Mode aussehen könnte. Der von "pm_init" ausgeführte Task kehrt "von sich aus" zum vorhergehenden Task zurück und wird nicht automatisch an irgendeiner Stelle im Programmcode unterbrochen.

Ein Beispiel für echtes pre-emptives Multitasking finden Sie unter Punkt 6. Komplexbeispiel.

Index
weiter >>
<< zurück ||

Last change 27/11/2022 by Docker Rocker.
This page uses no cookies, no tracking - just HTML.
Author: "Docker Rocker" ~ 2022 · [Public Git]