Home | History | Annotate | Download | only in Ia32
      1 ;------------------------------------------------------------------------------ ;
      2 ; Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
      3 ; This program and the accompanying materials
      4 ; are licensed and made available under the terms and conditions of the BSD License
      5 ; which accompanies this distribution.  The full text of the license may be found at
      6 ; http://opensource.org/licenses/bsd-license.php.
      7 ;
      8 ; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
      9 ; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     10 ;
     11 ; Module Name:
     12 ;
     13 ;   ExceptionHandlerAsm.Asm
     14 ;
     15 ; Abstract:
     16 ;
     17 ;   IA32 CPU Exception Handler
     18 ;
     19 ; Notes:
     20 ;
     21 ;------------------------------------------------------------------------------
     22 
     23 ;
     24 ; CommonExceptionHandler()
     25 ;
     26 extern ASM_PFX(CommonExceptionHandler)
     27 
     28 SECTION .data
     29 
     30 extern ASM_PFX(mErrorCodeFlag)            ; Error code flags for exceptions
     31 extern ASM_PFX(mDoFarReturnFlag)          ; Do far return flag
     32 
     33 SECTION .text
     34 
     35 ALIGN   8
     36 
     37 ;
     38 ; exception handler stub table
     39 ;
     40 AsmIdtVectorBegin:
     41 %rep  32
     42     db      0x6a        ; push  #VectorNum
     43     db      ($ - AsmIdtVectorBegin) / ((AsmIdtVectorEnd - AsmIdtVectorBegin) / 32) ; VectorNum
     44     push    eax
     45     mov     eax, ASM_PFX(CommonInterruptEntry)
     46     jmp     eax
     47 %endrep
     48 AsmIdtVectorEnd:
     49 
     50 HookAfterStubBegin:
     51     db      0x6a        ; push
     52 VectorNum:
     53     db      0          ; 0 will be fixed
     54     push    eax
     55     mov     eax, HookAfterStubHeaderEnd
     56     jmp     eax
     57 HookAfterStubHeaderEnd:
     58     pop     eax
     59     sub     esp, 8     ; reserve room for filling exception data later
     60     push    dword [esp + 8]
     61     xchg    ecx, [esp] ; get vector number
     62     bt      [ASM_PFX(mErrorCodeFlag)], ecx
     63     jnc     .0
     64     push    dword [esp]      ; addition push if exception data needed
     65 .0:
     66     xchg    ecx, [esp] ; restore ecx
     67     push    eax
     68 
     69 ;----------------------------------------------------------------------------;
     70 ; CommonInterruptEntry                                                               ;
     71 ;----------------------------------------------------------------------------;
     72 ; The follow algorithm is used for the common interrupt routine.
     73 ; Entry from each interrupt with a push eax and eax=interrupt number
     74 ; Stack:
     75 ; +---------------------+
     76 ; +    EFlags           +
     77 ; +---------------------+
     78 ; +    CS               +
     79 ; +---------------------+
     80 ; +    EIP              +
     81 ; +---------------------+
     82 ; +    Error Code       +
     83 ; +---------------------+
     84 ; +    Vector Number    +
     85 ; +---------------------+
     86 ; +    EBP              +
     87 ; +---------------------+ <-- EBP
     88 global ASM_PFX(CommonInterruptEntry)
     89 ASM_PFX(CommonInterruptEntry):
     90     cli
     91     pop    eax
     92     ;
     93     ; All interrupt handlers are invoked through interrupt gates, so
     94     ; IF flag automatically cleared at the entry point
     95     ;
     96 
     97     ;
     98     ; Get vector number from top of stack
     99     ;
    100     xchg    ecx, [esp]
    101     and     ecx, 0xFF       ; Vector number should be less than 256
    102     cmp     ecx, 32         ; Intel reserved vector for exceptions?
    103     jae     NoErrorCode
    104     bt      [ASM_PFX(mErrorCodeFlag)], ecx
    105     jc      HasErrorCode
    106 
    107 NoErrorCode:
    108 
    109     ;
    110     ; Stack:
    111     ; +---------------------+
    112     ; +    EFlags           +
    113     ; +---------------------+
    114     ; +    CS               +
    115     ; +---------------------+
    116     ; +    EIP              +
    117     ; +---------------------+
    118     ; +    ECX              +
    119     ; +---------------------+ <-- ESP
    120     ;
    121     ; Registers:
    122     ;   ECX - Vector Number
    123     ;
    124 
    125     ;
    126     ; Put Vector Number on stack
    127     ;
    128     push    ecx
    129 
    130     ;
    131     ; Put 0 (dummy) error code on stack, and restore ECX
    132     ;
    133     xor     ecx, ecx  ; ECX = 0
    134     xchg    ecx, [esp+4]
    135 
    136     jmp     ErrorCodeAndVectorOnStack
    137 
    138 HasErrorCode:
    139 
    140     ;
    141     ; Stack:
    142     ; +---------------------+
    143     ; +    EFlags           +
    144     ; +---------------------+
    145     ; +    CS               +
    146     ; +---------------------+
    147     ; +    EIP              +
    148     ; +---------------------+
    149     ; +    Error Code       +
    150     ; +---------------------+
    151     ; +    ECX              +
    152     ; +---------------------+ <-- ESP
    153     ;
    154     ; Registers:
    155     ;   ECX - Vector Number
    156     ;
    157 
    158     ;
    159     ; Put Vector Number on stack and restore ECX
    160     ;
    161     xchg    ecx, [esp]
    162 
    163 ErrorCodeAndVectorOnStack:
    164     push    ebp
    165     mov     ebp, esp
    166 
    167     ;
    168     ; Stack:
    169     ; +---------------------+
    170     ; +    EFlags           +
    171     ; +---------------------+
    172     ; +    CS               +
    173     ; +---------------------+
    174     ; +    EIP              +
    175     ; +---------------------+
    176     ; +    Error Code       +
    177     ; +---------------------+
    178     ; +    Vector Number    +
    179     ; +---------------------+
    180     ; +    EBP              +
    181     ; +---------------------+ <-- EBP
    182     ;
    183 
    184     ;
    185     ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
    186     ; is 16-byte aligned
    187     ;
    188     and     esp, 0xfffffff0
    189     sub     esp, 12
    190 
    191     sub     esp, 8
    192     push    0            ; clear EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
    193     push    0            ; clear EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
    194 
    195 ;; UINT32  Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
    196     push    eax
    197     push    ecx
    198     push    edx
    199     push    ebx
    200     lea     ecx, [ebp + 6 * 4]
    201     push    ecx                          ; ESP
    202     push    dword [ebp]              ; EBP
    203     push    esi
    204     push    edi
    205 
    206 ;; UINT32  Gs, Fs, Es, Ds, Cs, Ss;
    207     mov     eax, ss
    208     push    eax
    209     movzx   eax, word [ebp + 4 * 4]
    210     push    eax
    211     mov     eax, ds
    212     push    eax
    213     mov     eax, es
    214     push    eax
    215     mov     eax, fs
    216     push    eax
    217     mov     eax, gs
    218     push    eax
    219 
    220 ;; UINT32  Eip;
    221     mov     eax, [ebp + 3 * 4]
    222     push    eax
    223 
    224 ;; UINT32  Gdtr[2], Idtr[2];
    225     sub     esp, 8
    226     sidt    [esp]
    227     mov     eax, [esp + 2]
    228     xchg    eax, [esp]
    229     and     eax, 0xFFFF
    230     mov     [esp+4], eax
    231 
    232     sub     esp, 8
    233     sgdt    [esp]
    234     mov     eax, [esp + 2]
    235     xchg    eax, [esp]
    236     and     eax, 0xFFFF
    237     mov     [esp+4], eax
    238 
    239 ;; UINT32  Ldtr, Tr;
    240     xor     eax, eax
    241     str     ax
    242     push    eax
    243     sldt    ax
    244     push    eax
    245 
    246 ;; UINT32  EFlags;
    247     mov     eax, [ebp + 5 * 4]
    248     push    eax
    249 
    250 ;; UINT32  Cr0, Cr1, Cr2, Cr3, Cr4;
    251     mov     eax, 1
    252     push    ebx         ; temporarily save value of ebx on stack
    253     cpuid               ; use CPUID to determine if FXSAVE/FXRESTOR and DE
    254                         ; are supported
    255     pop     ebx         ; retore value of ebx that was overwritten by CPUID
    256     mov     eax, cr4
    257     push    eax         ; push cr4 firstly
    258     test    edx, BIT24  ; Test for FXSAVE/FXRESTOR support
    259     jz      .1
    260     or      eax, BIT9   ; Set CR4.OSFXSR
    261 .1:
    262     test    edx, BIT2   ; Test for Debugging Extensions support
    263     jz      .2
    264     or      eax, BIT3   ; Set CR4.DE
    265 .2:
    266     mov     cr4, eax
    267     mov     eax, cr3
    268     push    eax
    269     mov     eax, cr2
    270     push    eax
    271     xor     eax, eax
    272     push    eax
    273     mov     eax, cr0
    274     push    eax
    275 
    276 ;; UINT32  Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
    277     mov     eax, dr7
    278     push    eax
    279     mov     eax, dr6
    280     push    eax
    281     mov     eax, dr3
    282     push    eax
    283     mov     eax, dr2
    284     push    eax
    285     mov     eax, dr1
    286     push    eax
    287     mov     eax, dr0
    288     push    eax
    289 
    290 ;; FX_SAVE_STATE_IA32 FxSaveState;
    291     sub     esp, 512
    292     mov     edi, esp
    293     test    edx, BIT24  ; Test for FXSAVE/FXRESTOR support.
    294                         ; edx still contains result from CPUID above
    295     jz      .3
    296     db      0xf, 0xae, 0x7 ;fxsave [edi]
    297 .3:
    298 
    299 ;; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
    300     cld
    301 
    302 ;; UINT32  ExceptionData;
    303     push    dword [ebp + 2 * 4]
    304 
    305 ;; Prepare parameter and call
    306     mov     edx, esp
    307     push    edx
    308     mov     edx, dword [ebp + 1 * 4]
    309     push    edx
    310 
    311     ;
    312     ; Call External Exception Handler
    313     ;
    314     mov     eax, ASM_PFX(CommonExceptionHandler)
    315     call    eax
    316     add     esp, 8
    317 
    318     cli
    319 ;; UINT32  ExceptionData;
    320     add     esp, 4
    321 
    322 ;; FX_SAVE_STATE_IA32 FxSaveState;
    323     mov     esi, esp
    324     mov     eax, 1
    325     cpuid               ; use CPUID to determine if FXSAVE/FXRESTOR
    326                         ; are supported
    327     test    edx, BIT24  ; Test for FXSAVE/FXRESTOR support
    328     jz      .4
    329     db      0xf, 0xae, 0xe ; fxrstor [esi]
    330 .4:
    331     add     esp, 512
    332 
    333 ;; UINT32  Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
    334 ;; Skip restoration of DRx registers to support in-circuit emualators
    335 ;; or debuggers set breakpoint in interrupt/exception context
    336     add     esp, 4 * 6
    337 
    338 ;; UINT32  Cr0, Cr1, Cr2, Cr3, Cr4;
    339     pop     eax
    340     mov     cr0, eax
    341     add     esp, 4    ; not for Cr1
    342     pop     eax
    343     mov     cr2, eax
    344     pop     eax
    345     mov     cr3, eax
    346     pop     eax
    347     mov     cr4, eax
    348 
    349 ;; UINT32  EFlags;
    350     pop     dword [ebp + 5 * 4]
    351 
    352 ;; UINT32  Ldtr, Tr;
    353 ;; UINT32  Gdtr[2], Idtr[2];
    354 ;; Best not let anyone mess with these particular registers...
    355     add     esp, 24
    356 
    357 ;; UINT32  Eip;
    358     pop     dword [ebp + 3 * 4]
    359 
    360 ;; UINT32  Gs, Fs, Es, Ds, Cs, Ss;
    361 ;; NOTE - modified segment registers could hang the debugger...  We
    362 ;;        could attempt to insulate ourselves against this possibility,
    363 ;;        but that poses risks as well.
    364 ;;
    365     pop     gs
    366     pop     fs
    367     pop     es
    368     pop     ds
    369     pop     dword [ebp + 4 * 4]
    370     pop     ss
    371 
    372 ;; UINT32  Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
    373     pop     edi
    374     pop     esi
    375     add     esp, 4   ; not for ebp
    376     add     esp, 4   ; not for esp
    377     pop     ebx
    378     pop     edx
    379     pop     ecx
    380     pop     eax
    381 
    382     pop     dword [ebp - 8]
    383     pop     dword [ebp - 4]
    384     mov     esp, ebp
    385     pop     ebp
    386     add     esp, 8
    387     cmp     dword [esp - 16], 0   ; check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
    388     jz      DoReturn
    389     cmp     dword [esp - 20], 1   ; check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
    390     jz      ErrorCode
    391     jmp     dword [esp - 16]
    392 ErrorCode:
    393     sub     esp, 4
    394     jmp     dword [esp - 12]
    395 
    396 DoReturn:
    397     cmp     dword [ASM_PFX(mDoFarReturnFlag)], 0   ; Check if need to do far return instead of IRET
    398     jz      DoIret
    399     push    dword [esp + 8]    ; save EFLAGS
    400     add     esp, 16
    401     push    dword [esp - 8]    ; save CS in new location
    402     push    dword [esp - 8]    ; save EIP in new location
    403     push    dword [esp - 8]    ; save EFLAGS in new location
    404     popfd                ; restore EFLAGS
    405     retf                 ; far return
    406 
    407 DoIret:
    408     iretd
    409 
    410 ;---------------------------------------;
    411 ; _AsmGetTemplateAddressMap                  ;
    412 ;----------------------------------------------------------------------------;
    413 ;
    414 ; Protocol prototype
    415 ;   AsmGetTemplateAddressMap (
    416 ;     EXCEPTION_HANDLER_TEMPLATE_MAP *AddressMap
    417 ;   );
    418 ;
    419 ; Routine Description:
    420 ;
    421 ;  Return address map of interrupt handler template so that C code can generate
    422 ;  interrupt table.
    423 ;
    424 ; Arguments:
    425 ;
    426 ;
    427 ; Returns:
    428 ;
    429 ;   Nothing
    430 ;
    431 ;
    432 ; Input:  [ebp][0]  = Original ebp
    433 ;         [ebp][4]  = Return address
    434 ;
    435 ; Output: Nothing
    436 ;
    437 ; Destroys: Nothing
    438 ;-----------------------------------------------------------------------------;
    439 global ASM_PFX(AsmGetTemplateAddressMap)
    440 ASM_PFX(AsmGetTemplateAddressMap):
    441     push    ebp                 ; C prolog
    442     mov     ebp, esp
    443     pushad
    444 
    445     mov ebx, dword [ebp + 0x8]
    446     mov dword [ebx],      AsmIdtVectorBegin
    447     mov dword [ebx + 0x4], (AsmIdtVectorEnd - AsmIdtVectorBegin) / 32
    448     mov dword [ebx + 0x8], HookAfterStubBegin
    449 
    450     popad
    451     pop     ebp
    452     ret
    453 
    454 ;-------------------------------------------------------------------------------------
    455 ;  AsmVectorNumFixup (*NewVectorAddr, VectorNum, *OldVectorAddr);
    456 ;-------------------------------------------------------------------------------------
    457 global ASM_PFX(AsmVectorNumFixup)
    458 ASM_PFX(AsmVectorNumFixup):
    459     mov     eax, dword [esp + 8]
    460     mov     ecx, [esp + 4]
    461     mov     [ecx + (VectorNum - HookAfterStubBegin)], al
    462     ret
    463