fix O_RDWR bug.
[mit-jos.git] / lib / pfentry.S
blob914a207c34f73435695b04175b26b58a3cd9112d
1 #include <inc/mmu.h>
2 #include <inc/memlayout.h>
5 // Page fault upcall entrypoint.
7 // This is where we ask the kernel to redirect us to whenever we cause
8 // a page fault in user space (see the call to sys_set_pgfault_handler
9 // in pgfault.c).
11 // When a page fault actually occurs, the kernel switches our ESP to
12 // point to the user exception stack if we're not already on the user
13 // exception stack, and then it pushes a UTrapframe onto our user
14 // exception stack:
16 //      trap-time esp
17 //      trap-time eflags
18 //      trap-time eip
19 //      utf_regs.reg_eax
20 //      ...
21 //      utf_regs.reg_esi
22 //      utf_regs.reg_edi
23 //      utf_err (error code)
24 //      utf_fault_va            <-- %esp
26 // If this is a recursive fault, the kernel will reserve for us a
27 // blank word above the trap-time esp for scratch work when we unwind
28 // the recursive call.
30 // We then have call up to the appropriate page fault handler in C
31 // code, pointed to by the global variable '_pgfault_handler'.
33 .text
34 .globl _pgfault_upcall
35 _pgfault_upcall:
36         // Call the C page fault handler.
37         pushl %esp                      // function argument: pointer to UTF
38         movl _pgfault_handler, %eax
39         call *%eax
40         addl $4, %esp                   // pop function argument
41         
42         // Now the C page fault handler has returned and you must return
43         // to the trap time state.
44         // Push trap-time %eip onto the trap-time stack.
45         //
46         // Explanation:
47         //   We must prepare the trap-time stack for our eventual return to
48         //   re-execute the instruction that faulted.
49         //   Unfortunately, we can't return directly from the exception stack:
50         //   We can't call 'jmp', since that requires that we load the address
51         //   into a register, and all registers must have their trap-time
52         //   values after the return.
53         //   We can't call 'ret' from the exception stack either, since if we
54         //   did, %esp would have the wrong value.
55         //   So instead, we push the trap-time %eip onto the *trap-time* stack!
56         //   Below we'll switch to that stack and call 'ret', which will
57         //   restore %eip to its pre-fault value.
58         //
59         //   In the case of a recursive fault on the exception stack,
60         //   note that the word we're pushing now will fit in the
61         //   blank word that the kernel reserved for us.
62         //
63         // Hints:
64         //   What registers are available for intermediate calculations?
65         //
66         // ignore 'fault_va' and 'tf_err'
67         addl $8, %esp
68         // store the current esp
69         movl %esp, %ebx
70         // store trap-time esp
71         movl 40(%esp), %ecx
72         // store trap-time eip
73         movl 32(%esp), %edx
74         // change to trap-time esp
75         movl %ecx, %esp
76         // push trap-time eip to the trap-time stack
77         pushl %edx
78         // back to the user exception stack
79         movl %ebx, %esp
80         // the trap-time esp should be decremented by 4
81         subl $4, %ecx
82         // change trap-time esp
83         movl %ecx, 40(%esp)
84         // restore all the general registers
85         popal
86         // ignore trap-time eip
87         addl $4, %esp
88         // restore eflags
89         popfl
90         // into the trap-time stack
91         popl %esp
92         // voila
93         ret