mirror of
https://github.com/acidanthera/audk.git
synced 2025-08-18 16:18: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>
304 lines
8.1 KiB
NASM
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 $
|