Friedrich-Alexander-Universität Erlangen-Nürnberg  /   Technische Fakultät  /   Department Informatik
Aufgabe 2: Interruptbehandlung fĂŒr OOStuBS/MPStuBS

Lernziele

  • Behandlung asynchroner Ereignisse
  • Problematik und Schutz kritischer Abschnitte

Aufgabenbeschreibung

Es soll eine einfache Interruptbehandlung fĂŒr die Unterbrechungen durch die Tastatur vorgesehen werden.

Hierzu mĂŒssen die Klassen Gate, Panic und Keyboard, Funktionen in den Namespaces IOAPIC und Plugbox sowie die Funktion guardian() implementiert werden. Die Namespaces CPU und LAPIC sind in der Vorgabe enthalten.

Um das entsprechende GerĂ€t ĂŒberall in OOStuBS/MPStuBS nutzen zu können, soll von der Klasse Keyboard eine globale Instanz des Objekts keyboard angelegt werden.

dot_a2.png
KlassenĂŒbersicht fĂŒr Aufgabe 2

Implementierungshinweise

Teil A

Im ersten Schritt sollten die Funktionen im Namespace IOAPIC implementiert werden. Mit Hilfe der Namespaces IOAPIC, LAPIC und CPU können Unterbrechungen von der Tastatur zugelassen und behandelt werden (wĂ€hrend des Boot-Vorgangs wurden bei der CPU und beim I/O-APIC alle Unterbrechungen ausmaskiert). Wenn dies funktioniert, mĂŒsste automatisch bei jedem DrĂŒcken und Loslassen einer Taste die Funktion guardian() aktiviert werden, da die Interruptvektortabelle im Startup-Code entsprechend initialisiert wurde. Mit einer Ausgabe in guardian() kann Aufgabenteil A leicht getestet werden - zumindestens einige Male. Wenn die Zeichen nicht vom Tastaturcontroller abgeholt werden, lĂ€uft der Tastaturpuffer irgendwann voll. Sobald der Puffer voll ist, sendet der Tastaturcontroller jedoch keine Interrupts mehr. Deshalb kann es durchaus passieren, dass ihr zunĂ€chst nur fĂŒr ein oder zwei TastendrĂŒcke Interrupts bekommt. Je nach Umgebung kann es auch notwendig sein, den Tastaturpuffer vor der Aktivierung der Interrupts einmal komplett zu leeren.

Tipps

  • WĂ€hrend der Behandlung einer Unterbrechung braucht ihr euch um unerwĂŒnschte Interrupts nicht zu sorgen. Der Prozessor schaltet diese nĂ€mlich automatisch aus, wenn er mit der Behandlung beginnt und lĂ€sst sie erst wieder zu, wenn die Unterbrechungsbehandlung mit der Assembleranweisung iret beendet wird. Das entspricht der letzten schließenden Klammer der guardian()-Implementierung.
  • Eure Interruptverarbeitung kann natĂŒrlich nur funktionieren, wenn OOStuBS/MPStuBS auch lĂ€uft. Sobald OOStuBS/MPStuBS die main()-Funktion verlĂ€sst, kehrt es in den Startup-Code zurĂŒck, der mittels eines Aufrufs von CPU::die Interrupts deaktiviert und die CPU anhĂ€lt. Ein Betriebssystem sollte halt nicht plötzlich enden 😉. Explizit fĂŒr MPStuBS gilt dies auch fĂŒr die main_ap() Funktion, die von den Applikationsprozessoren ausgefĂŒhrt wird.
  • In einem modernen PC geschieht die Interruptverarbeitung durch ein Zusammenspiel des I/O-APICs, an welchen die externen GerĂ€te angeschlossen sind, mit den in jeder CPU integrierten Local APICs. Um euch das Leben zu vereinfachen, ist die Implementierung des Namespaces LAPIC (Local APIC) in der Vorgabe enthalten. DarĂŒberhinaus sorgt der Startupcode dafĂŒr, dass der Local APIC in einem definierten Zustand ist, so dass bei korrekter Implementierung der Funktionen im IOAPIC-Namespace die Interruptbehandlung funktionieren mĂŒsste.
  • Laut Spezifikation des Local APICs ist es notwendig, die Bearbeitung eines jeden Interrupts zu bestĂ€tigen. Dies ist durch Aufruf der Methode LAPIC::endOfInterrupt(), die schon in der Vorgabe enthalten ist, möglich.

