Add a new instances of the SmmCpuFeaturesLib that is used by platforms to enable the SMI Transfer Monitor(STM) feature. This new instance is in the same directory as the default SmmCpuFeaturesLib instance in order to share source files. The DSC file is updated to build both SmmCpuFeatureLib instances and to build two versions of the PiSmmCpuDxeSmm module using each of the SmmCpuFeatureLib instances. Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Jeff Fan <jeff.fan@intel.com> Cc: Feng Tian <feng.tian@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Michael Kinney <michael.d.kinney@intel.com> Reviewed-by: Jiewen Yao <jiewen.yao@intel.com> Reviewed-by: Jeff Fan <jeff.fan@intel.com>
282 lines
8.2 KiB
NASM
282 lines
8.2 KiB
NASM
;------------------------------------------------------------------------------ ;
|
|
; Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
|
|
; This program and the accompanying materials
|
|
; are licensed and made available under the terms and conditions of the BSD License
|
|
; which accompanies this distribution. The full text of the license may be found at
|
|
; http://opensource.org/licenses/bsd-license.php.
|
|
;
|
|
; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
;
|
|
; Module Name:
|
|
;
|
|
; SmiEntry.asm
|
|
;
|
|
; Abstract:
|
|
;
|
|
; Code template of the SMI handler for a particular processor
|
|
;
|
|
;-------------------------------------------------------------------------------
|
|
|
|
;
|
|
; Variables referenced by C code
|
|
;
|
|
EXTERNDEF SmiRendezvous:PROC
|
|
EXTERNDEF CpuSmmDebugEntry:PROC
|
|
EXTERNDEF CpuSmmDebugExit:PROC
|
|
EXTERNDEF gcStmSmiHandlerTemplate:BYTE
|
|
EXTERNDEF gcStmSmiHandlerSize:WORD
|
|
EXTERNDEF gcStmSmiHandlerOffset:WORD
|
|
EXTERNDEF gStmSmiCr3:DWORD
|
|
EXTERNDEF gStmSmiStack:DWORD
|
|
EXTERNDEF gStmSmbase:DWORD
|
|
EXTERNDEF gStmXdSupported:BYTE
|
|
EXTERNDEF gStmSmiHandlerIdtr:FWORD
|
|
|
|
MSR_IA32_MISC_ENABLE EQU 1A0h
|
|
MSR_EFER EQU 0c0000080h
|
|
MSR_EFER_XD EQU 0800h
|
|
|
|
;
|
|
; Constants relating to TXT_PROCESSOR_SMM_DESCRIPTOR
|
|
;
|
|
DSC_OFFSET EQU 0fb00h
|
|
DSC_GDTPTR EQU 48h
|
|
DSC_GDTSIZ EQU 50h
|
|
DSC_CS EQU 14h
|
|
DSC_DS EQU 16h
|
|
DSC_SS EQU 18h
|
|
DSC_OTHERSEG EQU 1ah
|
|
;
|
|
; Constants relating to CPU State Save Area
|
|
;
|
|
SSM_DR6 EQU 0ffd0h
|
|
SSM_DR7 EQU 0ffc8h
|
|
|
|
PROTECT_MODE_CS EQU 08h
|
|
PROTECT_MODE_DS EQU 20h
|
|
LONG_MODE_CS EQU 38h
|
|
TSS_SEGMENT EQU 40h
|
|
GDT_SIZE EQU 50h
|
|
|
|
.code
|
|
|
|
gcStmSmiHandlerTemplate LABEL BYTE
|
|
|
|
_StmSmiEntryPoint:
|
|
;
|
|
; The encoding of BX in 16-bit addressing mode is the same as of RDI in 64-
|
|
; bit addressing mode. And that coincidence has been used in the following
|
|
; "64-bit like" 16-bit code. Be aware that once RDI is referenced as a
|
|
; base address register, it is actually BX that is referenced.
|
|
;
|
|
DB 0bbh ; mov bx, imm16
|
|
DW offset _StmGdtDesc - _StmSmiEntryPoint + 8000h ; bx = GdtDesc offset
|
|
; fix GDT descriptor
|
|
DB 2eh, 0a1h ; mov ax, cs:[offset16]
|
|
DW DSC_OFFSET + DSC_GDTSIZ
|
|
DB 48h ; dec ax
|
|
DB 2eh
|
|
mov [rdi], eax ; mov cs:[bx], ax
|
|
DB 66h, 2eh, 0a1h ; mov eax, cs:[offset16]
|
|
DW DSC_OFFSET + DSC_GDTPTR
|
|
DB 2eh
|
|
mov [rdi + 2], ax ; mov cs:[bx + 2], eax
|
|
DB 66h, 2eh
|
|
lgdt fword ptr [rdi] ; lgdt fword ptr cs:[bx]
|
|
; Patch ProtectedMode Segment
|
|
DB 0b8h ; mov ax, imm16
|
|
DW PROTECT_MODE_CS ; set AX for segment directly
|
|
DB 2eh
|
|
mov [rdi - 2], eax ; mov cs:[bx - 2], ax
|
|
; Patch ProtectedMode entry
|
|
DB 66h, 0bfh ; mov edi, SMBASE
|
|
gStmSmbase DD ?
|
|
lea ax, [edi + (@ProtectedMode - _StmSmiEntryPoint) + 8000h]
|
|
DB 2eh
|
|
mov [rdi - 6], ax ; mov cs:[bx - 6], eax
|
|
; Switch into @ProtectedMode
|
|
mov rbx, cr0
|
|
DB 66h
|
|
and ebx, 9ffafff3h
|
|
DB 66h
|
|
or ebx, 00000023h
|
|
|
|
mov cr0, rbx
|
|
DB 66h, 0eah
|
|
DD ?
|
|
DW ?
|
|
|
|
_StmGdtDesc FWORD ?
|
|
@ProtectedMode:
|
|
mov ax, PROTECT_MODE_DS
|
|
mov ds, ax
|
|
mov es, ax
|
|
mov fs, ax
|
|
mov gs, ax
|
|
mov ss, ax
|
|
DB 0bch ; mov esp, imm32
|
|
gStmSmiStack DD ?
|
|
jmp ProtFlatMode
|
|
|
|
ProtFlatMode:
|
|
DB 0b8h ; mov eax, offset gStmSmiCr3
|
|
gStmSmiCr3 DD ?
|
|
mov cr3, rax
|
|
mov eax, 668h ; as cr4.PGE is not set here, refresh cr3
|
|
mov cr4, rax ; in PreModifyMtrrs() to flush TLB.
|
|
; Load TSS
|
|
sub esp, 8 ; reserve room in stack
|
|
sgdt fword ptr [rsp]
|
|
mov eax, [rsp + 2] ; eax = GDT base
|
|
add esp, 8
|
|
mov dl, 89h
|
|
mov [rax + TSS_SEGMENT + 5], dl ; clear busy flag
|
|
mov eax, TSS_SEGMENT
|
|
ltr ax
|
|
|
|
; enable NXE if supported
|
|
DB 0b0h ; mov al, imm8
|
|
gStmXdSupported DB 1
|
|
cmp al, 0
|
|
jz @SkipXd
|
|
;
|
|
; Check XD disable bit
|
|
;
|
|
mov ecx, MSR_IA32_MISC_ENABLE
|
|
rdmsr
|
|
sub esp, 4
|
|
push rdx ; save MSR_IA32_MISC_ENABLE[63-32]
|
|
test edx, BIT2 ; MSR_IA32_MISC_ENABLE[34]
|
|
jz @f
|
|
and dx, 0FFFBh ; clear XD Disable bit if it is set
|
|
wrmsr
|
|
@@:
|
|
mov ecx, MSR_EFER
|
|
rdmsr
|
|
or ax, MSR_EFER_XD ; enable NXE
|
|
wrmsr
|
|
jmp @XdDone
|
|
@SkipXd:
|
|
sub esp, 8
|
|
@XdDone:
|
|
|
|
; Switch into @LongMode
|
|
push LONG_MODE_CS ; push cs hardcore here
|
|
call Base ; push return address for retf later
|
|
Base:
|
|
add dword ptr [rsp], @LongMode - Base; offset for far retf, seg is the 1st arg
|
|
|
|
mov ecx, MSR_EFER
|
|
rdmsr
|
|
or ah, 1 ; enable LME
|
|
wrmsr
|
|
mov rbx, cr0
|
|
or ebx, 080010023h ; enable paging + WP + NE + MP + PE
|
|
mov cr0, rbx
|
|
retf
|
|
@LongMode: ; long mode (64-bit code) starts here
|
|
mov rax, offset gStmSmiHandlerIdtr
|
|
lidt fword ptr [rax]
|
|
lea ebx, [rdi + DSC_OFFSET]
|
|
mov ax, [rbx + DSC_DS]
|
|
mov ds, eax
|
|
mov ax, [rbx + DSC_OTHERSEG]
|
|
mov es, eax
|
|
mov fs, eax
|
|
mov gs, eax
|
|
mov ax, [rbx + DSC_SS]
|
|
mov ss, eax
|
|
|
|
CommonHandler:
|
|
mov rbx, [rsp + 0x08] ; rbx <- CpuIndex
|
|
|
|
;
|
|
; Save FP registers
|
|
;
|
|
sub rsp, 200h
|
|
DB 48h ; FXSAVE64
|
|
fxsave [rsp]
|
|
|
|
add rsp, -20h
|
|
|
|
mov rcx, rbx
|
|
mov rax, CpuSmmDebugEntry
|
|
call rax
|
|
|
|
mov rcx, rbx
|
|
mov rax, SmiRendezvous ; rax <- absolute addr of SmiRedezvous
|
|
call rax
|
|
|
|
mov rcx, rbx
|
|
mov rax, CpuSmmDebugExit
|
|
call rax
|
|
|
|
add rsp, 20h
|
|
|
|
;
|
|
; Restore FP registers
|
|
;
|
|
DB 48h ; FXRSTOR64
|
|
fxrstor [rsp]
|
|
|
|
add rsp, 200h
|
|
|
|
mov rax, offset ASM_PFX(gStmXdSupported)
|
|
mov al, [rax]
|
|
cmp al, 0
|
|
jz @f
|
|
pop rdx ; get saved MSR_IA32_MISC_ENABLE[63-32]
|
|
test edx, BIT2
|
|
jz @f
|
|
mov ecx, MSR_IA32_MISC_ENABLE
|
|
rdmsr
|
|
or dx, BIT2 ; set XD Disable bit if it was set before entering into SMM
|
|
wrmsr
|
|
|
|
@@:
|
|
rsm
|
|
|
|
_StmSmiHandler:
|
|
;
|
|
; Check XD disable bit
|
|
;
|
|
xor r8, r8
|
|
mov rax, offset ASM_PFX(gStmXdSupported)
|
|
mov al, [rax]
|
|
cmp al, 0
|
|
jz @StmXdDone
|
|
mov ecx, MSR_IA32_MISC_ENABLE
|
|
rdmsr
|
|
mov r8, rdx ; save MSR_IA32_MISC_ENABLE[63-32]
|
|
test edx, BIT2 ; MSR_IA32_MISC_ENABLE[34]
|
|
jz @f
|
|
and dx, 0FFFBh ; clear XD Disable bit if it is set
|
|
wrmsr
|
|
@@:
|
|
mov ecx, MSR_EFER
|
|
rdmsr
|
|
or ax, MSR_EFER_XD ; enable NXE
|
|
wrmsr
|
|
@StmXdDone:
|
|
push r8
|
|
|
|
; below step is needed, because STM does not run above code.
|
|
; we have to run below code to set IDT/CR0/CR4
|
|
mov rax, offset gStmSmiHandlerIdtr
|
|
lidt fword ptr [rax]
|
|
|
|
mov rax, cr0
|
|
or eax, 80010023h ; enable paging + WP + NE + MP + PE
|
|
mov cr0, rax
|
|
mov rax, cr4
|
|
mov eax, 668h ; as cr4.PGE is not set here, refresh cr3
|
|
mov cr4, rax ; in PreModifyMtrrs() to flush TLB.
|
|
; STM init finish
|
|
jmp CommonHandler
|
|
|
|
gcStmSmiHandlerSize DW $ - _StmSmiEntryPoint
|
|
gcStmSmiHandlerOffset DW _StmSmiHandler - _StmSmiEntryPoint
|
|
|
|
END
|