forked from woai3c/MIT6.828
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpfentry.S
89 lines (85 loc) · 3.08 KB
/
pfentry.S
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include <inc/mmu.h>
#include <inc/memlayout.h>
# Page fault upcall entrypoint.
# This is where we ask the kernel to redirect us to whenever we cause
# a page fault in user space (see the call to sys_set_pgfault_handler
# in pgfault.c).
#
# When a page fault actually occurs, the kernel switches our ESP to
# point to the user exception stack if we're not already on the user
# exception stack, and then it pushes a UTrapframe onto our user
# exception stack:
#
# trap-time esp
# trap-time eflags
# trap-time eip
# utf_regs.reg_eax
# ...
# utf_regs.reg_esi
# utf_regs.reg_edi
# utf_err (error code)
# utf_fault_va <-- %esp
#
# If this is a recursive fault, the kernel will reserve for us a
# blank word above the trap-time esp for scratch work when we unwind
# the recursive call.
#
# We then have call up to the appropriate page fault handler in C
# code, pointed to by the global variable '_pgfault_handler'.
.text
.globl _pgfault_upcall
_pgfault_upcall:
# Call the C page fault handler.
pushl %esp # function argument: pointer to UTF
movl _pgfault_handler, %eax
call *%eax
addl $4, %esp # pop function argument
# Now the C page fault handler has returned and you must return
# to the trap time state.
# Push trap-time %eip onto the trap-time stack.
#
# Explanation:
# We must prepare the trap-time stack for our eventual return to
# re-execute the instruction that faulted.
# Unfortunately, we can't return directly from the exception stack:
# We can't call 'jmp', since that requires that we load the address
# into a register, and all registers must have their trap-time
# values after the return.
# We can't call 'ret' from the exception stack either, since if we
# did, %esp would have the wrong value.
# So instead, we push the trap-time %eip onto the *trap-time* stack!
# Below we'll switch to that stack and call 'ret', which will
# restore %eip to its pre-fault value.
#
# In the case of a recursive fault on the exception stack,
# note that the word we're pushing now will fit in the
# blank word that the kernel reserved for us.
#
# Throughout the remaining code, think carefully about what
# registers are available for intermediate calculations. You
# may find that you have to rearrange your code in non-obvious
# ways as registers become unavailable as scratch space.
#
# LAB 4: Your code here.
movl 40(%esp), %eax # eip
movl 48(%esp), %ecx # esp
movl %eax, -4(%ecx) # 将原来的 eip 放入到原来的用户栈
# Restore the trap-time registers. After you do this, you
# can no longer modify any general-purpose registers.
# LAB 4: Your code here.
popl %eax
popl %eax # 跳过 fault_va 和 err
popal
# Restore eflags from the stack. After you do this, you can
# no longer use arithmetic operations or anything else that
# modifies eflags.
# LAB 4: Your code here.
addl $4, %esp #跳过eip
popfl
# Switch back to the adjusted trap-time stack.
# LAB 4: Your code here.
popl %esp
lea -4(%esp), %esp # 刚才没减去栈的 4 个字节 现在补上
# Return to re-execute the instruction that faulted.
# LAB 4: Your code here.
ret