[SOLVED] Page fault upon PIT interrupt in ring 3

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
avcado
Member
Member
Posts: 55
Joined: Wed Jan 20, 2021 11:32 am
GitHub: https://codeberg.org/minguss

[SOLVED] Page fault upon PIT interrupt in ring 3

Post by avcado »

Hi. Today I finally got ring 3 sort-of working. I can load a flat binary (ELF soon...), however, upon ani INT 0x20 interrupt, I get a page fault. Here is the QEMU interrupt trace:

Code: Select all

Servicing hardware INT=0x20
    32: v=20 e=0000 i=0 cpl=0 IP=0008:00201155 pc=00201155 SP=0010:0020aff2 env->regs[R_EAX]=0000029e
EAX=0000029e EBX=00000800 ECX=fd10a400 EDX=fd10a69d
ESI=00000002 EDI=00203baa EBP=0020b002 ESP=0020aff2
EIP=00201155 EFL=00200283 [--S---C] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
CS =0008 00000000 ffffffff 00cf9a00 DPL=0 CS32 [-R-]
SS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
DS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
FS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
GS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0028 e8e86ae8 000d006b 000d8900 DPL=0 TSS32-avl
GDT=     00202c15 0000002f
IDT=     0020b600 000007ff
CR0=80000011 CR2=00000000 CR3=0020d000 CR4=00000000
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000 
DR6=ffff0ff0 DR7=00000400
CCS=00000081 CCD=fffff89e CCO=EFLAGS
EFER=0000000000000000
Servicing hardware INT=0x20
    33: v=20 e=0000 i=0 cpl=3 IP=001b:00401005 pc=00401005 SP=0023:0020b116 env->regs[R_EAX]=deadbeef
