Hi,
This is a (subtle) bug
.
If the CPU receives an IRQ after starting the page fault handler but before the "
CLI" is executed, then a second page fault (that occurs while the IRQ is being handled) will overwrite CR2.
To avoid this use an "interrupt gate" rather than a "trap gate", so that the CPU automatically disables interrupts while starting the page fault handler.
You may also need to pass the error code from the exception to the C handler (for e.g. so you can handle things differently if the kernel caused the page fault, or check if it was a "page not present" or an "access denied").
Further, eventually the page fault handler may need to read data from disk (e.g. from the swap). This means that interrupts will need to be enabled at some point during the execution of the page fault handler. For the sake of reduced interrupt latency you might as well do it as soon as you can.
Combining all of the above results in using an "interrupt gate" that looks something like:
Code: Select all
isr14:
pushl %eax
movl %cr2,%eax ;eax = accessed address
pushl %ebx
movl 8(%esp),%ebx ;ebx = error code
sti ;re-enable interrupts
pushl %ecx
pushl %edx
pushl %eax ;put address on stack (parameter 1)
pushl %ebx ;put error code on stack (parameter 2)
call mm_page_fault_handler
sub $8,%esp ;remove both parameters from the stack
popl %edx
popl %ecx
popl %ebx
popl %eax
addl %esp, $4 ;remove CPU's error code from stack
iret
I'm not too sure what order C uses for parameters, but the C function would be:
void mm_page_fault_handler(unsigned int error_code, void *address);
Or:
void mm_page_fault_handler(void *address, unsigned int error_code);
I'm also not too good with AT&T syntax either, but I think the "
8(%esp)" is right (in Intel syntax it's "
[esp+8]"). Hopefully it's enough to give you the general idea....
Cheers,
Brendan