+EFI_STATUS\r
+FindCorePeSection(\r
+ IN VOID *FvImageBuffer,\r
+ IN UINT64 FvSize,\r
+ IN EFI_FV_FILETYPE FileType,\r
+ OUT EFI_FILE_SECTION_POINTER *Pe32Section\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Recursively searches the FV for the FFS file of specified type (typically\r
+ SEC or PEI core) and extracts the PE32 section for further processing.\r
+\r
+Arguments:\r
+\r
+ FvImageBuffer Buffer containing FV data\r
+ FvSize Size of the FV\r
+ FileType Type of FFS file to search for\r
+ Pe32Section PE32 section pointer when FFS file is found.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS Function Completed successfully.\r
+ EFI_ABORTED Error encountered.\r
+ EFI_INVALID_PARAMETER A required parameter was NULL.\r
+ EFI_NOT_FOUND Core file not found.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_FIRMWARE_VOLUME_HEADER *OrigFvHeader;\r
+ UINT32 OrigFvLength;\r
+ EFI_FFS_FILE_HEADER *CoreFfsFile;\r
+ UINTN FvImageFileCount;\r
+ EFI_FFS_FILE_HEADER *FvImageFile;\r
+ UINTN EncapFvSectionCount;\r
+ EFI_FILE_SECTION_POINTER EncapFvSection;\r
+ EFI_FIRMWARE_VOLUME_HEADER *EncapsulatedFvHeader;\r
+\r
+ if (Pe32Section == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Initialize FV library, saving previous values\r
+ //\r
+ OrigFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)NULL;\r
+ GetFvHeader (&OrigFvHeader, &OrigFvLength);\r
+ InitializeFvLib(FvImageBuffer, (UINT32)FvSize);\r
+\r
+ //\r
+ // First see if we can obtain the file directly in outer FV\r
+ //\r
+ Status = GetFileByType(FileType, 1, &CoreFfsFile);\r
+ if (!EFI_ERROR(Status) && (CoreFfsFile != NULL) ) {\r
+\r
+ //\r
+ // Core found, now find PE32 or TE section\r
+ //\r
+ Status = GetSectionByType(CoreFfsFile, EFI_SECTION_PE32, 1, Pe32Section);\r
+ if (EFI_ERROR(Status)) {\r
+ Status = GetSectionByType(CoreFfsFile, EFI_SECTION_TE, 1, Pe32Section);\r
+ }\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ Error(NULL, 0, 3000, "Invalid", "could not find a PE32 section in the core file.");\r
+ return EFI_ABORTED;\r
+ }\r
+\r
+ //\r
+ // Core PE/TE section, found, return\r
+ //\r
+ Status = EFI_SUCCESS;\r
+ goto EarlyExit;\r
+ }\r
+\r
+ //\r
+ // File was not found, look for FV Image file\r
+ //\r
+\r
+ // iterate through all FV image files in outer FV\r
+ for (FvImageFileCount = 1;; FvImageFileCount++) {\r
+\r
+ Status = GetFileByType(EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE, FvImageFileCount, &FvImageFile);\r
+\r
+ if (EFI_ERROR(Status) || (FvImageFile == NULL) ) {\r
+ // exit FV image file loop, no more found\r
+ break;\r
+ }\r
+\r
+ // Found an fv image file, look for an FV image section. The PI spec does not\r
+ // preclude multiple FV image sections so we loop accordingly.\r
+ for (EncapFvSectionCount = 1;; EncapFvSectionCount++) {\r
+\r
+ // Look for the next FV image section. The section search code will\r
+ // iterate into encapsulation sections. For example, it will iterate\r
+ // into an EFI_SECTION_GUID_DEFINED encapsulation section to find the\r
+ // EFI_SECTION_FIRMWARE_VOLUME_IMAGE sections contained therein.\r
+ Status = GetSectionByType(FvImageFile, EFI_SECTION_FIRMWARE_VOLUME_IMAGE, EncapFvSectionCount, &EncapFvSection);\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ // exit section inner loop, no more found\r
+ break;\r
+ }\r
+\r
+ EncapsulatedFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)((UINT8 *)EncapFvSection.FVImageSection + GetSectionHeaderLength(EncapFvSection.FVImageSection));\r
+\r
+ // recurse to search the encapsulated FV for this core file type\r
+ Status = FindCorePeSection(EncapsulatedFvHeader, EncapsulatedFvHeader->FvLength, FileType, Pe32Section);\r
+\r
+ if (!EFI_ERROR(Status)) {\r
+ // we found the core in the capsulated image, success\r
+ goto EarlyExit;\r
+ }\r
+\r
+ } // end encapsulated fv image section loop\r
+ } // end fv image file loop\r
+\r
+ // core was not found\r
+ Status = EFI_NOT_FOUND;\r
+\r
+EarlyExit:\r
+\r
+ // restore FV lib values\r
+ if(OrigFvHeader != NULL) {\r
+ InitializeFvLib(OrigFvHeader, OrigFvLength);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+GetCoreMachineType(\r
+ IN EFI_FILE_SECTION_POINTER Pe32Section,\r
+ OUT UINT16 *CoreMachineType\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Returns the machine type of a P32 image, typically SEC or PEI core.\r
+\r
+Arguments:\r
+\r
+ Pe32Section PE32 section data\r
+ CoreMachineType The extracted machine type\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS Function Completed successfully.\r
+ EFI_ABORTED Error encountered.\r
+ EFI_INVALID_PARAMETER A required parameter was NULL.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 EntryPoint;\r
+ UINT32 BaseOfCode;\r
+\r
+ if (CoreMachineType == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Status = GetPe32Info(\r
+ (VOID *)((UINTN)Pe32Section.Pe32Section + GetSectionHeaderLength(Pe32Section.CommonHeader)),\r
+ &EntryPoint,\r
+ &BaseOfCode,\r
+ CoreMachineType\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ Error(NULL, 0, 3000, "Invalid", "could not get the PE32 machine type for the core.");\r
+ return EFI_ABORTED;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+GetCoreEntryPointAddress(\r
+ IN VOID *FvImageBuffer,\r
+ IN FV_INFO *FvInfo,\r
+ IN EFI_FILE_SECTION_POINTER Pe32Section,\r
+ OUT EFI_PHYSICAL_ADDRESS *CoreEntryAddress\r
+)\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Returns the physical address of the core (SEC or PEI) entry point.\r
+\r
+Arguments:\r
+\r
+ FvImageBuffer Pointer to buffer containing FV data\r
+ FvInfo Info for the parent FV\r
+ Pe32Section PE32 section data\r
+ CoreEntryAddress The extracted core entry physical address\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS Function Completed successfully.\r
+ EFI_ABORTED Error encountered.\r
+ EFI_INVALID_PARAMETER A required parameter was NULL.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 EntryPoint;\r
+ UINT32 BaseOfCode;\r
+ UINT16 MachineType;\r
+ EFI_PHYSICAL_ADDRESS EntryPhysicalAddress;\r
+\r
+ if (CoreEntryAddress == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Status = GetPe32Info(\r
+ (VOID *)((UINTN)Pe32Section.Pe32Section + GetSectionHeaderLength(Pe32Section.CommonHeader)),\r
+ &EntryPoint,\r
+ &BaseOfCode,\r
+ &MachineType\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ Error(NULL, 0, 3000, "Invalid", "could not get the PE32 entry point for the core.");\r
+ return EFI_ABORTED;\r
+ }\r
+\r
+ //\r
+ // Physical address is FV base + offset of PE32 + offset of the entry point\r
+ //\r
+ EntryPhysicalAddress = FvInfo->BaseAddress;\r
+ EntryPhysicalAddress += (UINTN)Pe32Section.Pe32Section + GetSectionHeaderLength(Pe32Section.CommonHeader) - (UINTN)FvImageBuffer;\r
+ EntryPhysicalAddress += EntryPoint;\r
+\r
+ *CoreEntryAddress = EntryPhysicalAddress;\r
+\r
+ return EFI_SUCCESS;\r
+}\r