+ //\r
+ // Locate old build-in Ffs3 EFI_PEI_FIRMWARE_VOLUME_PPI which\r
+ // in flash.\r
+ //\r
+ Status = PeiServicesLocatePpi (\r
+ &gEfiFirmwareFileSystem3Guid,\r
+ 0,\r
+ &OldDescriptor,\r
+ &OldFfsFvPpi\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Re-install the EFI_PEI_FIRMWARE_VOLUME_PPI for build-in Ffs3\r
+ // which is shadowed from flash to permanent memory within PeiCore image.\r
+ //\r
+ Status = PeiServicesReInstallPpi (OldDescriptor, &mPeiFfs3FvPpiList);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Fixup all FvPpi pointers for the implementation in flash to permanent memory.\r
+ //\r
+ for (Index = 0; Index < PrivateData->FvCount; Index ++) {\r
+ if (PrivateData->Fv[Index].FvPpi == OldFfsFvPpi) {\r
+ PrivateData->Fv[Index].FvPpi = &mPeiFfs3FwVol.Fv;\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Report the information for a newly discovered FV in an unknown format.\r
+\r
+ If the EFI_PEI_FIRMWARE_VOLUME_PPI has not been installed for a third-party FV format, but\r
+ the FV has been discovered, then the information of this FV will be cached into PEI_CORE_INSTANCE's\r
+ UnknownFvInfo array.\r
+\r
+ Also a notification would be installed for unknown FV format GUID, if EFI_PEI_FIRMWARE_VOLUME_PPI\r
+ is installed later by platform's PEIM, the original unknown FV will be processed by\r
+ using new installed EFI_PEI_FIRMWARE_VOLUME_PPI.\r
+\r
+ @param PrivateData Point to instance of PEI_CORE_INSTANCE\r
+ @param FvInfo2Ppi Point to FvInfo2 PPI.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES The FV info array in PEI_CORE_INSTANCE has no more spaces.\r
+ @retval EFI_SUCCESS Success to add the information for unknown FV.\r
+**/\r
+EFI_STATUS\r
+AddUnknownFormatFvInfo (\r
+ IN PEI_CORE_INSTANCE *PrivateData,\r
+ IN EFI_PEI_FIRMWARE_VOLUME_INFO2_PPI *FvInfo2Ppi\r
+ )\r
+{\r
+ PEI_CORE_UNKNOW_FORMAT_FV_INFO *NewUnknownFv;\r
+ VOID *TempPtr;\r
+\r
+ if (PrivateData->UnknownFvInfoCount >= PrivateData->MaxUnknownFvInfoCount) {\r
+ //\r
+ // Run out of room, grow the buffer.\r
+ //\r
+ TempPtr = AllocateZeroPool (\r
+ sizeof (PEI_CORE_UNKNOW_FORMAT_FV_INFO) * (PrivateData->MaxUnknownFvInfoCount + FV_GROWTH_STEP)\r
+ );\r
+ ASSERT (TempPtr != NULL);\r
+ CopyMem (\r
+ TempPtr,\r
+ PrivateData->UnknownFvInfo,\r
+ sizeof (PEI_CORE_UNKNOW_FORMAT_FV_INFO) * PrivateData->MaxUnknownFvInfoCount\r
+ );\r
+ PrivateData->UnknownFvInfo = TempPtr;\r
+ PrivateData->MaxUnknownFvInfoCount = PrivateData->MaxUnknownFvInfoCount + FV_GROWTH_STEP;\r
+ }\r
+\r
+ NewUnknownFv = &PrivateData->UnknownFvInfo[PrivateData->UnknownFvInfoCount];\r
+ PrivateData->UnknownFvInfoCount ++;\r
+\r
+ CopyGuid (&NewUnknownFv->FvFormat, &FvInfo2Ppi->FvFormat);\r
+ NewUnknownFv->FvInfo = FvInfo2Ppi->FvInfo;\r
+ NewUnknownFv->FvInfoSize = FvInfo2Ppi->FvInfoSize;\r
+ NewUnknownFv->AuthenticationStatus = FvInfo2Ppi->AuthenticationStatus;\r
+ NewUnknownFv->NotifyDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);\r
+ NewUnknownFv->NotifyDescriptor.Guid = &NewUnknownFv->FvFormat;\r
+ NewUnknownFv->NotifyDescriptor.Notify = ThirdPartyFvPpiNotifyCallback;\r
+\r
+ PeiServicesNotifyPpi (&NewUnknownFv->NotifyDescriptor);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Find the FV information according to third-party FV format GUID.\r
+\r
+ This routine also will remove the FV information found by given FV format GUID from\r
+ PrivateData->UnknownFvInfo[].\r
+\r
+ @param PrivateData Point to instance of PEI_CORE_INSTANCE\r
+ @param Format Point to given FV format GUID\r
+ @param FvInfo On return, the pointer of FV information buffer\r
+ @param FvInfoSize On return, the size of FV information buffer.\r
+ @param AuthenticationStatus On return, the authentication status of FV information buffer.\r
+\r
+ @retval EFI_NOT_FOUND The FV is not found for new installed EFI_PEI_FIRMWARE_VOLUME_PPI\r
+ @retval EFI_SUCCESS Success to find a FV which could be processed by new installed EFI_PEI_FIRMWARE_VOLUME_PPI.\r
+**/\r
+EFI_STATUS\r
+FindUnknownFormatFvInfo (\r
+ IN PEI_CORE_INSTANCE *PrivateData,\r
+ IN EFI_GUID *Format,\r
+ OUT VOID **FvInfo,\r
+ OUT UINT32 *FvInfoSize,\r
+ OUT UINT32 *AuthenticationStatus\r
+ )\r
+{\r
+ UINTN Index;\r
+ UINTN Index2;\r
+\r
+ Index = 0;\r
+ for (; Index < PrivateData->UnknownFvInfoCount; Index ++) {\r
+ if (CompareGuid (Format, &PrivateData->UnknownFvInfo[Index].FvFormat)) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (Index == PrivateData->UnknownFvInfoCount) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ *FvInfo = PrivateData->UnknownFvInfo[Index].FvInfo;\r
+ *FvInfoSize = PrivateData->UnknownFvInfo[Index].FvInfoSize;\r
+ *AuthenticationStatus = PrivateData->UnknownFvInfo[Index].AuthenticationStatus;\r
+\r
+ //\r
+ // Remove an entry from UnknownFvInfo array.\r
+ //\r
+ Index2 = Index + 1;\r
+ for (;Index2 < PrivateData->UnknownFvInfoCount; Index2 ++, Index ++) {\r
+ CopyMem (&PrivateData->UnknownFvInfo[Index], &PrivateData->UnknownFvInfo[Index2], sizeof (PEI_CORE_UNKNOW_FORMAT_FV_INFO));\r
+ }\r
+ PrivateData->UnknownFvInfoCount --;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Notification callback function for EFI_PEI_FIRMWARE_VOLUME_PPI.\r
+\r
+ When a EFI_PEI_FIRMWARE_VOLUME_PPI is installed to support new FV format, this\r
+ routine is called to process all discovered FVs in this format.\r
+\r
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation\r
+ @param NotifyDescriptor Address of the notification descriptor data structure.\r
+ @param Ppi Address of the PPI that was installed.\r
+\r
+ @retval EFI_SUCCESS The notification callback is processed correctly.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ThirdPartyFvPpiNotifyCallback (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,\r
+ IN VOID *Ppi\r
+ )\r
+{\r
+ PEI_CORE_INSTANCE *PrivateData;\r
+ EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi;\r
+ VOID *FvInfo;\r
+ UINT32 FvInfoSize;\r
+ UINT32 AuthenticationStatus;\r
+ EFI_STATUS Status;\r
+ EFI_PEI_FV_HANDLE FvHandle;\r
+ BOOLEAN IsProcessed;\r
+ UINTN FvIndex;\r
+ EFI_PEI_FILE_HANDLE FileHandle;\r
+ VOID *DepexData;\r
+ UINTN CurFvCount;\r
+ VOID *TempPtr;\r
+\r
+ PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);\r
+ FvPpi = (EFI_PEI_FIRMWARE_VOLUME_PPI*) Ppi;\r
+\r
+ do {\r
+ Status = FindUnknownFormatFvInfo (PrivateData, NotifyDescriptor->Guid, &FvInfo, &FvInfoSize, &AuthenticationStatus);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Process new found FV and get FV handle.\r
+ //\r
+ Status = FvPpi->ProcessVolume (FvPpi, FvInfo, FvInfoSize, &FvHandle);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "Fail to process the FV 0x%p, FV may be corrupted!\n", FvInfo));\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Check whether the FV has already been processed.\r
+ //\r
+ IsProcessed = FALSE;\r
+ for (FvIndex = 0; FvIndex < PrivateData->FvCount; FvIndex ++) {\r
+ if (PrivateData->Fv[FvIndex].FvHandle == FvHandle) {\r
+ DEBUG ((DEBUG_INFO, "The FV %p has already been processed!\n", FvInfo));\r
+ IsProcessed = TRUE;\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (IsProcessed) {\r
+ continue;\r
+ }\r
+\r
+ if (PrivateData->FvCount >= PrivateData->MaxFvCount) {\r
+ //\r
+ // Run out of room, grow the buffer.\r
+ //\r
+ TempPtr = AllocateZeroPool (\r
+ sizeof (PEI_CORE_FV_HANDLE) * (PrivateData->MaxFvCount + FV_GROWTH_STEP)\r
+ );\r
+ ASSERT (TempPtr != NULL);\r
+ CopyMem (\r
+ TempPtr,\r
+ PrivateData->Fv,\r
+ sizeof (PEI_CORE_FV_HANDLE) * PrivateData->MaxFvCount\r
+ );\r
+ PrivateData->Fv = TempPtr;\r
+ PrivateData->MaxFvCount = PrivateData->MaxFvCount + FV_GROWTH_STEP;\r
+ }\r
+\r
+ //\r
+ // Update internal PEI_CORE_FV array.\r
+ //\r
+ PrivateData->Fv[PrivateData->FvCount].FvHeader = (EFI_FIRMWARE_VOLUME_HEADER*) FvInfo;\r
+ PrivateData->Fv[PrivateData->FvCount].FvPpi = FvPpi;\r
+ PrivateData->Fv[PrivateData->FvCount].FvHandle = FvHandle;\r
+ PrivateData->Fv[PrivateData->FvCount].AuthenticationStatus = AuthenticationStatus;\r
+ CurFvCount = PrivateData->FvCount;\r
+ DEBUG ((\r
+ EFI_D_INFO,\r
+ "The %dth FV start address is 0x%11p, size is 0x%08x, handle is 0x%p\n",\r
+ (UINT32) CurFvCount,\r
+ (VOID *) FvInfo,\r
+ FvInfoSize,\r
+ FvHandle\r
+ ));\r
+ PrivateData->FvCount ++;\r
+\r
+ //\r
+ // Scan and process the new discovered FV for EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE\r
+ //\r
+ FileHandle = NULL;\r
+ do {\r
+ Status = FvPpi->FindFileByType (\r
+ FvPpi,\r
+ EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE,\r
+ FvHandle,\r
+ &FileHandle\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = FvPpi->FindSectionByType (\r
+ FvPpi,\r
+ EFI_SECTION_PEI_DEPEX,\r
+ FileHandle,\r
+ (VOID**)&DepexData\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ if (!PeimDispatchReadiness (PeiServices, DepexData)) {\r
+ //\r
+ // Dependency is not satisfied.\r
+ //\r
+ continue;\r
+ }\r
+ }\r
+\r
+ DEBUG ((EFI_D_INFO, "Found firmware volume Image File %p in FV[%d] %p\n", FileHandle, CurFvCount, FvHandle));\r
+ ProcessFvFile (PrivateData, &PrivateData->Fv[CurFvCount], FileHandle);\r
+ }\r
+ } while (FileHandle != NULL);\r
+ } while (TRUE);\r
+}\r