Home | History | Annotate | Download | only in PrePiLib
      1 /** @file
      2   Implementation of the 6 PEI Ffs (FV) APIs in library form.
      3 
      4   This code only knows about a FV if it has a EFI_HOB_TYPE_FV entry in the HOB list
      5 
      6   Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
      7 
      8   This program and the accompanying materials
      9   are licensed and made available under the terms and conditions of the BSD License
     10   which accompanies this distribution.  The full text of the license may be found at
     11   http://opensource.org/licenses/bsd-license.php
     12 
     13   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     14   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     15 
     16 **/
     17 
     18 #include <PrePi.h>
     19 #include <Library/ExtractGuidedSectionLib.h>
     20 
     21 
     22 #define GET_OCCUPIED_SIZE(ActualSize, Alignment) \
     23   (ActualSize) + (((Alignment) - ((ActualSize) & ((Alignment) - 1))) & ((Alignment) - 1))
     24 
     25 
     26 /**
     27   Returns the highest bit set of the State field
     28 
     29   @param ErasePolarity   Erase Polarity  as defined by EFI_FVB2_ERASE_POLARITY
     30                          in the Attributes field.
     31   @param FfsHeader       Pointer to FFS File Header
     32 
     33 
     34   @retval the highest bit in the State field
     35 
     36 **/
     37 STATIC
     38 EFI_FFS_FILE_STATE
     39 GetFileState(
     40   IN UINT8                ErasePolarity,
     41   IN EFI_FFS_FILE_HEADER  *FfsHeader
     42   )
     43 {
     44   EFI_FFS_FILE_STATE  FileState;
     45   EFI_FFS_FILE_STATE  HighestBit;
     46 
     47   FileState = FfsHeader->State;
     48 
     49   if (ErasePolarity != 0) {
     50     FileState = (EFI_FFS_FILE_STATE)~FileState;
     51   }
     52 
     53   HighestBit = 0x80;
     54   while (HighestBit != 0 && (HighestBit & FileState) == 0) {
     55     HighestBit >>= 1;
     56   }
     57 
     58   return HighestBit;
     59 }
     60 
     61 
     62 /**
     63   Calculates the checksum of the header of a file.
     64   The header is a zero byte checksum, so zero means header is good
     65 
     66   @param FfsHeader       Pointer to FFS File Header
     67 
     68   @retval Checksum of the header
     69 
     70 **/
     71 STATIC
     72 UINT8
     73 CalculateHeaderChecksum (
     74   IN EFI_FFS_FILE_HEADER  *FileHeader
     75   )
     76 {
     77   UINT8   *Ptr;
     78   UINTN   Index;
     79   UINT8   Sum;
     80 
     81   Sum = 0;
     82   Ptr = (UINT8 *)FileHeader;
     83 
     84   for (Index = 0; Index < sizeof(EFI_FFS_FILE_HEADER) - 3; Index += 4) {
     85     Sum = (UINT8)(Sum + Ptr[Index]);
     86     Sum = (UINT8)(Sum + Ptr[Index+1]);
     87     Sum = (UINT8)(Sum + Ptr[Index+2]);
     88     Sum = (UINT8)(Sum + Ptr[Index+3]);
     89   }
     90 
     91   for (; Index < sizeof(EFI_FFS_FILE_HEADER); Index++) {
     92     Sum = (UINT8)(Sum + Ptr[Index]);
     93   }
     94 
     95   //
     96   // State field (since this indicates the different state of file).
     97   //
     98   Sum = (UINT8)(Sum - FileHeader->State);
     99   //
    100   // Checksum field of the file is not part of the header checksum.
    101   //
    102   Sum = (UINT8)(Sum - FileHeader->IntegrityCheck.Checksum.File);
    103 
    104   return Sum;
    105 }
    106 
    107 
    108 /**
    109   Given a FileHandle return the VolumeHandle
    110 
    111   @param FileHandle   File handle to look up
    112   @param VolumeHandle Match for FileHandle
    113 
    114   @retval TRUE  VolumeHandle is valid
    115 
    116 **/
    117 STATIC
    118 BOOLEAN
    119 EFIAPI
    120 FileHandleToVolume (
    121   IN   EFI_PEI_FILE_HANDLE     FileHandle,
    122   OUT  EFI_PEI_FV_HANDLE       *VolumeHandle
    123   )
    124 {
    125   EFI_FIRMWARE_VOLUME_HEADER  *FwVolHeader;
    126   EFI_PEI_HOB_POINTERS        Hob;
    127 
    128   Hob.Raw = GetHobList ();
    129   if (Hob.Raw == NULL) {
    130     return FALSE;
    131   }
    132 
    133   do {
    134     Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, Hob.Raw);
    135     if (Hob.Raw != NULL) {
    136       FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(Hob.FirmwareVolume->BaseAddress);
    137       if (((UINT64) (UINTN) FileHandle > (UINT64) (UINTN) FwVolHeader ) &&   \
    138           ((UINT64) (UINTN) FileHandle <= ((UINT64) (UINTN) FwVolHeader + FwVolHeader->FvLength - 1))) {
    139         *VolumeHandle = (EFI_PEI_FV_HANDLE)FwVolHeader;
    140         return TRUE;
    141       }
    142 
    143       Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, GET_NEXT_HOB (Hob));
    144     }
    145   } while (Hob.Raw != NULL);
    146 
    147   return FALSE;
    148 }
    149 
    150 
    151 
    152 /**
    153   Given the input file pointer, search for the next matching file in the
    154   FFS volume as defined by SearchType. The search starts from FileHeader inside
    155   the Firmware Volume defined by FwVolHeader.
    156 
    157   @param FileHandle   File handle to look up
    158   @param VolumeHandle Match for FileHandle
    159 
    160 
    161 **/
    162 EFI_STATUS
    163 FindFileEx (
    164   IN  CONST EFI_PEI_FV_HANDLE        FvHandle,
    165   IN  CONST EFI_GUID                 *FileName,   OPTIONAL
    166   IN        EFI_FV_FILETYPE          SearchType,
    167   IN OUT    EFI_PEI_FILE_HANDLE      *FileHandle
    168   )
    169 {
    170   EFI_FIRMWARE_VOLUME_HEADER           *FwVolHeader;
    171   EFI_FFS_FILE_HEADER                   **FileHeader;
    172   EFI_FFS_FILE_HEADER                   *FfsFileHeader;
    173   EFI_FIRMWARE_VOLUME_EXT_HEADER        *FwVolExHeaderInfo;
    174   UINT32                                FileLength;
    175   UINT32                                FileOccupiedSize;
    176   UINT32                                FileOffset;
    177   UINT64                                FvLength;
    178   UINT8                                 ErasePolarity;
    179   UINT8                                 FileState;
    180 
    181   FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FvHandle;
    182   FileHeader  = (EFI_FFS_FILE_HEADER **)FileHandle;
    183 
    184   FvLength = FwVolHeader->FvLength;
    185   if (FwVolHeader->Attributes & EFI_FVB2_ERASE_POLARITY) {
    186     ErasePolarity = 1;
    187   } else {
    188     ErasePolarity = 0;
    189   }
    190 
    191   //
    192   // If FileHeader is not specified (NULL) or FileName is not NULL,
    193   // start with the first file in the firmware volume.  Otherwise,
    194   // start from the FileHeader.
    195   //
    196   if ((*FileHeader == NULL) || (FileName != NULL)) {
    197     FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FwVolHeader + FwVolHeader->HeaderLength);
    198     if (FwVolHeader->ExtHeaderOffset != 0) {
    199       FwVolExHeaderInfo = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)(((UINT8 *)FwVolHeader) + FwVolHeader->ExtHeaderOffset);
    200       FfsFileHeader = (EFI_FFS_FILE_HEADER *)(((UINT8 *)FwVolExHeaderInfo) + FwVolExHeaderInfo->ExtHeaderSize);
    201     }
    202   } else {
    203     //
    204     // Length is 24 bits wide so mask upper 8 bits
    205     // FileLength is adjusted to FileOccupiedSize as it is 8 byte aligned.
    206     //
    207     FileLength = *(UINT32 *)(*FileHeader)->Size & 0x00FFFFFF;
    208     FileOccupiedSize = GET_OCCUPIED_SIZE (FileLength, 8);
    209     FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)*FileHeader + FileOccupiedSize);
    210   }
    211 
    212   // FFS files begin with a header that is aligned on an 8-byte boundary
    213   FfsFileHeader = ALIGN_POINTER (FfsFileHeader, 8);
    214 
    215   FileOffset = (UINT32) ((UINT8 *)FfsFileHeader - (UINT8 *)FwVolHeader);
    216   ASSERT (FileOffset <= 0xFFFFFFFF);
    217 
    218   while (FileOffset < (FvLength - sizeof (EFI_FFS_FILE_HEADER))) {
    219     //
    220     // Get FileState which is the highest bit of the State
    221     //
    222     FileState = GetFileState (ErasePolarity, FfsFileHeader);
    223 
    224     switch (FileState) {
    225 
    226     case EFI_FILE_HEADER_INVALID:
    227       FileOffset += sizeof(EFI_FFS_FILE_HEADER);
    228       FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + sizeof(EFI_FFS_FILE_HEADER));
    229       break;
    230 
    231     case EFI_FILE_DATA_VALID:
    232     case EFI_FILE_MARKED_FOR_UPDATE:
    233       if (CalculateHeaderChecksum (FfsFileHeader) != 0) {
    234         ASSERT (FALSE);
    235         *FileHeader = NULL;
    236         return EFI_NOT_FOUND;
    237       }
    238 
    239       FileLength = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF;
    240       FileOccupiedSize = GET_OCCUPIED_SIZE(FileLength, 8);
    241 
    242       if (FileName != NULL) {
    243         if (CompareGuid (&FfsFileHeader->Name, (EFI_GUID*)FileName)) {
    244           *FileHeader = FfsFileHeader;
    245           return EFI_SUCCESS;
    246         }
    247       } else if (((SearchType == FfsFileHeader->Type) || (SearchType == EFI_FV_FILETYPE_ALL)) &&
    248                  (FfsFileHeader->Type != EFI_FV_FILETYPE_FFS_PAD)) {
    249         *FileHeader = FfsFileHeader;
    250         return EFI_SUCCESS;
    251       }
    252 
    253       FileOffset += FileOccupiedSize;
    254       FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + FileOccupiedSize);
    255       break;
    256 
    257     case EFI_FILE_DELETED:
    258       FileLength = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF;
    259       FileOccupiedSize = GET_OCCUPIED_SIZE(FileLength, 8);
    260       FileOffset += FileOccupiedSize;
    261       FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + FileOccupiedSize);
    262       break;
    263 
    264     default:
    265       *FileHeader = NULL;
    266       return EFI_NOT_FOUND;
    267     }
    268   }
    269 
    270 
    271   *FileHeader = NULL;
    272   return EFI_NOT_FOUND;
    273 }
    274 
    275 
    276 /**
    277   Go through the file to search SectionType section,
    278   when meeting an encapsuled section.
    279 
    280   @param  SectionType  - Filter to find only section of this type.
    281   @param  Section      - From where to search.
    282   @param  SectionSize  - The file size to search.
    283   @param  OutputBuffer - Pointer to the section to search.
    284 
    285   @retval EFI_SUCCESS
    286 **/
    287 EFI_STATUS
    288 FfsProcessSection (
    289   IN EFI_SECTION_TYPE           SectionType,
    290   IN EFI_COMMON_SECTION_HEADER  *Section,
    291   IN UINTN                      SectionSize,
    292   OUT VOID                      **OutputBuffer
    293   )
    294 {
    295   EFI_STATUS                              Status;
    296   UINT32                                  SectionLength;
    297   UINT32                                  ParsedLength;
    298   EFI_COMPRESSION_SECTION                 *CompressionSection;
    299   UINT32                                  DstBufferSize;
    300   VOID                                    *ScratchBuffer;
    301   UINT32                                  ScratchBufferSize;
    302   VOID                                    *DstBuffer;
    303   UINT16                                  SectionAttribute;
    304   UINT32                                  AuthenticationStatus;
    305 
    306 
    307   *OutputBuffer = NULL;
    308   ParsedLength  = 0;
    309   Status        = EFI_NOT_FOUND;
    310   while (ParsedLength < SectionSize) {
    311     if (Section->Type == SectionType) {
    312       *OutputBuffer = (VOID *)(Section + 1);
    313 
    314       return EFI_SUCCESS;
    315     } else if ((Section->Type == EFI_SECTION_COMPRESSION) || (Section->Type == EFI_SECTION_GUID_DEFINED)) {
    316 
    317       if (Section->Type == EFI_SECTION_COMPRESSION) {
    318         CompressionSection  = (EFI_COMPRESSION_SECTION *) Section;
    319         SectionLength       = *(UINT32 *)Section->Size & 0x00FFFFFF;
    320 
    321         if (CompressionSection->CompressionType != EFI_STANDARD_COMPRESSION) {
    322           return EFI_UNSUPPORTED;
    323         }
    324 
    325         Status = UefiDecompressGetInfo (
    326                    (UINT8 *) ((EFI_COMPRESSION_SECTION *) Section + 1),
    327                    (UINT32) SectionLength - sizeof (EFI_COMPRESSION_SECTION),
    328                    &DstBufferSize,
    329                    &ScratchBufferSize
    330                    );
    331       } else if (Section->Type == EFI_SECTION_GUID_DEFINED) {
    332         Status = ExtractGuidedSectionGetInfo (
    333                    Section,
    334                    &DstBufferSize,
    335                    &ScratchBufferSize,
    336                    &SectionAttribute
    337                    );
    338       }
    339 
    340       if (EFI_ERROR (Status)) {
    341         //
    342         // GetInfo failed
    343         //
    344         DEBUG ((EFI_D_ERROR, "Decompress GetInfo Failed - %r\n", Status));
    345         return EFI_NOT_FOUND;
    346       }
    347       //
    348       // Allocate scratch buffer
    349       //
    350       ScratchBuffer = (VOID *)(UINTN)AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize));
    351       if (ScratchBuffer == NULL) {
    352         return EFI_OUT_OF_RESOURCES;
    353       }
    354       //
    355       // Allocate destination buffer, extra one page for adjustment
    356       //
    357       DstBuffer = (VOID *)(UINTN)AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize) + 1);
    358       if (DstBuffer == NULL) {
    359         return EFI_OUT_OF_RESOURCES;
    360       }
    361       //
    362       // DstBuffer still is one section. Adjust DstBuffer offset, skip EFI section header
    363       // to make section data at page alignment.
    364       //
    365       DstBuffer = (UINT8 *)DstBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER);
    366       //
    367       // Call decompress function
    368       //
    369       if (Section->Type == EFI_SECTION_COMPRESSION) {
    370         Status = UefiDecompress (
    371                     (CHAR8 *) ((EFI_COMPRESSION_SECTION *) Section + 1),
    372                     DstBuffer,
    373                     ScratchBuffer
    374                     );
    375       } else if (Section->Type == EFI_SECTION_GUID_DEFINED) {
    376         Status = ExtractGuidedSectionDecode (
    377                     Section,
    378                     &DstBuffer,
    379                     ScratchBuffer,
    380                     &AuthenticationStatus
    381                     );
    382       }
    383 
    384       if (EFI_ERROR (Status)) {
    385         //
    386         // Decompress failed
    387         //
    388         DEBUG ((EFI_D_ERROR, "Decompress Failed - %r\n", Status));
    389         return EFI_NOT_FOUND;
    390       } else {
    391         return FfsProcessSection (
    392                 SectionType,
    393                 DstBuffer,
    394                 DstBufferSize,
    395                 OutputBuffer
    396                 );
    397        }
    398     }
    399 
    400     //
    401     // Size is 24 bits wide so mask upper 8 bits.
    402     // SectionLength is adjusted it is 4 byte aligned.
    403     // Go to the next section
    404     //
    405     SectionLength = *(UINT32 *)Section->Size & 0x00FFFFFF;
    406     SectionLength = GET_OCCUPIED_SIZE (SectionLength, 4);
    407     ASSERT (SectionLength != 0);
    408     ParsedLength += SectionLength;
    409     Section = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)Section + SectionLength);
    410   }
    411 
    412   return EFI_NOT_FOUND;
    413 }
    414 
    415 
    416 
    417 /**
    418   This service enables discovery sections of a given type within a valid FFS file.
    419 
    420   @param  SearchType            The value of the section type to find.
    421   @param  FfsFileHeader         A pointer to the file header that contains the set of sections to
    422                                 be searched.
    423   @param  SectionData           A pointer to the discovered section, if successful.
    424 
    425   @retval EFI_SUCCESS           The section was found.
    426   @retval EFI_NOT_FOUND         The section was not found.
    427 
    428 **/
    429 EFI_STATUS
    430 EFIAPI
    431 FfsFindSectionData (
    432   IN EFI_SECTION_TYPE           SectionType,
    433   IN EFI_PEI_FILE_HANDLE        FileHandle,
    434   OUT VOID                      **SectionData
    435   )
    436 {
    437   EFI_FFS_FILE_HEADER                     *FfsFileHeader;
    438   UINT32                                  FileSize;
    439   EFI_COMMON_SECTION_HEADER               *Section;
    440 
    441   FfsFileHeader = (EFI_FFS_FILE_HEADER *)(FileHandle);
    442 
    443   //
    444   // Size is 24 bits wide so mask upper 8 bits.
    445   // Does not include FfsFileHeader header size
    446   // FileSize is adjusted to FileOccupiedSize as it is 8 byte aligned.
    447   //
    448   Section = (EFI_COMMON_SECTION_HEADER *)(FfsFileHeader + 1);
    449   FileSize = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF;
    450   FileSize -= sizeof (EFI_FFS_FILE_HEADER);
    451 
    452   return FfsProcessSection (
    453           SectionType,
    454           Section,
    455           FileSize,
    456           SectionData
    457           );
    458 }
    459 
    460 
    461 
    462 
    463 
    464 
    465 /**
    466   This service enables discovery of additional firmware files.
    467 
    468   @param  SearchType            A filter to find files only of this type.
    469   @param  FwVolHeader           Pointer to the firmware volume header of the volume to search.
    470                                 This parameter must point to a valid FFS volume.
    471   @param  FileHeader            Pointer to the current file from which to begin searching.
    472 
    473   @retval EFI_SUCCESS           The file was found.
    474   @retval EFI_NOT_FOUND         The file was not found.
    475   @retval EFI_NOT_FOUND         The header checksum was not zero.
    476 
    477 **/
    478 EFI_STATUS
    479 EFIAPI
    480 FfsFindNextFile (
    481   IN UINT8                       SearchType,
    482   IN EFI_PEI_FV_HANDLE           VolumeHandle,
    483   IN OUT EFI_PEI_FILE_HANDLE     *FileHandle
    484   )
    485 {
    486   return FindFileEx (VolumeHandle, NULL, SearchType, FileHandle);
    487 }
    488 
    489 
    490 /**
    491   This service enables discovery of additional firmware volumes.
    492 
    493   @param  Instance              This instance of the firmware volume to find.  The value 0 is the
    494                                 Boot Firmware Volume (BFV).
    495   @param  FwVolHeader           Pointer to the firmware volume header of the volume to return.
    496 
    497   @retval EFI_SUCCESS           The volume was found.
    498   @retval EFI_NOT_FOUND         The volume was not found.
    499 
    500 **/
    501 EFI_STATUS
    502 EFIAPI
    503 FfsFindNextVolume (
    504   IN UINTN                          Instance,
    505   IN OUT EFI_PEI_FV_HANDLE          *VolumeHandle
    506   )
    507 {
    508   EFI_PEI_HOB_POINTERS        Hob;
    509 
    510 
    511   Hob.Raw = GetHobList ();
    512   if (Hob.Raw == NULL) {
    513     return EFI_NOT_FOUND;
    514   }
    515 
    516   do {
    517     Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, Hob.Raw);
    518     if (Hob.Raw != NULL) {
    519       if (Instance-- == 0) {
    520         *VolumeHandle = (EFI_PEI_FV_HANDLE)(UINTN)(Hob.FirmwareVolume->BaseAddress);
    521         return EFI_SUCCESS;
    522       }
    523 
    524       Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, GET_NEXT_HOB (Hob));
    525     }
    526   } while (Hob.Raw != NULL);
    527 
    528   return EFI_NOT_FOUND;
    529 
    530 }
    531 
    532 
    533 /**
    534   Find a file in the volume by name
    535 
    536   @param FileName       A pointer to the name of the file to
    537                         find within the firmware volume.
    538 
    539   @param VolumeHandle   The firmware volume to search FileHandle
    540                         Upon exit, points to the found file's
    541                         handle or NULL if it could not be found.
    542 
    543   @retval EFI_SUCCESS             File was found.
    544 
    545   @retval EFI_NOT_FOUND           File was not found.
    546 
    547   @retval EFI_INVALID_PARAMETER   VolumeHandle or FileHandle or
    548                                   FileName was NULL.
    549 
    550 **/
    551 EFI_STATUS
    552 EFIAPI
    553 FfsFindFileByName (
    554   IN  CONST EFI_GUID        *FileName,
    555   IN  EFI_PEI_FV_HANDLE     VolumeHandle,
    556   OUT EFI_PEI_FILE_HANDLE   *FileHandle
    557   )
    558 {
    559   EFI_STATUS  Status;
    560   if ((VolumeHandle == NULL) || (FileName == NULL) || (FileHandle == NULL)) {
    561     return EFI_INVALID_PARAMETER;
    562   }
    563   Status = FindFileEx (VolumeHandle, FileName, 0, FileHandle);
    564   if (Status == EFI_NOT_FOUND) {
    565     *FileHandle = NULL;
    566   }
    567   return Status;
    568 }
    569 
    570 
    571 
    572 
    573 /**
    574   Get information about the file by name.
    575 
    576   @param FileHandle   Handle of the file.
    577 
    578   @param FileInfo     Upon exit, points to the file's
    579                       information.
    580 
    581   @retval EFI_SUCCESS             File information returned.
    582 
    583   @retval EFI_INVALID_PARAMETER   If FileHandle does not
    584                                   represent a valid file.
    585 
    586   @retval EFI_INVALID_PARAMETER   If FileInfo is NULL.
    587 
    588 **/
    589 EFI_STATUS
    590 EFIAPI
    591 FfsGetFileInfo (
    592   IN EFI_PEI_FILE_HANDLE  FileHandle,
    593   OUT EFI_FV_FILE_INFO    *FileInfo
    594   )
    595 {
    596   UINT8                       FileState;
    597   UINT8                       ErasePolarity;
    598   EFI_FFS_FILE_HEADER         *FileHeader;
    599   EFI_PEI_FV_HANDLE           VolumeHandle;
    600 
    601   if ((FileHandle == NULL) || (FileInfo == NULL)) {
    602     return EFI_INVALID_PARAMETER;
    603   }
    604 
    605   VolumeHandle = 0;
    606   //
    607   // Retrieve the FirmwareVolume which the file resides in.
    608   //
    609   if (!FileHandleToVolume(FileHandle, &VolumeHandle)) {
    610     return EFI_INVALID_PARAMETER;
    611   }
    612 
    613   if (((EFI_FIRMWARE_VOLUME_HEADER*)VolumeHandle)->Attributes & EFI_FVB2_ERASE_POLARITY) {
    614     ErasePolarity = 1;
    615   } else {
    616     ErasePolarity = 0;
    617   }
    618 
    619   //
    620   // Get FileState which is the highest bit of the State
    621   //
    622   FileState = GetFileState (ErasePolarity, (EFI_FFS_FILE_HEADER*)FileHandle);
    623 
    624   switch (FileState) {
    625     case EFI_FILE_DATA_VALID:
    626     case EFI_FILE_MARKED_FOR_UPDATE:
    627       break;
    628     default:
    629       return EFI_INVALID_PARAMETER;
    630     }
    631 
    632   FileHeader = (EFI_FFS_FILE_HEADER *)FileHandle;
    633   CopyMem (&FileInfo->FileName, &FileHeader->Name, sizeof(EFI_GUID));
    634   FileInfo->FileType = FileHeader->Type;
    635   FileInfo->FileAttributes = FileHeader->Attributes;
    636   FileInfo->BufferSize = ((*(UINT32 *)FileHeader->Size) & 0x00FFFFFF) -  sizeof (EFI_FFS_FILE_HEADER);
    637   FileInfo->Buffer = (FileHeader + 1);
    638   return EFI_SUCCESS;
    639 }
    640 
    641 
    642 /**
    643   Get Information about the volume by name
    644 
    645   @param VolumeHandle   Handle of the volume.
    646 
    647   @param VolumeInfo     Upon exit, points to the volume's
    648                         information.
    649 
    650   @retval EFI_SUCCESS             File information returned.
    651 
    652   @retval EFI_INVALID_PARAMETER   If FileHandle does not
    653                                   represent a valid file.
    654 
    655   @retval EFI_INVALID_PARAMETER   If FileInfo is NULL.
    656 
    657 **/
    658 EFI_STATUS
    659 EFIAPI
    660 FfsGetVolumeInfo (
    661   IN EFI_PEI_FV_HANDLE  VolumeHandle,
    662   OUT EFI_FV_INFO       *VolumeInfo
    663   )
    664 {
    665   EFI_FIRMWARE_VOLUME_HEADER             FwVolHeader;
    666   EFI_FIRMWARE_VOLUME_EXT_HEADER         *FwVolExHeaderInfo;
    667 
    668   if (VolumeInfo == NULL) {
    669     return EFI_INVALID_PARAMETER;
    670   }
    671 
    672   //
    673   // VolumeHandle may not align at 8 byte,
    674   // but FvLength is UINT64 type, which requires FvHeader align at least 8 byte.
    675   // So, Copy FvHeader into the local FvHeader structure.
    676   //
    677   CopyMem (&FwVolHeader, VolumeHandle, sizeof (EFI_FIRMWARE_VOLUME_HEADER));
    678   //
    679   // Check Fv Image Signature
    680   //
    681   if (FwVolHeader.Signature != EFI_FVH_SIGNATURE) {
    682     return EFI_INVALID_PARAMETER;
    683   }
    684   VolumeInfo->FvAttributes = FwVolHeader.Attributes;
    685   VolumeInfo->FvStart = (VOID *) VolumeHandle;
    686   VolumeInfo->FvSize = FwVolHeader.FvLength;
    687   CopyMem (&VolumeInfo->FvFormat, &FwVolHeader.FileSystemGuid, sizeof(EFI_GUID));
    688 
    689   if (FwVolHeader.ExtHeaderOffset != 0) {
    690     FwVolExHeaderInfo = (EFI_FIRMWARE_VOLUME_EXT_HEADER*)(((UINT8 *)VolumeHandle) + FwVolHeader.ExtHeaderOffset);
    691     CopyMem (&VolumeInfo->FvName, &FwVolExHeaderInfo->FvName, sizeof(EFI_GUID));
    692   }
    693   return EFI_SUCCESS;
    694 }
    695 
    696 
    697 
    698 /**
    699   Search through every FV until you find a file of type FileType
    700 
    701   @param FileType        File handle of a Fv type file.
    702   @param Volumehandle    On succes Volume Handle of the match
    703   @param FileHandle      On success File Handle of the match
    704 
    705   @retval EFI_NOT_FOUND  FV image can't be found.
    706   @retval EFI_SUCCESS    Successfully found FileType
    707 
    708 **/
    709 EFI_STATUS
    710 EFIAPI
    711 FfsAnyFvFindFirstFile (
    712   IN  EFI_FV_FILETYPE       FileType,
    713   OUT EFI_PEI_FV_HANDLE     *VolumeHandle,
    714   OUT EFI_PEI_FILE_HANDLE   *FileHandle
    715   )
    716 {
    717   EFI_STATUS        Status;
    718   UINTN             Instance;
    719 
    720   //
    721   // Search every FV for the DXE Core
    722   //
    723   Instance    = 0;
    724   *FileHandle = NULL;
    725 
    726   while (1)
    727   {
    728     Status = FfsFindNextVolume (Instance++, VolumeHandle);
    729     if (EFI_ERROR (Status))
    730     {
    731       break;
    732     }
    733 
    734     Status = FfsFindNextFile (FileType, *VolumeHandle, FileHandle);
    735     if (!EFI_ERROR (Status))
    736     {
    737       break;
    738     }
    739   }
    740 
    741   return Status;
    742 }
    743 
    744 
    745 
    746 /**
    747   Get Fv image from the FV type file, then add FV & FV2 Hob.
    748 
    749   @param FileHandle  File handle of a Fv type file.
    750 
    751 
    752   @retval EFI_NOT_FOUND  FV image can't be found.
    753   @retval EFI_SUCCESS    Successfully to process it.
    754 
    755 **/
    756 EFI_STATUS
    757 EFIAPI
    758 FfsProcessFvFile (
    759   IN  EFI_PEI_FILE_HANDLE   FvFileHandle
    760   )
    761 {
    762   EFI_STATUS            Status;
    763   EFI_PEI_FV_HANDLE     FvImageHandle;
    764   EFI_FV_INFO           FvImageInfo;
    765   UINT32                FvAlignment;
    766   VOID                  *FvBuffer;
    767   EFI_PEI_HOB_POINTERS  HobFv2;
    768 
    769   FvBuffer             = NULL;
    770 
    771 
    772   //
    773   // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has already
    774   // been extracted.
    775   //
    776   HobFv2.Raw = GetHobList ();
    777   while ((HobFv2.Raw = GetNextHob (EFI_HOB_TYPE_FV2, HobFv2.Raw)) != NULL) {
    778     if (CompareGuid (&(((EFI_FFS_FILE_HEADER *)FvFileHandle)->Name), &HobFv2.FirmwareVolume2->FileName)) {
    779       //
    780       // this FILE has been dispatched, it will not be dispatched again.
    781       //
    782       return EFI_SUCCESS;
    783     }
    784     HobFv2.Raw = GET_NEXT_HOB (HobFv2);
    785   }
    786 
    787   //
    788   // Find FvImage in FvFile
    789   //
    790   Status = FfsFindSectionData (EFI_SECTION_FIRMWARE_VOLUME_IMAGE, FvFileHandle, (VOID **)&FvImageHandle);
    791   if (EFI_ERROR (Status)) {
    792     return Status;
    793   }
    794 
    795   //
    796   // Collect FvImage Info.
    797   //
    798   ZeroMem (&FvImageInfo, sizeof (FvImageInfo));
    799   Status = FfsGetVolumeInfo (FvImageHandle, &FvImageInfo);
    800   ASSERT_EFI_ERROR (Status);
    801 
    802   //
    803   // FvAlignment must be more than 8 bytes required by FvHeader structure.
    804   //
    805   FvAlignment = 1 << ((FvImageInfo.FvAttributes & EFI_FVB2_ALIGNMENT) >> 16);
    806   if (FvAlignment < 8) {
    807     FvAlignment = 8;
    808   }
    809 
    810   //
    811   // Check FvImage
    812   //
    813   if ((UINTN) FvImageInfo.FvStart % FvAlignment != 0) {
    814     FvBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES ((UINT32) FvImageInfo.FvSize), FvAlignment);
    815     if (FvBuffer == NULL) {
    816       return EFI_OUT_OF_RESOURCES;
    817     }
    818     CopyMem (FvBuffer, FvImageInfo.FvStart, (UINTN) FvImageInfo.FvSize);
    819     //
    820     // Update FvImageInfo after reload FvImage to new aligned memory
    821     //
    822     FfsGetVolumeInfo ((EFI_PEI_FV_HANDLE) FvBuffer, &FvImageInfo);
    823   }
    824 
    825 
    826   //
    827   // Inform HOB consumer phase, i.e. DXE core, the existance of this FV
    828   //
    829   BuildFvHob ((EFI_PHYSICAL_ADDRESS) (UINTN) FvImageInfo.FvStart, FvImageInfo.FvSize);
    830 
    831   //
    832   // Makes the encapsulated volume show up in DXE phase to skip processing of
    833   // encapsulated file again.
    834   //
    835   BuildFv2Hob (
    836     (EFI_PHYSICAL_ADDRESS) (UINTN) FvImageInfo.FvStart,
    837     FvImageInfo.FvSize,
    838     &FvImageInfo.FvName,
    839     &(((EFI_FFS_FILE_HEADER *)FvFileHandle)->Name)
    840     );
    841 
    842   return EFI_SUCCESS;
    843 }
    844 
    845 
    846