From 13df44fb6fcd124a9f5658cbe682e9f07415c919 Mon Sep 17 00:00:00 2001 From: churl Date: Sat, 14 May 2022 21:12:32 +0200 Subject: [PATCH] implement exercise 04 interrupts --- c_os/devices/Keyboard.cc | 42 +++++++++++++ c_os/devices/Keyboard.h | 80 ++++++++++++++----------- c_os/kernel/CPU.h | 40 ++++++------- c_os/kernel/interrupts/IntDispatcher.cc | 47 ++++++++++----- c_os/kernel/interrupts/PIC.cc | 60 +++++++++++++++---- c_os/kernel/interrupts/PIC.h | 19 +++--- c_os/main.cc | 30 ++-------- c_os/user/KeyIRQDemo.cc | 10 +++- 8 files changed, 208 insertions(+), 120 deletions(-) diff --git a/c_os/devices/Keyboard.cc b/c_os/devices/Keyboard.cc index 43b9715..8fb569a 100755 --- a/c_os/devices/Keyboard.cc +++ b/c_os/devices/Keyboard.cc @@ -9,6 +9,7 @@ *****************************************************************************/ #include "devices/Keyboard.h" +#include "kernel/Globals.h" /* Tabellen fuer ASCII-Codes (Klassenvariablen) intiialisieren */ @@ -321,3 +322,44 @@ void Keyboard::set_led(char led, bool on) { /* Hier muss Code eingefuegt werden. */ } + +// Registriert die Tastatur ISR im IntDispatcher +// und erlaubt den keyboard interrupt +void Keyboard::plugin(IntDispatcher& intdis, PIC& pic) { + intdis.assign(IntDispatcher::keyboard, *this); + pic.allow(PIC::keyboard); +} + +void scroll_mode(Key key); + +void Keyboard::trigger() { + // TODO: Get data from PS/2 Mouse if necessary + + Key key = this->key_hit(); + + // NOTE: My keyboard has no delete key... + if (key.ctrl_left() && key.alt_left() && (char)key == 'r') { + this->reboot(); + } + + scroll_mode(key); + + // kout.show(0, 0, (char)key); +} + +// TODO: Where to place this? +// Waits for keys to control the scrollback buffer display +void scroll_mode(Key key) { + kout.show(kout.COLUMNS - 1, 0, (char)(48 + kout.current_page)); + + switch ((char)key) { + case 'k': + kout.scroll_page_backward(); + kout.show(kout.COLUMNS - 1, 0, (char)(48 + kout.current_page)); + break; + case 'j': + kout.scroll_page_forward(); + kout.show(kout.COLUMNS - 1, 0, (char)(48 + kout.current_page)); + break; + } +} diff --git a/c_os/devices/Keyboard.h b/c_os/devices/Keyboard.h index ea516d6..55d0250 100755 --- a/c_os/devices/Keyboard.h +++ b/c_os/devices/Keyboard.h @@ -12,44 +12,53 @@ #define __Keyboard_include__ #include "devices/Key.h" -#include "kernel/IOport.h" +#include "kernel/interrupts/IntDispatcher.h" #include "kernel/interrupts/ISR.h" +#include "kernel/interrupts/PIC.h" +#include "kernel/IOport.h" class Keyboard : public ISR { - -private: - Keyboard(const Keyboard ©); // Verhindere Kopieren - unsigned char code; // Byte von Tastatur - unsigned char prefix; // Prefix von Tastatur - Key gather; // letzter dekodierter Key - char leds; // Zustand LEDs +private: + Keyboard(const Keyboard& copy); // Verhindere Kopieren + + unsigned char code; // Byte von Tastatur + unsigned char prefix; // Prefix von Tastatur + Key gather; // letzter dekodierter Key + char leds; // Zustand LEDs // Benutzte Ports des Tastaturcontrollers - const IOport ctrl_port; // Status- (R) u. Steuerregister (W) - const IOport data_port; // Ausgabe- (R) u. Eingabepuffer (W) + const IOport ctrl_port; // Status- (R) u. Steuerregister (W) + const IOport data_port; // Ausgabe- (R) u. Eingabepuffer (W) // Bits im Statusregister - enum { outb = 0x01, inpb = 0x02, auxb = 0x20 }; + enum { outb = 0x01, + inpb = 0x02, + auxb = 0x20 }; // Kommandos an die Tastatur struct kbd_cmd { - enum { set_led = 0xed, set_speed = 0xf3 }; + enum { set_led = 0xed, + set_speed = 0xf3 }; }; enum { cpu_reset = 0xfe }; // Namen der LEDs struct led { - enum { caps_lock = 4, num_lock = 2, scroll_lock = 1 }; - }; + enum { caps_lock = 4, + num_lock = 2, + scroll_lock = 1 }; + }; // Antworten der Tastatur struct kbd_reply { enum { ack = 0xfa }; - }; + }; // Konstanten fuer die Tastaturdekodierung - enum { break_bit = 0x80, prefix1 = 0xe0, prefix2 = 0xe1 }; + enum { break_bit = 0x80, + prefix1 = 0xe0, + prefix2 = 0xe1 }; // Klassenvariablen static unsigned char normal_tab[]; @@ -57,36 +66,35 @@ private: static unsigned char alt_tab[]; static unsigned char asc_num_tab[]; static unsigned char scan_num_tab[]; - + // Interpretiert die Make und Break-Codes der Tastatur. - bool key_decoded (); + bool key_decoded(); // Ermittelt anhand von Tabellen den ASCII-Code. - void get_ascii_code (); - - + void get_ascii_code(); + public: + // Initialisierung der Tastatur. + Keyboard(); - // Initialisierung der Tastatur. - Keyboard (); + // Tastaturabfrage (vorerst Polling) + Key key_hit(); - // Tastaturabfrage (vorerst Polling) - Key key_hit (); + // Fuehrt einen Neustart des Rechners durch. + void reboot(); - // Fuehrt einen Neustart des Rechners durch. - void reboot (); + // Einstellen der Wiederholungsrate der Tastatur. + void set_repeat_rate(int speed, int delay); - // Einstellen der Wiederholungsrate der Tastatur. - void set_repeat_rate (int speed, int delay); + // Setzt oder loescht die angegebene Leuchtdiode. + void set_led(char led, bool on); - // Setzt oder loescht die angegebene Leuchtdiode. - void set_led (char led, bool on); + // Aktivierung der Unterbrechungen fuer die Tastatur + // TODO: NOTE: I added this (parameters), but is it supposed to be this way? + void plugin(IntDispatcher& intdis, PIC& pic); - // Aktivierung der Unterbrechungen fuer die Tastatur - void plugin (); - - // Unterbrechnungsroutine der Tastatur. - void trigger (); + // Unterbrechnungsroutine der Tastatur. + void trigger() override; }; #endif diff --git a/c_os/kernel/CPU.h b/c_os/kernel/CPU.h index b1e2407..21c7b0e 100755 --- a/c_os/kernel/CPU.h +++ b/c_os/kernel/CPU.h @@ -12,43 +12,41 @@ #ifndef __CPU_include__ #define __CPU_include__ - class CPU { - + private: - CPU(const CPU ©); // Verhindere Kopieren + CPU(const CPU& copy); // Verhindere Kopieren public: CPU() {} // Erlauben von (Hardware-)Interrupts - inline void enable_int () { - asm volatile ( "sti" ); + inline void enable_int() { + asm volatile("sti"); } - + // Interrupts werden ignoriert/verboten - inline void disable_int () { - asm volatile ( "cli" ); + inline void disable_int() { + asm volatile("cli"); } - + // Prozessor bis zum naechsten Interrupt anhalten - inline void idle () { - asm volatile ( "sti;" - "hlt" - ); + inline void idle() { + asm volatile("sti;" + "hlt"); } - + // Prozessor anhalten - inline void halt () { - asm volatile ( "cli;" - "hlt" - ); + inline void halt() { + asm volatile("cli;" + "hlt"); } - + // Time-Stamp-Counter auslesen inline unsigned long long int rdtsc() { - unsigned long long int ret; - asm volatile ( "rdtsc" : "=A"(ret) ); + unsigned long long int ret; + asm volatile("rdtsc" + : "=A"(ret)); return ret; } }; diff --git a/c_os/kernel/interrupts/IntDispatcher.cc b/c_os/kernel/interrupts/IntDispatcher.cc index 4a3de70..2d5d022 100755 --- a/c_os/kernel/interrupts/IntDispatcher.cc +++ b/c_os/kernel/interrupts/IntDispatcher.cc @@ -10,13 +10,11 @@ * * * Autor: Michael Schoettner, 31.8.2016 * *****************************************************************************/ +#include "kernel/interrupts/IntDispatcher.h" #include "kernel/CPU.h" #include "kernel/Globals.h" -#include "kernel/interrupts/IntDispatcher.h" - - -extern "C" void int_disp (unsigned int slot); +extern "C" void int_disp(unsigned int slot); /***************************************************************************** * Prozedur: int_disp * @@ -30,26 +28,25 @@ extern "C" void int_disp (unsigned int slot); * Parameter: * * vector: Vektor-Nummer der Unterbrechung * *****************************************************************************/ -void int_disp (unsigned int vector) { +void int_disp(unsigned int vector) { /* hier muss Code eingefuegt werden */ - - kout << "Ein Interrupt ist aufgetreten" << slot << endl; + // kout << "Ein Interrupt ist aufgetreten (vector: " << vector << ")" << endl; + intdis.report(vector); } - /***************************************************************************** * Konstruktor: IntDispatcher::IntDispatcher * *---------------------------------------------------------------------------* * Beschreibung: Initialisierung der ISR map mit einer Default-ISR. * *****************************************************************************/ -IntDispatcher::IntDispatcher () { - for (unsigned int slot=0; slot= this->size) { + kout << "Invalid vector number when assigning" << endl; + return -1; + } + this->map[vector] = &isr; + kout << "Registered ISR for vector " << dec << vector << endl; + + return 0; +} /***************************************************************************** * Methode: IntDispatcher::report * @@ -78,8 +83,22 @@ int IntDispatcher::assign (unsigned int vector, ISR& isr) { * * * Rueckgabewert: 0 = ISR wurde aufgerufen, -1 = unbekannte Vektor-Nummer * *****************************************************************************/ -int IntDispatcher::report (unsigned int vector) { +int IntDispatcher::report(unsigned int vector) { /* hier muss Code eingefuegt werden */ + if (vector >= this->size) { + return -1; + } + + ISR* isr = this->map[vector]; + + if (isr == 0) { + kout << "No ISR registered for vector " << vector << endl; + return -1; + } + + isr->trigger(); + + return 0; } diff --git a/c_os/kernel/interrupts/PIC.cc b/c_os/kernel/interrupts/PIC.cc index b1db518..e582151 100755 --- a/c_os/kernel/interrupts/PIC.cc +++ b/c_os/kernel/interrupts/PIC.cc @@ -15,13 +15,11 @@ * Autor: Olaf Spinczyk, TU Dortmund * *****************************************************************************/ -#include "kernel/PIC.h" +#include "kernel/interrupts/PIC.h" #include "kernel/IOport.h" - -static IOport IMR1 (0x21); // interrupt mask register von PIC 1 -static IOport IMR2 (0xa1); // interrupt mask register von PIC 2 - +static IOport IMR1(0x21); // interrupt mask register von PIC 1 +static IOport IMR2(0xa1); // interrupt mask register von PIC 2 /***************************************************************************** * Methode: PIC::allow * @@ -34,12 +32,24 @@ static IOport IMR2 (0xa1); // interrupt mask register von PIC 2 * Parameter: * * irq: IRQ der erlaubt werden soll * *****************************************************************************/ -void PIC::allow (int irq) { +void PIC::allow(int irq) { /* hier muss Code eingefuegt werden */ - -} + // NOTE: allow sets the bit to 0 + + unsigned char IMR; + unsigned char mask = ~(0x1 << (irq % 8)); + if (irq < 8) { + // PIC 1 + IMR = IMR1.inb(); // We don't want to change the other interrupt masks so use this as start value + IMR1.outb(IMR & mask); + } else { + // PIC 2 + IMR = IMR2.inb(); + IMR2.outb(IMR & mask); + } +} /***************************************************************************** * Methode: PIC::forbid * @@ -49,12 +59,24 @@ void PIC::allow (int irq) { * Parameter: * * interrupt: IRQ der maskiert werden soll * *****************************************************************************/ -void PIC::forbid (int irq) { +void PIC::forbid(int irq) { /* hier muss Code eingefuegt werden */ -} + // NOTE: forbid sets the bit to 1 + unsigned char IMR; + unsigned char mask = 0x1 << (irq % 8); + if (irq < 8) { + // PIC 1 + IMR = IMR1.inb(); // We don't want to change the other interrupt masks so use this as start value + IMR1.outb(IMR | mask); + } else { + // PIC 2 + IMR = IMR2.inb(); + IMR2.outb(IMR | mask); + } +} /***************************************************************************** * Methode: PIC::status * @@ -65,9 +87,23 @@ void PIC::forbid (int irq) { * Parameter: * * irq: IRQ dessen Status erfragt werden soll * *****************************************************************************/ -bool PIC::status (int irq) { +bool PIC::status(int irq) { /* hier muss Code eingefuegt werden */ + // TODO: How is IRQ2 handled (Slave PIC)? + // Does masking IRQ2 disable the whole slave? + + unsigned char IMR; + if (irq < 8) { + // PIC 1 + IMR = IMR1.inb(); + } else { + // PIC 2 + IMR = IMR2.inb(); + } + + // Use % 8 to account for two PICs + unsigned char mask = 0x1 << (irq % 8); + return IMR & mask; } - diff --git a/c_os/kernel/interrupts/PIC.h b/c_os/kernel/interrupts/PIC.h index 61a29c4..5cd5513 100755 --- a/c_os/kernel/interrupts/PIC.h +++ b/c_os/kernel/interrupts/PIC.h @@ -18,27 +18,28 @@ #define __PIC_include__ class PIC { - + private: - PIC(const PIC ©); // Verhindere Kopieren + PIC(const PIC& copy); // Verhindere Kopieren + public: PIC() {} - + public: // IRQ-Nummern von Geraeten enum { - timer = 0, // Programmable Interrupt Timer (PIT) - keyboard = 1 // Tastatur + timer = 0, // Programmable Interrupt Timer (PIT) + keyboard = 1 // Tastatur }; // Freischalten der Weiterleitung eines IRQs durch den PIC an die CPU - void allow (int irq); + void allow(int irq); // Unterdruecken der Weiterleitung eines IRQs durch den PIC an die CPU - void forbid (int irq); + void forbid(int irq); // Abfragen, ob die Weiterleitung fuer einen bestimmten IRQ unterdrueckt ist - bool status (int interrupt_device); - }; + bool status(int interrupt_device); +}; #endif diff --git a/c_os/main.cc b/c_os/main.cc index 1a251a3..a84c8f4 100755 --- a/c_os/main.cc +++ b/c_os/main.cc @@ -15,27 +15,6 @@ #include "user/HeapDemo.h" #include "user/KeyIRQDemo.h" -// Waits for keys to control the scrollback buffer display -void scroll_mode() { - kout.show(kout.COLUMNS - 1, 0, (char)(48 + kout.current_page)); - - Key key; - while (true) { - key = kb.key_hit(); - - switch ((char)key) { - case 'k': - kout.scroll_page_backward(); - kout.show(kout.COLUMNS - 1, 0, (char)(48 + kout.current_page)); - break; - case 'j': - kout.scroll_page_forward(); - kout.show(kout.COLUMNS - 1, 0, (char)(48 + kout.current_page)); - break; - } - } -} - int main() { kout.clear(); @@ -43,7 +22,7 @@ int main() { allocator.init(); // Initialize scrollback buffer after allocator.init() - kout.init(); + kout.init(5); // text_demo(); // sound_demo(); @@ -52,14 +31,13 @@ int main() { // Tastatur-Unterbrechungsroutine 'einstoepseln' /* hier muss Code eingefuegt werden */ + kb.plugin(intdis, pic); // Interrupts erlauben (Tastatur) /* hier muss Code eingefuegt werden */ + cpu.enable_int(); - key_irq_demo(); - - // TODO: Use interrupts - // scroll_mode(); + // key_irq_demo(); while (1) {}; return 0; diff --git a/c_os/user/KeyIRQDemo.cc b/c_os/user/KeyIRQDemo.cc index fef1903..0c06662 100755 --- a/c_os/user/KeyIRQDemo.cc +++ b/c_os/user/KeyIRQDemo.cc @@ -10,9 +10,15 @@ #include "kernel/Globals.h" - void key_irq_demo() { - /* Hier muss Code eingefuegt werden */ + /* Hier muss Code eingefuegt werden */ + // TODO: I don't understand the task + + while (true) { + for (unsigned char i = 0; i < 10; ++i) { + kout.show(kout.COLUMNS - 1, i, (char)(48 + i)); + } + } }