xref: /DragonOS/kernel/src/arch/x86_64/asm/entry.S (revision a9e28e9ce9607ebd1953898dda370c22d4f1425d)
111f78b73SLoGin#include <common/asm.h>
211f78b73SLoGin.code64
311f78b73SLoGin//.section .text
411f78b73SLoGin
511f78b73SLoGinR15 =   0x00
611f78b73SLoGinR14 =   0x08
711f78b73SLoGinR13 =   0x10
811f78b73SLoGinR12 =   0x18
911f78b73SLoGinR11 =   0x20
1011f78b73SLoGinR10 =   0x28
1111f78b73SLoGinR9  =   0x30
1211f78b73SLoGinR8  =   0x38
1311f78b73SLoGinRBX =   0x40
1411f78b73SLoGinRCX =   0x48
1511f78b73SLoGinRDX =   0x50
1611f78b73SLoGinRSI =   0x58
1711f78b73SLoGinRDI	=	0x60
1811f78b73SLoGinRBP	=	0x68
1911f78b73SLoGinDS	=	0x70
2011f78b73SLoGinES	=	0x78
2111f78b73SLoGinRAX	=	0x80
2211f78b73SLoGinFUNC	=	0x88
2311f78b73SLoGinERRCODE	=	0x90
2411f78b73SLoGin// 以下几个字段,在中断产生时,由处理器压入栈内
2511f78b73SLoGinRIP	    =	0x98
2611f78b73SLoGinCS	    =	0xa0
2711f78b73SLoGinRFLAGS	=	0xa8
2811f78b73SLoGinOLD_RSP	=	0xb0
2911f78b73SLoGinOLDSS	=	0xb8
3011f78b73SLoGin
3111f78b73SLoGinRestore_all:
3211f78b73SLoGin    // === 恢复调用现场 ===
3311f78b73SLoGin    popq %r15
3411f78b73SLoGin    popq %r14
3511f78b73SLoGin    popq %r13
3611f78b73SLoGin    popq %r12
3711f78b73SLoGin    popq %r11
3811f78b73SLoGin    popq %r10
3911f78b73SLoGin    popq %r9
4011f78b73SLoGin    popq %r8
4111f78b73SLoGin    popq %rbx
4211f78b73SLoGin    popq %rcx
4311f78b73SLoGin    popq %rdx
4411f78b73SLoGin    popq %rsi
4511f78b73SLoGin    popq %rdi
4611f78b73SLoGin    popq %rbp
4711f78b73SLoGin
4811f78b73SLoGin    popq %rax   //  不允许直接pop到ds
4911f78b73SLoGin    movq %rax, %ds
5011f78b73SLoGin
5111f78b73SLoGin    popq %rax
5211f78b73SLoGin    movq %rax, %es
5311f78b73SLoGin
5411f78b73SLoGin    popq %rax
5511f78b73SLoGin    addq $0x10, %rsp // 弹出变量FUNC和errcode
5611f78b73SLoGin
5711f78b73SLoGin    iretq
5811f78b73SLoGin
5911f78b73SLoGinret_from_exception:
6011f78b73SLoGin    // === 从中断中返回 ===
6111f78b73SLoGin
6211f78b73SLoGinENTRY(ret_from_intr)
6311f78b73SLoGin
6411f78b73SLoGin    // 进入信号处理流程
6511f78b73SLoGin    cli
6611f78b73SLoGin
6711f78b73SLoGin    // 将原本要返回的栈帧的栈指针传入do_signal的第一个参数
6811f78b73SLoGin    movq %rsp, %rdi
6911f78b73SLoGin    callq do_signal
7011f78b73SLoGin    cli
7111f78b73SLoGin
7211f78b73SLoGin__entry_ret_from_intr_before_gs_check_2:
7311f78b73SLoGin    push %rcx
7411f78b73SLoGin    addq $8, %rsp
7511f78b73SLoGin    movq CS(%rsp), %rcx
7611f78b73SLoGin    subq $8, %rsp
7711f78b73SLoGin    andq $0x3, %rcx
7811f78b73SLoGin    cmpq $0x3, %rcx
7911f78b73SLoGin
8011f78b73SLoGin    jne __entry_ret_from_intr_after_gs_check_2
8111f78b73SLoGin    swapgs
8211f78b73SLoGin
8311f78b73SLoGin__entry_ret_from_intr_after_gs_check_2:
8411f78b73SLoGin    popq %rcx
8511f78b73SLoGin
8611f78b73SLoGin    // 恢复寄存器
8711f78b73SLoGin    jmp Restore_all
8811f78b73SLoGin
8911f78b73SLoGin
9011f78b73SLoGinErr_Code:
9111f78b73SLoGin
9211f78b73SLoGin    // ===== 有错误码的情况下,保存寄存器并跳转服务程序
9311f78b73SLoGin    pushq	%rax
9411f78b73SLoGin	movq	%es,	%rax
9511f78b73SLoGin	pushq	%rax
9611f78b73SLoGin	movq	%ds,	%rax
9711f78b73SLoGin	pushq	%rax
9811f78b73SLoGin	xorq	%rax,	%rax
9911f78b73SLoGin
10011f78b73SLoGin	pushq	%rbp
10111f78b73SLoGin	pushq	%rdi
10211f78b73SLoGin	pushq	%rsi
10311f78b73SLoGin	pushq	%rdx
10411f78b73SLoGin	pushq	%rcx
10511f78b73SLoGin	pushq	%rbx
10611f78b73SLoGin	pushq	%r8
10711f78b73SLoGin	pushq	%r9
10811f78b73SLoGin	pushq	%r10
10911f78b73SLoGin	pushq	%r11
11011f78b73SLoGin	pushq	%r12
11111f78b73SLoGin	pushq	%r13
11211f78b73SLoGin	pushq	%r14
11311f78b73SLoGin	pushq	%r15
11411f78b73SLoGin
11511f78b73SLoGin    cld
11611f78b73SLoGin
11711f78b73SLoGin    movq ERRCODE(%rsp), %rsi    // 把错误码装进rsi,作为函数的第二个参数
11811f78b73SLoGin    movq FUNC(%rsp), %rdx
11911f78b73SLoGin
12011f78b73SLoGin    movq $0x10, %rdi    // 加载内核段的地址
12111f78b73SLoGin    movq %rdi, %ds
12211f78b73SLoGin    movq %rdi, %es
12311f78b73SLoGin
12411f78b73SLoGin    movq %rsp, %rdi // 把栈指针装入rdi,作为函数的第一个的参数
12511f78b73SLoGin
12611f78b73SLoGin__entry_err_code_before_gs_check_1:
12711f78b73SLoGin    pushq %rcx
12811f78b73SLoGin    movq CS(%rdi), %rcx
12911f78b73SLoGin    and $0x3, %rcx
13011f78b73SLoGin    cmp $0x3, %rcx
13111f78b73SLoGin
13211f78b73SLoGin    jne __entry_err_code_after_gs_check_1
13311f78b73SLoGin    swapgs
13411f78b73SLoGin
13511f78b73SLoGin__entry_err_code_after_gs_check_1:
13611f78b73SLoGin    popq %rcx
13711f78b73SLoGin
13811f78b73SLoGin    callq *%rdx //调用服务程序 带*号表示调用的是绝对地址
13911f78b73SLoGin
14011f78b73SLoGin__entry_err_code_to_ret_from_exception:
14111f78b73SLoGin    jmp ret_from_exception
14211f78b73SLoGin
14311f78b73SLoGin
14411f78b73SLoGin// 0 #DE 除法错误
145f2022a8aSLoGinENTRY(trap_divide_error)
14611f78b73SLoGin
14711f78b73SLoGin    pushq $0    //由于#DE不会产生错误码,但是为了保持弹出结构的一致性,故也压入一个错误码0
14811f78b73SLoGin    pushq %rax  // 先将rax入栈
14911f78b73SLoGin    leaq do_divide_error(%rip), %rax    // 获取中断服务程序的地址
15011f78b73SLoGin
15111f78b73SLoGin    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
15211f78b73SLoGin    jmp Err_Code
15311f78b73SLoGin
15411f78b73SLoGin// 1 #DB 调试异常
155f2022a8aSLoGinENTRY(trap_debug)
15611f78b73SLoGin    pushq $0
15711f78b73SLoGin    pushq %rax
15811f78b73SLoGin    leaq do_debug(%rip), %rax    // 获取中断服务程序的地址
15911f78b73SLoGin    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
16011f78b73SLoGin    jmp Err_Code
16111f78b73SLoGin
16211f78b73SLoGin// 2 不可屏蔽中断
163f2022a8aSLoGinENTRY(trap_nmi)
16411f78b73SLoGin    // 不可屏蔽中断不是异常,而是一个外部中断,不会产生错误码
16511f78b73SLoGin    // 应执行中断处理流程
16611f78b73SLoGin    pushq $0  //占位err_code
16711f78b73SLoGin
16811f78b73SLoGin    pushq %rax
16911f78b73SLoGin    leaq do_nmi(%rip), %rax
17011f78b73SLoGin    xchgq %rax, (%rsp)
17111f78b73SLoGin    jmp Err_Code
17211f78b73SLoGin
17311f78b73SLoGin// 3 #BP 断点异常
174f2022a8aSLoGinENTRY(trap_int3)
17511f78b73SLoGin    pushq $0
17611f78b73SLoGin    pushq %rax
17711f78b73SLoGin    leaq do_int3(%rip), %rax    // 获取中断服务程序的地址
17811f78b73SLoGin    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
17911f78b73SLoGin    jmp Err_Code
18011f78b73SLoGin
18111f78b73SLoGin// 4 #OF 溢出异常
182f2022a8aSLoGinENTRY(trap_overflow)
18311f78b73SLoGin    pushq $0
18411f78b73SLoGin    pushq %rax
18511f78b73SLoGin    leaq do_overflow(%rip), %rax    // 获取中断服务程序的地址
18611f78b73SLoGin    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
18711f78b73SLoGin    jmp Err_Code
18811f78b73SLoGin
18911f78b73SLoGin// 5 #BR 越界异常
190f2022a8aSLoGinENTRY(trap_bounds)
19111f78b73SLoGin    pushq $0
19211f78b73SLoGin    pushq %rax
19311f78b73SLoGin    leaq do_bounds(%rip), %rax    // 获取中断服务程序的地址
19411f78b73SLoGin    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
19511f78b73SLoGin    jmp Err_Code
19611f78b73SLoGin
19711f78b73SLoGin// 6 #UD 无效/未定义的机器码
198f2022a8aSLoGinENTRY(trap_undefined_opcode)
19911f78b73SLoGin    pushq $0
20011f78b73SLoGin    pushq %rax
20111f78b73SLoGin    leaq do_undefined_opcode(%rip), %rax    // 获取中断服务程序的地址
20211f78b73SLoGin    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
20311f78b73SLoGin    jmp Err_Code
20411f78b73SLoGin
20511f78b73SLoGin// 7 #NM 设备异常(FPU不存在)
206f2022a8aSLoGinENTRY(trap_dev_not_avaliable)
20711f78b73SLoGin    pushq $0
20811f78b73SLoGin    pushq %rax
20911f78b73SLoGin    leaq do_dev_not_avaliable(%rip), %rax    // 获取中断服务程序的地址
21011f78b73SLoGin    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
21111f78b73SLoGin    jmp Err_Code
21211f78b73SLoGin
21311f78b73SLoGin// 8 #DF 双重错误
214f2022a8aSLoGinENTRY(trap_double_fault)
21511f78b73SLoGin    pushq %rax
21611f78b73SLoGin    leaq do_double_fault(%rip), %rax    // 获取中断服务程序的地址
21711f78b73SLoGin    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
21811f78b73SLoGin    jmp Err_Code
21911f78b73SLoGin
22011f78b73SLoGin// 9 协处理器越界(保留)
221f2022a8aSLoGinENTRY(trap_coprocessor_segment_overrun)
22211f78b73SLoGin    pushq $0
22311f78b73SLoGin    pushq %rax
22411f78b73SLoGin    leaq do_coprocessor_segment_overrun(%rip), %rax    // 获取中断服务程序的地址
22511f78b73SLoGin    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
22611f78b73SLoGin    jmp Err_Code
22711f78b73SLoGin
22811f78b73SLoGin// 10 #TS 无效的TSS段
229f2022a8aSLoGinENTRY(trap_invalid_TSS)
23011f78b73SLoGin    // === 不正确的任务状态段 #TS ==
23111f78b73SLoGin    // 有错误码,处理器已经自动在异常处理程序栈中压入错误码
23211f78b73SLoGin    pushq %rax
23311f78b73SLoGin    leaq do_invalid_TSS(%rip), %rax
23411f78b73SLoGin    xchgq %rax, (%rsp)
23511f78b73SLoGin    jmp Err_Code
23611f78b73SLoGin
23711f78b73SLoGin// 11 #NP 段不存在
238f2022a8aSLoGinENTRY(trap_segment_not_exists)
23911f78b73SLoGin    pushq %rax
24011f78b73SLoGin    leaq do_segment_not_exists(%rip), %rax    // 获取中断服务程序的地址
24111f78b73SLoGin    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
24211f78b73SLoGin    jmp Err_Code
24311f78b73SLoGin
24411f78b73SLoGin// 12 #SS 段错误
245f2022a8aSLoGinENTRY(trap_stack_segment_fault)
24611f78b73SLoGin    pushq %rax
24711f78b73SLoGin    leaq do_stack_segment_fault(%rip), %rax    // 获取中断服务程序的地址
24811f78b73SLoGin    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
24911f78b73SLoGin    jmp Err_Code
25011f78b73SLoGin
25111f78b73SLoGin// 13 #GP 通用保护性异常
252f2022a8aSLoGinENTRY(trap_general_protection)
25311f78b73SLoGin    pushq %rax
25411f78b73SLoGin    leaq do_general_protection(%rip), %rax    // 获取中断服务程序的地址
25511f78b73SLoGin    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
25611f78b73SLoGin    jmp Err_Code
25711f78b73SLoGin
25811f78b73SLoGin// 14 #PF 页错误
259f2022a8aSLoGinENTRY(trap_page_fault)
26011f78b73SLoGin    // === 页故障 #PF ==
26111f78b73SLoGin    // 有错误码
26211f78b73SLoGin    pushq %rax
26311f78b73SLoGin    leaq do_page_fault(%rip), %rax
26411f78b73SLoGin    xchgq %rax, (%rsp)
26511f78b73SLoGin    jmp Err_Code
26611f78b73SLoGin
26711f78b73SLoGin// 15 Intel保留,请勿使用
26811f78b73SLoGin
26911f78b73SLoGin// 16 #MF X87 FPU错误(计算错误)
270f2022a8aSLoGinENTRY(trap_x87_FPU_error)
27111f78b73SLoGin    pushq $0
27211f78b73SLoGin    pushq %rax
27311f78b73SLoGin    leaq do_x87_FPU_error(%rip), %rax    // 获取中断服务程序的地址
27411f78b73SLoGin    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
27511f78b73SLoGin    jmp Err_Code
27611f78b73SLoGin
27711f78b73SLoGin// 17 #AC 对齐检测
278f2022a8aSLoGinENTRY(trap_alignment_check)
27911f78b73SLoGin    pushq %rax
28011f78b73SLoGin    leaq do_alignment_check(%rip), %rax    // 获取中断服务程序的地址
28111f78b73SLoGin    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
28211f78b73SLoGin    jmp Err_Code
28311f78b73SLoGin
28411f78b73SLoGin// 18 #MC 机器检测
285f2022a8aSLoGinENTRY(trap_machine_check)
28611f78b73SLoGin    pushq $0
28711f78b73SLoGin    pushq %rax
28811f78b73SLoGin    leaq do_machine_check(%rip), %rax    // 获取中断服务程序的地址
28911f78b73SLoGin    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
29011f78b73SLoGin    jmp Err_Code
29111f78b73SLoGin
29211f78b73SLoGin// 19 #XM SIMD浮点异常
293f2022a8aSLoGinENTRY(trap_SIMD_exception)
29411f78b73SLoGin    pushq $0
29511f78b73SLoGin    pushq %rax
29611f78b73SLoGin    leaq do_SIMD_exception(%rip), %rax    // 获取中断服务程序的地址
29711f78b73SLoGin    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
29811f78b73SLoGin    jmp Err_Code
29911f78b73SLoGin
30011f78b73SLoGin// 20 #VE 虚拟化异常
301f2022a8aSLoGinENTRY(trap_virtualization_exception)
30211f78b73SLoGin    pushq $0
30311f78b73SLoGin    pushq %rax
30411f78b73SLoGin    leaq do_virtualization_exception(%rip), %rax    // 获取中断服务程序的地址
30511f78b73SLoGin    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
30611f78b73SLoGin    jmp Err_Code
30711f78b73SLoGin
30811f78b73SLoGin
30911f78b73SLoGin
31011f78b73SLoGin// 系统调用入口
31111f78b73SLoGin// 0x80 系统调用门
31211f78b73SLoGinENTRY(syscall_int)
31311f78b73SLoGin    pushq $0
31411f78b73SLoGin    pushq %rax
31511f78b73SLoGin    leaq syscall_handler(%rip), %rax    // 获取系统调用服务程序的地址
31611f78b73SLoGin    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
31711f78b73SLoGin    jmp Err_Code
31811f78b73SLoGin
31911f78b73SLoGin// irq模块初始化后的ignore_int入点
32011f78b73SLoGinENTRY(ignore_int)
32111f78b73SLoGin    pushq $0
32211f78b73SLoGin    pushq %rax
32311f78b73SLoGin    leaq ignore_int_handler(%rip), %rax    // 获取ignore处理程序的地址
32411f78b73SLoGin    xchgq %rax, (%rsp)  // 把FUNC的地址换入栈中
32511f78b73SLoGin    jmp Err_Code
32611f78b73SLoGin
32711f78b73SLoGinENTRY(syscall_64)
32811f78b73SLoGin    // 切换用户栈和内核栈
329*52bcb59eSGnoCiYeH    cli
33011f78b73SLoGin    swapgs
33111f78b73SLoGin    movq %rsp, %gs:0x8
33211f78b73SLoGin    movq %gs:0x0, %rsp
33311f78b73SLoGin
33411f78b73SLoGin    pushq $43       // USER_DS
33511f78b73SLoGin    pushq %gs:0x8   // rsp
33611f78b73SLoGin    pushq %r11      // RFLAGS
33711f78b73SLoGin    pushq $51       // USER_CS
33811f78b73SLoGin    pushq %rcx      // RIP
33911f78b73SLoGin    pushq $0        // error code占位
34011f78b73SLoGin
34111f78b73SLoGin    pushq %rax
34211f78b73SLoGin    leaq syscall_handler(%rip), %rax // FUNC
34311f78b73SLoGin    xchgq %rax, (%rsp)
34411f78b73SLoGin
34511f78b73SLoGin    pushq %rax      // rax
34611f78b73SLoGin
34711f78b73SLoGin    movq %es, %rax
34811f78b73SLoGin    pushq %rax      // es
34911f78b73SLoGin    movq %ds, %rax
35011f78b73SLoGin    pushq %rax      // ds
35111f78b73SLoGin    xorq %rax, %rax
35211f78b73SLoGin
35311f78b73SLoGin    pushq	%rbp
35411f78b73SLoGin	pushq	%rdi
35511f78b73SLoGin	pushq	%rsi
35611f78b73SLoGin	pushq	%rdx
35711f78b73SLoGin	pushq	%rcx
35811f78b73SLoGin	pushq	%rbx
35911f78b73SLoGin	pushq	%r8
36011f78b73SLoGin	pushq	%r9
36111f78b73SLoGin	pushq	%r10
36211f78b73SLoGin	pushq	%r11
36311f78b73SLoGin	pushq	%r12
36411f78b73SLoGin	pushq	%r13
36511f78b73SLoGin	pushq	%r14
36611f78b73SLoGin	pushq	%r15
36711f78b73SLoGin
36811f78b73SLoGin    cld
36911f78b73SLoGin
37011f78b73SLoGin    xorq %rsi, %rsi
37111f78b73SLoGin    movq FUNC(%rsp), %rdx
37211f78b73SLoGin
37311f78b73SLoGin    movq %rsp, %rdi // 把栈指针装入rdi,作为函数的第一个的参数
37411f78b73SLoGin
375*52bcb59eSGnoCiYeH    sti
37611f78b73SLoGin    callq *%rdx //调用服务程序
37711f78b73SLoGin
3788612b6ceSLoGin    // 将原本要返回的栈帧的栈指针传入do_signal的第一个参数
3798612b6ceSLoGin    movq %rsp, %rdi
380*52bcb59eSGnoCiYeH
3818612b6ceSLoGin    callq do_signal
3828612b6ceSLoGin
38311f78b73SLoGin    cli
38411f78b73SLoGin
38511f78b73SLoGin    // === 恢复调用现场 ===
38611f78b73SLoGin    popq %r15
38711f78b73SLoGin    popq %r14
38811f78b73SLoGin    popq %r13
38911f78b73SLoGin    popq %r12
39011f78b73SLoGin    popq %r11
39111f78b73SLoGin    popq %r10
39211f78b73SLoGin    popq %r9
39311f78b73SLoGin    popq %r8
39411f78b73SLoGin    popq %rbx
39511f78b73SLoGin    popq %rcx
39611f78b73SLoGin    popq %rdx
39711f78b73SLoGin    popq %rsi
39811f78b73SLoGin    popq %rdi
39911f78b73SLoGin    popq %rbp
40011f78b73SLoGin
40111f78b73SLoGin    popq %rax           // 不允许直接pop到ds
40211f78b73SLoGin    movq %rax, %ds
40311f78b73SLoGin
40411f78b73SLoGin    popq %rax
40511f78b73SLoGin    movq %rax, %es
40611f78b73SLoGin
40711f78b73SLoGin    popq %rax
40811f78b73SLoGin    addq $0x10, %rsp    // 弹出变量FUNC和errcode
40911f78b73SLoGin
41011f78b73SLoGin    popq %rcx           // pop rip到rcx
41111f78b73SLoGin
41211f78b73SLoGin    addq $0x8, %rsp     // 弹出cs
41311f78b73SLoGin    popq %r11           // pop rflags到r11
41411f78b73SLoGin    popq %rsp           // Restore rsp
41511f78b73SLoGin
41611f78b73SLoGin    swapgs
41711f78b73SLoGin    sysretq
418