Home | History | Annotate | Download | only in X64
      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