2016-02-28 15:28:17 -05:00
|
|
|
/* Descriptors.cc
|
|
|
|
* vim: set tw=80:
|
|
|
|
* Eryn Wells <eryn@erynwells.me>
|
|
|
|
*/
|
|
|
|
/**
|
|
|
|
* Oh god oh god. Descriptor tables.
|
|
|
|
*/
|
|
|
|
|
2016-02-28 23:26:42 -05:00
|
|
|
#include "Descriptors.hh"
|
2016-03-13 15:47:11 -04:00
|
|
|
#include "Console.hh"
|
2016-02-28 15:28:17 -05:00
|
|
|
|
2016-03-01 12:01:51 -05:00
|
|
|
namespace {
|
2016-02-28 15:28:17 -05:00
|
|
|
|
2016-02-28 23:26:42 -05:00
|
|
|
/**
|
2016-03-01 12:01:51 -05:00
|
|
|
* Six byte field containing the length and a linear address where a descriptor
|
2016-03-25 01:29:02 -04:00
|
|
|
* table lives. One of these is passed to the `lgdt` and `lidt` instructions.
|
2016-02-28 23:26:42 -05:00
|
|
|
*/
|
2016-03-01 12:01:51 -05:00
|
|
|
struct PseudoDescriptor
|
2016-02-28 23:26:42 -05:00
|
|
|
{
|
|
|
|
uint16_t limit;
|
|
|
|
uint32_t base;
|
|
|
|
} __attribute((__packed__));
|
|
|
|
|
2016-03-01 12:01:51 -05:00
|
|
|
}
|
|
|
|
|
2016-03-09 01:12:05 -05:00
|
|
|
namespace x86 {
|
2016-03-01 12:01:51 -05:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Public
|
|
|
|
*/
|
|
|
|
|
|
|
|
GDT::DescriptorSpec
|
|
|
|
GDT::DescriptorSpec::kernelSegment(uint32_t base,
|
|
|
|
uint32_t limit,
|
|
|
|
GDT::Type type)
|
|
|
|
{
|
|
|
|
return {base, limit, true, true, false, false, true, DPL::Ring0, true, type};
|
|
|
|
}
|
2016-02-28 23:26:42 -05:00
|
|
|
|
2016-02-28 15:28:17 -05:00
|
|
|
|
2016-03-02 02:02:34 -05:00
|
|
|
Descriptor
|
2016-03-01 12:01:51 -05:00
|
|
|
GDT::DescriptorSpec::descriptor()
|
|
|
|
const
|
2016-02-28 15:28:17 -05:00
|
|
|
{
|
2016-03-01 12:01:51 -05:00
|
|
|
Descriptor descriptor = 0;
|
|
|
|
|
2016-03-13 12:51:42 -04:00
|
|
|
const auto dpl = uint8_t(privilegeLevel) & 0x3;
|
|
|
|
const auto typ = uint8_t(type) & 0xF;
|
2016-03-01 12:01:51 -05:00
|
|
|
|
|
|
|
descriptor = base & 0xFF000000; // Bits 31:24 of the base address.
|
2016-03-13 12:51:42 -04:00
|
|
|
if (hasCoarseGranularity) {
|
|
|
|
descriptor |= (1 << 23); // Granularity field
|
|
|
|
}
|
|
|
|
if (has32BitOperations) {
|
|
|
|
descriptor |= (1 << 22); // D/B field
|
|
|
|
}
|
|
|
|
if (hasNative64BitCode) {
|
|
|
|
descriptor |= (1 << 21); // L field
|
|
|
|
}
|
|
|
|
if (available) {
|
|
|
|
descriptor |= (1 << 20); // AVL field
|
|
|
|
}
|
2016-03-01 12:01:51 -05:00
|
|
|
descriptor |= limit & 0x000F0000; // Bits 19:16 of the segment limit.
|
2016-03-13 12:51:42 -04:00
|
|
|
if (isPresent) {
|
|
|
|
descriptor |= (1 << 15); // P field
|
|
|
|
}
|
2016-03-02 02:02:34 -05:00
|
|
|
descriptor |= (dpl << 13); // DPL field
|
2016-03-13 12:51:42 -04:00
|
|
|
if (isCodeDataSegment) {
|
|
|
|
descriptor |= (1 << 12); // S field
|
|
|
|
}
|
2016-03-02 02:02:34 -05:00
|
|
|
descriptor |= (typ << 8); // Type field: see Type
|
2016-03-01 12:01:51 -05:00
|
|
|
descriptor |= (base >> 16) & 0x000000FF; // Bits 23:16 of the base address.
|
2016-02-28 15:28:17 -05:00
|
|
|
|
|
|
|
// Shift everything up by 32 to make room for the lower 4 bytes
|
|
|
|
descriptor <<= 32;
|
|
|
|
|
2016-03-01 12:01:51 -05:00
|
|
|
descriptor |= base << 16; // Bits 15:00 of the base address.
|
|
|
|
descriptor |= limit & 0x0000FFFF; // Bits 15:00 of the segment limit.
|
2016-02-28 15:28:17 -05:00
|
|
|
|
|
|
|
return descriptor;
|
|
|
|
}
|
|
|
|
|
2016-03-01 12:01:51 -05:00
|
|
|
|
|
|
|
GDT::GDT()
|
2016-03-09 01:26:35 -05:00
|
|
|
: mTable{0}
|
2016-03-01 12:01:51 -05:00
|
|
|
{ }
|
|
|
|
|
2016-02-28 23:26:42 -05:00
|
|
|
|
|
|
|
void
|
2016-03-01 12:01:51 -05:00
|
|
|
GDT::setDescriptor(size_t index,
|
|
|
|
const GDT::DescriptorSpec& spec)
|
2016-02-28 23:26:42 -05:00
|
|
|
{
|
2016-03-02 02:02:34 -05:00
|
|
|
if (index >= GDT::Size) {
|
|
|
|
return;
|
|
|
|
}
|
2016-03-09 01:26:35 -05:00
|
|
|
mTable[index] = spec.descriptor();
|
2016-03-01 12:01:51 -05:00
|
|
|
}
|
2016-02-28 23:26:42 -05:00
|
|
|
|
2016-03-01 12:01:51 -05:00
|
|
|
|
|
|
|
void
|
|
|
|
GDT::setNullDescriptor(size_t index)
|
|
|
|
{
|
2016-03-02 02:02:34 -05:00
|
|
|
if (index >= GDT::Size) {
|
|
|
|
return;
|
|
|
|
}
|
2016-03-09 01:26:35 -05:00
|
|
|
mTable[index] = 0;
|
2016-03-01 12:01:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
GDT::load()
|
2016-03-02 02:02:34 -05:00
|
|
|
const
|
2016-03-01 12:01:51 -05:00
|
|
|
{
|
2016-03-09 01:26:35 -05:00
|
|
|
PseudoDescriptor gdt {Size * sizeof(Descriptor) - 1, uint32_t(&mTable)};
|
2016-02-28 23:26:42 -05:00
|
|
|
/*
|
|
|
|
* 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");
|
|
|
|
}
|
|
|
|
|
2016-03-02 02:02:01 -05:00
|
|
|
/*
|
|
|
|
* Static
|
|
|
|
*/
|
|
|
|
|
|
|
|
IDT&
|
|
|
|
IDT::systemIDT()
|
|
|
|
{
|
|
|
|
static IDT sIDT;
|
|
|
|
return sIDT;
|
|
|
|
}
|
|
|
|
|
2016-03-13 12:52:05 -04:00
|
|
|
|
|
|
|
IDT::DescriptorSpec
|
|
|
|
IDT::DescriptorSpec::exceptionHandler(uint16_t segment,
|
|
|
|
void (*handler)())
|
|
|
|
{
|
|
|
|
return {segment, uint32_t(handler), true, DPL::Ring0, true, Type::Interrupt};
|
|
|
|
}
|
|
|
|
|
2016-03-02 02:02:01 -05:00
|
|
|
/*
|
|
|
|
* Public
|
|
|
|
*/
|
|
|
|
|
|
|
|
Descriptor
|
|
|
|
IDT::DescriptorSpec::descriptor()
|
|
|
|
const
|
|
|
|
{
|
|
|
|
Descriptor descriptor = 0;
|
|
|
|
|
|
|
|
if (type != Type::Task) {
|
|
|
|
descriptor = offset & 0xFFFF0000;
|
|
|
|
}
|
|
|
|
|
2016-03-13 12:51:42 -04:00
|
|
|
const auto dpl = uint8_t(privilegeLevel) & 0x3;
|
|
|
|
const auto typ = uint8_t(type) & 0x7;
|
2016-03-02 02:02:01 -05:00
|
|
|
|
2016-03-13 12:51:42 -04:00
|
|
|
if (isPresent) {
|
|
|
|
descriptor |= 1 << 15;
|
|
|
|
}
|
2016-03-02 02:02:01 -05:00
|
|
|
descriptor |= dpl << 13;
|
2016-03-13 12:51:42 -04:00
|
|
|
if (type != Type::Task && is32BitGate) {
|
|
|
|
descriptor |= 1 << 11;
|
|
|
|
}
|
2016-03-02 02:02:01 -05:00
|
|
|
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)};
|
2016-03-13 12:51:42 -04:00
|
|
|
asm volatile("lidt %0\n" : : "m" (idt));
|
2016-03-02 02:02:01 -05:00
|
|
|
}
|
|
|
|
|
2016-03-09 01:12:05 -05:00
|
|
|
} /* namespace x86 */
|