OSDev.org

The Place to Start for Operating System Developers
It is currently Sun Apr 28, 2024 9:58 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 4 posts ] 
Author Message
 Post subject: Strange bug with #GP(0) after IRET
PostPosted: Fri Oct 13, 2023 2:47 pm 
Offline
Member
Member

Joined: Fri Jan 26, 2018 11:43 am
Posts: 64
I thought my interrupt handling system was working, but it seems not. I believe my problem can be summed up as follows:

- 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:
        Address             Value
STACK 0xffff80007ff7dfa8 = 0xffffffff80000c62
STACK 0xffff80007ff7dfb0 = 0x0000000000000008
STACK 0xffff80007ff7dfb8 = 0x0000000000000286
STACK 0xffff80007ff7dfc0 = 0xffff80007ff7dfd0
STACK 0xffff80007ff7dfc8 = 0x0000000000000010
STACK 0xffff80007ff7dfd0 = 0x0000000000000000

- The GDT looks like this:
Code:
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

- The CPU registers look like this (before IRET):
Code:
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

So, everything looks good. I've verified that 0xffffffff80000c62 (the top of the stack, which should be popped by IRET into RIP) is the correct return address. The CS and SS images on the stack are correct. The RSP image is correct too. I'm unsure about the RFLAGS image on the stack (0x286), but it seems fine.

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:
10618899027e[CPU0  ] fetch_raw_descriptor: LDTR.valid=0

So, looking through Bochs's source code I can see that this particular message is only shown when the CPU is trying to use the LDT (instead of the GDT as my CS and SS images would suggest). I cannot think of why this would possibly be happening.

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? :)


Top
 Profile  
 
 Post subject: Re: Strange bug with #GP(0) after IRET
PostPosted: Fri Oct 13, 2023 3:09 pm 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5146
Which IRET are you using? Some assemblers default to a 32-bit operand size if you don't specify, but you need a 64-bit operand size.


Top
 Profile  
 
 Post subject: Re: Strange bug with #GP(0) after IRET
PostPosted: Fri Oct 13, 2023 11:23 pm 
Offline
Member
Member

Joined: Fri Jan 26, 2018 11:43 am
Posts: 64
Good question, I'll check soon when I get back to my computer. I'm using NASM, so I'm not sure what default it uses. But now I think of it, when looking at the disassembly in bochs it did say iret rather than iretq, so that is likely the problem


Top
 Profile  
 
 Post subject: Re: Strange bug with #GP(0) after IRET
PostPosted: Sat Oct 14, 2023 2:06 am 
Offline
Member
Member

Joined: Fri Jan 26, 2018 11:43 am
Posts: 64
Octocontrabass wrote:
Which IRET are you using? Some assemblers default to a 32-bit operand size if you don't specify, but you need a 64-bit operand size.


Yes this was in fact the problem :) The amount of hours I spent debugging this for it to come down to adding a single "q" character to my code....


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 4 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: Bing [Bot], FrankRay78, Majestic-12 [Bot] and 32 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group