]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.S
UefiCpuPkg/CpuExceptionHandlerLib: Add stack switch support
[mirror_edk2.git] / UefiCpuPkg / Library / CpuExceptionHandlerLib / Ia32 / ExceptionHandlerAsm.S
index b9e881ac5e5d8fe8b28179287b23a1e9fbfdd462..c134257d9d5854e7f2a211ccd3e6722230b39dbf 100644 (file)
@@ -1,6 +1,6 @@
 #------------------------------------------------------------------------------\r
 #*\r
-#*   Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>\r
+#*   Copyright (c) 2012 - 2015, Intel Corporation. All rights reserved.<BR>\r
 #*   This program and the accompanying materials\r
 #*   are licensed and made available under the terms and conditions of the BSD License\r
 #*   which accompanies this distribution.  The full text of the license may be found at\r
 #------------------------------------------------------------------------------\r
 \r
 \r
-\r
-\r
-\r
 #.MMX\r
 #.XMM\r
 \r
 ASM_GLOBAL ASM_PFX(CommonExceptionHandler)\r
 ASM_GLOBAL ASM_PFX(CommonInterruptEntry)\r
+ASM_GLOBAL ASM_PFX(HookAfterStubHeaderEnd)\r
 \r
-#EXTRN ASM_PFX(mErrorCodeFlag):DWORD # Error code flags for exceptions\r
+#EXTRN ASM_PFX(mErrorCodeFlag):DWORD           # Error code flags for exceptions\r
+#EXTRN ASM_PFX(mDoFarReturnFlag):DWORD         # Do far return flag\r
 \r
 .text\r
 \r
@@ -35,101 +34,250 @@ ASM_GLOBAL ASM_PFX(CommonInterruptEntry)
 # exception handler stub table\r
 #\r
 Exception0Handle:\r
-    pushl   $0\r
-    jmp     ASM_PFX(CommonInterruptEntry)\r
+    .byte   0x6a    #  push #VectorNum\r
+    .byte   0\r
+    pushl   %eax\r
+    .byte   0xB8\r
+    .long   ASM_PFX(CommonInterruptEntry)\r
+    jmp     *%eax\r
 Exception1Handle:\r
-    pushl   $1\r
-    jmp     ASM_PFX(CommonInterruptEntry)\r
+    .byte   0x6a    #  push #VectorNum\r
+    .byte   1\r
+    pushl   %eax\r
+    .byte   0xB8\r
+    .long   ASM_PFX(CommonInterruptEntry)\r
+    jmp     *%eax\r
 Exception2Handle:\r
-    pushl   $2\r
-    jmp     ASM_PFX(CommonInterruptEntry)\r
+    .byte   0x6a    #  push #VectorNum\r
+    .byte   2\r
+    pushl   %eax\r
+    .byte   0xB8\r
+    .long   ASM_PFX(CommonInterruptEntry)\r
+    jmp     *%eax\r
 Exception3Handle:\r
-    pushl    $3\r
-    jmp     ASM_PFX(CommonInterruptEntry)\r
+    .byte   0x6a    #  push #VectorNum\r
+    .byte   3\r
+    pushl   %eax\r
+    .byte   0xB8\r
+    .long   ASM_PFX(CommonInterruptEntry)\r
+    jmp     *%eax\r
 Exception4Handle:\r
-    pushl    $4\r
-    jmp     ASM_PFX(CommonInterruptEntry)\r
+    .byte   0x6a    #  push #VectorNum\r
+    .byte   4\r
+    pushl   %eax\r
+    .byte   0xB8\r
+    .long   ASM_PFX(CommonInterruptEntry)\r
+    jmp     *%eax\r
 Exception5Handle:\r
-    pushl    $5\r
-    jmp     ASM_PFX(CommonInterruptEntry)\r
+    .byte   0x6a    #  push #VectorNum\r
+    .byte   5\r
+    pushl   %eax\r
+    .byte   0xB8\r
+    .long   ASM_PFX(CommonInterruptEntry)\r
+    jmp     *%eax\r
 Exception6Handle:\r
