mirror of
https://github.com/acidanthera/audk.git
synced 2025-08-17 23:58:12 +02:00
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>
183 lines
4.5 KiB
NASM
183 lines
4.5 KiB
NASM
;------------------------------------------------------------------------------
|
|
;
|
|
; Copyright (c) 2022 - 2023, Intel Corporation. All rights reserved.<BR>
|
|
; SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
;
|
|
; Abstract:
|
|
;
|
|
; 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
|
|
; EFIAPI
|
|
; Pei2LoaderSwitchStack (
|
|
; VOID
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
global ASM_PFX(Pei2LoaderSwitchStack)
|
|
ASM_PFX(Pei2LoaderSwitchStack):
|
|
xor rax, rax
|
|
jmp ASM_PFX(FspSwitchStack)
|
|
|
|
;------------------------------------------------------------------------------
|
|
; UINT32
|
|
; EFIAPI
|
|
; Loader2PeiSwitchStack (
|
|
; VOID
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
global ASM_PFX(Loader2PeiSwitchStack)
|
|
ASM_PFX(Loader2PeiSwitchStack):
|
|
jmp ASM_PFX(FspSwitchStack)
|
|
|
|
;------------------------------------------------------------------------------
|
|
; UINT32
|
|
; EFIAPI
|
|
; FspSwitchStack (
|
|
; VOID
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
global ASM_PFX(FspSwitchStack)
|
|
ASM_PFX(FspSwitchStack):
|
|
; Save current contexts. The format must align with CONTEXT_STACK_64.
|
|
push rdx ; Reserved QWORD for stack alignment
|
|
push rdx ; ApiParam2
|
|
push rcx ; ApiParam1
|
|
push rax ; FspInfoHeader
|
|
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]
|
|
|
|
; Load new stack
|
|
mov rcx, rsp
|
|
sub rsp, 0x20
|
|
call ASM_PFX(SwapStack)
|
|
add rsp, 0x20
|
|
mov rsp, rax
|
|
|
|
; 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
|
|
ret
|
|
|