--- /dev/null
+;------------------------------------------------------------------------------ ;\r
+; Copyright (c) 2016, 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
+; http://opensource.org/licenses/bsd-license.php.\r
+;\r
+; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+;\r
+; Module Name:\r
+;\r
+; ExceptionHandlerAsm.Asm\r
+;\r
+; Abstract:\r
+;\r
+; IA32 CPU Exception Handler\r
+;\r
+; Notes:\r
+;\r
+;------------------------------------------------------------------------------\r
+\r
+;\r
+; CommonExceptionHandler()\r
+;\r
+extern ASM_PFX(CommonExceptionHandler)\r
+\r
+SECTION .data\r
+\r
+extern ASM_PFX(mErrorCodeFlag) ; Error code flags for exceptions\r
+extern ASM_PFX(mDoFarReturnFlag) ; Do far return flag\r
+\r
+SECTION .text\r
+\r
+ALIGN 8\r
+\r
+;\r
+; exception handler stub table\r
+;\r
+AsmIdtVectorBegin:\r
+%rep 32\r
+ db 0x6a ; push #VectorNum\r
+ db ($ - AsmIdtVectorBegin) / ((AsmIdtVectorEnd - AsmIdtVectorBegin) / 32) ; VectorNum\r
+ push eax\r
+ mov eax, ASM_PFX(CommonInterruptEntry)\r
+ jmp eax\r
+%endrep\r
+AsmIdtVectorEnd:\r
+\r
+HookAfterStubBegin:\r
+ db 0x6a ; push\r
+VectorNum:\r
+ db 0 ; 0 will be fixed\r
+ push eax\r
+ mov eax, HookAfterStubHeaderEnd\r
+ jmp eax\r
+HookAfterStubHeaderEnd:\r
+ pop eax\r
+ sub esp, 8 ; reserve room for filling exception data later\r
+ push dword [esp + 8]\r
+ xchg ecx, [esp] ; get vector number\r
+ bt [ASM_PFX(mErrorCodeFlag)], ecx\r
+ jnc .0\r
+ push dword [esp] ; addition push if exception data needed\r
+.0:\r
+ xchg ecx, [esp] ; restore ecx\r
+ push eax\r
+\r
+;----------------------------------------------------------------------------;\r
+; CommonInterruptEntry ;\r
+;----------------------------------------------------------------------------;\r
+; The follow algorithm is used for the common interrupt routine.\r
+; Entry from each interrupt with a push eax and eax=interrupt number\r
+; Stack:\r
+; +---------------------+\r
+; + EFlags +\r
+; +---------------------+\r
+; + CS +\r
+; +---------------------+\r
+; + EIP +\r
+; +---------------------+\r
+; + Error Code +\r
+; +---------------------+\r
+; + Vector Number +\r
+; +---------------------+\r
+; + EBP +\r
+; +---------------------+ <-- EBP\r
+global ASM_PFX(CommonInterruptEntry)\r
+ASM_PFX(CommonInterruptEntry):\r
+ cli\r
+ pop 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
+ ; Get vector number from top of stack\r
+ ;\r
+ xchg ecx, [esp]\r
+ and ecx, 0xFF ; Vector number should be less than 256\r
+ cmp ecx, 32 ; Intel reserved vector for exceptions?\r
+ jae NoErrorCode\r
+ bt [ASM_PFX(mErrorCodeFlag)], ecx\r
+ jc HasErrorCode\r
+\r
+NoErrorCode:\r
+\r
+ ;\r
+ ; Stack:\r
+ ; +---------------------+\r
+ ; + EFlags +\r
+ ; +---------------------+\r
+ ; + CS +\r
+ ; +---------------------+\r
+ ; + EIP +\r
+ ; +---------------------+\r
+ ; + ECX +\r
+ ; +---------------------+ <-- ESP\r
+ ;\r
+ ; Registers:\r
+ ; ECX - Vector Number\r
+ ;\r
+\r
+ ;\r
+ ; Put Vector Number on stack\r
+ ;\r
+ push ecx\r
+\r
+ ;\r
+ ; Put 0 (dummy) error code on stack, and restore ECX\r
+ ;\r
+ xor ecx, ecx ; ECX = 0\r
+ xchg ecx, [esp+4]\r
+\r
+ jmp ErrorCodeAndVectorOnStack\r
+\r
+HasErrorCode:\r
+\r
+ ;\r
+ ; Stack:\r
+ ; +---------------------+\r
+ ; + EFlags +\r
+ ; +---------------------+\r
+ ; + CS +\r
+ ; +---------------------+\r
+ ; + EIP +\r
+ ; +---------------------+\r
+ ; + Error Code +\r
+ ; +---------------------+\r
+ ; + ECX +\r
+ ; +---------------------+ <-- ESP\r
+ ;\r
+ ; Registers:\r
+ ; ECX - Vector Number\r
+ ;\r
+\r
+ ;\r
+ ; Put Vector Number on stack and restore ECX\r
+ ;\r
+ xchg ecx, [esp]\r
+\r
+ErrorCodeAndVectorOnStack:\r
+ push ebp\r
+ mov ebp, esp\r
+\r
+ ;\r
+ ; Stack:\r
+ ; +---------------------+\r
+ ; + EFlags +\r
+ ; +---------------------+\r
+ ; + CS +\r
+ ; +---------------------+\r
+ ; + EIP +\r
+ ; +---------------------+\r
+ ; + Error Code +\r
+ ; +---------------------+\r
+ ; + Vector Number +\r
+ ; +---------------------+\r
+ ; + EBP +\r
+ ; +---------------------+ <-- EBP\r
+ ;\r
+\r
+ ;\r
+ ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32\r
+ ; is 16-byte aligned\r
+ ;\r
+ and esp, 0xfffffff0\r
+ sub esp, 12\r
+\r
+ sub esp, 8\r
+ push 0 ; clear EXCEPTION_HANDLER_CONTEXT.OldIdtHandler\r
+ push 0 ; clear EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag\r
+\r
+;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;\r
+ push eax\r
+ push ecx\r
+ push edx\r
+ push ebx\r
+ lea ecx, [ebp + 6 * 4]\r
+ push ecx ; ESP\r
+ push dword [ebp] ; EBP\r
+ push esi\r
+ push edi\r
+\r
+;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;\r
+ mov eax, ss\r
+ push eax\r
+ movzx eax, word [ebp + 4 * 4]\r
+ push eax\r
+ mov eax, ds\r
+ push eax\r
+ mov eax, es\r
+ push eax\r
+ mov eax, fs\r
+ push eax\r
+ mov eax, gs\r
+ push eax\r
+\r
+;; UINT32 Eip;\r
+ mov eax, [ebp + 3 * 4]\r
+ push eax\r
+\r
+;; UINT32 Gdtr[2], Idtr[2];\r
+ sub esp, 8\r
+ sidt [esp]\r
+ mov eax, [esp + 2]\r
+ xchg eax, [esp]\r
+ and eax, 0xFFFF\r
+ mov [esp+4], eax\r
+\r
+ sub esp, 8\r
+ sgdt [esp]\r
+ mov eax, [esp + 2]\r
+ xchg eax, [esp]\r
+ and eax, 0xFFFF\r
+ mov [esp+4], eax\r
+\r
+;; UINT32 Ldtr, Tr;\r
+ xor eax, eax\r
+ str ax\r
+ push eax\r
+ sldt ax\r
+ push eax\r
+\r
+;; UINT32 EFlags;\r
+ mov eax, [ebp + 5 * 4]\r
+ push eax\r
+\r
+;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;\r
+ mov eax, 1\r
+ push ebx ; temporarily save value of ebx on stack\r
+ cpuid ; use CPUID to determine if FXSAVE/FXRESTOR and DE\r
+ ; are supported\r
+ pop ebx ; retore value of ebx that was overwritten by CPUID\r
+ mov eax, cr4\r
+ push eax ; push cr4 firstly\r
+ test edx, BIT24 ; Test for FXSAVE/FXRESTOR support\r
+ jz .1\r
+ or eax, BIT9 ; Set CR4.OSFXSR\r
+.1:\r
+ test edx, BIT2 ; Test for Debugging Extensions support\r
+ jz .2\r
+ or eax, BIT3 ; Set CR4.DE\r
+.2:\r
+ mov cr4, eax\r
+ mov eax, cr3\r
+ push eax\r
+ mov eax, cr2\r
+ push eax\r
+ xor eax, eax\r
+ push eax\r
+ mov eax, cr0\r
+ push eax\r
+\r
+;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;\r
+ mov eax, dr7\r
+ push eax\r
+ mov eax, dr6\r
+ push eax\r
+ mov eax, dr3\r
+ push eax\r
+ mov eax, dr2\r
+ push eax\r
+ mov eax, dr1\r
+ push eax\r
+ mov eax, dr0\r
+ push eax\r
+\r
+;; FX_SAVE_STATE_IA32 FxSaveState;\r
+ sub esp, 512\r
+ mov edi, esp\r
+ test edx, BIT24 ; Test for FXSAVE/FXRESTOR support.\r
+ ; edx still contains result from CPUID above\r
+ jz .3\r
+ db 0xf, 0xae, 0x7 ;fxsave [edi]\r
+.3:\r
+\r
+;; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear\r
+ cld\r
+\r
+;; UINT32 ExceptionData;\r
+ push dword [ebp + 2 * 4]\r
+\r
+;; Prepare parameter and call\r
+ mov edx, esp\r
+ push edx\r
+ mov edx, dword [ebp + 1 * 4]\r
+ push edx\r
+\r
+ ;\r
+ ; Call External Exception Handler\r
+ ;\r
+ mov eax, ASM_PFX(CommonExceptionHandler)\r
+ call eax\r
+ add esp, 8\r
+\r
+ cli\r
+;; UINT32 ExceptionData;\r
+ add esp, 4\r
+\r
+;; FX_SAVE_STATE_IA32 FxSaveState;\r
+ mov esi, esp\r
+ mov eax, 1\r
+ cpuid ; use CPUID to determine if FXSAVE/FXRESTOR\r
+ ; are supported\r
+ test edx, BIT24 ; Test for FXSAVE/FXRESTOR support\r
+ jz .4\r
+ db 0xf, 0xae, 0xe ; fxrstor [esi]\r
+.4:\r
+ add esp, 512\r
+\r
+;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;\r
+;; Skip restoration of DRx registers to support in-circuit emualators\r
+;; or debuggers set breakpoint in interrupt/exception context\r
+ add esp, 4 * 6\r
+\r
+;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;\r
+ pop eax\r
+ mov cr0, eax\r
+ add esp, 4 ; not for Cr1\r
+ pop eax\r
+ mov cr2, eax\r
+ pop eax\r
+ mov cr3, eax\r
+ pop eax\r
+ mov cr4, eax\r
+\r
+;; UINT32 EFlags;\r
+ pop dword [ebp + 5 * 4]\r
+\r
+;; UINT32 Ldtr, Tr;\r
+;; UINT32 Gdtr[2], Idtr[2];\r
+;; Best not let anyone mess with these particular registers...\r
+ add esp, 24\r
+\r
+;; UINT32 Eip;\r
+ pop dword [ebp + 3 * 4]\r
+\r
+;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;\r
+;; NOTE - modified segment registers could hang the debugger... We\r
+;; could attempt to insulate ourselves against this possibility,\r
+;; but that poses risks as well.\r
+;;\r
+ pop gs\r
+ pop fs\r
+ pop es\r
+ pop ds\r
+ pop dword [ebp + 4 * 4]\r
+ pop ss\r
+\r
+;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;\r
+ pop edi\r
+ pop esi\r
+ add esp, 4 ; not for ebp\r
+ add esp, 4 ; not for esp\r
+ pop ebx\r
+ pop edx\r
+ pop ecx\r
+ pop eax\r
+\r
+ pop dword [ebp - 8]\r
+ pop dword [ebp - 4]\r
+ mov esp, ebp\r
+ pop ebp\r
+ add esp, 8\r
+ cmp dword [esp - 16], 0 ; check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler\r
+ jz DoReturn\r
+ cmp dword [esp - 20], 1 ; check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag\r
+ jz ErrorCode\r
+ jmp dword [esp - 16]\r
+ErrorCode:\r
+ sub esp, 4\r
+ jmp dword [esp - 12]\r
+\r
+DoReturn:\r
+ cmp dword [ASM_PFX(mDoFarReturnFlag)], 0 ; Check if need to do far return instead of IRET\r
+ jz DoIret\r
+ push dword [esp + 8] ; save EFLAGS\r
+ add esp, 16\r
+ push dword [esp - 8] ; save CS in new location\r
+ push dword [esp - 8] ; save EIP in new location\r
+ push dword [esp - 8] ; save EFLAGS in new location\r
+ popfd ; restore EFLAGS\r
+ retf ; far return\r
+\r
+DoIret:\r
+ iretd\r
+\r
+;---------------------------------------;\r
+; _AsmGetTemplateAddressMap ;\r
+;----------------------------------------------------------------------------;\r
+;\r
+; Protocol prototype\r
+; AsmGetTemplateAddressMap (\r
+; EXCEPTION_HANDLER_TEMPLATE_MAP *AddressMap\r
+; );\r
+;\r
+; Routine Description:\r
+;\r
+; Return address map of interrupt handler template so that C code can generate\r
+; interrupt table.\r
+;\r
+; Arguments:\r
+;\r
+;\r
+; Returns:\r
+;\r
+; Nothing\r
+;\r
+;\r
+; Input: [ebp][0] = Original ebp\r
+; [ebp][4] = Return address\r
+;\r
+; Output: Nothing\r
+;\r
+; Destroys: Nothing\r
+;-----------------------------------------------------------------------------;\r
+global ASM_PFX(AsmGetTemplateAddressMap)\r
+ASM_PFX(AsmGetTemplateAddressMap):\r
+ push ebp ; C prolog\r
+ mov ebp, esp\r
+ pushad\r
+\r
+ mov ebx, dword [ebp + 0x8]\r
+ mov dword [ebx], AsmIdtVectorBegin\r
+ mov dword [ebx + 0x4], (AsmIdtVectorEnd - AsmIdtVectorBegin) / 32\r
+ mov dword [ebx + 0x8], HookAfterStubBegin\r
+\r
+ popad\r
+ pop ebp\r
+ ret\r
+\r
+;-------------------------------------------------------------------------------------\r
+; AsmVectorNumFixup (*NewVectorAddr, VectorNum, *OldVectorAddr);\r
+;-------------------------------------------------------------------------------------\r
+global ASM_PFX(AsmVectorNumFixup)\r
+ASM_PFX(AsmVectorNumFixup):\r
+ mov eax, dword [esp + 8]\r
+ mov ecx, [esp + 4]\r
+ mov [ecx + (VectorNum - HookAfterStubBegin)], al\r
+ ret\r