1#include"../common/asm.h"
2.code64
3//.section .text
4
5R15 =   0x00
6R14 =   0x08
7R13 =   0x10
8R12 =   0x18
9R11 =   0x20
10R10 =   0x28
11R9  =   0x30
12R8  =   0x38
13RBX =   0x40
14RCX =   0x48
15RDX =   0x50
16RSI =   0x58
17RDI	=	0x60
18RBP	=	0x68
19DS	=	0x70
20ES	=	0x78
21RAX	=	0x80
22FUNC	=	0x88
23ERRCODE	=	0x90
24// 以下几个字段,在中断产生时,由处理器压入栈内
25RIP	    =	0x98
26CS	    =	0xa0
27RFLAGS	=	0xa8
28OLD_RSP	=	0xb0
29OLDSS	=	0xb8
30
31Restore_all:
32    // === 恢复调用现场 ===
33    popq %r15
34    popq %r14
35    popq %r13
36    popq %r12
37    popq %r11
38    popq %r10
39    popq %r9
40    popq %r8
41    popq %rbx
42    popq %rcx
43    popq %rdx
44    popq %rsi
45    popq %rdi
46    popq %rbp
47
48    popq %rax   //  不允许直接pop到ds
49    movq %rax, %ds
50
51    popq %rax
52    movq %rax, %es
53
54    popq %rax
55    addq $0x10, %rsp // 弹出变量FUNC和errcode
56
57    sti
58    iretq
59
60ret_from_exception:
61    // === 从中断中返回 ===
62
63ENTRY(ret_from_intr)
64
65    // 进入信号处理流程
66    cli
67
68    // 将原本要返回的栈帧的栈指针传入do_signal的第一个参数
69    movq %rsp, %rdi
70    callq do_signal
71
72    // 恢复寄存器
73    jmp Restore_all
74
75
76Err_Code:
77
78    // ===== 有错误码的情况下,保存寄存器并跳转服务程序
79    pushq	%rax
80	movq	%es,	%rax
81	pushq	%rax
82	movq	%ds,	%rax
83	pushq	%rax
84	xorq	%rax,	%rax
85
86	pushq	%rbp
87	pushq	%rdi
88	pushq	%rsi
89	pushq	%rdx
90	pushq	%rcx
91	pushq	%rbx
92	pushq	%r8
93	pushq	%r9
94	pushq	%r10
95	pushq	%r11
96	pushq	%r12
97	pushq	%r13
98	pushq	%r14
99	pushq	%r15
100
101    cld
102
103    movq ERRCODE(%rsp), %rsi    // 把错误码装进rsi,作为函数的第二个参数
104    movq FUNC(%rsp), %rdx
105
106    movq $0x10, %rdi    // 加载内核段的地址
107    movq %rdi, %ds
108    movq %rdi, %es
109
110    movq %rsp, %rdi // 把栈指针装入rdi,作为函数的第一个的参数
111
112    callq *%rdx //调用服务程序 带*号表示调用的是绝对地址
113    jmp ret_from_exception
114
115
116// 0 #DE 除法错误
117ENTRY(divide_error)
118
119    pushq $0    //由于#DE不会产生错误码,但是为了保持弹出结构的一致性,故也压入一个错误码0
120    pushq %rax  // 先将rax入栈
121    leaq do_divide_error(%rip), %rax    // 获取中断服务程序的地址
122
123    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
124    jmp Err_Code
125
126// 1 #DB 调试异常
127ENTRY(debug)
128    pushq $0
129    pushq %rax
130    leaq do_debug(%rip), %rax    // 获取中断服务程序的地址
131    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
132    jmp Err_Code
133
134// 2 不可屏蔽中断
135ENTRY(nmi)
136    // 不可屏蔽中断不是异常,而是一个外部中断,不会产生错误码
137    // 应执行中断处理流程
138    pushq $0  //占位err_code
139
140    pushq %rax
141    leaq do_nmi(%rip), %rax
142    xchgq %rax, (%rsp)
143    jmp Err_Code
144
145// 3 #BP 断点异常
146ENTRY(int3)
147    pushq $0
148    pushq %rax
149    leaq do_int3(%rip), %rax    // 获取中断服务程序的地址
150    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
151    jmp Err_Code
152
153// 4 #OF 溢出异常
154ENTRY(overflow)
155    pushq $0
156    pushq %rax
157    leaq do_overflow(%rip), %rax    // 获取中断服务程序的地址
158    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
159    jmp Err_Code
160
161// 5 #BR 越界异常
162ENTRY(bounds)
163    pushq $0
164    pushq %rax
165    leaq do_bounds(%rip), %rax    // 获取中断服务程序的地址
166    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
167    jmp Err_Code
168
169// 6 #UD 无效/未定义的机器码
170ENTRY(undefined_opcode)
171    pushq $0
172    pushq %rax
173    leaq do_undefined_opcode(%rip), %rax    // 获取中断服务程序的地址
174    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
175    jmp Err_Code
176
177// 7 #NM 设备异常(FPU不存在)
178ENTRY(dev_not_avaliable)
179    pushq $0
180    pushq %rax
181    leaq do_dev_not_avaliable(%rip), %rax    // 获取中断服务程序的地址
182    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
183    jmp Err_Code
184
185// 8 #DF 双重错误
186ENTRY(double_fault)
187    pushq %rax
188    leaq do_double_fault(%rip), %rax    // 获取中断服务程序的地址
189    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
190    jmp Err_Code
191
192// 9 协处理器越界(保留)
193ENTRY(coprocessor_segment_overrun)
194    pushq $0
195    pushq %rax
196    leaq do_coprocessor_segment_overrun(%rip), %rax    // 获取中断服务程序的地址
197    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
198    jmp Err_Code
199
200// 10 #TS 无效的TSS段
201ENTRY(invalid_TSS)
202    // === 不正确的任务状态段 #TS ==
203    // 有错误码,处理器已经自动在异常处理程序栈中压入错误码
204    pushq %rax
205    leaq do_invalid_TSS(%rip), %rax
206    xchgq %rax, (%rsp)
207    jmp Err_Code
208
209// 11 #NP 段不存在
210ENTRY(segment_not_exists)
211    pushq %rax
212    leaq do_segment_not_exists(%rip), %rax    // 获取中断服务程序的地址
213    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
214    jmp Err_Code
215
216// 12 #SS 段错误
217ENTRY(stack_segment_fault)
218    pushq %rax
219    leaq do_stack_segment_fault(%rip), %rax    // 获取中断服务程序的地址
220    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
221    jmp Err_Code
222
223// 13 #GP 通用保护性异常
224ENTRY(general_protection)
225    pushq %rax
226    leaq do_general_protection(%rip), %rax    // 获取中断服务程序的地址
227    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
228    jmp Err_Code
229
230// 14 #PF 页错误
231ENTRY(page_fault)
232    // === 页故障 #PF ==
233    // 有错误码
234    pushq %rax
235    leaq do_page_fault(%rip), %rax
236    xchgq %rax, (%rsp)
237    jmp Err_Code
238
239// 15 Intel保留,请勿使用
240
241// 16 #MF X87 FPU错误(计算错误)
242ENTRY(x87_FPU_error)
243    pushq $0
244    pushq %rax
245    leaq do_x87_FPU_error(%rip), %rax    // 获取中断服务程序的地址
246    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
247    jmp Err_Code
248
249// 17 #AC 对齐检测
250ENTRY(alignment_check)
251    pushq %rax
252    leaq do_alignment_check(%rip), %rax    // 获取中断服务程序的地址
253    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
254    jmp Err_Code
255
256// 18 #MC 机器检测
257ENTRY(machine_check)
258    pushq $0
259    pushq %rax
260    leaq do_machine_check(%rip), %rax    // 获取中断服务程序的地址
261    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
262    jmp Err_Code
263
264// 19 #XM SIMD浮点异常
265ENTRY(SIMD_exception)
266    pushq $0
267    pushq %rax
268    leaq do_SIMD_exception(%rip), %rax    // 获取中断服务程序的地址
269    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
270    jmp Err_Code
271
272// 20 #VE 虚拟化异常
273ENTRY(virtualization_exception)
274    pushq $0
275    pushq %rax
276    leaq do_virtualization_exception(%rip), %rax    // 获取中断服务程序的地址
277    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
278    jmp Err_Code
279
280
281
282// 系统调用入口
283// 0x80 系统调用门
284ENTRY(syscall_int)
285    pushq $0
286    pushq %rax
287    leaq syscall_handler(%rip), %rax    // 获取系统调用服务程序的地址
288    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
289    jmp Err_Code
290
291// irq模块初始化后的ignore_int入点
292ENTRY(ignore_int)
293    pushq $0
294    pushq %rax
295    leaq ignore_int_handler(%rip), %rax    // 获取ignore处理程序的地址
296    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
297    jmp Err_Code
298
299