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
GetFileState(IN UINT8 ErasePolarity,IN EFI_FFS_FILE_HEADER * FfsHeader)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
CalculateHeaderChecksum(IN EFI_FFS_FILE_HEADER * FileHeader)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
FileHandleToVolume(IN EFI_PEI_FILE_HANDLE FileHandle,OUT EFI_PEI_FV_HANDLE * VolumeHandle)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
FindFileEx(IN CONST EFI_PEI_FV_HANDLE FvHandle,IN CONST EFI_GUID * FileName,OPTIONAL IN EFI_FV_FILETYPE SearchType,IN OUT EFI_PEI_FILE_HANDLE * FileHandle)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   FileOffset = (UINT32) ((UINT8 *)FfsFileHeader - (UINT8 *)FwVolHeader);
213   ASSERT (FileOffset <= 0xFFFFFFFF);
214 
215   while (FileOffset < (FvLength - sizeof (EFI_FFS_FILE_HEADER))) {
216     //
217     // Get FileState which is the highest bit of the State
218     //
219     FileState = GetFileState (ErasePolarity, FfsFileHeader);
220 
221     switch (FileState) {
222 
223     case EFI_FILE_HEADER_INVALID:
224       FileOffset += sizeof(EFI_FFS_FILE_HEADER);
225       FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + sizeof(EFI_FFS_FILE_HEADER));
226       break;
227 
228     case EFI_FILE_DATA_VALID:
229     case EFI_FILE_MARKED_FOR_UPDATE:
230       if (CalculateHeaderChecksum (FfsFileHeader) != 0) {
231         ASSERT (FALSE);
232         *FileHeader = NULL;
233         return EFI_NOT_FOUND;
234       }
235 
236       FileLength = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF;
237       FileOccupiedSize = GET_OCCUPIED_SIZE(FileLength, 8);
238 
239       if (FileName != NULL) {
240         if (CompareGuid (&FfsFileHeader->Name, (EFI_GUID*)FileName)) {
241           *FileHeader = FfsFileHeader;
242           return EFI_SUCCESS;
243         }
244       } else if (((SearchType == FfsFileHeader->Type) || (SearchType == EFI_FV_FILETYPE_ALL)) &&
245                  (FfsFileHeader->Type != EFI_FV_FILETYPE_FFS_PAD)) {
246         *FileHeader = FfsFileHeader;
247         return EFI_SUCCESS;
248       }
249 
250       FileOffset += FileOccupiedSize;
251       FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + FileOccupiedSize);
252       break;
253 
254     case EFI_FILE_DELETED:
255       FileLength = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF;
256       FileOccupiedSize = GET_OCCUPIED_SIZE(FileLength, 8);
257       FileOffset += FileOccupiedSize;
258       FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + FileOccupiedSize);
259       break;
260 
261     default:
262       *FileHeader = NULL;
263       return EFI_NOT_FOUND;
264     }
265   }
266 
267 
268   *FileHeader = NULL;
269   return EFI_NOT_FOUND;
270 }
271 
272 
273 /**
274   Go through the file to search SectionType section,
275   when meeting an encapsuled section.
276 
277   @param  SectionType  - Filter to find only section of this type.
278   @param  Section      - From where to search.
279   @param  SectionSize  - The file size to search.
280   @param  OutputBuffer - Pointer to the section to search.
281 
282   @retval EFI_SUCCESS
283 **/
284 EFI_STATUS
FfsProcessSection(IN EFI_SECTION_TYPE SectionType,IN EFI_COMMON_SECTION_HEADER * Section,IN UINTN SectionSize,OUT VOID ** OutputBuffer)285 FfsProcessSection (
286   IN EFI_SECTION_TYPE           SectionType,
287   IN EFI_COMMON_SECTION_HEADER  *Section,
288   IN UINTN                      SectionSize,
289   OUT VOID                      **OutputBuffer
290   )
291 {
292   EFI_STATUS                              Status;
293   UINT32                                  SectionLength;
294   UINT32                                  ParsedLength;
295   EFI_COMPRESSION_SECTION                 *CompressionSection;
296   UINT32                                  DstBufferSize;
297   VOID                                    *ScratchBuffer;
298   UINT32                                  ScratchBufferSize;
299   VOID                                    *DstBuffer;
300   UINT16                                  SectionAttribute;
301   UINT32                                  AuthenticationStatus;
302 
303 
304   *OutputBuffer = NULL;
305   ParsedLength  = 0;
306   Status        = EFI_NOT_FOUND;
307   while (ParsedLength < SectionSize) {
308     if (Section->Type == SectionType) {
309       *OutputBuffer = (VOID *)(Section + 1);
310 
311       return EFI_SUCCESS;
312     } else if ((Section->Type == EFI_SECTION_COMPRESSION) || (Section->Type == EFI_SECTION_GUID_DEFINED)) {
313 
314       if (Section->Type == EFI_SECTION_COMPRESSION) {
315         CompressionSection  = (EFI_COMPRESSION_SECTION *) Section;
316         SectionLength       = *(UINT32 *)Section->Size & 0x00FFFFFF;
317 
318         if (CompressionSection->CompressionType != EFI_STANDARD_COMPRESSION) {
319           return EFI_UNSUPPORTED;
320         }
321 
322         Status = UefiDecompressGetInfo (
323                    (UINT8 *) ((EFI_COMPRESSION_SECTION *) Section + 1),
324                    (UINT32) SectionLength - sizeof (EFI_COMPRESSION_SECTION),
325                    &DstBufferSize,
326                    &ScratchBufferSize
327                    );
328       } else if (Section->Type == EFI_SECTION_GUID_DEFINED) {
329         Status = ExtractGuidedSectionGetInfo (
330                    Section,
331                    &DstBufferSize,
332                    &ScratchBufferSize,
333                    &SectionAttribute
334                    );
335       }
336 
337       if (EFI_ERROR (Status)) {
338         //
339         // GetInfo failed
340         //
341         DEBUG ((EFI_D_ERROR, "Decompress GetInfo Failed - %r\n", Status));
342         return EFI_NOT_FOUND;
343       }
344       //
345       // Allocate scratch buffer
346       //
347       ScratchBuffer = (VOID *)(UINTN)AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize));
348       if (ScratchBuffer == NULL) {
349         return EFI_OUT_OF_RESOURCES;
350       }
351       //
352       // Allocate destination buffer, extra one page for adjustment
353       //
354       DstBuffer = (VOID *)(UINTN)AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize) + 1);
355       if (DstBuffer == NULL) {
356         return EFI_OUT_OF_RESOURCES;
357       }
358       //
359       // DstBuffer still is one section. Adjust DstBuffer offset, skip EFI section header
360       // to make section data at page alignment.
361       //
362       DstBuffer = (UINT8 *)DstBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER);
363       //
364       // Call decompress function
365       //
366       if (Section->Type == EFI_SECTION_COMPRESSION) {
367         Status = UefiDecompress (
368                     (CHAR8 *) ((EFI_COMPRESSION_SECTION *) Section + 1),
369                     DstBuffer,
370                     ScratchBuffer
371                     );
372       } else if (Section->Type == EFI_SECTION_GUID_DEFINED) {
373         Status = ExtractGuidedSectionDecode (
374                     Section,
375                     &DstBuffer,
376                     ScratchBuffer,
377                     &AuthenticationStatus
378                     );
379       }
380 
381       if (EFI_ERROR (Status)) {
382         //
383         // Decompress failed
384         //
385         DEBUG ((EFI_D_ERROR, "Decompress Failed - %r\n", Status));
386         return EFI_NOT_FOUND;
387       } else {
388         return FfsProcessSection (
389                 SectionType,
390                 DstBuffer,
391                 DstBufferSize,
392                 OutputBuffer
393                 );
394        }
395     }
396 
397     //
398     // Size is 24 bits wide so mask upper 8 bits.
399     // SectionLength is adjusted it is 4 byte aligned.
400     // Go to the next section
401     //
402     SectionLength = *(UINT32 *)Section->Size & 0x00FFFFFF;
403     SectionLength = GET_OCCUPIED_SIZE (SectionLength, 4);
404     ASSERT (SectionLength != 0);
405     ParsedLength += SectionLength;
406     Section = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)Section + SectionLength);
407   }
408 
409   return EFI_NOT_FOUND;
410 }
411 
412 
413 
414 /**
415   This service enables discovery sections of a given type within a valid FFS file.
416 
417   @param  SearchType            The value of the section type to find.
418   @param  FfsFileHeader         A pointer to the file header that contains the set of sections to
419                                 be searched.
420   @param  SectionData           A pointer to the discovered section, if successful.
421 
422   @retval EFI_SUCCESS           The section was found.
423   @retval EFI_NOT_FOUND         The section was not found.
424 
425 **/
426 EFI_STATUS
427 EFIAPI
FfsFindSectionData(IN EFI_SECTION_TYPE SectionType,IN EFI_PEI_FILE_HANDLE FileHandle,OUT VOID ** SectionData)428 FfsFindSectionData (
429   IN EFI_SECTION_TYPE           SectionType,
430   IN EFI_PEI_FILE_HANDLE        FileHandle,
431   OUT VOID                      **SectionData
432   )
433 {
434   EFI_FFS_FILE_HEADER                     *FfsFileHeader;
435   UINT32                                  FileSize;
436   EFI_COMMON_SECTION_HEADER               *Section;
437 
438   FfsFileHeader = (EFI_FFS_FILE_HEADER *)(FileHandle);
439 
440   //
441   // Size is 24 bits wide so mask upper 8 bits.
442   // Does not include FfsFileHeader header size
443   // FileSize is adjusted to FileOccupiedSize as it is 8 byte aligned.
444   //
445   Section = (EFI_COMMON_SECTION_HEADER *)(FfsFileHeader + 1);
446   FileSize = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF;
447   FileSize -= sizeof (EFI_FFS_FILE_HEADER);
448 
449   return FfsProcessSection (
450           SectionType,
451           Section,
452           FileSize,
453           SectionData
454           );
455 }
456 
457 
458 
459 
460 
461 
462 /**
463   This service enables discovery of additional firmware files.
464 
465   @param  SearchType            A filter to find files only of this type.
466   @param  FwVolHeader           Pointer to the firmware volume header of the volume to search.
467                                 This parameter must point to a valid FFS volume.
468   @param  FileHeader            Pointer to the current file from which to begin searching.
469 
470   @retval EFI_SUCCESS           The file was found.
471   @retval EFI_NOT_FOUND         The file was not found.
472   @retval EFI_NOT_FOUND         The header checksum was not zero.
473 
474 **/
475 EFI_STATUS
476 EFIAPI
FfsFindNextFile(IN UINT8 SearchType,IN EFI_PEI_FV_HANDLE VolumeHandle,IN OUT EFI_PEI_FILE_HANDLE * FileHandle)477 FfsFindNextFile (
478   IN UINT8                       SearchType,
479   IN EFI_PEI_FV_HANDLE           VolumeHandle,
480   IN OUT EFI_PEI_FILE_HANDLE     *FileHandle
481   )
482 {
483   return FindFileEx (VolumeHandle, NULL, SearchType, FileHandle);
484 }
485 
486 
487 /**
488   This service enables discovery of additional firmware volumes.
489 
490   @param  Instance              This instance of the firmware volume to find.  The value 0 is the
491                                 Boot Firmware Volume (BFV).
492   @param  FwVolHeader           Pointer to the firmware volume header of the volume to return.
493 
494   @retval EFI_SUCCESS           The volume was found.
495   @retval EFI_NOT_FOUND         The volume was not found.
496 
497 **/
498 EFI_STATUS
499 EFIAPI
FfsFindNextVolume(IN UINTN Instance,IN OUT EFI_PEI_FV_HANDLE * VolumeHandle)500 FfsFindNextVolume (
501   IN UINTN                          Instance,
502   IN OUT EFI_PEI_FV_HANDLE          *VolumeHandle
503   )
504 {
505   EFI_PEI_HOB_POINTERS        Hob;
506 
507 
508   Hob.Raw = GetHobList ();
509   if (Hob.Raw == NULL) {
510     return EFI_NOT_FOUND;
511   }
512 
513   do {
514     Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, Hob.Raw);
515     if (Hob.Raw != NULL) {
516       if (Instance-- == 0) {
517         *VolumeHandle = (EFI_PEI_FV_HANDLE)(UINTN)(Hob.FirmwareVolume->BaseAddress);
518         return EFI_SUCCESS;
519       }
520 
521       Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, GET_NEXT_HOB (Hob));
522     }
523   } while (Hob.Raw != NULL);
524 
525   return EFI_NOT_FOUND;
526 
527 }
528 
529 
530 /**
531   Find a file in the volume by name
532 
533   @param FileName       A pointer to the name of the file to
534                         find within the firmware volume.
535 
536   @param VolumeHandle   The firmware volume to search FileHandle
537                         Upon exit, points to the found file's
538                         handle or NULL if it could not be found.
539 
540   @retval EFI_SUCCESS             File was found.
541 
542   @retval EFI_NOT_FOUND           File was not found.
543 
544   @retval EFI_INVALID_PARAMETER   VolumeHandle or FileHandle or
545                                   FileName was NULL.
546 
547 **/
548 EFI_STATUS
549 EFIAPI
FfsFindFileByName(IN CONST EFI_GUID * FileName,IN EFI_PEI_FV_HANDLE VolumeHandle,OUT EFI_PEI_FILE_HANDLE * FileHandle)550 FfsFindFileByName (
551   IN  CONST EFI_GUID        *FileName,
552   IN  EFI_PEI_FV_HANDLE     VolumeHandle,
553   OUT EFI_PEI_FILE_HANDLE   *FileHandle
554   )
555 {
556   EFI_STATUS  Status;
557   if ((VolumeHandle == NULL) || (FileName == NULL) || (FileHandle == NULL)) {
558     return EFI_INVALID_PARAMETER;
559   }
560   Status = FindFileEx (VolumeHandle, FileName, 0, FileHandle);
561   if (Status == EFI_NOT_FOUND) {
562     *FileHandle = NULL;
563   }
564   return Status;
565 }
566 
567 
568 
569 
570 /**
571   Get information about the file by name.
572 
573   @param FileHandle   Handle of the file.
574 
575   @param FileInfo     Upon exit, points to the file's
576                       information.
577 
578   @retval EFI_SUCCESS             File information returned.
579 
580   @retval EFI_INVALID_PARAMETER   If FileHandle does not
581                                   represent a valid file.
582 
583   @retval EFI_INVALID_PARAMETER   If FileInfo is NULL.
584 
585 **/
586 EFI_STATUS
587 EFIAPI
FfsGetFileInfo(IN EFI_PEI_FILE_HANDLE FileHandle,OUT EFI_FV_FILE_INFO * FileInfo)588 FfsGetFileInfo (
589   IN EFI_PEI_FILE_HANDLE  FileHandle,
590   OUT EFI_FV_FILE_INFO    *FileInfo
591   )
592 {
593   UINT8                       FileState;
594   UINT8                       ErasePolarity;
595   EFI_FFS_FILE_HEADER         *FileHeader;
596   EFI_PEI_FV_HANDLE           VolumeHandle;
597 
598   if ((FileHandle == NULL) || (FileInfo == NULL)) {
599     return EFI_INVALID_PARAMETER;
600   }
601 
602   VolumeHandle = 0;
603   //
604   // Retrieve the FirmwareVolume which the file resides in.
605   //
606   if (!FileHandleToVolume(FileHandle, &VolumeHandle)) {
607     return EFI_INVALID_PARAMETER;
608   }
609 
610   if (((EFI_FIRMWARE_VOLUME_HEADER*)VolumeHandle)->Attributes & EFI_FVB2_ERASE_POLARITY) {
611     ErasePolarity = 1;
612   } else {
613     ErasePolarity = 0;
614   }
615 
616   //
617   // Get FileState which is the highest bit of the State
618   //
619   FileState = GetFileState (ErasePolarity, (EFI_FFS_FILE_HEADER*)FileHandle);
620 
621   switch (FileState) {
622     case EFI_FILE_DATA_VALID:
623     case EFI_FILE_MARKED_FOR_UPDATE:
624       break;
625     default:
626       return EFI_INVALID_PARAMETER;
627     }
628 
629   FileHeader = (EFI_FFS_FILE_HEADER *)FileHandle;
630   CopyMem (&FileInfo->FileName, &FileHeader->Name, sizeof(EFI_GUID));
631   FileInfo->FileType = FileHeader->Type;
632   FileInfo->FileAttributes = FileHeader->Attributes;
633   FileInfo->BufferSize = ((*(UINT32 *)FileHeader->Size) & 0x00FFFFFF) -  sizeof (EFI_FFS_FILE_HEADER);
634   FileInfo->Buffer = (FileHeader + 1);
635   return EFI_SUCCESS;
636 }
637 
638 
639 /**
640   Get Information about the volume by name
641 
642   @param VolumeHandle   Handle of the volume.
643 
644   @param VolumeInfo     Upon exit, points to the volume's
645                         information.
646 
647   @retval EFI_SUCCESS             File information returned.
648 
649   @retval EFI_INVALID_PARAMETER   If FileHandle does not
650                                   represent a valid file.
651 
652   @retval EFI_INVALID_PARAMETER   If FileInfo is NULL.
653 
654 **/
655 EFI_STATUS
656 EFIAPI
FfsGetVolumeInfo(IN EFI_PEI_FV_HANDLE VolumeHandle,OUT EFI_FV_INFO * VolumeInfo)657 FfsGetVolumeInfo (
658   IN EFI_PEI_FV_HANDLE  VolumeHandle,
659   OUT EFI_FV_INFO       *VolumeInfo
660   )
661 {
662   EFI_FIRMWARE_VOLUME_HEADER             FwVolHeader;
663   EFI_FIRMWARE_VOLUME_EXT_HEADER         *FwVolExHeaderInfo;
664 
665   if (VolumeInfo == NULL) {
666     return EFI_INVALID_PARAMETER;
667   }
668 
669   //
670   // VolumeHandle may not align at 8 byte,
671   // but FvLength is UINT64 type, which requires FvHeader align at least 8 byte.
672   // So, Copy FvHeader into the local FvHeader structure.
673   //
674   CopyMem (&FwVolHeader, VolumeHandle, sizeof (EFI_FIRMWARE_VOLUME_HEADER));
675   //
676   // Check Fv Image Signature
677   //
678   if (FwVolHeader.Signature != EFI_FVH_SIGNATURE) {
679     return EFI_INVALID_PARAMETER;
680   }
681   VolumeInfo->FvAttributes = FwVolHeader.Attributes;
682   VolumeInfo->FvStart = (VOID *) VolumeHandle;
683   VolumeInfo->FvSize = FwVolHeader.FvLength;
684   CopyMem (&VolumeInfo->FvFormat, &FwVolHeader.FileSystemGuid, sizeof(EFI_GUID));
685 
686   if (FwVolHeader.ExtHeaderOffset != 0) {
687     FwVolExHeaderInfo = (EFI_FIRMWARE_VOLUME_EXT_HEADER*)(((UINT8 *)VolumeHandle) + FwVolHeader.ExtHeaderOffset);
688     CopyMem (&VolumeInfo->FvName, &FwVolExHeaderInfo->FvName, sizeof(EFI_GUID));
689   }
690   return EFI_SUCCESS;
691 }
692 
693 
694 
695 /**
696   Search through every FV until you find a file of type FileType
697 
698   @param FileType        File handle of a Fv type file.
699   @param Volumehandle    On succes Volume Handle of the match
700   @param FileHandle      On success File Handle of the match
701 
702   @retval EFI_NOT_FOUND  FV image can't be found.
703   @retval EFI_SUCCESS    Successfully found FileType
704 
705 **/
706 EFI_STATUS
707 EFIAPI
FfsAnyFvFindFirstFile(IN EFI_FV_FILETYPE FileType,OUT EFI_PEI_FV_HANDLE * VolumeHandle,OUT EFI_PEI_FILE_HANDLE * FileHandle)708 FfsAnyFvFindFirstFile (
709   IN  EFI_FV_FILETYPE       FileType,
710   OUT EFI_PEI_FV_HANDLE     *VolumeHandle,
711   OUT EFI_PEI_FILE_HANDLE   *FileHandle
712   )
713 {
714   EFI_STATUS        Status;
715   UINTN             Instance;
716 
717   //
718   // Search every FV for the DXE Core
719   //
720   Instance    = 0;
721   *FileHandle = NULL;
722 
723   while (1)
724   {
725     Status = FfsFindNextVolume (Instance++, VolumeHandle);
726     if (EFI_ERROR (Status))
727     {
728       break;
729     }
730 
731     Status = FfsFindNextFile (FileType, *VolumeHandle, FileHandle);
732     if (!EFI_ERROR (Status))
733     {
734       break;
735     }
736   }
737 
738   return Status;
739 }
740 
741 
742 
743 /**
744   Get Fv image from the FV type file, then add FV & FV2 Hob.
745 
746   @param FileHandle  File handle of a Fv type file.
747 
748 
749   @retval EFI_NOT_FOUND  FV image can't be found.
750   @retval EFI_SUCCESS    Successfully to process it.
751 
752 **/
753 EFI_STATUS
754 EFIAPI
FfsProcessFvFile(IN EFI_PEI_FILE_HANDLE FvFileHandle)755 FfsProcessFvFile (
756   IN  EFI_PEI_FILE_HANDLE   FvFileHandle
757   )
758 {
759   EFI_STATUS            Status;
760   EFI_PEI_FV_HANDLE     FvImageHandle;
761   EFI_FV_INFO           FvImageInfo;
762   UINT32                FvAlignment;
763   VOID                  *FvBuffer;
764   EFI_PEI_HOB_POINTERS  HobFv2;
765 
766   FvBuffer             = NULL;
767 
768 
769   //
770   // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has already
771   // been extracted.
772   //
773   HobFv2.Raw = GetHobList ();
774   while ((HobFv2.Raw = GetNextHob (EFI_HOB_TYPE_FV2, HobFv2.Raw)) != NULL) {
775     if (CompareGuid (&(((EFI_FFS_FILE_HEADER *)FvFileHandle)->Name), &HobFv2.FirmwareVolume2->FileName)) {
776       //
777       // this FILE has been dispatched, it will not be dispatched again.
778       //
779       return EFI_SUCCESS;
780     }
781     HobFv2.Raw = GET_NEXT_HOB (HobFv2);
782   }
783 
784   //
785   // Find FvImage in FvFile
786   //
787   Status = FfsFindSectionData (EFI_SECTION_FIRMWARE_VOLUME_IMAGE, FvFileHandle, (VOID **)&FvImageHandle);
788   if (EFI_ERROR (Status)) {
789     return Status;
790   }
791 
792   //
793   // Collect FvImage Info.
794   //
795   ZeroMem (&FvImageInfo, sizeof (FvImageInfo));
796   Status = FfsGetVolumeInfo (FvImageHandle, &FvImageInfo);
797   ASSERT_EFI_ERROR (Status);
798 
799   //
800   // FvAlignment must be more than 8 bytes required by FvHeader structure.
801   //
802   FvAlignment = 1 << ((FvImageInfo.FvAttributes & EFI_FVB2_ALIGNMENT) >> 16);
803   if (FvAlignment < 8) {
804     FvAlignment = 8;
805   }
806 
807   //
808   // Check FvImage
809   //
810   if ((UINTN) FvImageInfo.FvStart % FvAlignment != 0) {
811     FvBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES ((UINT32) FvImageInfo.FvSize), FvAlignment);
812     if (FvBuffer == NULL) {
813       return EFI_OUT_OF_RESOURCES;
814     }
815     CopyMem (FvBuffer, FvImageInfo.FvStart, (UINTN) FvImageInfo.FvSize);
816     //
817     // Update FvImageInfo after reload FvImage to new aligned memory
818     //
819     FfsGetVolumeInfo ((EFI_PEI_FV_HANDLE) FvBuffer, &FvImageInfo);
820   }
821 
822 
823   //
824   // Inform HOB consumer phase, i.e. DXE core, the existance of this FV
825   //
826   BuildFvHob ((EFI_PHYSICAL_ADDRESS) (UINTN) FvImageInfo.FvStart, FvImageInfo.FvSize);
827 
828   //
829   // Makes the encapsulated volume show up in DXE phase to skip processing of
830   // encapsulated file again.
831   //
832   BuildFv2Hob (
833     (EFI_PHYSICAL_ADDRESS) (UINTN) FvImageInfo.FvStart,
834     FvImageInfo.FvSize,
835     &FvImageInfo.FvName,
836     &(((EFI_FFS_FILE_HEADER *)FvFileHandle)->Name)
837     );
838 
839   return EFI_SUCCESS;
840 }
841 
842 
843