audk/IntelFsp2Pkg/FspSecCore/Ia32/FspApiEntryM.nasm
Zhiguang Liu 14c9ba1a2c 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>
2024-09-11 05:45:54 +00:00

304 lines
8.1 KiB
NASM

;; @file
; Provide FSP API entry points.
;
; Copyright (c) 2016 - 2022, Intel Corporation. All rights reserved.<BR>
; SPDX-License-Identifier: BSD-2-Clause-Patent
;;
SECTION .text
;
; Following are fixed PCDs
;
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 {
.FspUpdHeader: resd 8
; }
; FSPM_ARCH_UPD {
.Revision: resb 1
.Reserved: resb 3
.NvsBufferPtr: resd 1
.StackBase: resd 1
.StackSize: resd 1
.BootLoaderTolumSize: resd 1
.BootMode: resd 1
.Reserved1: resb 8
; }
.size:
endstruc
struc FSPM_UPD_COMMON_FSP24
; FSP_UPD_HEADER {
.FspUpdHeader: resd 8
; }
; FSPM_ARCH2_UPD {
.Revision: resb 1
.Reserved: resb 3
.Length resd 1
.NvsBufferPtr resq 1
.StackBase: resq 1
.StackSize: resq 1
.BootLoaderTolumSize: resd 1
.BootMode: resd 1
.FspEventHandler resq 1
.Reserved1: resb 16
; }
.size:
endstruc
;
; Following functions will be provided in C
;
extern ASM_PFX(SecStartup)
extern ASM_PFX(FspApiCommon)
;
; Following functions will be provided in PlatformSecLib
;
extern ASM_PFX(AsmGetFspBaseAddress)
extern ASM_PFX(AsmGetFspInfoHeader)
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
;----------------------------------------------------------------------------
; FspMemoryInit API
;
; This FSP API is called after TempRamInit and initializes the memory.
;
;----------------------------------------------------------------------------
global ASM_PFX(FspMemoryInitApi)
ASM_PFX(FspMemoryInitApi):
mov eax, 3 ; FSP_API_INDEX.FspMemoryInitApiIndex
jmp ASM_PFX(FspApiCommon)
;----------------------------------------------------------------------------
; TempRamExitApi API
;
; This API tears down temporary RAM
;
;----------------------------------------------------------------------------
global ASM_PFX(TempRamExitApi)
ASM_PFX(TempRamExitApi):
mov eax, 4 ; FSP_API_INDEX.TempRamExitApiIndex
jmp ASM_PFX(FspApiCommon)
;----------------------------------------------------------------------------
; FspApiCommonContinue API
;
; This is the FSP API common entry point to resume the FSP execution
;
;----------------------------------------------------------------------------
global ASM_PFX(FspApiCommonContinue)
ASM_PFX(FspApiCommonContinue):
;
; EAX holds the API index
;
;
; FspMemoryInit API setup the initial stack frame
;
;
; Place holder to store the FspInfoHeader pointer
;
push eax
;
; Update the FspInfoHeader pointer
;
push eax
call ASM_PFX(AsmGetFspInfoHeader)
mov [esp + 4], eax
pop eax
;
; Create a Task Frame in the stack for the Boot Loader
;
pushfd ; 2 pushf for 4 byte alignment
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]
; Get Stackbase and StackSize from FSPM_UPD Param
mov edx, [esp + API_PARAM1_OFFSET]
cmp edx, 0
jnz FspStackSetup
; Get UPD default values if FspmUpdDataPtr (ApiParam1) is null
push eax
call ASM_PFX(AsmGetFspInfoHeader)
mov edx, [eax + FSP_HEADER_IMGBASE_OFFSET]
add edx, [eax + FSP_HEADER_CFGREG_OFFSET]
pop eax
FspStackSetup:
mov ecx, [edx + FSPM_UPD_COMMON.Revision]
cmp ecx, 3
jae FspmUpdCommon2
;
; StackBase = temp memory base, StackSize = temp memory size
;
mov edi, [edx + FSPM_UPD_COMMON.StackBase]
mov ecx, [edx + FSPM_UPD_COMMON.StackSize]
jmp ChkFspHeapSize
FspmUpdCommon2:
mov edi, [edx + FSPM_UPD_COMMON_FSP24.StackBase]
mov ecx, [edx + FSPM_UPD_COMMON_FSP24.StackSize]
ChkFspHeapSize:
;
; Keep using bootloader stack if heap size % is 0
;
mov bl, BYTE [ASM_PFX(PcdGet8 (PcdFspHeapSizePercentage))]
cmp bl, 0
jz SkipStackSwitch
;
; Set up a dedicated temp ram stack for FSP if FSP heap size % doesn't equal 0
;
add edi, ecx
;
; Switch to new FSP stack
;
xchg edi, esp ; Exchange edi and esp, edi will be assigned to the current esp pointer and esp will be Stack base + Stack size
SkipStackSwitch:
;
; If heap size % is 0:
; EDI is FSPM_UPD_COMMON.StackBase and will hold ESP later (boot loader stack pointer)
; ECX is FSPM_UPD_COMMON.StackSize
; ESP is boot loader stack pointer (no stack switch)
; BL is 0 to indicate no stack switch (EBX will hold FSPM_UPD_COMMON.StackBase later)
;
; If heap size % is not 0
; EDI is boot loader stack pointer
; ECX is FSPM_UPD_COMMON.StackSize
; ESP is new stack (FSPM_UPD_COMMON.StackBase + FSPM_UPD_COMMON.StackSize)
; BL is NOT 0 to indicate stack has switched
;
cmp bl, 0
jnz StackHasBeenSwitched
mov ebx, edi ; Put FSPM_UPD_COMMON.StackBase to ebx as temp memory base
mov edi, esp ; Put boot loader stack pointer to edi
jmp StackSetupDone
StackHasBeenSwitched:
mov ebx, esp ; Put Stack base + Stack size in ebx
sub ebx, ecx ; Stack base + Stack size - Stack size as temp memory base
StackSetupDone:
;
; Pass the API Idx to SecStartup
;
push eax
;
; Pass the BootLoader stack to SecStartup
;
push edi
;
; Pass entry point of the PEI core
;
call ASM_PFX(AsmGetFspBaseAddress)
mov edi, eax
call ASM_PFX(AsmGetPeiCoreOffset)
add edi, eax
push edi
;
; Pass BFV into the PEI Core
; It uses relative address to calculate the actual boot FV base
; For FSP implementation with single FV, PcdFspBootFirmwareVolumeBase and
; PcdFspAreaBaseAddress are the same. For FSP with multiple FVs,
; they are different. The code below can handle both cases.
;
call ASM_PFX(AsmGetFspBaseAddress)
push eax
;
; Pass stack base and size into the PEI Core
;
push ebx
push ecx
;
; Pass Control into the PEI Core
;
call ASM_PFX(SecStartup)
add esp, 4
exit:
ret
global ASM_PFX(FspPeiCoreEntryOff)
ASM_PFX(FspPeiCoreEntryOff):
;
; This value will be patched by the build script
;
DD 0x12345678
global ASM_PFX(AsmGetPeiCoreOffset)
ASM_PFX(AsmGetPeiCoreOffset):
mov eax, dword [ASM_PFX(FspPeiCoreEntryOff)]
ret
;----------------------------------------------------------------------------
; TempRamInit API
;
; Empty function for WHOLEARCHIVE build option
;
;----------------------------------------------------------------------------
global ASM_PFX(TempRamInitApi)
ASM_PFX(TempRamInitApi):
jmp $
ret
;----------------------------------------------------------------------------
; Module Entrypoint API
;----------------------------------------------------------------------------
global ASM_PFX(_ModuleEntryPoint)
ASM_PFX(_ModuleEntryPoint):
jmp $