Home | History | Annotate | Download | only in FwVol
      1 /** @file
      2   Pei Core Firmware File System service routines.
      3 
      4 Copyright (c) 2015 HP Development Company, L.P.
      5 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
      6 This program and the accompanying materials
      7 are licensed and made available under the terms and conditions of the BSD License
      8 which accompanies this distribution.  The full text of the license may be found at
      9 http://opensource.org/licenses/bsd-license.php
     10 
     11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include "FwVol.h"
     17 
     18 EFI_PEI_NOTIFY_DESCRIPTOR mNotifyOnFvInfoList[] = {
     19   {
     20     EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
     21     &gEfiPeiFirmwareVolumeInfoPpiGuid,
     22     FirmwareVolmeInfoPpiNotifyCallback
     23   },
     24   {
     25     (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
     26     &gEfiPeiFirmwareVolumeInfo2PpiGuid,
     27     FirmwareVolmeInfoPpiNotifyCallback
     28   }
     29 };
     30 
     31 PEI_FW_VOL_INSTANCE mPeiFfs2FwVol = {
     32   PEI_FW_VOL_SIGNATURE,
     33   FALSE,
     34   {
     35     PeiFfsFvPpiProcessVolume,
     36     PeiFfsFvPpiFindFileByType,
     37     PeiFfsFvPpiFindFileByName,
     38     PeiFfsFvPpiGetFileInfo,
     39     PeiFfsFvPpiGetVolumeInfo,
     40     PeiFfsFvPpiFindSectionByType,
     41     PeiFfsFvPpiGetFileInfo2,
     42     PeiFfsFvPpiFindSectionByType2,
     43     EFI_PEI_FIRMWARE_VOLUME_PPI_SIGNATURE,
     44     EFI_PEI_FIRMWARE_VOLUME_PPI_REVISION
     45   }
     46 };
     47 
     48 PEI_FW_VOL_INSTANCE mPeiFfs3FwVol = {
     49   PEI_FW_VOL_SIGNATURE,
     50   TRUE,
     51   {
     52     PeiFfsFvPpiProcessVolume,
     53     PeiFfsFvPpiFindFileByType,
     54     PeiFfsFvPpiFindFileByName,
     55     PeiFfsFvPpiGetFileInfo,
     56     PeiFfsFvPpiGetVolumeInfo,
     57     PeiFfsFvPpiFindSectionByType,
     58     PeiFfsFvPpiGetFileInfo2,
     59     PeiFfsFvPpiFindSectionByType2,
     60     EFI_PEI_FIRMWARE_VOLUME_PPI_SIGNATURE,
     61     EFI_PEI_FIRMWARE_VOLUME_PPI_REVISION
     62   }
     63 };
     64 
     65 EFI_PEI_PPI_DESCRIPTOR  mPeiFfs2FvPpiList = {
     66   (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
     67   &gEfiFirmwareFileSystem2Guid,
     68   &mPeiFfs2FwVol.Fv
     69 };
     70 
     71 EFI_PEI_PPI_DESCRIPTOR  mPeiFfs3FvPpiList = {
     72   (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
     73   &gEfiFirmwareFileSystem3Guid,
     74   &mPeiFfs3FwVol.Fv
     75 };
     76 
     77 /**
     78 Required Alignment             Alignment Value in FFS         Alignment Value in
     79 (bytes)                        Attributes Field               Firmware Volume Interfaces
     80 1                                    0                                     0
     81 16                                   1                                     4
     82 128                                  2                                     7
     83 512                                  3                                     9
     84 1 KB                                 4                                     10
     85 4 KB                                 5                                     12
     86 32 KB                                6                                     15
     87 64 KB                                7                                     16
     88 **/
     89 UINT8 mFvAttributes[] = {0, 4, 7, 9, 10, 12, 15, 16};
     90 
     91 /**
     92   Convert the FFS File Attributes to FV File Attributes
     93 
     94   @param  FfsAttributes              The attributes of UINT8 type.
     95 
     96   @return The attributes of EFI_FV_FILE_ATTRIBUTES
     97 
     98 **/
     99 EFI_FV_FILE_ATTRIBUTES
    100 FfsAttributes2FvFileAttributes (
    101   IN EFI_FFS_FILE_ATTRIBUTES FfsAttributes
    102   )
    103 {
    104   UINT8                     DataAlignment;
    105   EFI_FV_FILE_ATTRIBUTES    FileAttribute;
    106 
    107   DataAlignment = (UINT8) ((FfsAttributes & FFS_ATTRIB_DATA_ALIGNMENT) >> 3);
    108   ASSERT (DataAlignment < 8);
    109 
    110   FileAttribute = (EFI_FV_FILE_ATTRIBUTES) mFvAttributes[DataAlignment];
    111 
    112   if ((FfsAttributes & FFS_ATTRIB_FIXED) == FFS_ATTRIB_FIXED) {
    113     FileAttribute |= EFI_FV_FILE_ATTRIB_FIXED;
    114   }
    115 
    116   return FileAttribute;
    117 }
    118 
    119 /**
    120   Returns the file state set by the highest zero bit in the State field
    121 
    122   @param ErasePolarity   Erase Polarity  as defined by EFI_FVB2_ERASE_POLARITY
    123                          in the Attributes field.
    124   @param FfsHeader       Pointer to FFS File Header.
    125 
    126   @retval EFI_FFS_FILE_STATE File state is set by the highest none zero bit
    127                              in the header State field.
    128 **/
    129 EFI_FFS_FILE_STATE
    130 GetFileState(
    131   IN UINT8                ErasePolarity,
    132   IN EFI_FFS_FILE_HEADER  *FfsHeader
    133   )
    134 {
    135   EFI_FFS_FILE_STATE  FileState;
    136   EFI_FFS_FILE_STATE  HighestBit;
    137 
    138   FileState = FfsHeader->State;
    139 
    140   if (ErasePolarity != 0) {
    141     FileState = (EFI_FFS_FILE_STATE)~FileState;
    142   }
    143 
    144   //
    145   // Get file state set by its highest none zero bit.
    146   //
    147   HighestBit = 0x80;
    148   while (HighestBit != 0 && (HighestBit & FileState) == 0) {
    149     HighestBit >>= 1;
    150   }
    151 
    152   return HighestBit;
    153 }
    154 
    155 /**
    156   Calculates the checksum of the header of a file.
    157 
    158   @param FileHeader      Pointer to FFS File Header.
    159 
    160   @return Checksum of the header.
    161           Zero means the header is good.
    162           Non-zero means the header is bad.
    163 **/
    164 UINT8
    165 CalculateHeaderChecksum (
    166   IN EFI_FFS_FILE_HEADER  *FileHeader
    167   )
    168 {
    169   EFI_FFS_FILE_HEADER2 TestFileHeader;
    170 
    171   if (IS_FFS_FILE2 (FileHeader)) {
    172     CopyMem (&TestFileHeader, FileHeader, sizeof (EFI_FFS_FILE_HEADER2));
    173     //
    174     // Ingore State and File field in FFS header.
    175     //
    176     TestFileHeader.State = 0;
    177     TestFileHeader.IntegrityCheck.Checksum.File = 0;
    178 
    179     return CalculateSum8 ((CONST UINT8 *) &TestFileHeader, sizeof (EFI_FFS_FILE_HEADER2));
    180   } else {
    181     CopyMem (&TestFileHeader, FileHeader, sizeof (EFI_FFS_FILE_HEADER));
    182     //
    183     // Ingore State and File field in FFS header.
    184     //
    185     TestFileHeader.State = 0;
    186     TestFileHeader.IntegrityCheck.Checksum.File = 0;
    187 
    188     return CalculateSum8 ((CONST UINT8 *) &TestFileHeader, sizeof (EFI_FFS_FILE_HEADER));
    189   }
    190 }
    191 
    192 /**
    193   Find FV handler according to FileHandle in that FV.
    194 
    195   @param FileHandle      Handle of file image
    196 
    197   @return Pointer to instance of PEI_CORE_FV_HANDLE.
    198 **/
    199 PEI_CORE_FV_HANDLE*
    200 FileHandleToVolume (
    201   IN   EFI_PEI_FILE_HANDLE          FileHandle
    202   )
    203 {
    204   UINTN                       Index;
    205   PEI_CORE_INSTANCE           *PrivateData;
    206   EFI_FIRMWARE_VOLUME_HEADER  *FwVolHeader;
    207   UINTN                       BestIndex;
    208 
    209   PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ());
    210   BestIndex   = PrivateData->FvCount;
    211 
    212   //
    213   // Find the best matched FV image that includes this FileHandle.
    214   // FV may include the child FV, and they are in the same continuous space.
    215   // If FileHandle is from the child FV, the updated logic can find its matched FV.
    216   //
    217   for (Index = 0; Index < PrivateData->FvCount; Index++) {
    218     FwVolHeader = PrivateData->Fv[Index].FvHeader;
    219     if (((UINT64) (UINTN) FileHandle > (UINT64) (UINTN) FwVolHeader ) &&   \
    220         ((UINT64) (UINTN) FileHandle <= ((UINT64) (UINTN) FwVolHeader + FwVolHeader->FvLength - 1))) {
    221       if (BestIndex == PrivateData->FvCount) {
    222         BestIndex = Index;
    223       } else {
    224         if ((UINT64) (UINTN) PrivateData->Fv[BestIndex].FvHeader < (UINT64) (UINTN) FwVolHeader) {
    225           BestIndex = Index;
    226         }
    227       }
    228     }
    229   }
    230 
    231   if (BestIndex < PrivateData->FvCount) {
    232     return &PrivateData->Fv[BestIndex];
    233   }
    234 
    235   return NULL;
    236 }
    237 
    238 /**
    239   Given the input file pointer, search for the first matching file in the
    240   FFS volume as defined by SearchType. The search starts from FileHeader inside
    241   the Firmware Volume defined by FwVolHeader.
    242   If SearchType is EFI_FV_FILETYPE_ALL, the first FFS file will return without check its file type.
    243   If SearchType is PEI_CORE_INTERNAL_FFS_FILE_DISPATCH_TYPE,
    244   the first PEIM, or COMBINED PEIM or FV file type FFS file will return.
    245 
    246   @param FvHandle        Pointer to the FV header of the volume to search
    247   @param FileName        File name
    248   @param SearchType      Filter to find only files of this type.
    249                          Type EFI_FV_FILETYPE_ALL causes no filtering to be done.
    250   @param FileHandle      This parameter must point to a valid FFS volume.
    251   @param AprioriFile     Pointer to AprioriFile image in this FV if has
    252 
    253   @return EFI_NOT_FOUND  No files matching the search criteria were found
    254   @retval EFI_SUCCESS    Success to search given file
    255 
    256 **/
    257 EFI_STATUS
    258 FindFileEx (
    259   IN  CONST EFI_PEI_FV_HANDLE        FvHandle,
    260   IN  CONST EFI_GUID                 *FileName,   OPTIONAL
    261   IN        EFI_FV_FILETYPE          SearchType,
    262   IN OUT    EFI_PEI_FILE_HANDLE      *FileHandle,
    263   IN OUT    EFI_PEI_FILE_HANDLE      *AprioriFile  OPTIONAL
    264   )
    265 {
    266   EFI_FIRMWARE_VOLUME_HEADER            *FwVolHeader;
    267   EFI_FIRMWARE_VOLUME_EXT_HEADER        *FwVolExtHeader;
    268   EFI_FFS_FILE_HEADER                   **FileHeader;
    269   EFI_FFS_FILE_HEADER                   *FfsFileHeader;
    270   UINT32                                FileLength;
    271   UINT32                                FileOccupiedSize;
    272   UINT32                                FileOffset;
    273   UINT64                                FvLength;
    274   UINT8                                 ErasePolarity;
    275   UINT8                                 FileState;
    276   UINT8                                 DataCheckSum;
    277   BOOLEAN                               IsFfs3Fv;
    278 
    279   //
    280   // Convert the handle of FV to FV header for memory-mapped firmware volume
    281   //
    282   FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) FvHandle;
    283   FileHeader  = (EFI_FFS_FILE_HEADER **)FileHandle;
    284 
    285   IsFfs3Fv = CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem3Guid);
    286 
    287   FvLength = FwVolHeader->FvLength;
    288   if ((FwVolHeader->Attributes & EFI_FVB2_ERASE_POLARITY) != 0) {
    289     ErasePolarity = 1;
    290   } else {
    291     ErasePolarity = 0;
    292   }
    293 
    294   //
    295   // If FileHeader is not specified (NULL) or FileName is not NULL,
    296   // start with the first file in the firmware volume.  Otherwise,
    297   // start from the FileHeader.
    298   //
    299   if ((*FileHeader == NULL) || (FileName != NULL)) {
    300     if (FwVolHeader->ExtHeaderOffset != 0) {
    301       //
    302       // Searching for files starts on an 8 byte aligned boundary after the end of the Extended Header if it exists.
    303       //
    304       FwVolExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *) ((UINT8 *) FwVolHeader + FwVolHeader->ExtHeaderOffset);
    305       FfsFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FwVolExtHeader + FwVolExtHeader->ExtHeaderSize);
    306       FfsFileHeader = (EFI_FFS_FILE_HEADER *) ALIGN_POINTER (FfsFileHeader, 8);
    307     } else {
    308       FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *) FwVolHeader + FwVolHeader->HeaderLength);
    309     }
    310   } else {
    311     if (IS_FFS_FILE2 (*FileHeader)) {
    312       if (!IsFfs3Fv) {
    313         DEBUG ((EFI_D_ERROR, "It is a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &(*FileHeader)->Name));
    314       }
    315       FileLength = FFS_FILE2_SIZE (*FileHeader);
    316       ASSERT (FileLength > 0x00FFFFFF);
    317     } else {
    318       FileLength = FFS_FILE_SIZE (*FileHeader);
    319     }
    320     //
    321     // FileLength is adjusted to FileOccupiedSize as it is 8 byte aligned.
    322     //
    323     FileOccupiedSize = GET_OCCUPIED_SIZE (FileLength, 8);
    324     FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)*FileHeader + FileOccupiedSize);
    325   }
    326 
    327   FileOffset = (UINT32) ((UINT8 *)FfsFileHeader - (UINT8 *)FwVolHeader);
    328   ASSERT (FileOffset <= 0xFFFFFFFF);
    329 
    330   while (FileOffset < (FvLength - sizeof (EFI_FFS_FILE_HEADER))) {
    331     //
    332     // Get FileState which is the highest bit of the State
    333     //
    334     FileState = GetFileState (ErasePolarity, FfsFileHeader);
    335     switch (FileState) {
    336 
    337     case EFI_FILE_HEADER_CONSTRUCTION:
    338     case EFI_FILE_HEADER_INVALID:
    339       if (IS_FFS_FILE2 (FfsFileHeader)) {
    340         if (!IsFfs3Fv) {
    341           DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &FfsFileHeader->Name));
    342         }
    343         FileOffset    += sizeof (EFI_FFS_FILE_HEADER2);
    344         FfsFileHeader =  (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER2));
    345       } else {
    346         FileOffset    += sizeof (EFI_FFS_FILE_HEADER);
    347         FfsFileHeader =  (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER));
    348       }
    349       break;
    350 
    351     case EFI_FILE_DATA_VALID:
    352     case EFI_FILE_MARKED_FOR_UPDATE:
    353       if (CalculateHeaderChecksum (FfsFileHeader) != 0) {
    354         ASSERT (FALSE);
    355         *FileHeader = NULL;
    356         return EFI_NOT_FOUND;
    357       }
    358 
    359       if (IS_FFS_FILE2 (FfsFileHeader)) {
    360         FileLength = FFS_FILE2_SIZE (FfsFileHeader);
    361         ASSERT (FileLength > 0x00FFFFFF);
    362         FileOccupiedSize = GET_OCCUPIED_SIZE (FileLength, 8);
    363         if (!IsFfs3Fv) {
    364           DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &FfsFileHeader->Name));
    365           FileOffset += FileOccupiedSize;
    366           FfsFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsFileHeader + FileOccupiedSize);
    367           break;
    368         }
    369       } else {
    370         FileLength = FFS_FILE_SIZE (FfsFileHeader);
    371         FileOccupiedSize = GET_OCCUPIED_SIZE (FileLength, 8);
    372       }
    373 
    374       DataCheckSum = FFS_FIXED_CHECKSUM;
    375       if ((FfsFileHeader->Attributes & FFS_ATTRIB_CHECKSUM) == FFS_ATTRIB_CHECKSUM) {
    376         if (IS_FFS_FILE2 (FfsFileHeader)) {
    377           DataCheckSum = CalculateCheckSum8 ((CONST UINT8 *) FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER2), FileLength - sizeof(EFI_FFS_FILE_HEADER2));
    378         } else {
    379           DataCheckSum = CalculateCheckSum8 ((CONST UINT8 *) FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER), FileLength - sizeof(EFI_FFS_FILE_HEADER));
    380         }
    381       }
    382       if (FfsFileHeader->IntegrityCheck.Checksum.File != DataCheckSum) {
    383         ASSERT (FALSE);
    384         *FileHeader = NULL;
    385         return EFI_NOT_FOUND;
    386       }
    387 
    388       if (FileName != NULL) {
    389         if (CompareGuid (&FfsFileHeader->Name, (EFI_GUID*)FileName)) {
    390           *FileHeader = FfsFileHeader;
    391           return EFI_SUCCESS;
    392         }
    393       } else if (SearchType == PEI_CORE_INTERNAL_FFS_FILE_DISPATCH_TYPE) {
    394         if ((FfsFileHeader->Type == EFI_FV_FILETYPE_PEIM) ||
    395             (FfsFileHeader->Type == EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER) ||
    396             (FfsFileHeader->Type == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE)) {
    397 
    398           *FileHeader = FfsFileHeader;
    399           return EFI_SUCCESS;
    400         } else if (AprioriFile != NULL) {
    401           if (FfsFileHeader->Type == EFI_FV_FILETYPE_FREEFORM) {
    402             if (CompareGuid (&FfsFileHeader->Name, &gPeiAprioriFileNameGuid)) {
    403               *AprioriFile = FfsFileHeader;
    404             }
    405           }
    406         }
    407       } else if (((SearchType == FfsFileHeader->Type) || (SearchType == EFI_FV_FILETYPE_ALL)) &&
    408                  (FfsFileHeader->Type != EFI_FV_FILETYPE_FFS_PAD)) {
    409         *FileHeader = FfsFileHeader;
    410         return EFI_SUCCESS;
    411       }
    412 
    413       FileOffset    += FileOccupiedSize;
    414       FfsFileHeader =  (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + FileOccupiedSize);
    415       break;
    416 
    417     case EFI_FILE_DELETED:
    418       if (IS_FFS_FILE2 (FfsFileHeader)) {
    419         if (!IsFfs3Fv) {
    420           DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &FfsFileHeader->Name));
    421         }
    422         FileLength = FFS_FILE2_SIZE (FfsFileHeader);
    423         ASSERT (FileLength > 0x00FFFFFF);
    424       } else {
    425         FileLength = FFS_FILE_SIZE (FfsFileHeader);
    426       }
    427       FileOccupiedSize =  GET_OCCUPIED_SIZE(FileLength, 8);
    428       FileOffset       += FileOccupiedSize;
    429       FfsFileHeader    =  (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + FileOccupiedSize);
    430       break;
    431 
    432     default:
    433       *FileHeader = NULL;
    434       return EFI_NOT_FOUND;
    435     }
    436   }
    437 
    438   *FileHeader = NULL;
    439   return EFI_NOT_FOUND;
    440 }
    441 
    442 /**
    443   Initialize PeiCore Fv List.
    444 
    445   @param PrivateData     - Pointer to PEI_CORE_INSTANCE.
    446   @param SecCoreData     - Pointer to EFI_SEC_PEI_HAND_OFF.
    447 **/
    448 VOID
    449 PeiInitializeFv (
    450   IN  PEI_CORE_INSTANCE           *PrivateData,
    451   IN CONST EFI_SEC_PEI_HAND_OFF   *SecCoreData
    452   )
    453 {
    454   EFI_STATUS                    Status;
    455   EFI_PEI_FIRMWARE_VOLUME_PPI   *FvPpi;
    456   EFI_PEI_FV_HANDLE             FvHandle;
    457   EFI_FIRMWARE_VOLUME_HEADER    *BfvHeader;
    458 
    459   //
    460   // Install FV_PPI for FFS2 file system.
    461   //
    462   PeiServicesInstallPpi (&mPeiFfs2FvPpiList);
    463 
    464   //
    465   // Install FV_PPI for FFS3 file system.
    466   //
    467   PeiServicesInstallPpi (&mPeiFfs3FvPpiList);
    468 
    469   BfvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)SecCoreData->BootFirmwareVolumeBase;
    470 
    471   //
    472   // The FV_PPI in BFV's format should be installed.
    473   //
    474   Status = PeiServicesLocatePpi (
    475              &BfvHeader->FileSystemGuid,
    476              0,
    477              NULL,
    478              (VOID**)&FvPpi
    479              );
    480   ASSERT_EFI_ERROR (Status);
    481 
    482   //
    483   // Get handle of BFV
    484   //
    485   FvPpi->ProcessVolume (
    486            FvPpi,
    487            SecCoreData->BootFirmwareVolumeBase,
    488            (UINTN)BfvHeader->FvLength,
    489            &FvHandle
    490            );
    491 
    492   //
    493   // Update internal PEI_CORE_FV array.
    494   //
    495   PrivateData->Fv[PrivateData->FvCount].FvHeader = BfvHeader;
    496   PrivateData->Fv[PrivateData->FvCount].FvPpi    = FvPpi;
    497   PrivateData->Fv[PrivateData->FvCount].FvHandle = FvHandle;
    498   PrivateData->Fv[PrivateData->FvCount].AuthenticationStatus = 0;
    499   DEBUG ((
    500     EFI_D_INFO,
    501     "The %dth FV start address is 0x%11p, size is 0x%08x, handle is 0x%p\n",
    502     (UINT32) PrivateData->FvCount,
    503     (VOID *) BfvHeader,
    504     BfvHeader->FvLength,
    505     FvHandle
    506     ));
    507   PrivateData->FvCount ++;
    508 
    509   //
    510   // Post a call-back for the FvInfoPPI and FvInfo2PPI services to expose
    511   // additional Fvs to PeiCore.
    512   //
    513   Status = PeiServicesNotifyPpi (mNotifyOnFvInfoList);
    514   ASSERT_EFI_ERROR (Status);
    515 
    516 }
    517 
    518 /**
    519   Process Firmware Volum Information once FvInfoPPI or FvInfo2PPI install.
    520   The FV Info will be registered into PeiCore private data structure.
    521   And search the inside FV image, if found, the new FV INFO(2) PPI will be installed.
    522 
    523   @param PeiServices       An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
    524   @param NotifyDescriptor  Address of the notification descriptor data structure.
    525   @param Ppi               Address of the PPI that was installed.
    526 
    527   @retval EFI_SUCCESS    The FV Info is registered into PeiCore private data structure.
    528   @return if not EFI_SUCESS, fail to verify FV.
    529 
    530 **/
    531 EFI_STATUS
    532 EFIAPI
    533 FirmwareVolmeInfoPpiNotifyCallback (
    534   IN EFI_PEI_SERVICES              **PeiServices,
    535   IN EFI_PEI_NOTIFY_DESCRIPTOR     *NotifyDescriptor,
    536   IN VOID                          *Ppi
    537   )
    538 {
    539   EFI_PEI_FIRMWARE_VOLUME_INFO2_PPI     FvInfo2Ppi;
    540   EFI_PEI_FIRMWARE_VOLUME_PPI           *FvPpi;
    541   PEI_CORE_INSTANCE                     *PrivateData;
    542   EFI_STATUS                            Status;
    543   EFI_PEI_FV_HANDLE                     FvHandle;
    544   UINTN                                 FvIndex;
    545   EFI_PEI_FILE_HANDLE                   FileHandle;
    546   VOID                                  *DepexData;
    547   BOOLEAN                               IsFvInfo2;
    548   UINTN                                 CurFvCount;
    549 
    550   Status       = EFI_SUCCESS;
    551   PrivateData  = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
    552 
    553   if (CompareGuid (NotifyDescriptor->Guid, &gEfiPeiFirmwareVolumeInfo2PpiGuid)) {
    554     //
    555     // It is FvInfo2PPI.
    556     //
    557     CopyMem (&FvInfo2Ppi, Ppi, sizeof (EFI_PEI_FIRMWARE_VOLUME_INFO2_PPI));
    558     IsFvInfo2 = TRUE;
    559   } else {
    560     //
    561     // It is FvInfoPPI.
    562     //
    563     CopyMem (&FvInfo2Ppi, Ppi, sizeof (EFI_PEI_FIRMWARE_VOLUME_INFO_PPI));
    564     FvInfo2Ppi.AuthenticationStatus = 0;
    565     IsFvInfo2 = FALSE;
    566   }
    567 
    568   if (CompareGuid (&FvInfo2Ppi.FvFormat, &gEfiFirmwareFileSystem2Guid)) {
    569     //
    570     // gEfiFirmwareFileSystem2Guid is specified for FvFormat, then here to check the
    571     // FileSystemGuid pointed by FvInfo against gEfiFirmwareFileSystem2Guid to make sure
    572     // FvInfo has the firmware file system 2 format.
    573     //
    574     // If the ASSERT really appears, FvFormat needs to be specified correctly, for example,
    575     // gEfiFirmwareFileSystem3Guid can be used for firmware file system 3 format, or
    576     // ((EFI_FIRMWARE_VOLUME_HEADER *) FvInfo)->FileSystemGuid can be just used for both
    577     // firmware file system 2 and 3 format.
    578     //
    579     ASSERT (CompareGuid (&(((EFI_FIRMWARE_VOLUME_HEADER *) FvInfo2Ppi.FvInfo)->FileSystemGuid), &gEfiFirmwareFileSystem2Guid));
    580   }
    581 
    582   //
    583   // Locate the corresponding FV_PPI according to founded FV's format guid
    584   //
    585   Status = PeiServicesLocatePpi (
    586              &FvInfo2Ppi.FvFormat,
    587              0,
    588              NULL,
    589              (VOID**)&FvPpi
    590              );
    591   if (!EFI_ERROR (Status)) {
    592     //
    593     // Process new found FV and get FV handle.
    594     //
    595     Status = FvPpi->ProcessVolume (FvPpi, FvInfo2Ppi.FvInfo, FvInfo2Ppi.FvInfoSize, &FvHandle);
    596     if (EFI_ERROR (Status)) {
    597       DEBUG ((EFI_D_ERROR, "Fail to process new found FV, FV may be corrupted!\n"));
    598       return Status;
    599     }
    600 
    601     //
    602     // Check whether the FV has already been processed.
    603     //
    604     for (FvIndex = 0; FvIndex < PrivateData->FvCount; FvIndex ++) {
    605       if (PrivateData->Fv[FvIndex].FvHandle == FvHandle) {
    606         if (IsFvInfo2 && (FvInfo2Ppi.AuthenticationStatus != PrivateData->Fv[FvIndex].AuthenticationStatus)) {
    607           PrivateData->Fv[FvIndex].AuthenticationStatus = FvInfo2Ppi.AuthenticationStatus;
    608           DEBUG ((EFI_D_INFO, "Update AuthenticationStatus of the %dth FV to 0x%x!\n", FvIndex, FvInfo2Ppi.AuthenticationStatus));
    609         }
    610         DEBUG ((EFI_D_INFO, "The Fv %p has already been processed!\n", FvInfo2Ppi.FvInfo));
    611         return EFI_SUCCESS;
    612       }
    613     }
    614 
    615     if (PrivateData->FvCount >= PcdGet32 (PcdPeiCoreMaxFvSupported)) {
    616       DEBUG ((EFI_D_ERROR, "The number of Fv Images (%d) exceed the max supported FVs (%d) in Pei", PrivateData->FvCount + 1, PcdGet32 (PcdPeiCoreMaxFvSupported)));
    617       DEBUG ((EFI_D_ERROR, "PcdPeiCoreMaxFvSupported value need be reconfigurated in DSC"));
    618       ASSERT (FALSE);
    619     }
    620 
    621     //
    622     // Update internal PEI_CORE_FV array.
    623     //
    624     PrivateData->Fv[PrivateData->FvCount].FvHeader = (EFI_FIRMWARE_VOLUME_HEADER*) FvInfo2Ppi.FvInfo;
    625     PrivateData->Fv[PrivateData->FvCount].FvPpi    = FvPpi;
    626     PrivateData->Fv[PrivateData->FvCount].FvHandle = FvHandle;
    627     PrivateData->Fv[PrivateData->FvCount].AuthenticationStatus = FvInfo2Ppi.AuthenticationStatus;
    628     CurFvCount = PrivateData->FvCount;
    629     DEBUG ((
    630       EFI_D_INFO,
    631       "The %dth FV start address is 0x%11p, size is 0x%08x, handle is 0x%p\n",
    632       (UINT32) CurFvCount,
    633       (VOID *) FvInfo2Ppi.FvInfo,
    634       FvInfo2Ppi.FvInfoSize,
    635       FvHandle
    636       ));
    637     PrivateData->FvCount ++;
    638 
    639     //
    640     // Scan and process the new discoveried FV for EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
    641     //
    642     FileHandle = NULL;
    643     do {
    644       Status = FvPpi->FindFileByType (
    645                         FvPpi,
    646                         EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE,
    647                         FvHandle,
    648                         &FileHandle
    649                        );
    650       if (!EFI_ERROR (Status)) {
    651         Status = FvPpi->FindSectionByType (
    652                           FvPpi,
    653                           EFI_SECTION_PEI_DEPEX,
    654                           FileHandle,
    655                           (VOID**)&DepexData
    656                           );
    657         if (!EFI_ERROR (Status)) {
    658           if (!PeimDispatchReadiness (PeiServices, DepexData)) {
    659             //
    660             // Dependency is not satisfied.
    661             //
    662             continue;
    663           }
    664         }
    665 
    666         DEBUG ((EFI_D_INFO, "Found firmware volume Image File %p in FV[%d] %p\n", FileHandle, CurFvCount, FvHandle));
    667         ProcessFvFile (PrivateData, &PrivateData->Fv[CurFvCount], FileHandle);
    668       }
    669     } while (FileHandle != NULL);
    670   } else {
    671     DEBUG ((EFI_D_ERROR, "Fail to process FV %p because no corresponding EFI_FIRMWARE_VOLUME_PPI is found!\n", FvInfo2Ppi.FvInfo));
    672 
    673     AddUnknownFormatFvInfo (PrivateData, &FvInfo2Ppi);
    674   }
    675 
    676   return EFI_SUCCESS;
    677 }
    678 
    679 /**
    680   Verify the Guided Section GUID by checking if there is the Guided Section GUID HOB recorded the GUID itself.
    681 
    682   @param GuidedSectionGuid          The Guided Section GUID.
    683   @param GuidedSectionExtraction    A pointer to the pointer to the supported Guided Section Extraction Ppi
    684                                     for the Guided Section.
    685 
    686   @return TRUE      The GuidedSectionGuid could be identified, and the pointer to
    687                     the Guided Section Extraction Ppi will be returned to *GuidedSectionExtraction.
    688   @return FALSE     The GuidedSectionGuid could not be identified, or
    689                     the Guided Section Extraction Ppi has not been installed yet.
    690 
    691 **/
    692 BOOLEAN
    693 VerifyGuidedSectionGuid (
    694   IN  EFI_GUID                                  *GuidedSectionGuid,
    695   OUT EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI     **GuidedSectionExtraction
    696   )
    697 {
    698   EFI_PEI_HOB_POINTERS  Hob;
    699   EFI_GUID              *GuidRecorded;
    700   VOID                  *Interface;
    701   EFI_STATUS            Status;
    702 
    703   //
    704   // Check if there is the Guided Section GUID HOB recorded the GUID itself.
    705   //
    706   Hob.Raw = GetFirstGuidHob (GuidedSectionGuid);
    707   if (Hob.Raw != NULL) {
    708     GuidRecorded = (EFI_GUID *) GET_GUID_HOB_DATA (Hob);
    709     if (CompareGuid (GuidRecorded, GuidedSectionGuid)) {
    710       //
    711       // Found the recorded GuidedSectionGuid.
    712       //
    713       Status = PeiServicesLocatePpi (GuidedSectionGuid, 0, NULL, (VOID **) &Interface);
    714       if (!EFI_ERROR (Status) && Interface != NULL) {
    715         //
    716         // Found the supported Guided Section Extraction Ppi for the Guided Section.
    717         //
    718         *GuidedSectionExtraction = (EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI *) Interface;
    719         return TRUE;
    720       }
    721       return FALSE;
    722     }
    723   }
    724 
    725   return FALSE;
    726 }
    727 
    728 /**
    729   Go through the file to search SectionType section.
    730   Search within encapsulation sections (compression and GUIDed) recursively,
    731   until the match section is found.
    732 
    733   @param PeiServices       An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
    734   @param SectionType       Filter to find only section of this type.
    735   @param SectionInstance   Pointer to the filter to find the specific instance of section.
    736   @param Section           From where to search.
    737   @param SectionSize       The file size to search.
    738   @param OutputBuffer      A pointer to the discovered section, if successful.
    739                            NULL if section not found
    740   @param AuthenticationStatus Updated upon return to point to the authentication status for this section.
    741   @param IsFfs3Fv          Indicates the FV format.
    742 
    743   @return EFI_NOT_FOUND    The match section is not found.
    744   @return EFI_SUCCESS      The match section is found.
    745 
    746 **/
    747 EFI_STATUS
    748 ProcessSection (
    749   IN CONST EFI_PEI_SERVICES     **PeiServices,
    750   IN EFI_SECTION_TYPE           SectionType,
    751   IN OUT UINTN                  *SectionInstance,
    752   IN EFI_COMMON_SECTION_HEADER  *Section,
    753   IN UINTN                      SectionSize,
    754   OUT VOID                      **OutputBuffer,
    755   OUT UINT32                    *AuthenticationStatus,
    756   IN BOOLEAN                    IsFfs3Fv
    757   )
    758 {
    759   EFI_STATUS                              Status;
    760   UINT32                                  SectionLength;
    761   UINT32                                  ParsedLength;
    762   EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI   *GuidSectionPpi;
    763   EFI_PEI_DECOMPRESS_PPI                  *DecompressPpi;
    764   VOID                                    *PpiOutput;
    765   UINTN                                   PpiOutputSize;
    766   UINTN                                   Index;
    767   UINT32                                  Authentication;
    768   PEI_CORE_INSTANCE                       *PrivateData;
    769   EFI_GUID                                *SectionDefinitionGuid;
    770   BOOLEAN                                 SectionCached;
    771   VOID                                    *TempOutputBuffer;
    772   UINT32                                  TempAuthenticationStatus;
    773   UINT16                                  GuidedSectionAttributes;
    774 
    775   PrivateData   = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
    776   *OutputBuffer = NULL;
    777   ParsedLength  = 0;
    778   Index         = 0;
    779   Status        = EFI_NOT_FOUND;
    780   PpiOutput     = NULL;
    781   PpiOutputSize = 0;
    782   while (ParsedLength < SectionSize) {
    783 
    784     if (IS_SECTION2 (Section)) {
    785       ASSERT (SECTION2_SIZE (Section) > 0x00FFFFFF);
    786       if (!IsFfs3Fv) {
    787         DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted section in a non-FFS3 formatted FV.\n"));
    788         SectionLength = SECTION2_SIZE (Section);
    789         //
    790         // SectionLength is adjusted it is 4 byte aligned.
    791         // Go to the next section
    792         //
    793         SectionLength = GET_OCCUPIED_SIZE (SectionLength, 4);
    794         ASSERT (SectionLength != 0);
    795         ParsedLength += SectionLength;
    796         Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) Section + SectionLength);
    797         continue;
    798       }
    799     }
    800 
    801     if (Section->Type == SectionType) {
    802       //
    803       // The type matches, so check the instance count to see if it's the one we want.
    804       //
    805       (*SectionInstance)--;
    806       if (*SectionInstance == 0) {
    807         //
    808         // Got it!
    809         //
    810         if (IS_SECTION2 (Section)) {
    811           *OutputBuffer = (VOID *)((UINT8 *) Section + sizeof (EFI_COMMON_SECTION_HEADER2));
    812         } else {
    813           *OutputBuffer = (VOID *)((UINT8 *) Section + sizeof (EFI_COMMON_SECTION_HEADER));
    814         }
    815         return EFI_SUCCESS;
    816       } else {
    817         if (IS_SECTION2 (Section)) {
    818           SectionLength = SECTION2_SIZE (Section);
    819         } else {
    820           SectionLength = SECTION_SIZE (Section);
    821         }
    822         //
    823         // SectionLength is adjusted it is 4 byte aligned.
    824         // Go to the next section
    825         //
    826         SectionLength = GET_OCCUPIED_SIZE (SectionLength, 4);
    827         ASSERT (SectionLength != 0);
    828         ParsedLength += SectionLength;
    829         Section = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)Section + SectionLength);
    830         continue;
    831       }
    832     } else if ((Section->Type == EFI_SECTION_GUID_DEFINED) || (Section->Type == EFI_SECTION_COMPRESSION)) {
    833       //
    834       // Check the encapsulated section is extracted into the cache data.
    835       //
    836       SectionCached = FALSE;
    837       for (Index = 0; Index < PrivateData->CacheSection.AllSectionCount; Index ++) {
    838         if (Section == PrivateData->CacheSection.Section[Index]) {
    839           SectionCached = TRUE;
    840           PpiOutput     = PrivateData->CacheSection.SectionData[Index];
    841           PpiOutputSize = PrivateData->CacheSection.SectionSize[Index];
    842           Authentication = PrivateData->CacheSection.AuthenticationStatus[Index];
    843           //
    844           // Search section directly from the cache data.
    845           //
    846           TempAuthenticationStatus = 0;
    847           Status = ProcessSection (
    848                      PeiServices,
    849                      SectionType,
    850                      SectionInstance,
    851                      PpiOutput,
    852                      PpiOutputSize,
    853                      &TempOutputBuffer,
    854                      &TempAuthenticationStatus,
    855                      IsFfs3Fv
    856                    );
    857           if (!EFI_ERROR (Status)) {
    858             *OutputBuffer = TempOutputBuffer;
    859             *AuthenticationStatus = TempAuthenticationStatus | Authentication;
    860             return EFI_SUCCESS;
    861           }
    862         }
    863       }
    864 
    865       //
    866       // If SectionCached is TRUE, the section data has been cached and scanned.
    867       //
    868       if (!SectionCached) {
    869         Status = EFI_NOT_FOUND;
    870         Authentication = 0;
    871         if (Section->Type == EFI_SECTION_GUID_DEFINED) {
    872           if (IS_SECTION2 (Section)) {
    873             SectionDefinitionGuid   = &((EFI_GUID_DEFINED_SECTION2 *)Section)->SectionDefinitionGuid;
    874             GuidedSectionAttributes = ((EFI_GUID_DEFINED_SECTION2 *)Section)->Attributes;
    875           } else {
    876             SectionDefinitionGuid   = &((EFI_GUID_DEFINED_SECTION *)Section)->SectionDefinitionGuid;
    877             GuidedSectionAttributes = ((EFI_GUID_DEFINED_SECTION *)Section)->Attributes;
    878           }
    879           if (VerifyGuidedSectionGuid (SectionDefinitionGuid, &GuidSectionPpi)) {
    880             Status = GuidSectionPpi->ExtractSection (
    881                                        GuidSectionPpi,
    882                                        Section,
    883                                        &PpiOutput,
    884                                        &PpiOutputSize,
    885                                        &Authentication
    886                                        );
    887           } else if ((GuidedSectionAttributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) == 0) {
    888             //
    889             // Figure out the proper authentication status for GUIDED section without processing required
    890             //
    891             Status = EFI_SUCCESS;
    892             if ((GuidedSectionAttributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) == EFI_GUIDED_SECTION_AUTH_STATUS_VALID) {
    893               Authentication |= EFI_AUTH_STATUS_IMAGE_SIGNED | EFI_AUTH_STATUS_NOT_TESTED;
    894             }
    895             if (IS_SECTION2 (Section)) {
    896               PpiOutputSize = SECTION2_SIZE (Section) - ((EFI_GUID_DEFINED_SECTION2 *) Section)->DataOffset;
    897               PpiOutput     = (UINT8 *) Section + ((EFI_GUID_DEFINED_SECTION2 *) Section)->DataOffset;
    898             } else {
    899               PpiOutputSize = SECTION_SIZE (Section) - ((EFI_GUID_DEFINED_SECTION *) Section)->DataOffset;
    900               PpiOutput     = (UINT8 *) Section + ((EFI_GUID_DEFINED_SECTION *) Section)->DataOffset;
    901             }
    902           }
    903         } else if (Section->Type == EFI_SECTION_COMPRESSION) {
    904           Status = PeiServicesLocatePpi (&gEfiPeiDecompressPpiGuid, 0, NULL, (VOID **) &DecompressPpi);
    905           if (!EFI_ERROR (Status)) {
    906             Status = DecompressPpi->Decompress (
    907                                       DecompressPpi,
    908                                       (CONST EFI_COMPRESSION_SECTION*) Section,
    909                                       &PpiOutput,
    910                                       &PpiOutputSize
    911                                       );
    912           }
    913         }
    914 
    915         if (!EFI_ERROR (Status)) {
    916           //
    917           // Update cache section data.
    918           //
    919           if (PrivateData->CacheSection.AllSectionCount < CACHE_SETION_MAX_NUMBER) {
    920             PrivateData->CacheSection.AllSectionCount ++;
    921           }
    922           PrivateData->CacheSection.Section [PrivateData->CacheSection.SectionIndex]     = Section;
    923           PrivateData->CacheSection.SectionData [PrivateData->CacheSection.SectionIndex] = PpiOutput;
    924           PrivateData->CacheSection.SectionSize [PrivateData->CacheSection.SectionIndex] = PpiOutputSize;
    925           PrivateData->CacheSection.AuthenticationStatus [PrivateData->CacheSection.SectionIndex] = Authentication;
    926           PrivateData->CacheSection.SectionIndex = (PrivateData->CacheSection.SectionIndex + 1)%CACHE_SETION_MAX_NUMBER;
    927 
    928           TempAuthenticationStatus = 0;
    929           Status = ProcessSection (
    930                      PeiServices,
    931                      SectionType,
    932                      SectionInstance,
    933                      PpiOutput,
    934                      PpiOutputSize,
    935                      &TempOutputBuffer,
    936                      &TempAuthenticationStatus,
    937                      IsFfs3Fv
    938                    );
    939           if (!EFI_ERROR (Status)) {
    940             *OutputBuffer = TempOutputBuffer;
    941             *AuthenticationStatus = TempAuthenticationStatus | Authentication;
    942             return EFI_SUCCESS;
    943           }
    944         }
    945       }
    946     }
    947 
    948     if (IS_SECTION2 (Section)) {
    949       SectionLength = SECTION2_SIZE (Section);
    950     } else {
    951       SectionLength = SECTION_SIZE (Section);
    952     }
    953     //
    954     // SectionLength is adjusted it is 4 byte aligned.
    955     // Go to the next section
    956     //
    957     SectionLength = GET_OCCUPIED_SIZE (SectionLength, 4);
    958     ASSERT (SectionLength != 0);
    959     ParsedLength += SectionLength;
    960     Section = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)Section + SectionLength);
    961   }
    962 
    963   return EFI_NOT_FOUND;
    964 }
    965 
    966 
    967 /**
    968   Searches for the next matching section within the specified file.
    969 
    970   @param PeiServices     An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
    971   @param SectionType     Filter to find only sections of this type.
    972   @param FileHandle      Pointer to the current file to search.
    973   @param SectionData     A pointer to the discovered section, if successful.
    974                          NULL if section not found
    975 
    976   @retval EFI_NOT_FOUND  The section was not found.
    977   @retval EFI_SUCCESS    The section was found.
    978 
    979 **/
    980 EFI_STATUS
    981 EFIAPI
    982 PeiFfsFindSectionData (
    983   IN CONST EFI_PEI_SERVICES    **PeiServices,
    984   IN     EFI_SECTION_TYPE      SectionType,
    985   IN     EFI_PEI_FILE_HANDLE   FileHandle,
    986   OUT VOID                     **SectionData
    987   )
    988 {
    989   PEI_CORE_FV_HANDLE           *CoreFvHandle;
    990 
    991   CoreFvHandle = FileHandleToVolume (FileHandle);
    992   if ((CoreFvHandle == NULL) || (CoreFvHandle->FvPpi == NULL)) {
    993     return EFI_NOT_FOUND;
    994   }
    995 
    996   return CoreFvHandle->FvPpi->FindSectionByType (CoreFvHandle->FvPpi, SectionType, FileHandle, SectionData);
    997 }
    998 
    999 /**
   1000   Searches for the next matching section within the specified file.
   1001 
   1002   @param  PeiServices           An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
   1003   @param  SectionType           The value of the section type to find.
   1004   @param  SectionInstance       Section instance to find.
   1005   @param  FileHandle            Handle of the firmware file to search.
   1006   @param  SectionData           A pointer to the discovered section, if successful.
   1007   @param  AuthenticationStatus  A pointer to the authentication status for this section.
   1008 
   1009   @retval EFI_SUCCESS      The section was found.
   1010   @retval EFI_NOT_FOUND    The section was not found.
   1011 
   1012 **/
   1013 EFI_STATUS
   1014 EFIAPI
   1015 PeiFfsFindSectionData3 (
   1016   IN CONST EFI_PEI_SERVICES    **PeiServices,
   1017   IN     EFI_SECTION_TYPE      SectionType,
   1018   IN     UINTN                 SectionInstance,
   1019   IN     EFI_PEI_FILE_HANDLE   FileHandle,
   1020   OUT VOID                     **SectionData,
   1021   OUT UINT32                   *AuthenticationStatus
   1022   )
   1023 {
   1024   PEI_CORE_FV_HANDLE           *CoreFvHandle;
   1025 
   1026   CoreFvHandle = FileHandleToVolume (FileHandle);
   1027   if ((CoreFvHandle == NULL) || (CoreFvHandle->FvPpi == NULL)) {
   1028     return EFI_NOT_FOUND;
   1029   }
   1030 
   1031   if ((CoreFvHandle->FvPpi->Signature == EFI_PEI_FIRMWARE_VOLUME_PPI_SIGNATURE) &&
   1032       (CoreFvHandle->FvPpi->Revision == EFI_PEI_FIRMWARE_VOLUME_PPI_REVISION)) {
   1033     return CoreFvHandle->FvPpi->FindSectionByType2 (CoreFvHandle->FvPpi, SectionType, SectionInstance, FileHandle, SectionData, AuthenticationStatus);
   1034   }
   1035   //
   1036   // The old FvPpi doesn't support to find section by section instance
   1037   // and return authentication status, so return EFI_UNSUPPORTED.
   1038   //
   1039   return EFI_UNSUPPORTED;
   1040 }
   1041 
   1042 /**
   1043   Searches for the next matching file in the firmware volume.
   1044 
   1045   @param PeiServices     An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
   1046   @param SearchType      Filter to find only files of this type.
   1047                          Type EFI_FV_FILETYPE_ALL causes no filtering to be done.
   1048   @param FvHandle        Handle of firmware volume in which to search.
   1049   @param FileHandle      On entry, points to the current handle from which to begin searching or NULL to start
   1050                          at the beginning of the firmware volume. On exit, points the file handle of the next file
   1051                          in the volume or NULL if there are no more files.
   1052 
   1053   @retval EFI_NOT_FOUND  The file was not found.
   1054   @retval EFI_NOT_FOUND  The header checksum was not zero.
   1055   @retval EFI_SUCCESS    The file was found.
   1056 
   1057 **/
   1058 EFI_STATUS
   1059 EFIAPI
   1060 PeiFfsFindNextFile (
   1061   IN CONST EFI_PEI_SERVICES      **PeiServices,
   1062   IN UINT8                       SearchType,
   1063   IN EFI_PEI_FV_HANDLE           FvHandle,
   1064   IN OUT EFI_PEI_FILE_HANDLE     *FileHandle
   1065   )
   1066 {
   1067   PEI_CORE_FV_HANDLE      *CoreFvHandle;
   1068 
   1069   CoreFvHandle = FvHandleToCoreHandle (FvHandle);
   1070 
   1071   //
   1072   // To make backward compatiblity, if can not find corresponding the handle of FV
   1073   // then treat FV as build-in FFS2/FFS3 format and memory mapped FV that FV handle is pointed
   1074   // to the address of first byte of FV.
   1075   //
   1076   if ((CoreFvHandle == NULL) && FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {
   1077     return FindFileEx (FvHandle, NULL, SearchType, FileHandle, NULL);
   1078   }
   1079 
   1080   if ((CoreFvHandle == NULL) || CoreFvHandle->FvPpi == NULL) {
   1081     return EFI_NOT_FOUND;
   1082   }
   1083 
   1084   return CoreFvHandle->FvPpi->FindFileByType (CoreFvHandle->FvPpi, SearchType, FvHandle, FileHandle);
   1085 }
   1086 
   1087 
   1088 /**
   1089   Search the firmware volumes by index
   1090 
   1091   @param PeiServices     An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
   1092   @param Instance        This instance of the firmware volume to find. The value 0 is the Boot Firmware
   1093                          Volume (BFV).
   1094   @param VolumeHandle    On exit, points to the next volume handle or NULL if it does not exist.
   1095 
   1096   @retval EFI_INVALID_PARAMETER  VolumeHandle is NULL
   1097   @retval EFI_NOT_FOUND          The volume was not found.
   1098   @retval EFI_SUCCESS            The volume was found.
   1099 
   1100 **/
   1101 EFI_STATUS
   1102 EFIAPI
   1103 PeiFfsFindNextVolume (
   1104   IN CONST EFI_PEI_SERVICES         **PeiServices,
   1105   IN     UINTN                      Instance,
   1106   IN OUT EFI_PEI_FV_HANDLE          *VolumeHandle
   1107   )
   1108 {
   1109   PEI_CORE_INSTANCE  *Private;
   1110   PEI_CORE_FV_HANDLE *CoreFvHandle;
   1111 
   1112   if (VolumeHandle == NULL) {
   1113     return EFI_INVALID_PARAMETER;
   1114   }
   1115 
   1116   Private = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
   1117 
   1118   CoreFvHandle = FindNextCoreFvHandle (Private, Instance);
   1119   if (CoreFvHandle == NULL) {
   1120     *VolumeHandle = NULL;
   1121     return EFI_NOT_FOUND;
   1122   }
   1123 
   1124   *VolumeHandle = CoreFvHandle->FvHandle;
   1125 
   1126   return EFI_SUCCESS;
   1127 }
   1128 
   1129 
   1130 /**
   1131   Find a file within a volume by its name.
   1132 
   1133   @param FileName        A pointer to the name of the file to find within the firmware volume.
   1134   @param VolumeHandle    The firmware volume to search
   1135   @param FileHandle      Upon exit, points to the found file's handle
   1136                          or NULL if it could not be found.
   1137 
   1138   @retval EFI_SUCCESS            File was found.
   1139   @retval EFI_NOT_FOUND          File was not found.
   1140   @retval EFI_INVALID_PARAMETER  VolumeHandle or FileHandle or FileName was NULL.
   1141 
   1142 **/
   1143 EFI_STATUS
   1144 EFIAPI
   1145 PeiFfsFindFileByName (
   1146   IN  CONST EFI_GUID        *FileName,
   1147   IN  EFI_PEI_FV_HANDLE     VolumeHandle,
   1148   OUT EFI_PEI_FILE_HANDLE   *FileHandle
   1149   )
   1150 {
   1151   PEI_CORE_FV_HANDLE            *CoreFvHandle;
   1152 
   1153   if ((VolumeHandle == NULL) || (FileName == NULL) || (FileHandle == NULL)) {
   1154     return EFI_INVALID_PARAMETER;
   1155   }
   1156 
   1157   CoreFvHandle = FvHandleToCoreHandle (VolumeHandle);
   1158   if ((CoreFvHandle == NULL) || (CoreFvHandle->FvPpi == NULL)) {
   1159     return EFI_NOT_FOUND;
   1160   }
   1161 
   1162   return CoreFvHandle->FvPpi->FindFileByName (CoreFvHandle->FvPpi, FileName, &VolumeHandle, FileHandle);
   1163 }
   1164 
   1165 /**
   1166   Returns information about a specific file.
   1167 
   1168   @param FileHandle       Handle of the file.
   1169   @param FileInfo         Upon exit, points to the file's information.
   1170 
   1171   @retval EFI_INVALID_PARAMETER If FileInfo is NULL.
   1172   @retval EFI_INVALID_PARAMETER If FileHandle does not represent a valid file.
   1173   @retval EFI_SUCCESS           File information returned.
   1174 
   1175 **/
   1176 EFI_STATUS
   1177 EFIAPI
   1178 PeiFfsGetFileInfo (
   1179   IN EFI_PEI_FILE_HANDLE  FileHandle,
   1180   OUT EFI_FV_FILE_INFO    *FileInfo
   1181   )
   1182 {
   1183   PEI_CORE_FV_HANDLE          *CoreFvHandle;
   1184 
   1185   if ((FileHandle == NULL) || (FileInfo == NULL)) {
   1186     return EFI_INVALID_PARAMETER;
   1187   }
   1188 
   1189   //
   1190   // Retrieve the FirmwareVolume which the file resides in.
   1191   //
   1192   CoreFvHandle = FileHandleToVolume (FileHandle);
   1193   if ((CoreFvHandle == NULL) || (CoreFvHandle->FvPpi == NULL)) {
   1194     return EFI_INVALID_PARAMETER;
   1195   }
   1196 
   1197   return CoreFvHandle->FvPpi->GetFileInfo (CoreFvHandle->FvPpi, FileHandle, FileInfo);
   1198 }
   1199 
   1200 /**
   1201   Returns information about a specific file.
   1202 
   1203   @param FileHandle       Handle of the file.
   1204   @param FileInfo         Upon exit, points to the file's information.
   1205 
   1206   @retval EFI_INVALID_PARAMETER If FileInfo is NULL.
   1207   @retval EFI_INVALID_PARAMETER If FileHandle does not represent a valid file.
   1208   @retval EFI_SUCCESS           File information returned.
   1209 
   1210 **/
   1211 EFI_STATUS
   1212 EFIAPI
   1213 PeiFfsGetFileInfo2 (
   1214   IN EFI_PEI_FILE_HANDLE  FileHandle,
   1215   OUT EFI_FV_FILE_INFO2   *FileInfo
   1216   )
   1217 {
   1218   PEI_CORE_FV_HANDLE          *CoreFvHandle;
   1219 
   1220   if ((FileHandle == NULL) || (FileInfo == NULL)) {
   1221     return EFI_INVALID_PARAMETER;
   1222   }
   1223 
   1224   //
   1225   // Retrieve the FirmwareVolume which the file resides in.
   1226   //
   1227   CoreFvHandle = FileHandleToVolume (FileHandle);
   1228   if ((CoreFvHandle == NULL) || (CoreFvHandle->FvPpi == NULL)) {
   1229     return EFI_INVALID_PARAMETER;
   1230   }
   1231 
   1232   if ((CoreFvHandle->FvPpi->Signature == EFI_PEI_FIRMWARE_VOLUME_PPI_SIGNATURE) &&
   1233       (CoreFvHandle->FvPpi->Revision == EFI_PEI_FIRMWARE_VOLUME_PPI_REVISION)) {
   1234     return CoreFvHandle->FvPpi->GetFileInfo2 (CoreFvHandle->FvPpi, FileHandle, FileInfo);
   1235   }
   1236   //
   1237   // The old FvPpi doesn't support to return file info with authentication status,
   1238   // so return EFI_UNSUPPORTED.
   1239   //
   1240   return EFI_UNSUPPORTED;
   1241 }
   1242 
   1243 /**
   1244   Returns information about the specified volume.
   1245 
   1246   This function returns information about a specific firmware
   1247   volume, including its name, type, attributes, starting address
   1248   and size.
   1249 
   1250   @param VolumeHandle   Handle of the volume.
   1251   @param VolumeInfo     Upon exit, points to the volume's information.
   1252 
   1253   @retval EFI_SUCCESS             Volume information returned.
   1254   @retval EFI_INVALID_PARAMETER   If VolumeHandle does not represent a valid volume.
   1255   @retval EFI_INVALID_PARAMETER   If VolumeHandle is NULL.
   1256   @retval EFI_SUCCESS             Information successfully returned.
   1257   @retval EFI_INVALID_PARAMETER   The volume designated by the VolumeHandle is not available.
   1258 
   1259 **/
   1260 EFI_STATUS
   1261 EFIAPI
   1262 PeiFfsGetVolumeInfo (
   1263   IN EFI_PEI_FV_HANDLE  VolumeHandle,
   1264   OUT EFI_FV_INFO       *VolumeInfo
   1265   )
   1266 {
   1267   PEI_CORE_FV_HANDLE                     *CoreHandle;
   1268 
   1269   if ((VolumeInfo == NULL) || (VolumeHandle == NULL)) {
   1270     return EFI_INVALID_PARAMETER;
   1271   }
   1272 
   1273   CoreHandle = FvHandleToCoreHandle (VolumeHandle);
   1274 
   1275   if ((CoreHandle == NULL) || (CoreHandle->FvPpi == NULL)) {
   1276     return EFI_INVALID_PARAMETER;
   1277   }
   1278 
   1279   return CoreHandle->FvPpi->GetVolumeInfo (CoreHandle->FvPpi, VolumeHandle, VolumeInfo);
   1280 }
   1281 
   1282 /**
   1283   Get Fv image from the FV type file, then install FV INFO(2) ppi, Build FV hob.
   1284 
   1285   @param PrivateData          PeiCore's private data structure
   1286   @param ParentFvCoreHandle   Pointer of EFI_CORE_FV_HANDLE to parent Fv image that contain this Fv image.
   1287   @param ParentFvFileHandle   File handle of a Fv type file that contain this Fv image.
   1288 
   1289   @retval EFI_NOT_FOUND         FV image can't be found.
   1290   @retval EFI_SUCCESS           Successfully to process it.
   1291   @retval EFI_OUT_OF_RESOURCES  Can not allocate page when aligning FV image
   1292   @retval EFI_SECURITY_VIOLATION Image is illegal
   1293   @retval Others                Can not find EFI_SECTION_FIRMWARE_VOLUME_IMAGE section
   1294 
   1295 **/
   1296 EFI_STATUS
   1297 ProcessFvFile (
   1298   IN  PEI_CORE_INSTANCE           *PrivateData,
   1299   IN  PEI_CORE_FV_HANDLE          *ParentFvCoreHandle,
   1300   IN  EFI_PEI_FILE_HANDLE         ParentFvFileHandle
   1301   )
   1302 {
   1303   EFI_STATUS                    Status;
   1304   EFI_FV_INFO                   ParentFvImageInfo;
   1305   UINT32                        FvAlignment;
   1306   VOID                          *NewFvBuffer;
   1307   EFI_PEI_HOB_POINTERS          HobPtr;
   1308   EFI_PEI_FIRMWARE_VOLUME_PPI   *ParentFvPpi;
   1309   EFI_PEI_FV_HANDLE             ParentFvHandle;
   1310   EFI_FIRMWARE_VOLUME_HEADER    *FvHeader;
   1311   EFI_FV_FILE_INFO              FileInfo;
   1312   UINT64                        FvLength;
   1313   UINT32                        AuthenticationStatus;
   1314 
   1315   //
   1316   // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has already
   1317   // been extracted.
   1318   //
   1319   HobPtr.Raw = GetHobList ();
   1320   while ((HobPtr.Raw = GetNextHob (EFI_HOB_TYPE_FV2, HobPtr.Raw)) != NULL) {
   1321     if (CompareGuid (&(((EFI_FFS_FILE_HEADER *)ParentFvFileHandle)->Name), &HobPtr.FirmwareVolume2->FileName)) {
   1322       //
   1323       // this FILE has been dispatched, it will not be dispatched again.
   1324       //
   1325       DEBUG ((EFI_D_INFO, "FV file %p has been dispatched!\r\n", ParentFvFileHandle));
   1326       return EFI_SUCCESS;
   1327     }
   1328     HobPtr.Raw = GET_NEXT_HOB (HobPtr);
   1329   }
   1330 
   1331   ParentFvHandle = ParentFvCoreHandle->FvHandle;
   1332   ParentFvPpi    = ParentFvCoreHandle->FvPpi;
   1333 
   1334   //
   1335   // Find FvImage in FvFile
   1336   //
   1337   AuthenticationStatus = 0;
   1338   if ((ParentFvPpi->Signature == EFI_PEI_FIRMWARE_VOLUME_PPI_SIGNATURE) &&
   1339       (ParentFvPpi->Revision == EFI_PEI_FIRMWARE_VOLUME_PPI_REVISION)) {
   1340     Status = ParentFvPpi->FindSectionByType2 (
   1341                             ParentFvPpi,
   1342                             EFI_SECTION_FIRMWARE_VOLUME_IMAGE,
   1343                             0,
   1344                             ParentFvFileHandle,
   1345                             (VOID **)&FvHeader,
   1346                             &AuthenticationStatus
   1347                             );
   1348   } else {
   1349     Status = ParentFvPpi->FindSectionByType (
   1350                             ParentFvPpi,
   1351                             EFI_SECTION_FIRMWARE_VOLUME_IMAGE,
   1352                             ParentFvFileHandle,
   1353                             (VOID **)&FvHeader
   1354                             );
   1355   }
   1356   if (EFI_ERROR (Status)) {
   1357     return Status;
   1358   }
   1359 
   1360   Status = VerifyPeim (PrivateData, ParentFvHandle, ParentFvFileHandle, AuthenticationStatus);
   1361   if (Status == EFI_SECURITY_VIOLATION) {
   1362     return Status;
   1363   }
   1364 
   1365   //
   1366   // If EFI_FVB2_WEAK_ALIGNMENT is set in the volume header then the first byte of the volume
   1367   // can be aligned on any power-of-two boundary. A weakly aligned volume can not be moved from
   1368   // its initial linked location and maintain its alignment.
   1369   //
   1370   if ((ReadUnaligned32 (&FvHeader->Attributes) & EFI_FVB2_WEAK_ALIGNMENT) != EFI_FVB2_WEAK_ALIGNMENT) {
   1371     //
   1372     // FvAlignment must be greater than or equal to 8 bytes of the minimum FFS alignment value.
   1373     //
   1374     FvAlignment = 1 << ((ReadUnaligned32 (&FvHeader->Attributes) & EFI_FVB2_ALIGNMENT) >> 16);
   1375     if (FvAlignment < 8) {
   1376       FvAlignment = 8;
   1377     }
   1378 
   1379     //
   1380     // Check FvImage
   1381     //
   1382     if ((UINTN) FvHeader % FvAlignment != 0) {
   1383       FvLength    = ReadUnaligned64 (&FvHeader->FvLength);
   1384       NewFvBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES ((UINT32) FvLength), FvAlignment);
   1385       if (NewFvBuffer == NULL) {
   1386         return EFI_OUT_OF_RESOURCES;
   1387       }
   1388       CopyMem (NewFvBuffer, FvHeader, (UINTN) FvLength);
   1389       FvHeader = (EFI_FIRMWARE_VOLUME_HEADER*) NewFvBuffer;
   1390     }
   1391   }
   1392 
   1393   Status = ParentFvPpi->GetVolumeInfo (ParentFvPpi, ParentFvHandle, &ParentFvImageInfo);
   1394   ASSERT_EFI_ERROR (Status);
   1395 
   1396   Status = ParentFvPpi->GetFileInfo (ParentFvPpi, ParentFvFileHandle, &FileInfo);
   1397   ASSERT_EFI_ERROR (Status);
   1398 
   1399   //
   1400   // Install FvInfo(2) Ppi
   1401   // NOTE: FvInfo2 must be installed before FvInfo so that recursive processing of encapsulated
   1402   // FVs inherit the proper AuthenticationStatus.
   1403   //
   1404   PeiServicesInstallFvInfo2Ppi(
   1405     &FvHeader->FileSystemGuid,
   1406     (VOID**)FvHeader,
   1407     (UINT32)FvHeader->FvLength,
   1408     &ParentFvImageInfo.FvName,
   1409     &FileInfo.FileName,
   1410     AuthenticationStatus
   1411     );
   1412 
   1413   PeiServicesInstallFvInfoPpi (
   1414     &FvHeader->FileSystemGuid,
   1415     (VOID**) FvHeader,
   1416     (UINT32) FvHeader->FvLength,
   1417     &ParentFvImageInfo.FvName,
   1418     &FileInfo.FileName
   1419     );
   1420 
   1421   //
   1422   // Inform the extracted FvImage to Fv HOB consumer phase, i.e. DXE phase
   1423   //
   1424   BuildFvHob (
   1425     (EFI_PHYSICAL_ADDRESS) (UINTN) FvHeader,
   1426     FvHeader->FvLength
   1427     );
   1428 
   1429   //
   1430   // Makes the encapsulated volume show up in DXE phase to skip processing of
   1431   // encapsulated file again.
   1432   //
   1433   BuildFv2Hob (
   1434     (EFI_PHYSICAL_ADDRESS) (UINTN) FvHeader,
   1435     FvHeader->FvLength,
   1436     &ParentFvImageInfo.FvName,
   1437     &FileInfo.FileName
   1438     );
   1439 
   1440   return EFI_SUCCESS;
   1441 }
   1442 
   1443 /**
   1444   Process a firmware volume and create a volume handle.
   1445 
   1446   Create a volume handle from the information in the buffer. For
   1447   memory-mapped firmware volumes, Buffer and BufferSize refer to
   1448   the start of the firmware volume and the firmware volume size.
   1449   For non memory-mapped firmware volumes, this points to a
   1450   buffer which contains the necessary information for creating
   1451   the firmware volume handle. Normally, these values are derived
   1452   from the EFI_FIRMWARE_VOLUME_INFO_PPI.
   1453 
   1454 
   1455   @param This                   Points to this instance of the
   1456                                 EFI_PEI_FIRMWARE_VOLUME_PPI.
   1457   @param Buffer                 Points to the start of the buffer.
   1458   @param BufferSize             Size of the buffer.
   1459   @param FvHandle               Points to the returned firmware volume
   1460                                 handle. The firmware volume handle must
   1461                                 be unique within the system.
   1462 
   1463   @retval EFI_SUCCESS           Firmware volume handle created.
   1464   @retval EFI_VOLUME_CORRUPTED  Volume was corrupt.
   1465 
   1466 **/
   1467 EFI_STATUS
   1468 EFIAPI
   1469 PeiFfsFvPpiProcessVolume (
   1470   IN  CONST  EFI_PEI_FIRMWARE_VOLUME_PPI *This,
   1471   IN  VOID                               *Buffer,
   1472   IN  UINTN                              BufferSize,
   1473   OUT EFI_PEI_FV_HANDLE                  *FvHandle
   1474   )
   1475 {
   1476   EFI_STATUS          Status;
   1477 
   1478   ASSERT (FvHandle != NULL);
   1479 
   1480   if (Buffer == NULL) {
   1481     return EFI_VOLUME_CORRUPTED;
   1482   }
   1483 
   1484   //
   1485   // The build-in EFI_PEI_FIRMWARE_VOLUME_PPI for FFS2/FFS3 support memory-mapped
   1486   // FV image and the handle is pointed to Fv image's buffer.
   1487   //
   1488   *FvHandle = (EFI_PEI_FV_HANDLE) Buffer;
   1489 
   1490   //
   1491   // Do verify for given FV buffer.
   1492   //
   1493   Status = VerifyFv ((EFI_FIRMWARE_VOLUME_HEADER*) Buffer);
   1494   if (EFI_ERROR(Status)) {
   1495     DEBUG ((EFI_D_ERROR, "Fail to verify FV which address is 0x%11p", Buffer));
   1496     return EFI_VOLUME_CORRUPTED;
   1497   }
   1498 
   1499   return EFI_SUCCESS;
   1500 }
   1501 
   1502 /**
   1503   Finds the next file of the specified type.
   1504 
   1505   This service enables PEI modules to discover additional firmware files.
   1506   The FileHandle must be unique within the system.
   1507 
   1508   @param This           Points to this instance of the
   1509                         EFI_PEI_FIRMWARE_VOLUME_PPI.
   1510   @param SearchType     A filter to find only files of this type. Type
   1511                         EFI_FV_FILETYPE_ALL causes no filtering to be
   1512                         done.
   1513   @param FvHandle       Handle of firmware volume in which to
   1514                         search.
   1515   @param FileHandle     Points to the current handle from which to
   1516                         begin searching or NULL to start at the
   1517                         beginning of the firmware volume. Updated
   1518                         upon return to reflect the file found.
   1519 
   1520   @retval EFI_SUCCESS   The file was found.
   1521   @retval EFI_NOT_FOUND The file was not found. FileHandle contains NULL.
   1522 
   1523 **/
   1524 EFI_STATUS
   1525 EFIAPI
   1526 PeiFfsFvPpiFindFileByType (
   1527   IN CONST  EFI_PEI_FIRMWARE_VOLUME_PPI *This,
   1528   IN        EFI_FV_FILETYPE             SearchType,
   1529   IN        EFI_PEI_FV_HANDLE           FvHandle,
   1530   IN OUT    EFI_PEI_FILE_HANDLE         *FileHandle
   1531   )
   1532 {
   1533   return FindFileEx (FvHandle, NULL, SearchType, FileHandle, NULL);
   1534 }
   1535 
   1536 /**
   1537   Find a file within a volume by its name.
   1538 
   1539   This service searches for files with a specific name, within
   1540   either the specified firmware volume or all firmware volumes.
   1541 
   1542   @param This                   Points to this instance of the
   1543                                 EFI_PEI_FIRMWARE_VOLUME_PPI.
   1544   @param FileName               A pointer to the name of the file to find
   1545                                 within the firmware volume.
   1546   @param FvHandle               Upon entry, the pointer to the firmware
   1547                                 volume to search or NULL if all firmware
   1548                                 volumes should be searched. Upon exit, the
   1549                                 actual firmware volume in which the file was
   1550                                 found.
   1551   @param FileHandle             Upon exit, points to the found file's
   1552                                 handle or NULL if it could not be found.
   1553 
   1554   @retval EFI_SUCCESS           File was found.
   1555   @retval EFI_NOT_FOUND         File was not found.
   1556   @retval EFI_INVALID_PARAMETER FvHandle or FileHandle or
   1557                                 FileName was NULL.
   1558 
   1559 
   1560 **/
   1561 EFI_STATUS
   1562 EFIAPI
   1563 PeiFfsFvPpiFindFileByName (
   1564   IN  CONST  EFI_PEI_FIRMWARE_VOLUME_PPI *This,
   1565   IN  CONST  EFI_GUID                    *FileName,
   1566   IN  EFI_PEI_FV_HANDLE                  *FvHandle,
   1567   OUT EFI_PEI_FILE_HANDLE                *FileHandle
   1568   )
   1569 {
   1570   EFI_STATUS        Status;
   1571   PEI_CORE_INSTANCE *PrivateData;
   1572   UINTN             Index;
   1573 
   1574   if ((FvHandle == NULL) || (FileName == NULL) || (FileHandle == NULL)) {
   1575     return EFI_INVALID_PARAMETER;
   1576   }
   1577 
   1578   if (*FvHandle != NULL) {
   1579     Status = FindFileEx (*FvHandle, FileName, 0, FileHandle, NULL);
   1580     if (Status == EFI_NOT_FOUND) {
   1581       *FileHandle = NULL;
   1582     }
   1583   } else {
   1584     //
   1585     // If *FvHandle = NULL, so search all FV for given filename
   1586     //
   1587     Status = EFI_NOT_FOUND;
   1588 
   1589     PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer());
   1590     for (Index = 0; Index < PrivateData->FvCount; Index ++) {
   1591       //
   1592       // Only search the FV which is associated with a EFI_PEI_FIRMWARE_VOLUME_PPI instance.
   1593       //
   1594       if (PrivateData->Fv[Index].FvPpi != NULL) {
   1595         Status = FindFileEx (PrivateData->Fv[Index].FvHandle, FileName, 0, FileHandle, NULL);
   1596         if (!EFI_ERROR (Status)) {
   1597           *FvHandle = PrivateData->Fv[Index].FvHandle;
   1598           break;
   1599         }
   1600       }
   1601     }
   1602   }
   1603 
   1604   return Status;
   1605 }
   1606 
   1607 /**
   1608   Returns information about a specific file.
   1609 
   1610   This function returns information about a specific
   1611   file, including its file name, type, attributes, starting
   1612   address and size.
   1613 
   1614   @param This                     Points to this instance of the
   1615                                   EFI_PEI_FIRMWARE_VOLUME_PPI.
   1616   @param FileHandle               Handle of the file.
   1617   @param FileInfo                 Upon exit, points to the file's
   1618                                   information.
   1619 
   1620   @retval EFI_SUCCESS             File information returned.
   1621   @retval EFI_INVALID_PARAMETER   If FileHandle does not
   1622                                   represent a valid file.
   1623   @retval EFI_INVALID_PARAMETER   If FileInfo is NULL.
   1624 
   1625 **/
   1626 EFI_STATUS
   1627 EFIAPI
   1628 PeiFfsFvPpiGetFileInfo (
   1629   IN  CONST EFI_PEI_FIRMWARE_VOLUME_PPI   *This,
   1630   IN        EFI_PEI_FILE_HANDLE           FileHandle,
   1631   OUT       EFI_FV_FILE_INFO              *FileInfo
   1632   )
   1633 {
   1634   UINT8                       FileState;
   1635   UINT8                       ErasePolarity;
   1636   EFI_FFS_FILE_HEADER         *FileHeader;
   1637   PEI_CORE_FV_HANDLE          *CoreFvHandle;
   1638   PEI_FW_VOL_INSTANCE         *FwVolInstance;
   1639 
   1640   if ((FileHandle == NULL) || (FileInfo == NULL)) {
   1641     return EFI_INVALID_PARAMETER;
   1642   }
   1643 
   1644   //
   1645   // Retrieve the FirmwareVolume which the file resides in.
   1646   //
   1647   CoreFvHandle = FileHandleToVolume (FileHandle);
   1648   if (CoreFvHandle == NULL) {
   1649     return EFI_INVALID_PARAMETER;
   1650   }
   1651 
   1652   FwVolInstance = PEI_FW_VOL_INSTANCE_FROM_FV_THIS (This);
   1653 
   1654   if ((CoreFvHandle->FvHeader->Attributes & EFI_FVB2_ERASE_POLARITY) != 0) {
   1655     ErasePolarity = 1;
   1656   } else {
   1657     ErasePolarity = 0;
   1658   }
   1659 
   1660   //
   1661   // Get FileState which is the highest bit of the State
   1662   //
   1663   FileState = GetFileState (ErasePolarity, (EFI_FFS_FILE_HEADER*)FileHandle);
   1664 
   1665   switch (FileState) {
   1666     case EFI_FILE_DATA_VALID:
   1667     case EFI_FILE_MARKED_FOR_UPDATE:
   1668       break;
   1669     default:
   1670       return EFI_INVALID_PARAMETER;
   1671     }
   1672 
   1673   FileHeader = (EFI_FFS_FILE_HEADER *)FileHandle;
   1674   if (IS_FFS_FILE2 (FileHeader)) {
   1675     ASSERT (FFS_FILE2_SIZE (FileHeader) > 0x00FFFFFF);
   1676     if (!FwVolInstance->IsFfs3Fv) {
   1677       DEBUG ((EFI_D_ERROR, "It is a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &FileHeader->Name));
   1678       return EFI_INVALID_PARAMETER;
   1679     }
   1680     FileInfo->BufferSize = FFS_FILE2_SIZE (FileHeader) - sizeof (EFI_FFS_FILE_HEADER2);
   1681     FileInfo->Buffer = (UINT8 *) FileHeader + sizeof (EFI_FFS_FILE_HEADER2);
   1682   } else {
   1683     FileInfo->BufferSize = FFS_FILE_SIZE (FileHeader) - sizeof (EFI_FFS_FILE_HEADER);
   1684     FileInfo->Buffer = (UINT8 *) FileHeader + sizeof (EFI_FFS_FILE_HEADER);
   1685   }
   1686   CopyMem (&FileInfo->FileName, &FileHeader->Name, sizeof(EFI_GUID));
   1687   FileInfo->FileType = FileHeader->Type;
   1688   FileInfo->FileAttributes = FfsAttributes2FvFileAttributes (FileHeader->Attributes);
   1689   if ((CoreFvHandle->FvHeader->Attributes & EFI_FVB2_MEMORY_MAPPED) == EFI_FVB2_MEMORY_MAPPED) {
   1690     FileInfo->FileAttributes |= EFI_FV_FILE_ATTRIB_MEMORY_MAPPED;
   1691   }
   1692   return EFI_SUCCESS;
   1693 }
   1694 
   1695 /**
   1696   Returns information about a specific file.
   1697 
   1698   This function returns information about a specific
   1699   file, including its file name, type, attributes, starting
   1700   address, size and authentication status.
   1701 
   1702   @param This                     Points to this instance of the
   1703                                   EFI_PEI_FIRMWARE_VOLUME_PPI.
   1704   @param FileHandle               Handle of the file.
   1705   @param FileInfo                 Upon exit, points to the file's
   1706                                   information.
   1707 
   1708   @retval EFI_SUCCESS             File information returned.
   1709   @retval EFI_INVALID_PARAMETER   If FileHandle does not
   1710                                   represent a valid file.
   1711   @retval EFI_INVALID_PARAMETER   If FileInfo is NULL.
   1712 
   1713 **/
   1714 EFI_STATUS
   1715 EFIAPI
   1716 PeiFfsFvPpiGetFileInfo2 (
   1717   IN  CONST EFI_PEI_FIRMWARE_VOLUME_PPI   *This,
   1718   IN        EFI_PEI_FILE_HANDLE           FileHandle,
   1719   OUT       EFI_FV_FILE_INFO2             *FileInfo
   1720   )
   1721 {
   1722   EFI_STATUS                  Status;
   1723   PEI_CORE_FV_HANDLE          *CoreFvHandle;
   1724 
   1725   if ((FileHandle == NULL) || (FileInfo == NULL)) {
   1726     return EFI_INVALID_PARAMETER;
   1727   }
   1728 
   1729   //
   1730   // Retrieve the FirmwareVolume which the file resides in.
   1731   //
   1732   CoreFvHandle = FileHandleToVolume (FileHandle);
   1733   if (CoreFvHandle == NULL) {
   1734     return EFI_INVALID_PARAMETER;
   1735   }
   1736 
   1737   Status = PeiFfsFvPpiGetFileInfo (This, FileHandle, (EFI_FV_FILE_INFO *) FileInfo);
   1738   if (!EFI_ERROR (Status)) {
   1739     FileInfo->AuthenticationStatus = CoreFvHandle->AuthenticationStatus;
   1740   }
   1741 
   1742   return Status;
   1743 }
   1744 
   1745 /**
   1746   This function returns information about the firmware volume.
   1747 
   1748   @param This                     Points to this instance of the
   1749                                   EFI_PEI_FIRMWARE_VOLUME_PPI.
   1750   @param FvHandle                 Handle to the firmware handle.
   1751   @param VolumeInfo               Points to the returned firmware volume
   1752                                   information.
   1753 
   1754   @retval EFI_SUCCESS             Information returned successfully.
   1755   @retval EFI_INVALID_PARAMETER   FvHandle does not indicate a valid
   1756                                   firmware volume or VolumeInfo is NULL.
   1757 
   1758 **/
   1759 EFI_STATUS
   1760 EFIAPI
   1761 PeiFfsFvPpiGetVolumeInfo (
   1762   IN  CONST  EFI_PEI_FIRMWARE_VOLUME_PPI   *This,
   1763   IN  EFI_PEI_FV_HANDLE                    FvHandle,
   1764   OUT EFI_FV_INFO                          *VolumeInfo
   1765   )
   1766 {
   1767   EFI_FIRMWARE_VOLUME_HEADER             FwVolHeader;
   1768   EFI_FIRMWARE_VOLUME_EXT_HEADER         *FwVolExHeaderInfo;
   1769 
   1770   if ((VolumeInfo == NULL) || (FvHandle == NULL)) {
   1771     return EFI_INVALID_PARAMETER;
   1772   }
   1773 
   1774   //
   1775   // VolumeHandle may not align at 8 byte,
   1776   // but FvLength is UINT64 type, which requires FvHeader align at least 8 byte.
   1777   // So, Copy FvHeader into the local FvHeader structure.
   1778   //
   1779   CopyMem (&FwVolHeader, FvHandle, sizeof (EFI_FIRMWARE_VOLUME_HEADER));
   1780 
   1781   //
   1782   // Check Fv Image Signature
   1783   //
   1784   if (FwVolHeader.Signature != EFI_FVH_SIGNATURE) {
   1785     return EFI_INVALID_PARAMETER;
   1786   }
   1787 
   1788   ZeroMem (VolumeInfo, sizeof (EFI_FV_INFO));
   1789   VolumeInfo->FvAttributes  = FwVolHeader.Attributes;
   1790   VolumeInfo->FvStart       = (VOID *) FvHandle;
   1791   VolumeInfo->FvSize        = FwVolHeader.FvLength;
   1792   CopyMem (&VolumeInfo->FvFormat, &FwVolHeader.FileSystemGuid, sizeof(EFI_GUID));
   1793 
   1794   if (FwVolHeader.ExtHeaderOffset != 0) {
   1795     FwVolExHeaderInfo = (EFI_FIRMWARE_VOLUME_EXT_HEADER*)(((UINT8 *)FvHandle) + FwVolHeader.ExtHeaderOffset);
   1796     CopyMem (&VolumeInfo->FvName, &FwVolExHeaderInfo->FvName, sizeof(EFI_GUID));
   1797   }
   1798 
   1799   return EFI_SUCCESS;
   1800 }
   1801 
   1802 /**
   1803   Find the next matching section in the firmware file.
   1804 
   1805   This service enables PEI modules to discover sections
   1806   of a given type within a valid file.
   1807 
   1808   @param This             Points to this instance of the
   1809                           EFI_PEI_FIRMWARE_VOLUME_PPI.
   1810   @param SearchType       A filter to find only sections of this
   1811                           type.
   1812   @param FileHandle       Handle of firmware file in which to
   1813                           search.
   1814   @param SectionData      Updated upon return to point to the
   1815                           section found.
   1816 
   1817   @retval EFI_SUCCESS     Section was found.
   1818   @retval EFI_NOT_FOUND   Section of the specified type was not
   1819                           found. SectionData contains NULL.
   1820 **/
   1821 EFI_STATUS
   1822 EFIAPI
   1823 PeiFfsFvPpiFindSectionByType (
   1824   IN  CONST EFI_PEI_FIRMWARE_VOLUME_PPI    *This,
   1825   IN        EFI_SECTION_TYPE               SearchType,
   1826   IN        EFI_PEI_FILE_HANDLE            FileHandle,
   1827   OUT VOID                                 **SectionData
   1828   )
   1829 {
   1830   UINT32 AuthenticationStatus;
   1831   return PeiFfsFvPpiFindSectionByType2 (This, SearchType, 0, FileHandle, SectionData, &AuthenticationStatus);
   1832 }
   1833 
   1834 /**
   1835   Find the next matching section in the firmware file.
   1836 
   1837   This service enables PEI modules to discover sections
   1838   of a given instance and type within a valid file.
   1839 
   1840   @param This                   Points to this instance of the
   1841                                 EFI_PEI_FIRMWARE_VOLUME_PPI.
   1842   @param SearchType             A filter to find only sections of this
   1843                                 type.
   1844   @param SearchInstance         A filter to find the specific instance
   1845                                 of sections.
   1846   @param FileHandle             Handle of firmware file in which to
   1847                                 search.
   1848   @param SectionData            Updated upon return to point to the
   1849                                 section found.
   1850   @param AuthenticationStatus   Updated upon return to point to the
   1851                                 authentication status for this section.
   1852 
   1853   @retval EFI_SUCCESS     Section was found.
   1854   @retval EFI_NOT_FOUND   Section of the specified type was not
   1855                           found. SectionData contains NULL.
   1856 **/
   1857 EFI_STATUS
   1858 EFIAPI
   1859 PeiFfsFvPpiFindSectionByType2 (
   1860   IN  CONST EFI_PEI_FIRMWARE_VOLUME_PPI    *This,
   1861   IN        EFI_SECTION_TYPE               SearchType,
   1862   IN        UINTN                          SearchInstance,
   1863   IN        EFI_PEI_FILE_HANDLE            FileHandle,
   1864   OUT VOID                                 **SectionData,
   1865   OUT UINT32                               *AuthenticationStatus
   1866   )
   1867 {
   1868   EFI_STATUS                              Status;
   1869   EFI_FFS_FILE_HEADER                     *FfsFileHeader;
   1870   UINT32                                  FileSize;
   1871   EFI_COMMON_SECTION_HEADER               *Section;
   1872   PEI_FW_VOL_INSTANCE                     *FwVolInstance;
   1873   PEI_CORE_FV_HANDLE                      *CoreFvHandle;
   1874   UINTN                                   Instance;
   1875   UINT32                                  ExtractedAuthenticationStatus;
   1876 
   1877   if (SectionData == NULL) {
   1878     return EFI_NOT_FOUND;
   1879   }
   1880 
   1881   FwVolInstance = PEI_FW_VOL_INSTANCE_FROM_FV_THIS (This);
   1882 
   1883   //
   1884   // Retrieve the FirmwareVolume which the file resides in.
   1885   //
   1886   CoreFvHandle = FileHandleToVolume (FileHandle);
   1887   if (CoreFvHandle == NULL) {
   1888     return EFI_NOT_FOUND;
   1889   }
   1890 
   1891   FfsFileHeader = (EFI_FFS_FILE_HEADER *)(FileHandle);
   1892 
   1893   if (IS_FFS_FILE2 (FfsFileHeader)) {
   1894     ASSERT (FFS_FILE2_SIZE (FfsFileHeader) > 0x00FFFFFF);
   1895     if (!FwVolInstance->IsFfs3Fv) {
   1896       DEBUG ((EFI_D_ERROR, "It is a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &FfsFileHeader->Name));
   1897       return EFI_NOT_FOUND;
   1898     }
   1899     Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER2));
   1900     FileSize = FFS_FILE2_SIZE (FfsFileHeader) - sizeof (EFI_FFS_FILE_HEADER2);
   1901   } else {
   1902     Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER));
   1903     FileSize = FFS_FILE_SIZE (FfsFileHeader) - sizeof (EFI_FFS_FILE_HEADER);
   1904   }
   1905 
   1906   Instance = SearchInstance + 1;
   1907   ExtractedAuthenticationStatus = 0;
   1908   Status = ProcessSection (
   1909              GetPeiServicesTablePointer (),
   1910              SearchType,
   1911              &Instance,
   1912              Section,
   1913              FileSize,
   1914              SectionData,
   1915              &ExtractedAuthenticationStatus,
   1916              FwVolInstance->IsFfs3Fv
   1917              );
   1918   if (!EFI_ERROR (Status)) {
   1919     //
   1920     // Inherit the authentication status.
   1921     //
   1922     *AuthenticationStatus = ExtractedAuthenticationStatus | CoreFvHandle->AuthenticationStatus;
   1923   }
   1924   return Status;
   1925 }
   1926 
   1927 /**
   1928   Convert the handle of FV to pointer of corresponding PEI_CORE_FV_HANDLE.
   1929 
   1930   @param FvHandle   The handle of a FV.
   1931 
   1932   @retval NULL if can not find.
   1933   @return Pointer of corresponding PEI_CORE_FV_HANDLE.
   1934 **/
   1935 PEI_CORE_FV_HANDLE *
   1936 FvHandleToCoreHandle (
   1937   IN EFI_PEI_FV_HANDLE  FvHandle
   1938   )
   1939 {
   1940   UINTN             Index;
   1941   PEI_CORE_INSTANCE *PrivateData;
   1942 
   1943   PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer());
   1944   for (Index = 0; Index < PrivateData->FvCount; Index ++) {
   1945     if (FvHandle == PrivateData->Fv[Index].FvHandle) {
   1946       return &PrivateData->Fv[Index];
   1947     }
   1948   }
   1949 
   1950   return NULL;
   1951 }
   1952 
   1953 /**
   1954   Get instance of PEI_CORE_FV_HANDLE for next volume according to given index.
   1955 
   1956   This routine also will install FvInfo ppi for FV hob in PI ways.
   1957 
   1958   @param Private    Pointer of PEI_CORE_INSTANCE
   1959   @param Instance   The index of FV want to be searched.
   1960 
   1961   @return Instance of PEI_CORE_FV_HANDLE.
   1962 **/
   1963 PEI_CORE_FV_HANDLE *
   1964 FindNextCoreFvHandle (
   1965   IN PEI_CORE_INSTANCE  *Private,
   1966   IN UINTN              Instance
   1967   )
   1968 {
   1969   UINTN                    Index;
   1970   BOOLEAN                  Match;
   1971   EFI_HOB_FIRMWARE_VOLUME  *FvHob;
   1972 
   1973   //
   1974   // Handle Framework FvHob and Install FvInfo Ppi for it.
   1975   //
   1976   if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {
   1977     //
   1978     // Loop to search the wanted FirmwareVolume which supports FFS
   1979     //
   1980     FvHob = (EFI_HOB_FIRMWARE_VOLUME *)GetFirstHob (EFI_HOB_TYPE_FV);
   1981     while (FvHob != NULL) {
   1982       //
   1983       // Search whether FvHob has been installed into PeiCore's FV database.
   1984       // If found, no need install new FvInfoPpi for it.
   1985       //
   1986       for (Index = 0, Match = FALSE; Index < Private->FvCount; Index++) {
   1987         if ((EFI_PEI_FV_HANDLE)(UINTN)FvHob->BaseAddress == Private->Fv[Index].FvHeader) {
   1988           Match = TRUE;
   1989           break;
   1990         }
   1991       }
   1992 
   1993       //
   1994       // Search whether FvHob has been cached into PeiCore's Unknown FV database.
   1995       // If found, no need install new FvInfoPpi for it.
   1996       //
   1997       if (!Match) {
   1998         for (Index = 0; Index < Private->UnknownFvInfoCount; Index ++) {
   1999           if ((UINTN)FvHob->BaseAddress == (UINTN)Private->UnknownFvInfo[Index].FvInfo) {
   2000             Match = TRUE;
   2001             break;
   2002           }
   2003         }
   2004       }
   2005 
   2006       //
   2007       // If the Fv in FvHob has not been installed into PeiCore's FV database and has
   2008       // not been cached into PeiCore's Unknown FV database, install a new FvInfoPpi
   2009       // for it then PeiCore will dispatch it in callback of FvInfoPpi.
   2010       //
   2011       if (!Match) {
   2012         PeiServicesInstallFvInfoPpi (
   2013           &(((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FvHob->BaseAddress)->FileSystemGuid),
   2014           (VOID *)(UINTN)FvHob->BaseAddress,
   2015           (UINT32)FvHob->Length,
   2016           NULL,
   2017           NULL
   2018           );
   2019       }
   2020 
   2021       FvHob = (EFI_HOB_FIRMWARE_VOLUME *)GetNextHob (EFI_HOB_TYPE_FV, (VOID *)((UINTN)FvHob + FvHob->Header.HobLength));
   2022     }
   2023   }
   2024 
   2025   ASSERT (Private->FvCount <= PcdGet32 (PcdPeiCoreMaxFvSupported));
   2026   if (Instance >= Private->FvCount) {
   2027     return NULL;
   2028   }
   2029 
   2030   return &Private->Fv[Instance];
   2031 }
   2032 
   2033 /**
   2034   After PeiCore image is shadowed into permanent memory, all build-in FvPpi should
   2035   be re-installed with the instance in permanent memory and all cached FvPpi pointers in
   2036   PrivateData->Fv[] array should be fixed up to be pointed to the one in permanent
   2037   memory.
   2038 
   2039   @param PrivateData   Pointer to PEI_CORE_INSTANCE.
   2040 **/
   2041 VOID
   2042 PeiReinitializeFv (
   2043   IN  PEI_CORE_INSTANCE           *PrivateData
   2044   )
   2045 {
   2046   VOID                    *OldFfsFvPpi;
   2047   EFI_PEI_PPI_DESCRIPTOR  *OldDescriptor;
   2048   UINTN                   Index;
   2049   EFI_STATUS              Status;
   2050 
   2051   //
   2052   // Locate old build-in Ffs2 EFI_PEI_FIRMWARE_VOLUME_PPI which
   2053   // in flash.
   2054   //
   2055   Status = PeiServicesLocatePpi (
   2056             &gEfiFirmwareFileSystem2Guid,
   2057             0,
   2058             &OldDescriptor,
   2059             &OldFfsFvPpi
   2060             );
   2061   ASSERT_EFI_ERROR (Status);
   2062 
   2063   //
   2064   // Re-install the EFI_PEI_FIRMWARE_VOLUME_PPI for build-in Ffs2
   2065   // which is shadowed from flash to permanent memory within PeiCore image.
   2066   //
   2067   Status = PeiServicesReInstallPpi (OldDescriptor, &mPeiFfs2FvPpiList);
   2068   ASSERT_EFI_ERROR (Status);
   2069 
   2070   //
   2071   // Fixup all FvPpi pointers for the implementation in flash to permanent memory.
   2072   //
   2073   for (Index = 0; Index < PcdGet32 (PcdPeiCoreMaxFvSupported); Index ++) {
   2074     if (PrivateData->Fv[Index].FvPpi == OldFfsFvPpi) {
   2075       PrivateData->Fv[Index].FvPpi = &mPeiFfs2FwVol.Fv;
   2076     }
   2077   }
   2078 
   2079   //
   2080   // Locate old build-in Ffs3 EFI_PEI_FIRMWARE_VOLUME_PPI which
   2081   // in flash.
   2082   //
   2083   Status = PeiServicesLocatePpi (
   2084              &gEfiFirmwareFileSystem3Guid,
   2085              0,
   2086              &OldDescriptor,
   2087              &OldFfsFvPpi
   2088              );
   2089   ASSERT_EFI_ERROR (Status);
   2090 
   2091   //
   2092   // Re-install the EFI_PEI_FIRMWARE_VOLUME_PPI for build-in Ffs3
   2093   // which is shadowed from flash to permanent memory within PeiCore image.
   2094   //
   2095   Status = PeiServicesReInstallPpi (OldDescriptor, &mPeiFfs3FvPpiList);
   2096   ASSERT_EFI_ERROR (Status);
   2097 
   2098   //
   2099   // Fixup all FvPpi pointers for the implementation in flash to permanent memory.
   2100   //
   2101   for (Index = 0; Index < PcdGet32 (PcdPeiCoreMaxFvSupported); Index ++) {
   2102     if (PrivateData->Fv[Index].FvPpi == OldFfsFvPpi) {
   2103       PrivateData->Fv[Index].FvPpi = &mPeiFfs3FwVol.Fv;
   2104     }
   2105   }
   2106 }
   2107 
   2108 /**
   2109   Report the information for a new discoveried FV in unknown third-party format.
   2110 
   2111   If the EFI_PEI_FIRMWARE_VOLUME_PPI has not been installed for third-party FV format, but
   2112   the FV in this format has been discoveried, then this FV's information will be cached into
   2113   PEI_CORE_INSTANCE's UnknownFvInfo array.
   2114   Also a notification would be installed for unknown third-party FV format guid, if EFI_PEI_FIRMWARE_VOLUME_PPI
   2115   is installed later by platform's PEIM, the original unknown third-party FV will be processed by
   2116   using new installed EFI_PEI_FIRMWARE_VOLUME_PPI.
   2117 
   2118   @param PrivateData  Point to instance of PEI_CORE_INSTANCE
   2119   @param FvInfo2Ppi   Point to FvInfo2 PPI.
   2120 
   2121   @retval EFI_OUT_OF_RESOURCES  The FV info array in PEI_CORE_INSTANCE has no more spaces.
   2122   @retval EFI_SUCCESS           Success to add the information for unknown FV.
   2123 **/
   2124 EFI_STATUS
   2125 AddUnknownFormatFvInfo (
   2126   IN PEI_CORE_INSTANCE                  *PrivateData,
   2127   IN EFI_PEI_FIRMWARE_VOLUME_INFO2_PPI  *FvInfo2Ppi
   2128   )
   2129 {
   2130   PEI_CORE_UNKNOW_FORMAT_FV_INFO    *NewUnknownFv;
   2131 
   2132   if (PrivateData->UnknownFvInfoCount + 1 >= PcdGet32 (PcdPeiCoreMaxFvSupported)) {
   2133     return EFI_OUT_OF_RESOURCES;
   2134   }
   2135 
   2136   NewUnknownFv = &PrivateData->UnknownFvInfo[PrivateData->UnknownFvInfoCount];
   2137   PrivateData->UnknownFvInfoCount ++;
   2138 
   2139   CopyGuid (&NewUnknownFv->FvFormat, &FvInfo2Ppi->FvFormat);
   2140   NewUnknownFv->FvInfo     = FvInfo2Ppi->FvInfo;
   2141   NewUnknownFv->FvInfoSize = FvInfo2Ppi->FvInfoSize;
   2142   NewUnknownFv->AuthenticationStatus = FvInfo2Ppi->AuthenticationStatus;
   2143   NewUnknownFv->NotifyDescriptor.Flags  = (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
   2144   NewUnknownFv->NotifyDescriptor.Guid   = &NewUnknownFv->FvFormat;
   2145   NewUnknownFv->NotifyDescriptor.Notify = ThirdPartyFvPpiNotifyCallback;
   2146 
   2147   PeiServicesNotifyPpi (&NewUnknownFv->NotifyDescriptor);
   2148   return EFI_SUCCESS;
   2149 }
   2150 
   2151 /**
   2152   Find the FV information according to third-party FV format guid.
   2153 
   2154   This routine also will remove the FV information found by given FV format guid from
   2155   PrivateData->UnknownFvInfo[].
   2156 
   2157   @param PrivateData      Point to instance of PEI_CORE_INSTANCE
   2158   @param Format           Point to given FV format guid
   2159   @param FvInfo           On return, the pointer of FV information buffer
   2160   @param FvInfoSize       On return, the size of FV information buffer.
   2161   @param AuthenticationStatus On return, the authentication status of FV information buffer.
   2162 
   2163   @retval EFI_NOT_FOUND  The FV is not found for new installed EFI_PEI_FIRMWARE_VOLUME_PPI
   2164   @retval EFI_SUCCESS    Success to find a FV which could be processed by new installed EFI_PEI_FIRMWARE_VOLUME_PPI.
   2165 **/
   2166 EFI_STATUS
   2167 FindUnknownFormatFvInfo (
   2168   IN  PEI_CORE_INSTANCE *PrivateData,
   2169   IN  EFI_GUID          *Format,
   2170   OUT VOID              **FvInfo,
   2171   OUT UINT32            *FvInfoSize,
   2172   OUT UINT32            *AuthenticationStatus
   2173   )
   2174 {
   2175   UINTN Index;
   2176   UINTN Index2;
   2177 
   2178   Index = 0;
   2179   for (; Index < PrivateData->UnknownFvInfoCount; Index ++) {
   2180     if (CompareGuid (Format, &PrivateData->UnknownFvInfo[Index].FvFormat)) {
   2181       break;
   2182     }
   2183   }
   2184 
   2185   if (Index == PrivateData->UnknownFvInfoCount) {
   2186     return EFI_NOT_FOUND;
   2187   }
   2188 
   2189   *FvInfo     = PrivateData->UnknownFvInfo[Index].FvInfo;
   2190   *FvInfoSize = PrivateData->UnknownFvInfo[Index].FvInfoSize;
   2191   *AuthenticationStatus = PrivateData->UnknownFvInfo[Index].AuthenticationStatus;
   2192 
   2193   //
   2194   // Remove an entry from UnknownFvInfo array.
   2195   //
   2196   Index2 = Index + 1;
   2197   for (;Index2 < PrivateData->UnknownFvInfoCount; Index2 ++, Index ++) {
   2198     CopyMem (&PrivateData->UnknownFvInfo[Index], &PrivateData->UnknownFvInfo[Index2], sizeof (PEI_CORE_UNKNOW_FORMAT_FV_INFO));
   2199   }
   2200   PrivateData->UnknownFvInfoCount --;
   2201   return EFI_SUCCESS;
   2202 }
   2203 
   2204 /**
   2205   Notification callback function for EFI_PEI_FIRMWARE_VOLUME_PPI.
   2206 
   2207   When a EFI_PEI_FIRMWARE_VOLUME_PPI is installed to support new FV format, this
   2208   routine is called to process all discoveried FVs in this format.
   2209 
   2210   @param PeiServices       An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
   2211   @param NotifyDescriptor  Address of the notification descriptor data structure.
   2212   @param Ppi               Address of the PPI that was installed.
   2213 
   2214   @retval EFI_SUCCESS  The notification callback is processed correctly.
   2215 **/
   2216 EFI_STATUS
   2217 EFIAPI
   2218 ThirdPartyFvPpiNotifyCallback (
   2219   IN EFI_PEI_SERVICES              **PeiServices,
   2220   IN EFI_PEI_NOTIFY_DESCRIPTOR     *NotifyDescriptor,
   2221   IN VOID                          *Ppi
   2222   )
   2223 {
   2224   PEI_CORE_INSTANCE            *PrivateData;
   2225   EFI_PEI_FIRMWARE_VOLUME_PPI  *FvPpi;
   2226   VOID                         *FvInfo;
   2227   UINT32                       FvInfoSize;
   2228   UINT32                       AuthenticationStatus;
   2229   EFI_STATUS                   Status;
   2230   EFI_PEI_FV_HANDLE            FvHandle;
   2231   BOOLEAN                      IsProcessed;
   2232   UINTN                        FvIndex;
   2233   EFI_PEI_FILE_HANDLE          FileHandle;
   2234   VOID                         *DepexData;
   2235   UINTN                        CurFvCount;
   2236 
   2237   PrivateData  = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
   2238   FvPpi = (EFI_PEI_FIRMWARE_VOLUME_PPI*) Ppi;
   2239 
   2240   do {
   2241     Status = FindUnknownFormatFvInfo (PrivateData, NotifyDescriptor->Guid, &FvInfo, &FvInfoSize, &AuthenticationStatus);
   2242     if (EFI_ERROR (Status)) {
   2243       return EFI_SUCCESS;
   2244     }
   2245 
   2246     //
   2247     // Process new found FV and get FV handle.
   2248     //
   2249     Status = FvPpi->ProcessVolume (FvPpi, FvInfo, FvInfoSize, &FvHandle);
   2250     if (EFI_ERROR (Status)) {
   2251       DEBUG ((EFI_D_ERROR, "Fail to process the FV 0x%p, FV may be corrupted!\n", FvInfo));
   2252       continue;
   2253     }
   2254 
   2255     //
   2256     // Check whether the FV has already been processed.
   2257     //
   2258     IsProcessed = FALSE;
   2259     for (FvIndex = 0; FvIndex < PrivateData->FvCount; FvIndex ++) {
   2260       if (PrivateData->Fv[FvIndex].FvHandle == FvHandle) {
   2261         DEBUG ((EFI_D_INFO, "The Fv %p has already been processed!\n", FvInfo));
   2262         IsProcessed = TRUE;
   2263         break;
   2264       }
   2265     }
   2266 
   2267     if (IsProcessed) {
   2268       continue;
   2269     }
   2270 
   2271     if (PrivateData->FvCount >= PcdGet32 (PcdPeiCoreMaxFvSupported)) {
   2272       DEBUG ((EFI_D_ERROR, "The number of Fv Images (%d) exceed the max supported FVs (%d) in Pei", PrivateData->FvCount + 1, PcdGet32 (PcdPeiCoreMaxFvSupported)));
   2273       DEBUG ((EFI_D_ERROR, "PcdPeiCoreMaxFvSupported value need be reconfigurated in DSC"));
   2274       ASSERT (FALSE);
   2275     }
   2276 
   2277     //
   2278     // Update internal PEI_CORE_FV array.
   2279     //
   2280     PrivateData->Fv[PrivateData->FvCount].FvHeader = (EFI_FIRMWARE_VOLUME_HEADER*) FvInfo;
   2281     PrivateData->Fv[PrivateData->FvCount].FvPpi    = FvPpi;
   2282     PrivateData->Fv[PrivateData->FvCount].FvHandle = FvHandle;
   2283     PrivateData->Fv[PrivateData->FvCount].AuthenticationStatus = AuthenticationStatus;
   2284     CurFvCount = PrivateData->FvCount;
   2285     DEBUG ((
   2286       EFI_D_INFO,
   2287       "The %dth FV start address is 0x%11p, size is 0x%08x, handle is 0x%p\n",
   2288       (UINT32) CurFvCount,
   2289       (VOID *) FvInfo,
   2290       FvInfoSize,
   2291       FvHandle
   2292       ));
   2293     PrivateData->FvCount ++;
   2294 
   2295     //
   2296     // Scan and process the new discoveried FV for EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
   2297     //
   2298     FileHandle = NULL;
   2299     do {
   2300       Status = FvPpi->FindFileByType (
   2301                         FvPpi,
   2302                         EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE,
   2303                         FvHandle,
   2304                         &FileHandle
   2305                        );
   2306       if (!EFI_ERROR (Status)) {
   2307         Status = FvPpi->FindSectionByType (
   2308                           FvPpi,
   2309                           EFI_SECTION_PEI_DEPEX,
   2310                           FileHandle,
   2311                           (VOID**)&DepexData
   2312                           );
   2313         if (!EFI_ERROR (Status)) {
   2314           if (!PeimDispatchReadiness (PeiServices, DepexData)) {
   2315             //
   2316             // Dependency is not satisfied.
   2317             //
   2318             continue;
   2319           }
   2320         }
   2321 
   2322         DEBUG ((EFI_D_INFO, "Found firmware volume Image File %p in FV[%d] %p\n", FileHandle, CurFvCount, FvHandle));
   2323         ProcessFvFile (PrivateData, &PrivateData->Fv[CurFvCount], FileHandle);
   2324       }
   2325     } while (FileHandle != NULL);
   2326   } while (TRUE);
   2327 }
   2328