diff --git a/src/Descriptors.cc b/src/Descriptors.cc index 4e8e7fa..d71de9b 100644 --- a/src/Descriptors.cc +++ b/src/Descriptors.cc @@ -6,10 +6,19 @@ * Oh god oh god. Descriptor tables. */ +#include #include +#include "Descriptors.hh" namespace kernel { +/** + * 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 SegmentDescriptor; + + /** Descriptor privilege level. */ enum class DPL { Ring0 = 0x0, @@ -18,6 +27,7 @@ enum class DPL { Ring3 = 0x3 }; + /** A four bit value describing the type of the segment. */ enum class Type { // Data segment types @@ -41,13 +51,18 @@ enum class Type { CodeEXRCA = 0xf // Execute/read, conforming, accessed }; -/** - * 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 SegmentDescriptor; -SegmentDescriptor sGDT[4]; +/** Six byte field containing the length and a linear address where the GDT lives. */ +struct GDTPointer +{ + uint16_t limit; + uint32_t base; +} __attribute((__packed__)); + + +static const size_t GDTSize = 5; +static SegmentDescriptor sGDT[GDTSize]; + static inline SegmentDescriptor createSegmentDescriptor(uint32_t base, @@ -81,4 +96,39 @@ createSegmentDescriptor(uint32_t base, return descriptor; } +/* + * Static + */ + +void +initGDT() +{ + sGDT[0] = 0; // First descriptor is always NULL. + sGDT[1] = createSegmentDescriptor(0x00000000, 0x000FFFFF, Type::CodeEXR, DPL::Ring0); + sGDT[2] = createSegmentDescriptor(0x00000000, 0x000FFFFF, Type::DataRW, DPL::Ring0); + sGDT[3] = 0; // Unused for now. + sGDT[4] = 0; // Unused for now. + + GDTPointer gdt {GDTSize * sizeof(SegmentDescriptor) - 1, uint32_t(&sGDT)}; + + /* + * Load the new GDT with the pointer defined above. The GDT isn't actually + * used until the segment registers are reladed. Below, CS is reloaded by + * a long jump into the new code segment. The rest of the segment registers + * can be loaded directly. + */ + asm volatile( + "lgdt %0\n" + "ljmpl $0x08, $reloadSegments\n" + "reloadSegments:\n" + "movl $0x10, %%eax\n" + "movl %%eax, %%ds\n" + "movl %%eax, %%es\n" + "movl %%eax, %%fs\n" + "movl %%eax, %%gs\n" + "movl %%eax, %%ss\n" + : : "m" (gdt) + : "%eax"); +} + } /* namespace kernel */ diff --git a/src/Descriptors.hh b/src/Descriptors.hh new file mode 100644 index 0000000..36502a1 --- /dev/null +++ b/src/Descriptors.hh @@ -0,0 +1,12 @@ +/* Descriptors.hh vim: set tw=80: Eryn Wells + */ +/** + * Declaration of relevant classes and functions for dealing with the GDT and + * IDT. + */ + +namespace kernel { + +void initGDT(); + +} /* namespace kernel */ diff --git a/src/Main.cc b/src/Main.cc index b75b1c7..da26650 100644 --- a/src/Main.cc +++ b/src/Main.cc @@ -1,6 +1,7 @@ #include #include #include "Console.hh" +#include "Descriptors.hh" #if defined(__linux__) #error "This file should be compiled with a cross-compiler, not the Linux system compiler!" @@ -19,6 +20,8 @@ kearly() console.clear(kernel::Console::Color::Blue); console.writeString("Loading system ...\n"); + kernel::initGDT(); + volatile int foo = 0; int i = 0; for (;;) {