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 16ASM_GLOBAL ASM_PFX(OrigVector) 17ASM_GLOBAL ASM_PFX(InterruptEntryStub) 18ASM_GLOBAL ASM_PFX(StubSize) 19ASM_GLOBAL ASM_PFX(CommonIdtEntry) 20ASM_GLOBAL ASM_PFX(FxStorSupport) 21 22.data 23 24ASM_PFX(StubSize): .long ASM_PFX(InterruptEntryStubEnd) - ASM_PFX(InterruptEntryStub) 25ASM_PFX(AppRsp): .long 0x11111111 # ? 26 .long 0x11111111 # ? 27ASM_PFX(DebugRsp): .long 0x22222222 # ? 28 .long 0x22222222 # ? 29ASM_PFX(ExtraPush): .long 0x33333333 # ? 30 .long 0x33333333 # ? 31ASM_PFX(ExceptData): .long 0x44444444 # ? 32 .long 0x44444444 # ? 33ASM_PFX(Rflags): .long 0x55555555 # ? 34 .long 0x55555555 # ? 35ASM_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 71DebugStackEnd : .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 # 78ASM_PFX(ExceptionNumber): .long 0x77777777 # first entry will be the vector number pushed by the stub 79 .long 0x77777777 # ? 80 81DebugStackBegin : .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// 94ASM_GLOBAL ASM_PFX(FxStorSupport) 95ASM_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// 116ASM_GLOBAL ASM_PFX(Vect2Desc) 117ASM_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// 136ASM_GLOBAL ASM_PFX(InterruptEntryStub) 137ASM_PFX(InterruptEntryStub): 138 139 pushq $0 # push vector number - will be modified before installed 140 jmp ASM_PFX(CommonIdtEntry) 141 142ASM_GLOBAL ASM_PFX(InterruptEntryStubEnd) 143ASM_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// 151ASM_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 195ASM_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 247ExtraPushOne: 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 258ExtraPushDone: 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) 473NoAppStackMove: 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 481Chain: 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 502PhonyIretq: 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) 527NoChain: 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