-    pushl    $6\r
-    jmp     ASM_PFX(CommonInterruptEntry)\r
+    .byte   0x6a    #  push #VectorNum\r
+    .byte   6\r
+    pushl   %eax\r
+    .byte   0xB8\r
+    .long   ASM_PFX(CommonInterruptEntry)\r
+    jmp     *%eax\r
 Exception7Handle:\r
-    pushl    $7\r
-    jmp     ASM_PFX(CommonInterruptEntry)\r
+    .byte   0x6a    #  push #VectorNum\r
+    .byte   7\r
+    pushl   %eax\r
+    .byte   0xB8\r
+    .long   ASM_PFX(CommonInterruptEntry)\r
+    jmp     *%eax\r
 Exception8Handle:\r
-    pushl    $8\r
-    jmp     ASM_PFX(CommonInterruptEntry)\r
+    .byte   0x6a    #  push #VectorNum\r
+    .byte   8\r
+    pushl   %eax\r
+     .byte   0xB8\r
+    .long   ASM_PFX(CommonInterruptEntry)\r
+    jmp     *%eax\r
 Exception9Handle:\r
-    pushl    $9\r
-    jmp     ASM_PFX(CommonInterruptEntry)\r
+    .byte   0x6a    #  push #VectorNum\r
+    .byte   9\r
+    pushl   %eax\r
+    .byte   0xB8\r
+    .long   ASM_PFX(CommonInterruptEntry)\r
+    jmp     *%eax\r
 Exception10Handle:\r
-    pushl    $10\r
-    jmp     ASM_PFX(CommonInterruptEntry)\r
+    .byte   0x6a    #  push #VectorNum\r
+    .byte   10\r
+    pushl   %eax\r
+    .byte   0xB8\r
+    .long   ASM_PFX(CommonInterruptEntry)\r
+    jmp     *%eax\r
 Exception11Handle:\r
-    pushl    $11\r
-    jmp     ASM_PFX(CommonInterruptEntry)\r
+    .byte   0x6a    #  push #VectorNum\r
+    .byte   11\r
+    pushl   %eax\r
+    .byte   0xB8\r
+    .long   ASM_PFX(CommonInterruptEntry)\r
+    jmp     *%eax\r
 Exception12Handle:\r
-    pushl    $12\r
-    jmp     ASM_PFX(CommonInterruptEntry)\r
+    .byte   0x6a    #  push #VectorNum\r
+    .byte   12\r
+    pushl   %eax\r
+    .byte   0xB8\r
+    .long   ASM_PFX(CommonInterruptEntry)\r
+    jmp     *%eax\r
 Exception13Handle:\r
-    pushl    $13\r
-    jmp     ASM_PFX(CommonInterruptEntry)\r
+    .byte   0x6a    #  push #VectorNum\r
+    .byte   13\r
+    pushl   %eax\r
+    .byte   0xB8\r
+    .long   ASM_PFX(CommonInterruptEntry)\r
+    jmp     *%eax\r
 Exception14Handle:\r
-    pushl    $14\r
-    jmp     ASM_PFX(CommonInterruptEntry)\r
+    .byte   0x6a    #  push #VectorNum\r
+    .byte   14\r
+    pushl   %eax\r
+    .byte   0xB8\r
+    .long   ASM_PFX(CommonInterruptEntry)\r
+    jmp     *%eax\r
 Exception15Handle:\r
-    pushl    $15\r
-    jmp     ASM_PFX(CommonInterruptEntry)\r
+    .byte   0x6a    #  push #VectorNum\r
+    .byte   15\r
+    pushl   %eax\r
+    .byte   0xB8\r
+    .long   ASM_PFX(CommonInterruptEntry)\r
+    jmp     *%eax\r
 Exception16Handle:\r
-    pushl    $16\r
-    jmp     ASM_PFX(CommonInterruptEntry)\r
+    .byte   0x6a    #  push #VectorNum\r
+    .byte   16\r
+    pushl   %eax\r
+    .byte   0xB8\r
+    .long   ASM_PFX(CommonInterruptEntry)\r
+    jmp     *%eax\r
 Exception17Handle:\r
