mirror of https://github.com/acidanthera/audk.git
UefiCpuPkg/PiSmmCpuDxeSmm: Add paging protection.
PiSmmCpuDxeSmm consumes SmmAttributesTable and setup page table: 1) Code region is marked as read-only and Data region is non-executable, if the PE image is 4K aligned. 2) Important data structure is set to RO, such as GDT/IDT. 3) SmmSaveState is set to non-executable, and SmmEntrypoint is set to read-only. 4) If static page is supported, page table is read-only. We use page table to protect other components, and itself. If we use dynamic paging, we can still provide *partial* protection. And hope page table is not modified by other components. The XD enabling code is moved to SmiEntry to let NX take effect. Cc: Jeff Fan <jeff.fan@intel.com> Cc: Feng Tian <feng.tian@intel.com> Cc: Star Zeng <star.zeng@intel.com> Cc: Michael D Kinney <michael.d.kinney@intel.com> Cc: Laszlo Ersek <lersek@redhat.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiewen Yao <jiewen.yao@intel.com> Tested-by: Laszlo Ersek <lersek@redhat.com> Reviewed-by: Jeff Fan <jeff.fan@intel.com> Reviewed-by: Michael D Kinney <michael.d.kinney@intel.com>
This commit is contained in:
parent
28b020b5de
commit
717fb60443
|
@ -58,7 +58,7 @@ SmmInitPageTable (
|
|||
if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
|
||||
InitializeIDTSmmStackGuard ();
|
||||
}
|
||||
return Gen4GPageTable (0, TRUE);
|
||||
return Gen4GPageTable (TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -99,7 +99,7 @@ SmiPFHandler (
|
|||
if ((FeaturePcdGet (PcdCpuSmmStackGuard)) &&
|
||||
(PFAddress >= mCpuHotPlugData.SmrrBase) &&
|
||||
(PFAddress < (mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize))) {
|
||||
DEBUG ((EFI_D_ERROR, "SMM stack overflow!\n"));
|
||||
DEBUG ((DEBUG_ERROR, "SMM stack overflow!\n"));
|
||||
CpuDeadLoop ();
|
||||
}
|
||||
|
||||
|
@ -109,7 +109,7 @@ SmiPFHandler (
|
|||
if ((PFAddress < mCpuHotPlugData.SmrrBase) ||
|
||||
(PFAddress >= mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize)) {
|
||||
if ((SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_ID) != 0) {
|
||||
DEBUG ((EFI_D_ERROR, "Code executed on IP(0x%x) out of SMM range after SMM is locked!\n", PFAddress));
|
||||
DEBUG ((DEBUG_ERROR, "Code executed on IP(0x%x) out of SMM range after SMM is locked!\n", PFAddress));
|
||||
DEBUG_CODE (
|
||||
DumpModuleInfoByIp (*(UINTN *)(UINTN)SystemContext.SystemContextIa32->Esp);
|
||||
);
|
||||
|
@ -128,3 +128,68 @@ SmiPFHandler (
|
|||
|
||||
ReleaseSpinLock (mPFLock);
|
||||
}
|
||||
|
||||
/**
|
||||
This function sets memory attribute for page table.
|
||||
**/
|
||||
VOID
|
||||
SetPageTableAttributes (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
UINTN Index2;
|
||||
UINTN Index3;
|
||||
UINT64 *L1PageTable;
|
||||
UINT64 *L2PageTable;
|
||||
UINT64 *L3PageTable;
|
||||
BOOLEAN IsSplitted;
|
||||
BOOLEAN PageTableSplitted;
|
||||
|
||||
DEBUG ((DEBUG_INFO, "SetPageTableAttributes\n"));
|
||||
|
||||
//
|
||||
// Disable write protection, because we need mark page table to be write protected.
|
||||
// We need *write* page table memory, to mark itself to be *read only*.
|
||||
//
|
||||
AsmWriteCr0 (AsmReadCr0() & ~CR0_WP);
|
||||
|
||||
do {
|
||||
DEBUG ((DEBUG_INFO, "Start...\n"));
|
||||
PageTableSplitted = FALSE;
|
||||
|
||||
L3PageTable = (UINT64 *)GetPageTableBase ();
|
||||
|
||||
SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS)(UINTN)L3PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);
|
||||
PageTableSplitted = (PageTableSplitted || IsSplitted);
|
||||
|
||||
for (Index3 = 0; Index3 < 4; Index3++) {
|
||||
L2PageTable = (UINT64 *)(UINTN)(L3PageTable[Index3] & PAGING_4K_ADDRESS_MASK_64);
|
||||
if (L2PageTable == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS)(UINTN)L2PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);
|
||||
PageTableSplitted = (PageTableSplitted || IsSplitted);
|
||||
|
||||
for (Index2 = 0; Index2 < SIZE_4KB/sizeof(UINT64); Index2++) {
|
||||
if ((L2PageTable[Index2] & IA32_PG_PS) != 0) {
|
||||
// 2M
|
||||
continue;
|
||||
}
|
||||
L1PageTable = (UINT64 *)(UINTN)(L2PageTable[Index2] & PAGING_4K_ADDRESS_MASK_64);
|
||||
if (L1PageTable == NULL) {
|
||||
continue;
|
||||
}
|
||||
SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS)(UINTN)L1PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);
|
||||
PageTableSplitted = (PageTableSplitted || IsSplitted);
|
||||
}
|
||||
}
|
||||
} while (PageTableSplitted);
|
||||
|
||||
//
|
||||
// Enable write protection, after page table updated.
|
||||
//
|
||||
AsmWriteCr0 (AsmReadCr0() | CR0_WP);
|
||||
|
||||
return ;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#------------------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
|
||||
# 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
|
||||
|
@ -24,9 +24,13 @@ ASM_GLOBAL ASM_PFX(gcSmiHandlerSize)
|
|||
ASM_GLOBAL ASM_PFX(gSmiCr3)
|
||||
ASM_GLOBAL ASM_PFX(gSmiStack)
|
||||
ASM_GLOBAL ASM_PFX(gSmbase)
|
||||
ASM_GLOBAL ASM_PFX(mXdSupported)
|
||||
ASM_GLOBAL ASM_PFX(FeaturePcdGet (PcdCpuSmmStackGuard))
|
||||
ASM_GLOBAL ASM_PFX(gSmiHandlerIdtr)
|
||||
|
||||
.equ MSR_EFER, 0xc0000080
|
||||
.equ MSR_EFER_XD, 0x800
|
||||
|
||||
.equ DSC_OFFSET, 0xfb00
|
||||
.equ DSC_GDTPTR, 0x30
|
||||
.equ DSC_GDTSIZ, 0x38
|
||||
|
@ -122,8 +126,41 @@ L11:
|
|||
orl $BIT10, %eax
|
||||
L12: # as cr4.PGE is not set here, refresh cr3
|
||||
movl %eax, %cr4 # in PreModifyMtrrs() to flush TLB.
|
||||
|
||||
cmpb $0, ASM_PFX(FeaturePcdGet (PcdCpuSmmStackGuard))
|
||||
jz L5
|
||||
# Load TSS
|
||||
movb $0x89, (TSS_SEGMENT + 5)(%ebp) # clear busy flag
|
||||
movl $TSS_SEGMENT, %eax
|
||||
ltrw %ax
|
||||
L5:
|
||||
|
||||
# enable NXE if supported
|
||||
.byte 0xb0 # mov al, imm8
|
||||
ASM_PFX(mXdSupported): .byte 1
|
||||
cmpb $0, %al
|
||||
jz SkipNxe
|
||||
#
|
||||
# Check XD disable bit
|
||||
#
|
||||
movl $MSR_IA32_MISC_ENABLE, %ecx
|
||||
rdmsr
|
||||
pushl %edx # save MSR_IA32_MISC_ENABLE[63-32]
|
||||
testl $BIT2, %edx # MSR_IA32_MISC_ENABLE[34]
|
||||
jz L13
|
||||
andw $0x0FFFB, %dx # clear XD Disable bit if it is set
|
||||
wrmsr
|
||||
L13:
|
||||
movl $MSR_EFER, %ecx
|
||||
rdmsr
|
||||
orw $MSR_EFER_XD,%ax # enable NXE
|
||||
wrmsr
|
||||
SkipNxe:
|
||||
subl $4, %esp
|
||||
NxeDone:
|
||||
|
||||
movl %cr0, %ebx
|
||||
orl $0x080010000, %ebx # enable paging + WP
|
||||
orl $0x080010023, %ebx # enable paging + WP + NE + MP + PE
|
||||
movl %ebx, %cr0
|
||||
leal DSC_OFFSET(%edi),%ebx
|
||||
movw DSC_DS(%ebx),%ax
|
||||
|
@ -135,35 +172,39 @@ L12: # as cr4.PGE is not set here, refresh
|
|||
movw DSC_SS(%ebx),%ax
|
||||
movl %eax, %ss
|
||||
|
||||
cmpb $0, ASM_PFX(FeaturePcdGet (PcdCpuSmmStackGuard))
|
||||
jz L5
|
||||
|
||||
# Load TSS
|
||||
movb $0x89, (TSS_SEGMENT + 5)(%ebp) # clear busy flag
|
||||
movl $TSS_SEGMENT, %eax
|
||||
ltrw %ax
|
||||
L5:
|
||||
|
||||
# jmp _SmiHandler # instruction is not needed
|
||||
|
||||
_SmiHandler:
|
||||
movl (%esp), %ebx
|
||||
movl 4(%esp), %ebx
|
||||
|
||||
pushl %ebx
|
||||
movl $ASM_PFX(CpuSmmDebugEntry), %eax
|
||||
call *%eax
|
||||
popl %ecx
|
||||
addl $4, %esp
|
||||
|
||||
pushl %ebx
|
||||
movl $ASM_PFX(SmiRendezvous), %eax
|
||||
call *%eax
|
||||
popl %ecx
|
||||
addl $4, %esp
|
||||
|
||||
pushl %ebx
|
||||
movl $ASM_PFX(CpuSmmDebugExit), %eax
|
||||
call *%eax
|
||||
popl %ecx
|
||||
addl $4, %esp
|
||||
|
||||
movl $ASM_PFX(mXdSupported), %eax
|
||||
movb (%eax), %al
|
||||
cmpb $0, %al
|
||||
jz L16
|
||||
popl %edx # get saved MSR_IA32_MISC_ENABLE[63-32]
|
||||
testl $BIT2, %edx
|
||||
jz L16
|
||||
movl $MSR_IA32_MISC_ENABLE, %ecx
|
||||
rdmsr
|
||||
orw $BIT2, %dx # set XD Disable bit if it was set before entering into SMM
|
||||
wrmsr
|
||||
|
||||
L16:
|
||||
rsm
|
||||
|
||||
ASM_PFX(gcSmiHandlerSize): .word . - _SmiEntryPoint
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
;------------------------------------------------------------------------------ ;
|
||||
; Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
|
||||
; 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
|
||||
|
@ -22,6 +22,10 @@
|
|||
.model flat,C
|
||||
.xmm
|
||||
|
||||
MSR_IA32_MISC_ENABLE EQU 1A0h
|
||||
MSR_EFER EQU 0c0000080h
|
||||
MSR_EFER_XD EQU 0800h
|
||||
|
||||
DSC_OFFSET EQU 0fb00h
|
||||
DSC_GDTPTR EQU 30h
|
||||
DSC_GDTSIZ EQU 38h
|
||||
|
@ -43,6 +47,7 @@ EXTERNDEF gcSmiHandlerSize:WORD
|
|||
EXTERNDEF gSmiCr3:DWORD
|
||||
EXTERNDEF gSmiStack:DWORD
|
||||
EXTERNDEF gSmbase:DWORD
|
||||
EXTERNDEF mXdSupported:BYTE
|
||||
EXTERNDEF FeaturePcdGet (PcdCpuSmmStackGuard):BYTE
|
||||
EXTERNDEF gSmiHandlerIdtr:FWORD
|
||||
|
||||
|
@ -128,8 +133,42 @@ gSmiCr3 DD ?
|
|||
or eax, BIT10
|
||||
@@: ; as cr4.PGE is not set here, refresh cr3
|
||||
mov cr4, eax ; in PreModifyMtrrs() to flush TLB.
|
||||
|
||||
cmp FeaturePcdGet (PcdCpuSmmStackGuard), 0
|
||||
jz @F
|
||||
; Load TSS
|
||||
mov byte ptr [ebp + TSS_SEGMENT + 5], 89h ; clear busy flag
|
||||
mov eax, TSS_SEGMENT
|
||||
ltr ax
|
||||
@@:
|
||||
|
||||
; enable NXE if supported
|
||||
DB 0b0h ; mov al, imm8
|
||||
mXdSupported DB 1
|
||||
cmp al, 0
|
||||
jz @SkipXd
|
||||
;
|
||||
; Check XD disable bit
|
||||
;
|
||||
mov ecx, MSR_IA32_MISC_ENABLE
|
||||
rdmsr
|
||||
push edx ; 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, 4
|
||||
@XdDone:
|
||||
|
||||
mov ebx, cr0
|
||||
or ebx, 080010000h ; enable paging + WP
|
||||
or ebx, 080010023h ; enable paging + WP + NE + MP + PE
|
||||
mov cr0, ebx
|
||||
lea ebx, [edi + DSC_OFFSET]
|
||||
mov ax, [ebx + DSC_DS]
|
||||
|
@ -141,34 +180,38 @@ gSmiCr3 DD ?
|
|||
mov ax, [ebx + DSC_SS]
|
||||
mov ss, eax
|
||||
|
||||
cmp FeaturePcdGet (PcdCpuSmmStackGuard), 0
|
||||
jz @F
|
||||
|
||||
; Load TSS
|
||||
mov byte ptr [ebp + TSS_SEGMENT + 5], 89h ; clear busy flag
|
||||
mov eax, TSS_SEGMENT
|
||||
ltr ax
|
||||
@@:
|
||||
; jmp _SmiHandler ; instruction is not needed
|
||||
|
||||
_SmiHandler PROC
|
||||
mov ebx, [esp] ; CPU Index
|
||||
|
||||
mov ebx, [esp + 4] ; CPU Index
|
||||
push ebx
|
||||
mov eax, CpuSmmDebugEntry
|
||||
call eax
|
||||
pop ecx
|
||||
add esp, 4
|
||||
|
||||
push ebx
|
||||
mov eax, SmiRendezvous
|
||||
call eax
|
||||
pop ecx
|
||||
add esp, 4
|
||||
|
||||
push ebx
|
||||
mov eax, CpuSmmDebugExit
|
||||
call eax
|
||||
pop ecx
|
||||
add esp, 4
|
||||
|
||||
mov eax, mXdSupported
|
||||
mov al, [eax]
|
||||
cmp al, 0
|
||||
jz @f
|
||||
pop edx ; 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
|
||||
_SmiHandler ENDP
|
||||
|
||||
|
|
|
@ -18,6 +18,10 @@
|
|||
;
|
||||
;-------------------------------------------------------------------------------
|
||||
|
||||
%define MSR_IA32_MISC_ENABLE 0x1A0
|
||||
%define MSR_EFER 0xc0000080
|
||||
%define MSR_EFER_XD 0x800
|
||||
|
||||
%define DSC_OFFSET 0xfb00
|
||||
%define DSC_GDTPTR 0x30
|
||||
%define DSC_GDTSIZ 0x38
|
||||
|
@ -40,6 +44,7 @@ global ASM_PFX(gcSmiHandlerSize)
|
|||
global ASM_PFX(gSmiCr3)
|
||||
global ASM_PFX(gSmiStack)
|
||||
global ASM_PFX(gSmbase)
|
||||
global ASM_PFX(mXdSupported)
|
||||
extern ASM_PFX(gSmiHandlerIdtr)
|
||||
|
||||
SECTION .text
|
||||
|
@ -115,8 +120,42 @@ ASM_PFX(gSmiCr3): DD 0
|
|||
or eax, BIT10
|
||||
.4: ; as cr4.PGE is not set here, refresh cr3
|
||||
mov cr4, eax ; in PreModifyMtrrs() to flush TLB.
|
||||
|
||||
cmp byte [dword ASM_PFX(FeaturePcdGet (PcdCpuSmmStackGuard))], 0
|
||||
jz .6
|
||||
; Load TSS
|
||||
mov byte [ebp + TSS_SEGMENT + 5], 0x89 ; clear busy flag
|
||||
mov eax, TSS_SEGMENT
|
||||
ltr ax
|
||||
.6:
|
||||
|
||||
; enable NXE if supported
|
||||
DB 0b0h ; mov al, imm8
|
||||
ASM_PFX(mXdSupported): DB 1
|
||||
cmp al, 0
|
||||
jz @SkipXd
|
||||
;
|
||||
; Check XD disable bit
|
||||
;
|
||||
mov ecx, MSR_IA32_MISC_ENABLE
|
||||
rdmsr
|
||||
push edx ; save MSR_IA32_MISC_ENABLE[63-32]
|
||||
test edx, BIT2 ; MSR_IA32_MISC_ENABLE[34]
|
||||
jz .5
|
||||
and dx, 0xFFFB ; clear XD Disable bit if it is set
|
||||
wrmsr
|
||||
.5:
|
||||
mov ecx, MSR_EFER
|
||||
rdmsr
|
||||
or ax, MSR_EFER_XD ; enable NXE
|
||||
wrmsr
|
||||
jmp @XdDone
|
||||
@SkipXd:
|
||||
sub esp, 4
|
||||
@XdDone:
|
||||
|
||||
mov ebx, cr0
|
||||
or ebx, 0x080010000 ; enable paging + WP
|
||||
or ebx, 0x80010023 ; enable paging + WP + NE + MP + PE
|
||||
mov cr0, ebx
|
||||
lea ebx, [edi + DSC_OFFSET]
|
||||
mov ax, [ebx + DSC_DS]
|
||||
|
@ -128,35 +167,39 @@ ASM_PFX(gSmiCr3): DD 0
|
|||
mov ax, [ebx + DSC_SS]
|
||||
mov ss, eax
|
||||
|
||||
cmp byte [dword ASM_PFX(FeaturePcdGet (PcdCpuSmmStackGuard))], 0
|
||||
jz .5
|
||||
|
||||
; Load TSS
|
||||
mov byte [ebp + TSS_SEGMENT + 5], 0x89 ; clear busy flag
|
||||
mov eax, TSS_SEGMENT
|
||||
ltr ax
|
||||
.5:
|
||||
; jmp _SmiHandler ; instruction is not needed
|
||||
|
||||
global ASM_PFX(SmiHandler)
|
||||
ASM_PFX(SmiHandler):
|
||||
mov ebx, [esp] ; CPU Index
|
||||
|
||||
mov ebx, [esp + 4] ; CPU Index
|
||||
push ebx
|
||||
mov eax, ASM_PFX(CpuSmmDebugEntry)
|
||||
call eax
|
||||
pop ecx
|
||||
add esp, 4
|
||||
|
||||
push ebx
|
||||
mov eax, ASM_PFX(SmiRendezvous)
|
||||
call eax
|
||||
pop ecx
|
||||
add esp, 4
|
||||
|
||||
push ebx
|
||||
mov eax, ASM_PFX(CpuSmmDebugExit)
|
||||
call eax
|
||||
pop ecx
|
||||
add esp, 4
|
||||
|
||||
mov eax, ASM_PFX(mXdSupported)
|
||||
mov al, [eax]
|
||||
cmp al, 0
|
||||
jz .7
|
||||
pop edx ; get saved MSR_IA32_MISC_ENABLE[63-32]
|
||||
test edx, BIT2
|
||||
jz .7
|
||||
mov ecx, MSR_IA32_MISC_ENABLE
|
||||
rdmsr
|
||||
or dx, BIT2 ; set XD Disable bit if it was set before entering into SMM
|
||||
wrmsr
|
||||
|
||||
.7:
|
||||
rsm
|
||||
|
||||
ASM_PFX(gcSmiHandlerSize): DW $ - _SmiEntryPoint
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#------------------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
|
||||
# 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
|
||||
|
@ -24,6 +24,7 @@ ASM_GLOBAL ASM_PFX(PageFaultStubFunction)
|
|||
ASM_GLOBAL ASM_PFX(gSmiMtrrs)
|
||||
ASM_GLOBAL ASM_PFX(gcSmiIdtr)
|
||||
ASM_GLOBAL ASM_PFX(gcSmiGdtr)
|
||||
ASM_GLOBAL ASM_PFX(gTaskGateDescriptor)
|
||||
ASM_GLOBAL ASM_PFX(gcPsd)
|
||||
ASM_GLOBAL ASM_PFX(FeaturePcdGet (PcdCpuSmmProfileEnable))
|
||||
|
||||
|
@ -236,207 +237,10 @@ ASM_PFX(gcPsd):
|
|||
ASM_PFX(gcSmiGdtr): .word GDT_SIZE - 1
|
||||
.long NullSeg
|
||||
|
||||
ASM_PFX(gcSmiIdtr): .word IDT_SIZE - 1
|
||||
.long _SmiIDT
|
||||
ASM_PFX(gcSmiIdtr): .word 0
|
||||
.long 0
|
||||
|
||||
_SmiIDT:
|
||||
# The following segment repeats 32 times:
|
||||
# No. 1
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
# No. 2
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
# No. 3
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
# No. 4
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
# No. 5
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
# No. 6
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
# No. 7
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
# No. 8
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
# No. 9
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
# No. 10
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
# No. 11
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
# No. 12
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
# No. 13
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
# No. 14
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
# No. 15
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
# No. 16
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
# No. 17
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
# No. 18
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
# No. 19
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
# No. 20
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
# No. 21
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
# No. 22
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
# No. 23
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
# No. 24
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
# No. 25
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
# No. 26
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
# No. 27
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
# No. 28
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
# No. 29
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
# No. 30
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
# No. 31
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
# No. 32
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
|
||||
.equ IDT_SIZE, . - _SmiIDT
|
||||
|
||||
TaskGateDescriptor:
|
||||
ASM_PFX(gTaskGateDescriptor):
|
||||
.word 0 # Reserved
|
||||
.word EXCEPTION_TSS_SEL # TSS Segment selector
|
||||
.byte 0 # Reserved
|
||||
|
@ -891,21 +695,3 @@ ASM_PFX(PageFaultStubFunction):
|
|||
#
|
||||
clts
|
||||
iret
|
||||
|
||||
ASM_GLOBAL ASM_PFX(InitializeIDTSmmStackGuard)
|
||||
ASM_PFX(InitializeIDTSmmStackGuard):
|
||||
pushl %ebx
|
||||
#
|
||||
# If SMM Stack Guard feature is enabled, the Page Fault Exception entry in IDT
|
||||
# is a Task Gate Descriptor so that when a Page Fault Exception occurs,
|
||||
# the processors can use a known good stack in case stack ran out.
|
||||
#
|
||||
leal _SmiIDT + 14 * 8, %ebx
|
||||
leal TaskGateDescriptor, %edx
|
||||
movl (%edx), %eax
|
||||
movl %eax, (%ebx)
|
||||
movl 4(%edx), %eax
|
||||
movl %eax, 4(%ebx)
|
||||
|
||||
popl %ebx
|
||||
ret
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
;------------------------------------------------------------------------------ ;
|
||||
; Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
|
||||
; 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
|
||||
|
@ -26,6 +26,7 @@ EXTERNDEF PageFaultStubFunction:PROC
|
|||
EXTERNDEF gSmiMtrrs:QWORD
|
||||
EXTERNDEF gcSmiIdtr:FWORD
|
||||
EXTERNDEF gcSmiGdtr:FWORD
|
||||
EXTERNDEF gTaskGateDescriptor:QWORD
|
||||
EXTERNDEF gcPsd:BYTE
|
||||
EXTERNDEF FeaturePcdGet (PcdCpuSmmProfileEnable):BYTE
|
||||
|
||||
|
@ -252,20 +253,10 @@ gcSmiGdtr LABEL FWORD
|
|||
DD offset NullSeg
|
||||
|
||||
gcSmiIdtr LABEL FWORD
|
||||
DW IDT_SIZE - 1
|
||||
DD offset _SmiIDT
|
||||
DW 0
|
||||
DD 0
|
||||
|
||||
_SmiIDT LABEL QWORD
|
||||
REPEAT 32
|
||||
DW 0 ; Offset 0:15
|
||||
DW CODE_SEL ; Segment selector
|
||||
DB 0 ; Unused
|
||||
DB 8eh ; Interrupt Gate, Present
|
||||
DW 0 ; Offset 16:31
|
||||
ENDM
|
||||
IDT_SIZE = $ - offset _SmiIDT
|
||||
|
||||
TaskGateDescriptor LABEL DWORD
|
||||
gTaskGateDescriptor LABEL QWORD
|
||||
DW 0 ; Reserved
|
||||
DW EXCEPTION_TSS_SEL ; TSS Segment selector
|
||||
DB 0 ; Reserved
|
||||
|
@ -720,19 +711,4 @@ PageFaultStubFunction PROC
|
|||
iretd
|
||||
PageFaultStubFunction ENDP
|
||||
|
||||
InitializeIDTSmmStackGuard PROC USES ebx
|
||||
;
|
||||
; If SMM Stack Guard feature is enabled, the Page Fault Exception entry in IDT
|
||||
; is a Task Gate Descriptor so that when a Page Fault Exception occurs,
|
||||
; the processors can use a known good stack in case stack is ran out.
|
||||
;
|
||||
lea ebx, _SmiIDT + 14 * 8
|
||||
lea edx, TaskGateDescriptor
|
||||
mov eax, [edx]
|
||||
mov [ebx], eax
|
||||
mov eax, [edx + 4]
|
||||
mov [ebx + 4], eax
|
||||
ret
|
||||
InitializeIDTSmmStackGuard ENDP
|
||||
|
||||
END
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
;------------------------------------------------------------------------------ ;
|
||||
; Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
|
||||
; 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
|
||||
|
@ -24,6 +24,7 @@ extern ASM_PFX(SmiPFHandler)
|
|||
|
||||
global ASM_PFX(gcSmiIdtr)
|
||||
global ASM_PFX(gcSmiGdtr)
|
||||
global ASM_PFX(gTaskGateDescriptor)
|
||||
global ASM_PFX(gcPsd)
|
||||
|
||||
SECTION .data
|
||||
|
@ -250,21 +251,10 @@ ASM_PFX(gcSmiGdtr):
|
|||
DD NullSeg
|
||||
|
||||
ASM_PFX(gcSmiIdtr):
|
||||
DW IDT_SIZE - 1
|
||||
DD _SmiIDT
|
||||
DW 0
|
||||
DD 0
|
||||
|
||||
_SmiIDT:
|
||||
%rep 32
|
||||
DW 0 ; Offset 0:15
|
||||
DW CODE_SEL ; Segment selector
|
||||
DB 0 ; Unused
|
||||
DB 0x8e ; Interrupt Gate, Present
|
||||
DW 0 ; Offset 16:31
|
||||
%endrep
|
||||
|
||||
IDT_SIZE equ $ - _SmiIDT
|
||||
|
||||
TaskGateDescriptor:
|
||||
ASM_PFX(gTaskGateDescriptor):
|
||||
DW 0 ; Reserved
|
||||
DW EXCEPTION_TSS_SEL ; TSS Segment selector
|
||||
DB 0 ; Reserved
|
||||
|
@ -717,19 +707,3 @@ ASM_PFX(PageFaultStubFunction):
|
|||
clts
|
||||
iretd
|
||||
|
||||
global ASM_PFX(InitializeIDTSmmStackGuard)
|
||||
ASM_PFX(InitializeIDTSmmStackGuard):
|
||||
push ebx
|
||||
;
|
||||
; If SMM Stack Guard feature is enabled, the Page Fault Exception entry in IDT
|
||||
; is a Task Gate Descriptor so that when a Page Fault Exception occurrs,
|
||||
; the processors can use a known good stack in case stack is ran out.
|
||||
;
|
||||
lea ebx, [_SmiIDT + 14 * 8]
|
||||
lea edx, [TaskGateDescriptor]
|
||||
mov eax, [edx]
|
||||
mov [ebx], eax
|
||||
mov eax, [edx + 4]
|
||||
mov [ebx + 4], eax
|
||||
pop ebx
|
||||
ret
|
||||
|
|
|
@ -14,6 +14,33 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|||
|
||||
#include "PiSmmCpuDxeSmm.h"
|
||||
|
||||
extern UINT64 gTaskGateDescriptor;
|
||||
|
||||
EFI_PHYSICAL_ADDRESS mGdtBuffer;
|
||||
UINTN mGdtBufferSize;
|
||||
|
||||
/**
|
||||
Initialize IDT for SMM Stack Guard.
|
||||
|
||||
**/
|
||||
VOID
|
||||
EFIAPI
|
||||
InitializeIDTSmmStackGuard (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
IA32_IDT_GATE_DESCRIPTOR *IdtGate;
|
||||
|
||||
//
|
||||
// If SMM Stack Guard feature is enabled, the Page Fault Exception entry in IDT
|
||||
// is a Task Gate Descriptor so that when a Page Fault Exception occurs,
|
||||
// the processors can use a known good stack in case stack is ran out.
|
||||
//
|
||||
IdtGate = (IA32_IDT_GATE_DESCRIPTOR *)gcSmiIdtr.Base;
|
||||
IdtGate += EXCEPT_IA32_PAGE_FAULT;
|
||||
IdtGate->Uint64 = gTaskGateDescriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
Initialize Gdt for all processors.
|
||||
|
||||
|
@ -49,8 +76,10 @@ InitGdt (
|
|||
gcSmiGdtr.Limit += (UINT16)(2 * sizeof (IA32_SEGMENT_DESCRIPTOR));
|
||||
|
||||
GdtTssTableSize = (gcSmiGdtr.Limit + 1 + TSS_SIZE * 2 + 7) & ~7; // 8 bytes aligned
|
||||
GdtTssTables = (UINT8*)AllocatePages (EFI_SIZE_TO_PAGES (GdtTssTableSize * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus));
|
||||
mGdtBufferSize = GdtTssTableSize * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus;
|
||||
GdtTssTables = (UINT8*)AllocateCodePages (EFI_SIZE_TO_PAGES (mGdtBufferSize));
|
||||
ASSERT (GdtTssTables != NULL);
|
||||
mGdtBuffer = (UINTN)GdtTssTables;
|
||||
GdtTableStepSize = GdtTssTableSize;
|
||||
|
||||
for (Index = 0; Index < gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; Index++) {
|
||||
|
@ -82,8 +111,10 @@ InitGdt (
|
|||
// Just use original table, AllocatePage and copy them here to make sure GDTs are covered in page memory.
|
||||
//
|
||||
GdtTssTableSize = gcSmiGdtr.Limit + 1;
|
||||
GdtTssTables = (UINT8*)AllocatePages (EFI_SIZE_TO_PAGES (GdtTssTableSize * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus));
|
||||
mGdtBufferSize = GdtTssTableSize * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus;
|
||||
GdtTssTables = (UINT8*)AllocateCodePages (EFI_SIZE_TO_PAGES (mGdtBufferSize));
|
||||
ASSERT (GdtTssTables != NULL);
|
||||
mGdtBuffer = (UINTN)GdtTssTables;
|
||||
GdtTableStepSize = GdtTssTableSize;
|
||||
|
||||
for (Index = 0; Index < gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; Index++) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/** @file
|
||||
IA-32 processor specific functions to enable SMM profile.
|
||||
|
||||
Copyright (c) 2012 - 2015, Intel Corporation. All rights reserved.<BR>
|
||||
Copyright (c) 2012 - 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
|
||||
|
@ -24,7 +24,7 @@ InitSmmS3Cr3 (
|
|||
VOID
|
||||
)
|
||||
{
|
||||
mSmmS3ResumeState->SmmS3Cr3 = Gen4GPageTable (0, TRUE);
|
||||
mSmmS3ResumeState->SmmS3Cr3 = Gen4GPageTable (TRUE);
|
||||
|
||||
return ;
|
||||
}
|
||||
|
|
|
@ -734,14 +734,12 @@ APHandler (
|
|||
/**
|
||||
Create 4G PageTable in SMRAM.
|
||||
|
||||
@param ExtraPages Additional page numbers besides for 4G memory
|
||||
@param Is32BitPageTable Whether the page table is 32-bit PAE
|
||||
@param[in] Is32BitPageTable Whether the page table is 32-bit PAE
|
||||
@return PageTable Address
|
||||
|
||||
**/
|
||||
UINT32
|
||||
Gen4GPageTable (
|
||||
IN UINTN ExtraPages,
|
||||
IN BOOLEAN Is32BitPageTable
|
||||
)
|
||||
{
|
||||
|
@ -775,10 +773,10 @@ Gen4GPageTable (
|
|||
//
|
||||
// Allocate the page table
|
||||
//
|
||||
PageTable = AllocatePageTableMemory (ExtraPages + 5 + PagesNeeded);
|
||||
PageTable = AllocatePageTableMemory (5 + PagesNeeded);
|
||||
ASSERT (PageTable != NULL);
|
||||
|
||||
PageTable = (VOID *)((UINTN)PageTable + EFI_PAGES_TO_SIZE (ExtraPages));
|
||||
PageTable = (VOID *)((UINTN)PageTable);
|
||||
Pte = (UINT64*)PageTable;
|
||||
|
||||
//
|
||||
|
@ -903,6 +901,94 @@ SetCacheability (
|
|||
PageTable[PTIndex] |= (UINT64)Cacheability;
|
||||
}
|
||||
|
||||
/**
|
||||
Schedule a procedure to run on the specified CPU.
|
||||
|
||||
@param[in] Procedure The address of the procedure to run
|
||||
@param[in] CpuIndex Target CPU Index
|
||||
@param[in, OUT] ProcArguments The parameter to pass to the procedure
|
||||
@param[in] BlockingMode Startup AP in blocking mode or not
|
||||
|
||||
@retval EFI_INVALID_PARAMETER CpuNumber not valid
|
||||
@retval EFI_INVALID_PARAMETER CpuNumber specifying BSP
|
||||
@retval EFI_INVALID_PARAMETER The AP specified by CpuNumber did not enter SMM
|
||||
@retval EFI_INVALID_PARAMETER The AP specified by CpuNumber is busy
|
||||
@retval EFI_SUCCESS The procedure has been successfully scheduled
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
InternalSmmStartupThisAp (
|
||||
IN EFI_AP_PROCEDURE Procedure,
|
||||
IN UINTN CpuIndex,
|
||||
IN OUT VOID *ProcArguments OPTIONAL,
|
||||
IN BOOLEAN BlockingMode
|
||||
)
|
||||
{
|
||||
if (CpuIndex >= gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus) {
|
||||
DEBUG((DEBUG_ERROR, "CpuIndex(%d) >= gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus(%d)\n", CpuIndex, gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus));
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
if (CpuIndex == gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingCpu) {
|
||||
DEBUG((DEBUG_ERROR, "CpuIndex(%d) == gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingCpu\n", CpuIndex));
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
if (!(*(mSmmMpSyncData->CpuData[CpuIndex].Present))) {
|
||||
if (mSmmMpSyncData->EffectiveSyncMode == SmmCpuSyncModeTradition) {
|
||||
DEBUG((DEBUG_ERROR, "!mSmmMpSyncData->CpuData[%d].Present\n", CpuIndex));
|
||||
}
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
if (gSmmCpuPrivate->Operation[CpuIndex] == SmmCpuRemove) {
|
||||
if (!FeaturePcdGet (PcdCpuHotPlugSupport)) {
|
||||
DEBUG((DEBUG_ERROR, "gSmmCpuPrivate->Operation[%d] == SmmCpuRemove\n", CpuIndex));
|
||||
}
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (BlockingMode) {
|
||||
AcquireSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);
|
||||
} else {
|
||||
if (!AcquireSpinLockOrFail (mSmmMpSyncData->CpuData[CpuIndex].Busy)) {
|
||||
DEBUG((DEBUG_ERROR, "mSmmMpSyncData->CpuData[%d].Busy\n", CpuIndex));
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
}
|
||||
|
||||
mSmmMpSyncData->CpuData[CpuIndex].Procedure = Procedure;
|
||||
mSmmMpSyncData->CpuData[CpuIndex].Parameter = ProcArguments;
|
||||
ReleaseSemaphore (mSmmMpSyncData->CpuData[CpuIndex].Run);
|
||||
|
||||
if (BlockingMode) {
|
||||
AcquireSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);
|
||||
ReleaseSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);
|
||||
}
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Schedule a procedure to run on the specified CPU in blocking mode.
|
||||
|
||||
@param[in] Procedure The address of the procedure to run
|
||||
@param[in] CpuIndex Target CPU Index
|
||||
@param[in, out] ProcArguments The parameter to pass to the procedure
|
||||
|
||||
@retval EFI_INVALID_PARAMETER CpuNumber not valid
|
||||
@retval EFI_INVALID_PARAMETER CpuNumber specifying BSP
|
||||
@retval EFI_INVALID_PARAMETER The AP specified by CpuNumber did not enter SMM
|
||||
@retval EFI_INVALID_PARAMETER The AP specified by CpuNumber is busy
|
||||
@retval EFI_SUCCESS The procedure has been successfully scheduled
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
SmmBlockingStartupThisAp (
|
||||
IN EFI_AP_PROCEDURE Procedure,
|
||||
IN UINTN CpuIndex,
|
||||
IN OUT VOID *ProcArguments OPTIONAL
|
||||
)
|
||||
{
|
||||
return InternalSmmStartupThisAp(Procedure, CpuIndex, ProcArguments, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
Schedule a procedure to run on the specified CPU.
|
||||
|
@ -926,23 +1012,7 @@ SmmStartupThisAp (
|
|||
IN OUT VOID *ProcArguments OPTIONAL
|
||||
)
|
||||
{
|
||||
if (CpuIndex >= gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus ||
|
||||
CpuIndex == gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingCpu ||
|
||||
!(*(mSmmMpSyncData->CpuData[CpuIndex].Present)) ||
|
||||
gSmmCpuPrivate->Operation[CpuIndex] == SmmCpuRemove ||
|
||||
!AcquireSpinLockOrFail (mSmmMpSyncData->CpuData[CpuIndex].Busy)) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
mSmmMpSyncData->CpuData[CpuIndex].Procedure = Procedure;
|
||||
mSmmMpSyncData->CpuData[CpuIndex].Parameter = ProcArguments;
|
||||
ReleaseSemaphore (mSmmMpSyncData->CpuData[CpuIndex].Run);
|
||||
|
||||
if (FeaturePcdGet (PcdCpuSmmBlockStartupThisAp)) {
|
||||
AcquireSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);
|
||||
ReleaseSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);
|
||||
}
|
||||
return EFI_SUCCESS;
|
||||
return InternalSmmStartupThisAp(Procedure, CpuIndex, ProcArguments, FeaturePcdGet (PcdCpuSmmBlockStartupThisAp));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -964,6 +1034,7 @@ CpuSmmDebugEntry (
|
|||
SMRAM_SAVE_STATE_MAP *CpuSaveState;
|
||||
|
||||
if (FeaturePcdGet (PcdCpuSmmDebug)) {
|
||||
ASSERT(CpuIndex < mMaxNumberOfCpus);
|
||||
CpuSaveState = (SMRAM_SAVE_STATE_MAP *)gSmmCpuPrivate->CpuSaveState[CpuIndex];
|
||||
if (mSmmSaveStateRegisterLma == EFI_SMM_SAVE_STATE_REGISTER_LMA_32BIT) {
|
||||
AsmWriteDr6 (CpuSaveState->x86._DR6);
|
||||
|
@ -993,6 +1064,7 @@ CpuSmmDebugExit (
|
|||
SMRAM_SAVE_STATE_MAP *CpuSaveState;
|
||||
|
||||
if (FeaturePcdGet (PcdCpuSmmDebug)) {
|
||||
ASSERT(CpuIndex < mMaxNumberOfCpus);
|
||||
CpuSaveState = (SMRAM_SAVE_STATE_MAP *)gSmmCpuPrivate->CpuSaveState[CpuIndex];
|
||||
if (mSmmSaveStateRegisterLma == EFI_SMM_SAVE_STATE_REGISTER_LMA_32BIT) {
|
||||
CpuSaveState->x86._DR7 = (UINT32)AsmReadDr7 ();
|
||||
|
@ -1022,8 +1094,8 @@ SmiRendezvous (
|
|||
BOOLEAN BspInProgress;
|
||||
UINTN Index;
|
||||
UINTN Cr2;
|
||||
BOOLEAN XdDisableFlag;
|
||||
MSR_IA32_MISC_ENABLE_REGISTER MiscEnableMsr;
|
||||
|
||||
ASSERT(CpuIndex < mMaxNumberOfCpus);
|
||||
|
||||
//
|
||||
// Save Cr2 because Page Fault exception in SMM may override its value
|
||||
|
@ -1082,20 +1154,6 @@ SmiRendezvous (
|
|||
InitializeSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);
|
||||
}
|
||||
|
||||
//
|
||||
// Try to enable XD
|
||||
//
|
||||
XdDisableFlag = FALSE;
|
||||
if (mXdSupported) {
|
||||
MiscEnableMsr.Uint64 = AsmReadMsr64 (MSR_IA32_MISC_ENABLE);
|
||||
if (MiscEnableMsr.Bits.XD == 1) {
|
||||
XdDisableFlag = TRUE;
|
||||
MiscEnableMsr.Bits.XD = 0;
|
||||
AsmWriteMsr64 (MSR_IA32_MISC_ENABLE, MiscEnableMsr.Uint64);
|
||||
}
|
||||
ActivateXd ();
|
||||
}
|
||||
|
||||
if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {
|
||||
ActivateSmmProfile (CpuIndex);
|
||||
}
|
||||
|
@ -1177,15 +1235,6 @@ SmiRendezvous (
|
|||
while (*mSmmMpSyncData->AllCpusInSync) {
|
||||
CpuPause ();
|
||||
}
|
||||
|
||||
//
|
||||
// Restore XD
|
||||
//
|
||||
if (XdDisableFlag) {
|
||||
MiscEnableMsr.Uint64 = AsmReadMsr64 (MSR_IA32_MISC_ENABLE);
|
||||
MiscEnableMsr.Bits.XD = 1;
|
||||
AsmWriteMsr64 (MSR_IA32_MISC_ENABLE, MiscEnableMsr.Uint64);
|
||||
}
|
||||
}
|
||||
|
||||
Exit:
|
||||
|
|
|
@ -113,6 +113,19 @@ InitializeSmmIdt (
|
|||
EFI_STATUS Status;
|
||||
BOOLEAN InterruptState;
|
||||
IA32_DESCRIPTOR DxeIdtr;
|
||||
|
||||
//
|
||||
// There are 32 (not 255) entries in it since only processor
|
||||
// generated exceptions will be handled.
|
||||
//
|
||||
gcSmiIdtr.Limit = (sizeof(IA32_IDT_GATE_DESCRIPTOR) * 32) - 1;
|
||||
//
|
||||
// Allocate page aligned IDT, because it might be set as read only.
|
||||
//
|
||||
gcSmiIdtr.Base = (UINTN)AllocateCodePages (EFI_SIZE_TO_PAGES(gcSmiIdtr.Limit + 1));
|
||||
ASSERT (gcSmiIdtr.Base != 0);
|
||||
ZeroMem ((VOID *)gcSmiIdtr.Base, gcSmiIdtr.Limit + 1);
|
||||
|
||||
//
|
||||
// Disable Interrupt and save DXE IDT table
|
||||
//
|
||||
|
@ -731,9 +744,9 @@ PiCpuSmmEntry (
|
|||
//
|
||||
BufferPages = EFI_SIZE_TO_PAGES (SIZE_32KB + TileSize * (mMaxNumberOfCpus - 1));
|
||||
if ((FamilyId == 4) || (FamilyId == 5)) {
|
||||
Buffer = AllocateAlignedPages (BufferPages, SIZE_32KB);
|
||||
Buffer = AllocateAlignedCodePages (BufferPages, SIZE_32KB);
|
||||
} else {
|
||||
Buffer = AllocateAlignedPages (BufferPages, SIZE_4KB);
|
||||
Buffer = AllocateAlignedCodePages (BufferPages, SIZE_4KB);
|
||||
}
|
||||
ASSERT (Buffer != NULL);
|
||||
DEBUG ((EFI_D_INFO, "SMRAM SaveState Buffer (0x%08x, 0x%08x)\n", Buffer, EFI_PAGES_TO_SIZE(BufferPages)));
|
||||
|
@ -842,6 +855,8 @@ PiCpuSmmEntry (
|
|||
//
|
||||
SmmCpuFeaturesSmmRelocationComplete ();
|
||||
|
||||
DEBUG ((DEBUG_INFO, "mXdSupported - 0x%x\n", mXdSupported));
|
||||
|
||||
//
|
||||
// SMM Time initialization
|
||||
//
|
||||
|
@ -1137,6 +1152,17 @@ ConfigSmmCodeAccessCheck (
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Set code region to be read only and data region to be execute disable.
|
||||
**/
|
||||
VOID
|
||||
SetRegionAttributes (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
SetMemMapAttributes ();
|
||||
}
|
||||
|
||||
/**
|
||||
This API provides a way to allocate memory for page table.
|
||||
|
||||
|
@ -1166,6 +1192,109 @@ AllocatePageTableMemory (
|
|||
return AllocatePages (Pages);
|
||||
}
|
||||
|
||||
/**
|
||||
Allocate pages for code.
|
||||
|
||||
@param[in] Pages Number of pages to be allocated.
|
||||
|
||||
@return Allocated memory.
|
||||
**/
|
||||
VOID *
|
||||
AllocateCodePages (
|
||||
IN UINTN Pages
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_PHYSICAL_ADDRESS Memory;
|
||||
|
||||
if (Pages == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Status = gSmst->SmmAllocatePages (AllocateAnyPages, EfiRuntimeServicesCode, Pages, &Memory);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return NULL;
|
||||
}
|
||||
return (VOID *) (UINTN) Memory;
|
||||
}
|
||||
|
||||
/**
|
||||
Allocate aligned pages for code.
|
||||
|
||||
@param[in] Pages Number of pages to be allocated.
|
||||
@param[in] Alignment The requested alignment of the allocation.
|
||||
Must be a power of two.
|
||||
If Alignment is zero, then byte alignment is used.
|
||||
|
||||
@return Allocated memory.
|
||||
**/
|
||||
VOID *
|
||||
AllocateAlignedCodePages (
|
||||
IN UINTN Pages,
|
||||
IN UINTN Alignment
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_PHYSICAL_ADDRESS Memory;
|
||||
UINTN AlignedMemory;
|
||||
UINTN AlignmentMask;
|
||||
UINTN UnalignedPages;
|
||||
UINTN RealPages;
|
||||
|
||||
//
|
||||
// Alignment must be a power of two or zero.
|
||||
//
|
||||
ASSERT ((Alignment & (Alignment - 1)) == 0);
|
||||
|
||||
if (Pages == 0) {
|
||||
return NULL;
|
||||
}
|
||||
if (Alignment > EFI_PAGE_SIZE) {
|
||||
//
|
||||
// Calculate the total number of pages since alignment is larger than page size.
|
||||
//
|
||||
AlignmentMask = Alignment - 1;
|
||||
RealPages = Pages + EFI_SIZE_TO_PAGES (Alignment);
|
||||
//
|
||||
// Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow.
|
||||
//
|
||||
ASSERT (RealPages > Pages);
|
||||
|
||||
Status = gSmst->SmmAllocatePages (AllocateAnyPages, EfiRuntimeServicesCode, RealPages, &Memory);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return NULL;
|
||||
}
|
||||
AlignedMemory = ((UINTN) Memory + AlignmentMask) & ~AlignmentMask;
|
||||
UnalignedPages = EFI_SIZE_TO_PAGES (AlignedMemory - (UINTN) Memory);
|
||||
if (UnalignedPages > 0) {
|
||||
//
|
||||
// Free first unaligned page(s).
|
||||
//
|
||||
Status = gSmst->SmmFreePages (Memory, UnalignedPages);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
}
|
||||
Memory = (EFI_PHYSICAL_ADDRESS) (AlignedMemory + EFI_PAGES_TO_SIZE (Pages));
|
||||
UnalignedPages = RealPages - Pages - UnalignedPages;
|
||||
if (UnalignedPages > 0) {
|
||||
//
|
||||
// Free last unaligned page(s).
|
||||
//
|
||||
Status = gSmst->SmmFreePages (Memory, UnalignedPages);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
}
|
||||
} else {
|
||||
//
|
||||
// Do not over-allocate pages in this case.
|
||||
//
|
||||
Status = gSmst->SmmAllocatePages (AllocateAnyPages, EfiRuntimeServicesCode, Pages, &Memory);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return NULL;
|
||||
}
|
||||
AlignedMemory = (UINTN) Memory;
|
||||
}
|
||||
return (VOID *) AlignedMemory;
|
||||
}
|
||||
|
||||
/**
|
||||
Perform the remaining tasks.
|
||||
|
||||
|
@ -1186,6 +1315,17 @@ PerformRemainingTasks (
|
|||
// Create a mix of 2MB and 4KB page table. Update some memory ranges absent and execute-disable.
|
||||
//
|
||||
InitPaging ();
|
||||
|
||||
//
|
||||
// Mark critical region to be read-only in page table
|
||||
//
|
||||
SetRegionAttributes ();
|
||||
|
||||
//
|
||||
// Set page table itself to be read-only
|
||||
//
|
||||
SetPageTableAttributes ();
|
||||
|
||||
//
|
||||
// Configure SMM Code Access Check feature if available.
|
||||
//
|
||||
|
|
|
@ -25,6 +25,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|||
#include <Protocol/SmmCpuService.h>
|
||||
|
||||
#include <Guid/AcpiS3Context.h>
|
||||
#include <Guid/PiSmmMemoryAttributesTable.h>
|
||||
|
||||
#include <Library/BaseLib.h>
|
||||
#include <Library/IoLib.h>
|
||||
|
@ -83,13 +84,38 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|||
#define IA32_PG_PMNT BIT62
|
||||
#define IA32_PG_NX BIT63
|
||||
|
||||
#define PAGE_ATTRIBUTE_BITS (IA32_PG_RW | IA32_PG_P)
|
||||
#define PAGE_ATTRIBUTE_BITS (IA32_PG_D | IA32_PG_A | IA32_PG_U | IA32_PG_RW | IA32_PG_P)
|
||||
//
|
||||
// Bits 1, 2, 5, 6 are reserved in the IA32 PAE PDPTE
|
||||
// X64 PAE PDPTE does not have such restriction
|
||||
//
|
||||
#define IA32_PAE_PDPTE_ATTRIBUTE_BITS (IA32_PG_P)
|
||||
|
||||
#define PAGE_PROGATE_BITS (IA32_PG_NX | PAGE_ATTRIBUTE_BITS)
|
||||
|
||||
#define PAGING_4K_MASK 0xFFF
|
||||
#define PAGING_2M_MASK 0x1FFFFF
|
||||
#define PAGING_1G_MASK 0x3FFFFFFF
|
||||
|
||||
#define PAGING_PAE_INDEX_MASK 0x1FF
|
||||
|
||||
#define PAGING_4K_ADDRESS_MASK_64 0x000FFFFFFFFFF000ull
|
||||
#define PAGING_2M_ADDRESS_MASK_64 0x000FFFFFFFE00000ull
|
||||
#define PAGING_1G_ADDRESS_MASK_64 0x000FFFFFC0000000ull
|
||||
|
||||
typedef enum {
|
||||
PageNone,
|
||||
Page4K,
|
||||
Page2M,
|
||||
Page1G,
|
||||
} PAGE_ATTRIBUTE;
|
||||
|
||||
typedef struct {
|
||||
PAGE_ATTRIBUTE Attribute;
|
||||
UINT64 Length;
|
||||
UINT64 AddressMask;
|
||||
} PAGE_ATTRIBUTE_TABLE;
|
||||
|
||||
//
|
||||
// Size of Task-State Segment defined in IA32 Manual
|
||||
//
|
||||
|
@ -98,6 +124,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|||
#define TSS_IA32_CR3_OFFSET 28
|
||||
#define TSS_IA32_ESP_OFFSET 56
|
||||
|
||||
#define CR0_WP BIT16
|
||||
|
||||
//
|
||||
// Code select value
|
||||
//
|
||||
|
@ -395,6 +423,8 @@ typedef struct {
|
|||
} SMM_CPU_SEMAPHORES;
|
||||
|
||||
extern IA32_DESCRIPTOR gcSmiGdtr;
|
||||
extern EFI_PHYSICAL_ADDRESS mGdtBuffer;
|
||||
extern UINTN mGdtBufferSize;
|
||||
extern IA32_DESCRIPTOR gcSmiIdtr;
|
||||
extern VOID *gcSmiIdtrPtr;
|
||||
extern CONST PROCESSOR_SMM_DESCRIPTOR gcPsd;
|
||||
|
@ -414,14 +444,12 @@ extern SPIN_LOCK *mMemoryMappedLock;
|
|||
/**
|
||||
Create 4G PageTable in SMRAM.
|
||||
|
||||
@param ExtraPages Additional page numbers besides for 4G memory
|
||||
@param Is32BitPageTable Whether the page table is 32-bit PAE
|
||||
@param[in] Is32BitPageTable Whether the page table is 32-bit PAE
|
||||
@return PageTable Address
|
||||
|
||||
**/
|
||||
UINT32
|
||||
Gen4GPageTable (
|
||||
IN UINTN ExtraPages,
|
||||
IN BOOLEAN Is32BitPageTable
|
||||
);
|
||||
|
||||
|
@ -760,6 +788,96 @@ DumpModuleInfoByIp (
|
|||
IN UINTN CallerIpAddress
|
||||
);
|
||||
|
||||
/**
|
||||
This function sets memory attribute according to MemoryAttributesTable.
|
||||
**/
|
||||
VOID
|
||||
SetMemMapAttributes (
|
||||
VOID
|
||||
);
|
||||
|
||||
/**
|
||||
This function sets memory attribute for page table.
|
||||
**/
|
||||
VOID
|
||||
SetPageTableAttributes (
|
||||
VOID
|
||||
);
|
||||
|
||||
/**
|
||||
Return page table base.
|
||||
|
||||
@return page table base.
|
||||
**/
|
||||
UINTN
|
||||
GetPageTableBase (
|
||||
VOID
|
||||
);
|
||||
|
||||
/**
|
||||
This function sets the attributes for the memory region specified by BaseAddress and
|
||||
Length from their current attributes to the attributes specified by Attributes.
|
||||
|
||||
@param[in] BaseAddress The physical address that is the start address of a memory region.
|
||||
@param[in] Length The size in bytes of the memory region.
|
||||
@param[in] Attributes The bit mask of attributes to set for the memory region.
|
||||
@param[out] IsSplitted TRUE means page table splitted. FALSE means page table not splitted.
|
||||
|
||||
@retval EFI_SUCCESS The attributes were set for the memory region.
|
||||
@retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
|
||||
BaseAddress and Length cannot be modified.
|
||||
@retval EFI_INVALID_PARAMETER Length is zero.
|
||||
Attributes specified an illegal combination of attributes that
|
||||
cannot be set together.
|
||||
@retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
|
||||
the memory resource range.
|
||||
@retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
|
||||
resource range specified by BaseAddress and Length.
|
||||
The bit mask of attributes is not support for the memory resource
|
||||
range specified by BaseAddress and Length.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
SmmSetMemoryAttributesEx (
|
||||
IN EFI_PHYSICAL_ADDRESS BaseAddress,
|
||||
IN UINT64 Length,
|
||||
IN UINT64 Attributes,
|
||||
OUT BOOLEAN *IsSplitted OPTIONAL
|
||||
);
|
||||
|
||||
/**
|
||||
This function clears the attributes for the memory region specified by BaseAddress and
|
||||
Length from their current attributes to the attributes specified by Attributes.
|
||||
|
||||
@param[in] BaseAddress The physical address that is the start address of a memory region.
|
||||
@param[in] Length The size in bytes of the memory region.
|
||||
@param[in] Attributes The bit mask of attributes to clear for the memory region.
|
||||
@param[out] IsSplitted TRUE means page table splitted. FALSE means page table not splitted.
|
||||
|
||||
@retval EFI_SUCCESS The attributes were cleared for the memory region.
|
||||
@retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
|
||||
BaseAddress and Length cannot be modified.
|
||||
@retval EFI_INVALID_PARAMETER Length is zero.
|
||||
Attributes specified an illegal combination of attributes that
|
||||
cannot be set together.
|
||||
@retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
|
||||
the memory resource range.
|
||||
@retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
|
||||
resource range specified by BaseAddress and Length.
|
||||
The bit mask of attributes is not support for the memory resource
|
||||
range specified by BaseAddress and Length.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
SmmClearMemoryAttributesEx (
|
||||
IN EFI_PHYSICAL_ADDRESS BaseAddress,
|
||||
IN UINT64 Length,
|
||||
IN UINT64 Attributes,
|
||||
OUT BOOLEAN *IsSplitted OPTIONAL
|
||||
);
|
||||
|
||||
/**
|
||||
This API provides a way to allocate memory for page table.
|
||||
|
||||
|
@ -780,6 +898,34 @@ AllocatePageTableMemory (
|
|||
IN UINTN Pages
|
||||
);
|
||||
|
||||
/**
|
||||
Allocate pages for code.
|
||||
|
||||
@param[in] Pages Number of pages to be allocated.
|
||||
|
||||
@return Allocated memory.
|
||||
**/
|
||||
VOID *
|
||||
AllocateCodePages (
|
||||
IN UINTN Pages
|
||||
);
|
||||
|
||||
/**
|
||||
Allocate aligned pages for code.
|
||||
|
||||
@param[in] Pages Number of pages to be allocated.
|
||||
@param[in] Alignment The requested alignment of the allocation.
|
||||
Must be a power of two.
|
||||
If Alignment is zero, then byte alignment is used.
|
||||
|
||||
@return Allocated memory.
|
||||
**/
|
||||
VOID *
|
||||
AllocateAlignedCodePages (
|
||||
IN UINTN Pages,
|
||||
IN UINTN Alignment
|
||||
);
|
||||
|
||||
|
||||
//
|
||||
// S3 related global variable and function prototype.
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
# This SMM driver performs SMM initialization, deploy SMM Entry Vector,
|
||||
# provides CPU specific services in SMM.
|
||||
#
|
||||
# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
|
||||
# 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
|
||||
|
@ -44,6 +44,7 @@
|
|||
SmmProfile.h
|
||||
SmmProfileInternal.h
|
||||
SmramSaveState.c
|
||||
SmmCpuMemoryManagement.c
|
||||
|
||||
[Sources.Ia32]
|
||||
Ia32/Semaphore.c
|
||||
|
@ -133,6 +134,7 @@
|
|||
gEfiGlobalVariableGuid ## SOMETIMES_PRODUCES ## Variable:L"SmmProfileData"
|
||||
gEfiAcpi20TableGuid ## SOMETIMES_CONSUMES ## SystemTable
|
||||
gEfiAcpi10TableGuid ## SOMETIMES_CONSUMES ## SystemTable
|
||||
gEdkiiPiSmmMemoryAttributesTableGuid ## CONSUMES ## SystemTable
|
||||
|
||||
[FeaturePcd]
|
||||
gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmDebug ## CONSUMES
|
||||
|
@ -153,6 +155,7 @@
|
|||
gUefiCpuPkgTokenSpaceGuid.PcdCpuHotPlugDataAddress ## SOMETIMES_PRODUCES
|
||||
gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmCodeAccessCheckEnable ## CONSUMES
|
||||
gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmSyncMode ## CONSUMES
|
||||
gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStaticPageTable ## CONSUMES
|
||||
gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiS3Enable ## CONSUMES
|
||||
|
||||
[Depex]
|
||||
|
|
|
@ -0,0 +1,871 @@
|
|||
/** @file
|
||||
|
||||
Copyright (c) 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.
|
||||
|
||||
**/
|
||||
|
||||
#include "PiSmmCpuDxeSmm.h"
|
||||
|
||||
#define NEXT_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \
|
||||
((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) + (Size)))
|
||||
|
||||
PAGE_ATTRIBUTE_TABLE mPageAttributeTable[] = {
|
||||
{Page4K, SIZE_4KB, PAGING_4K_ADDRESS_MASK_64},
|
||||
{Page2M, SIZE_2MB, PAGING_2M_ADDRESS_MASK_64},
|
||||
{Page1G, SIZE_1GB, PAGING_1G_ADDRESS_MASK_64},
|
||||
};
|
||||
|
||||
/**
|
||||
Return page table base.
|
||||
|
||||
@return page table base.
|
||||
**/
|
||||
UINTN
|
||||
GetPageTableBase (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return (AsmReadCr3 () & PAGING_4K_ADDRESS_MASK_64);
|
||||
}
|
||||
|
||||
/**
|
||||
Return length according to page attributes.
|
||||
|
||||
@param[in] PageAttributes The page attribute of the page entry.
|
||||
|
||||
@return The length of page entry.
|
||||
**/
|
||||
UINTN
|
||||
PageAttributeToLength (
|
||||
IN PAGE_ATTRIBUTE PageAttribute
|
||||
)
|
||||
{
|
||||
UINTN Index;
|
||||
for (Index = 0; Index < sizeof(mPageAttributeTable)/sizeof(mPageAttributeTable[0]); Index++) {
|
||||
if (PageAttribute == mPageAttributeTable[Index].Attribute) {
|
||||
return (UINTN)mPageAttributeTable[Index].Length;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
Return address mask according to page attributes.
|
||||
|
||||
@param[in] PageAttributes The page attribute of the page entry.
|
||||
|
||||
@return The address mask of page entry.
|
||||
**/
|
||||
UINTN
|
||||
PageAttributeToMask (
|
||||
IN PAGE_ATTRIBUTE PageAttribute
|
||||
)
|
||||
{
|
||||
UINTN Index;
|
||||
for (Index = 0; Index < sizeof(mPageAttributeTable)/sizeof(mPageAttributeTable[0]); Index++) {
|
||||
if (PageAttribute == mPageAttributeTable[Index].Attribute) {
|
||||
return (UINTN)mPageAttributeTable[Index].AddressMask;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
Return page table entry to match the address.
|
||||
|
||||
@param[in] Address The address to be checked.
|
||||
@param[out] PageAttributes The page attribute of the page entry.
|
||||
|
||||
@return The page entry.
|
||||
**/
|
||||
VOID *
|
||||
GetPageTableEntry (
|
||||
IN PHYSICAL_ADDRESS Address,
|
||||
OUT PAGE_ATTRIBUTE *PageAttribute
|
||||
)
|
||||
{
|
||||
UINTN Index1;
|
||||
UINTN Index2;
|
||||
UINTN Index3;
|
||||
UINTN Index4;
|
||||
UINT64 *L1PageTable;
|
||||
UINT64 *L2PageTable;
|
||||
UINT64 *L3PageTable;
|
||||
UINT64 *L4PageTable;
|
||||
|
||||
Index4 = ((UINTN)RShiftU64 (Address, 39)) & PAGING_PAE_INDEX_MASK;
|
||||
Index3 = ((UINTN)Address >> 30) & PAGING_PAE_INDEX_MASK;
|
||||
Index2 = ((UINTN)Address >> 21) & PAGING_PAE_INDEX_MASK;
|
||||
Index1 = ((UINTN)Address >> 12) & PAGING_PAE_INDEX_MASK;
|
||||
|
||||
if (sizeof(UINTN) == sizeof(UINT64)) {
|
||||
L4PageTable = (UINT64 *)GetPageTableBase ();
|
||||
if (L4PageTable[Index4] == 0) {
|
||||
*PageAttribute = PageNone;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
L3PageTable = (UINT64 *)(UINTN)(L4PageTable[Index4] & PAGING_4K_ADDRESS_MASK_64);
|
||||
} else {
|
||||
L3PageTable = (UINT64 *)GetPageTableBase ();
|
||||
}
|
||||
if (L3PageTable[Index3] == 0) {
|
||||
*PageAttribute = PageNone;
|
||||
return NULL;
|
||||
}
|
||||
if ((L3PageTable[Index3] & IA32_PG_PS) != 0) {
|
||||
// 1G
|
||||
*PageAttribute = Page1G;
|
||||
return &L3PageTable[Index3];
|
||||
}
|
||||
|
||||
L2PageTable = (UINT64 *)(UINTN)(L3PageTable[Index3] & PAGING_4K_ADDRESS_MASK_64);
|
||||
if (L2PageTable[Index2] == 0) {
|
||||
*PageAttribute = PageNone;
|
||||
return NULL;
|
||||
}
|
||||
if ((L2PageTable[Index2] & IA32_PG_PS) != 0) {
|
||||
// 2M
|
||||
*PageAttribute = Page2M;
|
||||
return &L2PageTable[Index2];
|
||||
}
|
||||
|
||||
// 4k
|
||||
L1PageTable = (UINT64 *)(UINTN)(L2PageTable[Index2] & PAGING_4K_ADDRESS_MASK_64);
|
||||
if ((L1PageTable[Index1] == 0) && (Address != 0)) {
|
||||
*PageAttribute = PageNone;
|
||||
return NULL;
|
||||
}
|
||||
*PageAttribute = Page4K;
|
||||
return &L1PageTable[Index1];
|
||||
}
|
||||
|
||||
/**
|
||||
Return memory attributes of page entry.
|
||||
|
||||
@param[in] PageEntry The page entry.
|
||||
|
||||
@return Memory attributes of page entry.
|
||||
**/
|
||||
UINT64
|
||||
GetAttributesFromPageEntry (
|
||||
IN UINT64 *PageEntry
|
||||
)
|
||||
{
|
||||
UINT64 Attributes;
|
||||
Attributes = 0;
|
||||
if ((*PageEntry & IA32_PG_P) == 0) {
|
||||
Attributes |= EFI_MEMORY_RP;
|
||||
}
|
||||
if ((*PageEntry & IA32_PG_RW) == 0) {
|
||||
Attributes |= EFI_MEMORY_RO;
|
||||
}
|
||||
if ((*PageEntry & IA32_PG_NX) != 0) {
|
||||
Attributes |= EFI_MEMORY_XP;
|
||||
}
|
||||
return Attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
Modify memory attributes of page entry.
|
||||
|
||||
@param[in] PageEntry The page entry.
|
||||
@param[in] Attributes The bit mask of attributes to modify for the memory region.
|
||||
@param[in] IsSet TRUE means to set attributes. FALSE means to clear attributes.
|
||||
@param[out] IsModified TRUE means page table modified. FALSE means page table not modified.
|
||||
**/
|
||||
VOID
|
||||
ConvertPageEntryAttribute (
|
||||
IN UINT64 *PageEntry,
|
||||
IN UINT64 Attributes,
|
||||
IN BOOLEAN IsSet,
|
||||
OUT BOOLEAN *IsModified
|
||||
)
|
||||
{
|
||||
UINT64 CurrentPageEntry;
|
||||
UINT64 NewPageEntry;
|
||||
|
||||
CurrentPageEntry = *PageEntry;
|
||||
NewPageEntry = CurrentPageEntry;
|
||||
if ((Attributes & EFI_MEMORY_RP) != 0) {
|
||||
if (IsSet) {
|
||||
NewPageEntry &= ~(UINT64)IA32_PG_P;
|
||||
} else {
|
||||
NewPageEntry |= IA32_PG_P;
|
||||
}
|
||||
}
|
||||
if ((Attributes & EFI_MEMORY_RO) != 0) {
|
||||
if (IsSet) {
|
||||
NewPageEntry &= ~(UINT64)IA32_PG_RW;
|
||||
} else {
|
||||
NewPageEntry |= IA32_PG_RW;
|
||||
}
|
||||
}
|
||||
if ((Attributes & EFI_MEMORY_XP) != 0) {
|
||||
if (IsSet) {
|
||||
NewPageEntry |= IA32_PG_NX;
|
||||
} else {
|
||||
NewPageEntry &= ~IA32_PG_NX;
|
||||
}
|
||||
}
|
||||
*PageEntry = NewPageEntry;
|
||||
if (CurrentPageEntry != NewPageEntry) {
|
||||
*IsModified = TRUE;
|
||||
DEBUG ((DEBUG_VERBOSE, "ConvertPageEntryAttribute 0x%lx", CurrentPageEntry));
|
||||
DEBUG ((DEBUG_VERBOSE, "->0x%lx\n", NewPageEntry));
|
||||
} else {
|
||||
*IsModified = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
This function returns if there is need to split page entry.
|
||||
|
||||
@param[in] BaseAddress The base address to be checked.
|
||||
@param[in] Length The length to be checked.
|
||||
@param[in] PageEntry The page entry to be checked.
|
||||
@param[in] PageAttribute The page attribute of the page entry.
|
||||
|
||||
@retval SplitAttributes on if there is need to split page entry.
|
||||
**/
|
||||
PAGE_ATTRIBUTE
|
||||
NeedSplitPage (
|
||||
IN PHYSICAL_ADDRESS BaseAddress,
|
||||
IN UINT64 Length,
|
||||
IN UINT64 *PageEntry,
|
||||
IN PAGE_ATTRIBUTE PageAttribute
|
||||
)
|
||||
{
|
||||
UINT64 PageEntryLength;
|
||||
|
||||
PageEntryLength = PageAttributeToLength (PageAttribute);
|
||||
|
||||
if (((BaseAddress & (PageEntryLength - 1)) == 0) && (Length >= PageEntryLength)) {
|
||||
return PageNone;
|
||||
}
|
||||
|
||||
if (((BaseAddress & PAGING_2M_MASK) != 0) || (Length < SIZE_2MB)) {
|
||||
return Page4K;
|
||||
}
|
||||
|
||||
return Page2M;
|
||||
}
|
||||
|
||||
/**
|
||||
This function splits one page entry to small page entries.
|
||||
|
||||
@param[in] PageEntry The page entry to be splitted.
|
||||
@param[in] PageAttribute The page attribute of the page entry.
|
||||
@param[in] SplitAttribute How to split the page entry.
|
||||
|
||||
@retval RETURN_SUCCESS The page entry is splitted.
|
||||
@retval RETURN_UNSUPPORTED The page entry does not support to be splitted.
|
||||
@retval RETURN_OUT_OF_RESOURCES No resource to split page entry.
|
||||
**/
|
||||
RETURN_STATUS
|
||||
SplitPage (
|
||||
IN UINT64 *PageEntry,
|
||||
IN PAGE_ATTRIBUTE PageAttribute,
|
||||
IN PAGE_ATTRIBUTE SplitAttribute
|
||||
)
|
||||
{
|
||||
UINT64 BaseAddress;
|
||||
UINT64 *NewPageEntry;
|
||||
UINTN Index;
|
||||
|
||||
ASSERT (PageAttribute == Page2M || PageAttribute == Page1G);
|
||||
|
||||
if (PageAttribute == Page2M) {
|
||||
//
|
||||
// Split 2M to 4K
|
||||
//
|
||||
ASSERT (SplitAttribute == Page4K);
|
||||
if (SplitAttribute == Page4K) {
|
||||
NewPageEntry = AllocatePageTableMemory (1);
|
||||
DEBUG ((DEBUG_VERBOSE, "Split - 0x%x\n", NewPageEntry));
|
||||
if (NewPageEntry == NULL) {
|
||||
return RETURN_OUT_OF_RESOURCES;
|
||||
}
|
||||
BaseAddress = *PageEntry & PAGING_2M_ADDRESS_MASK_64;
|
||||
for (Index = 0; Index < SIZE_4KB / sizeof(UINT64); Index++) {
|
||||
NewPageEntry[Index] = BaseAddress + SIZE_4KB * Index + ((*PageEntry) & PAGE_PROGATE_BITS);
|
||||
}
|
||||
(*PageEntry) = (UINT64)(UINTN)NewPageEntry + ((*PageEntry) & PAGE_PROGATE_BITS);
|
||||
return RETURN_SUCCESS;
|
||||
} else {
|
||||
return RETURN_UNSUPPORTED;
|
||||
}
|
||||
} else if (PageAttribute == Page1G) {
|
||||
//
|
||||
// Split 1G to 2M
|
||||
// No need support 1G->4K directly, we should use 1G->2M, then 2M->4K to get more compact page table.
|
||||
//
|
||||
ASSERT (SplitAttribute == Page2M || SplitAttribute == Page4K);
|
||||
if ((SplitAttribute == Page2M || SplitAttribute == Page4K)) {
|
||||
NewPageEntry = AllocatePageTableMemory (1);
|
||||
DEBUG ((DEBUG_VERBOSE, "Split - 0x%x\n", NewPageEntry));
|
||||
if (NewPageEntry == NULL) {
|
||||
return RETURN_OUT_OF_RESOURCES;
|
||||
}
|
||||
BaseAddress = *PageEntry & PAGING_1G_ADDRESS_MASK_64;
|
||||
for (Index = 0; Index < SIZE_4KB / sizeof(UINT64); Index++) {
|
||||
NewPageEntry[Index] = BaseAddress + SIZE_2MB * Index + IA32_PG_PS + ((*PageEntry) & PAGE_PROGATE_BITS);
|
||||
}
|
||||
(*PageEntry) = (UINT64)(UINTN)NewPageEntry + ((*PageEntry) & PAGE_PROGATE_BITS);
|
||||
return RETURN_SUCCESS;
|
||||
} else {
|
||||
return RETURN_UNSUPPORTED;
|
||||
}
|
||||
} else {
|
||||
return RETURN_UNSUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
This function modifies the page attributes for the memory region specified by BaseAddress and
|
||||
Length from their current attributes to the attributes specified by Attributes.
|
||||
|
||||
Caller should make sure BaseAddress and Length is at page boundary.
|
||||
|
||||
@param[in] BaseAddress The physical address that is the start address of a memory region.
|
||||
@param[in] Length The size in bytes of the memory region.
|
||||
@param[in] Attributes The bit mask of attributes to modify for the memory region.
|
||||
@param[in] IsSet TRUE means to set attributes. FALSE means to clear attributes.
|
||||
@param[out] IsSplitted TRUE means page table splitted. FALSE means page table not splitted.
|
||||
@param[out] IsModified TRUE means page table modified. FALSE means page table not modified.
|
||||
|
||||
@retval RETURN_SUCCESS The attributes were modified for the memory region.
|
||||
@retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by
|
||||
BaseAddress and Length cannot be modified.
|
||||
@retval RETURN_INVALID_PARAMETER Length is zero.
|
||||
Attributes specified an illegal combination of attributes that
|
||||
cannot be set together.
|
||||
@retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
|
||||
the memory resource range.
|
||||
@retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the memory
|
||||
resource range specified by BaseAddress and Length.
|
||||
The bit mask of attributes is not support for the memory resource
|
||||
range specified by BaseAddress and Length.
|
||||
**/
|
||||
RETURN_STATUS
|
||||
EFIAPI
|
||||
ConvertMemoryPageAttributes (
|
||||
IN PHYSICAL_ADDRESS BaseAddress,
|
||||
IN UINT64 Length,
|
||||
IN UINT64 Attributes,
|
||||
IN BOOLEAN IsSet,
|
||||
OUT BOOLEAN *IsSplitted, OPTIONAL
|
||||
OUT BOOLEAN *IsModified OPTIONAL
|
||||
)
|
||||
{
|
||||
UINT64 *PageEntry;
|
||||
PAGE_ATTRIBUTE PageAttribute;
|
||||
UINTN PageEntryLength;
|
||||
PAGE_ATTRIBUTE SplitAttribute;
|
||||
RETURN_STATUS Status;
|
||||
BOOLEAN IsEntryModified;
|
||||
|
||||
ASSERT (Attributes != 0);
|
||||
ASSERT ((Attributes & ~(EFI_MEMORY_RP | EFI_MEMORY_RO | EFI_MEMORY_XP)) == 0);
|
||||
|
||||
ASSERT ((BaseAddress & (SIZE_4KB - 1)) == 0);
|
||||
ASSERT ((Length & (SIZE_4KB - 1)) == 0);
|
||||
|
||||
if (Length == 0) {
|
||||
return RETURN_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
// DEBUG ((DEBUG_ERROR, "ConvertMemoryPageAttributes(%x) - %016lx, %016lx, %02lx\n", IsSet, BaseAddress, Length, Attributes));
|
||||
|
||||
if (IsSplitted != NULL) {
|
||||
*IsSplitted = FALSE;
|
||||
}
|
||||
if (IsModified != NULL) {
|
||||
*IsModified = FALSE;
|
||||
}
|
||||
|
||||
//
|
||||
// Below logic is to check 2M/4K page to make sure we donot waist memory.
|
||||
//
|
||||
while (Length != 0) {
|
||||
PageEntry = GetPageTableEntry (BaseAddress, &PageAttribute);
|
||||
if (PageEntry == NULL) {
|
||||
return RETURN_UNSUPPORTED;
|
||||
}
|
||||
PageEntryLength = PageAttributeToLength (PageAttribute);
|
||||
SplitAttribute = NeedSplitPage (BaseAddress, Length, PageEntry, PageAttribute);
|
||||
if (SplitAttribute == PageNone) {
|
||||
ConvertPageEntryAttribute (PageEntry, Attributes, IsSet, &IsEntryModified);
|
||||
if (IsEntryModified) {
|
||||
if (IsModified != NULL) {
|
||||
*IsModified = TRUE;
|
||||
}
|
||||
}
|
||||
//
|
||||
// Convert success, move to next
|
||||
//
|
||||
BaseAddress += PageEntryLength;
|
||||
Length -= PageEntryLength;
|
||||
} else {
|
||||
Status = SplitPage (PageEntry, PageAttribute, SplitAttribute);
|
||||
if (RETURN_ERROR (Status)) {
|
||||
return RETURN_UNSUPPORTED;
|
||||
}
|
||||
if (IsSplitted != NULL) {
|
||||
*IsSplitted = TRUE;
|
||||
}
|
||||
if (IsModified != NULL) {
|
||||
*IsModified = TRUE;
|
||||
}
|
||||
//
|
||||
// Just split current page
|
||||
// Convert success in next around
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
return RETURN_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
FlushTlb on current processor.
|
||||
|
||||
@param[in,out] Buffer Pointer to private data buffer.
|
||||
**/
|
||||
VOID
|
||||
EFIAPI
|
||||
FlushTlbOnCurrentProcessor (
|
||||
IN OUT VOID *Buffer
|
||||
)
|
||||
{
|
||||
CpuFlushTlb ();
|
||||
}
|
||||
|
||||
/**
|
||||
FlushTlb for all processors.
|
||||
**/
|
||||
VOID
|
||||
FlushTlbForAll (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
UINTN Index;
|
||||
|
||||
FlushTlbOnCurrentProcessor (NULL);
|
||||
|
||||
for (Index = 0; Index < gSmst->NumberOfCpus; Index++) {
|
||||
if (Index != gSmst->CurrentlyExecutingCpu) {
|
||||
// Force to start up AP in blocking mode,
|
||||
SmmBlockingStartupThisAp (FlushTlbOnCurrentProcessor, Index, NULL);
|
||||
// Do not check return status, because AP might not be present in some corner cases.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
This function sets the attributes for the memory region specified by BaseAddress and
|
||||
Length from their current attributes to the attributes specified by Attributes.
|
||||
|
||||
@param[in] BaseAddress The physical address that is the start address of a memory region.
|
||||
@param[in] Length The size in bytes of the memory region.
|
||||
@param[in] Attributes The bit mask of attributes to set for the memory region.
|
||||
@param[out] IsSplitted TRUE means page table splitted. FALSE means page table not splitted.
|
||||
|
||||
@retval EFI_SUCCESS The attributes were set for the memory region.
|
||||
@retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
|
||||
BaseAddress and Length cannot be modified.
|
||||
@retval EFI_INVALID_PARAMETER Length is zero.
|
||||
Attributes specified an illegal combination of attributes that
|
||||
cannot be set together.
|
||||
@retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
|
||||
the memory resource range.
|
||||
@retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
|
||||
resource range specified by BaseAddress and Length.
|
||||
The bit mask of attributes is not support for the memory resource
|
||||
range specified by BaseAddress and Length.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
SmmSetMemoryAttributesEx (
|
||||
IN EFI_PHYSICAL_ADDRESS BaseAddress,
|
||||
IN UINT64 Length,
|
||||
IN UINT64 Attributes,
|
||||
OUT BOOLEAN *IsSplitted OPTIONAL
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
BOOLEAN IsModified;
|
||||
|
||||
Status = ConvertMemoryPageAttributes (BaseAddress, Length, Attributes, TRUE, IsSplitted, &IsModified);
|
||||
if (!EFI_ERROR(Status)) {
|
||||
if (IsModified) {
|
||||
//
|
||||
// Flush TLB as last step
|
||||
//
|
||||
FlushTlbForAll();
|
||||
}
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
This function clears the attributes for the memory region specified by BaseAddress and
|
||||
Length from their current attributes to the attributes specified by Attributes.
|
||||
|
||||
@param[in] BaseAddress The physical address that is the start address of a memory region.
|
||||
@param[in] Length The size in bytes of the memory region.
|
||||
@param[in] Attributes The bit mask of attributes to clear for the memory region.
|
||||
@param[out] IsSplitted TRUE means page table splitted. FALSE means page table not splitted.
|
||||
|
||||
@retval EFI_SUCCESS The attributes were cleared for the memory region.
|
||||
@retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
|
||||
BaseAddress and Length cannot be modified.
|
||||
@retval EFI_INVALID_PARAMETER Length is zero.
|
||||
Attributes specified an illegal combination of attributes that
|
||||
cannot be set together.
|
||||
@retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
|
||||
the memory resource range.
|
||||
@retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
|
||||
resource range specified by BaseAddress and Length.
|
||||
The bit mask of attributes is not support for the memory resource
|
||||
range specified by BaseAddress and Length.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
SmmClearMemoryAttributesEx (
|
||||
IN EFI_PHYSICAL_ADDRESS BaseAddress,
|
||||
IN UINT64 Length,
|
||||
IN UINT64 Attributes,
|
||||
OUT BOOLEAN *IsSplitted OPTIONAL
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
BOOLEAN IsModified;
|
||||
|
||||
Status = ConvertMemoryPageAttributes (BaseAddress, Length, Attributes, FALSE, IsSplitted, &IsModified);
|
||||
if (!EFI_ERROR(Status)) {
|
||||
if (IsModified) {
|
||||
//
|
||||
// Flush TLB as last step
|
||||
//
|
||||
FlushTlbForAll();
|
||||
}
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
This function sets the attributes for the memory region specified by BaseAddress and
|
||||
Length from their current attributes to the attributes specified by Attributes.
|
||||
|
||||
@param[in] BaseAddress The physical address that is the start address of a memory region.
|
||||
@param[in] Length The size in bytes of the memory region.
|
||||
@param[in] Attributes The bit mask of attributes to set for the memory region.
|
||||
|
||||
@retval EFI_SUCCESS The attributes were set for the memory region.
|
||||
@retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
|
||||
BaseAddress and Length cannot be modified.
|
||||
@retval EFI_INVALID_PARAMETER Length is zero.
|
||||
Attributes specified an illegal combination of attributes that
|
||||
cannot be set together.
|
||||
@retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
|
||||
the memory resource range.
|
||||
@retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
|
||||
resource range specified by BaseAddress and Length.
|
||||
The bit mask of attributes is not support for the memory resource
|
||||
range specified by BaseAddress and Length.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
SmmSetMemoryAttributes (
|
||||
IN EFI_PHYSICAL_ADDRESS BaseAddress,
|
||||
IN UINT64 Length,
|
||||
IN UINT64 Attributes
|
||||
)
|
||||
{
|
||||
return SmmSetMemoryAttributesEx (BaseAddress, Length, Attributes, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
This function clears the attributes for the memory region specified by BaseAddress and
|
||||
Length from their current attributes to the attributes specified by Attributes.
|
||||
|
||||
@param[in] BaseAddress The physical address that is the start address of a memory region.
|
||||
@param[in] Length The size in bytes of the memory region.
|
||||
@param[in] Attributes The bit mask of attributes to clear for the memory region.
|
||||
|
||||
@retval EFI_SUCCESS The attributes were cleared for the memory region.
|
||||
@retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
|
||||
BaseAddress and Length cannot be modified.
|
||||
@retval EFI_INVALID_PARAMETER Length is zero.
|
||||
Attributes specified an illegal combination of attributes that
|
||||
cannot be set together.
|
||||
@retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
|
||||
the memory resource range.
|
||||
@retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
|
||||
resource range specified by BaseAddress and Length.
|
||||
The bit mask of attributes is not support for the memory resource
|
||||
range specified by BaseAddress and Length.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
SmmClearMemoryAttributes (
|
||||
IN EFI_PHYSICAL_ADDRESS BaseAddress,
|
||||
IN UINT64 Length,
|
||||
IN UINT64 Attributes
|
||||
)
|
||||
{
|
||||
return SmmClearMemoryAttributesEx (BaseAddress, Length, Attributes, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Retrieves a pointer to the system configuration table from the SMM System Table
|
||||
based on a specified GUID.
|
||||
|
||||
@param[in] TableGuid The pointer to table's GUID type.
|
||||
@param[out] Table The pointer to the table associated with TableGuid in the EFI System Table.
|
||||
|
||||
@retval EFI_SUCCESS A configuration table matching TableGuid was found.
|
||||
@retval EFI_NOT_FOUND A configuration table matching TableGuid could not be found.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
SmmGetSystemConfigurationTable (
|
||||
IN EFI_GUID *TableGuid,
|
||||
OUT VOID **Table
|
||||
)
|
||||
{
|
||||
UINTN Index;
|
||||
|
||||
ASSERT (TableGuid != NULL);
|
||||
ASSERT (Table != NULL);
|
||||
|
||||
*Table = NULL;
|
||||
for (Index = 0; Index < gSmst->NumberOfTableEntries; Index++) {
|
||||
if (CompareGuid (TableGuid, &(gSmst->SmmConfigurationTable[Index].VendorGuid))) {
|
||||
*Table = gSmst->SmmConfigurationTable[Index].VendorTable;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
/**
|
||||
This function sets SMM save state buffer to be RW and XP.
|
||||
**/
|
||||
VOID
|
||||
PatchSmmSaveStateMap (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
UINTN Index;
|
||||
UINTN TileCodeSize;
|
||||
UINTN TileDataSize;
|
||||
UINTN TileSize;
|
||||
|
||||
TileCodeSize = GetSmiHandlerSize ();
|
||||
TileCodeSize = ALIGN_VALUE(TileCodeSize, SIZE_4KB);
|
||||
TileDataSize = sizeof (SMRAM_SAVE_STATE_MAP) + sizeof (PROCESSOR_SMM_DESCRIPTOR);
|
||||
TileDataSize = ALIGN_VALUE(TileDataSize, SIZE_4KB);
|
||||
TileSize = TileDataSize + TileCodeSize - 1;
|
||||
TileSize = 2 * GetPowerOfTwo32 ((UINT32)TileSize);
|
||||
|
||||
DEBUG ((DEBUG_INFO, "PatchSmmSaveStateMap:\n"));
|
||||
for (Index = 0; Index < mMaxNumberOfCpus - 1; Index++) {
|
||||
//
|
||||
// Code
|
||||
//
|
||||
SmmSetMemoryAttributes (
|
||||
mCpuHotPlugData.SmBase[Index] + SMM_HANDLER_OFFSET,
|
||||
TileCodeSize,
|
||||
EFI_MEMORY_RO
|
||||
);
|
||||
SmmClearMemoryAttributes (
|
||||
mCpuHotPlugData.SmBase[Index] + SMM_HANDLER_OFFSET,
|
||||
TileCodeSize,
|
||||
EFI_MEMORY_XP
|
||||
);
|
||||
|
||||
//
|
||||
// Data
|
||||
//
|
||||
SmmClearMemoryAttributes (
|
||||
mCpuHotPlugData.SmBase[Index] + SMM_HANDLER_OFFSET + TileCodeSize,
|
||||
TileSize - TileCodeSize,
|
||||
EFI_MEMORY_RO
|
||||
);
|
||||
SmmSetMemoryAttributes (
|
||||
mCpuHotPlugData.SmBase[Index] + SMM_HANDLER_OFFSET + TileCodeSize,
|
||||
TileSize - TileCodeSize,
|
||||
EFI_MEMORY_XP
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
// Code
|
||||
//
|
||||
SmmSetMemoryAttributes (
|
||||
mCpuHotPlugData.SmBase[mMaxNumberOfCpus - 1] + SMM_HANDLER_OFFSET,
|
||||
TileCodeSize,
|
||||
EFI_MEMORY_RO
|
||||
);
|
||||
SmmClearMemoryAttributes (
|
||||
mCpuHotPlugData.SmBase[mMaxNumberOfCpus - 1] + SMM_HANDLER_OFFSET,
|
||||
TileCodeSize,
|
||||
EFI_MEMORY_XP
|
||||
);
|
||||
|
||||
//
|
||||
// Data
|
||||
//
|
||||
SmmClearMemoryAttributes (
|
||||
mCpuHotPlugData.SmBase[mMaxNumberOfCpus - 1] + SMM_HANDLER_OFFSET + TileCodeSize,
|
||||
SIZE_32KB - TileCodeSize,
|
||||
EFI_MEMORY_RO
|
||||
);
|
||||
SmmSetMemoryAttributes (
|
||||
mCpuHotPlugData.SmBase[mMaxNumberOfCpus - 1] + SMM_HANDLER_OFFSET + TileCodeSize,
|
||||
SIZE_32KB - TileCodeSize,
|
||||
EFI_MEMORY_XP
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
This function sets GDT/IDT buffer to be RO and XP.
|
||||
**/
|
||||
VOID
|
||||
PatchGdtIdtMap (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
EFI_PHYSICAL_ADDRESS BaseAddress;
|
||||
UINTN Size;
|
||||
|
||||
//
|
||||
// GDT
|
||||
//
|
||||
DEBUG ((DEBUG_INFO, "PatchGdtIdtMap - GDT:\n"));
|
||||
|
||||
BaseAddress = mGdtBuffer;
|
||||
Size = ALIGN_VALUE(mGdtBufferSize, SIZE_4KB);
|
||||
SmmSetMemoryAttributes (
|
||||
BaseAddress,
|
||||
Size,
|
||||
EFI_MEMORY_RO
|
||||
);
|
||||
SmmSetMemoryAttributes (
|
||||
BaseAddress,
|
||||
Size,
|
||||
EFI_MEMORY_XP
|
||||
);
|
||||
|
||||
//
|
||||
// IDT
|
||||
//
|
||||
DEBUG ((DEBUG_INFO, "PatchGdtIdtMap - IDT:\n"));
|
||||
|
||||
BaseAddress = gcSmiIdtr.Base;
|
||||
Size = ALIGN_VALUE(gcSmiIdtr.Limit + 1, SIZE_4KB);
|
||||
SmmSetMemoryAttributes (
|
||||
BaseAddress,
|
||||
Size,
|
||||
EFI_MEMORY_RO
|
||||
);
|
||||
SmmSetMemoryAttributes (
|
||||
BaseAddress,
|
||||
Size,
|
||||
EFI_MEMORY_XP
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
This function sets memory attribute according to MemoryAttributesTable.
|
||||
**/
|
||||
VOID
|
||||
SetMemMapAttributes (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
EFI_MEMORY_DESCRIPTOR *MemoryMap;
|
||||
EFI_MEMORY_DESCRIPTOR *MemoryMapStart;
|
||||
UINTN MemoryMapEntryCount;
|
||||
UINTN DescriptorSize;
|
||||
UINTN Index;
|
||||
EDKII_PI_SMM_MEMORY_ATTRIBUTES_TABLE *MemoryAttributesTable;
|
||||
|
||||
SmmGetSystemConfigurationTable (&gEdkiiPiSmmMemoryAttributesTableGuid, (VOID **)&MemoryAttributesTable);
|
||||
if (MemoryAttributesTable == NULL) {
|
||||
DEBUG ((DEBUG_INFO, "MemoryAttributesTable - NULL\n"));
|
||||
return ;
|
||||
}
|
||||
|
||||
DEBUG ((DEBUG_INFO, "MemoryAttributesTable:\n"));
|
||||
DEBUG ((DEBUG_INFO, " Version - 0x%08x\n", MemoryAttributesTable->Version));
|
||||
DEBUG ((DEBUG_INFO, " NumberOfEntries - 0x%08x\n", MemoryAttributesTable->NumberOfEntries));
|
||||
DEBUG ((DEBUG_INFO, " DescriptorSize - 0x%08x\n", MemoryAttributesTable->DescriptorSize));
|
||||
|
||||
MemoryMapEntryCount = MemoryAttributesTable->NumberOfEntries;
|
||||
DescriptorSize = MemoryAttributesTable->DescriptorSize;
|
||||
MemoryMapStart = (EFI_MEMORY_DESCRIPTOR *)(MemoryAttributesTable + 1);
|
||||
MemoryMap = MemoryMapStart;
|
||||
for (Index = 0; Index < MemoryMapEntryCount; Index++) {
|
||||
DEBUG ((DEBUG_INFO, "Entry (0x%x)\n", MemoryMap));
|
||||
DEBUG ((DEBUG_INFO, " Type - 0x%x\n", MemoryMap->Type));
|
||||
DEBUG ((DEBUG_INFO, " PhysicalStart - 0x%016lx\n", MemoryMap->PhysicalStart));
|
||||
DEBUG ((DEBUG_INFO, " VirtualStart - 0x%016lx\n", MemoryMap->VirtualStart));
|
||||
DEBUG ((DEBUG_INFO, " NumberOfPages - 0x%016lx\n", MemoryMap->NumberOfPages));
|
||||
DEBUG ((DEBUG_INFO, " Attribute - 0x%016lx\n", MemoryMap->Attribute));
|
||||
MemoryMap = NEXT_MEMORY_DESCRIPTOR(MemoryMap, DescriptorSize);
|
||||
}
|
||||
|
||||
MemoryMap = MemoryMapStart;
|
||||
for (Index = 0; Index < MemoryMapEntryCount; Index++) {
|
||||
DEBUG ((DEBUG_VERBOSE, "SetAttribute: Memory Entry - 0x%lx, 0x%x\n", MemoryMap->PhysicalStart, MemoryMap->NumberOfPages));
|
||||
switch (MemoryMap->Type) {
|
||||
case EfiRuntimeServicesCode:
|
||||
SmmSetMemoryAttributes (
|
||||
MemoryMap->PhysicalStart,
|
||||
EFI_PAGES_TO_SIZE((UINTN)MemoryMap->NumberOfPages),
|
||||
EFI_MEMORY_RO
|
||||
);
|
||||
break;
|
||||
case EfiRuntimeServicesData:
|
||||
SmmSetMemoryAttributes (
|
||||
MemoryMap->PhysicalStart,
|
||||
EFI_PAGES_TO_SIZE((UINTN)MemoryMap->NumberOfPages),
|
||||
EFI_MEMORY_XP
|
||||
);
|
||||
break;
|
||||
default:
|
||||
SmmSetMemoryAttributes (
|
||||
MemoryMap->PhysicalStart,
|
||||
EFI_PAGES_TO_SIZE((UINTN)MemoryMap->NumberOfPages),
|
||||
EFI_MEMORY_XP
|
||||
);
|
||||
break;
|
||||
}
|
||||
MemoryMap = NEXT_MEMORY_DESCRIPTOR(MemoryMap, DescriptorSize);
|
||||
}
|
||||
|
||||
PatchSmmSaveStateMap ();
|
||||
PatchGdtIdtMap ();
|
||||
|
||||
return ;
|
||||
}
|
|
@ -29,11 +29,6 @@ UINTN mSmmProfileSize;
|
|||
//
|
||||
UINTN mMsrDsAreaSize = SMM_PROFILE_DTS_SIZE;
|
||||
|
||||
//
|
||||
// The flag indicates if execute-disable is supported by processor.
|
||||
//
|
||||
BOOLEAN mXdSupported = TRUE;
|
||||
|
||||
//
|
||||
// The flag indicates if execute-disable is enabled on processor.
|
||||
//
|
||||
|
@ -529,6 +524,12 @@ InitPaging (
|
|||
//
|
||||
continue;
|
||||
}
|
||||
if ((*Pde & IA32_PG_PS) != 0) {
|
||||
//
|
||||
// This is 1G entry, skip it
|
||||
//
|
||||
continue;
|
||||
}
|
||||
Pte = (UINT64 *)(UINTN)(*Pde & PHYSICAL_ADDRESS_MASK);
|
||||
if (Pte == 0) {
|
||||
continue;
|
||||
|
@ -587,6 +588,15 @@ InitPaging (
|
|||
//
|
||||
continue;
|
||||
}
|
||||
if ((*Pde & IA32_PG_PS) != 0) {
|
||||
//
|
||||
// This is 1G entry, set NX bit and skip it
|
||||
//
|
||||
if (mXdSupported) {
|
||||
*Pde = *Pde | IA32_PG_NX;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
Pte = (UINT64 *)(UINTN)(*Pde & PHYSICAL_ADDRESS_MASK);
|
||||
if (Pte == 0) {
|
||||
continue;
|
||||
|
@ -975,25 +985,6 @@ CheckFeatureSupported (
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Enable XD feature.
|
||||
|
||||
**/
|
||||
VOID
|
||||
ActivateXd (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
UINT64 MsrRegisters;
|
||||
|
||||
MsrRegisters = AsmReadMsr64 (MSR_EFER);
|
||||
if ((MsrRegisters & MSR_EFER_XD) != 0) {
|
||||
return ;
|
||||
}
|
||||
MsrRegisters |= MSR_EFER_XD;
|
||||
AsmWriteMsr64 (MSR_EFER, MsrRegisters);
|
||||
}
|
||||
|
||||
/**
|
||||
Enable single step.
|
||||
|
||||
|
|
|
@ -96,15 +96,6 @@ CheckFeatureSupported (
|
|||
VOID
|
||||
);
|
||||
|
||||
/**
|
||||
Enable XD feature.
|
||||
|
||||
**/
|
||||
VOID
|
||||
ActivateXd (
|
||||
VOID
|
||||
);
|
||||
|
||||
/**
|
||||
Update page table according to protected memory ranges and the 4KB-page mapped memory ranges.
|
||||
|
||||
|
@ -114,7 +105,13 @@ InitPaging (
|
|||
VOID
|
||||
);
|
||||
|
||||
//
|
||||
// The flag indicates if execute-disable is supported by processor.
|
||||
//
|
||||
extern BOOLEAN mXdSupported;
|
||||
//
|
||||
// The flag indicates if execute-disable is enabled on processor.
|
||||
//
|
||||
extern BOOLEAN mXdEnabled;
|
||||
|
||||
#endif // _SMM_PROFILE_H_
|
||||
|
|
|
@ -18,6 +18,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|||
#define ACC_MAX_BIT BIT3
|
||||
LIST_ENTRY mPagePool = INITIALIZE_LIST_HEAD_VARIABLE (mPagePool);
|
||||
BOOLEAN m1GPageTableSupport = FALSE;
|
||||
UINT8 mPhysicalAddressBits;
|
||||
BOOLEAN mCpuSmmStaticPageTable;
|
||||
|
||||
/**
|
||||
Check if 1-GByte pages is supported by processor or not.
|
||||
|
@ -85,6 +87,146 @@ GetSubEntriesNum (
|
|||
return BitFieldRead64 (*Entry, 52, 60);
|
||||
}
|
||||
|
||||
/**
|
||||
Calculate the maximum support address.
|
||||
|
||||
@return the maximum support address.
|
||||
**/
|
||||
UINT8
|
||||
CalculateMaximumSupportAddress (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
UINT32 RegEax;
|
||||
UINT8 PhysicalAddressBits;
|
||||
VOID *Hob;
|
||||
|
||||
//
|
||||
// Get physical address bits supported.
|
||||
//
|
||||
Hob = GetFirstHob (EFI_HOB_TYPE_CPU);
|
||||
if (Hob != NULL) {
|
||||
PhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace;
|
||||
} else {
|
||||
AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
|
||||
if (RegEax >= 0x80000008) {
|
||||
AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
|
||||
PhysicalAddressBits = (UINT8) RegEax;
|
||||
} else {
|
||||
PhysicalAddressBits = 36;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.
|
||||
//
|
||||
ASSERT (PhysicalAddressBits <= 52);
|
||||
if (PhysicalAddressBits > 48) {
|
||||
PhysicalAddressBits = 48;
|
||||
}
|
||||
return PhysicalAddressBits;
|
||||
}
|
||||
|
||||
/**
|
||||
Set static page table.
|
||||
|
||||
@param[in] PageTable Address of page table.
|
||||
**/
|
||||
VOID
|
||||
SetStaticPageTable (
|
||||
IN UINTN PageTable
|
||||
)
|
||||
{
|
||||
UINT64 PageAddress;
|
||||
UINTN NumberOfPml4EntriesNeeded;
|
||||
UINTN NumberOfPdpEntriesNeeded;
|
||||
UINTN IndexOfPml4Entries;
|
||||
UINTN IndexOfPdpEntries;
|
||||
UINTN IndexOfPageDirectoryEntries;
|
||||
UINT64 *PageMapLevel4Entry;
|
||||
UINT64 *PageMap;
|
||||
UINT64 *PageDirectoryPointerEntry;
|
||||
UINT64 *PageDirectory1GEntry;
|
||||
UINT64 *PageDirectoryEntry;
|
||||
|
||||
if (mPhysicalAddressBits <= 39 ) {
|
||||
NumberOfPml4EntriesNeeded = 1;
|
||||
NumberOfPdpEntriesNeeded = (UINT32)LShiftU64 (1, (mPhysicalAddressBits - 30));
|
||||
} else {
|
||||
NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (mPhysicalAddressBits - 39));
|
||||
NumberOfPdpEntriesNeeded = 512;
|
||||
}
|
||||
|
||||
//
|
||||
// By architecture only one PageMapLevel4 exists - so lets allocate storage for it.
|
||||
//
|
||||
PageMap = (VOID *) PageTable;
|
||||
|
||||
PageMapLevel4Entry = PageMap;
|
||||
PageAddress = 0;
|
||||
for (IndexOfPml4Entries = 0; IndexOfPml4Entries < NumberOfPml4EntriesNeeded; IndexOfPml4Entries++, PageMapLevel4Entry++) {
|
||||
//
|
||||
// Each PML4 entry points to a page of Page Directory Pointer entries.
|
||||
//
|
||||
PageDirectoryPointerEntry = (UINT64 *) ((*PageMapLevel4Entry) & gPhyMask);
|
||||
if (PageDirectoryPointerEntry == NULL) {
|
||||
PageDirectoryPointerEntry = AllocatePageTableMemory (1);
|
||||
ASSERT(PageDirectoryPointerEntry != NULL);
|
||||
ZeroMem (PageDirectoryPointerEntry, EFI_PAGES_TO_SIZE(1));
|
||||
|
||||
*PageMapLevel4Entry = ((UINTN)PageDirectoryPointerEntry & gPhyMask) | PAGE_ATTRIBUTE_BITS;
|
||||
}
|
||||
|
||||
if (m1GPageTableSupport) {
|
||||
PageDirectory1GEntry = PageDirectoryPointerEntry;
|
||||
for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectory1GEntry++, PageAddress += SIZE_1GB) {
|
||||
if (IndexOfPml4Entries == 0 && IndexOfPageDirectoryEntries < 4) {
|
||||
//
|
||||
// Skip the < 4G entries
|
||||
//
|
||||
continue;
|
||||
}
|
||||
//
|
||||
// Fill in the Page Directory entries
|
||||
//
|
||||
*PageDirectory1GEntry = (PageAddress & gPhyMask) | IA32_PG_PS | PAGE_ATTRIBUTE_BITS;
|
||||
}
|
||||
} else {
|
||||
PageAddress = BASE_4GB;
|
||||
for (IndexOfPdpEntries = 0; IndexOfPdpEntries < NumberOfPdpEntriesNeeded; IndexOfPdpEntries++, PageDirectoryPointerEntry++) {
|
||||
if (IndexOfPml4Entries == 0 && IndexOfPdpEntries < 4) {
|
||||
//
|
||||
// Skip the < 4G entries
|
||||
//
|
||||
continue;
|
||||
}
|
||||
//
|
||||
// Each Directory Pointer entries points to a page of Page Directory entires.
|
||||
// So allocate space for them and fill them in in the IndexOfPageDirectoryEntries loop.
|
||||
//
|
||||
PageDirectoryEntry = (UINT64 *) ((*PageDirectoryPointerEntry) & gPhyMask);
|
||||
if (PageDirectoryEntry == NULL) {
|
||||
PageDirectoryEntry = AllocatePageTableMemory (1);
|
||||
ASSERT(PageDirectoryEntry != NULL);
|
||||
ZeroMem (PageDirectoryEntry, EFI_PAGES_TO_SIZE(1));
|
||||
|
||||
//
|
||||
// Fill in a Page Directory Pointer Entries
|
||||
//
|
||||
*PageDirectoryPointerEntry = (UINT64)(UINTN)PageDirectoryEntry | PAGE_ATTRIBUTE_BITS;
|
||||
}
|
||||
|
||||
for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PageAddress += SIZE_2MB) {
|
||||
//
|
||||
// Fill in the Page Directory entries
|
||||
//
|
||||
*PageDirectoryEntry = (UINT64)PageAddress | IA32_PG_PS | PAGE_ATTRIBUTE_BITS;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Create PageTable for SMM use.
|
||||
|
||||
|
@ -108,11 +250,17 @@ SmmInitPageTable (
|
|||
//
|
||||
InitializeSpinLock (mPFLock);
|
||||
|
||||
mCpuSmmStaticPageTable = PcdGetBool (PcdCpuSmmStaticPageTable);
|
||||
m1GPageTableSupport = Is1GPageSupport ();
|
||||
DEBUG ((DEBUG_INFO, "1GPageTableSupport - 0x%x\n", m1GPageTableSupport));
|
||||
DEBUG ((DEBUG_INFO, "PcdCpuSmmStaticPageTable - 0x%x\n", mCpuSmmStaticPageTable));
|
||||
|
||||
mPhysicalAddressBits = CalculateMaximumSupportAddress ();
|
||||
DEBUG ((DEBUG_INFO, "PhysicalAddressBits - 0x%x\n", mPhysicalAddressBits));
|
||||
//
|
||||
// Generate PAE page table for the first 4GB memory space
|
||||
//
|
||||
Pages = Gen4GPageTable (PAGE_TABLE_PAGES + 1, FALSE);
|
||||
Pages = Gen4GPageTable (FALSE);
|
||||
|
||||
//
|
||||
// Set IA32_PG_PMNT bit to mask this entry
|
||||
|
@ -125,22 +273,29 @@ SmmInitPageTable (
|
|||
//
|
||||
// Fill Page-Table-Level4 (PML4) entry
|
||||
//
|
||||
PTEntry = (UINT64*)(UINTN)(Pages - EFI_PAGES_TO_SIZE (PAGE_TABLE_PAGES + 1));
|
||||
*PTEntry = Pages + PAGE_ATTRIBUTE_BITS;
|
||||
PTEntry = (UINT64*)AllocatePageTableMemory (1);
|
||||
ASSERT (PTEntry != NULL);
|
||||
*PTEntry = Pages | PAGE_ATTRIBUTE_BITS;
|
||||
ZeroMem (PTEntry + 1, EFI_PAGE_SIZE - sizeof (*PTEntry));
|
||||
|
||||
//
|
||||
// Set sub-entries number
|
||||
//
|
||||
SetSubEntriesNum (PTEntry, 3);
|
||||
|
||||
if (mCpuSmmStaticPageTable) {
|
||||
SetStaticPageTable ((UINTN)PTEntry);
|
||||
} else {
|
||||
//
|
||||
// Add remaining pages to page pool
|
||||
// Add pages to page pool
|
||||
//
|
||||
FreePage = (LIST_ENTRY*)(PTEntry + EFI_PAGE_SIZE / sizeof (*PTEntry));
|
||||
while ((UINTN)FreePage < Pages) {
|
||||
FreePage = (LIST_ENTRY*)AllocatePageTableMemory (PAGE_TABLE_PAGES);
|
||||
ASSERT (FreePage != NULL);
|
||||
for (Index = 0; Index < PAGE_TABLE_PAGES; Index++) {
|
||||
InsertTailList (&mPagePool, FreePage);
|
||||
FreePage += EFI_PAGE_SIZE / sizeof (*FreePage);
|
||||
}
|
||||
}
|
||||
|
||||
if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {
|
||||
//
|
||||
|
@ -561,7 +716,7 @@ SmiDefaultPFHandler (
|
|||
break;
|
||||
case SmmPageSize1G:
|
||||
if (!m1GPageTableSupport) {
|
||||
DEBUG ((EFI_D_ERROR, "1-GByte pages is not supported!"));
|
||||
DEBUG ((DEBUG_ERROR, "1-GByte pages is not supported!"));
|
||||
ASSERT (FALSE);
|
||||
}
|
||||
//
|
||||
|
@ -612,8 +767,8 @@ SmiDefaultPFHandler (
|
|||
// Check if the entry has already existed, this issue may occur when the different
|
||||
// size page entries created under the same entry
|
||||
//
|
||||
DEBUG ((EFI_D_ERROR, "PageTable = %lx, PTIndex = %x, PageTable[PTIndex] = %lx\n", PageTable, PTIndex, PageTable[PTIndex]));
|
||||
DEBUG ((EFI_D_ERROR, "New page table overlapped with old page table!\n"));
|
||||
DEBUG ((DEBUG_ERROR, "PageTable = %lx, PTIndex = %x, PageTable[PTIndex] = %lx\n", PageTable, PTIndex, PageTable[PTIndex]));
|
||||
DEBUG ((DEBUG_ERROR, "New page table overlapped with old page table!\n"));
|
||||
ASSERT (FALSE);
|
||||
}
|
||||
//
|
||||
|
@ -654,13 +809,18 @@ SmiPFHandler (
|
|||
|
||||
PFAddress = AsmReadCr2 ();
|
||||
|
||||
if (mCpuSmmStaticPageTable && (PFAddress >= LShiftU64 (1, (mPhysicalAddressBits - 1)))) {
|
||||
DEBUG ((DEBUG_ERROR, "Do not support address 0x%lx by processor!\n", PFAddress));
|
||||
CpuDeadLoop ();
|
||||
}
|
||||
|
||||
//
|
||||
// If a page fault occurs in SMRAM range, it should be in a SMM stack guard page.
|
||||
//
|
||||
if ((FeaturePcdGet (PcdCpuSmmStackGuard)) &&
|
||||
(PFAddress >= mCpuHotPlugData.SmrrBase) &&
|
||||
(PFAddress < (mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize))) {
|
||||
DEBUG ((EFI_D_ERROR, "SMM stack overflow!\n"));
|
||||
DEBUG ((DEBUG_ERROR, "SMM stack overflow!\n"));
|
||||
CpuDeadLoop ();
|
||||
}
|
||||
|
||||
|
@ -670,7 +830,7 @@ SmiPFHandler (
|
|||
if ((PFAddress < mCpuHotPlugData.SmrrBase) ||
|
||||
(PFAddress >= mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize)) {
|
||||
if ((SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_ID) != 0) {
|
||||
DEBUG ((EFI_D_ERROR, "Code executed on IP(0x%lx) out of SMM range after SMM is locked!\n", PFAddress));
|
||||
DEBUG ((DEBUG_ERROR, "Code executed on IP(0x%lx) out of SMM range after SMM is locked!\n", PFAddress));
|
||||
DEBUG_CODE (
|
||||
DumpModuleInfoByIp (*(UINTN *)(UINTN)SystemContext.SystemContextX64->Rsp);
|
||||
);
|
||||
|
@ -689,3 +849,87 @@ SmiPFHandler (
|
|||
|
||||
ReleaseSpinLock (mPFLock);
|
||||
}
|
||||
|
||||
/**
|
||||
This function sets memory attribute for page table.
|
||||
**/
|
||||
VOID
|
||||
SetPageTableAttributes (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
UINTN Index2;
|
||||
UINTN Index3;
|
||||
UINTN Index4;
|
||||
UINT64 *L1PageTable;
|
||||
UINT64 *L2PageTable;
|
||||
UINT64 *L3PageTable;
|
||||
UINT64 *L4PageTable;
|
||||
BOOLEAN IsSplitted;
|
||||
BOOLEAN PageTableSplitted;
|
||||
|
||||
if (!mCpuSmmStaticPageTable) {
|
||||
return ;
|
||||
}
|
||||
|
||||
DEBUG ((DEBUG_INFO, "SetPageTableAttributes\n"));
|
||||
|
||||
//
|
||||
// Disable write protection, because we need mark page table to be write protected.
|
||||
// We need *write* page table memory, to mark itself to be *read only*.
|
||||
//
|
||||
AsmWriteCr0 (AsmReadCr0() & ~CR0_WP);
|
||||
|
||||
do {
|
||||
DEBUG ((DEBUG_INFO, "Start...\n"));
|
||||
PageTableSplitted = FALSE;
|
||||
|
||||
L4PageTable = (UINT64 *)GetPageTableBase ();
|
||||
SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS)(UINTN)L4PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);
|
||||
PageTableSplitted = (PageTableSplitted || IsSplitted);
|
||||
|
||||
for (Index4 = 0; Index4 < SIZE_4KB/sizeof(UINT64); Index4++) {
|
||||
L3PageTable = (UINT64 *)(UINTN)(L4PageTable[Index4] & PAGING_4K_ADDRESS_MASK_64);
|
||||
if (L3PageTable == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS)(UINTN)L3PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);
|
||||
PageTableSplitted = (PageTableSplitted || IsSplitted);
|
||||
|
||||
for (Index3 = 0; Index3 < SIZE_4KB/sizeof(UINT64); Index3++) {
|
||||
if ((L3PageTable[Index3] & IA32_PG_PS) != 0) {
|
||||
// 1G
|
||||
continue;
|
||||
}
|
||||
L2PageTable = (UINT64 *)(UINTN)(L3PageTable[Index3] & PAGING_4K_ADDRESS_MASK_64);
|
||||
if (L2PageTable == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS)(UINTN)L2PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);
|
||||
PageTableSplitted = (PageTableSplitted || IsSplitted);
|
||||
|
||||
for (Index2 = 0; Index2 < SIZE_4KB/sizeof(UINT64); Index2++) {
|
||||
if ((L2PageTable[Index2] & IA32_PG_PS) != 0) {
|
||||
// 2M
|
||||
continue;
|
||||
}
|
||||
L1PageTable = (UINT64 *)(UINTN)(L2PageTable[Index2] & PAGING_4K_ADDRESS_MASK_64);
|
||||
if (L1PageTable == NULL) {
|
||||
continue;
|
||||
}
|
||||
SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS)(UINTN)L1PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);
|
||||
PageTableSplitted = (PageTableSplitted || IsSplitted);
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (PageTableSplitted);
|
||||
|
||||
//
|
||||
// Enable write protection, after page table updated.
|
||||
//
|
||||
AsmWriteCr0 (AsmReadCr0() | CR0_WP);
|
||||
|
||||
return ;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#------------------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
|
||||
# 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
|
||||
|
@ -24,8 +24,13 @@ ASM_GLOBAL ASM_PFX(gcSmiHandlerSize)
|
|||
ASM_GLOBAL ASM_PFX(gSmiCr3)
|
||||
ASM_GLOBAL ASM_PFX(gSmiStack)
|
||||
ASM_GLOBAL ASM_PFX(gSmbase)
|
||||
ASM_GLOBAL ASM_PFX(mXdSupported)
|
||||
ASM_GLOBAL ASM_PFX(gSmiHandlerIdtr)
|
||||
|
||||
.equ MSR_IA32_MISC_ENABLE, 0x1A0
|
||||
.equ MSR_EFER, 0xc0000080
|
||||
.equ MSR_EFER_XD, 0x800
|
||||
|
||||
#
|
||||
# Constants relating to PROCESSOR_SMM_DESCRIPTOR
|
||||
#
|
||||
|
@ -132,6 +137,32 @@ ASM_PFX(gSmiCr3): .space 4
|
|||
movl $TSS_SEGMENT, %eax
|
||||
ltr %ax
|
||||
|
||||
# enable NXE if supported
|
||||
.byte 0xb0 # mov al, imm8
|
||||
ASM_PFX(mXdSupported): .byte 1
|
||||
cmpb $0, %al
|
||||
jz SkipNxe
|
||||
#
|
||||
# Check XD disable bit
|
||||
#
|
||||
movl $MSR_IA32_MISC_ENABLE, %ecx
|
||||
rdmsr
|
||||
subl $4, %esp
|
||||
pushq %rdx # save MSR_IA32_MISC_ENABLE[63-32]
|
||||
testl $BIT2, %edx # MSR_IA32_MISC_ENABLE[34]
|
||||
jz L13
|
||||
andw $0x0FFFB, %dx # clear XD Disable bit if it is set
|
||||
wrmsr
|
||||
L13:
|
||||
movl $MSR_EFER, %ecx
|
||||
rdmsr
|
||||
orw $MSR_EFER_XD,%ax # enable NXE
|
||||
wrmsr
|
||||
jmp @NxeDone
|
||||
SkipNxe:
|
||||
subl $8, %esp
|
||||
NxeDone:
|
||||
|
||||
#
|
||||
# Switch to LongMode
|
||||
#
|
||||
|
@ -139,12 +170,13 @@ ASM_PFX(gSmiCr3): .space 4
|
|||
call Base # push return address for retf later
|
||||
Base:
|
||||
addl $(LongMode - Base), (%rsp) # offset for far retf, seg is the 1st arg
|
||||
movl $0xc0000080, %ecx
|
||||
|
||||
movl $MSR_EFER, %ecx
|
||||
rdmsr
|
||||
orb $1,%ah
|
||||
orb $1,%ah # enable LME
|
||||
wrmsr
|
||||
movq %cr0, %rbx
|
||||
orl $0x080010000, %ebx # enable paging + WP
|
||||
orl $0x080010023, %ebx # enable paging + WP + NE + MP + PE
|
||||
movq %rbx, %cr0
|
||||
retf
|
||||
LongMode: # long mode (64-bit code) starts here
|
||||
|
@ -162,10 +194,10 @@ LongMode: # long mode (64-bit code) starts here
|
|||
# jmp _SmiHandler ; instruction is not needed
|
||||
|
||||
_SmiHandler:
|
||||
movq (%rsp), %rbx
|
||||
movq 8(%rsp), %rbx
|
||||
# Save FP registers
|
||||
|
||||
subq $0x208, %rsp
|
||||
subq $0x200, %rsp
|
||||
.byte 0x48 # FXSAVE64
|
||||
fxsave (%rsp)
|
||||
|
||||
|
@ -191,6 +223,21 @@ _SmiHandler:
|
|||
.byte 0x48 # FXRSTOR64
|
||||
fxrstor (%rsp)
|
||||
|
||||
addq $0x200, %rsp
|
||||
|
||||
movabsq $ASM_PFX(mXdSupported), %rax
|
||||
movb (%rax), %al
|
||||
cmpb $0, %al
|
||||
jz L16
|
||||
popq %rdx # get saved MSR_IA32_MISC_ENABLE[63-32]
|
||||
testl $BIT2, %edx
|
||||
jz L16
|
||||
movl $MSR_IA32_MISC_ENABLE, %ecx
|
||||
rdmsr
|
||||
orw $BIT2, %dx # set XD Disable bit if it was set before entering into SMM
|
||||
wrmsr
|
||||
|
||||
L16:
|
||||
rsm
|
||||
|
||||
ASM_PFX(gcSmiHandlerSize): .word . - _SmiEntryPoint
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
;------------------------------------------------------------------------------ ;
|
||||
; Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
|
||||
; 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
|
||||
|
@ -29,8 +29,12 @@ EXTERNDEF gcSmiHandlerSize:WORD
|
|||
EXTERNDEF gSmiCr3:DWORD
|
||||
EXTERNDEF gSmiStack:DWORD
|
||||
EXTERNDEF gSmbase:DWORD
|
||||
EXTERNDEF mXdSupported:BYTE
|
||||
EXTERNDEF gSmiHandlerIdtr:FWORD
|
||||
|
||||
MSR_IA32_MISC_ENABLE EQU 1A0h
|
||||
MSR_EFER EQU 0c0000080h
|
||||
MSR_EFER_XD EQU 0800h
|
||||
|
||||
;
|
||||
; Constants relating to PROCESSOR_SMM_DESCRIPTOR
|
||||
|
@ -130,17 +134,44 @@ gSmiCr3 DD ?
|
|||
mov eax, TSS_SEGMENT
|
||||
ltr ax
|
||||
|
||||
; enable NXE if supported
|
||||
DB 0b0h ; mov al, imm8
|
||||
mXdSupported 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, 0c0000080h
|
||||
|
||||
mov ecx, MSR_EFER
|
||||
rdmsr
|
||||
or ah, 1
|
||||
or ah, 1 ; enable LME
|
||||
wrmsr
|
||||
mov rbx, cr0
|
||||
or ebx, 080010000h ; enable paging + WP
|
||||
or ebx, 080010023h ; enable paging + WP + NE + MP + PE
|
||||
mov cr0, rbx
|
||||
retf
|
||||
@LongMode: ; long mode (64-bit code) starts here
|
||||
|
@ -163,7 +194,7 @@ _SmiHandler:
|
|||
;
|
||||
; Save FP registers
|
||||
;
|
||||
sub rsp, 208h
|
||||
sub rsp, 200h
|
||||
DB 48h ; FXSAVE64
|
||||
fxsave [rsp]
|
||||
|
||||
|
@ -189,6 +220,21 @@ _SmiHandler:
|
|||
DB 48h ; FXRSTOR64
|
||||
fxrstor [rsp]
|
||||
|
||||
add rsp, 200h
|
||||
|
||||
mov rax, ASM_PFX(mXdSupported)
|
||||
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
|
||||
|
||||
gcSmiHandlerSize DW $ - _SmiEntryPoint
|
||||
|
|
|
@ -22,6 +22,10 @@
|
|||
; Variables referrenced by C code
|
||||
;
|
||||
|
||||
%define MSR_IA32_MISC_ENABLE 0x1A0
|
||||
%define MSR_EFER 0xc0000080
|
||||
%define MSR_EFER_XD 0x800
|
||||
|
||||
;
|
||||
; Constants relating to PROCESSOR_SMM_DESCRIPTOR
|
||||
;
|
||||
|
@ -50,6 +54,7 @@ extern ASM_PFX(CpuSmmDebugEntry)
|
|||
extern ASM_PFX(CpuSmmDebugExit)
|
||||
|
||||
global ASM_PFX(gSmbase)
|
||||
global ASM_PFX(mXdSupported)
|
||||
global ASM_PFX(gSmiStack)
|
||||
global ASM_PFX(gSmiCr3)
|
||||
global ASM_PFX(gcSmiHandlerTemplate)
|
||||
|
@ -112,17 +117,44 @@ ASM_PFX(gSmiCr3): DD 0
|
|||
mov eax, TSS_SEGMENT
|
||||
ltr ax
|
||||
|
||||
; enable NXE if supported
|
||||
DB 0xb0 ; mov al, imm8
|
||||
ASM_PFX(mXdSupported): 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 .0
|
||||
and dx, 0xFFFB ; clear XD Disable bit if it is set
|
||||
wrmsr
|
||||
.0:
|
||||
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 reture address for retf later
|
||||
call Base ; push return address for retf later
|
||||
Base:
|
||||
add dword [rsp], @LongMode - Base; offset for far retf, seg is the 1st arg
|
||||
mov ecx, 0xc0000080
|
||||
|
||||
mov ecx, MSR_EFER
|
||||
rdmsr
|
||||
or ah, 1
|
||||
or ah, 1 ; enable LME
|
||||
wrmsr
|
||||
mov rbx, cr0
|
||||
or ebx, 080010000h ; enable paging + WP
|
||||
or ebx, 0x80010023 ; enable paging + WP + NE + MP + PE
|
||||
mov cr0, rbx
|
||||
retf
|
||||
@LongMode: ; long mode (64-bit code) starts here
|
||||
|
@ -140,12 +172,12 @@ Base:
|
|||
; jmp _SmiHandler ; instruction is not needed
|
||||
|
||||
_SmiHandler:
|
||||
mov rbx, [rsp] ; rbx <- CpuIndex
|
||||
mov rbx, [rsp + 0x8] ; rcx <- CpuIndex
|
||||
|
||||
;
|
||||
; Save FP registers
|
||||
;
|
||||
sub rsp, 0x208
|
||||
sub rsp, 0x200
|
||||
DB 0x48 ; FXSAVE64
|
||||
fxsave [rsp]
|
||||
|
||||
|
@ -171,6 +203,21 @@ _SmiHandler:
|
|||
DB 0x48 ; FXRSTOR64
|
||||
fxrstor [rsp]
|
||||
|
||||
add rsp, 0x200
|
||||
|
||||
mov rax, ASM_PFX(mXdSupported)
|
||||
mov al, [rax]
|
||||
cmp al, 0
|
||||
jz .1
|
||||
pop rdx ; get saved MSR_IA32_MISC_ENABLE[63-32]
|
||||
test edx, BIT2
|
||||
jz .1
|
||||
mov ecx, MSR_IA32_MISC_ENABLE
|
||||
rdmsr
|
||||
or dx, BIT2 ; set XD Disable bit if it was set before entering into SMM
|
||||
wrmsr
|
||||
|
||||
.1:
|
||||
rsm
|
||||
|
||||
gcSmiHandlerSize DW $ - _SmiEntryPoint
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#------------------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
|
||||
# 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
|
||||
|
@ -128,244 +128,8 @@ ASM_PFX(gcSmiGdtr):
|
|||
.quad NullSeg
|
||||
|
||||
ASM_PFX(gcSmiIdtr):
|
||||
.word IDT_SIZE - 1
|
||||
.quad _SmiIDT
|
||||
|
||||
|
||||
#
|
||||
# Here is the IDT. There are 32 (not 255) entries in it since only processor
|
||||
# generated exceptions will be handled.
|
||||
#
|
||||
_SmiIDT:
|
||||
# The following segment repeats 32 times:
|
||||
# No. 1
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
.quad 0 # Offset 32:63
|
||||
# No. 2
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
.quad 0 # Offset 32:63
|
||||
# No. 3
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
.quad 0 # Offset 32:63
|
||||
# No. 4
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
.quad 0 # Offset 32:63
|
||||
# No. 5
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
.quad 0 # Offset 32:63
|
||||
# No. 6
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
.quad 0 # Offset 32:63
|
||||
# No. 7
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
.quad 0 # Offset 32:63
|
||||
# No. 8
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
.quad 0 # Offset 32:63
|
||||
# No. 9
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
.quad 0 # Offset 32:63
|
||||
# No. 10
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
.quad 0 # Offset 32:63
|
||||
# No. 11
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
.quad 0 # Offset 32:63
|
||||
# No. 12
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
.quad 0 # Offset 32:63
|
||||
# No. 13
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
.quad 0 # Offset 32:63
|
||||
# No. 14
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
.quad 0 # Offset 32:63
|
||||
# No. 15
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
.quad 0 # Offset 32:63
|
||||
# No. 16
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
.quad 0 # Offset 32:63
|
||||
# No. 17
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
.quad 0 # Offset 32:63
|
||||
# No. 18
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
.quad 0 # Offset 32:63
|
||||
# No. 19
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
.quad 0 # Offset 32:63
|
||||
# No. 20
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
.quad 0 # Offset 32:63
|
||||
# No. 21
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
.quad 0 # Offset 32:63
|
||||
# No. 22
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
.quad 0 # Offset 32:63
|
||||
# No. 23
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
.quad 0 # Offset 32:63
|
||||
# No. 24
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
.quad 0 # Offset 32:63
|
||||
# No. 25
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
.quad 0 # Offset 32:63
|
||||
# No. 26
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
.quad 0 # Offset 32:63
|
||||
# No. 27
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
.quad 0 # Offset 32:63
|
||||
# No. 28
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
.quad 0 # Offset 32:63
|
||||
# No. 29
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
.quad 0 # Offset 32:63
|
||||
# No. 30
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
.quad 0 # Offset 32:63
|
||||
# No. 31
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
.quad 0 # Offset 32:63
|
||||
# No. 32
|
||||
.word 0 # Offset 0:15
|
||||
.word CODE_SEL
|
||||
.byte 0 # Unused
|
||||
.byte 0x8e # Interrupt Gate, Present
|
||||
.word 0 # Offset 16:31
|
||||
.quad 0 # Offset 32:63
|
||||
|
||||
_SmiIDTEnd:
|
||||
|
||||
.equ IDT_SIZE, (_SmiIDTEnd - _SmiIDT)
|
||||
.word 0
|
||||
.quad 0
|
||||
|
||||
.text
|
||||
|
||||
|
@ -600,11 +364,3 @@ L5:
|
|||
addq $16, %rsp # skip INT# & ErrCode
|
||||
iretq
|
||||
|
||||
ASM_GLOBAL ASM_PFX(InitializeIDTSmmStackGuard)
|
||||
ASM_PFX(InitializeIDTSmmStackGuard):
|
||||
# If SMM Stack Guard feature is enabled, set the IST field of
|
||||
# the interrupt gate for Page Fault Exception to be 1
|
||||
#
|
||||
movabsq $_SmiIDT + 14 * 16, %rax
|
||||
movb $1, 4(%rax)
|
||||
ret
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
;------------------------------------------------------------------------------ ;
|
||||
; Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
|
||||
; 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
|
||||
|
@ -144,27 +144,8 @@ gcSmiGdtr LABEL FWORD
|
|||
DQ offset NullSeg
|
||||
|
||||
gcSmiIdtr LABEL FWORD
|
||||
DW IDT_SIZE - 1
|
||||
DQ offset _SmiIDT
|
||||
|
||||
.data
|
||||
|
||||
;
|
||||
; Here is the IDT. There are 32 (not 255) entries in it since only processor
|
||||
; generated exceptions will be handled.
|
||||
;
|
||||
_SmiIDT:
|
||||
REPEAT 32
|
||||
DW 0 ; Offset 0:15
|
||||
DW CODE_SEL ; Segment selector
|
||||
DB 0 ; Unused
|
||||
DB 8eh ; Interrupt Gate, Present
|
||||
DW 0 ; Offset 16:31
|
||||
DQ 0 ; Offset 32:63
|
||||
ENDM
|
||||
_SmiIDTEnd:
|
||||
|
||||
IDT_SIZE = (offset _SmiIDTEnd - offset _SmiIDT)
|
||||
DW 0
|
||||
DQ 0
|
||||
|
||||
.code
|
||||
|
||||
|
@ -400,14 +381,4 @@ PageFaultIdtHandlerSmmProfile PROC
|
|||
iretq
|
||||
PageFaultIdtHandlerSmmProfile ENDP
|
||||
|
||||
InitializeIDTSmmStackGuard PROC
|
||||
;
|
||||
; If SMM Stack Guard feature is enabled, set the IST field of
|
||||
; the interrupt gate for Page Fault Exception to be 1
|
||||
;
|
||||
lea rax, _SmiIDT + 14 * 16
|
||||
mov byte ptr [rax + 4], 1
|
||||
ret
|
||||
InitializeIDTSmmStackGuard ENDP
|
||||
|
||||
END
|
||||
|
|
|
@ -145,25 +145,8 @@ ASM_PFX(gcSmiGdtr):
|
|||
DQ NullSeg
|
||||
|
||||
ASM_PFX(gcSmiIdtr):
|
||||
DW IDT_SIZE - 1
|
||||
DQ _SmiIDT
|
||||
|
||||
;
|
||||
; Here is the IDT. There are 32 (not 255) entries in it since only processor
|
||||
; generated exceptions will be handled.
|
||||
;
|
||||
_SmiIDT:
|
||||
%rep 32
|
||||
DW 0 ; 0:15
|
||||
DW CODE_SEL ; Segment selector
|
||||
DB 0 ; Unused
|
||||
DB 0x8e ; Interrupt Gate, Present
|
||||
DW 0 ; 16:31
|
||||
DQ 0 ; 32:63
|
||||
%endrep
|
||||
_SmiIDTEnd:
|
||||
|
||||
IDT_SIZE equ _SmiIDTEnd - _SmiIDT
|
||||
DW 0
|
||||
DQ 0
|
||||
|
||||
DEFAULT REL
|
||||
SECTION .text
|
||||
|
@ -400,13 +383,3 @@ ASM_PFX(PageFaultIdtHandlerSmmProfile):
|
|||
add rsp, 16 ; skip INT# & ErrCode
|
||||
iretq
|
||||
|
||||
global ASM_PFX(InitializeIDTSmmStackGuard)
|
||||
ASM_PFX(InitializeIDTSmmStackGuard):
|
||||
;
|
||||
; If SMM Stack Guard feature is enabled, set the IST field of
|
||||
; the interrupt gate for Page Fault Exception to be 1
|
||||
;
|
||||
lea rax, [_SmiIDT + 14 * 16]
|
||||
mov byte [rax + 4], 1
|
||||
ret
|
||||
|
||||
|
|
|
@ -14,6 +14,30 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|||
|
||||
#include "PiSmmCpuDxeSmm.h"
|
||||
|
||||
EFI_PHYSICAL_ADDRESS mGdtBuffer;
|
||||
UINTN mGdtBufferSize;
|
||||
|
||||
/**
|
||||
Initialize IDT for SMM Stack Guard.
|
||||
|
||||
**/
|
||||
VOID
|
||||
EFIAPI
|
||||
InitializeIDTSmmStackGuard (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
IA32_IDT_GATE_DESCRIPTOR *IdtGate;
|
||||
|
||||
//
|
||||
// If SMM Stack Guard feature is enabled, set the IST field of
|
||||
// the interrupt gate for Page Fault Exception to be 1
|
||||
//
|
||||
IdtGate = (IA32_IDT_GATE_DESCRIPTOR *)gcSmiIdtr.Base;
|
||||
IdtGate += EXCEPT_IA32_PAGE_FAULT;
|
||||
IdtGate->Bits.Reserved_0 = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
Initialize Gdt for all processors.
|
||||
|
||||
|
@ -41,8 +65,10 @@ InitGdt (
|
|||
// on each SMI entry.
|
||||
//
|
||||
GdtTssTableSize = (gcSmiGdtr.Limit + 1 + TSS_SIZE + 7) & ~7; // 8 bytes aligned
|
||||
GdtTssTables = (UINT8*)AllocatePages (EFI_SIZE_TO_PAGES (GdtTssTableSize * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus));
|
||||
mGdtBufferSize = GdtTssTableSize * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus;
|
||||
GdtTssTables = (UINT8*)AllocateCodePages (EFI_SIZE_TO_PAGES (mGdtBufferSize));
|
||||
ASSERT (GdtTssTables != NULL);
|
||||
mGdtBuffer = (UINTN)GdtTssTables;
|
||||
GdtTableStepSize = GdtTssTableSize;
|
||||
|
||||
for (Index = 0; Index < gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; Index++) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/** @file
|
||||
X64 processor specific functions to enable SMM profile.
|
||||
|
||||
Copyright (c) 2012 - 2015, Intel Corporation. All rights reserved.<BR>
|
||||
Copyright (c) 2012 - 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
|
||||
|
@ -45,12 +45,13 @@ InitSmmS3Cr3 (
|
|||
//
|
||||
// Generate PAE page table for the first 4GB memory space
|
||||
//
|
||||
Pages = Gen4GPageTable (1, FALSE);
|
||||
Pages = Gen4GPageTable (FALSE);
|
||||
|
||||
//
|
||||
// Fill Page-Table-Level4 (PML4) entry
|
||||
//
|
||||
PTEntry = (UINT64*)(UINTN)(Pages - EFI_PAGES_TO_SIZE (1));
|
||||
PTEntry = (UINT64*)AllocatePageTableMemory (1);
|
||||
ASSERT (PTEntry != NULL);
|
||||
*PTEntry = Pages | PAGE_ATTRIBUTE_BITS;
|
||||
ZeroMem (PTEntry + 1, EFI_PAGE_SIZE - sizeof (*PTEntry));
|
||||
|
||||
|
|
Loading…
Reference in New Issue