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.
I just finished re-setting up my exception handler, so I tried testing it by purposely dividing by 0. That works fine, but if I try to do anything else after that, I get a General Protection Fault. What could I be doing wrong, or will I have to post code?
There are two possible causes. The first one (the probably one actually) is that there's a problem with your handler, so that it causes a GPF when it returns... or something like that.
Also, IIRC divide by zero is an abort, which means you shouldn't try to resume the code that caused it..
%macro ISTUB 1
PUSH GS
PUSH FS
PUSH ES
PUSH DS
PUSHAD
MOV AX, SYS_DATA_SEL
MOV DS, EAX
MOV ES, EAX
MOV FS, EAX
MOV GS, EAX
; Why does it work when I comment these?
;MOV EAX, %1
;PUSH EAX ; Pass the interrupt # to the Kernel Interrupt Handler
CALL _InterruptHandler
;Do I have to pop them after the C function?
POPAD
POP DS
POP ES
POP FS
POP GS
ADD ESP, 8
IRET
%endmacro
; Why does it work when I comment these?
;MOV EAX, %1
;PUSH EAX ; Pass the interrupt # to the Kernel Interrupt Handler
The reason it works without that is because you don't pop it afterwards. And yes that answers the other question, C/C++ functions do not pop their own parameters, in a standard C call the parameters are pushed and popped by the caller.
Also with these interrupt handlers, be aware that the parameters are not meant to be popped (The compiler usually puts ADD ESP, X to simply delete them) so be aware of that. I had an interesting experience with compiler optimizations where the compiler decided to completely override the parameters since they weren't used in the function which naturally made a big mess when I tried to pop the segment registers [GPF which is incidentally what is happening here, you were popping an invalid value for the segment registers].
%macro ISTUB 1
PUSH GS
PUSH FS
PUSH ES
PUSH DS
PUSHAD
MOV EAX, SYS_DATA_SEL
MOV DS, EAX
MOV ES, EAX
MOV FS, EAX
MOV GS, EAX
PUSH %1 ; Pass the interrupt # to the Kernel Interrupt Handler
CALL _InterruptHandler
ADD ESP, 4 ;Delete PUSH %1 value
POPAD
POP DS
POP ES
POP FS
POP GS
ADD ESP, 8
IRET
%endmacro
How you use this code would be useful, I am a bit confused by the last part ( ADD ESP, 8 ) being in a macro. Are you adding this code as is to the IDT or is there a stub that jumps to it?
In Bochs I recommend inserting "hlt; nop" pairs to let you step through it and print the stack as it goes to see where it messes up.
I haven't actually tried using Bochs yet, I've been using GRUB to boot up and I really don't feel like waiting for Bochs it to boot from floppy etc... right now I have a test rig with GRUB installed on the hard drive, so all I have to do is insert the floppy and turn the computer on.
This is the code I have so far for the ISR:
It finally does not reboot the computer, but I still get a full screen of GPFs, then after about a minute, the screen turns white! :S
That's why people don't use real floppies and use floppy disk images instead.
Ok, I see now, you've made a mess of your stack, remove the ADD ESP, 8 and it may work, some exception handlers have error codes (like page fault, GPF, TSS, etc) which do require an ADD ESP, 4 at the end however.
Divide error doesn't push an error code on the stack, so you don't need the "ADD ESP, 8"
Anyway, for exceptions that DO push an error code, you want to use "ADD ESP, 4"
The next problem you encounter may be an infinite loop of exceptions. Divide error is a fault, so the IRET returns to the instruction that caused it -- which immediately causes another divide error. (Hmmm, try it and see...could be amusing :)
Darn it, just when I thought everything was fixed and good, I opened up the source code, replaced the divide by 0 with an INT 0x1E to test my system call and it still says that it is a divide by 0. This interrupt stuff is really confusing! :S
How does the interrupt handler get a zero from 0x1E?
might you have something broken in your compilation code ?
moreover, as you have previously removed the part that passes the interrupt code to the C code, i'm not surprised that all interrupts appears as a single one