From 8cb13eb9df20d93987a2a0f991e29f89ba1b0308 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Quei=C3=9Fner?= Date: Fri, 6 May 2016 09:28:30 +0200 Subject: [PATCH] Adds interrupt handlers. --- prototypes/base/Makefile | 2 +- prototypes/base/include/idt.hpp | 57 +++++++++++++++++---------- prototypes/base/init.cpp | 7 ++++ prototypes/base/src/idt.cpp | 69 +++++++++++++++++++++++++++++++-- 4 files changed, 111 insertions(+), 24 deletions(-) diff --git a/prototypes/base/Makefile b/prototypes/base/Makefile index 904d1c7..8aaff01 100644 --- a/prototypes/base/Makefile +++ b/prototypes/base/Makefile @@ -47,7 +47,7 @@ kernel-base.ker: $(OBJS) run: - qemu-system-i386 -kernel kernel-base.ker -m 64 -d int + qemu-system-i386 -kernel kernel-base.ker -m 64 bnr: kernel-base.ker run diff --git a/prototypes/base/include/idt.hpp b/prototypes/base/include/idt.hpp index 0ac2f4f..965b38d 100644 --- a/prototypes/base/include/idt.hpp +++ b/prototypes/base/include/idt.hpp @@ -28,38 +28,44 @@ struct InterruptDescriptor InterruptFlags flags; uint16_t offset1; - InterruptDescriptor() : - offset0(0), selector(0), zero(0), flags(InterruptFlags::None), offset1(0) - { + InterruptDescriptor(); - } + InterruptDescriptor(uint32_t offset, uint32_t selector, InterruptFlags flags); - InterruptDescriptor(uint32_t offset, uint32_t selector, InterruptFlags flags) : - offset0(0), selector(selector), zero(0), flags(flags), offset1(0) - { - this->setOffset(offset); - } - - uint32_t offset() const - { - return this->offset0 | (this->offset1 << 16); - } - - void setOffset(uint32_t offset) - { - this->offset0 = (offset & 0x0000FFFF) >> 0; - this->offset1 = (offset & 0xFFFF0000) >> 16; - } + uint32_t offset() const; + void setOffset(uint32_t offset); } __attribute__((packed)); static_assert(sizeof(InterruptDescriptor) == 8, "InterruptDescriptor must be 8 byte large."); +/** + * An interrupt that specifies + * a handler and if the interrupt is + * enabled. Any non-enabled interrupt + * causes a BSOD. + */ +class Interrupt +{ + friend class IDT; + using Handler = void (*)(CpuState *cpu); +private: + bool isEnabled; + Handler handler; + +public: + Interrupt(); + explicit Interrupt(Handler handler); +}; + class IDT { public: static const uint32_t length = 256; + + static Interrupt interrupts[length]; + private: static InterruptDescriptor descriptors[length]; IDT() = delete; @@ -68,8 +74,19 @@ private: static void setupPIC(); public: + /** + * Accessor to an interrupt handler. + */ + static Interrupt & interrupt(uint32_t index); + + /** + * Gets an interrupt descriptor + */ static InterruptDescriptor & descriptor(uint32_t idx); + /** + * Initializes the interrupt table and sets up the PIC. + */ static void initialize(); }; \ No newline at end of file diff --git a/prototypes/base/init.cpp b/prototypes/base/init.cpp index 1d6c694..bfbd422 100644 --- a/prototypes/base/init.cpp +++ b/prototypes/base/init.cpp @@ -19,6 +19,11 @@ struct dummy; extern dummy kernelStartMarker; extern dummy kernelEndMarker; +void timer(CpuState *cpu) +{ + Console::main << "tick! "; +} + extern "C" void init(Structure const & data) { Console::main @@ -83,6 +88,8 @@ extern "C" void init(Structure const & data) << (freeMemory >> 12) << "Pages\n"; IDT::initialize(); + + IDT::interrupt(0x20) = Interrupt(timer); Console::main << "Interrupts set up.\n"; diff --git a/prototypes/base/src/idt.cpp b/prototypes/base/src/idt.cpp index 01bb9cf..8503f31 100644 --- a/prototypes/base/src/idt.cpp +++ b/prototypes/base/src/idt.cpp @@ -9,17 +9,28 @@ #undef ISR #undef ISR_ERR -static InterruptDescriptor invalid; +static InterruptDescriptor invalidDesc; +static Interrupt invalidIntr; + InterruptDescriptor IDT::descriptors[length]; +Interrupt IDT::interrupts[length]; InterruptDescriptor & IDT::descriptor(uint32_t idx) { if(idx >= IDT::length) { - return invalid; + return invalidDesc; } return IDT::descriptors[idx]; } +Interrupt & IDT::interrupt(uint32_t index) +{ + if(index >= IDT::length) { + return invalidIntr; + } + return IDT::interrupts[index]; +} + void IDT::initialize() { #define ISR(num) IDT::descriptor(num) = InterruptDescriptor( \ @@ -54,13 +65,22 @@ void IDT::setupPIC() void IDT::dispatch(CpuState *cpu) { + Interrupt &intr = IDT::interrupts[cpu->interrupt]; + if(intr.isEnabled) { + (*intr.handler)(cpu); + } else { + BSOD::die(Error::UnhandledException, "Unhandled Interrupt!", cpu); + } + if(cpu->interrupt <= 0x1F) { // Exception Handling - BSOD::die(Error::UnhandledException, "Ermahgerd, Exceptions!", cpu); + } else if (cpu->interrupt >= 0x20 && cpu->interrupt <= 0x2F) { // IRQ // Console::main << "[IRQ " << (cpu->interrupt - 0x20) << "]"; + + if(cpu->interrupt >= 0x28) { slavePIC.sendEndOfInterrupt(); @@ -69,4 +89,47 @@ void IDT::dispatch(CpuState *cpu) } else { BSOD::die(Error::UnhandledInterrupt, "Ermahgerd, Interrupts!", cpu); } +} + + + + +Interrupt::Interrupt() : + isEnabled(false), + handler(nullptr) +{ + +} + +Interrupt::Interrupt(Handler handler) : + isEnabled(true), + handler(handler) +{ + +} + + + + +InterruptDescriptor::InterruptDescriptor() : + offset0(0), selector(0), zero(0), flags(InterruptFlags::None), offset1(0) +{ + +} + +InterruptDescriptor::InterruptDescriptor(uint32_t offset, uint32_t selector, InterruptFlags flags) : + offset0(0), selector(selector), zero(0), flags(flags), offset1(0) +{ + this->setOffset(offset); +} + +uint32_t InterruptDescriptor::offset() const +{ + return this->offset0 | (this->offset1 << 16); +} + +void InterruptDescriptor::setOffset(uint32_t offset) +{ + this->offset0 = (offset & 0x0000FFFF) >> 0; + this->offset1 = (offset & 0xFFFF0000) >> 16; } \ No newline at end of file