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 ASM_GLOBAL ASM_PFX(OrigVector)
     16 ASM_GLOBAL ASM_PFX(InterruptEntryStub)
     17 ASM_GLOBAL ASM_PFX(StubSize)
     18 ASM_GLOBAL ASM_PFX(CommonIdtEntry)
     19 ASM_GLOBAL ASM_PFX(FxStorSupport)
     20 
     21 ASM_PFX(StubSize):       .long   ASM_PFX(InterruptEntryStubEnd) - ASM_PFX(InterruptEntryStub)
     22 ASM_PFX(AppEsp):         .long   0x11111111 # ?
     23 ASM_PFX(DebugEsp):       .long   0x22222222 # ?
     24 ASM_PFX(ExtraPush):      .long   0x33333333 # ?
     25 ASM_PFX(ExceptData):     .long   0x44444444 # ?
     26 ASM_PFX(Eflags):         .long   0x55555555 # ?
     27 ASM_PFX(OrigVector):     .long   0x66666666 # ?
     28 
     29 #------------------------------------------------------------------------------
     30 # BOOLEAN
     31 # FxStorSupport (
     32 #   void
     33 #   )
     34 #
     35 # Abstract: Returns TRUE if FxStor instructions are supported
     36 #
     37 ASM_GLOBAL ASM_PFX(FxStorSupport)
     38 ASM_PFX(FxStorSupport):
     39 #
     40 # cpuid corrupts ebx which must be preserved per the C calling convention
     41 #
     42         push   %ebx
     43         mov    $0x1,%eax
     44         cpuid
     45         mov    %edx,%eax
     46         and    $0x1000000,%eax
     47         shr    $0x18,%eax
     48         pop    %ebx
     49         ret
     50 #------------------------------------------------------------------------------
     51 # void
     52 # Vect2Desc (
     53 #   DESCRIPTOR * DestDesc,
     54 #   void (*Vector) (void)
     55 #   )
     56 #
     57 # Abstract: Encodes an IDT descriptor with the given physical address
     58 #
     59 
     60 ASM_GLOBAL ASM_PFX(Vect2Desc)
     61 ASM_PFX(Vect2Desc):
     62         push   %ebp
     63         mov    %esp,%ebp
     64         mov    0xc(%ebp),%eax
     65         mov    0x8(%ebp),%ecx
     66         mov    %ax,(%ecx)
     67         movw   $0x20,0x2(%ecx)
     68         movw   $0x8e00,0x4(%ecx)
     69         shr    $0x10,%eax
     70         mov    %ax,0x6(%ecx)
     71         leave
     72         ret
     73 
     74 ASM_GLOBAL ASM_PFX(InterruptEntryStub)
     75 ASM_PFX(InterruptEntryStub):
     76         mov    %esp,0x0                    # save stack top
     77         mov    $0x0,%esp                   # switch to debugger stack
     78         push   $0x0                        # push vector number - will be modified before installed
     79         jmp    ASM_PFX(CommonIdtEntry)     # jump CommonIdtEntry
     80 ASM_GLOBAL ASM_PFX(InterruptEntryStubEnd)
     81 ASM_PFX(InterruptEntryStubEnd):
     82 
     83 #------------------------------------------------------------------------------
     84 # CommonIdtEntry
     85 #
     86 # Abstract: This code is not a function, but is the common part for all IDT
     87 #               vectors.
     88 #
     89 ASM_GLOBAL ASM_PFX(CommonIdtEntry)
     90 ASM_PFX(CommonIdtEntry):
     91 ##
     92 ## At this point, the stub has saved the current application stack esp into AppEsp
     93 ## and switched stacks to the debug stack, where it pushed the vector number
     94 ##
     95 ## The application stack looks like this:
     96 ##
     97 ##              ...
     98 ##              (last application stack entry)
     99 ##              eflags from interrupted task
    100 ##              CS from interrupted task
    101 ##              EIP from interrupted task
    102 ##              Error code <-------------------- Only present for some exeption types
    103 ##
    104 ##
    105 
    106 
    107 ## The stub switched us to the debug stack and pushed the interrupt number.
    108 ##
    109 ## Next, construct the context record.  It will be build on the debug stack by
    110 ## pushing the registers in the correct order so as to create the context structure
    111 ## on the debug stack.  The context record must be built from the end back to the
    112 ## beginning because the stack grows down...
    113 #
    114 ## For reference, the context record looks like this:
    115 ##
    116 ## typedef
    117 ## struct {
    118 ##   UINT32             ExceptionData;
    119 ##   FX_SAVE_STATE_IA32 FxSaveState;
    120 ##   UINT32             Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
    121 ##   UINT32             Cr0, Cr2, Cr3, Cr4;
    122 ##   UINT32             EFlags;
    123 ##   UINT32             Ldtr, Tr;
    124 ##   UINT32             Gdtr[2], Idtr[2];
    125 ##   UINT32             Eip;
    126 ##   UINT32             Gs, Fs, Es, Ds, Cs, Ss;
    127 ##   UINT32             Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
    128 ## } SYSTEM_CONTEXT_IA32;  // 32 bit system context record
    129 
    130 ## UINT32  Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
    131         pusha
    132 ## Save interrupt state eflags register...
    133         pushf
    134         pop    %eax
    135 ## We need to determine if any extra data was pushed by the exception, and if so, save it
    136 ## To do this, we check the exception number pushed by the stub, and cache the
    137 ## result in a variable since we'll need this again.
    138         mov    %eax,0x0
    139         cmpl   $0x8,0x0
    140         jne    ASM_PFX(CommonIdtEntry+0x20)
    141         movl   $0x1,0x0
    142         jmp    ASM_PFX(CommonIdtEntry+0xa8)
    143         cmpl   $0xa,0x0
    144         jne    ASM_PFX(CommonIdtEntry+0x35)
    145         movl   $0x1,0x0
    146         jmp    ASM_PFX(CommonIdtEntry+0xa8)
    147         cmpl   $0xb,0x0
    148         jne    ASM_PFX(CommonIdtEntry+0x4a)
    149         movl   $0x1,0x0
    150         jmp    ASM_PFX(CommonIdtEntry+0xa8)
    151         cmpl   $0xc,0x0
    152         jne    ASM_PFX(CommonIdtEntry+0x5f)
    153         movl   $0x1,0x0
    154         jmp    ASM_PFX(CommonIdtEntry+0xa8)
    155         cmpl   $0xd,0x0
    156         jne    ASM_PFX(CommonIdtEntry+0x74)
    157         movl   $0x1,0x0
    158         jmp    ASM_PFX(CommonIdtEntry+0xa8)
    159         cmpl   $0xe,0x0
    160         jne    ASM_PFX(CommonIdtEntry+0x89)
    161         movl   $0x1,0x0
    162         jmp    ASM_PFX(CommonIdtEntry+0xa8)
    163         cmpl   $0x11,0x0
    164         jne    ASM_PFX(CommonIdtEntry+0x9e)
    165         movl   $0x1,0x0
    166         jmp    ASM_PFX(CommonIdtEntry+0xa8)
    167         movl   $0x0,0x0
    168 ## If there's some extra data, save it also, and modify the saved AppEsp to effectively
    169 ## pop this value off the application's stack.
    170 
    171         cmpl   $0x1,0x0
    172         jne    ASM_PFX(CommonIdtEntry+0xc8)
    173         mov    0x0,%eax
    174         mov    (%eax),%ebx
    175         mov    %ebx,0x0
    176         add    $0x4,%eax
    177         mov    %eax,0x0
    178         jmp    ASM_PFX(CommonIdtEntry+0xd2)
    179         movl   $0x0,0x0
    180 ## The "pushad" above pushed the debug stack esp.  Since what we're actually doing
    181 ## is building the context record on the debug stack, we need to save the pushed
    182 ## debug ESP, and replace it with the application's last stack entry...
    183         mov    0xc(%esp),%eax
    184         mov    %eax,0x0
    185         mov    0x0,%eax
    186         add    $0xc,%eax
    187         # application stack has eflags, cs, & eip, so
    188         # last actual application stack entry is
    189         # 12 bytes into the application stack.
    190         mov    %eax,0xc(%esp)
    191 ## continue building context record
    192 ## UINT32  Gs, Fs, Es, Ds, Cs, Ss;  insure high 16 bits of each is zero
    193         mov    %ss,%eax
    194         push   %eax
    195 
    196         # CS from application is one entry back in application stack
    197         mov    0x0,%eax
    198         movzwl 0x4(%eax),%eax
    199         push   %eax
    200         mov    %ds,%eax
    201         push   %eax
    202         mov    %es,%eax
    203         push   %eax
    204         mov    %fs,%eax
    205         push   %eax
    206         mov    %gs,%eax
    207         push   %eax
    208 
    209 ## UINT32  Eip;
    210         # Eip from application is on top of application stack
    211         mov    0x0,%eax
    212         pushl  (%eax)
    213 
    214 ## UINT32  Gdtr[2], Idtr[2];
    215         push   $0x0
    216         push   $0x0
    217         sidtl  (%esp)
    218         push   $0x0
    219         push   $0x0
    220         sgdtl  (%esp)
    221 
    222 ## UINT32  Ldtr, Tr;
    223         xor    %eax,%eax
    224         str    %eax
    225         push   %eax
    226         sldt   %eax
    227         push   %eax
    228 
    229 ## UINT32  EFlags;
    230 ## Eflags from application is two entries back in application stack
    231         mov    0x0,%eax
    232         pushl  0x8(%eax)
    233 
    234 ## UINT32  Cr0, Cr1, Cr2, Cr3, Cr4;
    235 ## insure FXSAVE/FXRSTOR is enabled in CR4...
    236 ## ... while we're at it, make sure DE is also enabled...
    237         mov    %cr4,%eax
    238         or     $0x208,%eax
    239         mov    %eax,%cr4
    240         push   %eax
    241         mov    %cr3,%eax
    242         push   %eax
    243         mov    %cr2,%eax
    244         push   %eax
    245         push   $0x0
    246         mov    %cr0,%eax
    247         push   %eax
    248 
    249 ## UINT32  Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
    250         mov    %db7,%eax
    251         push   %eax
    252 
    253 ## clear Dr7 while executing debugger itself
    254         xor    %eax,%eax
    255         mov    %eax,%db7
    256         mov    %db6,%eax
    257         push   %eax
    258 
    259 ## insure all status bits in dr6 are clear...
    260         xor    %eax,%eax
    261         mov    %eax,%db6
    262         mov    %db3,%eax
    263         push   %eax
    264         mov    %db2,%eax
    265         push   %eax
    266         mov    %db1,%eax
    267         push   %eax
    268         mov    %db0,%eax
    269         push   %eax
    270 
    271 ## FX_SAVE_STATE_IA32 FxSaveState;
    272         sub    $0x200,%esp
    273         mov    %esp,%edi
    274         # IMPORTANT!! The debug stack has been carefully constructed to
    275         # insure that esp and edi are 16 byte aligned when we get here.
    276         # They MUST be.  If they are not, a GP fault will occur.
    277         fxsave (%edi)
    278 
    279 ## UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
    280         cld
    281 
    282 ## UINT32  ExceptionData;
    283         mov    0x0,%eax
    284         push   %eax
    285 
    286 # call to C code which will in turn call registered handler
    287 # pass in the vector number
    288         mov    %esp,%eax
    289         push   %eax
    290         mov    0x0,%eax
    291         push   %eax
    292         call   ASM_PFX(CommonIdtEntry+0x184)
    293         add    $0x8,%esp
    294 
    295 # restore context...
    296 ## UINT32  ExceptionData;
    297         add    $0x4,%esp
    298 
    299 ## FX_SAVE_STATE_IA32 FxSaveState;
    300         mov    %esp,%esi
    301         fxrstor (%esi)
    302         add    $0x200,%esp
    303 
    304 ## UINT32  Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
    305         pop    %eax
    306         mov    %eax,%db0
    307         pop    %eax
    308         mov    %eax,%db1
    309         pop    %eax
    310         mov    %eax,%db2
    311         pop    %eax
    312         mov    %eax,%db3
    313 
    314 ## skip restore of dr6.  We cleared dr6 during the context save.
    315         add    $0x4,%esp
    316         pop    %eax
    317         mov    %eax,%db7
    318 
    319 ## UINT32  Cr0, Cr1, Cr2, Cr3, Cr4;
    320         pop    %eax
    321         mov    %eax,%cr0
    322         add    $0x4,%esp
    323         pop    %eax
    324         mov    %eax,%cr2
    325         pop    %eax
    326         mov    %eax,%cr3
    327         pop    %eax
    328         mov    %eax,%cr4
    329 
    330 ## UINT32  EFlags;
    331         mov    0x0,%eax
    332         popl   0x8(%eax)
    333 
    334 ## UINT32  Ldtr, Tr;
    335 ## UINT32  Gdtr[2], Idtr[2];
    336 ## Best not let anyone mess with these particular registers...
    337         add    $0x18,%esp
    338 
    339 ## UINT32  Eip;
    340         popl   (%eax)
    341 
    342 ## UINT32  SegGs, SegFs, SegEs, SegDs, SegCs, SegSs;
    343 ## NOTE - modified segment registers could hang the debugger...  We
    344 ##        could attempt to insulate ourselves against this possibility,
    345 ##        but that poses risks as well.
    346 ##
    347 
    348         pop    %gs
    349         pop    %fs
    350         pop    %es
    351         pop    %ds
    352         popl   0x4(%eax)
    353         pop    %ss
    354         mov    0xc(%esp),%ebx
    355 
    356 ## The next stuff to restore is the general purpose registers that were pushed
    357 ## using the "pushad" instruction.
    358 ##
    359 ## The value of ESP as stored in the context record is the application ESP
    360 ## including the 3 entries on the application stack caused by the exception
    361 ## itself. It may have been modified by the debug agent, so we need to
    362 ## determine if we need to relocate the application stack.
    363 
    364         mov    0x0,%eax          # move the potentially modified AppEsp into ebx
    365         add    $0xc,%eax
    366         cmp    %eax,%ebx
    367         je     ASM_PFX(CommonIdtEntry+0x202)
    368         mov    0x0,%eax
    369         mov    (%eax),%ecx       # EIP
    370         mov    %ecx,(%ebx)
    371         mov    0x4(%eax),%ecx    # CS
    372         mov    %ecx,0x4(%ebx)
    373         mov    0x8(%eax),%ecx    # EFLAGS
    374         mov    %ecx,0x8(%ebx)
    375 
    376         mov    %ebx,%eax         # modify the saved AppEsp to the new AppEsp
    377         mov    %eax,0x0
    378         mov    0x0,%eax          # restore the DebugEsp on the debug stack
    379 	                               # so our "popad" will not cause a stack switch
    380         mov    %eax,0xc(%esp)
    381         cmpl   $0x68,0x0
    382         jne    PhonyIretd+0xd
    383 ## Restore eflags so when we chain, the flags will be exactly as if we were never here.
    384 ## We gin up the stack to do an iretd so we can get ALL the flags.
    385         mov    0x0,%eax
    386         mov    0x8(%eax),%ebx
    387         and    $0xfffffcff,%ebx  # special handling for IF and TF
    388         push   %ebx
    389         push   %cs
    390         push   $0x0
    391         iret
    392 
    393 PhonyIretd:
    394 ## UINT32  Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
    395         popa
    396 
    397 ## Switch back to application stack
    398         mov    0x0,%esp
    399         jmp    *0x0
    400 ## Jump to original handler
    401 ## UINT32  Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
    402         popa
    403 ## Switch back to application stack
    404         mov    0x0,%esp
    405 
    406 ## We're outa here...
    407         iret
    408