gIntelFsp2PkgTokenSpaceGuid.PcdFspHeapSizePercentage ## CONSUMES\r
gIntelFsp2PkgTokenSpaceGuid.PcdFspMaxInterruptSupported ## CONSUMES\r
gIntelFsp2PkgTokenSpaceGuid.PcdFspPrivateTemporaryRamSize ## CONSUMES\r
+ gIntelFsp2PkgTokenSpaceGuid.PcdFspSaveRestorePageTableEnable ## CONSUMES\r
\r
[Ppis]\r
gEfiTemporaryRamSupportPpiGuid ## PRODUCES\r
gIntelFsp2PkgTokenSpaceGuid.PcdFspHeapSizePercentage ## CONSUMES\r
gIntelFsp2PkgTokenSpaceGuid.PcdFspMaxInterruptSupported ## CONSUMES\r
gIntelFsp2PkgTokenSpaceGuid.PcdFspPrivateTemporaryRamSize ## CONSUMES\r
+ gIntelFsp2PkgTokenSpaceGuid.PcdFspSaveRestorePageTableEnable ## CONSUMES\r
\r
[Ppis]\r
gEfiTemporaryRamSupportPpiGuid ## PRODUCES\r
extern ASM_PFX(PcdGet32(PcdTemporaryRamBase))\r
extern ASM_PFX(PcdGet32(PcdFspTemporaryRamSize))\r
extern ASM_PFX(PcdGet8 (PcdFspHeapSizePercentage))\r
+extern ASM_PFX(FeaturePcdGet (PcdFspSaveRestorePageTableEnable))\r
\r
struc FSPM_UPD_COMMON\r
; FSP_UPD_HEADER {\r
extern ASM_PFX(FspMultiPhaseMemInitApiHandler)\r
\r
STACK_SAVED_EAX_OFFSET EQU 4 * 7 ; size of a general purpose register * eax index\r
-API_PARAM1_OFFSET EQU 34h ; ApiParam1 [ sub esp,8 + pushad + pushfd + push eax + call]\r
+API_PARAM1_OFFSET EQU 44h ; ApiParam1 [ sub esp,8 + push cr0/cr3/cr4/EFER + pushad + pushfd + push eax + call]\r
FSP_HEADER_IMGBASE_OFFSET EQU 1Ch\r
FSP_HEADER_CFGREG_OFFSET EQU 24h\r
\r
cli\r
pushad\r
\r
+ ;\r
+ ; Allocate 4x4 bytes on the stack.\r
+ ;\r
+ sub esp, 16\r
+ cmp byte [dword ASM_PFX(FeaturePcdGet (PcdFspSaveRestorePageTableEnable))], 0\r
+ jz SkipPagetableSave\r
+\r
+ add esp, 16\r
+ ; Save EFER MSR lower 32 bits\r
+ push ecx\r
+ push eax\r
+ mov ecx, 0xC0000080\r
+ rdmsr\r
+ mov edx, eax\r
+ pop eax\r
+ pop ecx\r
+ push edx\r
+\r
+ ; Save CR registers\r
+ mov edx, cr4\r
+ push edx\r
+ mov edx, cr3\r
+ push edx\r
+ mov edx, cr0\r
+ push edx\r
+SkipPagetableSave:\r
+\r
; Reserve 8 bytes for IDT save/restore\r
sub esp, 8\r
sidt [esp]\r
extern ASM_PFX(PcdGet32(PcdTemporaryRamBase))\r
extern ASM_PFX(PcdGet32(PcdFspTemporaryRamSize))\r
extern ASM_PFX(PcdGet8 (PcdFspHeapSizePercentage))\r
+extern ASM_PFX(FeaturePcdGet (PcdFspSaveRestorePageTableEnable))\r
\r
struc FSPM_UPD_COMMON\r
; FSP_UPD_HEADER {\r
extern ASM_PFX(AsmGetFspBaseAddress)\r
extern ASM_PFX(AsmGetFspInfoHeader)\r
\r
-API_PARAM1_OFFSET EQU 34h ; ApiParam1 [ sub esp,8 + pushad + pushfd + push eax + call]\r
+API_PARAM1_OFFSET EQU 44h ; ApiParam1 [ sub esp,8 + push cr0/cr3/cr4/EFER +pushad + pushfd + push eax + call]\r
FSP_HEADER_IMGBASE_OFFSET EQU 1Ch\r
FSP_HEADER_CFGREG_OFFSET EQU 24h\r
\r
cli\r
pushad\r
\r
+ ;\r
+ ; Allocate 4x4 bytes on the stack.\r
+ ;\r
+ sub esp, 16\r
+ cmp byte [dword ASM_PFX(FeaturePcdGet (PcdFspSaveRestorePageTableEnable))], 0\r
+ jz SkipPagetableSave\r
+\r
+ add esp, 16\r
+ ; Save EFER MSR lower 32-bit\r
+ push ecx\r
+ push eax\r
+ mov ecx, 0xC0000080\r
+ rdmsr\r
+ mov edx, eax\r
+ pop eax\r
+ pop ecx\r
+ push edx\r
+\r
+ ; Save CR registers\r
+ mov edx, cr4\r
+ push edx\r
+ mov edx, cr3\r
+ push edx\r
+ mov edx, cr0\r
+ push edx\r
+\r
+SkipPagetableSave:\r
; Reserve 8 bytes for IDT save/restore\r
sub esp, 8\r
sidt [esp]\r
; Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>\r
; SPDX-License-Identifier: BSD-2-Clause-Patent\r
;;\r
-\r
+ DEFAULT REL\r
SECTION .text\r
\r
%include "PushPopRegsNasm.inc"\r
; Following are fixed PCDs\r
;\r
extern ASM_PFX(PcdGet8 (PcdFspHeapSizePercentage))\r
+extern ASM_PFX(FeaturePcdGet (PcdFspSaveRestorePageTableEnable))\r
\r
struc FSPM_UPD_COMMON_FSP24\r
; FSP_UPD_HEADER {\r
cli\r
PUSHA_64\r
\r
+ ;\r
+ ; Allocate 4x8 bytes on the stack.\r
+ ;\r
+ sub rsp, 32\r
+ lea rdx, [ASM_PFX(FeaturePcdGet (PcdFspSaveRestorePageTableEnable))]\r
+ mov dl, byte [rdx]\r
+ cmp dl, 0\r
+ jz SkipPagetableSave\r
+\r
+ add rsp, 32\r
+ ; Save EFER MSR\r
+ push rcx\r
+ push rax\r
+ mov rcx, 0xC0000080\r
+ rdmsr\r
+ shl rdx, 0x20\r
+ or rdx, rax\r
+ pop rax\r
+ pop rcx\r
+ push rdx\r
+\r
+ ; Save CR registers\r
+ mov rdx, cr4\r
+ push rdx\r
+ mov rdx, cr3\r
+ push rdx\r
+ mov rdx, cr0\r
+ push rdx\r
+SkipPagetableSave:\r
+\r
; Reserve 16 bytes for IDT save/restore\r
sub rsp, 16\r
sidt [rsp]\r
; Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>\r
; SPDX-License-Identifier: BSD-2-Clause-Patent\r
;;\r
-\r
+ DEFAULT REL\r
SECTION .text\r
\r
%include "PushPopRegsNasm.inc"\r
; Following are fixed PCDs\r
;\r
extern ASM_PFX(PcdGet8 (PcdFspHeapSizePercentage))\r
+extern ASM_PFX(FeaturePcdGet (PcdFspSaveRestorePageTableEnable))\r
\r
struc FSPM_UPD_COMMON_FSP24\r
; FSP_UPD_HEADER {\r
cli\r
PUSHA_64\r
\r
+ ;\r
+ ; Allocate 4x8 bytes on the stack.\r
+ ;\r
+ sub rsp, 32\r
+ lea rdx, [ASM_PFX(FeaturePcdGet (PcdFspSaveRestorePageTableEnable))]\r
+ mov dl, byte [rdx]\r
+ cmp dl, 0\r
+ jz SkipPagetableSave\r
+\r
+ add rsp, 32\r
+ ; Save EFER MSR\r
+ push rcx\r
+ push rax\r
+ mov rcx, 0xC0000080\r
+ rdmsr\r
+ shl rdx, 0x20\r
+ or rdx, rax\r
+ pop rax\r
+ pop rcx\r
+ push rdx\r
+\r
+ ; Save CR registers\r
+ mov rdx, cr4\r
+ push rdx\r
+ mov rdx, cr3\r
+ push rdx\r
+ mov rdx, cr0\r
+ push rdx\r
+SkipPagetableSave:\r
+\r
; Reserve 16 bytes for IDT save/restore\r
sub rsp, 16\r
sidt [rsp]\r
#\r
gIntelFsp2PkgTokenSpaceGuid.PcdFspPrivateTemporaryRamSize |0x00000000|UINT32|0x10000006\r
\r
+[PcdsFeatureFlag]\r
+ #\r
+ # Indicates if the FSP will save and restore page table. Only works in FSP API mode\r
+ # TRUE - FSP will save and restore page table\r
+ # FALSE - FSP will not save and restore page table\r
+ #\r
+ gIntelFsp2PkgTokenSpaceGuid.PcdFspSaveRestorePageTableEnable |FALSE|BOOLEAN|0x10000007\r
+\r
[PcdsFixedAtBuild,PcdsDynamic,PcdsDynamicEx]\r
gIntelFsp2PkgTokenSpaceGuid.PcdFspReservedMemoryLength |0x00100000|UINT32|0x46530000\r
gIntelFsp2PkgTokenSpaceGuid.PcdBootLoaderEntry |0xFFFFFFE4|UINT32|0x46530100\r
\r
#pragma pack(1)\r
\r
-//\r
-// API Parameter +0x34\r
-// API return address +0x30\r
-//\r
-// push FspInfoHeader +0x2C\r
-// pushfd +0x28\r
-// cli\r
-// pushad +0x24\r
-// sub esp, 8 +0x00\r
-// sidt fword ptr [esp]\r
-//\r
typedef struct {\r
UINT16 IdtrLimit;\r
UINT32 IdtrBase;\r
UINT16 Reserved;\r
+ UINT32 Cr0;\r
+ UINT32 Cr3;\r
+ UINT32 Cr4;\r
+ UINT32 Efer; // lower 32-bit of EFER since only NXE bit (BIT11) need to be restored.\r
UINT32 Registers[8]; // General Purpose Registers: Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx and Eax\r
UINT16 Flags[2];\r
UINT32 FspInfoHeader;\r
UINT32 ApiParam[2];\r
} CONTEXT_STACK;\r
\r
-//\r
-// API return address +0xB8\r
-// Reserved +0xB0\r
-// push API Parameter2 +0xA8\r
-// push API Parameter1 +0xA0\r
-// push FspInfoHeader +0x98\r
-// pushfq +0x90\r
-// cli\r
-// PUSHA_64 +0x10\r
-// sub rsp, 16 +0x00\r
-// sidt [rsp]\r
-//\r
typedef struct {\r
UINT64 Idtr[2]; // IDTR Limit - bit0:bi15, IDTR Base - bit16:bit79\r
+ UINT64 Cr0;\r
+ UINT64 Cr3;\r
+ UINT64 Cr4;\r
+ UINT64 Efer;\r
UINT64 Registers[16]; // General Purpose Registers: RDI, RSI, RBP, RSP, RBX, RDX, RCX, RAX, and R15 to R8\r
UINT32 Flags[2];\r
UINT64 FspInfoHeader;\r
BaseLib\r
IoLib\r
\r
-\r
-\r
+[Pcd]\r
+ gIntelFsp2PkgTokenSpaceGuid.PcdFspSaveRestorePageTableEnable\r
SECTION .text\r
\r
extern ASM_PFX(SwapStack)\r
+extern ASM_PFX(FeaturePcdGet (PcdFspSaveRestorePageTableEnable))\r
+\r
+; Page table related bits in CR0/CR4/EFER\r
+%define CR0_PG_MASK 0x80010000 ; CR0.PG and CR0.WP\r
+%define CR4_PG_MASK 0x10B0 ; CR4.PSE, CR4.PAE, CR4.PGE and CR4.LA57\r
+%define EFER_PG_MASK 0x800 ; EFER.NXE\r
\r
;------------------------------------------------------------------------------\r
; UINT32\r
pushfd\r
cli\r
pushad\r
+\r
+ ;\r
+ ; Allocate 4x4 bytes on the stack.\r
+ ;\r
+ sub esp, 16\r
+ cmp byte [dword ASM_PFX(FeaturePcdGet (PcdFspSaveRestorePageTableEnable))], 0\r
+ jz SkipPagetableSave\r
+\r
+ add esp, 16\r
+ ; Save EFER MSR lower 32 bits\r
+ push ecx\r
+ push eax\r
+ mov ecx, 0xC0000080\r
+ rdmsr\r
+ mov edx, eax\r
+ pop eax\r
+ pop ecx\r
+ push edx\r
+\r
+ ; Save CR registers\r
+ mov eax, cr4\r
+ push eax\r
+ mov eax, cr3\r
+ push eax\r
+ mov eax, cr0\r
+ push eax\r
+SkipPagetableSave:\r
+\r
sub esp, 8\r
sidt [esp]\r
\r
; Restore previous contexts\r
lidt [esp]\r
add esp, 8\r
+\r
+ cmp byte [dword ASM_PFX(FeaturePcdGet (PcdFspSaveRestorePageTableEnable))], 0\r
+ jz SkipPagetableRestore\r
+ ; [esp] stores new cr0\r
+ ; [esp+4] stores new cr3\r
+ ; [esp+8] stores new cr4\r
+ ; [esp+12] stores new Efer\r
+ ;\r
+ ; When new EFER.NXE == 1, the restore flow is: EFER --> CRx\r
+ ; Otherwise: CRx --> EFER\r
+ ; When new CR0.PG == 1, the restore flow for CRx is: CR3 --> CR4 --> CR0\r
+ ; Otherwise, the restore flow is: CR0 --> CR3 --> CR4\r
+ ;\r
+ ; If NXE bit is changed to 1, change NXE before CR register\r
+ ; This is because Nx bit in page table entry in new CR3 will be invalid\r
+ ; if updating CR3 before EFER MSR.\r
+ ;\r
+ mov eax, [esp+12]\r
+ bt eax, 11\r
+ jnc SkipEferLabel1\r
+\r
+ ; Restore EFER MSR\r
+ mov ecx, 0xC0000080\r
+ rdmsr\r
+ and eax, ~EFER_PG_MASK\r
+ mov ebx, [esp+12]\r
+ and ebx, EFER_PG_MASK\r
+ or eax, ebx\r
+ wrmsr\r
+\r
+SkipEferLabel1:\r
+\r
+ ;\r
+ ; if new cr0 is to disable page table, change CR0 before CR3/CR4\r
+ ;\r
+ mov eax, [esp]\r
+ bt eax, 31\r
+ jc SkipCr0Label1\r
+\r
+ ; Restore CR0\r
+ mov edx, cr0\r
+ and edx, ~CR0_PG_MASK\r
+ mov eax, [esp]\r
+ and eax, CR0_PG_MASK\r
+ or edx, eax\r
+ mov cr0, edx\r
+\r
+SkipCr0Label1:\r
+\r
+ ; Restore CR3/CR4\r
+ mov eax, [esp+4]\r
+ mov cr3, eax\r
+\r
+ mov edx, cr4\r
+ and edx, ~CR4_PG_MASK\r
+ mov eax, [esp+8]\r
+ and eax, CR4_PG_MASK\r
+ or edx, eax\r
+ mov cr4, edx\r
+\r
+ ;\r
+ ; if new cr0 is to enable page table, change CR0 after CR3/CR4\r
+ ;\r
+ mov eax, [esp]\r
+ bt eax, 31\r
+ jnc SkipCr0Label2\r
+\r
+ ; Restore CR0\r
+ mov edx, cr0\r
+ and edx, ~CR0_PG_MASK\r
+ mov eax, [esp]\r
+ and eax, CR0_PG_MASK\r
+ or edx, eax\r
+ mov cr0, edx\r
+\r
+SkipCr0Label2:\r
+ ;\r
+ ; If NXE bit is changed to 0, change NXE after than CR regiser\r
+ ;\r
+ mov eax, [esp+12]\r
+ bt eax, 11\r
+ jc SkipEferLabel2\r
+\r
+ ; Restore EFER MSR\r
+ mov ecx, 0xC0000080\r
+ rdmsr\r
+ and eax, ~EFER_PG_MASK\r
+ mov ebx, [esp+12]\r
+ and ebx, EFER_PG_MASK\r
+ or eax, ebx\r
+ wrmsr\r
+\r
+SkipEferLabel2:\r
+SkipPagetableRestore:\r
+\r
+ ; pop page table related registers.\r
+ add esp, 16\r
+\r
popad\r
popfd\r
add esp, 4\r
; Switch the stack from temporary memory to permanent memory.\r
;\r
;------------------------------------------------------------------------------\r
-\r
+ DEFAULT REL\r
SECTION .text\r
\r
%include "PushPopRegsNasm.inc"\r
\r
+; Page table related bits in CR0/CR4/EFER\r
+%define CR0_PG_MASK 0x80010000 ; CR0.PG and CR0.WP\r
+%define CR4_PG_MASK 0x10B0 ; CR4.PSE, CR4.PAE, CR4.PGE and CR4.LA57\r
+%define EFER_PG_MASK 0x800 ; EFER.NXE\r
+\r
extern ASM_PFX(SwapStack)\r
+extern ASM_PFX(FeaturePcdGet (PcdFspSaveRestorePageTableEnable))\r
\r
;------------------------------------------------------------------------------\r
; UINT32\r
pushfq\r
cli\r
PUSHA_64\r
+\r
+ ;\r
+ ; Allocate 4x8 bytes on the stack.\r
+ ;\r
+ sub rsp, 32\r
+ lea rdx, [ASM_PFX(FeaturePcdGet (PcdFspSaveRestorePageTableEnable))]\r
+ mov dl, byte [rdx]\r
+ cmp dl, 0\r
+ jz SkipPagetableSave\r
+\r
+ add rsp, 32\r
+ ; Save EFER MSR\r
+ push rcx\r
+ push rax\r
+ mov rcx, 0xC0000080\r
+ rdmsr\r
+ shl rdx, 0x20\r
+ or rdx, rax\r
+ pop rax\r
+ pop rcx\r
+ push rdx\r
+\r
+ ; Save CR registers\r
+ mov rdx, cr4\r
+ push rdx\r
+ mov rdx, cr3\r
+ push rdx\r
+ mov rdx, cr0\r
+ push rdx\r
+SkipPagetableSave:\r
+\r
sub rsp, 16\r
sidt [rsp]\r
\r
; Restore previous contexts\r
lidt [rsp]\r
add rsp, 16\r
+\r
+ lea rax, [ASM_PFX(FeaturePcdGet (PcdFspSaveRestorePageTableEnable))]\r
+ mov al, byte [rax]\r
+ cmp al, 0\r
+ jz SkipPagetableRestore\r
+ ; [rsp] stores new cr0\r
+ ; [rsp+8] stores new cr3\r
+ ; [rsp+16] stores new cr4\r
+ ; [rsp+24] stores new Efer\r
+ ;\r
+ ; When new EFER.NXE == 1, the restore flow is: EFER --> CRx\r
+ ; Otherwise: CRx --> EFER\r
+ ;\r
+ ; If NXE bit is changed to 1, change NXE before CR register\r
+ ; This is because Nx bit in page table entry in new CR3 will be invalid\r
+ ; if updating CR3 before EFER MSR.\r
+ ;\r
+ mov rax, [rsp + 24]\r
+ bt rax, 11\r
+ jnc SkipEferLabel1\r
+\r
+ ; Restore EFER MSR\r
+ mov ecx, 0xC0000080\r
+ rdmsr\r
+ and eax, ~EFER_PG_MASK\r
+ mov ebx, [rsp + 24]\r
+ and ebx, EFER_PG_MASK\r
+ or eax, ebx\r
+ wrmsr\r
+\r
+SkipEferLabel1:\r
+\r
+ mov rbx, [rsp]\r
+ mov rdx, cr0\r
+ and rdx, ~CR0_PG_MASK\r
+ and rbx, CR0_PG_MASK\r
+ or rdx, rbx\r
+ mov cr0, rdx\r
+\r
+ mov rbx, [rsp + 8]\r
+ mov cr3, rbx\r
+\r
+ mov rbx, [rsp + 16]\r
+ mov rdx, cr4\r
+ and rdx, ~CR4_PG_MASK\r
+ and rbx, CR4_PG_MASK\r
+ or rdx, rbx\r
+ mov cr4, rdx\r
+\r
+ ;\r
+ ; If NXE bit is changed to 0, change NXE after than CR regiser\r
+ ;\r
+ mov rax, [rsp + 24]\r
+ bt rax, 11\r
+ jc SkipEferLabel2\r
+\r
+ ; Restore EFER MSR\r
+ mov ecx, 0xC0000080\r
+ rdmsr\r
+ and eax, ~EFER_PG_MASK\r
+ mov ebx, [rsp + 24]\r
+ and ebx, EFER_PG_MASK\r
+ or eax, ebx\r
+ wrmsr\r
+\r
+SkipEferLabel2:\r
+SkipPagetableRestore:\r
+ ; pop page table related registers.\r
+ add rsp, 32\r
+\r
POPA_64\r
popfq\r
add rsp, 32 ; FspInfoHeader + ApiParam[2] + Reserved QWORD\r