Code: Select all
static uint64_t gdtEntries[NUM_GDT_ENTRIES];
static struct gdt_pointer
{
uint16_t limit;
uint32_t firstEntryAddr;
} gdtPtr;
static uint64_t CreateGDTEntry(uint32_t base, uint32_t limit, uint16_t type)
{
uint64_t entry = 0u;
entry = limit & 0x000F0000;
entry |= (type << 8u) & 0x00F0FF00;
entry |= (base >> 16u) & 0x000000FF;
entry |= base & 0xFF000000;
entry <<= 32u;
entry |= base << 16u;
entry |= limit & 0x0000FFFF;
return entry;
}
extern void FlushGDT(uint32_t);
void InitGDT()
{
gdtPtr.limit = sizeof(uint64_t) * NUM_GDT_ENTRIES;
gdtPtr.firstEntryAddr = (uint32_t)&gdtEntries;
gdtEntries[0u] = CreateGDTEntry(0u, 0u, 0u); // Null segment
gdtEntries[1u] = CreateGDTEntry(0u, 0xFFFFFFFF, 0x9A); // Kernel code segment
gdtEntries[2u] = CreateGDTEntry(0u, 0xFFFFFFFF, 0x92); // Kernel data segment
FlushGDT((uint32_t)&gdtPtr);
}
Code: Select all
; Inputs: Physical address of GDT to be loaded
FlushGDT:
mov eax, [esp+4]
lgdt [eax]
; We can now switch to the new data selectors (0x10 is the selector for the new kernel data segment)
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
; We now do a far jump to the new kernel code segment (0x08 is the selector for the new code segment)
jmp 0x08:.flush
.flush:
ret