--- /dev/null
+;; @file\r
+; Provide FSP API entry points.\r
+;\r
+; Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>\r
+; SPDX-License-Identifier: BSD-2-Clause-Patent\r
+;;\r
+\r
+ SECTION .text\r
+\r
+%include "PushPopRegsNasm.inc"\r
+\r
+;\r
+; Following are fixed PCDs\r
+;\r
+extern ASM_PFX(PcdGet8 (PcdFspHeapSizePercentage))\r
+\r
+struc FSPM_UPD_COMMON_FSP24\r
+ ; FSP_UPD_HEADER {\r
+ .FspUpdHeader: resd 8\r
+ ; }\r
+ ; FSPM_ARCH2_UPD {\r
+ .Revision: resb 1\r
+ .Reserved: resb 3\r
+ .Length resd 1\r
+ .StackBase: resq 1\r
+ .StackSize: resq 1\r
+ .BootLoaderTolumSize: resd 1\r
+ .BootMode: resd 1\r
+ .FspEventHandler resq 1\r
+ .Reserved1: resb 24\r
+ ; }\r
+ .size:\r
+endstruc\r
+\r
+;\r
+; Following functions will be provided in C\r
+;\r
+extern ASM_PFX(SecStartup)\r
+extern ASM_PFX(FspApiCommon)\r
+\r
+;\r
+; Following functions will be provided in PlatformSecLib\r
+;\r
+extern ASM_PFX(AsmGetFspBaseAddress)\r
+extern ASM_PFX(AsmGetFspInfoHeader)\r
+\r
+FSP_HEADER_IMGBASE_OFFSET EQU 1Ch\r
+FSP_HEADER_CFGREG_OFFSET EQU 24h\r
+\r
+;----------------------------------------------------------------------------\r
+; FspMemoryInit API\r
+;\r
+; This FSP API is called after TempRamInit and initializes the memory.\r
+;\r
+;----------------------------------------------------------------------------\r
+global ASM_PFX(FspMemoryInitApi)\r
+ASM_PFX(FspMemoryInitApi):\r
+ mov eax, 3 ; FSP_API_INDEX.FspMemoryInitApiIndex\r
+ jmp ASM_PFX(FspApiCommon)\r
+\r
+;----------------------------------------------------------------------------\r
+; TempRamExitApi API\r
+;\r
+; This API tears down temporary RAM\r
+;\r
+;----------------------------------------------------------------------------\r
+global ASM_PFX(TempRamExitApi)\r
+ASM_PFX(TempRamExitApi):\r
+ mov eax, 4 ; FSP_API_INDEX.TempRamExitApiIndex\r
+ jmp ASM_PFX(FspApiCommon)\r
+\r
+;----------------------------------------------------------------------------\r
+; FspApiCommonContinue API\r
+;\r
+; This is the FSP API common entry point to resume the FSP execution\r
+;\r
+;----------------------------------------------------------------------------\r
+global ASM_PFX(FspApiCommonContinue)\r
+ASM_PFX(FspApiCommonContinue):\r
+ ;\r
+ ; RAX holds the API index\r
+ ; Push RDX and RCX to form CONTEXT_STACK_64\r
+ ;\r
+ push rdx ; Push a QWORD data for stack alignment\r
+ push rdx ; Push API Parameter2 on stack\r
+ push rcx ; Push API Parameter1 on stack\r
+\r
+ ;\r
+ ; FspMemoryInit API setup the initial stack frame\r
+ ;\r
+\r
+ ;\r
+ ; Place holder to store the FspInfoHeader pointer\r
+ ;\r
+ push rax\r
+\r
+ ;\r
+ ; Update the FspInfoHeader pointer\r
+ ;\r
+ push rax\r
+ call ASM_PFX(AsmGetFspInfoHeader)\r
+ mov [rsp + 8], rax\r
+ pop rax\r
+\r
+ ;\r
+ ; Create a Task Frame in the stack for the Boot Loader\r
+ ;\r
+ pushfq\r
+ cli\r
+ PUSHA_64\r
+\r
+ ; Reserve 16 bytes for IDT save/restore\r
+ sub rsp, 16\r
+ sidt [rsp]\r
+\r
+ ; Get Stackbase and StackSize from FSPM_UPD Param\r
+ mov rdx, rcx ; Put FSPM_UPD Param to rdx\r
+ cmp rdx, 0\r
+ jnz FspStackSetup\r
+\r
+ ; Get UPD default values if FspmUpdDataPtr (ApiParam1) is null\r
+ xchg rbx, rax\r
+ call ASM_PFX(AsmGetFspInfoHeader)\r
+ mov edx, [rax + FSP_HEADER_IMGBASE_OFFSET]\r
+ add edx, [rax + FSP_HEADER_CFGREG_OFFSET]\r
+ xchg rbx, rax\r
+\r
+FspStackSetup:\r
+ mov cl, [rdx + FSPM_UPD_COMMON_FSP24.Revision]\r
+ cmp cl, 3\r
+ jae FspmUpdCommonFsp24\r
+\r
+ mov rax, 08000000000000002h ; RETURN_INVALID_PARAMETER\r
+ sub rsp, 0b8h\r
+ ret\r
+\r
+FspmUpdCommonFsp24:\r
+ ;\r
+ ; StackBase = temp memory base, StackSize = temp memory size\r
+ ;\r
+ mov rdi, [rdx + FSPM_UPD_COMMON_FSP24.StackBase]\r
+ mov ecx, [rdx + FSPM_UPD_COMMON_FSP24.StackSize]\r
+\r
+ ;\r
+ ; Keep using bootloader stack if heap size % is 0\r
+ ;\r
+ mov rbx, ASM_PFX(PcdGet8 (PcdFspHeapSizePercentage))\r
+ mov bl, BYTE [rbx]\r
+ cmp bl, 0\r
+ jz SkipStackSwitch\r
+\r
+ ;\r
+ ; Set up a dedicated temp ram stack for FSP if FSP heap size % doesn't equal 0\r
+ ;\r
+ add rdi, rcx\r
+ ;\r
+ ; Switch to new FSP stack\r
+ ;\r
+ xchg rdi, rsp ; Exchange rdi and rsp, rdi will be assigned to the current rsp pointer and rsp will be Stack base + Stack size\r
+\r
+SkipStackSwitch:\r
+ ;\r
+ ; If heap size % is 0:\r
+ ; EDI is FSPM_UPD_COMMON_FSP24.StackBase and will hold ESP later (boot loader stack pointer)\r
+ ; ECX is FSPM_UPD_COMMON_FSP24.StackSize\r
+ ; ESP is boot loader stack pointer (no stack switch)\r
+ ; BL is 0 to indicate no stack switch (EBX will hold FSPM_UPD_COMMON_FSP24.StackBase later)\r
+ ;\r
+ ; If heap size % is not 0\r
+ ; EDI is boot loader stack pointer\r
+ ; ECX is FSPM_UPD_COMMON_FSP24.StackSize\r
+ ; ESP is new stack (FSPM_UPD_COMMON_FSP24.StackBase + FSPM_UPD_COMMON_FSP24.StackSize)\r
+ ; BL is NOT 0 to indicate stack has switched\r
+ ;\r
+ cmp bl, 0\r
+ jnz StackHasBeenSwitched\r
+\r
+ mov rbx, rdi ; Put FSPM_UPD_COMMON_FSP24.StackBase to rbx as temp memory base\r
+ mov rdi, rsp ; Put boot loader stack pointer to rdi\r
+ jmp StackSetupDone\r
+\r
+StackHasBeenSwitched:\r
+ mov rbx, rsp ; Put Stack base + Stack size in ebx\r
+ sub rbx, rcx ; Stack base + Stack size - Stack size as temp memory base\r
+\r
+StackSetupDone:\r
+\r
+ ;\r
+ ; Per X64 calling convention, make sure RSP is 16-byte aligned.\r
+ ;\r
+ mov rdx, rsp\r
+ and rdx, 0fh\r
+ sub rsp, rdx\r
+\r
+ ;\r
+ ; Pass the API Idx to SecStartup\r
+ ;\r
+ push rax\r
+\r
+ ;\r
+ ; Pass the BootLoader stack to SecStartup\r
+ ;\r
+ push rdi\r
+\r
+ ;\r
+ ; Pass BFV into the PEI Core\r
+ ; It uses relative address to calculate the actual boot FV base\r
+ ; For FSP implementation with single FV, PcdFspBootFirmwareVolumeBase and\r
+ ; PcdFspAreaBaseAddress are the same. For FSP with multiple FVs,\r
+ ; they are different. The code below can handle both cases.\r
+ ;\r
+ call ASM_PFX(AsmGetFspBaseAddress)\r
+ mov r8, rax\r
+\r
+ ;\r
+ ; Pass entry point of the PEI core\r
+ ;\r
+ call ASM_PFX(AsmGetPeiCoreOffset)\r
+ lea r9, [r8 + rax]\r
+\r
+ ;\r
+ ; Pass stack base and size into the PEI Core\r
+ ;\r
+ mov rcx, rcx\r
+ mov rdx, rbx\r
+\r
+ ;\r
+ ; Pass Control into the PEI Core\r
+ ; RCX = SizeOfRam, RDX = TempRamBase, R8 = BFV, R9 = PeiCoreEntry, Last 1 Stack = BL stack, Last 2 Stack = API index\r
+ ; According to X64 calling convention, caller has to allocate 32 bytes as a shadow store on call stack right before\r
+ ; calling the function.\r
+ ;\r
+ sub rsp, 20h\r
+ call ASM_PFX(SecStartup)\r
+ add rsp, 20h\r
+exit:\r
+ ret\r
+\r
+global ASM_PFX(FspPeiCoreEntryOff)\r
+ASM_PFX(FspPeiCoreEntryOff):\r
+ ;\r
+ ; This value will be patched by the build script\r
+ ;\r
+ DD 0x12345678\r
+\r
+global ASM_PFX(AsmGetPeiCoreOffset)\r
+ASM_PFX(AsmGetPeiCoreOffset):\r
+ push rbx\r
+ mov rbx, ASM_PFX(FspPeiCoreEntryOff)\r
+ mov eax, dword[ebx]\r
+ pop rbx\r
+ ret\r
+\r
+;----------------------------------------------------------------------------\r
+; TempRamInit API\r
+;\r
+; Empty function for WHOLEARCHIVE build option\r
+;\r
+;----------------------------------------------------------------------------\r
+global ASM_PFX(TempRamInitApi)\r
+ASM_PFX(TempRamInitApi):\r
+ jmp $\r
+ ret\r
+\r
+;----------------------------------------------------------------------------\r
+; Module Entrypoint API\r
+;----------------------------------------------------------------------------\r
+global ASM_PFX(_ModuleEntryPoint)\r
+ASM_PFX(_ModuleEntryPoint):\r
+ jmp $\r
+\r