summaryrefslogtreecommitdiffstats
path: root/IntelFsp2Pkg
diff options
context:
space:
mode:
authorZhiguang Liu <zhiguang.liu@intel.com>2024-06-18 16:13:12 +0800
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>2024-09-11 05:45:54 +0000
commit14c9ba1a2ca64137de148968823dc20988dcaa4c (patch)
treeeb72fb06f97a282a9b9a97bea54301c57c7d6e45 /IntelFsp2Pkg
parent9a4088777fbe7941664ad9bb2bd78446d223cbf9 (diff)
downloadedk2-14c9ba1a2ca64137de148968823dc20988dcaa4c.tar.gz
edk2-14c9ba1a2ca64137de148968823dc20988dcaa4c.tar.bz2
edk2-14c9ba1a2ca64137de148968823dc20988dcaa4c.zip
IntelFsp2Pkg: Support FSP API to save and restore page table
A potential issue may happen when FSP creates/changes page table while bootloader doesn't expect page table being changed in FSP. Current, FSP API support to save/restore stack, IDT and general purpose registers. Following the same pattern, add save/restore page table support to solve this issue. Note that this feature only impacts FSP API mode, and is controlled by PCD PcdFspSaveRestorePageTableEnable. For compatibility, the PCD default value is set as FALSE. Signed-off-by: Zhiguang Liu <zhiguang.liu@intel.com>
Diffstat (limited to 'IntelFsp2Pkg')
-rw-r--r--IntelFsp2Pkg/FspSecCore/Fsp24SecCoreM.inf1
-rw-r--r--IntelFsp2Pkg/FspSecCore/FspSecCoreM.inf1
-rw-r--r--IntelFsp2Pkg/FspSecCore/Ia32/Fsp24ApiEntryM.nasm30
-rw-r--r--IntelFsp2Pkg/FspSecCore/Ia32/FspApiEntryM.nasm30
-rw-r--r--IntelFsp2Pkg/FspSecCore/X64/Fsp24ApiEntryM.nasm33
-rw-r--r--IntelFsp2Pkg/FspSecCore/X64/FspApiEntryM.nasm33
-rw-r--r--IntelFsp2Pkg/IntelFsp2Pkg.dec8
-rw-r--r--IntelFsp2Pkg/Library/BaseFspCommonLib/FspCommonLib.c31
-rw-r--r--IntelFsp2Pkg/Library/BaseFspSwitchStackLib/BaseFspSwitchStackLib.inf4
-rw-r--r--IntelFsp2Pkg/Library/BaseFspSwitchStackLib/Ia32/Stack.nasm132
-rw-r--r--IntelFsp2Pkg/Library/BaseFspSwitchStackLib/X64/Stack.nasm109
11 files changed, 382 insertions, 30 deletions
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.<BR>
; 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.<BR>
; 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