| ;------------------------------------------------------------------------------ ; | |
| ; Copyright (c) 2016 - 2018, 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(SmiPFHandler) | |
| extern ASM_PFX(mSetupDebugTrap) | |
| global ASM_PFX(gcSmiIdtr) | |
| global ASM_PFX(gcSmiGdtr) | |
| 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 | |
| ; TSS Segment for X64 specially | |
| TssSeg: | |
| DW TSS_DESC_SIZE ; LimitLow | |
| DW 0 ; BaseLow | |
| DB 0 ; BaseMid | |
| DB 0x89 | |
| DB 0x80 ; LimitHigh | |
| DB 0 ; BaseHigh | |
| DD 0 ; BaseUpper | |
| DD 0 ; Reserved | |
| GDT_SIZE equ $ - NullSeg | |
| ; Create TSS Descriptor just after GDT | |
| TssDescriptor: | |
| DD 0 ; Reserved | |
| DQ 0 ; RSP0 | |
| DQ 0 ; RSP1 | |
| DQ 0 ; RSP2 | |
| DD 0 ; Reserved | |
| DD 0 ; Reserved | |
| DQ 0 ; IST1 | |
| DQ 0 ; IST2 | |
| DQ 0 ; IST3 | |
| DQ 0 ; IST4 | |
| DQ 0 ; IST5 | |
| DQ 0 ; IST6 | |
| DQ 0 ; IST7 | |
| DD 0 ; Reserved | |
| DD 0 ; Reserved | |
| DW 0 ; Reserved | |
| DW 0 ; I/O Map Base Address | |
| TSS_DESC_SIZE equ $ - TssDescriptor | |
| ; | |
| ; This structure serves as a template for all processors. | |
| ; | |
| 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 ; fixed in InitializeMpServiceData() | |
| DQ NullSeg | |
| DD GDT_SIZE | |
| DD 0 | |
| times 24 DB 0 | |
| DQ 0 | |
| PSD_SIZE equ $ - ASM_PFX(gcPsd) | |
| ; | |
| ; CODE & DATA segments for SMM runtime | |
| ; | |
| CODE_SEL equ CodeSeg64 - NullSeg | |
| DATA_SEL equ DataSeg32 - NullSeg | |
| CODE32_SEL equ CodeSeg32 - NullSeg | |
| ASM_PFX(gcSmiGdtr): | |
| DW GDT_SIZE - 1 | |
| DQ NullSeg | |
| ASM_PFX(gcSmiIdtr): | |
| DW 0 | |
| DQ 0 | |
| DEFAULT REL | |
| SECTION .text | |
| ;------------------------------------------------------------------------------ | |
| ; _SmiExceptionEntryPoints is the collection of exception entrypoints followed | |
| ; by a common exception handler. | |
| ; | |
| ; Stack frame would be as follows as specified in IA32 manuals: | |
| ; | |
| ; +---------------------+ <-- 16-byte aligned ensured by processor | |
| ; + Old SS + | |
| ; +---------------------+ | |
| ; + Old RSP + | |
| ; +---------------------+ | |
| ; + RFlags + | |
| ; +---------------------+ | |
| ; + CS + | |
| ; +---------------------+ | |
| ; + RIP + | |
| ; +---------------------+ | |
| ; + Error Code + | |
| ; +---------------------+ | |
| ; + Vector Number + | |
| ; +---------------------+ | |
| ; + RBP + | |
| ; +---------------------+ <-- RBP, 16-byte aligned | |
| ; | |
| ; RSP set to odd multiple of 8 at @CommonEntryPoint means ErrCode PRESENT | |
| ;------------------------------------------------------------------------------ | |
| global ASM_PFX(PageFaultIdtHandlerSmmProfile) | |
| ASM_PFX(PageFaultIdtHandlerSmmProfile): | |
| push 0xe ; Page Fault | |
| test spl, 8 ; odd multiple of 8 => ErrCode present | |
| jnz .0 | |
| push qword [rsp] ; duplicate INT# if no ErrCode | |
| mov qword [rsp + 8], 0 | |
| .0: | |
| push rbp | |
| mov rbp, rsp | |
| ; | |
| ; Since here the stack pointer is 16-byte aligned, so | |
| ; EFI_FX_SAVE_STATE_X64 of EFI_SYSTEM_CONTEXT_x64 | |
| ; is 16-byte aligned | |
| ; | |
| ;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax; | |
| ;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15; | |
| push r15 | |
| push r14 | |
| push r13 | |
| push r12 | |
| push r11 | |
| push r10 | |
| push r9 | |
| push r8 | |
| push rax | |
| push rcx | |
| push rdx | |
| push rbx | |
| push qword [rbp + 48] ; RSP | |
| push qword [rbp] ; RBP | |
| push rsi | |
| push rdi | |
| ;; UINT64 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero | |
| movzx rax, word [rbp + 56] | |
| push rax ; for ss | |
| movzx rax, word [rbp + 32] | |
| push rax ; for cs | |
| mov rax, ds | |
| push rax | |
| mov rax, es | |
| push rax | |
| mov rax, fs | |
| push rax | |
| mov rax, gs | |
| push rax | |
| ;; UINT64 Rip; | |
| push qword [rbp + 24] | |
| ;; UINT64 Gdtr[2], Idtr[2]; | |
| sub rsp, 16 | |
| sidt [rsp] | |
| sub rsp, 16 | |
| sgdt [rsp] | |
| ;; UINT64 Ldtr, Tr; | |
| xor rax, rax | |
| str ax | |
| push rax | |
| sldt ax | |
| push rax | |
| ;; UINT64 RFlags; | |
| push qword [rbp + 40] | |
| ;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8; | |
| mov rax, cr8 | |
| push rax | |
| mov rax, cr4 | |
| or rax, 0x208 | |
| mov cr4, rax | |
| push rax | |
| mov rax, cr3 | |
| push rax | |
| mov rax, cr2 | |
| push rax | |
| xor rax, rax | |
| push rax | |
| mov rax, cr0 | |
| push rax | |
| ;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; | |
| mov rax, dr7 | |
| push rax | |
| mov rax, dr6 | |
| push rax | |
| mov rax, dr3 | |
| push rax | |
| mov rax, dr2 | |
| push rax | |
| mov rax, dr1 | |
| push rax | |
| mov rax, dr0 | |
| push rax | |
| ;; FX_SAVE_STATE_X64 FxSaveState; | |
| sub rsp, 512 | |
| mov rdi, rsp | |
| fxsave [rdi] | |
| ; UEFI calling convention for x64 requires that Direction flag in EFLAGs is clear | |
| cld | |
| ;; UINT32 ExceptionData; | |
| push qword [rbp + 16] | |
| ;; call into exception handler | |
| mov rcx, [rbp + 8] | |
| lea rax, [ASM_PFX(SmiPFHandler)] | |
| ;; Prepare parameter and call | |
| mov rdx, rsp | |
| ; | |
| ; Per X64 calling convention, allocate maximum parameter stack space | |
| ; and make sure RSP is 16-byte aligned | |
| ; | |
| sub rsp, 4 * 8 + 8 | |
| call rax | |
| add rsp, 4 * 8 + 8 | |
| jmp .1 | |
| .1: | |
| ;; UINT64 ExceptionData; | |
| add rsp, 8 | |
| ;; FX_SAVE_STATE_X64 FxSaveState; | |
| mov rsi, rsp | |
| fxrstor [rsi] | |
| add rsp, 512 | |
| ;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; | |
| ;; Skip restoration of DRx registers to support debuggers | |
| ;; that set breakpoints in interrupt/exception context | |
| add rsp, 8 * 6 | |
| ;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8; | |
| pop rax | |
| mov cr0, rax | |
| add rsp, 8 ; not for Cr1 | |
| pop rax | |
| mov cr2, rax | |
| pop rax | |
| mov cr3, rax | |
| pop rax | |
| mov cr4, rax | |
| pop rax | |
| mov cr8, rax | |
| ;; UINT64 RFlags; | |
| pop qword [rbp + 40] | |
| ;; UINT64 Ldtr, Tr; | |
| ;; UINT64 Gdtr[2], Idtr[2]; | |
| ;; Best not let anyone mess with these particular registers... | |
| add rsp, 48 | |
| ;; UINT64 Rip; | |
| pop qword [rbp + 24] | |
| ;; UINT64 Gs, Fs, Es, Ds, Cs, Ss; | |
| pop rax | |
| ; mov gs, rax ; not for gs | |
| pop rax | |
| ; mov fs, rax ; not for fs | |
| ; (X64 will not use fs and gs, so we do not restore it) | |
| pop rax | |
| mov es, rax | |
| pop rax | |
| mov ds, rax | |
| pop qword [rbp + 32] ; for cs | |
| pop qword [rbp + 56] ; for ss | |
| ;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax; | |
| ;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15; | |
| pop rdi | |
| pop rsi | |
| add rsp, 8 ; not for rbp | |
| pop qword [rbp + 48] ; for rsp | |
| pop rbx | |
| pop rdx | |
| pop rcx | |
| pop rax | |
| pop r8 | |
| pop r9 | |
| pop r10 | |
| pop r11 | |
| pop r12 | |
| pop r13 | |
| pop r14 | |
| pop r15 | |
| mov rsp, rbp | |
| ; Check if mSetupDebugTrap is TRUE (non-zero) | |
| cmp byte [dword ASM_PFX(mSetupDebugTrap)], 0 | |
| jz SkipSettingTF | |
| ; Enable TF bit after page fault handler runs | |
| bts dword [rsp + 40], 8 ;RFLAGS | |
| SkipSettingTF: | |
| pop rbp | |
| add rsp, 16 ; skip INT# & ErrCode | |
| iretq | |