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:
|
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
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
};
|
};
|
|
@ -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";
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
Loading…
Reference in a new issue