Page 1 of 1

Trying to execute RETF after loading GDT causes triple fault

Posted: Mon Dec 28, 2020 12:40 pm
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 

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

Posted: Mon Dec 28, 2020 8:28 pm
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).

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

Posted: Tue Dec 29, 2020 2:28 am
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).