Adds interrupt handlers.
This commit is contained in:
parent
55cdb2050c
commit
8cb13eb9df
4 changed files with 111 additions and 24 deletions
|
@ -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
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
};
|
|
@ -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
|
||||
|
@ -84,6 +89,8 @@ extern "C" void init(Structure const & data)
|
|||
|
||||
IDT::initialize();
|
||||
|
||||
IDT::interrupt(0x20) = Interrupt(timer);
|
||||
|
||||
Console::main << "Interrupts set up.\n";
|
||||
|
||||
asm volatile("sti");
|
||||
|
|
|
@ -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,14 +65,23 @@ 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();
|
||||
}
|
||||
|
@ -70,3 +90,46 @@ void IDT::dispatch(CpuState *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;
|
||||
}
|
Loading…
Reference in a new issue