• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   // 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
FfsProcessSection(IN EFI_SECTION_TYPE SectionType,IN EFI_COMMON_SECTION_HEADER * Section,IN UINTN SectionSize,OUT VOID ** OutputBuffer)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
FfsFindSectionData(IN EFI_SECTION_TYPE SectionType,IN EFI_PEI_FILE_HANDLE FileHandle,OUT VOID ** SectionData)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
FfsFindNextFile(IN UINT8 SearchType,IN EFI_PEI_FV_HANDLE VolumeHandle,IN OUT EFI_PEI_FILE_HANDLE * FileHandle)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
FfsFindNextVolume(IN UINTN Instance,IN OUT EFI_PEI_FV_HANDLE * VolumeHandle)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
FfsFindFileByName(IN CONST EFI_GUID * FileName,IN EFI_PEI_FV_HANDLE VolumeHandle,OUT EFI_PEI_FILE_HANDLE * FileHandle)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
FfsGetFileInfo(IN EFI_PEI_FILE_HANDLE FileHandle,OUT EFI_FV_FILE_INFO * FileInfo)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
FfsGetVolumeInfo(IN EFI_PEI_FV_HANDLE VolumeHandle,OUT EFI_FV_INFO * VolumeInfo)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
FfsAnyFvFindFirstFile(IN EFI_FV_FILETYPE FileType,OUT EFI_PEI_FV_HANDLE * VolumeHandle,OUT EFI_PEI_FILE_HANDLE * FileHandle)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
FfsProcessFvFile(IN EFI_PEI_FILE_HANDLE FvFileHandle)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