diff options
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.nasm')
-rw-r--r-- | src/VBox/Devices/EFI/Firmware/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.nasm | 705 |
1 files changed, 705 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.nasm b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.nasm new file mode 100644 index 00000000..bcd5a007 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.nasm @@ -0,0 +1,705 @@ +;------------------------------------------------------------------------------ ; +; Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR> +; SPDX-License-Identifier: BSD-2-Clause-Patent +; +; Module Name: +; +; SmiException.nasm +; +; Abstract: +; +; Exception handlers used in SM mode +; +;------------------------------------------------------------------------------- + +extern ASM_PFX(FeaturePcdGet (PcdCpuSmmProfileEnable)) +extern ASM_PFX(SmiPFHandler) +extern ASM_PFX(mSetupDebugTrap) + +global ASM_PFX(gcSmiIdtr) +global ASM_PFX(gcSmiGdtr) +global ASM_PFX(gTaskGateDescriptor) +global ASM_PFX(gcPsd) + + SECTION .data + +NullSeg: DQ 0 ; reserved by architecture +CodeSeg32: + DW -1 ; LimitLow + DW 0 ; BaseLow + DB 0 ; BaseMid + DB 0x9b + DB 0xcf ; LimitHigh + DB 0 ; BaseHigh +ProtModeCodeSeg32: + DW -1 ; LimitLow + DW 0 ; BaseLow + DB 0 ; BaseMid + DB 0x9b + DB 0xcf ; LimitHigh + DB 0 ; BaseHigh +ProtModeSsSeg32: + DW -1 ; LimitLow + DW 0 ; BaseLow + DB 0 ; BaseMid + DB 0x93 + DB 0xcf ; LimitHigh + DB 0 ; BaseHigh +DataSeg32: + DW -1 ; LimitLow + DW 0 ; BaseLow + DB 0 ; BaseMid + DB 0x93 + DB 0xcf ; LimitHigh + DB 0 ; BaseHigh +CodeSeg16: + DW -1 + DW 0 + DB 0 + DB 0x9b + DB 0x8f + DB 0 +DataSeg16: + DW -1 + DW 0 + DB 0 + DB 0x93 + DB 0x8f + DB 0 +CodeSeg64: + DW -1 ; LimitLow + DW 0 ; BaseLow + DB 0 ; BaseMid + DB 0x9b + DB 0xaf ; LimitHigh + DB 0 ; BaseHigh +GDT_SIZE equ $ - NullSeg + +TssSeg: + DW TSS_DESC_SIZE ; LimitLow + DW 0 ; BaseLow + DB 0 ; BaseMid + DB 0x89 + DB 0x80 ; LimitHigh + DB 0 ; BaseHigh +ExceptionTssSeg: + DW EXCEPTION_TSS_DESC_SIZE ; LimitLow + DW 0 ; BaseLow + DB 0 ; BaseMid + DB 0x89 + DB 0x80 ; LimitHigh + DB 0 ; BaseHigh + +CODE_SEL equ CodeSeg32 - NullSeg +DATA_SEL equ DataSeg32 - NullSeg +TSS_SEL equ TssSeg - NullSeg +EXCEPTION_TSS_SEL equ ExceptionTssSeg - NullSeg + +struc IA32_TSS + resw 1 + resw 1 + .ESP0: resd 1 + .SS0: resw 1 + resw 1 + .ESP1: resd 1 + .SS1: resw 1 + resw 1 + .ESP2: resd 1 + .SS2: resw 1 + resw 1 + ._CR3: resd 1 + .EIP: resd 1 + .EFLAGS: resd 1 + ._EAX: resd 1 + ._ECX: resd 1 + ._EDX: resd 1 + ._EBX: resd 1 + ._ESP: resd 1 + ._EBP: resd 1 + ._ESI: resd 1 + ._EDI: resd 1 + ._ES: resw 1 + resw 1 + ._CS: resw 1 + resw 1 + ._SS: resw 1 + resw 1 + ._DS: resw 1 + resw 1 + ._FS: resw 1 + resw 1 + ._GS: resw 1 + resw 1 + .LDT: resw 1 + resw 1 + resw 1 + resw 1 +endstruc + +; Create 2 TSS segments just after GDT +TssDescriptor: + DW 0 ; PreviousTaskLink + DW 0 ; Reserved + DD 0 ; ESP0 + DW 0 ; SS0 + DW 0 ; Reserved + DD 0 ; ESP1 + DW 0 ; SS1 + DW 0 ; Reserved + DD 0 ; ESP2 + DW 0 ; SS2 + DW 0 ; Reserved + DD 0 ; CR3 + DD 0 ; EIP + DD 0 ; EFLAGS + DD 0 ; EAX + DD 0 ; ECX + DD 0 ; EDX + DD 0 ; EBX + DD 0 ; ESP + DD 0 ; EBP + DD 0 ; ESI + DD 0 ; EDI + DW 0 ; ES + DW 0 ; Reserved + DW 0 ; CS + DW 0 ; Reserved + DW 0 ; SS + DW 0 ; Reserved + DW 0 ; DS + DW 0 ; Reserved + DW 0 ; FS + DW 0 ; Reserved + DW 0 ; GS + DW 0 ; Reserved + DW 0 ; LDT Selector + DW 0 ; Reserved + DW 0 ; T + DW 0 ; I/O Map Base +TSS_DESC_SIZE equ $ - TssDescriptor + +ExceptionTssDescriptor: + DW 0 ; PreviousTaskLink + DW 0 ; Reserved + DD 0 ; ESP0 + DW 0 ; SS0 + DW 0 ; Reserved + DD 0 ; ESP1 + DW 0 ; SS1 + DW 0 ; Reserved + DD 0 ; ESP2 + DW 0 ; SS2 + DW 0 ; Reserved + DD 0 ; CR3 + DD PFHandlerEntry ; EIP + DD 00000002 ; EFLAGS + DD 0 ; EAX + DD 0 ; ECX + DD 0 ; EDX + DD 0 ; EBX + DD 0 ; ESP + DD 0 ; EBP + DD 0 ; ESI + DD 0 ; EDI + DW DATA_SEL ; ES + DW 0 ; Reserved + DW CODE_SEL ; CS + DW 0 ; Reserved + DW DATA_SEL ; SS + DW 0 ; Reserved + DW DATA_SEL ; DS + DW 0 ; Reserved + DW DATA_SEL ; FS + DW 0 ; Reserved + DW DATA_SEL ; GS + DW 0 ; Reserved + DW 0 ; LDT Selector + DW 0 ; Reserved + DW 0 ; T + DW 0 ; I/O Map Base + DD 0 ; SSP +EXCEPTION_TSS_DESC_SIZE equ $ - ExceptionTssDescriptor + +ASM_PFX(gcPsd): + DB 'PSDSIG ' + DW PSD_SIZE + DW 2 + DW 1 << 2 + DW CODE_SEL + DW DATA_SEL + DW DATA_SEL + DW DATA_SEL + DW 0 + DQ 0 + DQ 0 + DQ 0 + DD 0 + DD NullSeg + DD GDT_SIZE + DD 0 + times 24 DB 0 + DD 0 + DD 0 +PSD_SIZE equ $ - ASM_PFX(gcPsd) + +ASM_PFX(gcSmiGdtr): + DW GDT_SIZE - 1 + DD NullSeg + +ASM_PFX(gcSmiIdtr): + DW 0 + DD 0 + +ASM_PFX(gTaskGateDescriptor): + DW 0 ; Reserved + DW EXCEPTION_TSS_SEL ; TSS Segment selector + DB 0 ; Reserved + DB 0x85 ; Task Gate, present, DPL = 0 + DW 0 ; Reserved + + SECTION .text +;------------------------------------------------------------------------------ +; PageFaultIdtHandlerSmmProfile is the entry point page fault only +; +; +; Stack: +; +---------------------+ +; + EFlags + +; +---------------------+ +; + CS + +; +---------------------+ +; + EIP + +; +---------------------+ +; + Error Code + +; +---------------------+ +; + Vector Number + +; +---------------------+ +; + EBP + +; +---------------------+ <-- EBP +; +; +;------------------------------------------------------------------------------ +global ASM_PFX(PageFaultIdtHandlerSmmProfile) +ASM_PFX(PageFaultIdtHandlerSmmProfile): + push 0xe ; Page Fault + + push ebp + mov ebp, esp + + ; + ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32 + ; is 16-byte aligned + ; + and esp, 0xfffffff0 + sub esp, 12 + +;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; + push eax + push ecx + push edx + push ebx + lea ecx, [ebp + 6 * 4] + push ecx ; ESP + push dword [ebp] ; EBP + push esi + push edi + +;; UINT32 Gs, Fs, Es, Ds, Cs, Ss; + mov eax, ss + push eax + movzx eax, word [ebp + 4 * 4] + push eax + mov eax, ds + push eax + mov eax, es + push eax + mov eax, fs + push eax + mov eax, gs + push eax + +;; UINT32 Eip; + mov eax, [ebp + 3 * 4] + push eax + +;; UINT32 Gdtr[2], Idtr[2]; + sub esp, 8 + sidt [esp] + mov eax, [esp + 2] + xchg eax, [esp] + and eax, 0xFFFF + mov [esp+4], eax + + sub esp, 8 + sgdt [esp] + mov eax, [esp + 2] + xchg eax, [esp] + and eax, 0xFFFF + mov [esp+4], eax + +;; UINT32 Ldtr, Tr; + xor eax, eax + str ax + push eax + sldt ax + push eax + +;; UINT32 EFlags; + mov eax, [ebp + 5 * 4] + push eax + +;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; + mov eax, cr4 + or eax, 0x208 + mov cr4, eax + push eax + mov eax, cr3 + push eax + mov eax, cr2 + push eax + xor eax, eax + push eax + mov eax, cr0 + push eax + +;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; + mov eax, dr7 + push eax + mov eax, dr6 + push eax + mov eax, dr3 + push eax + mov eax, dr2 + push eax + mov eax, dr1 + push eax + mov eax, dr0 + push eax + +;; FX_SAVE_STATE_IA32 FxSaveState; + sub esp, 512 + mov edi, esp + fxsave [edi] + +; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear + cld + +;; UINT32 ExceptionData; + push dword [ebp + 2 * 4] + +;; call into exception handler + +;; Prepare parameter and call + mov edx, esp + push edx + mov edx, dword [ebp + 1 * 4] + push edx + + ; + ; Call External Exception Handler + ; + mov eax, ASM_PFX(SmiPFHandler) + call eax + add esp, 8 + +;; UINT32 ExceptionData; + add esp, 4 + +;; FX_SAVE_STATE_IA32 FxSaveState; + mov esi, esp + fxrstor [esi] + add esp, 512 + +;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; +;; Skip restoration of DRx registers to support debuggers +;; that set breakpoint in interrupt/exception context + add esp, 4 * 6 + +;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; + pop eax + mov cr0, eax + add esp, 4 ; not for Cr1 + pop eax + mov cr2, eax + pop eax + mov cr3, eax + pop eax + mov cr4, eax + +;; UINT32 EFlags; + pop dword [ebp + 5 * 4] + +;; UINT32 Ldtr, Tr; +;; UINT32 Gdtr[2], Idtr[2]; +;; Best not let anyone mess with these particular registers... + add esp, 24 + +;; UINT32 Eip; + pop dword [ebp + 3 * 4] + +;; UINT32 Gs, Fs, Es, Ds, Cs, Ss; +;; NOTE - modified segment registers could hang the debugger... We +;; could attempt to insulate ourselves against this possibility, +;; but that poses risks as well. +;; + pop gs + pop fs + pop es + pop ds + pop dword [ebp + 4 * 4] + pop ss + +;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; + pop edi + pop esi + add esp, 4 ; not for ebp + add esp, 4 ; not for esp + pop ebx + pop edx + pop ecx + pop eax + + mov esp, ebp + pop ebp + +; Enable TF bit after page fault handler runs + bts dword [esp + 16], 8 ; EFLAGS + + add esp, 8 ; skip INT# & ErrCode +Return: + iretd +; +; Page Fault Exception Handler entry when SMM Stack Guard is enabled +; Executiot starts here after a task switch +; +PFHandlerEntry: +; +; Get this processor's TSS +; + sub esp, 8 + sgdt [esp + 2] + mov eax, [esp + 4] ; GDT base + add esp, 8 + mov ecx, [eax + TSS_SEL + 2] + shl ecx, 8 + mov cl, [eax + TSS_SEL + 7] + ror ecx, 8 ; ecx = TSS base + + mov ebp, esp + + ; + ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32 + ; is 16-byte aligned + ; + and esp, 0xfffffff0 + sub esp, 12 + +;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; + push dword [ecx + IA32_TSS._EAX] + push dword [ecx + IA32_TSS._ECX] + push dword [ecx + IA32_TSS._EDX] + push dword [ecx + IA32_TSS._EBX] + push dword [ecx + IA32_TSS._ESP] + push dword [ecx + IA32_TSS._EBP] + push dword [ecx + IA32_TSS._ESI] + push dword [ecx + IA32_TSS._EDI] + +;; UINT32 Gs, Fs, Es, Ds, Cs, Ss; + movzx eax, word [ecx + IA32_TSS._SS] + push eax + movzx eax, word [ecx + IA32_TSS._CS] + push eax + movzx eax, word [ecx + IA32_TSS._DS] + push eax + movzx eax, word [ecx + IA32_TSS._ES] + push eax + movzx eax, word [ecx + IA32_TSS._FS] + push eax + movzx eax, word [ecx + IA32_TSS._GS] + push eax + +;; UINT32 Eip; + push dword [ecx + IA32_TSS.EIP] + +;; UINT32 Gdtr[2], Idtr[2]; + sub esp, 8 + sidt [esp] + mov eax, [esp + 2] + xchg eax, [esp] + and eax, 0xFFFF + mov [esp+4], eax + + sub esp, 8 + sgdt [esp] + mov eax, [esp + 2] + xchg eax, [esp] + and eax, 0xFFFF + mov [esp+4], eax + +;; UINT32 Ldtr, Tr; + mov eax, TSS_SEL + push eax + movzx eax, word [ecx + IA32_TSS.LDT] + push eax + +;; UINT32 EFlags; + push dword [ecx + IA32_TSS.EFLAGS] + +;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; + mov eax, cr4 + or eax, 0x208 + mov cr4, eax + push eax + mov eax, cr3 + push eax + mov eax, cr2 + push eax + xor eax, eax + push eax + mov eax, cr0 + push eax + +;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; + mov eax, dr7 + push eax + mov eax, dr6 + push eax + mov eax, dr3 + push eax + mov eax, dr2 + push eax + mov eax, dr1 + push eax + mov eax, dr0 + push eax + +;; FX_SAVE_STATE_IA32 FxSaveState; +;; Clear TS bit in CR0 to avoid Device Not Available Exception (#NM) +;; when executing fxsave/fxrstor instruction + clts + sub esp, 512 + mov edi, esp + fxsave [edi] + +; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear + cld + +;; UINT32 ExceptionData; + push dword [ebp] + +;; call into exception handler + mov ebx, ecx + mov eax, ASM_PFX(SmiPFHandler) + +;; Prepare parameter and call + mov edx, esp + push edx + mov edx, 14 + push edx + + ; + ; Call External Exception Handler + ; + call eax + add esp, 8 + + mov ecx, ebx +;; UINT32 ExceptionData; + add esp, 4 + +;; FX_SAVE_STATE_IA32 FxSaveState; + mov esi, esp + fxrstor [esi] + add esp, 512 + +;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; +;; Skip restoration of DRx registers to support debuggers +;; that set breakpoints in interrupt/exception context + add esp, 4 * 6 + +;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4; + pop eax + mov cr0, eax + add esp, 4 ; not for Cr1 + pop eax + mov cr2, eax + pop eax + mov dword [ecx + IA32_TSS._CR3], eax + pop eax + mov cr4, eax + +;; UINT32 EFlags; + pop dword [ecx + IA32_TSS.EFLAGS] + +;; UINT32 Ldtr, Tr; +;; UINT32 Gdtr[2], Idtr[2]; +;; Best not let anyone mess with these particular registers... + add esp, 24 + +;; UINT32 Eip; + pop dword [ecx + IA32_TSS.EIP] + +;; UINT32 Gs, Fs, Es, Ds, Cs, Ss; +;; NOTE - modified segment registers could hang the debugger... We +;; could attempt to insulate ourselves against this possibility, +;; but that poses risks as well. +;; + pop eax +o16 mov [ecx + IA32_TSS._GS], ax + pop eax +o16 mov [ecx + IA32_TSS._FS], ax + pop eax +o16 mov [ecx + IA32_TSS._ES], ax + pop eax +o16 mov [ecx + IA32_TSS._DS], ax + pop eax +o16 mov [ecx + IA32_TSS._CS], ax + pop eax +o16 mov [ecx + IA32_TSS._SS], ax + +;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax; + pop dword [ecx + IA32_TSS._EDI] + pop dword [ecx + IA32_TSS._ESI] + add esp, 4 ; not for ebp + add esp, 4 ; not for esp + pop dword [ecx + IA32_TSS._EBX] + pop dword [ecx + IA32_TSS._EDX] + pop dword [ecx + IA32_TSS._ECX] + pop dword [ecx + IA32_TSS._EAX] + + mov esp, ebp + +; Set single step DB# if SMM profile is enabled and page fault exception happens + cmp byte [dword ASM_PFX(mSetupDebugTrap)], 0 + jz @Done2 + +; Create return context for iretd in stub function + mov eax, dword [ecx + IA32_TSS._ESP] ; Get old stack pointer + mov ebx, dword [ecx + IA32_TSS.EIP] + mov [eax - 0xc], ebx ; create EIP in old stack + movzx ebx, word [ecx + IA32_TSS._CS] + mov [eax - 0x8], ebx ; create CS in old stack + mov ebx, dword [ecx + IA32_TSS.EFLAGS] + bts ebx, 8 + mov [eax - 0x4], ebx ; create eflags in old stack + mov eax, dword [ecx + IA32_TSS._ESP] ; Get old stack pointer + sub eax, 0xc ; minus 12 byte + mov dword [ecx + IA32_TSS._ESP], eax ; Set new stack pointer +; Replace the EIP of interrupted task with stub function + mov eax, ASM_PFX(PageFaultStubFunction) + mov dword [ecx + IA32_TSS.EIP], eax +; Jump to the iretd so next page fault handler as a task will start again after iretd. +@Done2: + add esp, 4 ; skip ErrCode + + jmp Return + +global ASM_PFX(PageFaultStubFunction) +ASM_PFX(PageFaultStubFunction): +; +; we need clean TS bit in CR0 to execute +; x87 FPU/MMX/SSE/SSE2/SSE3/SSSE3/SSE4 instructions. +; + clts + iretd + |