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