Teil B

Im zweiten Schritt wird eine Infrastruktur geschaffen, um die Unterbrechungsbehandlung an ein zugeordnetes GerĂ€tetreiberobjekt weiterzuleiten. Zur Verwaltung von Treiberobjekten dient der Namespace Plugbox, in dem fĂŒr jeden möglichen Interrupt ein Zeiger auf ein Gate-Objekt bereitgehalten wird. Gate ist eine abstrakte Klasse, die die Schnittstelle aller Interrupt-behandelnden Treiber beschreibt. Initial werden alle Zeiger der Plugbox so gesetzt, dass sie auf ein globales Panic-Objekt verweisen.

Teil C

Hier soll die Klasse Keyboard implementiert werden. Sie stellt den eigentlichen Tastaturtreiber dar. Die Unterbrechungen, die die Tastatur auslöst, mĂŒssen abgefangen und interpretiert werden. Als Ergebnis sollen nach jedem Tastendruck die entsprechenden Zeichen auf ihrer eigenen Zeile auf dem Bildschirm dargestellt werden. Die Tastenkombination "Ctrl-Alt-Delete" soll einen Reboot auslösen.

Teil D

Nun soll das Testprogramm an die Interruptverarbeitung angepasst werden.

OOStuBS

Schreibt ein Testprogramm in Application::action(), das von main() aus aufgerufen wird. Dieses soll in einer Endlosschleife Ausgaben (beispielsweise ein int-ZĂ€hler) mit Hilfe von CGA_Window::setpos() und den Streamoperatoren von O_Stream an einer festen Position im kout-Objekt erzeugen. Es sollte nun möglich sein, durch das DrĂŒcken von Tasten die Ausgabe "durcheinander" bringen zu können. Überlegt euch, was dabei passiert, warum es passiert, und vermeidet das Problem mit Hilfe der Methoden im Namespace CPU.

MPStuBS

In MPStuBS sollen im Hauptprogramm aller CPUs Ausgaben an verschiedenen Stellen des Bildschirms mit Hilfe des globalen kout Objekts durchgefĂŒhrt werden (CGA_Window::setpos() verwenden!). Hier braucht man nicht einmal Interrupts, um die Ausgabe durcheinander zu bringen (Warum?). Zur Vermeidung des Problems reichen die Methoden im Namespace CPU alleine nicht aus. Deshalb soll hier noch zusĂ€tzlich die Klasse Spinlock (optional auch Ticketlock) implementiert werden, um parallele KontrollflĂŒsse zu synchronisieren. Was muss bei der Verwendung des Spinlocks beachtet werden? Welche Probleme können dabei auftreten?

Teil E (optional)

Als freiwillige Zusatzaufgabe kann nun mittels der Unterbrechungbehandlungen und der seriellen Schnittstelle ein GDB_Stub eingebaut werden, mit dem auch die Rechner (ohne teure Zusatzhardware) entkÀfert werden können.

Bitte beachten: FĂŒr diese Erweiterung werden sowohl Serial (optional in Aufgabe 1) als auch Ticketlock benötigt. Änderungen an Serial sind jedoch nicht notwendig (kein Interruptbetrieb - folgt in der nĂ€chsten Aufgabe).

Vorgaben

Die Implementierung der Namespaces CPU und LAPIC haben wir bereits fĂŒr euch ĂŒbernommen. FĂŒr die eigentliche Tastaturabfrage könnt ihr eure Klasse Keyboard_Controller aus Aufgabe 1 wiederverwenden (Hinweis: Die Funktion Keyboard_Controller::key_hit kann an die nun verĂ€nderte Situation angepasst werden).

Hilfestellung