+/**\r
+ Migrate a PEIM from temporary RAM to permanent memory.\r
+\r
+ @param PeimFileHandle Pointer to the FFS file header of the image.\r
+ @param MigratedFileHandle Pointer to the FFS file header of the migrated image.\r
+\r
+ @retval EFI_SUCCESS Successfully migrated the PEIM to permanent memory.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MigratePeim (\r
+ IN EFI_PEI_FILE_HANDLE FileHandle,\r
+ IN EFI_PEI_FILE_HANDLE MigratedFileHandle\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_FFS_FILE_HEADER *FileHeader;\r
+ VOID *Pe32Data;\r
+ VOID *ImageAddress;\r
+ CHAR8 *AsciiString;\r
+ UINTN Index;\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ FileHeader = (EFI_FFS_FILE_HEADER *)FileHandle;\r
+ ASSERT (!IS_FFS_FILE2 (FileHeader));\r
+\r
+ ImageAddress = NULL;\r
+ PeiGetPe32Data (MigratedFileHandle, &ImageAddress);\r
+ if (ImageAddress != NULL) {\r
+ DEBUG_CODE_BEGIN ();\r
+ AsciiString = PeCoffLoaderGetPdbPointer (ImageAddress);\r
+ for (Index = 0; AsciiString[Index] != 0; Index++) {\r
+ if ((AsciiString[Index] == '\\') || (AsciiString[Index] == '/')) {\r
+ AsciiString = AsciiString + Index + 1;\r
+ Index = 0;\r
+ } else if (AsciiString[Index] == '.') {\r
+ AsciiString[Index] = 0;\r
+ }\r
+ }\r
+\r
+ DEBUG ((DEBUG_VERBOSE, "%a", AsciiString));\r
+ DEBUG_CODE_END ();\r
+\r
+ Pe32Data = (VOID *)((UINTN)ImageAddress - (UINTN)MigratedFileHandle + (UINTN)FileHandle);\r
+ Status = LoadAndRelocatePeCoffImageInPlace (Pe32Data, ImageAddress);\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Migrate Status Code Callback function pointers inside an FV from temporary memory to permanent memory.\r
+\r
+ @param OrgFvHandle Address of FV handle in temporary memory.\r
+ @param FvHandle Address of FV handle in permanent memory.\r
+ @param FvSize Size of the FV.\r
+\r
+**/\r
+VOID\r
+ConvertStatusCodeCallbacks (\r
+ IN UINTN OrgFvHandle,\r
+ IN UINTN FvHandle,\r
+ IN UINTN FvSize\r
+ )\r
+{\r
+ EFI_PEI_HOB_POINTERS Hob;\r
+ UINTN *NumberOfEntries;\r
+ UINTN *CallbackEntry;\r
+ UINTN Index;\r
+\r
+ Hob.Raw = GetFirstGuidHob (&gStatusCodeCallbackGuid);\r
+ while (Hob.Raw != NULL) {\r
+ NumberOfEntries = GET_GUID_HOB_DATA (Hob);\r
+ CallbackEntry = NumberOfEntries + 1;\r
+ for (Index = 0; Index < *NumberOfEntries; Index++) {\r
+ if (((VOID *)CallbackEntry[Index]) != NULL) {\r
+ if ((CallbackEntry[Index] >= OrgFvHandle) && (CallbackEntry[Index] < (OrgFvHandle + FvSize))) {\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "Migrating CallbackEntry[%Lu] from 0x%0*Lx to ",\r
+ (UINT64)Index,\r
+ (sizeof CallbackEntry[Index]) * 2,\r
+ (UINT64)CallbackEntry[Index]\r
+ ));\r
+ if (OrgFvHandle > FvHandle) {\r
+ CallbackEntry[Index] = CallbackEntry[Index] - (OrgFvHandle - FvHandle);\r
+ } else {\r
+ CallbackEntry[Index] = CallbackEntry[Index] + (FvHandle - OrgFvHandle);\r
+ }\r
+\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "0x%0*Lx\n",\r
+ (sizeof CallbackEntry[Index]) * 2,\r
+ (UINT64)CallbackEntry[Index]\r
+ ));\r
+ }\r
+ }\r
+ }\r
+\r
+ Hob.Raw = GET_NEXT_HOB (Hob);\r
+ Hob.Raw = GetNextGuidHob (&gStatusCodeCallbackGuid, Hob.Raw);\r
+ }\r
+}\r
+\r
+/**\r
+ Migrates PEIMs in the given firmware volume.\r
+\r
+ @param Private Pointer to the PeiCore's private data structure.\r
+ @param FvIndex The firmware volume index to migrate.\r
+ @param OrgFvHandle The handle to the firmware volume in temporary memory.\r
+ @param FvHandle The handle to the firmware volume in permanent memory.\r
+\r
+ @retval EFI_SUCCESS The PEIMs in the FV were migrated successfully\r
+ @retval EFI_INVALID_PARAMETER The Private pointer is NULL or FvCount is invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MigratePeimsInFv (\r
+ IN PEI_CORE_INSTANCE *Private,\r
+ IN UINTN FvIndex,\r
+ IN UINTN OrgFvHandle,\r
+ IN UINTN FvHandle\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ volatile UINTN FileIndex;\r
+ EFI_PEI_FILE_HANDLE MigratedFileHandle;\r
+ EFI_PEI_FILE_HANDLE FileHandle;\r
+\r
+ if ((Private == NULL) || (FvIndex >= Private->FvCount)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Private->Fv[FvIndex].ScanFv) {\r
+ for (FileIndex = 0; FileIndex < Private->Fv[FvIndex].PeimCount; FileIndex++) {\r
+ if (Private->Fv[FvIndex].FvFileHandles[FileIndex] != NULL) {\r
+ FileHandle = Private->Fv[FvIndex].FvFileHandles[FileIndex];\r
+\r
+ MigratedFileHandle = (EFI_PEI_FILE_HANDLE)((UINTN)FileHandle - OrgFvHandle + FvHandle);\r
+\r
+ DEBUG ((DEBUG_VERBOSE, " Migrating FileHandle %2d ", FileIndex));\r
+ Status = MigratePeim (FileHandle, MigratedFileHandle);\r
+ DEBUG ((DEBUG_VERBOSE, "\n"));\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ Private->Fv[FvIndex].FvFileHandles[FileIndex] = MigratedFileHandle;\r
+ if (FvIndex == Private->CurrentPeimFvCount) {\r
+ Private->CurrentFvFileHandles[FileIndex] = MigratedFileHandle;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Migrate FVs out of temporary RAM before the cache is flushed.\r
+\r
+ @param Private PeiCore's private data structure\r
+ @param SecCoreData Points to a data structure containing information about the PEI core's operating\r
+ environment, such as the size and location of temporary RAM, the stack location and\r
+ the BFV location.\r
+\r
+ @retval EFI_SUCCESS Successfully migrated installed FVs from temporary RAM to permanent memory.\r
+ @retval EFI_OUT_OF_RESOURCES Insufficient memory exists to allocate needed pages.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EvacuateTempRam (\r
+ IN PEI_CORE_INSTANCE *Private,\r
+ IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ volatile UINTN FvIndex;\r
+ volatile UINTN FvChildIndex;\r
+ UINTN ChildFvOffset;\r
+ EFI_PHYSICAL_ADDRESS FvHeaderAddress;\r
+ EFI_FIRMWARE_VOLUME_HEADER *FvHeader;\r
+ EFI_FIRMWARE_VOLUME_HEADER *ChildFvHeader;\r
+ EFI_FIRMWARE_VOLUME_HEADER *MigratedFvHeader;\r
+ EFI_FIRMWARE_VOLUME_HEADER *RawDataFvHeader;\r
+ EFI_FIRMWARE_VOLUME_HEADER *MigratedChildFvHeader;\r
+\r
+ PEI_CORE_FV_HANDLE PeiCoreFvHandle;\r
+ EFI_PEI_CORE_FV_LOCATION_PPI *PeiCoreFvLocationPpi;\r
+ EDKII_MIGRATED_FV_INFO MigratedFvInfo;\r
+\r
+ ASSERT (Private->PeiMemoryInstalled);\r
+\r
+ DEBUG ((DEBUG_VERBOSE, "Beginning evacuation of content in temporary RAM.\n"));\r
+\r
+ //\r
+ // Migrate PPI Pointers of PEI_CORE from temporary memory to newly loaded PEI_CORE in permanent memory.\r
+ //\r
+ Status = PeiLocatePpi ((CONST EFI_PEI_SERVICES **)&Private->Ps, &gEfiPeiCoreFvLocationPpiGuid, 0, NULL, (VOID **)&PeiCoreFvLocationPpi);\r
+ if (!EFI_ERROR (Status) && (PeiCoreFvLocationPpi->PeiCoreFvLocation != NULL)) {\r
+ PeiCoreFvHandle.FvHandle = (EFI_PEI_FV_HANDLE)PeiCoreFvLocationPpi->PeiCoreFvLocation;\r
+ } else {\r
+ PeiCoreFvHandle.FvHandle = (EFI_PEI_FV_HANDLE)SecCoreData->BootFirmwareVolumeBase;\r
+ }\r
+\r
+ for (FvIndex = 0; FvIndex < Private->FvCount; FvIndex++) {\r
+ if (Private->Fv[FvIndex].FvHandle == PeiCoreFvHandle.FvHandle) {\r
+ CopyMem (&PeiCoreFvHandle, &Private->Fv[FvIndex], sizeof (PEI_CORE_FV_HANDLE));\r
+ break;\r
+ }\r
+ }\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ ConvertPeiCorePpiPointers (Private, &PeiCoreFvHandle);\r
+\r
+ for (FvIndex = 0; FvIndex < Private->FvCount; FvIndex++) {\r
+ FvHeader = Private->Fv[FvIndex].FvHeader;\r
+ ASSERT (FvHeader != NULL);\r
+ ASSERT (FvIndex < Private->FvCount);\r
+\r
+ DEBUG ((DEBUG_VERBOSE, "FV[%02d] at 0x%x.\n", FvIndex, (UINTN)FvHeader));\r
+ if (\r
+ !(\r
+ ((EFI_PHYSICAL_ADDRESS)(UINTN)FvHeader >= Private->PhysicalMemoryBegin) &&\r
+ (((EFI_PHYSICAL_ADDRESS)(UINTN)FvHeader + (FvHeader->FvLength - 1)) < Private->FreePhysicalMemoryTop)\r
+ )\r
+ )\r
+ {\r
+ //\r
+ // Allocate page to save the rebased PEIMs, the PEIMs will get dispatched later.\r
+ //\r
+ Status = PeiServicesAllocatePages (\r
+ EfiBootServicesCode,\r
+ EFI_SIZE_TO_PAGES ((UINTN)FvHeader->FvLength),\r
+ &FvHeaderAddress\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ MigratedFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FvHeaderAddress;\r
+\r
+ //\r
+ // Allocate pool to save the raw PEIMs, which is used to keep consistent context across\r
+ // multiple boot and PCR0 will keep the same no matter if the address of allocated page is changed.\r
+ //\r
+ Status = PeiServicesAllocatePages (\r
+ EfiBootServicesCode,\r
+ EFI_SIZE_TO_PAGES ((UINTN)FvHeader->FvLength),\r
+ &FvHeaderAddress\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ RawDataFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FvHeaderAddress;\r
+\r
+ DEBUG ((\r
+ DEBUG_VERBOSE,\r
+ " Migrating FV[%d] from 0x%08X to 0x%08X\n",\r
+ FvIndex,\r
+ (UINTN)FvHeader,\r
+ (UINTN)MigratedFvHeader\r
+ ));\r
+\r
+ //\r
+ // Copy the context to the rebased pages and raw pages, and create hob to save the\r
+ // information. The MigratedFvInfo HOB will never be produced when\r
+ // PcdMigrateTemporaryRamFirmwareVolumes is FALSE, because the PCD control the\r
+ // feature.\r
+ //\r
+ CopyMem (MigratedFvHeader, FvHeader, (UINTN)FvHeader->FvLength);\r
+ CopyMem (RawDataFvHeader, MigratedFvHeader, (UINTN)FvHeader->FvLength);\r
+ MigratedFvInfo.FvOrgBase = (UINT32)(UINTN)FvHeader;\r
+ MigratedFvInfo.FvNewBase = (UINT32)(UINTN)MigratedFvHeader;\r
+ MigratedFvInfo.FvDataBase = (UINT32)(UINTN)RawDataFvHeader;\r
+ MigratedFvInfo.FvLength = (UINT32)(UINTN)FvHeader->FvLength;\r
+ BuildGuidDataHob (&gEdkiiMigratedFvInfoGuid, &MigratedFvInfo, sizeof (MigratedFvInfo));\r
+\r
+ //\r
+ // Migrate any children for this FV now\r
+ //\r
+ for (FvChildIndex = FvIndex; FvChildIndex < Private->FvCount; FvChildIndex++) {\r
+ ChildFvHeader = Private->Fv[FvChildIndex].FvHeader;\r
+ if (\r
+ ((UINTN)ChildFvHeader > (UINTN)FvHeader) &&\r
+ (((UINTN)ChildFvHeader + ChildFvHeader->FvLength) < ((UINTN)FvHeader) + FvHeader->FvLength)\r
+ )\r
+ {\r
+ DEBUG ((DEBUG_VERBOSE, " Child FV[%02d] is being migrated.\n", FvChildIndex));\r
+ ChildFvOffset = (UINTN)ChildFvHeader - (UINTN)FvHeader;\r
+ DEBUG ((DEBUG_VERBOSE, " Child FV offset = 0x%x.\n", ChildFvOffset));\r
+ MigratedChildFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)((UINTN)MigratedFvHeader + ChildFvOffset);\r
+ Private->Fv[FvChildIndex].FvHeader = MigratedChildFvHeader;\r
+ Private->Fv[FvChildIndex].FvHandle = (EFI_PEI_FV_HANDLE)MigratedChildFvHeader;\r
+ DEBUG ((DEBUG_VERBOSE, " Child migrated FV header at 0x%x.\n", (UINTN)MigratedChildFvHeader));\r
+\r
+ Status = MigratePeimsInFv (Private, FvChildIndex, (UINTN)ChildFvHeader, (UINTN)MigratedChildFvHeader);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ ConvertPpiPointersFv (\r
+ Private,\r
+ (UINTN)ChildFvHeader,\r
+ (UINTN)MigratedChildFvHeader,\r
+ (UINTN)ChildFvHeader->FvLength - 1\r
+ );\r
+\r
+ ConvertStatusCodeCallbacks (\r
+ (UINTN)ChildFvHeader,\r
+ (UINTN)MigratedChildFvHeader,\r
+ (UINTN)ChildFvHeader->FvLength - 1\r
+ );\r
+\r
+ ConvertFvHob (Private, (UINTN)ChildFvHeader, (UINTN)MigratedChildFvHeader);\r
+ }\r
+ }\r
+\r
+ Private->Fv[FvIndex].FvHeader = MigratedFvHeader;\r
+ Private->Fv[FvIndex].FvHandle = (EFI_PEI_FV_HANDLE)MigratedFvHeader;\r
+\r
+ Status = MigratePeimsInFv (Private, FvIndex, (UINTN)FvHeader, (UINTN)MigratedFvHeader);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ ConvertPpiPointersFv (\r
+ Private,\r
+ (UINTN)FvHeader,\r
+ (UINTN)MigratedFvHeader,\r
+ (UINTN)FvHeader->FvLength - 1\r
+ );\r
+\r
+ ConvertStatusCodeCallbacks (\r
+ (UINTN)FvHeader,\r
+ (UINTN)MigratedFvHeader,\r
+ (UINTN)FvHeader->FvLength - 1\r
+ );\r
+\r
+ ConvertFvHob (Private, (UINTN)FvHeader, (UINTN)MigratedFvHeader);\r
+ }\r
+ }\r
+\r
+ RemoveFvHobsInTemporaryMemory (Private);\r
+\r
+ return Status;\r
+}\r
+\r