Page fault on iret?

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
User avatar
restingwitchface
Posts: 22
Joined: Sat Nov 02, 2024 2:58 pm
GitHub: https://github.com/NyxNeptune

Page fault on iret?

Post by restingwitchface »

I've gotten exceptions working for i686, here's my stub for it:

Code: Select all

.macro isr vec
.global _isr_\vec
.type _isr_\vec, @function

_isr_\vec:
	pushal
	cld
	call isr_\vec
	popal
	iret
.endm
So I've worked on porting everything in my OS so far to x86_64, and it mostly works, except I for some reason get a page fault on iret. Here's my stub:

Code: Select all

/* Doesn't save SSE/SSE2/MMX state, but we don't use that in the kernel anyways. */
.macro pushaq
	pushq %rax
	[...]
	pushq %r15
.endm

.macro popaq
	popq %r15
	[...]
	popq %rax
.endm

.macro isr vec
.global _isr_\vec
.type _isr_\vec, @function

_isr_\vec:
pushaq
	cld
	call isr_\vec
popaq
	iret
.endm
With gdb (setting a breakpoint at the ISR's first and last instruction) I verified that RSP is the same on entry and exit from the interrupt, so it's not trying to restore some junk state:

Code: Select all

(gdb) print $rsp
$1 = (void *) 0xffffc00000187f88
(gdb) c
Continuing.
(gdb) print $rsp
$2 = (void *) 0xffffc00000187f88
Here's the section of the QEMU logs containing the original interrupt (keyboard, 0x21) and the following page fault:

Code: Select all

Servicing hardware INT=0x21
     0: v=21 e=0000 i=0 cpl=0 IP=0008:ffffc000000007c0 pc=ffffc000000007c0 SP=0010:ffffc00000187fb0 env->regs[R_EAX]=0000000000000000
RAX=0000000000000000 RBX=ffffc00000100010 RCX=ffffc00000100120 RDX=00000000000003f8
RSI=000000000000000a RDI=0000000000000020 RBP=ffffc00000187ff0 RSP=ffffc00000187fb0
R8 =cccccccccccccccd R9 =ffffc000001989b1 R10=0000000000000000 R11=0000000000000000
R12=ffffc00000000a30 R13=ffffc00000000a80 R14=ffffc00000080052 R15=ffffc000000012a0
RIP=ffffc000000007c0 RFL=00000246 [---Z-P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 0000000000000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
CS =0008 0000000000000000 ffffffff 00af9b00 DPL=0 CS64 [-RA]
SS =0010 0000000000000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
DS =0010 0000000000000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
FS =0010 0000000000000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
GS =0010 0000000000000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
LDT=0000 0000000000000000 0000ffff 00008200 DPL=0 LDT
TR =0000 0000000000000000 0000ffff 00008b00 DPL=0 TSS64-busy
GDT=     0000000000200010 00000017
IDT=     ffffc00000188fe0 00000fff
CR0=80000011 CR2=0000000000000000 CR3=0000000000203000 CR4=00000020
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000 
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=0000000000000044 CCD=0000000000000000 CCO=EFLAGS
EFER=0000000000000500
check_exception old: 0xffffffff new 0xe
     1: v=0e e=0000 i=0 cpl=0 IP=0008:ffffc00000000069 pc=ffffc00000000069 SP=0010:ffffc00000187f88 CR2=0000000000187f88
RAX=0000000000000000 RBX=ffffc00000100010 RCX=ffffc00000100120 RDX=00000000000003f8
RSI=000000000000000a RDI=0000000000000020 RBP=ffffc00000187ff0 RSP=ffffc00000187f88
R8 =cccccccccccccccd R9 =ffffc000001989b1 R10=0000000000000000 R11=0000000000000000
R12=ffffc00000000a30 R13=ffffc00000000a80 R14=ffffc00000080052 R15=ffffc000000012a0
RIP=ffffc00000000069 RFL=00000097 [--S-APC] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 0000000000000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
CS =0008 0000000000000000 ffffffff 00af9b00 DPL=0 CS64 [-RA]
SS =0010 0000000000000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
DS =0010 0000000000000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
FS =0010 0000000000000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
GS =0010 0000000000000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
LDT=0000 0000000000000000 0000ffff 00008200 DPL=0 LDT
TR =0000 0000000000000000 0000ffff 00008b00 DPL=0 TSS64-busy
GDT=     0000000000200010 00000017
IDT=     ffffc00000188fe0 00000fff
CR0=80000011 CR2=0000000000187f88 CR3=0000000000203000 CR4=00000020
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000 
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=0000000000000008 CCD=fffffffffffffff9 CCO=SUBB
EFER=0000000000000500
And here's the QEMU monitor's paging information (you'll notice I was too lazy to remove the VGA text buffer's identity mapping :P):

Code: Select all

(qemu) info mem
00000000000b8000-00000000000b9000 0000000000001000 -rw
0000000000200000-0000000000201000 0000000000001000 -rw
ffffc00000000000-ffffc00000002000 0000000000002000 -rw
ffffc00000080000-ffffc00000081000 0000000000001000 -rw
ffffc00000100000-ffffc00000101000 0000000000001000 -rw
ffffc00000180000-ffffc0000018b000 000000000000b000 -rw
ffffc00000200000-ffffc00000201000 0000000000001000 -rw
ffffff8000000000-ffffff8000002000 0000000000002000 -rw
ffffffe000000000-ffffffe000002000 0000000000002000 -rw
ffffffffc0000000-ffffffffc0001000 0000000000001000 -rw
fffffffff0000000-fffffffff0001000 0000000000001000 -rw
ffffffffffe00000-ffffffffffe01000 0000000000001000 -rw
fffffffffff80000-fffffffffff81000 0000000000001000 -rw
fffffffffffff000-0001000000000000 0000000000001000 -rw
Does anybody know what's going on here? Again, this all works fine on 32-bit. As you can see, the address it's trying to access here seems to be 0x187f88: I have no idea where that comes from...
she/her, please.

Don't flirt with me.
Oderint dum metuant.
GPG fingerprints:

Code: Select all

b16598566a5124946d87279fbc2d2dd299af811e (encryption)
b504ba54c5c164257156f53a32409b59258453e0 (signing)
User avatar
iansjack
Member
Member
Posts: 4908
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Page fault on iret?

Post by iansjack »

Try using “iretq” instead of “iret”.
User avatar
restingwitchface
Posts: 22
Joined: Sat Nov 02, 2024 2:58 pm
GitHub: https://github.com/NyxNeptune

Re: Page fault on iret?

Post by restingwitchface »

Thanks, that works!
In your Interrupt Service Routines, remember to return from the interrupt using the IRETQ instruction instead of IRET, as assemblers will not translate that for you. Many 64-bit IDT related problems on the forum are caused by that missing 'Q'. Don't let this happen to you.
Oops! Only now seeing this paragraph right below the 64-bit IDT structure I was reading...

What's the difference? I guess Intel was too lazy to make iret invalid in 64-bit (like they did with pusha) and have it still use the 32-bit interrupt structure.
she/her, please.

Don't flirt with me.
Oderint dum metuant.
GPG fingerprints:

Code: Select all

b16598566a5124946d87279fbc2d2dd299af811e (encryption)
b504ba54c5c164257156f53a32409b59258453e0 (signing)
User avatar
iansjack
Member
Member
Posts: 4908
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Page fault on iret?

Post by iansjack »

“iret” is still valid in 64-bit mode, but it indicates the use of 32-bit arguments. It would have worked if your kernel was not higher-half.
Octocontrabass
Member
Member
Posts: 6247
Joined: Mon Mar 25, 2013 7:01 pm

Re: Page fault on iret?

Post by Octocontrabass »

restingwitchface wrote: Fri Oct 03, 2025 1:18 pmWhat's the difference?
Instructions that allow both 32-bit and 64-bit operands default to 32-bit if you don't specify otherwise. If you just write "iret" you get "iretl" instead of "iretq".
restingwitchface wrote: Fri Oct 03, 2025 1:18 pmI guess Intel was too lazy to make iret invalid in 64-bit (like they did with pusha) and have it still use the 32-bit interrupt structure.
It would've been AMD, and I don't think they ever explained their reasoning. I would guess they saw "iretw" being useful somewhere in 32-bit code and figured "iretl" might be useful in 64-bit code.
iansjack wrote: Fri Oct 03, 2025 1:26 pmIt would have worked if your kernel was not higher-half.
Would it? I thought the stack layout depended on the operand size...
User avatar
iansjack
Member
Member
Posts: 4908
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Page fault on iret?

Post by iansjack »

My mistake. I thought the page fault was caused by the “iret” instruction only using the lower 32 bits of RSP so that it never got to see the stack frame.

I didn’t mean to imply that there wouldn’t be further errors.
Post Reply