- My operating system uses long mode in x86-64.
- When IRET is called from an ISR, a #GP exception is raised with error code 0.
- When IRET is called, the top of the stack (in this particular instance) looks like this:
Code: Select all
Address Value
STACK 0xffff80007ff7dfa8 = 0xffffffff80000c62
STACK 0xffff80007ff7dfb0 = 0x0000000000000008
STACK 0xffff80007ff7dfb8 = 0x0000000000000286
STACK 0xffff80007ff7dfc0 = 0xffff80007ff7dfd0
STACK 0xffff80007ff7dfc8 = 0x0000000000000010
STACK 0xffff80007ff7dfd0 = 0x0000000000000000
Code: Select all
GDT[0x0000]=??? descriptor hi=0x00000000, lo=0x00000000
GDT[0x0008]=Code segment, base=0x00000000, limit=0x00000fff, Execute/Read, Non-Conforming, Accessed, 64-bit
GDT[0x0010]=Data segment, base=0x00000000, limit=0x00000fff, Read/Write, Accessed
Code: Select all
rax: 00000000_00000000
rbx: 00000000_00000000
rcx: 00000000_00ffffff
rdx: 00000000_0051fa64
rsp: ffff8000_7ff7dfa8
rbp: ffff8000_7ff7dff0
rsi: 00000000_000000f9
rdi: ffffffff_800030f0
r8 : 00000000_00000010
r9 : 00000000_00000000
r10: 00000000_00000000
r11: 00000000_00000000
r12: 00000000_00000000
r13: 00000000_00000000
r14: 00000000_00000000
r15: 00000000_00000000
rip: ffffffff_80002470
eflags 0x00000282: id vip vif ac vm rf nt IOPL=0 of df IF tf SF zf af pf cf
But when IRET is executed in this state, I get a #GP exception (with error code 0). Furthermore, Bochs gives the following error on the command line:
Code: Select all
10618899027e[CPU0 ] fetch_raw_descriptor: LDTR.valid=0
But when reasoning about this problem, I thought of something. During IRET, RSP is popped before SS. Perhaps this means that SS would actually be popped from the stack that the RSP image points to? This seems like strange behaviour/CPU design. This can't be the case, right? Presumably the RSP image that's popped is not put into the actual RSP register until the whole IRET frame is popped. But I did just want to verify that.
So according to Intel, possible causes of a #GP(0) exception during IRET (in long mode) are:
If EFLAGS.NT[bit 14] = 1.
If the return code segment selector is NULL.
If the stack segment selector is NULL going back to compatibility mode.
If the stack segment selector is NULL going back to CPL3 64-bit mode.
If a NULL stack segment selector RPL is not equal to CPL going back to non-CPL3 64-bit mode.
If the return instruction pointer is not within the return code segment limit.
If the return instruction pointer is non-canonical.
So. EFLAGS.NT is not set. CS is theoretically not NULL. SS's RPL is theoretically equal to CPL (0). The return instruction pointer is definitely canonical. I'm unsure about the return instruction pointer being within the CS segment limit, but my understanding was under x86-64 long mode, GDT segment's limits and bases were automatically just "the whole of memory", basically?
Can anyone work out why this exception is being raised, then?