-    pushl    $17\r
-    jmp     ASM_PFX(CommonInterruptEntry)\r
+    .byte   0x6a    #  push #VectorNum\r
+    .byte   17\r
+    pushl   %eax\r
+    .byte   0xB8\r
+    .long   ASM_PFX(CommonInterruptEntry)\r
+    jmp     *%eax\r
 Exception18Handle:\r
-    pushl    $18\r
-    jmp     ASM_PFX(CommonInterruptEntry)\r
+    .byte   0x6a    #  push #VectorNum\r
+    .byte   18\r
+    pushl   %eax\r
+    .byte   0xB8\r
+    .long   ASM_PFX(CommonInterruptEntry)\r
+    jmp     *%eax\r
 Exception19Handle:\r
-    pushl    $19\r
-    jmp     ASM_PFX(CommonInterruptEntry)\r
+    .byte   0x6a    #  push #VectorNum\r
+    .byte   19\r
+    pushl   %eax\r
+    .byte   0xB8\r
+    .long   ASM_PFX(CommonInterruptEntry)\r
+    jmp     *%eax\r
 Exception20Handle:\r
-    pushl    $20\r
-    jmp     ASM_PFX(CommonInterruptEntry)\r
+    .byte   0x6a    #  push #VectorNum\r
+    .byte   20\r
+    pushl   %eax\r
+    .byte   0xB8\r
+    .long   ASM_PFX(CommonInterruptEntry)\r
+    jmp     *%eax\r
 Exception21Handle:\r
-    pushl    $21\r
-    jmp     ASM_PFX(CommonInterruptEntry)\r
+    .byte   0x6a    #  push #VectorNum\r
+    .byte   21\r
+    pushl   %eax\r
+    .byte   0xB8\r
+    .long   ASM_PFX(CommonInterruptEntry)\r
+    jmp     *%eax\r
 Exception22Handle:\r
-    pushl    $22\r
-    jmp     ASM_PFX(CommonInterruptEntry)\r
+    .byte   0x6a    #  push #VectorNum\r
+    .byte   22\r
+    pushl   %eax\r
+    .byte   0xB8\r
+    .long   ASM_PFX(CommonInterruptEntry)\r
+    jmp     *%eax\r
 Exception23Handle:\r
-    pushl    $23\r
-    jmp     ASM_PFX(CommonInterruptEntry)\r
+    .byte   0x6a    #  push #VectorNum\r
+    .byte   23\r
+    pushl   %eax\r
+    .byte   0xB8\r
+    .long   ASM_PFX(CommonInterruptEntry)\r
+    jmp     *%eax\r
 Exception24Handle:\r
-    pushl    $24\r
-    jmp     ASM_PFX(CommonInterruptEntry)\r
+    .byte   0x6a    #  push #VectorNum\r
+    .byte   24\r
+    pushl   %eax\r
+    .byte   0xB8\r
+    .long   ASM_PFX(CommonInterruptEntry)\r
+    jmp     *%eax\r
 Exception25Handle:\r
-    pushl    $25\r
-    jmp     ASM_PFX(CommonInterruptEntry)\r
+    .byte   0x6a    #  push #VectorNum\r
+    .byte   25\r
+    pushl   %eax\r
+    .byte   0xB8\r
+    .long   ASM_PFX(CommonInterruptEntry)\r
+    jmp     *%eax\r
 Exception26Handle:\r
-    pushl    $26\r
-    jmp     ASM_PFX(CommonInterruptEntry)\r
+    .byte   0x6a    #  push #VectorNum\r
+    .byte   26\r
+    pushl   %eax\r
+    .byte   0xB8\r
+    .long   ASM_PFX(CommonInterruptEntry)\r
+    jmp     *%eax\r
 Exception27Handle:\r
-    pushl    $27\r
-    jmp     ASM_PFX(CommonInterruptEntry)\r
+    .byte   0x6a    #  push #VectorNum\r
+    .byte   27\r
+    pushl   %eax\r
+    .byte   0xB8\r
+    .long   ASM_PFX(CommonInterruptEntry)\r
+    jmp     *%eax\r
 Exception28Handle:\r
