2 These functions assist in parsing and manipulating a Firmware Volume.
4 Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
13 #include "CommonLib.h"
14 #include "EfiUtilityMsgs.h"
17 // Module global variables
19 EFI_FIRMWARE_VOLUME_HEADER
*mFvHeader
= NULL
;
23 // External function implementations
34 This initializes the FV lib with a pointer to the FV and length. It does not
35 verify the FV in any way.
39 Fv Buffer containing the FV.
40 FvLength Length of the FV
44 EFI_SUCCESS Function Completed successfully.
45 EFI_INVALID_PARAMETER A required parameter was NULL.
50 // Verify input arguments
53 return EFI_INVALID_PARAMETER
;
56 mFvHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) Fv
;
64 OUT EFI_FIRMWARE_VOLUME_HEADER
**FvHeader
,
71 This function returns a pointer to the current FV and the size.
75 FvHeader Pointer to the FV buffer.
76 FvLength Length of the FV
80 EFI_SUCCESS Function Completed successfully.
81 EFI_INVALID_PARAMETER A required parameter was NULL.
82 EFI_ABORTED The library needs to be initialized.
87 // Verify library has been initialized.
89 if (mFvHeader
== NULL
|| mFvLength
== 0) {
93 // Verify input arguments
95 if (FvHeader
== NULL
) {
96 return EFI_INVALID_PARAMETER
;
99 *FvHeader
= mFvHeader
;
100 *FvLength
= mFvLength
;
106 IN EFI_FFS_FILE_HEADER
*CurrentFile
,
107 OUT EFI_FFS_FILE_HEADER
**NextFile
113 This function returns the next file. If the current file is NULL, it returns
114 the first file in the FV. If the function returns EFI_SUCCESS and the file
115 pointer is NULL, then there are no more files in the FV.
119 CurrentFile Pointer to the current file, must be within the current FV.
120 NextFile Pointer to the next file in the FV.
124 EFI_SUCCESS Function completed successfully.
125 EFI_INVALID_PARAMETER A required parameter was NULL or is out of range.
126 EFI_ABORTED The library needs to be initialized.
133 // Verify library has been initialized.
135 if (mFvHeader
== NULL
|| mFvLength
== 0) {
139 // Verify input arguments
141 if (NextFile
== NULL
) {
142 return EFI_INVALID_PARAMETER
;
147 Status
= VerifyFv (mFvHeader
);
148 if (EFI_ERROR (Status
)) {
154 if (CurrentFile
== NULL
) {
155 CurrentFile
= (EFI_FFS_FILE_HEADER
*) ((UINTN
) mFvHeader
+ mFvHeader
->HeaderLength
);
158 // Verify file is valid
160 Status
= VerifyFfsFile (CurrentFile
);
161 if (EFI_ERROR (Status
)) {
163 // no files in this FV
169 // Verify file is in this FV.
171 if ((UINTN
) CurrentFile
+ GetFfsFileLength(CurrentFile
) > (UINTN
) mFvHeader
+ mFvLength
) {
176 *NextFile
= CurrentFile
;
181 // Verify current file is in range
183 if (((UINTN
) CurrentFile
< (UINTN
) mFvHeader
+ mFvHeader
->HeaderLength
) ||
184 ((UINTN
) CurrentFile
+ GetFfsFileLength(CurrentFile
) > (UINTN
) mFvHeader
+ mFvLength
)
186 return EFI_INVALID_PARAMETER
;
189 // Get next file, compensate for 8 byte alignment if necessary.
191 *NextFile
= (EFI_FFS_FILE_HEADER
*) ((((UINTN
) CurrentFile
- (UINTN
) mFvHeader
+ GetFfsFileLength(CurrentFile
) + 0x07) & (~(UINTN
) 7)) + (UINT8
*) mFvHeader
);
194 // Verify file is in this FV.
196 if (((UINTN
) *NextFile
+ GetFfsHeaderLength(*NextFile
) >= (UINTN
) mFvHeader
+ mFvLength
) ||
197 ((UINTN
) *NextFile
+ GetFfsFileLength (*NextFile
) > (UINTN
) mFvHeader
+ mFvLength
)
203 // Verify file is valid
205 Status
= VerifyFfsFile (*NextFile
);
206 if (EFI_ERROR (Status
)) {
208 // no more files in this FV
219 IN EFI_GUID
*FileName
,
220 OUT EFI_FFS_FILE_HEADER
**File
226 Find a file by name. The function will return NULL if the file is not found.
230 FileName The GUID file name of the file to search for.
231 File Return pointer. In the case of an error, contents are undefined.
235 EFI_SUCCESS The function completed successfully.
236 EFI_ABORTED An error was encountered.
237 EFI_INVALID_PARAMETER One of the parameters was NULL.
241 EFI_FFS_FILE_HEADER
*CurrentFile
;
243 CHAR8 FileGuidString
[80];
246 // Verify library has been initialized.
248 if (mFvHeader
== NULL
|| mFvLength
== 0) {
252 // Verify input parameters
254 if (FileName
== NULL
|| File
== NULL
) {
255 return EFI_INVALID_PARAMETER
;
258 // File Guid String Name
260 PrintGuidToBuffer (FileName
, (UINT8
*)FileGuidString
, sizeof (FileGuidString
), TRUE
);
264 Status
= VerifyFv (mFvHeader
);
265 if (EFI_ERROR (Status
)) {
269 // Get the first file
271 Status
= GetNextFile (NULL
, &CurrentFile
);
272 if (EFI_ERROR (Status
)) {
273 Error (NULL
, 0, 0003, "error parsing FV image", "FFS file with Guid %s can't be found", FileGuidString
);
277 // Loop as long as we have a valid file
279 while (CurrentFile
) {
280 if (!CompareGuid (&CurrentFile
->Name
, FileName
)) {
285 Status
= GetNextFile (CurrentFile
, &CurrentFile
);
286 if (EFI_ERROR (Status
)) {
287 Error (NULL
, 0, 0003, "error parsing FV image", "FFS file with Guid %s can't be found", FileGuidString
);
292 // File not found in this FV.
300 IN EFI_FV_FILETYPE FileType
,
302 OUT EFI_FFS_FILE_HEADER
**File
308 Find a file by type and instance. An instance of 1 is the first instance.
309 The function will return NULL if a matching file cannot be found.
310 File type EFI_FV_FILETYPE_ALL means any file type is valid.
314 FileType Type of file to search for.
315 Instance Instance of the file type to return.
316 File Return pointer. In the case of an error, contents are undefined.
320 EFI_SUCCESS The function completed successfully.
321 EFI_ABORTED An error was encountered.
322 EFI_INVALID_PARAMETER One of the parameters was NULL.
326 EFI_FFS_FILE_HEADER
*CurrentFile
;
331 // Verify library has been initialized.
333 if (mFvHeader
== NULL
|| mFvLength
== 0) {
337 // Verify input parameters
340 return EFI_INVALID_PARAMETER
;
345 Status
= VerifyFv (mFvHeader
);
346 if (EFI_ERROR (Status
)) {
350 // Initialize the number of matching files found.
355 // Get the first file
357 Status
= GetNextFile (NULL
, &CurrentFile
);
358 if (EFI_ERROR (Status
)) {
359 Error (NULL
, 0, 0003, "error parsing FV image", "FFS file with FileType 0x%x can't be found", FileType
);
363 // Loop as long as we have a valid file
365 while (CurrentFile
) {
366 if (FileType
== EFI_FV_FILETYPE_ALL
|| CurrentFile
->Type
== FileType
) {
370 if (FileCount
== Instance
) {
375 Status
= GetNextFile (CurrentFile
, &CurrentFile
);
376 if (EFI_ERROR (Status
)) {
377 Error (NULL
, 0, 0003, "error parsing FV image", "FFS file with FileType 0x%x can't be found", FileType
);
387 SearchSectionByType (
388 IN EFI_FILE_SECTION_POINTER FirstSection
,
390 IN EFI_SECTION_TYPE SectionType
,
391 IN OUT UINTN
*StartIndex
,
393 OUT EFI_FILE_SECTION_POINTER
*Section
399 Helper function to search a sequence of sections from the section pointed
400 by FirstSection to SearchEnd for the Instance-th section of type SectionType.
401 The current counter is saved in StartIndex and when the section is found, it's
402 saved in Section. GUID-defined sections, if special processing is not required,
403 are searched recursively in a depth-first manner.
407 FirstSection The first section to start searching from.
408 SearchEnd The end address to stop search.
409 SectionType The type of section to search.
410 StartIndex The current counter is saved.
411 Instance The requested n-th section number.
412 Section The found section returned.
416 EFI_SUCCESS The function completed successfully.
417 EFI_NOT_FOUND The section is not found.
420 EFI_FILE_SECTION_POINTER CurrentSection
;
421 EFI_FILE_SECTION_POINTER InnerSection
;
425 UINT16 GuidDataOffset
;
429 CurrentSection
= FirstSection
;
431 while ((UINTN
) CurrentSection
.CommonHeader
< (UINTN
) SearchEnd
) {
432 if (CurrentSection
.CommonHeader
->Type
== SectionType
) {
436 if (*StartIndex
== Instance
) {
437 *Section
= CurrentSection
;
441 // If the requesting section is not GUID-defined and
442 // we find a GUID-defined section that doesn't need
443 // special processing, go ahead to search the requesting
444 // section inside the GUID-defined section.
446 if (CurrentSection
.CommonHeader
->Type
== EFI_SECTION_GUID_DEFINED
) {
447 if (GetLength(CurrentSection
.CommonHeader
->Size
) == 0xffffff) {
448 GuidSecAttr
= CurrentSection
.GuidDefinedSection2
->Attributes
;
449 GuidDataOffset
= CurrentSection
.GuidDefinedSection2
->DataOffset
;
451 GuidSecAttr
= CurrentSection
.GuidDefinedSection
->Attributes
;
452 GuidDataOffset
= CurrentSection
.GuidDefinedSection
->DataOffset
;
455 if (SectionType
!= EFI_SECTION_GUID_DEFINED
&&
456 CurrentSection
.CommonHeader
->Type
== EFI_SECTION_GUID_DEFINED
&&
457 !(GuidSecAttr
& EFI_GUIDED_SECTION_PROCESSING_REQUIRED
)) {
458 InnerSection
.CommonHeader
= (EFI_COMMON_SECTION_HEADER
*)
459 ((UINTN
) CurrentSection
.CommonHeader
+ GuidDataOffset
);
460 SectionSize
= GetSectionFileLength(CurrentSection
.CommonHeader
);
461 Status
= SearchSectionByType (
463 (UINT8
*) ((UINTN
) CurrentSection
.CommonHeader
+ SectionSize
),
469 if (!EFI_ERROR (Status
)) {
474 // Find next section (including compensating for alignment issues.
476 CurrentSection
.CommonHeader
= (EFI_COMMON_SECTION_HEADER
*) ((((UINTN
) CurrentSection
.CommonHeader
) + GetSectionFileLength(CurrentSection
.CommonHeader
) + 0x03) & (~(UINTN
) 3));
479 return EFI_NOT_FOUND
;
484 IN EFI_FFS_FILE_HEADER
*File
,
485 IN EFI_SECTION_TYPE SectionType
,
487 OUT EFI_FILE_SECTION_POINTER
*Section
493 Find a section in a file by type and instance. An instance of 1 is the first
494 instance. The function will return NULL if a matching section cannot be found.
495 GUID-defined sections, if special processing is not needed, are handled in a
500 File The file to search.
501 SectionType Type of file to search for.
502 Instance Instance of the section to return.
503 Section Return pointer. In the case of an error, contents are undefined.
507 EFI_SUCCESS The function completed successfully.
508 EFI_ABORTED An error was encountered.
509 EFI_INVALID_PARAMETER One of the parameters was NULL.
510 EFI_NOT_FOUND No found.
513 EFI_FILE_SECTION_POINTER CurrentSection
;
518 // Verify input parameters
520 if (File
== NULL
|| Instance
== 0) {
521 return EFI_INVALID_PARAMETER
;
526 Status
= VerifyFfsFile (File
);
527 if (EFI_ERROR (Status
)) {
528 Error (NULL
, 0, 0006, "invalid FFS file", NULL
);
532 // Initialize the number of matching sections found.
537 // Get the first section
539 CurrentSection
.CommonHeader
= (EFI_COMMON_SECTION_HEADER
*) ((UINTN
) File
+ GetFfsHeaderLength(File
));
542 // Depth-first manner to find section file.
544 Status
= SearchSectionByType (
546 (UINT8
*) ((UINTN
) File
+ GetFfsFileLength (File
)),
553 if (!EFI_ERROR (Status
)) {
559 (*Section
).Code16Section
= NULL
;
560 return EFI_NOT_FOUND
;
564 // will not parse compressed sections
568 IN EFI_FIRMWARE_VOLUME_HEADER
*FvHeader
574 Verify the current pointer points to a valid FV header.
578 FvHeader Pointer to an alleged FV file.
582 EFI_SUCCESS The FV header is valid.
583 EFI_VOLUME_CORRUPTED The FV header is not valid.
584 EFI_INVALID_PARAMETER A required parameter was NULL.
585 EFI_ABORTED Operation aborted.
592 // Verify input parameters
594 if (FvHeader
== NULL
) {
595 return EFI_INVALID_PARAMETER
;
598 if (FvHeader
->Signature
!= EFI_FVH_SIGNATURE
) {
599 Error (NULL
, 0, 0006, "invalid FV header signature", NULL
);
600 return EFI_VOLUME_CORRUPTED
;
603 // Verify header checksum
605 Checksum
= CalculateSum16 ((UINT16
*) FvHeader
, FvHeader
->HeaderLength
/ sizeof (UINT16
));
608 Error (NULL
, 0, 0006, "invalid FV header checksum", NULL
);
617 IN EFI_FFS_FILE_HEADER
*FfsHeader
623 Verify the current pointer points to a FFS file header.
627 FfsHeader Pointer to an alleged FFS file.
631 EFI_SUCCESS The Ffs header is valid.
632 EFI_NOT_FOUND This "file" is the beginning of free space.
633 EFI_VOLUME_CORRUPTED The Ffs header is not valid.
634 EFI_ABORTED The erase polarity is not known.
638 BOOLEAN ErasePolarity
;
640 EFI_FFS_FILE_HEADER2 BlankHeader
;
645 UINT8 FileGuidString
[80];
646 UINT32 FfsHeaderSize
;
649 // Verify library has been initialized.
651 if (mFvHeader
== NULL
|| mFvLength
== 0) {
657 Status
= VerifyFv (mFvHeader
);
658 if (EFI_ERROR (Status
)) {
662 // Get the erase polarity.
664 Status
= GetErasePolarity (&ErasePolarity
);
665 if (EFI_ERROR (Status
)) {
669 FfsHeaderSize
= GetFfsHeaderLength(FfsHeader
);
671 // Check if we have free space
674 memset (&BlankHeader
, -1, FfsHeaderSize
);
676 memset (&BlankHeader
, 0, FfsHeaderSize
);
679 if (memcmp (&BlankHeader
, FfsHeader
, FfsHeaderSize
) == 0) {
680 return EFI_NOT_FOUND
;
683 // Convert the GUID to a string so we can at least report which file
684 // if we find an error.
686 PrintGuidToBuffer (&FfsHeader
->Name
, FileGuidString
, sizeof (FileGuidString
), TRUE
);
688 // Verify file header checksum
690 SavedState
= FfsHeader
->State
;
691 FfsHeader
->State
= 0;
692 SavedChecksum
= FfsHeader
->IntegrityCheck
.Checksum
.File
;
693 FfsHeader
->IntegrityCheck
.Checksum
.File
= 0;
694 Checksum
= CalculateSum8 ((UINT8
*) FfsHeader
, FfsHeaderSize
);
695 FfsHeader
->State
= SavedState
;
696 FfsHeader
->IntegrityCheck
.Checksum
.File
= SavedChecksum
;
698 Error (NULL
, 0, 0006, "invalid FFS file header checksum", "Ffs file with Guid %s", FileGuidString
);
702 // Verify file checksum
704 if (FfsHeader
->Attributes
& FFS_ATTRIB_CHECKSUM
) {
706 // Verify file data checksum
708 FileLength
= GetFfsFileLength (FfsHeader
);
709 Checksum
= CalculateSum8 ((UINT8
*) ((UINT8
*)FfsHeader
+ FfsHeaderSize
), FileLength
- FfsHeaderSize
);
710 Checksum
= Checksum
+ FfsHeader
->IntegrityCheck
.Checksum
.File
;
712 Error (NULL
, 0, 0006, "invalid FFS file checksum", "Ffs file with Guid %s", FileGuidString
);
717 // File does not have a checksum
718 // Verify contents are 0xAA as spec'd
720 if (FfsHeader
->IntegrityCheck
.Checksum
.File
!= FFS_FIXED_CHECKSUM
) {
721 Error (NULL
, 0, 0006, "invalid fixed FFS file header checksum", "Ffs file with Guid %s", FileGuidString
);
731 IN EFI_FFS_FILE_HEADER
*FfsHeader
734 if (FfsHeader
== NULL
) {
737 if (FfsHeader
->Attributes
& FFS_ATTRIB_LARGE_FILE
) {
738 return sizeof(EFI_FFS_FILE_HEADER2
);
740 return sizeof(EFI_FFS_FILE_HEADER
);
744 GetSectionHeaderLength(
745 IN EFI_COMMON_SECTION_HEADER
*SectionHeader
748 if (SectionHeader
== NULL
) {
751 if (GetLength(SectionHeader
->Size
) == 0xffffff) {
752 return sizeof(EFI_COMMON_SECTION_HEADER2
);
754 return sizeof(EFI_COMMON_SECTION_HEADER
);
759 EFI_FFS_FILE_HEADER
*FfsHeader
765 Get FFS file length including FFS header.
769 FfsHeader Pointer to EFI_FFS_FILE_HEADER.
773 UINT32 Length of FFS file header.
777 if (FfsHeader
== NULL
) {
780 if (FfsHeader
->Attributes
& FFS_ATTRIB_LARGE_FILE
) {
781 return (UINT32
) ((EFI_FFS_FILE_HEADER2
*)FfsHeader
)->ExtendedSize
;
783 return GetLength(FfsHeader
->Size
);
788 GetSectionFileLength (
789 EFI_COMMON_SECTION_HEADER
*SectionHeader
793 if (SectionHeader
== NULL
) {
796 Length
= GetLength(SectionHeader
->Size
);
797 if (Length
== 0xffffff) {
798 Length
= ((EFI_COMMON_SECTION_HEADER2
*)SectionHeader
)->ExtendedSize
;
805 UINT8
*ThreeByteLength
811 Converts a three byte length value into a UINT32.
815 ThreeByteLength Pointer to the first of the 3 byte length.
819 UINT32 Size of the section
825 if (ThreeByteLength
== NULL
) {
829 Length
= *((UINT32
*) ThreeByteLength
);
830 Length
= Length
& 0x00FFFFFF;
837 OUT BOOLEAN
*ErasePolarity
843 This function returns with the FV erase polarity. If the erase polarity
844 for a bit is 1, the function return TRUE.
848 ErasePolarity A pointer to the erase polarity.
852 EFI_SUCCESS The function completed successfully.
853 EFI_INVALID_PARAMETER One of the input parameters was invalid.
854 EFI_ABORTED Operation aborted.
861 // Verify library has been initialized.
863 if (mFvHeader
== NULL
|| mFvLength
== 0) {
869 Status
= VerifyFv (mFvHeader
);
870 if (EFI_ERROR (Status
)) {
874 // Verify input parameters.
876 if (ErasePolarity
== NULL
) {
877 return EFI_INVALID_PARAMETER
;
880 if (mFvHeader
->Attributes
& EFI_FVB2_ERASE_POLARITY
) {
881 *ErasePolarity
= TRUE
;
883 *ErasePolarity
= FALSE
;
891 IN BOOLEAN ErasePolarity
,
892 IN EFI_FFS_FILE_HEADER
*FfsHeader
898 This function returns a the highest state bit in the FFS that is set.
899 It in no way validate the FFS file.
903 ErasePolarity The erase polarity for the file state bits.
904 FfsHeader Pointer to a FFS file.
908 UINT8 The hightest set state of the file.
915 FileState
= FfsHeader
->State
;
918 FileState
= (UINT8
)~FileState
;
922 while (HighestBit
!= 0 && (HighestBit
& FileState
) == 0) {