112 lines
3.0 KiB
C++
112 lines
3.0 KiB
C++
#define MODULE "gdt"
|
|
|
|
#include "gdt/GDT.h"
|
|
#include "kassert.h"
|
|
#include "log/Log.h"
|
|
#include "memory/MemoryManager.h"
|
|
#include "std/string.h"
|
|
#include <stdint.h>
|
|
|
|
struct GDTR
|
|
{
|
|
uint16_t size;
|
|
uint64_t offset;
|
|
} __attribute__((packed));
|
|
|
|
struct GDTEntry
|
|
{
|
|
uint16_t limit0;
|
|
uint16_t base0;
|
|
uint8_t base1;
|
|
uint8_t access;
|
|
uint8_t limit1_flags;
|
|
uint8_t base2;
|
|
} __attribute__((packed));
|
|
|
|
struct HighGDTEntry
|
|
{
|
|
uint32_t base_high;
|
|
uint32_t reserved;
|
|
} __attribute__((packed));
|
|
|
|
struct TSS
|
|
{
|
|
uint32_t reserved0;
|
|
uint64_t rsp[3];
|
|
uint64_t reserved1;
|
|
uint64_t ist[7];
|
|
uint64_t reserved2;
|
|
uint16_t reserved3;
|
|
uint16_t iomap_base;
|
|
} __attribute__((packed));
|
|
|
|
struct InternalGDT
|
|
{
|
|
GDTEntry null;
|
|
GDTEntry kernel_code;
|
|
GDTEntry kernel_data;
|
|
GDTEntry user_code;
|
|
GDTEntry user_data;
|
|
GDTEntry tss;
|
|
HighGDTEntry tss2;
|
|
} __attribute__((packed)) __attribute((aligned(PAGE_SIZE)));
|
|
|
|
__attribute__((aligned(PAGE_SIZE))) static InternalGDT internal_gdt = {{0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00},
|
|
{0xffff, 0x0000, 0x00, 0x9a, 0xaf, 0x00},
|
|
{0xffff, 0x0000, 0x00, 0x92, 0xcf, 0x00},
|
|
{0xffff, 0x0000, 0x00, 0xfa, 0xaf, 0x00},
|
|
{0xffff, 0x0000, 0x00, 0xf2, 0xcf, 0x00},
|
|
{0x0000, 0x0000, 0x00, 0xe9, 0x0f, 0x00},
|
|
{0x00000000, 0x00000000}};
|
|
|
|
static TSS main_tss;
|
|
|
|
extern "C" void load_gdt(GDTR* gdtr);
|
|
extern "C" void load_tr(int segment);
|
|
|
|
static void set_base(GDTEntry* entry, uint32_t base)
|
|
{
|
|
entry->base0 = (base & 0xFFFF);
|
|
entry->base1 = (base >> 16) & 0xFF;
|
|
entry->base2 = (uint8_t)((base >> 24) & 0xFF);
|
|
}
|
|
|
|
static void set_limit(GDTEntry* entry, uint32_t limit)
|
|
{
|
|
ASSERT(limit <= 0xFFFFF);
|
|
entry->limit0 = limit & 0xFFFF;
|
|
entry->limit1_flags = (entry->limit1_flags & 0xF0) | ((limit >> 16) & 0xF);
|
|
}
|
|
|
|
static void set_tss_base(GDTEntry* tss1, HighGDTEntry* tss2, uint64_t addr)
|
|
{
|
|
set_base(tss1, addr & 0xffffffff);
|
|
tss2->base_high = (uint32_t)(addr >> 32);
|
|
}
|
|
|
|
static void setup_tss()
|
|
{
|
|
memset(&main_tss, 0, sizeof(TSS));
|
|
main_tss.rsp[0] =
|
|
(uint64_t)MemoryManager::get_pages(4) + (PAGE_SIZE * 4) - 8; // allocate 16KB for the syscall stack
|
|
main_tss.iomap_base = sizeof(TSS);
|
|
set_tss_base(&internal_gdt.tss, &internal_gdt.tss2, (uint64_t)&main_tss);
|
|
set_limit(&internal_gdt.tss, sizeof(TSS) - 1);
|
|
}
|
|
|
|
static void load_tss()
|
|
{
|
|
kdbgln("Loading TR (GDT entry 0x2b)");
|
|
load_tr(0x2b);
|
|
}
|
|
|
|
void GDT::load()
|
|
{
|
|
static GDTR gdtr;
|
|
gdtr.offset = (uint64_t)&internal_gdt;
|
|
gdtr.size = sizeof(InternalGDT);
|
|
setup_tss();
|
|
kdbgln("Loading GDT at offset %lx, size %d", gdtr.offset, gdtr.size);
|
|
load_gdt(&gdtr);
|
|
load_tss();
|
|
} |