1 /** @file
2 These functions assist in parsing and manipulating a Firmware Volume.
3 
4 Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution.  The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9 
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 
13 **/
14 
15 //
16 // Include files
17 //
18 #include "FvLib.h"
19 #include "CommonLib.h"
20 #include "EfiUtilityMsgs.h"
21 
22 //
23 // Module global variables
24 //
25 EFI_FIRMWARE_VOLUME_HEADER  *mFvHeader  = NULL;
26 UINT32                      mFvLength   = 0;
27 
28 //
29 // External function implementations
30 //
31 EFI_STATUS
InitializeFvLib(IN VOID * Fv,IN UINT32 FvLength)32 InitializeFvLib (
33   IN VOID                         *Fv,
34   IN UINT32                       FvLength
35   )
36 /*++
37 
38 Routine Description:
39 
40   This initializes the FV lib with a pointer to the FV and length.  It does not
41   verify the FV in any way.
42 
43 Arguments:
44 
45   Fv            Buffer containing the FV.
46   FvLength      Length of the FV
47 
48 Returns:
49 
50   EFI_SUCCESS             Function Completed successfully.
51   EFI_INVALID_PARAMETER   A required parameter was NULL.
52 
53 --*/
54 {
55   //
56   // Verify input arguments
57   //
58   if (Fv == NULL) {
59     return EFI_INVALID_PARAMETER;
60   }
61 
62   mFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) Fv;
63   mFvLength = FvLength;
64 
65   return EFI_SUCCESS;
66 }
67 
68 EFI_STATUS
GetFvHeader(OUT EFI_FIRMWARE_VOLUME_HEADER ** FvHeader,OUT UINT32 * FvLength)69 GetFvHeader (
70   OUT EFI_FIRMWARE_VOLUME_HEADER  **FvHeader,
71   OUT UINT32                      *FvLength
72   )
73 /*++
74 
75 Routine Description:
76 
77   This function returns a pointer to the current FV and the size.
78 
79 Arguments:
80 
81   FvHeader      Pointer to the FV buffer.
82   FvLength      Length of the FV
83 
84 Returns:
85 
86   EFI_SUCCESS             Function Completed successfully.
87   EFI_INVALID_PARAMETER   A required parameter was NULL.
88   EFI_ABORTED             The library needs to be initialized.
89 
90 --*/
91 {
92   //
93   // Verify library has been initialized.
94   //
95   if (mFvHeader == NULL || mFvLength == 0) {
96     return EFI_ABORTED;
97   }
98   //
99   // Verify input arguments
100   //
101   if (FvHeader == NULL) {
102     return EFI_INVALID_PARAMETER;
103   }
104 
105   *FvHeader = mFvHeader;
106   *FvLength = mFvLength;
107   return EFI_SUCCESS;
108 }
109 
110 EFI_STATUS
GetNextFile(IN EFI_FFS_FILE_HEADER * CurrentFile,OUT EFI_FFS_FILE_HEADER ** NextFile)111 GetNextFile (
112   IN EFI_FFS_FILE_HEADER          *CurrentFile,
113   OUT EFI_FFS_FILE_HEADER         **NextFile
114   )
115 /*++
116 
117 Routine Description:
118 
119   This function returns the next file.  If the current file is NULL, it returns
120   the first file in the FV.  If the function returns EFI_SUCCESS and the file
121   pointer is NULL, then there are no more files in the FV.
122 
123 Arguments:
124 
125   CurrentFile   Pointer to the current file, must be within the current FV.
126   NextFile      Pointer to the next file in the FV.
127 
128 Returns:
129 
130   EFI_SUCCESS             Function completed successfully.
131   EFI_INVALID_PARAMETER   A required parameter was NULL or is out of range.
132   EFI_ABORTED             The library needs to be initialized.
133 
134 --*/
135 {
136   EFI_STATUS  Status;
137 
138   //
139   // Verify library has been initialized.
140   //
141   if (mFvHeader == NULL || mFvLength == 0) {
142     return EFI_ABORTED;
143   }
144   //
145   // Verify input arguments
146   //
147   if (NextFile == NULL) {
148     return EFI_INVALID_PARAMETER;
149   }
150   //
151   // Verify FV header
152   //
153   Status = VerifyFv (mFvHeader);
154   if (EFI_ERROR (Status)) {
155     return EFI_ABORTED;
156   }
157   //
158   // Get first file
159   //
160   if (CurrentFile == NULL) {
161     CurrentFile = (EFI_FFS_FILE_HEADER *) ((UINTN) mFvHeader + mFvHeader->HeaderLength);
162 
163     //
164     // Verify file is valid
165     //
166     Status = VerifyFfsFile (CurrentFile);
167     if (EFI_ERROR (Status)) {
168       //
169       // no files in this FV
170       //
171       *NextFile = NULL;
172       return EFI_SUCCESS;
173     } else {
174       //
175       // Verify file is in this FV.
176       //
177       if ((UINTN) CurrentFile + GetFfsFileLength(CurrentFile) > (UINTN) mFvHeader + mFvLength) {
178         *NextFile = NULL;
179         return EFI_SUCCESS;
180       }
181 
182       *NextFile = CurrentFile;
183       return EFI_SUCCESS;
184     }
185   }
186   //
187   // Verify current file is in range
188   //
189   if (((UINTN) CurrentFile < (UINTN) mFvHeader + mFvHeader->HeaderLength) ||
190       ((UINTN) CurrentFile + GetFfsFileLength(CurrentFile) > (UINTN) mFvHeader + mFvLength)
191      ) {
192     return EFI_INVALID_PARAMETER;
193   }
194   //
195   // Get next file, compensate for 8 byte alignment if necessary.
196   //
197   *NextFile = (EFI_FFS_FILE_HEADER *) ((((UINTN) CurrentFile - (UINTN) mFvHeader + GetFfsFileLength(CurrentFile) + 0x07) & (-1 << 3)) + (UINT8 *) mFvHeader);
198 
199   //
200   // Verify file is in this FV.
201   //
202   if (((UINTN) *NextFile + GetFfsHeaderLength(*NextFile) >= (UINTN) mFvHeader + mFvLength) ||
203       ((UINTN) *NextFile + GetFfsFileLength (*NextFile) > (UINTN) mFvHeader + mFvLength)
204      ) {
205     *NextFile = NULL;
206     return EFI_SUCCESS;
207   }
208   //
209   // Verify file is valid
210   //
211   Status = VerifyFfsFile (*NextFile);
212   if (EFI_ERROR (Status)) {
213     //
214     // no more files in this FV
215     //
216     *NextFile = NULL;
217     return EFI_SUCCESS;
218   }
219 
220   return EFI_SUCCESS;
221 }
222 
223 EFI_STATUS
GetFileByName(IN EFI_GUID * FileName,OUT EFI_FFS_FILE_HEADER ** File)224 GetFileByName (
225   IN EFI_GUID                     *FileName,
226   OUT EFI_FFS_FILE_HEADER         **File
227   )
228 /*++
229 
230 Routine Description:
231 
232   Find a file by name.  The function will return NULL if the file is not found.
233 
234 Arguments:
235 
236   FileName    The GUID file name of the file to search for.
237   File        Return pointer.  In the case of an error, contents are undefined.
238 
239 Returns:
240 
241   EFI_SUCCESS             The function completed successfully.
242   EFI_ABORTED             An error was encountered.
243   EFI_INVALID_PARAMETER   One of the parameters was NULL.
244 
245 --*/
246 {
247   EFI_FFS_FILE_HEADER *CurrentFile;
248   EFI_STATUS          Status;
249   CHAR8               FileGuidString[80];
250 
251   //
252   // Verify library has been initialized.
253   //
254   if (mFvHeader == NULL || mFvLength == 0) {
255     return EFI_ABORTED;
256   }
257   //
258   // Verify input parameters
259   //
260   if (FileName == NULL || File == NULL) {
261     return EFI_INVALID_PARAMETER;
262   }
263   //
264   // File Guid String Name
265   //
266   PrintGuidToBuffer (FileName, (UINT8 *)FileGuidString, sizeof (FileGuidString), TRUE);
267   //
268   // Verify FV header
269   //
270   Status = VerifyFv (mFvHeader);
271   if (EFI_ERROR (Status)) {
272     return EFI_ABORTED;
273   }
274   //
275   // Get the first file
276   //
277   Status = GetNextFile (NULL, &CurrentFile);
278   if (EFI_ERROR (Status)) {
279     Error (NULL, 0, 0003, "error parsing FV image", "FFS file with Guid %s can't be found", FileGuidString);
280     return EFI_ABORTED;
281   }
282   //
283   // Loop as long as we have a valid file
284   //
285   while (CurrentFile) {
286     if (!CompareGuid (&CurrentFile->Name, FileName)) {
287       *File = CurrentFile;
288       return EFI_SUCCESS;
289     }
290 
291     Status = GetNextFile (CurrentFile, &CurrentFile);
292     if (EFI_ERROR (Status)) {
293       Error (NULL, 0, 0003, "error parsing FV image", "FFS file with Guid %s can't be found", FileGuidString);
294       return EFI_ABORTED;
295     }
296   }
297   //
298   // File not found in this FV.
299   //
300   *File = NULL;
301   return EFI_SUCCESS;
302 }
303 
304 EFI_STATUS
GetFileByType(IN EFI_FV_FILETYPE FileType,IN UINTN Instance,OUT EFI_FFS_FILE_HEADER ** File)305 GetFileByType (
306   IN EFI_FV_FILETYPE              FileType,
307   IN UINTN                        Instance,
308   OUT EFI_FFS_FILE_HEADER         **File
309   )
310 /*++
311 
312 Routine Description:
313 
314   Find a file by type and instance.  An instance of 1 is the first instance.
315   The function will return NULL if a matching file cannot be found.
316   File type EFI_FV_FILETYPE_ALL means any file type is valid.
317 
318 Arguments:
319 
320   FileType    Type of file to search for.
321   Instance    Instace of the file type to return.
322   File        Return pointer.  In the case of an error, contents are undefined.
323 
324 Returns:
325 
326   EFI_SUCCESS             The function completed successfully.
327   EFI_ABORTED             An error was encountered.
328   EFI_INVALID_PARAMETER   One of the parameters was NULL.
329 
330 --*/
331 {
332   EFI_FFS_FILE_HEADER *CurrentFile;
333   EFI_STATUS          Status;
334   UINTN               FileCount;
335 
336   //
337   // Verify library has been initialized.
338   //
339   if (mFvHeader == NULL || mFvLength == 0) {
340     return EFI_ABORTED;
341   }
342   //
343   // Verify input parameters
344   //
345   if (File == NULL) {
346     return EFI_INVALID_PARAMETER;
347   }
348   //
349   // Verify FV header
350   //
351   Status = VerifyFv (mFvHeader);
352   if (EFI_ERROR (Status)) {
353     return EFI_ABORTED;
354   }
355   //
356   // Initialize the number of matching files found.
357   //
358   FileCount = 0;
359 
360   //
361   // Get the first file
362   //
363   Status = GetNextFile (NULL, &CurrentFile);
364   if (EFI_ERROR (Status)) {
365     Error (NULL, 0, 0003, "error parsing FV image", "FFS file with FileType 0x%x can't be found", FileType);
366     return EFI_ABORTED;
367   }
368   //
369   // Loop as long as we have a valid file
370   //
371   while (CurrentFile) {
372     if (FileType == EFI_FV_FILETYPE_ALL || CurrentFile->Type == FileType) {
373       FileCount++;
374     }
375 
376     if (FileCount == Instance) {
377       *File = CurrentFile;
378       return EFI_SUCCESS;
379     }
380 
381     Status = GetNextFile (CurrentFile, &CurrentFile);
382     if (EFI_ERROR (Status)) {
383       Error (NULL, 0, 0003, "error parsing FV image", "FFS file with FileType 0x%x can't be found", FileType);
384       return EFI_ABORTED;
385     }
386   }
387 
388   *File = NULL;
389   return EFI_SUCCESS;
390 }
391 
392 EFI_STATUS
SearchSectionByType(IN EFI_FILE_SECTION_POINTER FirstSection,IN UINT8 * SearchEnd,IN EFI_SECTION_TYPE SectionType,IN OUT UINTN * StartIndex,IN UINTN Instance,OUT EFI_FILE_SECTION_POINTER * Section)393 SearchSectionByType (
394   IN EFI_FILE_SECTION_POINTER  FirstSection,
395   IN UINT8                     *SearchEnd,
396   IN EFI_SECTION_TYPE          SectionType,
397   IN OUT UINTN                 *StartIndex,
398   IN UINTN                     Instance,
399   OUT EFI_FILE_SECTION_POINTER *Section
400   )
401 /*++
402 
403 Routine Description:
404 
405   Helper function to search a sequence of sections from the section pointed
406   by FirstSection to SearchEnd for the Instance-th section of type SectionType.
407   The current counter is saved in StartIndex and when the section is found, it's
408   saved in Section. GUID-defined sections, if special processing is not required,
409   are searched recursively in a depth-first manner.
410 
411 Arguments:
412 
413   FirstSection The first section to start searching from.
414   SearchEnd    The end address to stop search.
415   SectionType  The type of section to search.
416   StartIndex   The current counter is saved.
417   Instance     The requested n-th section number.
418   Section      The found section returned.
419 
420 Returns:
421 
422   EFI_SUCCESS             The function completed successfully.
423   EFI_NOT_FOUND           The section is not found.
424 --*/
425 {
426   EFI_FILE_SECTION_POINTER  CurrentSection;
427   EFI_FILE_SECTION_POINTER  InnerSection;
428   EFI_STATUS                Status;
429   UINTN                     SectionSize;
430   UINT16                    GuidSecAttr;
431   UINT16                    GuidDataOffset;
432 
433   GuidSecAttr = 0;
434   GuidDataOffset = 0;
435   CurrentSection = FirstSection;
436 
437   while ((UINTN) CurrentSection.CommonHeader < (UINTN) SearchEnd) {
438     if (CurrentSection.CommonHeader->Type == SectionType) {
439       (*StartIndex)++;
440     }
441 
442     if (*StartIndex == Instance) {
443       *Section = CurrentSection;
444       return EFI_SUCCESS;
445     }
446     //
447     // If the requesting section is not GUID-defined and
448     // we find a GUID-defined section that doesn't need
449     // special processing, go ahead to search the requesting
450     // section inside the GUID-defined section.
451     //
452     if (CurrentSection.CommonHeader->Type == EFI_SECTION_GUID_DEFINED) {
453       if (GetLength(CurrentSection.CommonHeader->Size) == 0xffffff) {
454         GuidSecAttr = CurrentSection.GuidDefinedSection2->Attributes;
455         GuidDataOffset = CurrentSection.GuidDefinedSection2->DataOffset;
456       } else {
457         GuidSecAttr = CurrentSection.GuidDefinedSection->Attributes;
458         GuidDataOffset = CurrentSection.GuidDefinedSection->DataOffset;
459       }
460     }
461     if (SectionType != EFI_SECTION_GUID_DEFINED &&
462         CurrentSection.CommonHeader->Type == EFI_SECTION_GUID_DEFINED &&
463         !(GuidSecAttr & EFI_GUIDED_SECTION_PROCESSING_REQUIRED)) {
464       InnerSection.CommonHeader = (EFI_COMMON_SECTION_HEADER *)
465         ((UINTN) CurrentSection.CommonHeader + GuidDataOffset);
466       SectionSize = GetSectionFileLength(CurrentSection.CommonHeader);
467       Status = SearchSectionByType (
468                  InnerSection,
469                  (UINT8 *) ((UINTN) CurrentSection.CommonHeader + SectionSize),
470                  SectionType,
471                  StartIndex,
472                  Instance,
473                  Section
474                  );
475       if (!EFI_ERROR (Status)) {
476         return EFI_SUCCESS;
477       }
478     }
479     //
480     // Find next section (including compensating for alignment issues.
481     //
482     CurrentSection.CommonHeader = (EFI_COMMON_SECTION_HEADER *) ((((UINTN) CurrentSection.CommonHeader) + GetSectionFileLength(CurrentSection.CommonHeader) + 0x03) & (-1 << 2));
483   }
484 
485   return EFI_NOT_FOUND;
486 }
487 
488 EFI_STATUS
GetSectionByType(IN EFI_FFS_FILE_HEADER * File,IN EFI_SECTION_TYPE SectionType,IN UINTN Instance,OUT EFI_FILE_SECTION_POINTER * Section)489 GetSectionByType (
490   IN EFI_FFS_FILE_HEADER          *File,
491   IN EFI_SECTION_TYPE             SectionType,
492   IN UINTN                        Instance,
493   OUT EFI_FILE_SECTION_POINTER    *Section
494   )
495 /*++
496 
497 Routine Description:
498 
499   Find a section in a file by type and instance.  An instance of 1 is the first
500   instance.  The function will return NULL if a matching section cannot be found.
501   GUID-defined sections, if special processing is not needed, are handled in a
502   depth-first manner.
503 
504 Arguments:
505 
506   File        The file to search.
507   SectionType Type of file to search for.
508   Instance    Instace of the section to return.
509   Section     Return pointer.  In the case of an error, contents are undefined.
510 
511 Returns:
512 
513   EFI_SUCCESS             The function completed successfully.
514   EFI_ABORTED             An error was encountered.
515   EFI_INVALID_PARAMETER   One of the parameters was NULL.
516   EFI_NOT_FOUND           No found.
517 --*/
518 {
519   EFI_FILE_SECTION_POINTER  CurrentSection;
520   EFI_STATUS                Status;
521   UINTN                     SectionCount;
522 
523   //
524   // Verify input parameters
525   //
526   if (File == NULL || Instance == 0) {
527     return EFI_INVALID_PARAMETER;
528   }
529   //
530   // Verify FFS header
531   //
532   Status = VerifyFfsFile (File);
533   if (EFI_ERROR (Status)) {
534     Error (NULL, 0, 0006, "invalid FFS file", NULL);
535     return EFI_ABORTED;
536   }
537   //
538   // Initialize the number of matching sections found.
539   //
540   SectionCount = 0;
541 
542   //
543   // Get the first section
544   //
545   CurrentSection.CommonHeader = (EFI_COMMON_SECTION_HEADER *) ((UINTN) File + GetFfsHeaderLength(File));
546 
547   //
548   // Depth-first manner to find section file.
549   //
550   Status = SearchSectionByType (
551              CurrentSection,
552              (UINT8 *) ((UINTN) File + GetFfsFileLength (File)),
553              SectionType,
554              &SectionCount,
555              Instance,
556              Section
557              );
558 
559   if (!EFI_ERROR (Status)) {
560     return EFI_SUCCESS;
561   } else {
562     //
563     // Section not found
564     //
565     (*Section).Code16Section = NULL;
566     return EFI_NOT_FOUND;
567   }
568 }
569 //
570 // will not parse compressed sections
571 //
572 EFI_STATUS
VerifyFv(IN EFI_FIRMWARE_VOLUME_HEADER * FvHeader)573 VerifyFv (
574   IN EFI_FIRMWARE_VOLUME_HEADER   *FvHeader
575   )
576 /*++
577 
578 Routine Description:
579 
580   Verify the current pointer points to a valid FV header.
581 
582 Arguments:
583 
584   FvHeader     Pointer to an alleged FV file.
585 
586 Returns:
587 
588   EFI_SUCCESS             The FV header is valid.
589   EFI_VOLUME_CORRUPTED    The FV header is not valid.
590   EFI_INVALID_PARAMETER   A required parameter was NULL.
591   EFI_ABORTED             Operation aborted.
592 
593 --*/
594 {
595   UINT16  Checksum;
596 
597   //
598   // Verify input parameters
599   //
600   if (FvHeader == NULL) {
601     return EFI_INVALID_PARAMETER;
602   }
603 
604   if (FvHeader->Signature != EFI_FVH_SIGNATURE) {
605     Error (NULL, 0, 0006, "invalid FV header signature", NULL);
606     return EFI_VOLUME_CORRUPTED;
607   }
608   //
609   // Verify header checksum
610   //
611   Checksum = CalculateSum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16));
612 
613   if (Checksum != 0) {
614     Error (NULL, 0, 0006, "invalid FV header checksum", NULL);
615     return EFI_ABORTED;
616   }
617 
618   return EFI_SUCCESS;
619 }
620 
621 EFI_STATUS
VerifyFfsFile(IN EFI_FFS_FILE_HEADER * FfsHeader)622 VerifyFfsFile (
623   IN EFI_FFS_FILE_HEADER  *FfsHeader
624   )
625 /*++
626 
627 Routine Description:
628 
629   Verify the current pointer points to a FFS file header.
630 
631 Arguments:
632 
633   FfsHeader     Pointer to an alleged FFS file.
634 
635 Returns:
636 
637   EFI_SUCCESS           The Ffs header is valid.
638   EFI_NOT_FOUND         This "file" is the beginning of free space.
639   EFI_VOLUME_CORRUPTED  The Ffs header is not valid.
640   EFI_ABORTED           The erase polarity is not known.
641 
642 --*/
643 {
644   BOOLEAN             ErasePolarity;
645   EFI_STATUS          Status;
646   EFI_FFS_FILE_HEADER2 BlankHeader;
647   UINT8               Checksum;
648   UINT32              FileLength;
649   UINT8               SavedChecksum;
650   UINT8               SavedState;
651   UINT8               FileGuidString[80];
652   UINT32              FfsHeaderSize;
653 
654   //
655   // Verify library has been initialized.
656   //
657   if (mFvHeader == NULL || mFvLength == 0) {
658     return EFI_ABORTED;
659   }
660   //
661   // Verify FV header
662   //
663   Status = VerifyFv (mFvHeader);
664   if (EFI_ERROR (Status)) {
665     return EFI_ABORTED;
666   }
667   //
668   // Get the erase polarity.
669   //
670   Status = GetErasePolarity (&ErasePolarity);
671   if (EFI_ERROR (Status)) {
672     return EFI_ABORTED;
673   }
674 
675   FfsHeaderSize = GetFfsHeaderLength(FfsHeader);
676   //
677   // Check if we have free space
678   //
679   if (ErasePolarity) {
680     memset (&BlankHeader, -1, FfsHeaderSize);
681   } else {
682     memset (&BlankHeader, 0, FfsHeaderSize);
683   }
684 
685   if (memcmp (&BlankHeader, FfsHeader, FfsHeaderSize) == 0) {
686     return EFI_NOT_FOUND;
687   }
688   //
689   // Convert the GUID to a string so we can at least report which file
690   // if we find an error.
691   //
692   PrintGuidToBuffer (&FfsHeader->Name, FileGuidString, sizeof (FileGuidString), TRUE);
693   //
694   // Verify file header checksum
695   //
696   SavedState = FfsHeader->State;
697   FfsHeader->State = 0;
698   SavedChecksum = FfsHeader->IntegrityCheck.Checksum.File;
699   FfsHeader->IntegrityCheck.Checksum.File = 0;
700   Checksum = CalculateSum8 ((UINT8 *) FfsHeader, FfsHeaderSize);
701   FfsHeader->State = SavedState;
702   FfsHeader->IntegrityCheck.Checksum.File = SavedChecksum;
703   if (Checksum != 0) {
704     Error (NULL, 0, 0006, "invalid FFS file header checksum", "Ffs file with Guid %s", FileGuidString);
705     return EFI_ABORTED;
706   }
707   //
708   // Verify file checksum
709   //
710   if (FfsHeader->Attributes & FFS_ATTRIB_CHECKSUM) {
711     //
712     // Verify file data checksum
713     //
714     FileLength          = GetFfsFileLength (FfsHeader);
715     Checksum            = CalculateSum8 ((UINT8 *) ((UINT8 *)FfsHeader + FfsHeaderSize), FileLength - FfsHeaderSize);
716     Checksum            = Checksum + FfsHeader->IntegrityCheck.Checksum.File;
717     if (Checksum != 0) {
718       Error (NULL, 0, 0006, "invalid FFS file checksum", "Ffs file with Guid %s", FileGuidString);
719       return EFI_ABORTED;
720     }
721   } else {
722     //
723     // File does not have a checksum
724     // Verify contents are 0xAA as spec'd
725     //
726     if (FfsHeader->IntegrityCheck.Checksum.File != FFS_FIXED_CHECKSUM) {
727       Error (NULL, 0, 0006, "invalid fixed FFS file header checksum", "Ffs file with Guid %s", FileGuidString);
728       return EFI_ABORTED;
729     }
730   }
731 
732   return EFI_SUCCESS;
733 }
734 
735 UINT32
GetFfsHeaderLength(IN EFI_FFS_FILE_HEADER * FfsHeader)736 GetFfsHeaderLength(
737    IN EFI_FFS_FILE_HEADER *FfsHeader
738    )
739 {
740   if (FfsHeader == NULL) {
741     return 0;
742   }
743   if (FfsHeader->Attributes & FFS_ATTRIB_LARGE_FILE) {
744     return sizeof(EFI_FFS_FILE_HEADER2);
745   }
746   return sizeof(EFI_FFS_FILE_HEADER);
747 }
748 
749 UINT32
GetSectionHeaderLength(IN EFI_COMMON_SECTION_HEADER * SectionHeader)750 GetSectionHeaderLength(
751    IN EFI_COMMON_SECTION_HEADER *SectionHeader
752    )
753 {
754   if (SectionHeader == NULL) {
755     return 0;
756   }
757   if (GetLength(SectionHeader->Size) == 0xffffff) {
758     return sizeof(EFI_COMMON_SECTION_HEADER2);
759   }
760   return sizeof(EFI_COMMON_SECTION_HEADER);
761 }
762 
763 UINT32
GetFfsFileLength(EFI_FFS_FILE_HEADER * FfsHeader)764 GetFfsFileLength (
765   EFI_FFS_FILE_HEADER *FfsHeader
766   )
767 /*++
768 
769 Routine Description:
770 
771   Get FFS file length including FFS header.
772 
773 Arguments:
774 
775   FfsHeader   Pointer to EFI_FFS_FILE_HEADER.
776 
777 Returns:
778 
779   UINT32      Length of FFS file header.
780 
781 --*/
782 {
783   if (FfsHeader == NULL) {
784     return 0;
785   }
786   if (FfsHeader->Attributes & FFS_ATTRIB_LARGE_FILE) {
787     return ((EFI_FFS_FILE_HEADER2 *)FfsHeader)->ExtendedSize;
788   } else {
789     return GetLength(FfsHeader->Size);
790   }
791 }
792 
793 UINT32
GetSectionFileLength(EFI_COMMON_SECTION_HEADER * SectionHeader)794 GetSectionFileLength (
795   EFI_COMMON_SECTION_HEADER *SectionHeader
796   )
797 {
798   UINT32 Length;
799   if (SectionHeader == NULL) {
800     return 0;
801   }
802   Length = GetLength(SectionHeader->Size);
803   if (Length == 0xffffff) {
804     Length = ((EFI_COMMON_SECTION_HEADER2 *)SectionHeader)->ExtendedSize;
805   }
806   return Length;
807 }
808 
809 UINT32
GetLength(UINT8 * ThreeByteLength)810 GetLength (
811   UINT8     *ThreeByteLength
812   )
813 /*++
814 
815 Routine Description:
816 
817   Converts a three byte length value into a UINT32.
818 
819 Arguments:
820 
821   ThreeByteLength   Pointer to the first of the 3 byte length.
822 
823 Returns:
824 
825   UINT32      Size of the section
826 
827 --*/
828 {
829   UINT32  Length;
830 
831   if (ThreeByteLength == NULL) {
832     return 0;
833   }
834 
835   Length  = *((UINT32 *) ThreeByteLength);
836   Length  = Length & 0x00FFFFFF;
837 
838   return Length;
839 }
840 
841 EFI_STATUS
GetErasePolarity(OUT BOOLEAN * ErasePolarity)842 GetErasePolarity (
843   OUT BOOLEAN   *ErasePolarity
844   )
845 /*++
846 
847 Routine Description:
848 
849   This function returns with the FV erase polarity.  If the erase polarity
850   for a bit is 1, the function return TRUE.
851 
852 Arguments:
853 
854   ErasePolarity   A pointer to the erase polarity.
855 
856 Returns:
857 
858   EFI_SUCCESS              The function completed successfully.
859   EFI_INVALID_PARAMETER    One of the input parameters was invalid.
860   EFI_ABORTED              Operation aborted.
861 
862 --*/
863 {
864   EFI_STATUS  Status;
865 
866   //
867   // Verify library has been initialized.
868   //
869   if (mFvHeader == NULL || mFvLength == 0) {
870     return EFI_ABORTED;
871   }
872   //
873   // Verify FV header
874   //
875   Status = VerifyFv (mFvHeader);
876   if (EFI_ERROR (Status)) {
877     return EFI_ABORTED;
878   }
879   //
880   // Verify input parameters.
881   //
882   if (ErasePolarity == NULL) {
883     return EFI_INVALID_PARAMETER;
884   }
885 
886   if (mFvHeader->Attributes & EFI_FVB2_ERASE_POLARITY) {
887     *ErasePolarity = TRUE;
888   } else {
889     *ErasePolarity = FALSE;
890   }
891 
892   return EFI_SUCCESS;
893 }
894 
895 UINT8
GetFileState(IN BOOLEAN ErasePolarity,IN EFI_FFS_FILE_HEADER * FfsHeader)896 GetFileState (
897   IN BOOLEAN              ErasePolarity,
898   IN EFI_FFS_FILE_HEADER  *FfsHeader
899   )
900 /*++
901 
902 Routine Description:
903 
904   This function returns a the highest state bit in the FFS that is set.
905   It in no way validate the FFS file.
906 
907 Arguments:
908 
909   ErasePolarity The erase polarity for the file state bits.
910   FfsHeader     Pointer to a FFS file.
911 
912 Returns:
913 
914   UINT8   The hightest set state of the file.
915 
916 --*/
917 {
918   UINT8 FileState;
919   UINT8 HighestBit;
920 
921   FileState = FfsHeader->State;
922 
923   if (ErasePolarity) {
924     FileState = (UINT8)~FileState;
925   }
926 
927   HighestBit = 0x80;
928   while (HighestBit != 0 && (HighestBit & FileState) == 0) {
929     HighestBit >>= 1;
930   }
931 
932   return HighestBit;
933 }
934