IRET instruction setting wrong code segment

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
mrgian
Posts: 2
Joined: Wed Mar 29, 2023 2:41 am

IRET instruction setting wrong code segment

Post by mrgian »

Hello everyone!

I'm having some trouble with ISRs in my OS written in Rust. The problem is that IRET instrction is restoring a wrong CS.
Let me show step by step what it happens.

First I generate a division error exception by dividing by zero. This is the situation before the exception:
https://i.ibb.co/k5L9qt3/Schermata-del- ... -37-36.png

Then I step to generate the exception:
https://i.ibb.co/W547mSV/Schermata-del- ... -38-10.png

CPU jumps to 0x1004d0, which is what I'm expecting since that is the address of my division error handler, which is made by the only IRET instruction.
Stack also seems fine, EIP, CS, and EFLAGS got pushed and they are correct (0x8 is my code segment).

So far, so good.
However see what happens when I step again to execute the IRET instruction:
https://i.ibb.co/b1d35sx/Schermata-del- ... -38-53.png

Instead of returning, a general protection fault exception is generated, and if I'm right the extra data pushed to stack is the error code.
In the case of a general protection fault the error code is the segment related to the excpetion, in my case is 0x10. WHY?
And indeed, Bochs is complaining check_cs(0x0010): not a valid code segment !, and Bochs is right since my code segment is 0x8 and not 0x10

My understanding of the problem is that IRET is popping wrong values from the stack, but how I can solve this?

Complete source code here: https://github.com/mrgian/felix
alexfru
Member
Member
Posts: 1111
Joined: Tue Mar 04, 2014 5:27 am

Re: IRET instruction setting wrong code segment

Post by alexfru »

You have a 16-bit IRET in 32-bit mode. And you need 32-bit one, AKA IRETD.
IOW, in 32-bit mode the instruction needs to be encoded as 0xCF and not as 0x66, 0xCF (your disassembly gives this away as the first digit 6 and length of 2 bytes).

Also, doing IRETD will go back to (I)DIV. If you intend to skip the offending instruction, the ISR needs to adjust the return address on the stack.
Octocontrabass
Member
Member
Posts: 5560
Joined: Mon Mar 25, 2013 7:01 pm

Re: IRET instruction setting wrong code segment

Post by Octocontrabass »

Looks like you already fixed the problem. I'm curious why your assembler decided you wanted IRETW instead of IRETD in 32-bit mode, that's a pretty unusual problem to have.
MichaelPetch
Member
Member
Posts: 797
Joined: Fri Aug 26, 2016 1:41 pm
Libera.chat IRC: mpetch

Re: IRET instruction setting wrong code segment

Post by MichaelPetch »

Almost like the code had a `.code16gcc` directive or equivalent in it.
mrgian
Posts: 2
Joined: Wed Mar 29, 2023 2:41 am

Re: IRET instruction setting wrong code segment

Post by mrgian »

Octocontrabass wrote:Looks like you already fixed the problem. I'm curious why your assembler decided you wanted IRETW instead of IRETD in 32-bit mode, that's a pretty unusual problem to have.
Yep. That was the problem. I still don't know why Rust inline asm assembler translated IRET to IRETW instead of IRETD, even if I'm in 32 bit mode.
Post Reply