/** @file
Copyright (c) 2014 - 2022, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include
#include
#include
#include
#include
#include
#include
#pragma pack(1)
//
// API Parameter +0x34
// API return address +0x30
//
// push FspInfoHeader +0x2C
// pushfd +0x28
// cli
// pushad +0x24
// sub esp, 8 +0x00
// sidt fword ptr [esp]
//
typedef struct {
UINT16 IdtrLimit;
UINT32 IdtrBase;
UINT16 Reserved;
UINT32 Registers[8]; // General Purpose Registers: Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx and Eax
UINT16 Flags[2];
UINT32 FspInfoHeader;
UINT32 ApiRet;
UINT32 ApiParam[2];
} CONTEXT_STACK;
//
// API return address +0xB8
// Reserved +0xB0
// push API Parameter2 +0xA8
// push API Parameter1 +0xA0
// push FspInfoHeader +0x98
// pushfq +0x90
// cli
// PUSHA_64 +0x10
// sub rsp, 16 +0x00
// sidt [rsp]
//
typedef struct {
UINT64 Idtr[2]; // IDTR Limit - bit0:bi15, IDTR Base - bit16:bit79
UINT64 Registers[16]; // General Purpose Registers: RDI, RSI, RBP, RSP, RBX, RDX, RCX, RAX, and R15 to R8
UINT32 Flags[2];
UINT64 FspInfoHeader;
UINT64 ApiParam[2];
UINT64 Reserved; // The reserved QWORD is needed for stack alignment in X64.
UINT64 ApiRet; // 64bit stack format is different from the 32bit one due to x64 calling convention
} CONTEXT_STACK_64;
#define CONTEXT_STACK_OFFSET(x) (sizeof(UINTN) == sizeof (UINT32) ? (UINTN)&((CONTEXT_STACK *)(UINTN)0)->x : (UINTN)&((CONTEXT_STACK_64 *)(UINTN)0)->x)
#pragma pack()
/**
This function sets the FSP global data pointer.
@param[in] FspData FSP global data pointer.
**/
VOID
EFIAPI
SetFspGlobalDataPointer (
IN FSP_GLOBAL_DATA *FspData
)
{
ASSERT (FspData != NULL);
*((volatile UINT32 *)(UINTN)PcdGet32 (PcdGlobalDataPointerAddress)) = (UINT32)(UINTN)FspData;
}
/**
This function gets the FSP global data pointer.
**/
FSP_GLOBAL_DATA *
EFIAPI
GetFspGlobalDataPointer (
VOID
)
{
FSP_GLOBAL_DATA *FspData;
FspData = *(FSP_GLOBAL_DATA **)(UINTN)PcdGet32 (PcdGlobalDataPointerAddress);
return FspData;
}
/**
This function gets back the FSP API first parameter passed by the bootloader.
@retval ApiParameter FSP API first parameter passed by the bootloader.
**/
UINTN
EFIAPI
GetFspApiParameter (
VOID
)
{
FSP_GLOBAL_DATA *FspData;
FspData = GetFspGlobalDataPointer ();
return *(UINTN *)(FspData->CoreStack + CONTEXT_STACK_OFFSET (ApiParam[0]));
}
/**
This function returns the FSP entry stack pointer from address of the first API parameter.
@retval FSP entry stack pointer.
**/
VOID *
EFIAPI
GetFspEntryStack (
VOID
)
{
FSP_GLOBAL_DATA *FspData;
FspData = GetFspGlobalDataPointer ();
return (VOID *)(FspData->CoreStack + CONTEXT_STACK_OFFSET (ApiParam[0]));
}
/**
This function gets back the FSP API second parameter passed by the bootloader.
@retval ApiParameter FSP API second parameter passed by the bootloader.
**/
UINTN
EFIAPI
GetFspApiParameter2 (
VOID
)
{
FSP_GLOBAL_DATA *FspData;
FspData = GetFspGlobalDataPointer ();
return *(UINTN *)(FspData->CoreStack + CONTEXT_STACK_OFFSET (ApiParam[1]));
}
/**
This function sets the FSP API parameter in the stack.
@param[in] Value New parameter value.
**/
VOID
EFIAPI
SetFspApiParameter (
IN UINT32 Value
)
{
FSP_GLOBAL_DATA *FspData;
FspData = GetFspGlobalDataPointer ();
*(UINTN *)(FspData->CoreStack + CONTEXT_STACK_OFFSET (ApiParam)) = Value;
}
/**
This function set the API status code returned to the BootLoader.
@param[in] ReturnStatus Status code to return.
**/
VOID
EFIAPI
SetFspApiReturnStatus (
IN UINTN ReturnStatus
)
{
FSP_GLOBAL_DATA *FspData;
FspData = GetFspGlobalDataPointer ();
*(UINTN *)(FspData->CoreStack + CONTEXT_STACK_OFFSET (Registers[7])) = ReturnStatus;
}
/**
This function sets the context switching stack to a new stack frame.
@param[in] NewStackTop New core stack to be set.
**/
VOID
EFIAPI
SetFspCoreStackPointer (
IN VOID *NewStackTop
)
{
FSP_GLOBAL_DATA *FspData;
UINTN *OldStack;
UINTN *NewStack;
UINT32 StackContextLen;
FspData = GetFspGlobalDataPointer ();
StackContextLen = sizeof (CONTEXT_STACK) / sizeof (UINTN);
//
// Reserve space for the ContinuationFunc two parameters
//
OldStack = (UINTN *)FspData->CoreStack;
NewStack = (UINTN *)NewStackTop - StackContextLen - 2;
FspData->CoreStack = (UINTN)NewStack;
while (StackContextLen-- != 0) {
*NewStack++ = *OldStack++;
}
}
/**
This function sets the platform specific data pointer.
@param[in] PlatformData FSP platform specific data pointer.
**/
VOID
EFIAPI
SetFspPlatformDataPointer (
IN VOID *PlatformData
)
{
FSP_GLOBAL_DATA *FspData;
FspData = GetFspGlobalDataPointer ();
FspData->PlatformData.DataPtr = PlatformData;
}
/**
This function gets the platform specific data pointer.
@param[in] PlatformData FSP platform specific data pointer.
**/
VOID *
EFIAPI
GetFspPlatformDataPointer (
VOID
)
{
FSP_GLOBAL_DATA *FspData;
FspData = GetFspGlobalDataPointer ();
return FspData->PlatformData.DataPtr;
}
/**
This function sets the UPD data pointer.
@param[in] UpdDataPtr UPD data pointer.
**/
VOID
EFIAPI
SetFspUpdDataPointer (
IN VOID *UpdDataPtr
)
{
FSP_GLOBAL_DATA *FspData;
//
// Get the FSP Global Data Pointer
//
FspData = GetFspGlobalDataPointer ();
//
// Set the UPD pointer.
//
FspData->UpdDataPtr = UpdDataPtr;
}
/**
This function gets the UPD data pointer.
@return UpdDataPtr UPD data pointer.
**/
VOID *
EFIAPI
GetFspUpdDataPointer (
VOID
)
{
FSP_GLOBAL_DATA *FspData;
FspData = GetFspGlobalDataPointer ();
return FspData->UpdDataPtr;
}
/**
This function sets the FspMemoryInit UPD data pointer.
@param[in] MemoryInitUpdPtr FspMemoryInit UPD data pointer.
**/
VOID
EFIAPI
SetFspMemoryInitUpdDataPointer (
IN VOID *MemoryInitUpdPtr
)
{
FSP_GLOBAL_DATA *FspData;
//
// Get the FSP Global Data Pointer
//
FspData = GetFspGlobalDataPointer ();
//
// Set the FspMemoryInit UPD pointer.
//
FspData->MemoryInitUpdPtr = MemoryInitUpdPtr;
}
/**
This function gets the FspMemoryInit UPD data pointer.
@return FspMemoryInit UPD data pointer.
**/
VOID *
EFIAPI
GetFspMemoryInitUpdDataPointer (
VOID
)
{
FSP_GLOBAL_DATA *FspData;
FspData = GetFspGlobalDataPointer ();
return FspData->MemoryInitUpdPtr;
}
/**
This function sets the FspSiliconInit UPD data pointer.
@param[in] SiliconInitUpdPtr FspSiliconInit UPD data pointer.
**/
VOID
EFIAPI
SetFspSiliconInitUpdDataPointer (
IN VOID *SiliconInitUpdPtr
)
{
FSP_GLOBAL_DATA *FspData;
//
// Get the FSP Global Data Pointer
//
FspData = GetFspGlobalDataPointer ();
//
// Set the FspSiliconInit UPD data pointer.
//
FspData->SiliconInitUpdPtr = SiliconInitUpdPtr;
}
/**
This function gets the FspSiliconInit UPD data pointer.
@return FspSiliconInit UPD data pointer.
**/
VOID *
EFIAPI
GetFspSiliconInitUpdDataPointer (
VOID
)
{
FSP_GLOBAL_DATA *FspData;
FspData = GetFspGlobalDataPointer ();
return FspData->SiliconInitUpdPtr;
}
/**
This function sets the FspSmmInit UPD data pointer.
@param[in] SmmInitUpdPtr FspSmmInit UPD data pointer.
**/
VOID
EFIAPI
SetFspSmmInitUpdDataPointer (
IN VOID *SmmInitUpdPtr
)
{
FSP_GLOBAL_DATA *FspData;
//
// Get the FSP Global Data Pointer
//
FspData = GetFspGlobalDataPointer ();
//
// Set the FspSmmInit UPD data pointer.
//
FspData->SmmInitUpdPtr = SmmInitUpdPtr;
}
/**
This function gets the FspSmmInit UPD data pointer.
@return FspSmmInit UPD data pointer.
**/
VOID *
EFIAPI
GetFspSmmInitUpdDataPointer (
VOID
)
{
FSP_GLOBAL_DATA *FspData;
FspData = GetFspGlobalDataPointer ();
return FspData->SmmInitUpdPtr;
}
/**
Set FSP measurement point timestamp.
@param[in] Id Measurement point ID.
@return performance timestamp if current PerfIdx is valid,
else return 0 as invalid performance timestamp
**/
UINT64
EFIAPI
SetFspMeasurePoint (
IN UINT8 Id
)
{
FSP_GLOBAL_DATA *FspData;
//
// Bit [55: 0] will be the timestamp
// Bit [63:56] will be the ID
//
FspData = GetFspGlobalDataPointer ();
if (FspData->PerfIdx < sizeof (FspData->PerfData) / sizeof (FspData->PerfData[0])) {
FspData->PerfData[FspData->PerfIdx] = AsmReadTsc ();
((UINT8 *)(&FspData->PerfData[FspData->PerfIdx]))[7] = Id;
return FspData->PerfData[(FspData->PerfIdx)++];
}
return 0;
}
/**
This function gets the FSP info header pointer.
@retval FspInfoHeader FSP info header pointer
**/
FSP_INFO_HEADER *
EFIAPI
GetFspInfoHeader (
VOID
)
{
return GetFspGlobalDataPointer ()->FspInfoHeader;
}
/**
This function sets the FSP info header pointer.
@param[in] FspInfoHeader FSP info header pointer
**/
VOID
EFIAPI
SetFspInfoHeader (
FSP_INFO_HEADER *FspInfoHeader
)
{
GetFspGlobalDataPointer ()->FspInfoHeader = FspInfoHeader;
}
/**
This function gets the FSP info header pointer using the API stack context.
@retval FspInfoHeader FSP info header pointer using the API stack context
**/
FSP_INFO_HEADER *
EFIAPI
GetFspInfoHeaderFromApiContext (
VOID
)
{
FSP_GLOBAL_DATA *FspData;
FspData = GetFspGlobalDataPointer ();
return (FSP_INFO_HEADER *)(*(UINTN *)(FspData->CoreStack + CONTEXT_STACK_OFFSET (FspInfoHeader)));
}
/**
This function gets the CfgRegion data pointer.
@return CfgRegion data pointer.
**/
VOID *
EFIAPI
GetFspCfgRegionDataPointer (
VOID
)
{
FSP_INFO_HEADER *FspInfoHeader;
FspInfoHeader = GetFspInfoHeader ();
return (VOID *)(UINTN)(FspInfoHeader->ImageBase + FspInfoHeader->CfgRegionOffset);
}
/**
This function gets FSP API calling index.
@retval API calling index
**/
UINT8
EFIAPI
GetFspApiCallingIndex (
VOID
)
{
return GetFspGlobalDataPointer ()->ApiIdx;
}
/**
This function sets FSP API calling mode.
@param[in] Index API calling index
**/
VOID
EFIAPI
SetFspApiCallingIndex (
UINT8 Index
)
{
FSP_GLOBAL_DATA *FspData;
FspData = GetFspGlobalDataPointer ();
FspData->ApiIdx = Index;
}
/**
This function gets FSP Phase StatusCode.
@retval StatusCode
**/
UINT32
EFIAPI
GetPhaseStatusCode (
VOID
)
{
return GetFspGlobalDataPointer ()->StatusCode;
}
/**
This function sets FSP Phase StatusCode.
@param[in] Mode Phase StatusCode
**/
VOID
EFIAPI
SetPhaseStatusCode (
UINT32 StatusCode
)
{
FSP_GLOBAL_DATA *FspData;
FspData = GetFspGlobalDataPointer ();
FspData->StatusCode = StatusCode;
}
/**
This function updates the return status of the FSP API with requested reset type and returns to Boot Loader.
@param[in] FspResetType Reset type that needs to returned as API return status
**/
VOID
EFIAPI
FspApiReturnStatusReset (
IN EFI_STATUS FspResetType
)
{
volatile BOOLEAN LoopUntilReset;
LoopUntilReset = TRUE;
DEBUG ((DEBUG_INFO, "FSP returning control to Bootloader with reset required return status %x\n", FspResetType));
if (GetFspGlobalDataPointer ()->FspMode == FSP_IN_API_MODE) {
///
/// Below code is not an infinite loop.The control will go back to API calling function in BootLoader each time BootLoader
/// calls the FSP API without honoring the reset request by FSP
///
do {
SetFspApiReturnStatus (FspResetType);
Pei2LoaderSwitchStack ();
DEBUG ((DEBUG_ERROR, "!!!ERROR: FSP has requested BootLoader for reset. But BootLoader has not honored the reset\n"));
DEBUG ((DEBUG_ERROR, "!!!ERROR: Please add support in BootLoader to honor the reset request from FSP\n"));
} while (LoopUntilReset);
}
}