Adds interrupt handlers.

This commit is contained in:
Felix Queißner 2016-05-06 09:28:30 +02:00
parent 55cdb2050c
commit 8cb13eb9df
4 changed files with 111 additions and 24 deletions

View file

@ -47,7 +47,7 @@ kernel-base.ker: $(OBJS)
run: 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 bnr: kernel-base.ker run

View file

@ -28,38 +28,44 @@ struct InterruptDescriptor
InterruptFlags flags; InterruptFlags flags;
uint16_t offset1; uint16_t offset1;
InterruptDescriptor() : InterruptDescriptor();
offset0(0), selector(0), zero(0), flags(InterruptFlags::None), offset1(0)
{
} InterruptDescriptor(uint32_t offset, uint32_t selector, InterruptFlags flags);
InterruptDescriptor(uint32_t offset, uint32_t selector, InterruptFlags flags) : uint32_t offset() const;
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;
}
void setOffset(uint32_t offset);
} __attribute__((packed)); } __attribute__((packed));
static_assert(sizeof(InterruptDescriptor) == 8, "InterruptDescriptor must be 8 byte large."); 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 class IDT
{ {
public: public:
static const uint32_t length = 256; static const uint32_t length = 256;
static Interrupt interrupts[length];
private: private:
static InterruptDescriptor descriptors[length]; static InterruptDescriptor descriptors[length];
IDT() = delete; IDT() = delete;
@ -68,8 +74,19 @@ private:
static void setupPIC(); static void setupPIC();
public: public:
/**
* Accessor to an interrupt handler.
*/
static Interrupt & interrupt(uint32_t index);
/**
* Gets an interrupt descriptor
*/
static InterruptDescriptor & descriptor(uint32_t idx); static InterruptDescriptor & descriptor(uint32_t idx);
/**
* Initializes the interrupt table and sets up the PIC.
*/
static void initialize(); static void initialize();
}; };

View file

@ -19,6 +19,11 @@ struct dummy;
extern dummy kernelStartMarker; extern dummy kernelStartMarker;
extern dummy kernelEndMarker; extern dummy kernelEndMarker;
void timer(CpuState *cpu)
{
Console::main << "tick! ";
}
extern "C" void init(Structure const & data) extern "C" void init(Structure const & data)
{ {
Console::main Console::main
@ -83,6 +88,8 @@ extern "C" void init(Structure const & data)
<< (freeMemory >> 12) << "Pages\n"; << (freeMemory >> 12) << "Pages\n";
IDT::initialize(); IDT::initialize();
IDT::interrupt(0x20) = Interrupt(timer);
Console::main << "Interrupts set up.\n"; Console::main << "Interrupts set up.\n";

View file

@ -9,17 +9,28 @@
#undef ISR #undef ISR
#undef ISR_ERR #undef ISR_ERR
static InterruptDescriptor invalid; static InterruptDescriptor invalidDesc;
static Interrupt invalidIntr;
InterruptDescriptor IDT::descriptors[length]; InterruptDescriptor IDT::descriptors[length];
Interrupt IDT::interrupts[length];
InterruptDescriptor & IDT::descriptor(uint32_t idx) InterruptDescriptor & IDT::descriptor(uint32_t idx)
{ {
if(idx >= IDT::length) { if(idx >= IDT::length) {
return invalid; return invalidDesc;
} }
return IDT::descriptors[idx]; return IDT::descriptors[idx];
} }
Interrupt & IDT::interrupt(uint32_t index)
{
if(index >= IDT::length) {
return invalidIntr;
}
return IDT::interrupts[index];
}
void IDT::initialize() void IDT::initialize()
{ {
#define ISR(num) IDT::descriptor(num) = InterruptDescriptor( \ #define ISR(num) IDT::descriptor(num) = InterruptDescriptor( \
@ -54,13 +65,22 @@ void IDT::setupPIC()
void IDT::dispatch(CpuState *cpu) 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) { if(cpu->interrupt <= 0x1F) {
// Exception Handling // Exception Handling
BSOD::die(Error::UnhandledException, "Ermahgerd, Exceptions!", cpu);
} else if (cpu->interrupt >= 0x20 && cpu->interrupt <= 0x2F) { } else if (cpu->interrupt >= 0x20 && cpu->interrupt <= 0x2F) {
// IRQ // IRQ
// Console::main << "[IRQ " << (cpu->interrupt - 0x20) << "]"; // Console::main << "[IRQ " << (cpu->interrupt - 0x20) << "]";
if(cpu->interrupt >= 0x28) { if(cpu->interrupt >= 0x28) {
slavePIC.sendEndOfInterrupt(); slavePIC.sendEndOfInterrupt();
@ -69,4 +89,47 @@ void IDT::dispatch(CpuState *cpu)
} else { } else {
BSOD::die(Error::UnhandledInterrupt, "Ermahgerd, Interrupts!", cpu); 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;
} }