Page 1 of 1

old error back again

Posted: Fri May 06, 2005 9:30 am
by Poseidon
A long time ago, I had problems with a page fault... something creates a page fault, and when the page fault irets, I get a triple fault... can't remember how I fixed it, but I just discovered the error was back again :(

Anyone ideas what the error could cause?

Here is the code that calls the pagefaulthandler:

Code: Select all

isr14:   cli
   
   pushl %eax
   pushl %ebx
   pushl %ecx
   pushl %edx
   
   call mm_page_fault_handler
   
   popl %edx
   popl %ecx
   popl %ebx
   popl %eax
   
   iret
Thanks :)

Re:old error back again

Posted: Fri May 06, 2005 10:05 am
by Zorro
Hello Poseidon!

I think this will solve your problems:

Code: Select all

isr14:   cli
   
   pushl %eax
   pushl %ebx
   pushl %ecx
   pushl %edx
   mov %esp %ebp
   
   call mm_page_fault_handler
   
   mov %ebp %esp
   popl %edx
   popl %ecx
   popl %ebx
   popl %eax
   
   addl %esp, $4
   iret

Re:old error back again

Posted: Fri May 06, 2005 11:43 am
by Poseidon
i edited it a bit, and now it works... thanks :)

Re:old error back again

Posted: Sun May 08, 2005 12:48 am
by Neo
Edited which? The code that "Zorro" posted?

Re:old error back again

Posted: Sun May 08, 2005 1:51 am
by Brendan
Hi,

Code: Select all

isr14:
   cli
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

Re:old error back again

Posted: Sun May 08, 2005 2:05 am
by Colonel Kernel
According to most C calling conventions I know of, parameters are pushed from right to left, so it's your first prototype.

Re:old error back again

Posted: Sun May 08, 2005 3:15 pm
by Poseidon
Thanks all :)