I am trying to load a GDT. I have an array of entries, with each entry created like so:
Code:
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);
}
I then load the GDT and switch to the new code and data segment like so:
Code:
; 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
It triple faults, but not where I thought it would (the far jump). Instead, it seems to start executing some random code after `mov ds, ax` (which is weird because I haven't changed the CS yet??). I usually try to be fairly self-sufficient with debugging, but I can't find the relevant part of the Intel manual and the wiki seems to have slightly conflicting methods. I would appreciate some pointers in what I've done wrong; thanks in advance!