diff --git a/IntelFsp2Pkg/FspSecCore/Fsp24SecCoreM.inf b/IntelFsp2Pkg/FspSecCore/Fsp24SecCoreM.inf index 762d485bab..40ff9f22f7 100644 --- a/IntelFsp2Pkg/FspSecCore/Fsp24SecCoreM.inf +++ b/IntelFsp2Pkg/FspSecCore/Fsp24SecCoreM.inf @@ -69,6 +69,7 @@ gIntelFsp2PkgTokenSpaceGuid.PcdFspHeapSizePercentage ## CONSUMES gIntelFsp2PkgTokenSpaceGuid.PcdFspMaxInterruptSupported ## CONSUMES gIntelFsp2PkgTokenSpaceGuid.PcdFspPrivateTemporaryRamSize ## CONSUMES + gIntelFsp2PkgTokenSpaceGuid.PcdFspSaveRestorePageTableEnable ## CONSUMES [Ppis] gEfiTemporaryRamSupportPpiGuid ## PRODUCES diff --git a/IntelFsp2Pkg/FspSecCore/FspSecCoreM.inf b/IntelFsp2Pkg/FspSecCore/FspSecCoreM.inf index 3acf4f6f9d..ac572a6168 100644 --- a/IntelFsp2Pkg/FspSecCore/FspSecCoreM.inf +++ b/IntelFsp2Pkg/FspSecCore/FspSecCoreM.inf @@ -68,6 +68,7 @@ gIntelFsp2PkgTokenSpaceGuid.PcdFspHeapSizePercentage ## CONSUMES gIntelFsp2PkgTokenSpaceGuid.PcdFspMaxInterruptSupported ## CONSUMES gIntelFsp2PkgTokenSpaceGuid.PcdFspPrivateTemporaryRamSize ## CONSUMES + gIntelFsp2PkgTokenSpaceGuid.PcdFspSaveRestorePageTableEnable ## CONSUMES [Ppis] gEfiTemporaryRamSupportPpiGuid ## PRODUCES diff --git a/IntelFsp2Pkg/FspSecCore/Ia32/Fsp24ApiEntryM.nasm b/IntelFsp2Pkg/FspSecCore/Ia32/Fsp24ApiEntryM.nasm index 5fa5c03569..e9bf0cbed2 100644 --- a/IntelFsp2Pkg/FspSecCore/Ia32/Fsp24ApiEntryM.nasm +++ b/IntelFsp2Pkg/FspSecCore/Ia32/Fsp24ApiEntryM.nasm @@ -13,6 +13,7 @@ extern ASM_PFX(PcdGet32(PcdTemporaryRamBase)) extern ASM_PFX(PcdGet32(PcdFspTemporaryRamSize)) extern ASM_PFX(PcdGet8 (PcdFspHeapSizePercentage)) +extern ASM_PFX(FeaturePcdGet (PcdFspSaveRestorePageTableEnable)) struc FSPM_UPD_COMMON ; FSP_UPD_HEADER { @@ -64,7 +65,7 @@ extern ASM_PFX(AsmGetFspInfoHeader) extern ASM_PFX(FspMultiPhaseMemInitApiHandler) STACK_SAVED_EAX_OFFSET EQU 4 * 7 ; size of a general purpose register * eax index -API_PARAM1_OFFSET EQU 34h ; ApiParam1 [ sub esp,8 + pushad + pushfd + push eax + call] +API_PARAM1_OFFSET EQU 44h ; ApiParam1 [ sub esp,8 + push cr0/cr3/cr4/EFER + pushad + pushfd + push eax + call] FSP_HEADER_IMGBASE_OFFSET EQU 1Ch FSP_HEADER_CFGREG_OFFSET EQU 24h @@ -153,6 +154,33 @@ NotMultiPhaseMemoryInitApi: cli pushad + ; + ; Allocate 4x4 bytes on the stack. + ; + sub esp, 16 + cmp byte [dword ASM_PFX(FeaturePcdGet (PcdFspSaveRestorePageTableEnable))], 0 + jz SkipPagetableSave + + add esp, 16 + ; Save EFER MSR lower 32 bits + push ecx + push eax + mov ecx, 0xC0000080 + rdmsr + mov edx, eax + pop eax + pop ecx + push edx + + ; Save CR registers + mov edx, cr4 + push edx + mov edx, cr3 + push edx + mov edx, cr0 + push edx +SkipPagetableSave: + ; Reserve 8 bytes for IDT save/restore sub esp, 8 sidt [esp] diff --git a/IntelFsp2Pkg/FspSecCore/Ia32/FspApiEntryM.nasm b/IntelFsp2Pkg/FspSecCore/Ia32/FspApiEntryM.nasm index 861cce4d01..b1623063ef 100644 --- a/IntelFsp2Pkg/FspSecCore/Ia32/FspApiEntryM.nasm +++ b/IntelFsp2Pkg/FspSecCore/Ia32/FspApiEntryM.nasm @@ -13,6 +13,7 @@ extern ASM_PFX(PcdGet32(PcdTemporaryRamBase)) extern ASM_PFX(PcdGet32(PcdFspTemporaryRamSize)) extern ASM_PFX(PcdGet8 (PcdFspHeapSizePercentage)) +extern ASM_PFX(FeaturePcdGet (PcdFspSaveRestorePageTableEnable)) struc FSPM_UPD_COMMON ; FSP_UPD_HEADER { @@ -62,7 +63,7 @@ extern ASM_PFX(FspApiCommon) extern ASM_PFX(AsmGetFspBaseAddress) extern ASM_PFX(AsmGetFspInfoHeader) -API_PARAM1_OFFSET EQU 34h ; ApiParam1 [ sub esp,8 + pushad + pushfd + push eax + call] +API_PARAM1_OFFSET EQU 44h ; ApiParam1 [ sub esp,8 + push cr0/cr3/cr4/EFER +pushad + pushfd + push eax + call] FSP_HEADER_IMGBASE_OFFSET EQU 1Ch FSP_HEADER_CFGREG_OFFSET EQU 24h @@ -124,6 +125,33 @@ ASM_PFX(FspApiCommonContinue): cli pushad + ; + ; Allocate 4x4 bytes on the stack. + ; + sub esp, 16 + cmp byte [dword ASM_PFX(FeaturePcdGet (PcdFspSaveRestorePageTableEnable))], 0 + jz SkipPagetableSave + + add esp, 16 + ; Save EFER MSR lower 32-bit + push ecx + push eax + mov ecx, 0xC0000080 + rdmsr + mov edx, eax + pop eax + pop ecx + push edx + + ; Save CR registers + mov edx, cr4 + push edx + mov edx, cr3 + push edx + mov edx, cr0 + push edx + +SkipPagetableSave: ; Reserve 8 bytes for IDT save/restore sub esp, 8 sidt [esp] diff --git a/IntelFsp2Pkg/FspSecCore/X64/Fsp24ApiEntryM.nasm b/IntelFsp2Pkg/FspSecCore/X64/Fsp24ApiEntryM.nasm index a3b38e4585..3066156bcf 100644 --- a/IntelFsp2Pkg/FspSecCore/X64/Fsp24ApiEntryM.nasm +++ b/IntelFsp2Pkg/FspSecCore/X64/Fsp24ApiEntryM.nasm @@ -4,7 +4,7 @@ ; Copyright (c) 2022, Intel Corporation. All rights reserved.
; SPDX-License-Identifier: BSD-2-Clause-Patent ;; - + DEFAULT REL SECTION .text %include "PushPopRegsNasm.inc" @@ -13,6 +13,7 @@ ; Following are fixed PCDs ; extern ASM_PFX(PcdGet8 (PcdFspHeapSizePercentage)) +extern ASM_PFX(FeaturePcdGet (PcdFspSaveRestorePageTableEnable)) struc FSPM_UPD_COMMON_FSP24 ; FSP_UPD_HEADER { @@ -142,6 +143,36 @@ NotMultiPhaseMemoryInitApi: cli PUSHA_64 + ; + ; Allocate 4x8 bytes on the stack. + ; + sub rsp, 32 + lea rdx, [ASM_PFX(FeaturePcdGet (PcdFspSaveRestorePageTableEnable))] + mov dl, byte [rdx] + cmp dl, 0 + jz SkipPagetableSave + + add rsp, 32 + ; Save EFER MSR + push rcx + push rax + mov rcx, 0xC0000080 + rdmsr + shl rdx, 0x20 + or rdx, rax + pop rax + pop rcx + push rdx + + ; Save CR registers + mov rdx, cr4 + push rdx + mov rdx, cr3 + push rdx + mov rdx, cr0 + push rdx +SkipPagetableSave: + ; Reserve 16 bytes for IDT save/restore sub rsp, 16 sidt [rsp] diff --git a/IntelFsp2Pkg/FspSecCore/X64/FspApiEntryM.nasm b/IntelFsp2Pkg/FspSecCore/X64/FspApiEntryM.nasm index 2d2f75b1f0..b0b6b6a4aa 100644 --- a/IntelFsp2Pkg/FspSecCore/X64/FspApiEntryM.nasm +++ b/IntelFsp2Pkg/FspSecCore/X64/FspApiEntryM.nasm @@ -4,7 +4,7 @@ ; Copyright (c) 2022, Intel Corporation. All rights reserved.
; SPDX-License-Identifier: BSD-2-Clause-Patent ;; - + DEFAULT REL SECTION .text %include "PushPopRegsNasm.inc" @@ -13,6 +13,7 @@ ; Following are fixed PCDs ; extern ASM_PFX(PcdGet8 (PcdFspHeapSizePercentage)) +extern ASM_PFX(FeaturePcdGet (PcdFspSaveRestorePageTableEnable)) struc FSPM_UPD_COMMON_FSP24 ; FSP_UPD_HEADER { @@ -110,6 +111,36 @@ ASM_PFX(FspApiCommonContinue): cli PUSHA_64 + ; + ; Allocate 4x8 bytes on the stack. + ; + sub rsp, 32 + lea rdx, [ASM_PFX(FeaturePcdGet (PcdFspSaveRestorePageTableEnable))] + mov dl, byte [rdx] + cmp dl, 0 + jz SkipPagetableSave + + add rsp, 32 + ; Save EFER MSR + push rcx + push rax + mov rcx, 0xC0000080 + rdmsr + shl rdx, 0x20 + or rdx, rax + pop rax + pop rcx + push rdx + + ; Save CR registers + mov rdx, cr4 + push rdx + mov rdx, cr3 + push rdx + mov rdx, cr0 + push rdx +SkipPagetableSave: + ; Reserve 16 bytes for IDT save/restore sub rsp, 16 sidt [rsp] diff --git a/IntelFsp2Pkg/IntelFsp2Pkg.dec b/IntelFsp2Pkg/IntelFsp2Pkg.dec index d1c3d3ee7b..8fe6b64f99 100644 --- a/IntelFsp2Pkg/IntelFsp2Pkg.dec +++ b/IntelFsp2Pkg/IntelFsp2Pkg.dec @@ -114,6 +114,14 @@ # gIntelFsp2PkgTokenSpaceGuid.PcdFspPrivateTemporaryRamSize |0x00000000|UINT32|0x10000006 +[PcdsFeatureFlag] + # + # Indicates if the FSP will save and restore page table. Only works in FSP API mode + # TRUE - FSP will save and restore page table + # FALSE - FSP will not save and restore page table + # + gIntelFsp2PkgTokenSpaceGuid.PcdFspSaveRestorePageTableEnable |FALSE|BOOLEAN|0x10000007 + [PcdsFixedAtBuild,PcdsDynamic,PcdsDynamicEx] gIntelFsp2PkgTokenSpaceGuid.PcdFspReservedMemoryLength |0x00100000|UINT32|0x46530000 gIntelFsp2PkgTokenSpaceGuid.PcdBootLoaderEntry |0xFFFFFFE4|UINT32|0x46530100 diff --git a/IntelFsp2Pkg/Library/BaseFspCommonLib/FspCommonLib.c b/IntelFsp2Pkg/Library/BaseFspCommonLib/FspCommonLib.c index 54dbf546c3..3ecc5bd265 100644 --- a/IntelFsp2Pkg/Library/BaseFspCommonLib/FspCommonLib.c +++ b/IntelFsp2Pkg/Library/BaseFspCommonLib/FspCommonLib.c @@ -15,21 +15,14 @@ #pragma pack(1) -// -// API Parameter +0x34 -// API return address +0x30 -// -// push FspInfoHeader +0x2C -// pushfd +0x28 -// cli -// pushad +0x24 -// sub esp, 8 +0x00 -// sidt fword ptr [esp] -// typedef struct { UINT16 IdtrLimit; UINT32 IdtrBase; UINT16 Reserved; + UINT32 Cr0; + UINT32 Cr3; + UINT32 Cr4; + UINT32 Efer; // lower 32-bit of EFER since only NXE bit (BIT11) need to be restored. UINT32 Registers[8]; // General Purpose Registers: Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx and Eax UINT16 Flags[2]; UINT32 FspInfoHeader; @@ -37,20 +30,12 @@ typedef struct { UINT32 ApiParam[2]; } CONTEXT_STACK; -// -// API return address +0xB8 -// Reserved +0xB0 -// push API Parameter2 +0xA8 -// push API Parameter1 +0xA0 -// push FspInfoHeader +0x98 -// pushfq +0x90 -// cli -// PUSHA_64 +0x10 -// sub rsp, 16 +0x00 -// sidt [rsp] -// typedef struct { UINT64 Idtr[2]; // IDTR Limit - bit0:bi15, IDTR Base - bit16:bit79 + UINT64 Cr0; + UINT64 Cr3; + UINT64 Cr4; + UINT64 Efer; UINT64 Registers[16]; // General Purpose Registers: RDI, RSI, RBP, RSP, RBX, RDX, RCX, RAX, and R15 to R8 UINT32 Flags[2]; UINT64 FspInfoHeader; diff --git a/IntelFsp2Pkg/Library/BaseFspSwitchStackLib/BaseFspSwitchStackLib.inf b/IntelFsp2Pkg/Library/BaseFspSwitchStackLib/BaseFspSwitchStackLib.inf index 6909aec651..0194c2e955 100644 --- a/IntelFsp2Pkg/Library/BaseFspSwitchStackLib/BaseFspSwitchStackLib.inf +++ b/IntelFsp2Pkg/Library/BaseFspSwitchStackLib/BaseFspSwitchStackLib.inf @@ -32,5 +32,5 @@ BaseLib IoLib - - +[Pcd] + gIntelFsp2PkgTokenSpaceGuid.PcdFspSaveRestorePageTableEnable diff --git a/IntelFsp2Pkg/Library/BaseFspSwitchStackLib/Ia32/Stack.nasm b/IntelFsp2Pkg/Library/BaseFspSwitchStackLib/Ia32/Stack.nasm index 6599901906..d13842451c 100644 --- a/IntelFsp2Pkg/Library/BaseFspSwitchStackLib/Ia32/Stack.nasm +++ b/IntelFsp2Pkg/Library/BaseFspSwitchStackLib/Ia32/Stack.nasm @@ -12,6 +12,12 @@ SECTION .text extern ASM_PFX(SwapStack) +extern ASM_PFX(FeaturePcdGet (PcdFspSaveRestorePageTableEnable)) + +; Page table related bits in CR0/CR4/EFER +%define CR0_PG_MASK 0x80010000 ; CR0.PG and CR0.WP +%define CR4_PG_MASK 0x10B0 ; CR4.PSE, CR4.PAE, CR4.PGE and CR4.LA57 +%define EFER_PG_MASK 0x800 ; EFER.NXE ;------------------------------------------------------------------------------ ; UINT32 @@ -50,6 +56,34 @@ ASM_PFX(FspSwitchStack): pushfd cli pushad + + ; + ; Allocate 4x4 bytes on the stack. + ; + sub esp, 16 + cmp byte [dword ASM_PFX(FeaturePcdGet (PcdFspSaveRestorePageTableEnable))], 0 + jz SkipPagetableSave + + add esp, 16 + ; Save EFER MSR lower 32 bits + push ecx + push eax + mov ecx, 0xC0000080 + rdmsr + mov edx, eax + pop eax + pop ecx + push edx + + ; Save CR registers + mov eax, cr4 + push eax + mov eax, cr3 + push eax + mov eax, cr0 + push eax +SkipPagetableSave: + sub esp, 8 sidt [esp] @@ -61,6 +95,104 @@ ASM_PFX(FspSwitchStack): ; Restore previous contexts lidt [esp] add esp, 8 + + cmp byte [dword ASM_PFX(FeaturePcdGet (PcdFspSaveRestorePageTableEnable))], 0 + jz SkipPagetableRestore + ; [esp] stores new cr0 + ; [esp+4] stores new cr3 + ; [esp+8] stores new cr4 + ; [esp+12] stores new Efer + ; + ; When new EFER.NXE == 1, the restore flow is: EFER --> CRx + ; Otherwise: CRx --> EFER + ; When new CR0.PG == 1, the restore flow for CRx is: CR3 --> CR4 --> CR0 + ; Otherwise, the restore flow is: CR0 --> CR3 --> CR4 + ; + ; If NXE bit is changed to 1, change NXE before CR register + ; This is because Nx bit in page table entry in new CR3 will be invalid + ; if updating CR3 before EFER MSR. + ; + mov eax, [esp+12] + bt eax, 11 + jnc SkipEferLabel1 + + ; Restore EFER MSR + mov ecx, 0xC0000080 + rdmsr + and eax, ~EFER_PG_MASK + mov ebx, [esp+12] + and ebx, EFER_PG_MASK + or eax, ebx + wrmsr + +SkipEferLabel1: + + ; + ; if new cr0 is to disable page table, change CR0 before CR3/CR4 + ; + mov eax, [esp] + bt eax, 31 + jc SkipCr0Label1 + + ; Restore CR0 + mov edx, cr0 + and edx, ~CR0_PG_MASK + mov eax, [esp] + and eax, CR0_PG_MASK + or edx, eax + mov cr0, edx + +SkipCr0Label1: + + ; Restore CR3/CR4 + mov eax, [esp+4] + mov cr3, eax + + mov edx, cr4 + and edx, ~CR4_PG_MASK + mov eax, [esp+8] + and eax, CR4_PG_MASK + or edx, eax + mov cr4, edx + + ; + ; if new cr0 is to enable page table, change CR0 after CR3/CR4 + ; + mov eax, [esp] + bt eax, 31 + jnc SkipCr0Label2 + + ; Restore CR0 + mov edx, cr0 + and edx, ~CR0_PG_MASK + mov eax, [esp] + and eax, CR0_PG_MASK + or edx, eax + mov cr0, edx + +SkipCr0Label2: + ; + ; If NXE bit is changed to 0, change NXE after than CR regiser + ; + mov eax, [esp+12] + bt eax, 11 + jc SkipEferLabel2 + + ; Restore EFER MSR + mov ecx, 0xC0000080 + rdmsr + and eax, ~EFER_PG_MASK + mov ebx, [esp+12] + and ebx, EFER_PG_MASK + or eax, ebx + wrmsr + +SkipEferLabel2: +SkipPagetableRestore: + + ; pop page table related registers. + add esp, 16 + popad popfd add esp, 4 diff --git a/IntelFsp2Pkg/Library/BaseFspSwitchStackLib/X64/Stack.nasm b/IntelFsp2Pkg/Library/BaseFspSwitchStackLib/X64/Stack.nasm index e3a7cf002f..f40df51ab4 100644 --- a/IntelFsp2Pkg/Library/BaseFspSwitchStackLib/X64/Stack.nasm +++ b/IntelFsp2Pkg/Library/BaseFspSwitchStackLib/X64/Stack.nasm @@ -8,12 +8,18 @@ ; Switch the stack from temporary memory to permanent memory. ; ;------------------------------------------------------------------------------ - + DEFAULT REL SECTION .text %include "PushPopRegsNasm.inc" +; Page table related bits in CR0/CR4/EFER +%define CR0_PG_MASK 0x80010000 ; CR0.PG and CR0.WP +%define CR4_PG_MASK 0x10B0 ; CR4.PSE, CR4.PAE, CR4.PGE and CR4.LA57 +%define EFER_PG_MASK 0x800 ; EFER.NXE + extern ASM_PFX(SwapStack) +extern ASM_PFX(FeaturePcdGet (PcdFspSaveRestorePageTableEnable)) ;------------------------------------------------------------------------------ ; UINT32 @@ -55,6 +61,37 @@ ASM_PFX(FspSwitchStack): pushfq cli PUSHA_64 + + ; + ; Allocate 4x8 bytes on the stack. + ; + sub rsp, 32 + lea rdx, [ASM_PFX(FeaturePcdGet (PcdFspSaveRestorePageTableEnable))] + mov dl, byte [rdx] + cmp dl, 0 + jz SkipPagetableSave + + add rsp, 32 + ; Save EFER MSR + push rcx + push rax + mov rcx, 0xC0000080 + rdmsr + shl rdx, 0x20 + or rdx, rax + pop rax + pop rcx + push rdx + + ; Save CR registers + mov rdx, cr4 + push rdx + mov rdx, cr3 + push rdx + mov rdx, cr0 + push rdx +SkipPagetableSave: + sub rsp, 16 sidt [rsp] @@ -68,6 +105,76 @@ ASM_PFX(FspSwitchStack): ; Restore previous contexts lidt [rsp] add rsp, 16 + + lea rax, [ASM_PFX(FeaturePcdGet (PcdFspSaveRestorePageTableEnable))] + mov al, byte [rax] + cmp al, 0 + jz SkipPagetableRestore + ; [rsp] stores new cr0 + ; [rsp+8] stores new cr3 + ; [rsp+16] stores new cr4 + ; [rsp+24] stores new Efer + ; + ; When new EFER.NXE == 1, the restore flow is: EFER --> CRx + ; Otherwise: CRx --> EFER + ; + ; If NXE bit is changed to 1, change NXE before CR register + ; This is because Nx bit in page table entry in new CR3 will be invalid + ; if updating CR3 before EFER MSR. + ; + mov rax, [rsp + 24] + bt rax, 11 + jnc SkipEferLabel1 + + ; Restore EFER MSR + mov ecx, 0xC0000080 + rdmsr + and eax, ~EFER_PG_MASK + mov ebx, [rsp + 24] + and ebx, EFER_PG_MASK + or eax, ebx + wrmsr + +SkipEferLabel1: + + mov rbx, [rsp] + mov rdx, cr0 + and rdx, ~CR0_PG_MASK + and rbx, CR0_PG_MASK + or rdx, rbx + mov cr0, rdx + + mov rbx, [rsp + 8] + mov cr3, rbx + + mov rbx, [rsp + 16] + mov rdx, cr4 + and rdx, ~CR4_PG_MASK + and rbx, CR4_PG_MASK + or rdx, rbx + mov cr4, rdx + + ; + ; If NXE bit is changed to 0, change NXE after than CR regiser + ; + mov rax, [rsp + 24] + bt rax, 11 + jc SkipEferLabel2 + + ; Restore EFER MSR + mov ecx, 0xC0000080 + rdmsr + and eax, ~EFER_PG_MASK + mov ebx, [rsp + 24] + and ebx, EFER_PG_MASK + or eax, ebx + wrmsr + +SkipEferLabel2: +SkipPagetableRestore: + ; pop page table related registers. + add rsp, 32 + POPA_64 popfq add rsp, 32 ; FspInfoHeader + ApiParam[2] + Reserved QWORD