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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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 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 callq *%rdx //调用服务程序 376 377 // 将原本要返回的栈帧的栈指针传入do_signal的第一个参数 378 movq %rsp, %rdi 379 callq do_signal 380 381 cli 382 383 // === 恢复调用现场 === 384 popq %r15 385 popq %r14 386 popq %r13 387 popq %r12 388 popq %r11 389 popq %r10 390 popq %r9 391 popq %r8 392 popq %rbx 393 popq %rcx 394 popq %rdx 395 popq %rsi 396 popq %rdi 397 popq %rbp 398 399 popq %rax // 不允许直接pop到ds 400 movq %rax, %ds 401 402 popq %rax 403 movq %rax, %es 404 405 popq %rax 406 addq $0x10, %rsp // 弹出变量FUNC和errcode 407 408 popq %rcx // pop rip到rcx 409 410 addq $0x8, %rsp // 弹出cs 411 popq %r11 // pop rflags到r11 412 popq %rsp // Restore rsp 413 414 swapgs 415 sysretq 416