1;/** @file 2; Low level x64 routines used by the debug support driver. 3; 4; Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR> 5; SPDX-License-Identifier: BSD-2-Clause-Patent 6; 7;**/ 8 9%define EXCPT64_DIVIDE_ERROR 0 10%define EXCPT64_DEBUG 1 11%define EXCPT64_NMI 2 12%define EXCPT64_BREAKPOINT 3 13%define EXCPT64_OVERFLOW 4 14%define EXCPT64_BOUND 5 15%define EXCPT64_INVALID_OPCODE 6 16%define EXCPT64_DOUBLE_FAULT 8 17%define EXCPT64_INVALID_TSS 10 18%define EXCPT64_SEG_NOT_PRESENT 11 19%define EXCPT64_STACK_FAULT 12 20%define EXCPT64_GP_FAULT 13 21%define EXCPT64_PAGE_FAULT 14 22%define EXCPT64_FP_ERROR 16 23%define EXCPT64_ALIGNMENT_CHECK 17 24%define EXCPT64_MACHINE_CHECK 18 25%define EXCPT64_SIMD 19 26 27%define FXSTOR_FLAG 0x1000000 ; bit cpuid 24 of feature flags 28 29;; The FXSTOR and FXRSTOR commands are used for saving and restoring the x87, 30;; MMX, SSE, SSE2, etc registers. The initialization of the debugsupport driver 31;; MUST check the CPUID feature flags to see that these instructions are available 32;; and fail to init if they are not. 33 34;; fxstor [rdi] 35%macro FXSTOR_RDI 0 36 db 0xf, 0xae, 00000111y ; mod = 00, reg/op = 000, r/m = 111 = [rdi] 37%endmacro 38 39;; fxrstor [rsi] 40%macro FXRSTOR_RSI 0 41 db 0xf, 0xae, 00001110y ; mod = 00, reg/op = 001, r/m = 110 = [rsi] 42%endmacro 43 44SECTION .data 45 46global ASM_PFX(OrigVector) 47global ASM_PFX(InterruptEntryStub) 48global ASM_PFX(StubSize) 49global ASM_PFX(CommonIdtEntry) 50global ASM_PFX(FxStorSupport) 51extern ASM_PFX(InterruptDistrubutionHub) 52 53ASM_PFX(StubSize): dd InterruptEntryStubEnd - ASM_PFX(InterruptEntryStub) 54AppRsp: dq 0x1111111111111111 ; ? 55DebugRsp: dq 0x2222222222222222 ; ? 56ExtraPush: dq 0x3333333333333333 ; ? 57ExceptData: dq 0x4444444444444444 ; ? 58Rflags: dq 0x5555555555555555 ; ? 59ASM_PFX(OrigVector): dq 0x6666666666666666 ; ? 60 61;; The declarations below define the memory region that will be used for the debug stack. 62;; The context record will be built by pushing register values onto this stack. 63;; It is imparitive that alignment be carefully managed, since the FXSTOR and 64;; FXRSTOR instructions will GP fault if their memory operand is not 16 byte aligned. 65;; 66;; The stub will switch stacks from the application stack to the debuger stack 67;; and pushes the exception number. 68;; 69;; Then we building the context record on the stack. Since the stack grows down, 70;; we push the fields of the context record from the back to the front. There 71;; are 336 bytes of stack used prior allocating the 512 bytes of stack to be 72;; used as the memory buffer for the fxstor instruction. Therefore address of 73;; the buffer used for the FXSTOR instruction is &Eax - 336 - 512, which 74;; must be 16 byte aligned. 75;; 76;; We carefully locate the stack to make this happen. 77;; 78;; For reference, the context structure looks like this: 79;; struct { 80;; UINT64 ExceptionData; 81;; FX_SAVE_STATE_X64 FxSaveState; // 512 bytes, must be 16 byte aligned 82;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; 83;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8; 84;; UINT64 RFlags; 85;; UINT64 Ldtr, Tr; 86;; UINT64 Gdtr[2], Idtr[2]; 87;; UINT64 Rip; 88;; UINT64 Gs, Fs, Es, Ds, Cs, Ss; 89;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax; 90;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15; 91;; } SYSTEM_CONTEXT_X64; // 64 bit system context record 92 93align 16 94DebugStackEnd: db "DbgStkEnd >>>>>>" ;; 16 byte long string - must be 16 bytes to preserve alignment 95 times 0x1ffc dd 0x0 ;; 32K should be enough stack 96 ;; This allocation is coocked to insure 97 ;; that the the buffer for the FXSTORE instruction 98 ;; will be 16 byte aligned also. 99 ;; 100ExceptionNumber: dq 0 ;; first entry will be the vector number pushed by the stub 101 102DebugStackBegin: db "<<<< DbgStkBegin" ;; initial debug ESP == DebugStackBegin, set in stub 103 104DEFAULT REL 105SECTION .text 106 107;------------------------------------------------------------------------------ 108; BOOLEAN 109; FxStorSupport ( 110; void 111; ) 112; 113; Abstract: Returns TRUE if FxStor instructions are supported 114; 115global ASM_PFX(FxStorSupport) 116ASM_PFX(FxStorSupport): 117 118; 119; cpuid corrupts rbx which must be preserved per the C calling convention 120; 121 push rbx 122 mov rax, dword 1 123 cpuid 124 mov eax, edx 125 and rax, FXSTOR_FLAG 126 shr rax, 24 127 pop rbx 128 ret 129 130;------------------------------------------------------------------------------ 131; void 132; Vect2Desc ( 133; IA32_IDT_GATE_DESCRIPTOR * DestDesc, // rcx 134; void (*Vector) (void) // rdx 135; ) 136; 137; Abstract: Encodes an IDT descriptor with the given physical address 138; 139global ASM_PFX(Vect2Desc) 140ASM_PFX(Vect2Desc): 141 142 mov rax, rdx 143 mov word [rcx], ax ; write bits 15..0 of offset 144 mov dx, cs 145 mov word [rcx+2], dx ; SYS_CODE_SEL from GDT 146 mov word [rcx+4], 0xe00 | 0x8000 ; type = 386 interrupt gate, present 147 shr rax, 16 148 mov word [rcx+6], ax ; write bits 31..16 of offset 149 shr rax, 16 150 mov dword [rcx+8], eax ; write bits 63..32 of offset 151 152 ret 153 154;------------------------------------------------------------------------------ 155; InterruptEntryStub 156; 157; Abstract: This code is not a function, but is a small piece of code that is 158; copied and fixed up once for each IDT entry that is hooked. 159; 160ASM_PFX(InterruptEntryStub): 161 push 0 ; push vector number - will be modified before installed 162 db 0xe9 ; jump rel32 163 dd 0 ; fixed up to relative address of CommonIdtEntry 164InterruptEntryStubEnd: 165 166;------------------------------------------------------------------------------ 167; CommonIdtEntry 168; 169; Abstract: This code is not a function, but is the common part for all IDT 170; vectors. 171; 172ASM_PFX(CommonIdtEntry): 173;; 174;; At this point, the stub has saved the current application stack esp into AppRsp 175;; and switched stacks to the debug stack, where it pushed the vector number 176;; 177;; The application stack looks like this: 178;; 179;; ... 180;; (last application stack entry) 181;; [16 bytes alignment, do not care it] 182;; SS from interrupted task 183;; RSP from interrupted task 184;; rflags from interrupted task 185;; CS from interrupted task 186;; RIP from interrupted task 187;; Error code <-------------------- Only present for some exeption types 188;; 189;; Vector Number <----------------- pushed in our IDT Entry 190;; 191 192;; The stub switched us to the debug stack and pushed the interrupt number. 193;; 194;; Next, construct the context record. It will be build on the debug stack by 195;; pushing the registers in the correct order so as to create the context structure 196;; on the debug stack. The context record must be built from the end back to the 197;; beginning because the stack grows down... 198; 199;; For reference, the context record looks like this: 200;; 201;; typedef 202;; struct { 203;; UINT64 ExceptionData; 204;; FX_SAVE_STATE_X64 FxSaveState; 205;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; 206;; UINT64 Cr0, Cr2, Cr3, Cr4, Cr8; 207;; UINT64 RFlags; 208;; UINT64 Ldtr, Tr; 209;; UINT64 Gdtr[2], Idtr[2]; 210;; UINT64 Rip; 211;; UINT64 Gs, Fs, Es, Ds, Cs, Ss; 212;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax; 213;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15; 214;; } SYSTEM_CONTEXT_X64; // 64 bit system context record 215 216;; NOTE: we save rsp here to prevent compiler put rip reference cause error AppRsp 217 push rax 218 mov rax, qword [rsp+8] ; save vector number 219 mov [ExceptionNumber], rax ; save vector number 220 pop rax 221 add rsp, 8 ; pop vector number 222 mov [AppRsp], rsp ; save stack top 223 lea rsp, [DebugStackBegin] ; switch to debugger stack 224 sub rsp, 8 ; leave space for vector number 225 226;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax; 227;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15; 228 push r15 229 push r14 230 push r13 231 push r12 232 push r11 233 push r10 234 push r9 235 push r8 236 push rax 237 push rcx 238 push rdx 239 push rbx 240 push rsp 241 push rbp 242 push rsi 243 push rdi 244 245;; Save interrupt state rflags register... 246 pushfq 247 pop rax 248 mov [Rflags], rax 249 250;; We need to determine if any extra data was pushed by the exception, and if so, save it 251;; To do this, we check the exception number pushed by the stub, and cache the 252;; result in a variable since we'll need this again. 253 cmp qword [ExceptionNumber], EXCPT64_DOUBLE_FAULT 254 jz ExtraPushOne 255 cmp qword [ExceptionNumber], EXCPT64_INVALID_TSS 256 jz ExtraPushOne 257 cmp qword [ExceptionNumber], EXCPT64_SEG_NOT_PRESENT 258 jz ExtraPushOne 259 cmp qword [ExceptionNumber], EXCPT64_STACK_FAULT 260 jz ExtraPushOne 261 cmp qword [ExceptionNumber], EXCPT64_GP_FAULT 262 jz ExtraPushOne 263 cmp qword [ExceptionNumber], EXCPT64_PAGE_FAULT 264 jz ExtraPushOne 265 cmp qword [ExceptionNumber], EXCPT64_ALIGNMENT_CHECK 266 jz ExtraPushOne 267 mov qword [ExtraPush], 0 268 mov qword [ExceptData], 0 269 jmp ExtraPushDone 270ExtraPushOne: 271 mov qword [ExtraPush], 1 272 273;; If there's some extra data, save it also, and modify the saved AppRsp to effectively 274;; pop this value off the application's stack. 275 mov rax, [AppRsp] 276 mov rbx, [rax] 277 mov qword [ExceptData], rbx 278 add rax, 8 279 mov [AppRsp], rax 280 281ExtraPushDone: 282 283;; The "push" above pushed the debug stack rsp. Since what we're actually doing 284;; is building the context record on the debug stack, we need to save the pushed 285;; debug RSP, and replace it with the application's last stack entry... 286 mov rax, [rsp + 24] 287 mov [DebugRsp], rax 288 mov rax, [AppRsp] 289 mov rax, QWORD [rax + 24] 290 ; application stack has ss, rsp, rflags, cs, & rip, so 291 ; last actual application stack entry is saved at offset 292 ; 24 bytes from stack top. 293 mov [rsp + 24], rax 294 295;; continue building context record 296;; UINT64 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero 297 mov rax, ss 298 push rax 299 300 ; CS from application is one entry back in application stack 301 mov rax, [AppRsp] 302 movzx rax, word [rax + 8] 303 push rax 304 305 mov rax, ds 306 push rax 307 mov rax, es 308 push rax 309 mov rax, fs 310 push rax 311 mov rax, gs 312 push rax 313 314;; UINT64 Rip; 315 ; Rip from application is on top of application stack 316 mov rax, [AppRsp] 317 push qword [rax] 318 319;; UINT64 Gdtr[2], Idtr[2]; 320 push 0 321 push 0 322 sidt [rsp] 323 push 0 324 push 0 325 sgdt [rsp] 326 327;; UINT64 Ldtr, Tr; 328 xor rax, rax 329 str ax 330 push rax 331 sldt ax 332 push rax 333 334;; UINT64 RFlags; 335;; Rflags from application is two entries back in application stack 336 mov rax, [AppRsp] 337 push qword [rax + 16] 338 339;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8; 340;; insure FXSAVE/FXRSTOR is enabled in CR4... 341;; ... while we're at it, make sure DE is also enabled... 342 mov rax, cr8 343 push rax 344 mov rax, cr4 345 or rax, 0x208 346 mov cr4, rax 347 push rax 348 mov rax, cr3 349 push rax 350 mov rax, cr2 351 push rax 352 push 0 353 mov rax, cr0 354 push rax 355 356;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; 357 mov rax, dr7 358 push rax 359;; clear Dr7 while executing debugger itself 360 xor rax, rax 361 mov dr7, rax 362 363 mov rax, dr6 364 push rax 365;; insure all status bits in dr6 are clear... 366 xor rax, rax 367 mov dr6, rax 368 369 mov rax, dr3 370 push rax 371 mov rax, dr2 372 push rax 373 mov rax, dr1 374 push rax 375 mov rax, dr0 376 push rax 377 378;; FX_SAVE_STATE_X64 FxSaveState; 379 sub rsp, 512 380 mov rdi, rsp 381 ; IMPORTANT!! The debug stack has been carefully constructed to 382 ; insure that rsp and rdi are 16 byte aligned when we get here. 383 ; They MUST be. If they are not, a GP fault will occur. 384 FXSTOR_RDI 385 386;; UEFI calling convention for x64 requires that Direction flag in EFLAGs is clear 387 cld 388 389;; UINT64 ExceptionData; 390 mov rax, [ExceptData] 391 push rax 392 393; call to C code which will in turn call registered handler 394; pass in the vector number 395 mov rdx, rsp 396 mov rcx, [ExceptionNumber] 397 sub rsp, 40 398 call ASM_PFX(InterruptDistrubutionHub) 399 add rsp, 40 400 401; restore context... 402;; UINT64 ExceptionData; 403 add rsp, 8 404 405;; FX_SAVE_STATE_X64 FxSaveState; 406 mov rsi, rsp 407 FXRSTOR_RSI 408 add rsp, 512 409 410;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; 411 pop rax 412 mov dr0, rax 413 pop rax 414 mov dr1, rax 415 pop rax 416 mov dr2, rax 417 pop rax 418 mov dr3, rax 419;; skip restore of dr6. We cleared dr6 during the context save. 420 add rsp, 8 421 pop rax 422 mov dr7, rax 423 424;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8; 425 pop rax 426 mov cr0, rax 427 add rsp, 8 428 pop rax 429 mov cr2, rax 430 pop rax 431 mov cr3, rax 432 pop rax 433 mov cr4, rax 434 pop rax 435 mov cr8, rax 436 437;; UINT64 RFlags; 438 mov rax, [AppRsp] 439 pop qword [rax + 16] 440 441;; UINT64 Ldtr, Tr; 442;; UINT64 Gdtr[2], Idtr[2]; 443;; Best not let anyone mess with these particular registers... 444 add rsp, 48 445 446;; UINT64 Rip; 447 pop qword [rax] 448 449;; UINT64 Gs, Fs, Es, Ds, Cs, Ss; 450;; NOTE - modified segment registers could hang the debugger... We 451;; could attempt to insulate ourselves against this possibility, 452;; but that poses risks as well. 453;; 454 455 pop rax 456 ; mov gs, rax 457 pop rax 458 ; mov fs, rax 459 pop rax 460 mov es, rax 461 pop rax 462 mov ds, rax 463 mov rax, [AppRsp] 464 pop qword [rax + 8] 465 pop rax 466 mov ss, rax 467 468;; The next stuff to restore is the general purpose registers that were pushed 469;; using the "push" instruction. 470;; 471;; The value of RSP as stored in the context record is the application RSP 472;; including the 5 entries on the application stack caused by the exception 473;; itself. It may have been modified by the debug agent, so we need to 474;; determine if we need to relocate the application stack. 475 476 mov rbx, [rsp + 24] ; move the potentially modified AppRsp into rbx 477 mov rax, [AppRsp] 478 mov rax, QWORD [rax + 24] 479 cmp rbx, rax 480 je NoAppStackMove 481 482 mov rax, [AppRsp] 483 mov rcx, [rax] ; RIP 484 mov [rbx], rcx 485 486 mov rcx, [rax + 8] ; CS 487 mov [rbx + 8], rcx 488 489 mov rcx, [rax + 16] ; RFLAGS 490 mov [rbx + 16], rcx 491 492 mov rcx, [rax + 24] ; RSP 493 mov [rbx + 24], rcx 494 495 mov rcx, [rax + 32] ; SS 496 mov [rbx + 32], rcx 497 498 mov rax, rbx ; modify the saved AppRsp to the new AppRsp 499 mov [AppRsp], rax 500NoAppStackMove: 501 mov rax, [DebugRsp] ; restore the DebugRsp on the debug stack 502 ; so our "pop" will not cause a stack switch 503 mov [rsp + 24], rax 504 505 cmp qword [ExceptionNumber], 0x68 506 jne NoChain 507 508Chain: 509 510;; Restore rflags so when we chain, the flags will be exactly as if we were never here. 511;; We gin up the stack to do an iretq so we can get ALL the flags. 512 mov rax, [AppRsp] 513 mov rbx, [rax + 40] 514 push rbx 515 mov rax, ss 516 push rax 517 mov rax, rsp 518 add rax, 16 519 push rax 520 mov rax, [AppRsp] 521 mov rbx, [rax + 16] 522 and rbx, ~ 0x300 ; special handling for IF and TF 523 push rbx 524 mov rax, cs 525 push rax 526 lea rax, [PhonyIretq] 527 push rax 528 iretq 529PhonyIretq: 530 531;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax; 532;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15; 533 pop rdi 534 pop rsi 535 pop rbp 536 pop rsp 537 pop rbx 538 pop rdx 539 pop rcx 540 pop rax 541 pop r8 542 pop r9 543 pop r10 544 pop r11 545 pop r12 546 pop r13 547 pop r14 548 pop r15 549 550;; Switch back to application stack 551 mov rsp, [AppRsp] 552 553;; Jump to original handler 554 jmp [ASM_PFX(OrigVector)] 555 556NoChain: 557;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax; 558;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15; 559 pop rdi 560 pop rsi 561 pop rbp 562 pop rsp 563 pop rbx 564 pop rdx 565 pop rcx 566 pop rax 567 pop r8 568 pop r9 569 pop r10 570 pop r11 571 pop r12 572 pop r13 573 pop r14 574 pop r15 575 576;; Switch back to application stack 577 mov rsp, [AppRsp] 578 579;; We're outa here... 580 iretq 581 582