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