ISR GPF Loop, IRQs Fine...

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
dega512
Posts: 4
Joined: Mon Jan 14, 2008 11:35 am

ISR GPF Loop, IRQs Fine...

Post by dega512 »

My title pretty much gives away my problem. Whenever my general ISR handler is called, it ends up causing a GPF (then when when it is called for the GPF, it causes a GPF, and thus the GPF cycle starts). I looked around the forums and I noticed other people had inifite GPF loops and an eventual triple fault/video corruption (probably from some sort of stack overrun would be my guess), but none of the problems were exactly like mine (a GPF is caused at the end of the ISR handler).

Here is my asm handler for ISRs:

Code: Select all

; This macro creates a 'stub' for an ISR that does not
; push its own error code, a dummy error code (0) is used instead.
; NOTE: The general handler expects the interrupt number
; and error code on the stack.
%macro ISR_STUB_NOERRORCODE 1
	[GLOBAL isr%1]
	isr%1:
		cli					; disable interrupts
		push 0				; push a dummy error code
		push dword %1		; push the interrupt number
		jmp common_stub_isr	; use the common ISR handler to handle this ISR
%endmacro

; This macro creates a 'stub' for an ISR that pushes its own error code.
; NOTE: The general handler expects the interrupt number
; and error code on the stack.
%macro ISR_STUB 1
	[GLOBAL isr%1]
	isr%1:
		cli					; disable interrupts
		push dword %1		; push the interrupt number
		jmp common_stub_isr	; use the common ISR handler to handle this ISR
%endmacro

...

; set up the ISR/IRQ stubs
ISR_STUB_NOERRORCODE	0
ISR_STUB_NOERRORCODE	1

...

; a C function that writes a string to the console
[EXTERN debugconsole_writeline]

fmt: db 'AD', 0  ; Acronym for 'Assembly-Done', I print this out for debugging...

; Common ISR stub that saves all needed information to the stack then calls
; the C handler.
common_stub_isr:
	pusha                    ; pushes edi, esi, ebp, esp, ebx, edx, ecx, eax
	
	xor eax, eax
	mov ax, ds               ; save the data segment descriptor
	push eax                 ; ...

	; The kernel data segment is the 3rd gdt entry (index 2),
	; each of which is 8 bytes.  Thus its offfset is (2 * 8) = 16
	; which is 0x10 in hex.
	;
	; We need to update all of the segment registers to reflect this.
	; 
	; For now, these registers are always 0x10 (this is setup when
	; the GDT is created, and hasn't been touched since; which
	; technically makes this code redundant).
	mov ax, 0x10
	mov ds, ax
	mov es, ax
	mov fs, ax
	mov gs, ax
	
	call IsrHandler	; call C code
	
	; print a notification to the screen saying we got this far
	; NOTE: This does result in 'AD' being printed to the screen.
	push fmt
	call debugconsole_writeline
	add esp, 4
	
	pop eax		; reload the original segment descriptors
	mov ds, ax
	mov es, ax
	mov fs, ax
	mov gs, ax
	
	; print a notification to the screen saying we got this far
	; Starting here, AD is no longer printed (which is why
	; I have come to believe the code above is the culprit)
	push fmt
	call debugconsole_writeline
	add esp, 4
	
	popa		; pops edi, esi, ebp, esp, eb, edx, ec, eax
	add esp, 8	; cleans up the pushed error code and ISR number
	
	; print a notification to the screen saying we got this far
	push fmt
	call debugconsole_writeline
	add esp, 4
	
	sti		; enable interrupts
	
	iret		; pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP

I would expect three sets of the string 'AD' to be printed on the screen, but that isn't the case, I only get one.

So my guess is that my problem lies in:

Code: Select all

	pop eax		; reload the original data segment descriptor
	mov ds, ax
	mov es, ax
	mov fs, ax
	mov gs, ax
Although to me I don't see why this could cause an error.... Also, an interesting thing to note is that my general IRQ handler uses almost identical code (the difference in them is that they call different C functions, and the IRQ function sends the EOI signal to the PICs), yet it doesn't have this problem....

I would greatly appreciate it if someone could send me in the right direction as far as where to hunt some bugs!

Thanks!
There is too much blood in my caffeine stream...
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Post by Combuster »

I invite you to grab bochs' debugger and find the exact instruction that is causing your problem. You may find the bug in the process as well.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
dega512
Posts: 4
Joined: Mon Jan 14, 2008 11:35 am

Post by dega512 »

Ok after some debugging with Qemu and GDB (I gave up on compiling Bochs with debugging support, I got way too many errors; but I have to say I love that I now have a debugger of some sort :) ) I've discovered that my GPF occurs at:

Code: Select all

...

call IsrHandler   ; call C code 

...

pop eax      ; reload the original segment descriptors   <-- value of EAX after this is 0x10
mov ds, ax  <-- GPF
mov es, ax
mov fs, ax
mov gs, ax 
What I don't understand is that there is code above it that is nearly identical (shown below) that doesn't cause a GPF....

Code: Select all

; The kernel data segment is the 3rd gdt entry (index 2),
; each of which is 8 bytes.  Thus its offfset is (2 * 8) = 16
; which is 0x10 in hex.
;
; We need to update all of the segment registers to reflect this.
;
; For now, these registers are always 0x10 (this is setup when
; the GDT is created, and hasn't been touched since; which
; technically makes this code redundant).
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax 
My flags byte for my IDT entries are 10001110 (Present, Ring Level 0) and have the kernel code selector 0x8, so I don't think my GPF has to do with the privileges of my code (especially since the almost identical code doesn't cause a GPF).

Why might the "mov ds, ax" that I marked cause a GPF?
There is too much blood in my caffeine stream...
User avatar
suthers
Member
Member
Posts: 672
Joined: Tue Feb 20, 2007 3:00 pm
Location: London UK
Contact:

Post by suthers »

Do you know what the content of your ax register is when you move it to ds, It looks like you probably have a problem with your stack frame and that your popping the wrong value into ax....
Make sure you have a pop for every push (I'm re-doing my isr right now so I'm experiencing similar problems... )
Jules
jnc100
Member
Member
Posts: 775
Joined: Mon Apr 09, 2007 12:10 pm
Location: London, UK
Contact:

Post by jnc100 »

In theory, as you've pushed eax before the C function and pop it immediately afterwards, then there shouldn't be a problem unless the C function messes up you stack. One way it could do this is if the function IsrHandler expects arguments and using a calling convention where the callee does stack clean-up.

As a side issue, you don't need to do an sti before an iret (look up interrupt and trap gates in the intel manuals).

Regards,
John.
User avatar
suthers
Member
Member
Posts: 672
Joined: Tue Feb 20, 2007 3:00 pm
Location: London UK
Contact:

Post by suthers »

To jnc100:
That's exactly what I was thinking, I suspect that one of the functions he called messed up his stack...
Jules
Post Reply