Home | History | Annotate | Download | only in Ia32
      1 #------------------------------------------------------------------------------
      2 #*
      3 #*   Copyright (c) 2012 - 2015, Intel Corporation. All rights reserved.<BR>
      4 #*   This program and the accompanying materials
      5 #*   are licensed and made available under the terms and conditions of the BSD License
      6 #*   which accompanies this distribution.  The full text of the license may be found at
      7 #*   http://opensource.org/licenses/bsd-license.php
      8 #*
      9 #*   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     10 #*   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     11 #*
     12 #*    ExceptionHandlerAsm.S
     13 #*
     14 #*   Abstract:
     15 #*
     16 #*     IA32 CPU Exception Handler
     17 #
     18 #------------------------------------------------------------------------------
     19 
     20 
     21 #.MMX
     22 #.XMM
     23 
     24 ASM_GLOBAL ASM_PFX(CommonExceptionHandler)
     25 ASM_GLOBAL ASM_PFX(CommonInterruptEntry)
     26 ASM_GLOBAL ASM_PFX(HookAfterStubHeaderEnd)
     27 
     28 #EXTRN ASM_PFX(mErrorCodeFlag):DWORD           # Error code flags for exceptions
     29 #EXTRN ASM_PFX(mDoFarReturnFlag):DWORD         # Do far return flag
     30 
     31 .text
     32 
     33 #
     34 # exception handler stub table
     35 #
     36 Exception0Handle:
     37     .byte   0x6a    #  push #VectorNum
     38     .byte   0
     39     pushl   %eax
     40     .byte   0xB8
     41     .long   ASM_PFX(CommonInterruptEntry)
     42     jmp     *%eax
     43 Exception1Handle:
     44     .byte   0x6a    #  push #VectorNum
     45     .byte   1
     46     pushl   %eax
     47     .byte   0xB8
     48     .long   ASM_PFX(CommonInterruptEntry)
     49     jmp     *%eax
     50 Exception2Handle:
     51     .byte   0x6a    #  push #VectorNum
     52     .byte   2
     53     pushl   %eax
     54     .byte   0xB8
     55     .long   ASM_PFX(CommonInterruptEntry)
     56     jmp     *%eax
     57 Exception3Handle:
     58     .byte   0x6a    #  push #VectorNum
     59     .byte   3
     60     pushl   %eax
     61     .byte   0xB8
     62     .long   ASM_PFX(CommonInterruptEntry)
     63     jmp     *%eax
     64 Exception4Handle:
     65     .byte   0x6a    #  push #VectorNum
     66     .byte   4
     67     pushl   %eax
     68     .byte   0xB8
     69     .long   ASM_PFX(CommonInterruptEntry)
     70     jmp     *%eax
     71 Exception5Handle:
     72     .byte   0x6a    #  push #VectorNum
     73     .byte   5
     74     pushl   %eax
     75     .byte   0xB8
     76     .long   ASM_PFX(CommonInterruptEntry)
     77     jmp     *%eax
     78 Exception6Handle:
     79     .byte   0x6a    #  push #VectorNum
     80     .byte   6
     81     pushl   %eax
     82     .byte   0xB8
     83     .long   ASM_PFX(CommonInterruptEntry)
     84     jmp     *%eax
     85 Exception7Handle:
     86     .byte   0x6a    #  push #VectorNum
     87     .byte   7
     88     pushl   %eax
     89     .byte   0xB8
     90     .long   ASM_PFX(CommonInterruptEntry)
     91     jmp     *%eax
     92 Exception8Handle:
     93     .byte   0x6a    #  push #VectorNum
     94     .byte   8
     95     pushl   %eax
     96      .byte   0xB8
     97     .long   ASM_PFX(CommonInterruptEntry)
     98     jmp     *%eax
     99 Exception9Handle:
    100     .byte   0x6a    #  push #VectorNum
    101     .byte   9
    102     pushl   %eax
    103     .byte   0xB8
    104     .long   ASM_PFX(CommonInterruptEntry)
    105     jmp     *%eax
    106 Exception10Handle:
    107     .byte   0x6a    #  push #VectorNum
    108     .byte   10
    109     pushl   %eax
    110     .byte   0xB8
    111     .long   ASM_PFX(CommonInterruptEntry)
    112     jmp     *%eax
    113 Exception11Handle:
    114     .byte   0x6a    #  push #VectorNum
    115     .byte   11
    116     pushl   %eax
    117     .byte   0xB8
    118     .long   ASM_PFX(CommonInterruptEntry)
    119     jmp     *%eax
    120 Exception12Handle:
    121     .byte   0x6a    #  push #VectorNum
    122     .byte   12
    123     pushl   %eax
    124     .byte   0xB8
    125     .long   ASM_PFX(CommonInterruptEntry)
    126     jmp     *%eax
    127 Exception13Handle:
    128     .byte   0x6a    #  push #VectorNum
    129     .byte   13
    130     pushl   %eax
    131     .byte   0xB8
    132     .long   ASM_PFX(CommonInterruptEntry)
    133     jmp     *%eax
    134 Exception14Handle:
    135     .byte   0x6a    #  push #VectorNum
    136     .byte   14
    137     pushl   %eax
    138     .byte   0xB8
    139     .long   ASM_PFX(CommonInterruptEntry)
    140     jmp     *%eax
    141 Exception15Handle:
    142     .byte   0x6a    #  push #VectorNum
    143     .byte   15
    144     pushl   %eax
    145     .byte   0xB8
    146     .long   ASM_PFX(CommonInterruptEntry)
    147     jmp     *%eax
    148 Exception16Handle:
    149     .byte   0x6a    #  push #VectorNum
    150     .byte   16
    151     pushl   %eax
    152     .byte   0xB8
    153     .long   ASM_PFX(CommonInterruptEntry)
    154     jmp     *%eax
    155 Exception17Handle:
    156     .byte   0x6a    #  push #VectorNum
    157     .byte   17
    158     pushl   %eax
    159     .byte   0xB8
    160     .long   ASM_PFX(CommonInterruptEntry)
    161     jmp     *%eax
    162 Exception18Handle:
    163     .byte   0x6a    #  push #VectorNum
    164     .byte   18
    165     pushl   %eax
    166     .byte   0xB8
    167     .long   ASM_PFX(CommonInterruptEntry)
    168     jmp     *%eax
    169 Exception19Handle:
    170     .byte   0x6a    #  push #VectorNum
    171     .byte   19
    172     pushl   %eax
    173     .byte   0xB8
    174     .long   ASM_PFX(CommonInterruptEntry)
    175     jmp     *%eax
    176 Exception20Handle:
    177     .byte   0x6a    #  push #VectorNum
    178     .byte   20
    179     pushl   %eax
    180     .byte   0xB8
    181     .long   ASM_PFX(CommonInterruptEntry)
    182     jmp     *%eax
    183 Exception21Handle:
    184     .byte   0x6a    #  push #VectorNum
    185     .byte   21
    186     pushl   %eax
    187     .byte   0xB8
    188     .long   ASM_PFX(CommonInterruptEntry)
    189     jmp     *%eax
    190 Exception22Handle:
    191     .byte   0x6a    #  push #VectorNum
    192     .byte   22
    193     pushl   %eax
    194     .byte   0xB8
    195     .long   ASM_PFX(CommonInterruptEntry)
    196     jmp     *%eax
    197 Exception23Handle:
    198     .byte   0x6a    #  push #VectorNum
    199     .byte   23
    200     pushl   %eax
    201     .byte   0xB8
    202     .long   ASM_PFX(CommonInterruptEntry)
    203     jmp     *%eax
    204 Exception24Handle:
    205     .byte   0x6a    #  push #VectorNum
    206     .byte   24
    207     pushl   %eax
    208     .byte   0xB8
    209     .long   ASM_PFX(CommonInterruptEntry)
    210     jmp     *%eax
    211 Exception25Handle:
    212     .byte   0x6a    #  push #VectorNum
    213     .byte   25
    214     pushl   %eax
    215     .byte   0xB8
    216     .long   ASM_PFX(CommonInterruptEntry)
    217     jmp     *%eax
    218 Exception26Handle:
    219     .byte   0x6a    #  push #VectorNum
    220     .byte   26
    221     pushl   %eax
    222     .byte   0xB8
    223     .long   ASM_PFX(CommonInterruptEntry)
    224     jmp     *%eax
    225 Exception27Handle:
    226     .byte   0x6a    #  push #VectorNum
    227     .byte   27
    228     pushl   %eax
    229     .byte   0xB8
    230     .long   ASM_PFX(CommonInterruptEntry)
    231     jmp     *%eax
    232 Exception28Handle:
    233     .byte   0x6a    #  push #VectorNum
    234     .byte   28
    235     pushl   %eax
    236     .byte   0xB8
    237     .long   ASM_PFX(CommonInterruptEntry)
    238     jmp     *%eax
    239 Exception29Handle:
    240     .byte   0x6a    #  push #VectorNum
    241     .byte   29
    242     pushl   %eax
    243     .byte   0xB8
    244     .long   ASM_PFX(CommonInterruptEntry)
    245     jmp     *%eax
    246 Exception30Handle:
    247     .byte   0x6a    #  push #VectorNum
    248     .byte   30
    249     pushl   %eax
    250     .byte   0xB8
    251     .long   ASM_PFX(CommonInterruptEntry)
    252     jmp     *%eax
    253 Exception31Handle:
    254     .byte   0x6a    #  push #VectorNum
    255     .byte   31
    256     pushl   %eax
    257     .byte   0xB8
    258     .long   ASM_PFX(CommonInterruptEntry)
    259     jmp     *%eax
    260 
    261 HookAfterStubBegin:
    262     .byte   0x6a       # push
    263 VectorNum:
    264     .byte   0          # 0 will be fixed
    265     pushl   %eax
    266     .byte   0xB8       # movl    ASM_PFX(HookAfterStubHeaderEnd), %eax
    267     .long   ASM_PFX(HookAfterStubHeaderEnd)
    268     jmp     *%eax
    269 ASM_GLOBAL ASM_PFX(HookAfterStubHeaderEnd)
    270 ASM_PFX(HookAfterStubHeaderEnd):
    271     popl    %eax
    272     subl    $8, %esp        # reserve room for filling exception data later
    273     pushl   8(%esp)
    274     xchgl   (%esp), %ecx    # get vector number
    275     bt      %ecx, ASM_PFX(mErrorCodeFlag)
    276     jnc     NoErrorData
    277     pushl    (%esp)         # addition push if exception data needed
    278 NoErrorData:
    279     xchg    (%esp), %ecx    # restore ecx
    280     pushl   %eax
    281 
    282 #---------------------------------------;
    283 # CommonInterruptEntry                  ;
    284 #---------------------------------------;
    285 # The follow algorithm is used for the common interrupt routine.
    286 
    287 ASM_GLOBAL ASM_PFX(CommonInterruptEntry)
    288 ASM_PFX(CommonInterruptEntry):
    289     cli
    290     popl    %eax
    291     #
    292     # All interrupt handlers are invoked through interrupt gates, so
    293     # IF flag automatically cleared at the entry point
    294     #
    295 
    296     #
    297     # Get vector number from top of stack
    298     #
    299     xchgl   (%esp), %ecx
    300     andl    $0x0FF, %ecx      # Vector number should be less than 256
    301     cmpl    $32, %ecx         # Intel reserved vector for exceptions?
    302     jae     NoErrorCode
    303     bt      %ecx, ASM_PFX(mErrorCodeFlag)
    304     jc      HasErrorCode
    305 
    306 NoErrorCode:
    307 
    308     #
    309     # Stack:
    310     # +---------------------+
    311     # +    EFlags           +
    312     # +---------------------+
    313     # +    CS               +
    314     # +---------------------+
    315     # +    EIP              +
    316     # +---------------------+
    317     # +    ECX              +
    318     # +---------------------+ <-- ESP
    319     #
    320     # Registers:
    321     #   ECX - Vector Number
    322     #
    323 
    324     #
    325     # Put Vector Number on stack
    326     #
    327     pushl   %ecx
    328 
    329     #
    330     # Put 0 (dummy) error code on stack, and restore ECX
    331     #
    332     xorl    %ecx, %ecx  # ECX = 0
    333     xchgl   4(%esp), %ecx
    334 
    335     jmp     ErrorCodeAndVectorOnStack
    336 
    337 HasErrorCode:
    338 
    339     #
    340     # Stack:
    341     # +---------------------+
    342     # +    EFlags           +
    343     # +---------------------+
    344     # +    CS               +
    345     # +---------------------+
    346     # +    EIP              +
    347     # +---------------------+
    348     # +    Error Code       +
    349     # +---------------------+
    350     # +    ECX              +
    351     # +---------------------+ <-- ESP
    352     #
    353     # Registers:
    354     #   ECX - Vector Number
    355     #
    356 
    357     #
    358     # Put Vector Number on stack and restore ECX
    359     #
    360     xchgl   (%esp), %ecx
    361 
    362 ErrorCodeAndVectorOnStack:
    363     pushl   %ebp
    364     movl    %esp, %ebp
    365 
    366     #
    367     # Stack:
    368     # +---------------------+
    369     # +    EFlags           +
    370     # +---------------------+
    371     # +    CS               +
    372     # +---------------------+
    373     # +    EIP              +
    374     # +---------------------+
    375     # +    Error Code       +
    376     # +---------------------+
    377     # +    Vector Number    +
    378     # +---------------------+
    379     # +    EBP              +
    380     # +---------------------+ <-- EBP
    381     #
    382 
    383     #
    384     # Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
    385     # is 16-byte aligned
    386     #
    387     andl    $0x0fffffff0, %esp
    388     subl    $12, %esp
    389 
    390     subl    $8, %esp
    391     pushl   $0         # check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
    392     pushl   $0         # check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
    393 
    394 #; UINT32  Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
    395     pushl   %eax
    396     pushl   %ecx
    397     pushl   %edx
    398     pushl   %ebx
    399     leal    24(%ebp), %ecx
    400     pushl   %ecx                          # ESP
    401     pushl   (%ebp)              # EBP
    402     pushl   %esi
    403     pushl   %edi
    404 
    405 #; UINT32  Gs, Fs, Es, Ds, Cs, Ss;
    406     movl    %ss, %eax
    407     pushl   %eax
    408     movzwl  16(%ebp), %eax
    409     pushl   %eax
    410     movl    %ds, %eax
    411     pushl   %eax
    412     movl    %es, %eax
    413     pushl   %eax
    414     movl    %fs, %eax
    415     pushl   %eax
    416     movl    %gs, %eax
    417     pushl   %eax
    418 
    419 #; UINT32  Eip;
    420     movl    12(%ebp), %eax
    421     pushl   %eax
    422 
    423 #; UINT32  Gdtr[2], Idtr[2];
    424     subl    $8, %esp
    425     sidt    (%esp)
    426     movl    2(%esp), %eax
    427     xchgl   (%esp), %eax
    428     andl    $0x0FFFF, %eax
    429     movl    %eax, 4(%esp)
    430 
    431     subl    $8, %esp
    432     sgdt    (%esp)
    433     movl    2(%esp), %eax
    434     xchgl   (%esp), %eax
    435     andl    $0x0FFFF, %eax
    436     movl    %eax, 4(%esp)
    437 
    438 #; UINT32  Ldtr, Tr;
    439     xorl    %eax, %eax
    440     str     %ax
    441     pushl   %eax
    442     sldt    %ax
    443     pushl   %eax
    444 
    445 #; UINT32  EFlags;
    446     movl    20(%ebp), %eax
    447     pushl   %eax
    448 
    449 #; UINT32  Cr0, Cr1, Cr2, Cr3, Cr4;
    450 ## insure FXSAVE/FXRSTOR is enabled in CR4...
    451 ## ... while we're at it, make sure DE is also enabled...
    452     mov     $1, %eax
    453     pushl   %ebx                         # temporarily save value of ebx on stack
    454     cpuid                                # use CPUID to determine if FXSAVE/FXRESTOR
    455                                          # and DE are supported
    456     popl    %ebx                         # retore value of ebx that was overwritten
    457                                          # by CPUID
    458     movl    %cr4, %eax
    459     pushl   %eax                         # push cr4 firstly
    460     testl   $BIT24, %edx                 # Test for FXSAVE/FXRESTOR support
    461     jz      L1
    462     orl     $BIT9, %eax                  # Set CR4.OSFXSR
    463 L1:
    464     testl   $BIT2, %edx                  # Test for Debugging Extensions support
    465     jz      L2
    466     orl     $BIT3, %eax                  # Set CR4.DE
    467 L2:
    468     movl    %eax, %cr4
    469     movl    %cr3, %eax
    470     pushl   %eax
    471     movl    %cr2, %eax
    472     pushl   %eax
    473     xorl    %eax, %eax
    474     pushl   %eax
    475     movl    %cr0, %eax
    476     pushl   %eax
    477 
    478 #; UINT32  Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
    479     movl    %dr7, %eax
    480     pushl   %eax
    481     movl    %dr6, %eax
    482     pushl   %eax
    483     movl    %dr3, %eax
    484     pushl   %eax
    485     movl    %dr2, %eax
    486     pushl   %eax
    487     movl    %dr1, %eax
    488     pushl   %eax
    489     movl    %dr0, %eax
    490     pushl   %eax
    491 
    492 #; FX_SAVE_STATE_IA32 FxSaveState;
    493     subl    $512, %esp
    494     movl    %esp, %edi
    495     testl   $BIT24, %edx     # Test for FXSAVE/FXRESTOR support.
    496                              # edx still contains result from CPUID above
    497     jz      L3
    498     .byte      0x0f, 0x0ae, 0x07 #fxsave [edi]
    499 L3:
    500 
    501 #; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
    502     cld
    503 
    504 #; UINT32  ExceptionData;
    505     pushl   8(%ebp)
    506 
    507 #; Prepare parameter and call
    508     movl    %esp, %edx
    509     pushl   %edx
    510     movl    4(%ebp), %edx
    511     pushl   %edx
    512 
    513     #
    514     # Call External Exception Handler
    515     #
    516     call    ASM_PFX(CommonExceptionHandler)
    517     addl    $8, %esp
    518 
    519     cli
    520 #; UINT32  ExceptionData;
    521     addl    $4, %esp
    522 
    523 #; FX_SAVE_STATE_IA32 FxSaveState;
    524     movl    %esp, %esi
    525     movl    $1, %eax
    526     cpuid                    # use CPUID to determine if FXSAVE/FXRESTOR
    527                              # are supported
    528     testl   $BIT24, %edx     # Test for FXSAVE/FXRESTOR support
    529     jz      L4
    530     .byte      0x0f, 0x0ae, 0x0e # fxrstor [esi]
    531 L4:
    532     addl    $512, %esp
    533 
    534 #; UINT32  Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
    535 #; Skip restoration of DRx registers to support in-circuit emualators
    536 #; or debuggers set breakpoint in interrupt/exception context
    537     addl    $24, %esp
    538 
    539 #; UINT32  Cr0, Cr1, Cr2, Cr3, Cr4;
    540     popl    %eax
    541     movl    %eax, %cr0
    542     addl    $4, %esp    # not for Cr1
    543     popl    %eax
    544     movl    %eax, %cr2
    545     popl    %eax
    546     movl    %eax, %cr3
    547     popl    %eax
    548     movl    %eax, %cr4
    549 
    550 #; UINT32  EFlags;
    551     popl    20(%ebp)
    552 
    553 #; UINT32  Ldtr, Tr;
    554 #; UINT32  Gdtr[2], Idtr[2];
    555 #; Best not let anyone mess with these particular registers...
    556     addl    $24, %esp
    557 
    558 #; UINT32  Eip;
    559     popl    12(%ebp)
    560 
    561 #; UINT32  Gs, Fs, Es, Ds, Cs, Ss;
    562 #; NOTE - modified segment registers could hang the debugger...  We
    563 #;        could attempt to insulate ourselves against this possibility,
    564 #;        but that poses risks as well.
    565 #;
    566     popl    %gs
    567     popl    %fs
    568     popl    %es
    569     popl    %ds
    570     popl    16(%ebp)
    571     popl    %ss
    572 
    573 #; UINT32  Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
    574     popl    %edi
    575     popl    %esi
    576     addl    $4, %esp   # not for ebp
    577     addl    $4, %esp   # not for esp
    578     popl    %ebx
    579     popl    %edx
    580     popl    %ecx
    581     popl    %eax
    582 
    583     popl    -8(%ebp)
    584     popl    -4(%ebp)
    585     movl    %ebp, %esp
    586     popl    %ebp
    587     addl    $8, %esp
    588     cmpl    $0, -16(%esp)  # check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
    589     jz      DoReturn
    590     cmpl    $1, -20(%esp)  # check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
    591     jz      ErrorCode
    592     jmp     *-16(%esp)
    593 ErrorCode:
    594     subl    $4, %esp
    595     jmp     *-12(%esp)
    596 
    597 DoReturn:
    598     cmpl    $0, ASM_PFX(mDoFarReturnFlag)
    599     jz      DoIret
    600     pushl   8(%esp)       # save EFLAGS
    601     addl    $16, %esp
    602     pushl   -8(%esp)      # save CS in new location
    603     pushl   -8(%esp)      # save EIP in new location
    604     pushl   -8(%esp)      # save EFLAGS in new location
    605     popfl                 # restore EFLAGS
    606     lret                  # far return
    607 
    608 DoIret:
    609     iretl
    610 
    611 
    612 #---------------------------------------;
    613 # _AsmGetTemplateAddressMap             ;
    614 #---------------------------------------;
    615 #
    616 # Protocol prototype
    617 #   AsmGetTemplateAddressMap (
    618 #     EXCEPTION_HANDLER_TEMPLATE_MAP *AddressMap
    619 #   );
    620 #
    621 # Routine Description:
    622 #
    623 #  Return address map of interrupt handler template so that C code can generate
    624 #  interrupt table.
    625 #
    626 # Arguments:
    627 #
    628 #
    629 # Returns:
    630 #
    631 #   Nothing
    632 #
    633 #
    634 # Input:  [ebp][0]  = Original ebp
    635 #         [ebp][4]  = Return address
    636 #
    637 # Output: Nothing
    638 #
    639 # Destroys: Nothing
    640 #-----------------------------------------------------------------------------;
    641 #-------------------------------------------------------------------------------------
    642 #  AsmGetAddressMap (&AddressMap);
    643 #-------------------------------------------------------------------------------------
    644 ASM_GLOBAL ASM_PFX(AsmGetTemplateAddressMap)
    645 ASM_PFX(AsmGetTemplateAddressMap):
    646 
    647         pushl       %ebp
    648         movl        %esp,%ebp
    649         pushal
    650 
    651         movl        0x8(%ebp), %ebx
    652         movl        $Exception0Handle, (%ebx)
    653         movl        $(Exception1Handle - Exception0Handle), 0x4(%ebx)
    654         movl        $(HookAfterStubBegin), 0x8(%ebx)
    655 
    656         popal
    657         popl        %ebp
    658         ret
    659 #-------------------------------------------------------------------------------------
    660 #  AsmVectorNumFixup (*NewVectorAddr, VectorNum, *OldVectorAddr);
    661 #-------------------------------------------------------------------------------------
    662 ASM_GLOBAL ASM_PFX(AsmVectorNumFixup)
    663 ASM_PFX(AsmVectorNumFixup):
    664         movl  8(%esp), %eax
    665         movl  4(%esp), %ecx
    666         movb  %al, (VectorNum - HookAfterStubBegin)(%ecx)
    667         ret
    668