Add IDT class for managing the interrupt table

This commit is contained in:
Eryn Wells 2016-03-02 02:02:01 -05:00
parent d2cfbfd45d
commit 00e961435e
2 changed files with 142 additions and 15 deletions

View file

@ -140,4 +140,88 @@ GDT::load()
: "%eax");
}
/*
* Static
*/
IDT&
IDT::systemIDT()
{
static IDT sIDT;
return sIDT;
}
/*
* Public
*/
Descriptor
IDT::DescriptorSpec::descriptor()
const
{
Descriptor descriptor = 0;
if (type != Type::Task) {
descriptor = offset & 0xFFFF0000;
}
const auto p = uint8_t(isPresent);
const auto dpl = uint8_t(privilegeLevel);
const auto d = uint8_t((type == Type::Task) ? 0 : is32BitGate);
const auto typ = uint8_t(type);
descriptor |= p << 15;
descriptor |= dpl << 13;
descriptor |= d << 11;
descriptor |= typ << 8;
// Shift everything up by 32 to make room for the lower 4 bytes
descriptor <<= 32;
descriptor |= segment << 16;
if (type != Type::Task) {
descriptor |= offset & 0x0000FFFF;
}
return descriptor;
}
IDT::IDT()
: mTable{0}
{ }
void
IDT::setDescriptor(size_t index,
const DescriptorSpec& spec)
{
if (index >= Size) {
return;
}
mTable[index] = spec.descriptor();
}
void
IDT::setNullDescriptor(size_t index)
{
if (index >= Size) {
return;
}
mTable[index] = 0;
}
void
IDT::load()
const
{
PseudoDescriptor idt{Size * sizeof(Descriptor) - 1, uint32_t(&mTable)};
asm volatile(
"lidt %0\n"
: : "m" (idt) :);
}
} /* namespace kernel */

View file

@ -9,24 +9,24 @@
namespace kernel {
void initGDT();
/**
* SegmentDescriptors are entries in the GDT and LDT that describe memory
* segments. Each descriptor is two double-words (8 bytes, 64 bits) long.
*/
typedef uint64_t Descriptor;
/** Descriptor privilege level. */
enum class DPL {
Ring0 = 0x0,
Ring1 = 0x1,
Ring2 = 0x2,
Ring3 = 0x3
};
struct GDT
{
/**
* SegmentDescriptors are entries in the GDT and LDT that describe memory
* segments. Each descriptor is two double-words (8 bytes, 64 bits) long.
*/
typedef uint64_t Descriptor;
/** Descriptor privilege level. */
enum class DPL {
Ring0 = 0x0,
Ring1 = 0x1,
Ring2 = 0x2,
Ring3 = 0x3
};
/** A four bit value describing the type of the segment. */
enum class Type {
// Data segment types
@ -93,4 +93,47 @@ private:
Descriptor table[Size];
};
struct IDT
{
enum class Type {
Task = 0x5,
Interrupt = 0x6,
Trap = 0x7,
};
struct DescriptorSpec
{
uint16_t segment;
uint32_t offset;
bool isPresent;
DPL privilegeLevel;
bool is32BitGate;
Type type;
Descriptor descriptor() const;
};
static IDT& systemIDT();
IDT();
/** Set the descriptor at the given `index` to the value of `spec`. */
void setDescriptor(size_t index, const DescriptorSpec& spec);
/** Set the descriptor at the given `index` to the NULL descriptor. */
void setNullDescriptor(size_t index);
void load() const;
private:
/**
* Size of the table. IDTs shouldn't have any more than this many
* descriptors.
*/
static const size_t Size = 256;
Descriptor mTable[Size];
};
} /* namespace kernel */