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