--- /dev/null
+;------------------------------------------------------------------------------ ;\r
+; Copyright (c) 2009 - 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
+; 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
+; SmiException.nasm\r
+;\r
+; Abstract:\r
+;\r
+; Exception handlers used in SM mode\r
+;\r
+;-------------------------------------------------------------------------------\r
+\r
+extern ASM_PFX(FeaturePcdGet (PcdCpuSmmProfileEnable))\r
+extern ASM_PFX(gSmiMtrrs)\r
+extern ASM_PFX(SmiPFHandler)\r
+\r
+global ASM_PFX(gcSmiIdtr)\r
+global ASM_PFX(gcSmiGdtr)\r
+global ASM_PFX(gcPsd)\r
+\r
+ SECTION .data\r
+\r
+NullSeg: DQ 0 ; reserved by architecture\r
+CodeSeg32:\r
+ DW -1 ; LimitLow\r
+ DW 0 ; BaseLow\r
+ DB 0 ; BaseMid\r
+ DB 0x9b\r
+ DB 0xcf ; LimitHigh\r
+ DB 0 ; BaseHigh\r
+ProtModeCodeSeg32:\r
+ DW -1 ; LimitLow\r
+ DW 0 ; BaseLow\r
+ DB 0 ; BaseMid\r
+ DB 0x9b\r
+ DB 0xcf ; LimitHigh\r
+ DB 0 ; BaseHigh\r
+ProtModeSsSeg32:\r
+ DW -1 ; LimitLow\r
+ DW 0 ; BaseLow\r
+ DB 0 ; BaseMid\r
+ DB 0x93\r
+ DB 0xcf ; LimitHigh\r
+ DB 0 ; BaseHigh\r
+DataSeg32:\r
+ DW -1 ; LimitLow\r
+ DW 0 ; BaseLow\r
+ DB 0 ; BaseMid\r
+ DB 0x93\r
+ DB 0xcf ; LimitHigh\r
+ DB 0 ; BaseHigh\r
+CodeSeg16:\r
+ DW -1\r
+ DW 0\r
+ DB 0\r
+ DB 0x9b\r
+ DB 0x8f\r
+ DB 0\r
+DataSeg16:\r
+ DW -1\r
+ DW 0\r
+ DB 0\r
+ DB 0x93\r
+ DB 0x8f\r
+ DB 0\r
+CodeSeg64:\r
+ DW -1 ; LimitLow\r
+ DW 0 ; BaseLow\r
+ DB 0 ; BaseMid\r
+ DB 0x9b\r
+ DB 0xaf ; LimitHigh\r
+ DB 0 ; BaseHigh\r
+GDT_SIZE equ $ - NullSeg\r
+\r
+TssSeg:\r
+ DW TSS_DESC_SIZE ; LimitLow\r
+ DW 0 ; BaseLow\r
+ DB 0 ; BaseMid\r
+ DB 0x89\r
+ DB 0x80 ; LimitHigh\r
+ DB 0 ; BaseHigh\r
+ExceptionTssSeg:\r
+ DW TSS_DESC_SIZE ; LimitLow\r
+ DW 0 ; BaseLow\r
+ DB 0 ; BaseMid\r
+ DB 0x89\r
+ DB 0x80 ; LimitHigh\r
+ DB 0 ; BaseHigh\r
+\r
+CODE_SEL equ CodeSeg32 - NullSeg\r
+DATA_SEL equ DataSeg32 - NullSeg\r
+TSS_SEL equ TssSeg - NullSeg\r
+EXCEPTION_TSS_SEL equ ExceptionTssSeg - NullSeg\r
+\r
+struc IA32_TSS\r
+ resw 1\r
+ resw 1\r
+ .ESP0: resd 1\r
+ .SS0: resw 1\r
+ resw 1\r
+ .ESP1: resd 1\r
+ .SS1: resw 1\r
+ resw 1\r
+ .ESP2: resd 1\r
+ .SS2: resw 1\r
+ resw 1\r
+ ._CR3: resd 1\r
+ .EIP: resd 1\r
+ .EFLAGS: resd 1\r
+ ._EAX: resd 1\r
+ ._ECX: resd 1\r
+ ._EDX: resd 1\r
+ ._EBX: resd 1\r
+ ._ESP: resd 1\r
+ ._EBP: resd 1\r
+ ._ESI: resd 1\r
+ ._EDI: resd 1\r
+ ._ES: resw 1\r
+ resw 1\r
+ ._CS: resw 1\r
+ resw 1\r
+ ._SS: resw 1\r
+ resw 1\r
+ ._DS: resw 1\r
+ resw 1\r
+ ._FS: resw 1\r
+ resw 1\r
+ ._GS: resw 1\r
+ resw 1\r
+ .LDT: resw 1\r
+ resw 1\r
+ resw 1\r
+ resw 1\r
+endstruc\r
+\r
+; Create 2 TSS segments just after GDT\r
+TssDescriptor:\r
+ DW 0 ; PreviousTaskLink\r
+ DW 0 ; Reserved\r
+ DD 0 ; ESP0\r
+ DW 0 ; SS0\r
+ DW 0 ; Reserved\r
+ DD 0 ; ESP1\r
+ DW 0 ; SS1\r
+ DW 0 ; Reserved\r
+ DD 0 ; ESP2\r
+ DW 0 ; SS2\r
+ DW 0 ; Reserved\r
+ DD 0 ; CR3\r
+ DD 0 ; EIP\r
+ DD 0 ; EFLAGS\r
+ DD 0 ; EAX\r
+ DD 0 ; ECX\r
+ DD 0 ; EDX\r
+ DD 0 ; EBX\r
+ DD 0 ; ESP\r
+ DD 0 ; EBP\r
+ DD 0 ; ESI\r
+ DD 0 ; EDI\r
+ DW 0 ; ES\r
+ DW 0 ; Reserved\r
+ DW 0 ; CS\r
+ DW 0 ; Reserved\r
+ DW 0 ; SS\r
+ DW 0 ; Reserved\r
+ DW 0 ; DS\r
+ DW 0 ; Reserved\r
+ DW 0 ; FS\r
+ DW 0 ; Reserved\r
+ DW 0 ; GS\r
+ DW 0 ; Reserved\r
+ DW 0 ; LDT Selector\r
+ DW 0 ; Reserved\r
+ DW 0 ; T\r
+ DW 0 ; I/O Map Base\r
+TSS_DESC_SIZE equ $ - TssDescriptor\r
+\r
+ExceptionTssDescriptor:\r
+ DW 0 ; PreviousTaskLink\r
+ DW 0 ; Reserved\r
+ DD 0 ; ESP0\r
+ DW 0 ; SS0\r
+ DW 0 ; Reserved\r
+ DD 0 ; ESP1\r
+ DW 0 ; SS1\r
+ DW 0 ; Reserved\r
+ DD 0 ; ESP2\r
+ DW 0 ; SS2\r
+ DW 0 ; Reserved\r
+ DD 0 ; CR3\r
+ DD PFHandlerEntry ; EIP\r
+ DD 00000002 ; EFLAGS\r
+ DD 0 ; EAX\r
+ DD 0 ; ECX\r
+ DD 0 ; EDX\r
+ DD 0 ; EBX\r
+ DD 0 ; ESP\r
+ DD 0 ; EBP\r
+ DD 0 ; ESI\r
+ DD 0 ; EDI\r
+ DW DATA_SEL ; ES\r
+ DW 0 ; Reserved\r
+ DW CODE_SEL ; CS\r
+ DW 0 ; Reserved\r
+ DW DATA_SEL ; SS\r
+ DW 0 ; Reserved\r
+ DW DATA_SEL ; DS\r
+ DW 0 ; Reserved\r
+ DW DATA_SEL ; FS\r
+ DW 0 ; Reserved\r
+ DW DATA_SEL ; GS\r
+ DW 0 ; Reserved\r
+ DW 0 ; LDT Selector\r
+ DW 0 ; Reserved\r
+ DW 0 ; T\r
+ DW 0 ; I/O Map Base\r
+\r
+ASM_PFX(gcPsd):\r
+ DB 'PSDSIG '\r
+ DW PSD_SIZE\r
+ DW 2\r
+ DW 1 << 2\r
+ DW CODE_SEL\r
+ DW DATA_SEL\r
+ DW DATA_SEL\r
+ DW DATA_SEL\r
+ DW 0\r
+ DQ 0\r
+ DQ 0\r
+ DQ 0\r
+ DD 0\r
+ DD NullSeg\r
+ DD GDT_SIZE\r
+ DD 0\r
+ times 24 DB 0\r
+ DD 0\r
+ DD ASM_PFX(gSmiMtrrs)\r
+PSD_SIZE equ $ - ASM_PFX(gcPsd)\r
+\r
+ASM_PFX(gcSmiGdtr):\r
+ DW GDT_SIZE - 1\r
+ DD NullSeg\r
+\r
+ASM_PFX(gcSmiIdtr):\r
+ DW IDT_SIZE - 1\r
+ DD _SmiIDT\r
+\r
+_SmiIDT:\r
+%rep 32\r
+ DW 0 ; Offset 0:15\r
+ DW CODE_SEL ; Segment selector\r
+ DB 0 ; Unused\r
+ DB 0x8e ; Interrupt Gate, Present\r
+ DW 0 ; Offset 16:31\r
+%endrep\r
+\r
+IDT_SIZE equ $ - _SmiIDT\r
+\r
+TaskGateDescriptor:\r
+ DW 0 ; Reserved\r
+ DW EXCEPTION_TSS_SEL ; TSS Segment selector\r
+ DB 0 ; Reserved\r
+ DB 0x85 ; Task Gate, present, DPL = 0\r
+ DW 0 ; Reserved\r
+\r
+ SECTION .text\r
+;------------------------------------------------------------------------------\r
+; PageFaultIdtHandlerSmmProfile is the entry point page fault only\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
+global ASM_PFX(PageFaultIdtHandlerSmmProfile)\r
+ASM_PFX(PageFaultIdtHandlerSmmProfile):\r
+ push 0xe ; Page Fault\r
+\r
+ push ebp\r
+ mov ebp, esp\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
+;; 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, cr4\r
+ or eax, 0x208\r
+ mov cr4, eax\r
+ push 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
+ db 0xf, 0xae, 0x7 ;fxsave [edi]\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
+;; call into exception handler\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(SmiPFHandler)\r
+ call eax\r
+ add esp, 8\r
+\r
+;; UINT32 ExceptionData;\r
+ add esp, 4\r
+\r
+;; FX_SAVE_STATE_IA32 FxSaveState;\r
+ mov esi, esp\r
+ db 0xf, 0xae, 0xe ; fxrstor [esi]\r
+ add esp, 512\r
+\r
+;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;\r
+;; Skip restoration of DRx registers to support debuggers\r
+;; that 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
+ mov esp, ebp\r
+ pop ebp\r
+\r
+; Enable TF bit after page fault handler runs\r
+ bts dword [esp + 16], 8 ; EFLAGS\r
+\r
+ add esp, 8 ; skip INT# & ErrCode\r
+Return:\r
+ iretd\r
+;\r
+; Page Fault Exception Handler entry when SMM Stack Guard is enabled\r
+; Executiot starts here after a task switch\r
+;\r
+PFHandlerEntry:\r
+;\r
+; Get this processor's TSS\r
+;\r
+ sub esp, 8\r
+ sgdt [esp + 2]\r
+ mov eax, [esp + 4] ; GDT base\r
+ add esp, 8\r
+ mov ecx, [eax + TSS_SEL + 2]\r
+ shl ecx, 8\r
+ mov cl, [eax + TSS_SEL + 7]\r
+ ror ecx, 8 ; ecx = TSS base\r
+\r
+ mov ebp, esp\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
+;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;\r
+ push dword [ecx + IA32_TSS._EAX]\r
+ push dword [ecx + IA32_TSS._ECX]\r
+ push dword [ecx + IA32_TSS._EDX]\r
+ push dword [ecx + IA32_TSS._EBX]\r
+ push dword [ecx + IA32_TSS._ESP]\r
+ push dword [ecx + IA32_TSS._EBP]\r
+ push dword [ecx + IA32_TSS._ESI]\r
+ push dword [ecx + IA32_TSS._EDI]\r
+\r
+;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;\r
+ movzx eax, word [ecx + IA32_TSS._SS]\r
+ push eax\r
+ movzx eax, word [ecx + IA32_TSS._CS]\r
+ push eax\r
+ movzx eax, word [ecx + IA32_TSS._DS]\r
+ push eax\r
+ movzx eax, word [ecx + IA32_TSS._ES]\r
+ push eax\r
+ movzx eax, word [ecx + IA32_TSS._FS]\r
+ push eax\r
+ movzx eax, word [ecx + IA32_TSS._GS]\r
+ push eax\r
+\r
+;; UINT32 Eip;\r
+ push dword [ecx + IA32_TSS.EIP]\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
+ mov eax, TSS_SEL\r
+ push eax\r
+ movzx eax, word [ecx + IA32_TSS.LDT]\r
+ push eax\r
+\r
+;; UINT32 EFlags;\r
+ push dword [ecx + IA32_TSS.EFLAGS]\r
+\r
+;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;\r
+ mov eax, cr4\r
+ or eax, 0x208\r
+ mov cr4, eax\r
+ push 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
+;; Clear TS bit in CR0 to avoid Device Not Available Exception (#NM)\r
+;; when executing fxsave/fxrstor instruction\r
+ clts\r
+ sub esp, 512\r
+ mov edi, esp\r
+ db 0xf, 0xae, 0x7 ;fxsave [edi]\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]\r
+\r
+;; call into exception handler\r
+ mov ebx, ecx\r
+ mov eax, ASM_PFX(SmiPFHandler)\r
+\r
+;; Prepare parameter and call\r
+ mov edx, esp\r
+ push edx\r
+ mov edx, 14\r
+ push edx\r
+\r
+ ;\r
+ ; Call External Exception Handler\r
+ ;\r
+ call eax\r
+ add esp, 8\r
+\r
+ mov ecx, ebx\r
+;; UINT32 ExceptionData;\r
+ add esp, 4\r
+\r
+;; FX_SAVE_STATE_IA32 FxSaveState;\r
+ mov esi, esp\r
+ db 0xf, 0xae, 0xe ; fxrstor [esi]\r
+ add esp, 512\r
+\r
+;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;\r
+;; Skip restoration of DRx registers to support debuggers\r
+;; that set breakpoints 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 dword [ecx + IA32_TSS._CR3], eax\r
+ pop eax\r
+ mov cr4, eax\r
+\r
+;; UINT32 EFlags;\r
+ pop dword [ecx + IA32_TSS.EFLAGS]\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 [ecx + IA32_TSS.EIP]\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 eax\r
+o16 mov [ecx + IA32_TSS._GS], ax\r
+ pop eax\r
+o16 mov [ecx + IA32_TSS._FS], ax\r
+ pop eax\r
+o16 mov [ecx + IA32_TSS._ES], ax\r
+ pop eax\r
+o16 mov [ecx + IA32_TSS._DS], ax\r
+ pop eax\r
+o16 mov [ecx + IA32_TSS._CS], ax\r
+ pop eax\r
+o16 mov [ecx + IA32_TSS._SS], ax\r
+\r
+;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;\r
+ pop dword [ecx + IA32_TSS._EDI]\r
+ pop dword [ecx + IA32_TSS._ESI]\r
+ add esp, 4 ; not for ebp\r
+ add esp, 4 ; not for esp\r
+ pop dword [ecx + IA32_TSS._EBX]\r
+ pop dword [ecx + IA32_TSS._EDX]\r
+ pop dword [ecx + IA32_TSS._ECX]\r
+ pop dword [ecx + IA32_TSS._EAX]\r
+\r
+ mov esp, ebp\r
+\r
+; Set single step DB# if SMM profile is enabled and page fault exception happens\r
+ cmp byte [dword ASM_PFX(FeaturePcdGet (PcdCpuSmmProfileEnable))], 0\r
+ jz @Done2\r
+\r
+; Create return context for iretd in stub function\r
+ mov eax, dword [ecx + IA32_TSS._ESP] ; Get old stack pointer\r
+ mov ebx, dword [ecx + IA32_TSS.EIP]\r
+ mov [eax - 0xc], ebx ; create EIP in old stack\r
+ movzx ebx, word [ecx + IA32_TSS._CS]\r
+ mov [eax - 0x8], ebx ; create CS in old stack\r
+ mov ebx, dword [ecx + IA32_TSS.EFLAGS]\r
+ bts ebx, 8\r
+ mov [eax - 0x4], ebx ; create eflags in old stack\r
+ mov eax, dword [ecx + IA32_TSS._ESP] ; Get old stack pointer\r
+ sub eax, 0xc ; minus 12 byte\r
+ mov dword [ecx + IA32_TSS._ESP], eax ; Set new stack pointer\r
+; Replace the EIP of interrupted task with stub function\r
+ mov eax, ASM_PFX(PageFaultStubFunction)\r
+ mov dword [ecx + IA32_TSS.EIP], eax\r
+; Jump to the iretd so next page fault handler as a task will start again after iretd.\r
+@Done2:\r
+ add esp, 4 ; skip ErrCode\r
+\r
+ jmp Return\r
+\r
+global ASM_PFX(PageFaultStubFunction)\r
+ASM_PFX(PageFaultStubFunction):\r
+;\r
+; we need clean TS bit in CR0 to execute\r
+; x87 FPU/MMX/SSE/SSE2/SSE3/SSSE3/SSE4 instructions.\r
+;\r
+ clts\r
+ iretd\r
+\r
+global ASM_PFX(InitializeIDTSmmStackGuard)\r
+ASM_PFX(InitializeIDTSmmStackGuard):\r
+ push ebx\r
+;\r
+; If SMM Stack Guard feature is enabled, the Page Fault Exception entry in IDT\r
+; is a Task Gate Descriptor so that when a Page Fault Exception occurrs,\r
+; the processors can use a known good stack in case stack is ran out.\r
+;\r
+ lea ebx, [_SmiIDT + 14 * 8]\r
+ lea edx, [TaskGateDescriptor]\r
+ mov eax, [edx]\r
+ mov [ebx], eax\r
+ mov eax, [edx + 4]\r
+ mov [ebx + 4], eax\r
+ pop ebx\r
+ ret\r
+\r
+ END\r