-
Notifications
You must be signed in to change notification settings - Fork 67
/
Copy pathinterrupt.asm
97 lines (86 loc) · 2.56 KB
/
interrupt.asm
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
90
91
92
93
94
95
96
97
# 我们将会用一个宏来用循环保存寄存器。这是必要的设置
.altmacro
# 寄存器宽度对应的字节数
.set REG_SIZE, 8
# Context 的大小
.set CONTEXT_SIZE, 34
# 宏:将寄存器存到栈上
.macro SAVE reg, offset
sd \reg, \offset * REG_SIZE(sp)
.endm
# 宏:将寄存器从栈中取出
.macro LOAD reg, offset
ld \reg, \offset * REG_SIZE(sp)
.endm
# 宏:将 n 号寄存器保存在第 n 个位置
.macro SAVE_N n
SAVE x\n, n
.endm
# 宏:将 n 号寄存器从第 n 个位置取出
.macro LOAD_N n
LOAD x\n, n
.endm
.section .text
.globl __interrupt
# 进入中断
# 保存 Context 并且进入 Rust 中的中断处理函数 interrupt::handler::handle_interrupt()
__interrupt:
# 因为线程当前的栈不一定可用,必须切换到中断栈来保存 Context 并进行中断流程
# 因此,我们使用 sscratch 寄存器保存中断栈地址
# 思考:sscratch 的值最初是在什么地方写入的?
# 交换 sp 和 sscratch(切换到中断栈)
csrrw sp, sscratch, sp
# 在中断栈开辟 Context 的空间
addi sp, sp, -CONTEXT_SIZE * REG_SIZE
# 保存通用寄存器,除了 x0(固定为 0)
SAVE x1, 1
# 将本来的栈地址 sp(即 x2)保存
csrr x1, sscratch
SAVE x1, 2
# 保存 x3 至 x31
.set n, 3
.rept 29
SAVE_N %n
.set n, n + 1
.endr
# 取出 CSR 并保存
csrr t0, sstatus
csrr t1, sepc
SAVE t0, 32
SAVE t1, 33
# 调用 handle_interrupt,传入参数
# context: &mut Context
mv a0, sp
# scause: Scause
csrr a1, scause
# stval: usize
csrr a2, stval
jal handle_interrupt
.globl __restore
# 离开中断
# 此时中断栈顶被推入了一个 Context,而 a0 指向它
# 接下来从 Context 中恢复所有寄存器,并将 Context 出栈(用 sscratch 记录中断栈地址)
# 最后跳转至恢复的 sepc 的位置
__restore:
# 从 a0 中读取 sp
# 思考:a0 是在哪里被赋值的?(有两种情况)
mv sp, a0
# 恢复 CSR
LOAD t0, 32
LOAD t1, 33
csrw sstatus, t0
csrw sepc, t1
# 将中断栈地址写入 sscratch
addi t0, sp, CONTEXT_SIZE * REG_SIZE
csrw sscratch, t0
# 恢复通用寄存器
LOAD x1, 1
# 恢复 x3 至 x31
.set n, 3
.rept 29
LOAD_N %n
.set n, n + 1
.endr
# 恢复 sp(又名 x2)这里最后恢复是为了上面可以正常使用 LOAD 宏
LOAD x2, 2
sret