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