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.
Hi.
I wrote a handler for the page fault exception, but suddenly found that the error code I get from the stack is not always the same in the same cases(I restarted the kernel and the error code was different, including the P RW US bits).
I got the value from the stack using an assembler insert in the handler in C(Yes, I know how stupid this is, I didn't take into account the stack change after starting the C function).
Now I was trying to copy the error code to some general-purpose register in an assembler handler.
It looked like this:
So you push all registers, pop what was in edi into edx, call some routine then do an interrupt return without restoring the stack. Under these conditions a crash is expected behaviour.
popa was always present, so it should be in the handler before calling the C function.
And pop eax according to my idea should save the error code in eax.
Last edited by mrjbom on Fri Jul 03, 2020 4:11 pm, edited 1 time in total.
iansjack wrote:So you push all registers, pop what was in edi into edx, call some routine then do an interrupt return without restoring the stack. Under these conditions a crash is expected behaviour.
The code is nearly correct, but it clobbers the eax register, and it doesn't remove the error code from the stack.
If you wish to preserve the value of eax you should push all registers then read the value of the error code directly from the appropriate position on the stack. Remember that the stack is just a series of memory locations so you can read/write its values directly (with an offset[%esp] instruction) instead of using pop/push. Also, remember to remove the error code from the stack before you return from the interrupt.
iansjack wrote:The code is nearly correct, but it clobbers the eax register, and it doesn't remove the error code from the stack.
If you wish to preserve the value of eax you should push all registers then read the value of the error code directly from the appropriate position on the stack. Remember that the stack is just a series of memory locations so you can read/write its values directly (with an offset[%esp] instruction) instead of using pop/push. Also, remember to remove the error code from the stack before you return from the interrupt.
page_fault:
;save error code from stack to eax
pop eax
;return error code to stack
push eax
;save all 32bit registers
pushad
call page_fault_handler
;return all 32bit registers
popad
iretd
(in all interrupts, I also replaced pusha, popa, iret with functions for bit mode(added d))
I don't fully understand how I can remove the error code from the stack at the end of the handler... if I make pop %eax to delete before popad, then popad will restore the esp and it will reference the wrong place...
Note that it passes the structure as a pointer. It cleans up the error code and interrupt number by adding 8 to esp. The D isn't necessary. NASM will translate. (It won't in 64 bit mode, but that is irrelevant.) I include the D for verbosity's purposes.
"How did you do this?"
"It's very simple — you read the protocol and write the code." - Bill Joy
Projects: NexNix | libnex | nnpkg
Note that it passes the structure as a pointer. It cleans up the error code and interrupt number by adding 8 to esp. The D isn't necessary. NASM will translate. (It won't in 64 bit mode, but that is irrelevant.) I include the D for verbosity's purposes.
Exactly, I forgot that it is desirable to disable interrupts while the interrupt handler is running.
Now my handler looks like this, I only clear the error code with add esp, 4.
Is that correct?
page_fault:
cli
;save error code from stack to eax
pop eax
;return error code to stack
push eax
;save all 32bit registers
pushad
call page_fault_handler
;return all 32bit registers
popad
;delete error code from stack
add esp, 4
sti
iretd
Yes, that looks good. Are using the registers as a structure in your C handler? If so, then it is good idea to pass the structure by pointer. Right before you call the function, you would do something like this
nexos wrote:Yes, that looks good. Are using the registers as a structure in your C handler? If so, then it is good idea to pass the structure by pointer. Right before you call the function, you would do something like this
No. You're still clobbering EAX. If you want to pass the error code to the function you're calling in a register, you need to read it from the stack after PUSHAD, using an instruction like "mov eax, [esp+32]". (How are you passing arguments to a C function in registers? The System V ABI uses the stack to pass arguments.)
You're also using CLI/STI, which is unnecessary. If you want to disable interrupts, set up your IDT so that this entry uses an interrupt gate.
No. You're still clobbering EAX. If you want to pass the error code to the function you're calling in a register, you need to read it from the stack after PUSHAD, using an instruction like "mov eax, [esp+32]"
Yes, exactly...
I changed the code like this:
But now the exception is looped, even though it shouldn't be... Did I do something wrong? After all, now registers are not damaged.