[SOLVED] Triple-fault on loading a GDT

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
isaacwoods
Member
Member
Posts: 47
Joined: Sun Sep 06, 2015 5:40 am

[SOLVED] Triple-fault on loading a GDT

Post by isaacwoods »

I am trying to load a GDT. I have an array of entries, with each entry created like so:

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);
}
I then load the GDT and switch to the new code and data segment like so:

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
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!
Last edited by isaacwoods on Thu Apr 20, 2017 3:57 am, edited 1 time in total.
User avatar
zaval
Member
Member
Posts: 659
Joined: Fri Feb 17, 2017 4:01 pm
Location: Ukraine, Bachmut
Contact:

Re: Triple-fault on loading a GDT

Post by zaval »

this

Code: Select all

static struct gdt_pointer
{
  uint16_t limit;
  uint32_t firstEntryAddr;
} gdtPtr;
I am not into x86 now, but this structure won't be a 6-byte entity expected by lgdt instruction. Because of alignment. No? Make it packed or better define some union.
ANT - NT-like OS for x64 and arm64.
efify - UEFI for a couple of boards (mips and arm). suspended due to lost of all the target park boards (russians destroyed our town).
isaacwoods
Member
Member
Posts: 47
Joined: Sun Sep 06, 2015 5:40 am

Re: Triple-fault on loading a GDT

Post by isaacwoods »

Okay, so I made that structure packed, and also realised I wasn't subtracting one from the size of the table, so I changed that line to:

Code: Select all

gdtPtr.limit = (sizeof(uint64_t) * NUM_GDT_ENTRIES) - 1u;
The GDT is now loaded correctly and DS,ES,FS,GS and SS are all set to 0x10. However, on the far jump (`jmp 0x08:.flush`), CS is set to 0xf000 and it starts executing code at 0xe05b (.flush is at 0x10022c), causing a triple-fault.
Thanks for the help anyways!
Octocontrabass
Member
Member
Posts: 5587
Joined: Mon Mar 25, 2013 7:01 pm

Re: Triple-fault on loading a GDT

Post by Octocontrabass »

BaconWraith wrote:However, on the far jump (`jmp 0x08:.flush`), CS is set to 0xf000 and it starts executing code at 0xe05b (.flush is at 0x10022c), causing a triple-fault.
The far jump to 0xF000:E05B is the result of a triple-fault, not the cause of it.

It looks like the triple fault is caused because your code segment descriptor is invalid. Are you sure you're calling CreateGDTEntry with the correct arguments?
isaacwoods
Member
Member
Posts: 47
Joined: Sun Sep 06, 2015 5:40 am

Re: Triple-fault on loading a GDT

Post by isaacwoods »

Okay, I've been dissecting the actual GDT entries and found I hadn't set the Sz bit of the flags, so I guess it was trying to use 16-bit addresses. It now works, so thank you very much and sorry for the oversight.
Post Reply