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:
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

View file

@ -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();
};

View file

@ -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";

View file

@ -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;
}