/** @file Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "SecFsp.h" /** Calculate the FSP IDT gate descriptor. @param[in] IdtEntryTemplate IDT gate descriptor template. @return FSP specific IDT gate descriptor. **/ UINT64 FspGetExceptionHandler( IN UINT64 IdtEntryTemplate ) { UINT32 Entry; UINT64 ExceptionHandler; IA32_IDT_GATE_DESCRIPTOR *IdtGateDescriptor; FSP_INFO_HEADER *FspInfoHeader; FspInfoHeader = (FSP_INFO_HEADER *)AsmGetFspInfoHeader(); ExceptionHandler = IdtEntryTemplate; IdtGateDescriptor = (IA32_IDT_GATE_DESCRIPTOR *)&ExceptionHandler; Entry = (IdtGateDescriptor->Bits.OffsetHigh << 16) | IdtGateDescriptor->Bits.OffsetLow; Entry = FspInfoHeader->ImageBase + FspInfoHeader->ImageSize - (~Entry + 1); IdtGateDescriptor->Bits.OffsetHigh = (UINT16)(Entry >> 16); IdtGateDescriptor->Bits.OffsetLow = (UINT16)Entry; return ExceptionHandler; } /** This function gets the FSP UPD region offset in flash. @return the offset of the UPD region. **/ UINT32 EFIAPI GetFspUpdRegionOffset ( VOID ) { FSP_GLOBAL_DATA *FspData; UINT32 *Offset; FspData = GetFspGlobalDataPointer (); // // It is required to put PcdUpdRegionOffset at offset 0x000C // for all FSPs. // gPlatformFspPkgTokenSpaceGuid.PcdUpdRegionOffset | 0x000C | 0x12345678 // Offset = (UINT32 *)(FspData->FspInfoHeader->ImageBase + \ FspData->FspInfoHeader->CfgRegionOffset + 0x0C); return *Offset; } /** This interface fills platform specific data. @param[in,out] FspData Pointer to the FSP global data. **/ VOID EFIAPI SecGetPlatformData ( IN OUT FSP_GLOBAL_DATA *FspData ) { FSP_PLAT_DATA *FspPlatformData; UINT32 TopOfCar; UINT32 *StackPtr; UINT32 DwordSize; FspPlatformData = &FspData->PlatformData; // // The entries of platform information, together with the number of them, // reside in the bottom of stack, left untouched by normal stack operation. // TopOfCar = PcdGet32 (PcdTemporaryRamBase) + PcdGet32 (PcdTemporaryRamSize); FspPlatformData->DataPtr = NULL; FspPlatformData->MicrocodeRegionBase = 0; FspPlatformData->MicrocodeRegionSize = 0; FspPlatformData->CodeRegionBase = 0; FspPlatformData->CodeRegionSize = 0; // // Pointer to the size field // StackPtr = (UINT32 *)(TopOfCar - sizeof(UINT32)); while (*StackPtr != 0) { if (*(StackPtr - 1) == FSP_MCUD_SIGNATURE) { // // This following data was pushed onto stack after TempRamInit API // DwordSize = 4; StackPtr = StackPtr - 1 - DwordSize; CopyMem (&(FspPlatformData->MicrocodeRegionBase), StackPtr, (DwordSize << 2)); StackPtr--; } else if (*(StackPtr - 1) == FSP_PER0_SIGNATURE) { // // This is the performance data for InitTempMemory API entry/exit // DwordSize = 4; StackPtr = StackPtr - 1 - DwordSize; CopyMem (FspData->PerfData, StackPtr, (DwordSize << 2)); ((UINT8 *)(&FspData->PerfData[0]))[7] = FSP_PERF_ID_API_TMPRAMINIT_ENTRY; ((UINT8 *)(&FspData->PerfData[1]))[7] = FSP_PERF_ID_API_TMPRAMINIT_EXIT; StackPtr--; } else { StackPtr -= (*StackPtr); } } } /** Initialize the FSP global data region. It needs to be done as soon as possible after the stack is setup. @param[in,out] PeiFspData Pointer of the FSP global data. @param[in] BootLoaderStack BootLoader stack. @param[in] ApiIdx The index of the FSP API. **/ VOID FspGlobalDataInit ( IN OUT FSP_GLOBAL_DATA *PeiFspData, IN UINT32 BootLoaderStack, IN UINT8 ApiIdx ) { VOID *UpdDataRgnPtr; FSP_INIT_PARAMS *FspInitParams; CHAR8 ImageId[9]; UINTN Idx; // // Init PCIE_BAR with value and set global FSP data pointer. // PciExpress Base should have been programmed by platform already. // SetFspGlobalDataPointer (PeiFspData); ZeroMem ((VOID *)PeiFspData, sizeof(FSP_GLOBAL_DATA)); PeiFspData->Signature = FSP_GLOBAL_DATA_SIGNATURE; PeiFspData->CoreStack = BootLoaderStack; PeiFspData->PerfIdx = 2; SetFspMeasurePoint (FSP_PERF_ID_API_FSPINIT_ENTRY); // // Get FSP Header offset // It may have multiple FVs, so look into the last one for FSP header // PeiFspData->FspInfoHeader = (FSP_INFO_HEADER *)AsmGetFspInfoHeader(); SecGetPlatformData (PeiFspData); // // Set API calling mode // SetFspApiCallingMode (ApiIdx == 1 ? 0 : 1); // // Initialize UPD pointer. // FspInitParams = (FSP_INIT_PARAMS *)GetFspApiParameter (); UpdDataRgnPtr = ((FSP_INIT_RT_COMMON_BUFFER *)FspInitParams->RtBufferPtr)->UpdDataRgnPtr; if (UpdDataRgnPtr == NULL) { UpdDataRgnPtr = (VOID *)(PeiFspData->FspInfoHeader->ImageBase + GetFspUpdRegionOffset()); } SetFspUpdDataPointer (UpdDataRgnPtr); // // Initialize serial port // It might have been done in ProcessLibraryConstructorList(), however, // the FSP global data is not initialized at that time. So do it again // for safe. // SerialPortInitialize (); // // Ensure the golbal data pointer is valid // ASSERT (GetFspGlobalDataPointer () == PeiFspData); for (Idx = 0; Idx < 8; Idx++) { ImageId[Idx] = PeiFspData->FspInfoHeader->ImageId[Idx]; } ImageId[Idx] = 0; DEBUG ((DEBUG_INFO | DEBUG_INIT, "\n============= PEIM FSP v1.%x (%a v%x.%x.%x.%x) =============\n", \ PeiFspData->FspInfoHeader->HeaderRevision - 1, \ ImageId, \ (PeiFspData->FspInfoHeader->ImageRevision >> 24) & 0xff, \ (PeiFspData->FspInfoHeader->ImageRevision >> 16) & 0xff, \ (PeiFspData->FspInfoHeader->ImageRevision >> 8) & 0xff, \ (PeiFspData->FspInfoHeader->ImageRevision >> 0) & 0xff)); } /** Adjust the FSP data pointers after the stack is migrated to memory. @param[in] OffsetGap The offset gap between the old stack and the new stack. **/ VOID FspDataPointerFixUp ( IN UINT32 OffsetGap ) { FSP_GLOBAL_DATA *NewFspData; NewFspData = (FSP_GLOBAL_DATA *)((UINTN)GetFspGlobalDataPointer() + (UINTN)OffsetGap); SetFspGlobalDataPointer (NewFspData); } /** This function check the FSP API calling condition. @param[in] ApiIdx Internal index of the FSP API. @param[in] ApiParam Parameter of the FSP API. **/ EFI_STATUS EFIAPI FspApiCallingCheck ( IN UINT32 ApiIdx, IN VOID *ApiParam ) { EFI_STATUS Status; FSP_GLOBAL_DATA *FspData; FSP_INIT_PARAMS *FspInitParams; FSP_INIT_RT_COMMON_BUFFER *FspRtBuffer; FspInitParams = (FSP_INIT_PARAMS *) ApiParam; FspRtBuffer = ((FSP_INIT_RT_COMMON_BUFFER *)FspInitParams->RtBufferPtr); Status = EFI_SUCCESS; FspData = GetFspGlobalDataPointer (); if (ApiIdx == 1) { // // FspInit check // if ((UINT32)FspData != 0xFFFFFFFF) { Status = EFI_UNSUPPORTED; } else if ((FspRtBuffer == NULL) || ((FspRtBuffer->BootLoaderTolumSize % EFI_PAGE_SIZE) != 0) || (EFI_ERROR(FspUpdSignatureCheck(ApiIdx, ApiParam)))) { Status = EFI_INVALID_PARAMETER; } } else if (ApiIdx == 2) { // // NotifyPhase check // if ((FspData == NULL) || ((UINT32)FspData == 0xFFFFFFFF)) { Status = EFI_UNSUPPORTED; } else { if (FspData->Signature != FSP_GLOBAL_DATA_SIGNATURE) { Status = EFI_UNSUPPORTED; } } } else if (ApiIdx == 3) { // // FspMemoryInit check // if ((UINT32)FspData != 0xFFFFFFFF) { Status = EFI_UNSUPPORTED; } else if ((FspRtBuffer == NULL) || ((FspRtBuffer->BootLoaderTolumSize % EFI_PAGE_SIZE) != 0) || (EFI_ERROR(FspUpdSignatureCheck(ApiIdx, ApiParam)))) { Status = EFI_INVALID_PARAMETER; } } else if (ApiIdx == 4) { // // TempRamExit check // if ((FspData == NULL) || ((UINT32)FspData == 0xFFFFFFFF)) { Status = EFI_UNSUPPORTED; } else { if (FspData->Signature != FSP_GLOBAL_DATA_SIGNATURE) { Status = EFI_UNSUPPORTED; } } } else if (ApiIdx == 5) { // // FspSiliconInit check // if ((FspData == NULL) || ((UINT32)FspData == 0xFFFFFFFF)) { Status = EFI_UNSUPPORTED; } else { if (FspData->Signature != FSP_GLOBAL_DATA_SIGNATURE) { Status = EFI_UNSUPPORTED; } else if (EFI_ERROR(FspUpdSignatureCheck(ApiIdx, ApiParam))) { Status = EFI_INVALID_PARAMETER; } } } else { Status = EFI_UNSUPPORTED; } return Status; } /** This function gets the boot FV offset in FSP. @return the boot firmware volumen offset inside FSP binary **/ UINT32 EFIAPI GetBootFirmwareVolumeOffset ( VOID ) { return PcdGet32 (PcdFspBootFirmwareVolumeBase) - PcdGet32 (PcdFspAreaBaseAddress); }