Trying to execute RETF after loading GDT causes triple fault

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
DreamingWarlord
Posts: 1
Joined: Mon Dec 28, 2020 12:30 pm

Trying to execute RETF after loading GDT causes triple fault

Post by DreamingWarlord »

I've been trying to get a GDT to work for like 2 days and i tried countless methods.
My "kernel" is in long mode

Code: Select all

void GDTInstall();

void LoadGDT()
{
    // NULL DESCRIPTOR
    PushEntry(0x0000000000000000);

    // DATA
    PushEntry(0xFFFF00000092C700);

    // CODE
    PushEntry(0x0000000000BAAF00);

    __gdt_pointer.limit = sizeof(struct GDTEntry) * 3 - 1;
    __gdt_pointer.addr = &entries[0];

    GDTInstall();
}
This is Util.asm

Code: Select all

section .text

extern __gdt_pointer

global GDTInstall

GDTInstall:
    CLI 
    LGDT [__gdt_pointer]

    PUSH WORD 0x10
    PUSH QWORD Stage2
    RETF

Stage2:
    MOV AX, 0x8 
    MOV DS, AX
    MOV ES, AX
    MOV FS, AX
    MOV GS, AX
    MOV SS, AX
    STI 
Octocontrabass
Member
Member
Posts: 5568
Joined: Mon Mar 25, 2013 7:01 pm

Re: Trying to execute RETF after loading GDT causes triple f

Post by Octocontrabass »

Code: Select all

    PUSH WORD 0x10
RETF pops an entire qword for the segment selector, even though it uses only the low 16 bits. You must push an entire qword onto the stack.

Code: Select all

GDTInstall:
...
    STI 
What is executed after this STI instruction?

There may be additional problems in code that you didn't post. I suggest examining the CPU state at the first exception that leads to the triple fault using an emulator or virtual machine with built-in debugging tools (such as QEMU or Bochs).
nullplan
Member
Member
Posts: 1790
Joined: Wed Aug 30, 2017 8:24 am

Re: Trying to execute RETF after loading GDT causes triple f

Post by nullplan »

Code: Select all

   // DATA
    PushEntry(0xFFFF00000092C700);

    // CODE
    PushEntry(0x0000000000BAAF00);
That is the wrong way around. And the code segment has the wrong DPL. For kernel data, use 0x00af92000000ffff and for kernel code use 0x00af9a000000ffff. For user code and user data, replace the 9s with Fs. The only other segment I have in the GDT is the TSS. And my code for that is:

Code: Select all

    gdt[TSS_DESC] = (tssp << 16) & 0xffffff0000 | (tssp << 32) & 0xff00000000000000 | sizeof (struct tss) - 1 | (uint64_t)0x89 << 40;
    gdt[TSSU_DESC] = tssp >> 32;
Where tssp is the pointer to the TSS as an integer, and struct tss is the data structure I'm using for it. Ensure that TSSU_DESC is exactly one larger than TSS_DESC (you need them in that order).
Carpe diem!
Post Reply