xref: /DragonOS/kernel/src/arch/x86_64/asm/entry.S (revision a9e28e9ce9607ebd1953898dda370c22d4f1425d)
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    iretq
58
59ret_from_exception:
60    // === 从中断中返回 ===
61
62ENTRY(ret_from_intr)
63
64    // 进入信号处理流程
65    cli
66
67    // 将原本要返回的栈帧的栈指针传入do_signal的第一个参数
68    movq %rsp, %rdi
69    callq do_signal
70    cli
71
72__entry_ret_from_intr_before_gs_check_2:
73    push %rcx
74    addq $8, %rsp
75    movq CS(%rsp), %rcx
76    subq $8, %rsp
77    andq $0x3, %rcx
78    cmpq $0x3, %rcx
79
80    jne __entry_ret_from_intr_after_gs_check_2
81    swapgs
82
83__entry_ret_from_intr_after_gs_check_2:
84    popq %rcx
85
86    // 恢复寄存器
87    jmp Restore_all
88
89
90Err_Code:
91
92    // ===== 有错误码的情况下,保存寄存器并跳转服务程序
93    pushq	%rax
94	movq	%es,	%rax
95	pushq	%rax
96	movq	%ds,	%rax
97	pushq	%rax
98	xorq	%rax,	%rax
99
100	pushq	%rbp
101	pushq	%rdi
102	pushq	%rsi
103	pushq	%rdx
104	pushq	%rcx
105	pushq	%rbx
106	pushq	%r8
107	pushq	%r9
108	pushq	%r10
109	pushq	%r11
110	pushq	%r12
111	pushq	%r13
112	pushq	%r14
113	pushq	%r15
114
115    cld
116
117    movq ERRCODE(%rsp), %rsi    // 把错误码装进rsi,作为函数的第二个参数
118    movq FUNC(%rsp), %rdx
119
120    movq $0x10, %rdi    // 加载内核段的地址
121    movq %rdi, %ds
122    movq %rdi, %es
123
124    movq %rsp, %rdi // 把栈指针装入rdi,作为函数的第一个的参数
125
126__entry_err_code_before_gs_check_1:
127    pushq %rcx
128    movq CS(%rdi), %rcx
129    and $0x3, %rcx
130    cmp $0x3, %rcx
131
132    jne __entry_err_code_after_gs_check_1
133    swapgs
134
135__entry_err_code_after_gs_check_1:
136    popq %rcx
137
138    callq *%rdx //调用服务程序 带*号表示调用的是绝对地址
139
140__entry_err_code_to_ret_from_exception:
141    jmp ret_from_exception
142
143
144// 0 #DE 除法错误
145ENTRY(trap_divide_error)
146
147    pushq $0    //由于#DE不会产生错误码,但是为了保持弹出结构的一致性,故也压入一个错误码0
148    pushq %rax  // 先将rax入栈
149    leaq do_divide_error(%rip), %rax    // 获取中断服务程序的地址
150
151    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
152    jmp Err_Code
153
154// 1 #DB 调试异常
155ENTRY(trap_debug)
156    pushq $0
157    pushq %rax
158    leaq do_debug(%rip), %rax    // 获取中断服务程序的地址
159    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
160    jmp Err_Code
161
162// 2 不可屏蔽中断
163ENTRY(trap_nmi)
164    // 不可屏蔽中断不是异常,而是一个外部中断,不会产生错误码
165    // 应执行中断处理流程
166    pushq $0  //占位err_code
167
168    pushq %rax
169    leaq do_nmi(%rip), %rax
170    xchgq %rax, (%rsp)
171    jmp Err_Code
172
173// 3 #BP 断点异常
174ENTRY(trap_int3)
175    pushq $0
176    pushq %rax
177    leaq do_int3(%rip), %rax    // 获取中断服务程序的地址
178    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
179    jmp Err_Code
180
181// 4 #OF 溢出异常
182ENTRY(trap_overflow)
183    pushq $0
184    pushq %rax
185    leaq do_overflow(%rip), %rax    // 获取中断服务程序的地址
186    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
187    jmp Err_Code
188
189// 5 #BR 越界异常
190ENTRY(trap_bounds)
191    pushq $0
192    pushq %rax
193    leaq do_bounds(%rip), %rax    // 获取中断服务程序的地址
194    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
195    jmp Err_Code
196
197// 6 #UD 无效/未定义的机器码
198ENTRY(trap_undefined_opcode)
199    pushq $0
200    pushq %rax
201    leaq do_undefined_opcode(%rip), %rax    // 获取中断服务程序的地址
202    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
203    jmp Err_Code
204
205// 7 #NM 设备异常(FPU不存在)
206ENTRY(trap_dev_not_avaliable)
207    pushq $0
208    pushq %rax
209    leaq do_dev_not_avaliable(%rip), %rax    // 获取中断服务程序的地址
210    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
211    jmp Err_Code
212
213// 8 #DF 双重错误
214ENTRY(trap_double_fault)
215    pushq %rax
216    leaq do_double_fault(%rip), %rax    // 获取中断服务程序的地址
217    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
218    jmp Err_Code
219
220// 9 协处理器越界(保留)
221ENTRY(trap_coprocessor_segment_overrun)
222    pushq $0
223    pushq %rax
224    leaq do_coprocessor_segment_overrun(%rip), %rax    // 获取中断服务程序的地址
225    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
226    jmp Err_Code
227
228// 10 #TS 无效的TSS段
229ENTRY(trap_invalid_TSS)
230    // === 不正确的任务状态段 #TS ==
231    // 有错误码,处理器已经自动在异常处理程序栈中压入错误码
232    pushq %rax
233    leaq do_invalid_TSS(%rip), %rax
234    xchgq %rax, (%rsp)
235    jmp Err_Code
236
237// 11 #NP 段不存在
238ENTRY(trap_segment_not_exists)
239    pushq %rax
240    leaq do_segment_not_exists(%rip), %rax    // 获取中断服务程序的地址
241    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
242    jmp Err_Code
243
244// 12 #SS 段错误
245ENTRY(trap_stack_segment_fault)
246    pushq %rax
247    leaq do_stack_segment_fault(%rip), %rax    // 获取中断服务程序的地址
248    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
249    jmp Err_Code
250
251// 13 #GP 通用保护性异常
252ENTRY(trap_general_protection)
253    pushq %rax
254    leaq do_general_protection(%rip), %rax    // 获取中断服务程序的地址
255    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
256    jmp Err_Code
257
258// 14 #PF 页错误
259ENTRY(trap_page_fault)
260    // === 页故障 #PF ==
261    // 有错误码
262    pushq %rax
263    leaq do_page_fault(%rip), %rax
264    xchgq %rax, (%rsp)
265    jmp Err_Code
266
267// 15 Intel保留,请勿使用
268
269// 16 #MF X87 FPU错误(计算错误)
270ENTRY(trap_x87_FPU_error)
271    pushq $0
272    pushq %rax
273    leaq do_x87_FPU_error(%rip), %rax    // 获取中断服务程序的地址
274    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
275    jmp Err_Code
276
277// 17 #AC 对齐检测
278ENTRY(trap_alignment_check)
279    pushq %rax
280    leaq do_alignment_check(%rip), %rax    // 获取中断服务程序的地址
281    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
282    jmp Err_Code
283
284// 18 #MC 机器检测
285ENTRY(trap_machine_check)
286    pushq $0
287    pushq %rax
288    leaq do_machine_check(%rip), %rax    // 获取中断服务程序的地址
289    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
290    jmp Err_Code
291
292// 19 #XM SIMD浮点异常
293ENTRY(trap_SIMD_exception)
294    pushq $0
295    pushq %rax
296    leaq do_SIMD_exception(%rip), %rax    // 获取中断服务程序的地址
297    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
298    jmp Err_Code
299
300// 20 #VE 虚拟化异常
301ENTRY(trap_virtualization_exception)
302    pushq $0
303    pushq %rax
304    leaq do_virtualization_exception(%rip), %rax    // 获取中断服务程序的地址
305    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
306    jmp Err_Code
307
308
309
310// 系统调用入口
311// 0x80 系统调用门
312ENTRY(syscall_int)
313    pushq $0
314    pushq %rax
315    leaq syscall_handler(%rip), %rax    // 获取系统调用服务程序的地址
316    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
317    jmp Err_Code
318
319// irq模块初始化后的ignore_int入点
320ENTRY(ignore_int)
321    pushq $0
322    pushq %rax
323    leaq ignore_int_handler(%rip), %rax    // 获取ignore处理程序的地址
324    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
325    jmp Err_Code
326
327ENTRY(syscall_64)
328    // 切换用户栈和内核栈
329    cli
330    swapgs
331    movq %rsp, %gs:0x8
332    movq %gs:0x0, %rsp
333
334    pushq $43       // USER_DS
335    pushq %gs:0x8   // rsp
336    pushq %r11      // RFLAGS
337    pushq $51       // USER_CS
338    pushq %rcx      // RIP
339    pushq $0        // error code占位
340
341    pushq %rax
342    leaq syscall_handler(%rip), %rax // FUNC
343    xchgq %rax, (%rsp)
344
345    pushq %rax      // rax
346
347    movq %es, %rax
348    pushq %rax      // es
349    movq %ds, %rax
350    pushq %rax      // ds
351    xorq %rax, %rax
352
353    pushq	%rbp
354	pushq	%rdi
355	pushq	%rsi
356	pushq	%rdx
357	pushq	%rcx
358	pushq	%rbx
359	pushq	%r8
360	pushq	%r9
361	pushq	%r10
362	pushq	%r11
363	pushq	%r12
364	pushq	%r13
365	pushq	%r14
366	pushq	%r15
367
368    cld
369
370    xorq %rsi, %rsi
371    movq FUNC(%rsp), %rdx
372
373    movq %rsp, %rdi // 把栈指针装入rdi,作为函数的第一个的参数
374
375    sti
376    callq *%rdx //调用服务程序
377
378    // 将原本要返回的栈帧的栈指针传入do_signal的第一个参数
379    movq %rsp, %rdi
380
381    callq do_signal
382
383    cli
384
385    // === 恢复调用现场 ===
386    popq %r15
387    popq %r14
388    popq %r13
389    popq %r12
390    popq %r11
391    popq %r10
392    popq %r9
393    popq %r8
394    popq %rbx
395    popq %rcx
396    popq %rdx
397    popq %rsi
398    popq %rdi
399    popq %rbp
400
401    popq %rax           // 不允许直接pop到ds
402    movq %rax, %ds
403
404    popq %rax
405    movq %rax, %es
406
407    popq %rax
408    addq $0x10, %rsp    // 弹出变量FUNC和errcode
409
410    popq %rcx           // pop rip到rcx
411
412    addq $0x8, %rsp     // 弹出cs
413    popq %r11           // pop rflags到r11
414    popq %rsp           // Restore rsp
415
416    swapgs
417    sysretq
418