-    pushl    $28\r
-    jmp     ASM_PFX(CommonInterruptEntry)\r
+    .byte   0x6a    #  push #VectorNum\r
+    .byte   28\r
+    pushl   %eax\r
+    .byte   0xB8\r
+    .long   ASM_PFX(CommonInterruptEntry)\r
+    jmp     *%eax\r
 Exception29Handle:\r
-    pushl    $29\r
-    jmp     ASM_PFX(CommonInterruptEntry)\r
+    .byte   0x6a    #  push #VectorNum\r
+    .byte   29\r
+    pushl   %eax\r
+    .byte   0xB8\r
+    .long   ASM_PFX(CommonInterruptEntry)\r
+    jmp     *%eax\r
 Exception30Handle:\r
-    pushl    $30\r
-    jmp     ASM_PFX(CommonInterruptEntry)\r
+    .byte   0x6a    #  push #VectorNum\r
+    .byte   30\r
+    pushl   %eax\r
+    .byte   0xB8\r
+    .long   ASM_PFX(CommonInterruptEntry)\r
+    jmp     *%eax\r
 Exception31Handle:\r
-    pushl    $31\r
-    jmp     ASM_PFX(CommonInterruptEntry)\r
+    .byte   0x6a    #  push #VectorNum\r
+    .byte   31\r
+    pushl   %eax\r
+    .byte   0xB8\r
+    .long   ASM_PFX(CommonInterruptEntry)\r
+    jmp     *%eax\r
+\r
+HookAfterStubBegin:\r
+    .byte   0x6a       # push\r
+VectorNum:\r
+    .byte   0          # 0 will be fixed\r
+    pushl   %eax\r
+    .byte   0xB8       # movl    ASM_PFX(HookAfterStubHeaderEnd), %eax\r
+    .long   ASM_PFX(HookAfterStubHeaderEnd)\r
+    jmp     *%eax\r
+ASM_GLOBAL ASM_PFX(HookAfterStubHeaderEnd)\r
+ASM_PFX(HookAfterStubHeaderEnd):\r
+    popl    %eax\r
+    subl    $8, %esp        # reserve room for filling exception data later\r
+    pushl   8(%esp)\r
+    xchgl   (%esp), %ecx    # get vector number\r
+    bt      %ecx, ASM_PFX(mErrorCodeFlag)\r
+    jnc     NoErrorData\r
+    pushl    (%esp)         # addition push if exception data needed\r
+NoErrorData:\r
+    xchg    (%esp), %ecx    # restore ecx\r
+    pushl   %eax\r
 \r
 #---------------------------------------;\r
 # CommonInterruptEntry                  ;\r
@@ -139,19 +287,17 @@ Exception31Handle:
 ASM_GLOBAL ASM_PFX(CommonInterruptEntry)\r
 ASM_PFX(CommonInterruptEntry):\r
     cli\r
+    popl    %eax\r
     #\r
     # All interrupt handlers are invoked through interrupt gates, so\r
     # IF flag automatically cleared at the entry point\r
     #\r
 \r
     #\r
-    # Calculate vector number\r
-    #\r
-    # Get the return address of call, actually, it is the\r
-    # address of vector number.\r
+    # Get vector number from top of stack\r
     #\r
     xchgl   (%esp), %ecx\r
-    andl    $0x0FFFF, %ecx\r
+    andl    $0x0FF, %ecx      # Vector number should be less than 256\r
     cmpl    $32, %ecx         # Intel reserved vector for exceptions?\r
     jae     NoErrorCode\r
     bt      %ecx, ASM_PFX(mErrorCodeFlag)\r
@@ -211,7 +357,7 @@ HasErrorCode:
     #\r
     # Put Vector Number on stack and restore ECX\r
     #\r
-    xchgl   (%esp), %ecx \r
+    xchgl   (%esp), %ecx\r
 \r
 ErrorCodeAndVectorOnStack:\r
     pushl   %ebp\r
@@ -238,9 +384,13 @@ ErrorCodeAndVectorOnStack:
     # Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32\r
     # is 16-byte aligned\r
     #\r
