From 00e961435e253521f19705e9537084c74b054bc6 Mon Sep 17 00:00:00 2001 From: Eryn Wells Date: Wed, 2 Mar 2016 02:02:01 -0500 Subject: [PATCH] Add IDT class for managing the interrupt table --- src/Descriptors.cc | 84 ++++++++++++++++++++++++++++++++++++++++++++++ src/Descriptors.hh | 73 +++++++++++++++++++++++++++++++--------- 2 files changed, 142 insertions(+), 15 deletions(-) diff --git a/src/Descriptors.cc b/src/Descriptors.cc index 7370326..29cd019 100644 --- a/src/Descriptors.cc +++ b/src/Descriptors.cc @@ -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 */ diff --git a/src/Descriptors.hh b/src/Descriptors.hh index 3b24fa6..054dc5f 100644 --- a/src/Descriptors.hh +++ b/src/Descriptors.hh @@ -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 */