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