-    andl    $0x0fffffff0, %esp \r
+    andl    $0x0fffffff0, %esp\r
     subl    $12, %esp\r
 \r
+    subl    $8, %esp\r
+    pushl   $0         # check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler\r
+    pushl   $0         # check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag\r
+\r
 #; UINT32  Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;\r
     pushl   %eax\r
     pushl   %ecx\r
@@ -255,7 +405,7 @@ ErrorCodeAndVectorOnStack:
 #; UINT32  Gs, Fs, Es, Ds, Cs, Ss;\r
     movl    %ss, %eax\r
     pushl   %eax\r
-    movzwl  16(%ebp), %eax \r
+    movzwl  16(%ebp), %eax\r
     pushl   %eax\r
     movl    %ds, %eax\r
     pushl   %eax\r
@@ -275,14 +425,14 @@ ErrorCodeAndVectorOnStack:
     sidt    (%esp)\r
     movl    2(%esp), %eax\r
     xchgl   (%esp), %eax\r
-    andl    $0x0FFFF, %eax \r
+    andl    $0x0FFFF, %eax\r
     movl    %eax, 4(%esp)\r
 \r
     subl    $8, %esp\r
     sgdt    (%esp)\r
     movl    2(%esp), %eax\r
     xchgl   (%esp), %eax\r
-    andl    $0x0FFFF, %eax \r
+    andl    $0x0FFFF, %eax\r
     movl    %eax, 4(%esp)\r
 \r
 #; UINT32  Ldtr, Tr;\r
@@ -297,10 +447,25 @@ ErrorCodeAndVectorOnStack:
     pushl   %eax\r
 \r
 #; UINT32  Cr0, Cr1, Cr2, Cr3, Cr4;\r
+## insure FXSAVE/FXRSTOR is enabled in CR4...\r
+## ... while we're at it, make sure DE is also enabled...\r
+    mov     $1, %eax\r
+    pushl   %ebx                         # temporarily save value of ebx on stack\r
+    cpuid                                # use CPUID to determine if FXSAVE/FXRESTOR\r
+                                         # and DE are supported\r
+    popl    %ebx                         # retore value of ebx that was overwritten\r
+                                         # by CPUID\r
     movl    %cr4, %eax\r
-    orl     $0x208, %eax\r
+    pushl   %eax                         # push cr4 firstly\r
+    testl   $BIT24, %edx                 # Test for FXSAVE/FXRESTOR support\r
+    jz      L1\r
+    orl     $BIT9, %eax                  # Set CR4.OSFXSR\r
+L1:\r
+    testl   $BIT2, %edx                  # Test for Debugging Extensions support\r
+    jz      L2\r
+    orl     $BIT3, %eax                  # Set CR4.DE\r
+L2:\r
     movl    %eax, %cr4\r
-    pushl   %eax\r
     movl    %cr3, %eax\r
     pushl   %eax\r
     movl    %cr2, %eax\r
@@ -327,7 +492,11 @@ ErrorCodeAndVectorOnStack:
 #; FX_SAVE_STATE_IA32 FxSaveState;\r
     subl    $512, %esp\r
     movl    %esp, %edi\r
+    testl   $BIT24, %edx     # Test for FXSAVE/FXRESTOR support.\r
+                             # edx still contains result from CPUID above\r
+    jz      L3\r
     .byte      0x0f, 0x0ae, 0x07 #fxsave [edi]\r
+L3:\r
 \r
 #; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear\r
     cld\r
@@ -353,7 +522,13 @@ ErrorCodeAndVectorOnStack:
 \r
 #; FX_SAVE_STATE_IA32 FxSaveState;\r
     movl    %esp, %esi\r
+    movl    $1, %eax\r
+    cpuid                    # use CPUID to determine if FXSAVE/FXRESTOR\r
+                             # are supported\r
+    testl   $BIT24, %edx     # Test for FXSAVE/FXRESTOR support\r
+    jz      L4\r
     .byte      0x0f, 0x0ae, 0x0e # fxrstor [esi]\r