EAX=deadbeef EBX=00000800 ECX=fd121600 EDX=00000000
ESI=00000002 EDI=00203baa EBP=0020b1b2 ESP=0020b116
EIP=00401005 EFL=00200202 [-------] CPL=3 II=0 A20=1 SMM=0 HLT=0
ES =0023 00000000 ffffffff 00cff300 DPL=3 DS   [-WA]
CS =001b 00000000 ffffffff 00cffa00 DPL=3 CS32 [-R-]
SS =0023 00000000 ffffffff 00cff300 DPL=3 DS   [-WA]
DS =0023 00000000 ffffffff 00cff300 DPL=3 DS   [-WA]
FS =0023 00000000 ffffffff 00cff300 DPL=3 DS   [-WA]
GS =0023 00000000 ffffffff 00cff300 DPL=3 DS   [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0028 e8e86ae8 000d006b 000d8900 DPL=0 TSS32-avl
GDT=     00202c15 0000002f
IDT=     0020b600 000007ff
CR0=80000011 CR2=00000000 CR3=0020d000 CR4=00000000
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000 
DR6=ffff0ff0 DR7=00000400
CCS=00000000 CCD=0020b11a CCO=EFLAGS
EFER=0000000000000000
check_exception old: 0xffffffff new 0xe
    34: v=0e e=0000 i=0 cpl=3 IP=001b:00401005 pc=00401005 SP=0023:0020b116 CR2=e8e86aec
EAX=deadbeef EBX=00000800 ECX=fd121600 EDX=00000000
ESI=00000002 EDI=00203baa EBP=0020b1b2 ESP=0020b116
EIP=00401005 EFL=00200202 [-------] CPL=3 II=0 A20=1 SMM=0 HLT=0
ES =0023 00000000 ffffffff 00cff300 DPL=3 DS   [-WA]
CS =001b 00000000 ffffffff 00cffa00 DPL=3 CS32 [-R-]
SS =0023 00000000 ffffffff 00cff300 DPL=3 DS   [-WA]
DS =0023 00000000 ffffffff 00cff300 DPL=3 DS   [-WA]
FS =0023 00000000 ffffffff 00cff300 DPL=3 DS   [-WA]
GS =0023 00000000 ffffffff 00cff300 DPL=3 DS   [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0028 e8e86ae8 000d006b 000d8900 DPL=0 TSS32-avl
GDT=     00202c15 0000002f
IDT=     0020b600 000007ff
CR0=80000011 CR2=e8e86aec CR3=0020d000 CR4=00000000
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000 
DR6=ffff0ff0 DR7=00000400
CCS=00000000 CCD=0020b11a CCO=EFLAGS
EFER=0000000000000000
User mode code (located at 0x401000) looks like:

Code: Select all

MOV EAX, 0xDEADBEEF
JMP $
I suspect this occurs in my interrupt stub handler, which looks like this:

Code: Select all

stub:
	pusha

	mov edi, esp
	push edi
	
	call int_handler

	pop edi
 	popa

	add esp, 8
 	iret
The add esp, 8 is needed here since esp, coming out of popa looks like this

Code: Select all

(gdb) print $esp
$1 = (void*) 0x20b04e
(gdb) print *0x20b04e
$2 = 32
(gdb) print *(0x20b04e+4)
$3 = 0
which corresponds to IRQ0 and no error code, [esp+8] is EIP. It's worth nothing that this issue does not occur outside of user-mode, and removing add esp, 8 causes a GPF at the IRET instruction (duh...)

Lastly, page tables look like this:

Code: Select all

00000000000b8000-00000000000b9000 0000000000001000 -rw   <--- video memory
0000000000109000-000000000010b000 0000000000002000 -rw   <--- multiboot's stuff (used to load initrd)
0000000000200000-000000000021a000 000000000001a000 -rw   <--- kernel space
0000000000401000-0000000000402000 0000000000001000 urw   <--- user space
What is happening here? I am happy to provide more code if needed.
Thanks in advance!!
Last edited by avcado on Sun Aug 17, 2025 5:49 pm, edited 1 time in total.
Octocontrabass
Member
Member
Posts: 6245
Joined: Mon Mar 25, 2013 7:01 pm

Re: Page fault upon PIT interrupt in ring 3

Post by Octocontrabass »

avcado wrote: Sun Aug 17, 2025 4:23 pm

Code: Select all

CR2=e8e86aec
TR =0028 e8e86ae8 000d006b 000d8900 DPL=0 TSS32-avl
It's a page fault when the CPU tries to access your TSS. Are you sure your TSS is set up correctly?
avcado
Member
Member
Posts: 55
Joined: Wed Jan 20, 2021 11:32 am
GitHub: https://codeberg.org/minguss

Re: Page fault upon PIT interrupt in ring 3

Post by avcado »

Octocontrabass wrote: Sun Aug 17, 2025 5:18 pm
avcado wrote: Sun Aug 17, 2025 4:23 pm

Code: Select all

CR2=e8e86aec
TR =0028 e8e86ae8 000d006b 000d8900 DPL=0 TSS32-avl
It's a page fault when the CPU tries to access your TSS. Are you sure your TSS is set up correctly?
Unfortunately, I'm not sure. I had originally written my GDT in assembly, and I didn't feel like porting the entire thing to C, so I tried to write the TSS part in Assembly aswell:

the TSS:

Code: Select all

; NOTE: stack_top is defined in my boot stub as kernel stack
tss:
	dd 0          ;; Link
	dd stack_top  ;; ESP0
	dd 0x10       ;; SS0
	times 22 dd 0
	dw 0
	dw 104        ;; IOPB
	dd 0
which is then loaded into the GDT like this:

Code: Select all

gdt:
	...
	.tss:
		dw 0x006b     ;; Limit: Sizeof(TSS)-1
		dw 0x0000     ;; Base, &TSS - set at runtime.
		db 0x00       ;; Base again
		db 0b10001001 ;; Access byte
		db 0b00001101 ;; WARN: limit is 0b1101011, but you can't fit that into 4 bits
		db 0x00       ;; Base

...

load_gdt:
	;; i have to do this at runtime because i'd
	;; rather not have to port this entire file to C.
	mov edx, tss
	mov [gdt+(5*8)+2], dx ;; Base = &TSS
	mov [gdt+(5*8)+4], dl
	mov [gdt+(5*8)+7], dl

	lgdt [gdtr]
	jmp CODESEL32:.flush
I do flush the TSS after loading both the GDT and IDT, flushing looks like:

Code: Select all


[global flush_tss]
flush_tss:
	mov ax, (5*8) | 0
	ltr ax
	ret
projects: minguss/skvn
Octocontrabass
Member
Member
Posts: 6245
Joined: Mon Mar 25, 2013 7:01 pm

Re: Page fault upon PIT interrupt in ring 3

Post by Octocontrabass »

avcado wrote: Sun Aug 17, 2025 5:22 pm

Code: Select all

		db 0b00001101 ;; WARN: limit is 0b1101011, but you can't fit that into 4 bits
This byte should contain the upper 4 bits (16 through 19) of the 20-bit limit. You're setting it to bits 3 through 6 of the limit.
avcado wrote: Sun Aug 17, 2025 5:22 pm

Code: Select all

	mov [gdt+(5*8)+4], dl
	mov [gdt+(5*8)+7], dl
These two bytes should contain the upper 16 bits of the 32-bit base. You're setting them both to the lower 8 bits of the base.
avcado
Member
Member
Posts: 55
Joined: Wed Jan 20, 2021 11:32 am
GitHub: https://codeberg.org/minguss

Re: Page fault upon PIT interrupt in ring 3

Post by avcado »

Octocontrabass wrote: Sun Aug 17, 2025 5:34 pm This byte should contain the upper 4 bits (16 through 19) of the 20-bit limit. You're setting it to bits 3 through 6 of the limit.
If i understand this correct, since the limit is sizeof(TSS)-1, which is 0x6B, which is 0b1101011, would that just be 0b0000 for the limit, i.e.

Code: Select all

	db 0b0000_0000
Octocontrabass wrote: Sun Aug 17, 2025 5:34 pm These two bytes should contain the upper 16 bits of the 32-bit base. You're setting them both to the lower 8 bits of the base.
I'm guessing this means

Code: Select all

shr edx, 16
mov [gdt+(5*8)+4], dh
mov [gdt+(5*8)+7], dl
Correct me if I'm wrong, and thank you for your help!
projects: minguss/skvn
Octocontrabass
Member
Member
Posts: 6245
Joined: Mon Mar 25, 2013 7:01 pm

Re: Page fault upon PIT interrupt in ring 3

Post by Octocontrabass »

avcado wrote: Sun Aug 17, 2025 5:41 pm

Code: Select all

	db 0b0000_0000
Correct.
avcado wrote: Sun Aug 17, 2025 5:41 pm

Code: Select all

shr edx, 16
mov [gdt+(5*8)+4], dh
mov [gdt+(5*8)+7], dl
I think you've got DL and DH backwards.
Post Reply