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