;------------------------------------------------------------------------------ ; | |
; 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) | |
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 | |
; Enable TF bit after page fault handler runs | |
bts dword [rsp + 40], 8 ;RFLAGS | |
pop rbp | |
add rsp, 16 ; skip INT# & ErrCode | |
iretq | |