Home | History | Annotate | Download | only in Ia32
      1 ;/** @file
      2 ;  Low leve IA32 specific debug support functions.
      3 ;
      4 ;  Copyright (c) 2006 - 2011, 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 .586p
     16 .MODEL          FLAT, C
     17 
     18 EXCPT32_DIVIDE_ERROR     EQU    0
     19 EXCPT32_DEBUG            EQU    1
     20 EXCPT32_NMI              EQU    2
     21 EXCPT32_BREAKPOINT       EQU    3
     22 EXCPT32_OVERFLOW         EQU    4
     23 EXCPT32_BOUND            EQU    5
     24 EXCPT32_INVALID_OPCODE   EQU    6
     25 EXCPT32_DOUBLE_FAULT     EQU    8
     26 EXCPT32_INVALID_TSS      EQU   10
     27 EXCPT32_SEG_NOT_PRESENT  EQU   11
     28 EXCPT32_STACK_FAULT      EQU   12
     29 EXCPT32_GP_FAULT         EQU   13
     30 EXCPT32_PAGE_FAULT       EQU   14
     31 EXCPT32_FP_ERROR         EQU   16
     32 EXCPT32_ALIGNMENT_CHECK  EQU   17
     33 EXCPT32_MACHINE_CHECK    EQU   18
     34 EXCPT32_SIMD             EQU   19
     35 
     36 FXSTOR_FLAG              EQU   01000000h         ; bit cpuid 24 of feature flags
     37 
     38 ;; The FXSTOR and FXRSTOR commands are used for saving and restoring the x87,
     39 ;; MMX, SSE, SSE2, etc registers.  The initialization of the debugsupport driver
     40 ;; MUST check the CPUID feature flags to see that these instructions are available
     41 ;; and fail to init if they are not.
     42 
     43 ;; fxstor [edi]
     44 FXSTOR_EDI               MACRO
     45                          db 0fh, 0aeh, 00000111y ; mod = 00, reg/op = 000, r/m = 111 = [edi]
     46 ENDM
     47 
     48 ;; fxrstor [esi]
     49 FXRSTOR_ESI              MACRO
     50                          db 0fh, 0aeh, 00001110y ; mod = 00, reg/op = 001, r/m = 110 = [esi]
     51 ENDM
     52 .DATA
     53 
     54 public          OrigVector, InterruptEntryStub, StubSize, CommonIdtEntry, FxStorSupport
     55 
     56 StubSize        dd      InterruptEntryStubEnd - InterruptEntryStub
     57 AppEsp          dd      11111111h ; ?
     58 DebugEsp        dd      22222222h ; ?
     59 ExtraPush       dd      33333333h ; ?
     60 ExceptData      dd      44444444h ; ?
     61 Eflags          dd      55555555h ; ?
     62 OrigVector      dd      66666666h ; ?
     63 
     64 ;; The declarations below define the memory region that will be used for the debug stack.
     65 ;; The context record will be built by pushing register values onto this stack.
     66 ;; It is imparitive that alignment be carefully managed, since the FXSTOR and
     67 ;; FXRSTOR instructions will GP fault if their memory operand is not 16 byte aligned.
     68 ;;
     69 ;; The stub will switch stacks from the application stack to the debuger stack
     70 ;; and pushes the exception number.
     71 ;;
     72 ;; Then we building the context record on the stack. Since the stack grows down,
     73 ;; we push the fields of the context record from the back to the front.  There
     74 ;; are 132 bytes of stack used prior allocating the 512 bytes of stack to be
     75 ;; used as the memory buffer for the fxstor instruction. Therefore address of
     76 ;; the buffer used for the FXSTOR instruction is &Eax - 132 - 512, which
     77 ;; must be 16 byte aligned.
     78 ;;
     79 ;; We carefully locate the stack to make this happen.
     80 ;;
     81 ;; For reference, the context structure looks like this:
     82 ;;      struct {
     83 ;;        UINT32             ExceptionData;
     84 ;;        FX_SAVE_STATE_IA32 FxSaveState;    // 512 bytes, must be 16 byte aligned
     85 ;;        UINT32             Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
     86 ;;        UINT32             Cr0, Cr1, Cr2, Cr3, Cr4;
     87 ;;        UINT32             EFlags;
     88 ;;        UINT32             Ldtr, Tr;
     89 ;;        UINT32             Gdtr[2], Idtr[2];
     90 ;;        UINT32             Eip;
     91 ;;        UINT32             Gs, Fs, Es, Ds, Cs, Ss;
     92 ;;        UINT32             Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
     93 ;;      } SYSTEM_CONTEXT_IA32;  // 32 bit system context record
     94 
     95 
     96 align           16
     97 DebugStackEnd   db      "DbgStkEnd >>>>>>"      ;; 16 byte long string - must be 16 bytes to preserve alignment
     98                 dd      1ffdh dup (000000000h)  ;; 32K should be enough stack
     99                                                 ;;   This allocation is coocked to insure
    100                                                 ;;   that the the buffer for the FXSTORE instruction
    101                                                 ;;   will be 16 byte aligned also.
    102                                                 ;;
    103 ExceptionNumber dd      ?                       ;; first entry will be the vector number pushed by the stub
    104 
    105 DebugStackBegin db      "<<<< DbgStkBegin"      ;; initial debug ESP == DebugStackBegin, set in stub
    106 
    107 .CODE
    108 
    109 externdef InterruptDistrubutionHub:near
    110 
    111 ;------------------------------------------------------------------------------
    112 ; BOOLEAN
    113 ; FxStorSupport (
    114 ;   void
    115 ;   )
    116 ;
    117 ; Abstract: Returns TRUE if FxStor instructions are supported
    118 ;
    119 FxStorSupport   PROC    C PUBLIC
    120 
    121 ;
    122 ; cpuid corrupts ebx which must be preserved per the C calling convention
    123 ;
    124                 push    ebx
    125                 mov     eax, 1
    126                 cpuid
    127                 mov     eax, edx
    128                 and     eax, FXSTOR_FLAG
    129                 shr     eax, 24
    130                 pop     ebx
    131                 ret
    132 FxStorSupport   ENDP
    133 
    134 
    135 
    136 ;------------------------------------------------------------------------------
    137 ; void
    138 ; Vect2Desc (
    139 ;   DESCRIPTOR * DestDesc,
    140 ;   void (*Vector) (void)
    141 ;   )
    142 ;
    143 ; Abstract: Encodes an IDT descriptor with the given physical address
    144 ;
    145 Vect2Desc       PROC    C PUBLIC DestPtr:DWORD, Vector:DWORD
    146 
    147                 mov     eax, Vector
    148                 mov     ecx, DestPtr
    149                 mov     word ptr [ecx], ax                  ; write bits 15..0 of offset
    150                 mov     dx, cs
    151                 mov     word ptr [ecx+2], dx                ; SYS_CODE_SEL from GDT
    152                 mov     word ptr [ecx+4], 0e00h OR 8000h    ; type = 386 interrupt gate, present
    153                 shr     eax, 16
    154                 mov     word ptr [ecx+6], ax                ; write bits 31..16 of offset
    155 
    156                 ret
    157 
    158 Vect2Desc       ENDP
    159 
    160 
    161 
    162 ;------------------------------------------------------------------------------
    163 ; InterruptEntryStub
    164 ;
    165 ; Abstract: This code is not a function, but is a small piece of code that is
    166 ;               copied and fixed up once for each IDT entry that is hooked.
    167 ;
    168 InterruptEntryStub::
    169                 mov     AppEsp, esp                  ; save stack top
    170                 mov     esp, offset DebugStackBegin  ; switch to debugger stack
    171                 push    0                            ; push vector number - will be modified before installed
    172                 db      0e9h                         ; jump rel32
    173                 dd      0                            ; fixed up to relative address of CommonIdtEntry
    174 InterruptEntryStubEnd:
    175 
    176 
    177 
    178 ;------------------------------------------------------------------------------
    179 ; CommonIdtEntry
    180 ;
    181 ; Abstract: This code is not a function, but is the common part for all IDT
    182 ;               vectors.
    183 ;
    184 CommonIdtEntry::
    185 ;;
    186 ;; At this point, the stub has saved the current application stack esp into AppEsp
    187 ;; and switched stacks to the debug stack, where it pushed the vector number
    188 ;;
    189 ;; The application stack looks like this:
    190 ;;
    191 ;;              ...
    192 ;;              (last application stack entry)
    193 ;;              eflags from interrupted task
    194 ;;              CS from interrupted task
    195 ;;              EIP from interrupted task
    196 ;;              Error code <-------------------- Only present for some exeption types
    197 ;;
    198 ;;
    199 
    200 
    201 ;; The stub switched us to the debug stack and pushed the interrupt number.
    202 ;;
    203 ;; Next, construct the context record.  It will be build on the debug stack by
    204 ;; pushing the registers in the correct order so as to create the context structure
    205 ;; on the debug stack.  The context record must be built from the end back to the
    206 ;; beginning because the stack grows down...
    207 ;
    208 ;; For reference, the context record looks like this:
    209 ;;
    210 ;; typedef
    211 ;; struct {
    212 ;;   UINT32             ExceptionData;
    213 ;;   FX_SAVE_STATE_IA32 FxSaveState;
    214 ;;   UINT32             Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
    215 ;;   UINT32             Cr0, Cr2, Cr3, Cr4;
    216 ;;   UINT32             EFlags;
    217 ;;   UINT32             Ldtr, Tr;
    218 ;;   UINT32             Gdtr[2], Idtr[2];
    219 ;;   UINT32             Eip;
    220 ;;   UINT32             Gs, Fs, Es, Ds, Cs, Ss;
    221 ;;   UINT32             Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
    222 ;; } SYSTEM_CONTEXT_IA32;  // 32 bit system context record
    223 
    224 ;; UINT32  Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
    225                 pushad
    226 
    227 ;; Save interrupt state eflags register...
    228                 pushfd
    229                 pop     eax
    230                 mov     dword ptr Eflags, eax
    231 
    232 ;; We need to determine if any extra data was pushed by the exception, and if so, save it
    233 ;; To do this, we check the exception number pushed by the stub, and cache the
    234 ;; result in a variable since we'll need this again.
    235                 .IF     ExceptionNumber == EXCPT32_DOUBLE_FAULT
    236                 mov     ExtraPush, 1
    237                 .ELSEIF ExceptionNumber == EXCPT32_INVALID_TSS
    238                 mov     ExtraPush, 1
    239                 .ELSEIF ExceptionNumber == EXCPT32_SEG_NOT_PRESENT
    240                 mov     ExtraPush, 1
    241                 .ELSEIF ExceptionNumber == EXCPT32_STACK_FAULT
    242                 mov     ExtraPush, 1
    243                 .ELSEIF ExceptionNumber == EXCPT32_GP_FAULT
    244                 mov     ExtraPush, 1
    245                 .ELSEIF ExceptionNumber == EXCPT32_PAGE_FAULT
    246                 mov     ExtraPush, 1
    247                 .ELSEIF ExceptionNumber == EXCPT32_ALIGNMENT_CHECK
    248                 mov     ExtraPush, 1
    249                 .ELSE
    250                 mov     ExtraPush, 0
    251                 .ENDIF
    252 
    253 ;; If there's some extra data, save it also, and modify the saved AppEsp to effectively
    254 ;; pop this value off the application's stack.
    255                 .IF     ExtraPush == 1
    256                 mov     eax, AppEsp
    257                 mov     ebx, [eax]
    258                 mov     ExceptData, ebx
    259                 add     eax, 4
    260                 mov     AppEsp, eax
    261                 .ELSE
    262                 mov     ExceptData, 0
    263                 .ENDIF
    264 
    265 ;; The "pushad" above pushed the debug stack esp.  Since what we're actually doing
    266 ;; is building the context record on the debug stack, we need to save the pushed
    267 ;; debug ESP, and replace it with the application's last stack entry...
    268                 mov     eax, [esp + 12]
    269                 mov     DebugEsp, eax
    270                 mov     eax, AppEsp
    271                 add     eax, 12
    272                 ; application stack has eflags, cs, & eip, so
    273                 ; last actual application stack entry is
    274                 ; 12 bytes into the application stack.
    275                 mov     [esp + 12], eax
    276 
    277 ;; continue building context record
    278 ;; UINT32  Gs, Fs, Es, Ds, Cs, Ss;  insure high 16 bits of each is zero
    279                 mov     eax, ss
    280                 push    eax
    281 
    282                 ; CS from application is one entry back in application stack
    283                 mov     eax, AppEsp
    284                 movzx   eax, word ptr [eax + 4]
    285                 push    eax
    286 
    287                 mov     eax, ds
    288                 push    eax
    289                 mov     eax, es
    290                 push    eax
    291                 mov     eax, fs
    292                 push    eax
    293                 mov     eax, gs
    294                 push    eax
    295 
    296 ;; UINT32  Eip;
    297                 ; Eip from application is on top of application stack
    298                 mov     eax, AppEsp
    299                 push    dword ptr [eax]
    300 
    301 ;; UINT32  Gdtr[2], Idtr[2];
    302                 push    0
    303                 push    0
    304                 sidt    fword ptr [esp]
    305                 push    0
    306                 push    0
    307                 sgdt    fword ptr [esp]
    308 
    309 ;; UINT32  Ldtr, Tr;
    310                 xor     eax, eax
    311                 str     ax
    312                 push    eax
    313                 sldt    ax
    314                 push    eax
    315 
    316 ;; UINT32  EFlags;
    317 ;; Eflags from application is two entries back in application stack
    318                 mov     eax, AppEsp
    319                 push    dword ptr [eax + 8]
    320 
    321 ;; UINT32  Cr0, Cr1, Cr2, Cr3, Cr4;
    322 ;; insure FXSAVE/FXRSTOR is enabled in CR4...
    323 ;; ... while we're at it, make sure DE is also enabled...
    324                 mov     eax, cr4
    325                 or      eax, 208h
    326                 mov     cr4, eax
    327                 push    eax
    328                 mov     eax, cr3
    329                 push    eax
    330                 mov     eax, cr2
    331                 push    eax
    332                 push    0
    333                 mov     eax, cr0
    334                 push    eax
    335 
    336 ;; UINT32  Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
    337                 mov     eax, dr7
    338                 push    eax
    339 ;; clear Dr7 while executing debugger itself
    340                 xor     eax, eax
    341                 mov     dr7, eax
    342 
    343                 mov     eax, dr6
    344                 push    eax
    345 ;; insure all status bits in dr6 are clear...
    346                 xor     eax, eax
    347                 mov     dr6, eax
    348 
    349                 mov     eax, dr3
    350                 push    eax
    351                 mov     eax, dr2
    352                 push    eax
    353                 mov     eax, dr1
    354                 push    eax
    355                 mov     eax, dr0
    356                 push    eax
    357 
    358 ;; FX_SAVE_STATE_IA32 FxSaveState;
    359                 sub     esp, 512
    360                 mov     edi, esp
    361                 ; IMPORTANT!! The debug stack has been carefully constructed to
    362                 ; insure that esp and edi are 16 byte aligned when we get here.
    363                 ; They MUST be.  If they are not, a GP fault will occur.
    364                 FXSTOR_EDI
    365 
    366 ;; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
    367                 cld
    368 
    369 ;; UINT32  ExceptionData;
    370                 mov     eax, ExceptData
    371                 push    eax
    372 
    373 ; call to C code which will in turn call registered handler
    374 ; pass in the vector number
    375                 mov     eax, esp
    376                 push    eax
    377                 mov     eax, ExceptionNumber
    378                 push    eax
    379                 call    InterruptDistrubutionHub
    380                 add     esp, 8
    381 
    382 ; restore context...
    383 ;; UINT32  ExceptionData;
    384                 add     esp, 4
    385 
    386 ;; FX_SAVE_STATE_IA32 FxSaveState;
    387                 mov     esi, esp
    388                 FXRSTOR_ESI
    389                 add     esp, 512
    390 
    391 ;; UINT32  Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
    392                 pop     eax
    393                 mov     dr0, eax
    394                 pop     eax
    395                 mov     dr1, eax
    396                 pop     eax
    397                 mov     dr2, eax
    398                 pop     eax
    399                 mov     dr3, eax
    400 ;; skip restore of dr6.  We cleared dr6 during the context save.
    401                 add     esp, 4
    402                 pop     eax
    403                 mov     dr7, eax
    404 
    405 ;; UINT32  Cr0, Cr1, Cr2, Cr3, Cr4;
    406                 pop     eax
    407                 mov     cr0, eax
    408                 add     esp, 4
    409                 pop     eax
    410                 mov     cr2, eax
    411                 pop     eax
    412                 mov     cr3, eax
    413                 pop     eax
    414                 mov     cr4, eax
    415 
    416 ;; UINT32  EFlags;
    417                 mov     eax, AppEsp
    418                 pop     dword ptr [eax + 8]
    419 
    420 ;; UINT32  Ldtr, Tr;
    421 ;; UINT32  Gdtr[2], Idtr[2];
    422 ;; Best not let anyone mess with these particular registers...
    423                 add     esp, 24
    424 
    425 ;; UINT32  Eip;
    426                 pop     dword ptr [eax]
    427 
    428 ;; UINT32  SegGs, SegFs, SegEs, SegDs, SegCs, SegSs;
    429 ;; NOTE - modified segment registers could hang the debugger...  We
    430 ;;        could attempt to insulate ourselves against this possibility,
    431 ;;        but that poses risks as well.
    432 ;;
    433 
    434                 pop     gs
    435                 pop     fs
    436                 pop     es
    437                 pop     ds
    438                 pop     [eax + 4]
    439                 pop     ss
    440 
    441 ;; The next stuff to restore is the general purpose registers that were pushed
    442 ;; using the "pushad" instruction.
    443 ;;
    444 ;; The value of ESP as stored in the context record is the application ESP
    445 ;; including the 3 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                 mov     ebx, [esp + 12]  ; move the potentially modified AppEsp into ebx
    450                 mov     eax, AppEsp
    451                 add     eax, 12
    452                 cmp     ebx, eax
    453                 je      NoAppStackMove
    454 
    455                 mov     eax, AppEsp
    456                 mov     ecx, [eax]       ; EIP
    457                 mov     [ebx], ecx
    458 
    459                 mov     ecx, [eax + 4]   ; CS
    460                 mov     [ebx + 4], ecx
    461 
    462                 mov     ecx, [eax + 8]   ; EFLAGS
    463                 mov     [ebx + 8], ecx
    464 
    465                 mov     eax, ebx         ; modify the saved AppEsp to the new AppEsp
    466                 mov     AppEsp, eax
    467 NoAppStackMove:
    468                 mov     eax, DebugEsp    ; restore the DebugEsp on the debug stack
    469                                          ; so our "popad" will not cause a stack switch
    470                 mov     [esp + 12], eax
    471 
    472                 cmp     ExceptionNumber, 068h
    473                 jne     NoChain
    474 
    475 Chain:
    476 
    477 ;; Restore eflags so when we chain, the flags will be exactly as if we were never here.
    478 ;; We gin up the stack to do an iretd so we can get ALL the flags.
    479                 mov     eax, AppEsp
    480                 mov     ebx, [eax + 8]
    481                 and     ebx, NOT 300h ; special handling for IF and TF
    482                 push    ebx
    483                 push    cs
    484                 push    PhonyIretd
    485                 iretd
    486 PhonyIretd:
    487 
    488 ;; UINT32  Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
    489                 popad
    490 
    491 ;; Switch back to application stack
    492                 mov     esp, AppEsp
    493 
    494 ;; Jump to original handler
    495                 jmp     OrigVector
    496 
    497 NoChain:
    498 ;; UINT32  Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
    499                 popad
    500 
    501 ;; Switch back to application stack
    502                 mov     esp, AppEsp
    503 
    504 ;; We're outa here...
    505                 iretd
    506 END
    507 
    508 
    509 
    510