+L4:\r
     addl    $512, %esp\r
 \r
 #; UINT32  Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;\r
@@ -405,46 +580,69 @@ ErrorCodeAndVectorOnStack:
     popl    %ecx\r
     popl    %eax\r
 \r
+    popl    -8(%ebp)\r
+    popl    -4(%ebp)\r
     movl    %ebp, %esp\r
     popl    %ebp\r
     addl    $8, %esp\r
+    cmpl    $0, -16(%esp)  # check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler\r
+    jz      DoReturn\r
+    cmpl    $1, -20(%esp)  # check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag\r
+    jz      ErrorCode\r
+    jmp     *-16(%esp)\r
+ErrorCode:\r
+    subl    $4, %esp\r
+    jmp     *-12(%esp)\r
+\r
+DoReturn:\r
+    cmpl    $0, ASM_PFX(mDoFarReturnFlag)\r
+    jz      DoIret\r
+    pushl   8(%esp)       # save EFLAGS\r
+    addl    $16, %esp\r
+    pushl   -8(%esp)      # save CS in new location\r
+    pushl   -8(%esp)      # save EIP in new location\r
+    pushl   -8(%esp)      # save EFLAGS in new location\r
+    popfl                 # restore EFLAGS\r
+    lret                  # far return\r
+\r
+DoIret:\r
     iretl\r
 \r
 \r
 #---------------------------------------;\r
-# _GetTemplateAddressMap                  ;\r
-#----------------------------------------------------------------------------;\r
-# \r
+# _AsmGetTemplateAddressMap             ;\r
+#---------------------------------------;\r
+#\r
 # Protocol prototype\r
-#   GetTemplateAddressMap (\r
+#   AsmGetTemplateAddressMap (\r
 #     EXCEPTION_HANDLER_TEMPLATE_MAP *AddressMap\r
 #   );\r
-#           \r
+#\r
 # Routine Description:\r
-# \r
+#\r
 #  Return address map of interrupt handler template so that C code can generate\r
 #  interrupt table.\r
-# \r
+#\r
 # Arguments:\r
-# \r
-# \r
-# Returns: \r
-# \r
+#\r
+#\r
+# Returns:\r
+#\r
 #   Nothing\r
 #\r
-# \r
+#\r
 # Input:  [ebp][0]  = Original ebp\r
 #         [ebp][4]  = Return address\r
-#          \r
+#\r
 # Output: Nothing\r
-#          \r
+#\r
 # Destroys: Nothing\r
 #-----------------------------------------------------------------------------;\r
 #-------------------------------------------------------------------------------------\r
 #  AsmGetAddressMap (&AddressMap);\r
 #-------------------------------------------------------------------------------------\r
-ASM_GLOBAL ASM_PFX(GetTemplateAddressMap)\r
-ASM_PFX(GetTemplateAddressMap):\r
+ASM_GLOBAL ASM_PFX(AsmGetTemplateAddressMap)\r
+ASM_PFX(AsmGetTemplateAddressMap):\r
 \r
         pushl       %ebp\r
         movl        %esp,%ebp\r
@@ -453,8 +651,17 @@ ASM_PFX(GetTemplateAddressMap):
         movl        0x8(%ebp), %ebx\r
         movl        $Exception0Handle, (%ebx)\r
         movl        $(Exception1Handle - Exception0Handle), 0x4(%ebx)\r
+        movl        $(HookAfterStubBegin), 0x8(%ebx)\r
 \r
         popal\r
         popl        %ebp\r
         ret\r
-\r
+#-------------------------------------------------------------------------------------\r
+#  AsmVectorNumFixup (*NewVectorAddr, VectorNum, *OldVectorAddr);\r
+#-------------------------------------------------------------------------------------\r
+ASM_GLOBAL ASM_PFX(AsmVectorNumFixup)\r
+ASM_PFX(AsmVectorNumFixup):\r
+        movl  8(%esp), %eax\r
+        movl  4(%esp), %ecx\r
+        movb  %al, (VectorNum - HookAfterStubBegin)(%ecx)\r
+        ret\r