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>
This commit is contained in:
Zhiguang Liu 2024-06-18 16:13:12 +08:00 committed by mergify[bot]
parent 9a4088777f
commit 14c9ba1a2c
11 changed files with 382 additions and 30 deletions

View File

@ -69,6 +69,7 @@
gIntelFsp2PkgTokenSpaceGuid.PcdFspHeapSizePercentage ## CONSUMES
gIntelFsp2PkgTokenSpaceGuid.PcdFspMaxInterruptSupported ## CONSUMES
gIntelFsp2PkgTokenSpaceGuid.PcdFspPrivateTemporaryRamSize ## CONSUMES
gIntelFsp2PkgTokenSpaceGuid.PcdFspSaveRestorePageTableEnable ## CONSUMES
[Ppis]
gEfiTemporaryRamSupportPpiGuid ## PRODUCES

View File

@ -68,6 +68,7 @@
gIntelFsp2PkgTokenSpaceGuid.PcdFspHeapSizePercentage ## CONSUMES
gIntelFsp2PkgTokenSpaceGuid.PcdFspMaxInterruptSupported ## CONSUMES
gIntelFsp2PkgTokenSpaceGuid.PcdFspPrivateTemporaryRamSize ## CONSUMES
gIntelFsp2PkgTokenSpaceGuid.PcdFspSaveRestorePageTableEnable ## CONSUMES
[Ppis]
gEfiTemporaryRamSupportPpiGuid ## PRODUCES

View File

@ -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]

View File

@ -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]

View File

@ -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]

View File

@ -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]

View File

@ -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

View File

@ -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;

View File

@ -32,5 +32,5 @@
BaseLib
IoLib
[Pcd]
gIntelFsp2PkgTokenSpaceGuid.PcdFspSaveRestorePageTableEnable

View File

@ -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

View File

@ -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