mirror of
				https://git.proxmox.com/git/mirror_edk2
				synced 2025-10-31 20:43:59 +00:00 
			
		
		
		
	 d3bb711834
			
		
	
	
		d3bb711834
		
	
	
	
	
		
			
			clang 3.8 flags -Wshift-negative-value warning, which turns fatal due to use of -Werror. Fixes: https://github.com/tianocore/edk2/issues/49 Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Zenith432 <zenith432@users.sourceforge.net> Reviewed-by: Liming Gao <liming.gao@intel.com>
		
			
				
	
	
		
			934 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			934 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
| These functions assist in parsing and manipulating a Firmware Volume.
 | |
| 
 | |
| Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
 | |
| This program and the accompanying materials                          
 | |
| are licensed and made available under the terms and conditions of the BSD License         
 | |
| which accompanies this distribution.  The full text of the license may be found at        
 | |
| http://opensource.org/licenses/bsd-license.php                                            
 | |
|                                                                                           
 | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
 | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             
 | |
| 
 | |
| **/
 | |
| 
 | |
| //
 | |
| // Include files
 | |
| //
 | |
| #include "FvLib.h"
 | |
| #include "CommonLib.h"
 | |
| #include "EfiUtilityMsgs.h"
 | |
| 
 | |
| //
 | |
| // Module global variables
 | |
| //
 | |
| EFI_FIRMWARE_VOLUME_HEADER  *mFvHeader  = NULL;
 | |
| UINT32                      mFvLength   = 0;
 | |
| 
 | |
| //
 | |
| // External function implementations
 | |
| //
 | |
| EFI_STATUS
 | |
| InitializeFvLib (
 | |
|   IN VOID                         *Fv,
 | |
|   IN UINT32                       FvLength
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   This initializes the FV lib with a pointer to the FV and length.  It does not
 | |
|   verify the FV in any way.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   Fv            Buffer containing the FV.
 | |
|   FvLength      Length of the FV
 | |
|     
 | |
| Returns:
 | |
|  
 | |
|   EFI_SUCCESS             Function Completed successfully.
 | |
|   EFI_INVALID_PARAMETER   A required parameter was NULL.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   //
 | |
|   // Verify input arguments
 | |
|   //
 | |
|   if (Fv == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   mFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) Fv;
 | |
|   mFvLength = FvLength;
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| GetFvHeader (
 | |
|   OUT EFI_FIRMWARE_VOLUME_HEADER  **FvHeader,
 | |
|   OUT UINT32                      *FvLength
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   This function returns a pointer to the current FV and the size.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   FvHeader      Pointer to the FV buffer.
 | |
|   FvLength      Length of the FV
 | |
|     
 | |
| Returns:
 | |
|  
 | |
|   EFI_SUCCESS             Function Completed successfully.
 | |
|   EFI_INVALID_PARAMETER   A required parameter was NULL.
 | |
|   EFI_ABORTED             The library needs to be initialized.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   //
 | |
|   // Verify library has been initialized.
 | |
|   //
 | |
|   if (mFvHeader == NULL || mFvLength == 0) {
 | |
|     return EFI_ABORTED;
 | |
|   }
 | |
|   //
 | |
|   // Verify input arguments
 | |
|   //
 | |
|   if (FvHeader == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   *FvHeader = mFvHeader;
 | |
|   *FvLength = mFvLength;
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| GetNextFile (
 | |
|   IN EFI_FFS_FILE_HEADER          *CurrentFile,
 | |
|   OUT EFI_FFS_FILE_HEADER         **NextFile
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   This function returns the next file.  If the current file is NULL, it returns
 | |
|   the first file in the FV.  If the function returns EFI_SUCCESS and the file 
 | |
|   pointer is NULL, then there are no more files in the FV.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   CurrentFile   Pointer to the current file, must be within the current FV.
 | |
|   NextFile      Pointer to the next file in the FV.
 | |
|     
 | |
| Returns:
 | |
|  
 | |
|   EFI_SUCCESS             Function completed successfully.
 | |
|   EFI_INVALID_PARAMETER   A required parameter was NULL or is out of range.
 | |
|   EFI_ABORTED             The library needs to be initialized.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   //
 | |
|   // Verify library has been initialized.
 | |
|   //
 | |
|   if (mFvHeader == NULL || mFvLength == 0) {
 | |
|     return EFI_ABORTED;
 | |
|   }
 | |
|   //
 | |
|   // Verify input arguments
 | |
|   //
 | |
|   if (NextFile == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
|   //
 | |
|   // Verify FV header
 | |
|   //
 | |
|   Status = VerifyFv (mFvHeader);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return EFI_ABORTED;
 | |
|   }
 | |
|   //
 | |
|   // Get first file
 | |
|   //
 | |
|   if (CurrentFile == NULL) {
 | |
|     CurrentFile = (EFI_FFS_FILE_HEADER *) ((UINTN) mFvHeader + mFvHeader->HeaderLength);
 | |
| 
 | |
|     //
 | |
|     // Verify file is valid
 | |
|     //
 | |
|     Status = VerifyFfsFile (CurrentFile);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       //
 | |
|       // no files in this FV
 | |
|       //
 | |
|       *NextFile = NULL;
 | |
|       return EFI_SUCCESS;
 | |
|     } else {
 | |
|       //
 | |
|       // Verify file is in this FV.
 | |
|       //
 | |
|       if ((UINTN) CurrentFile + GetFfsFileLength(CurrentFile) > (UINTN) mFvHeader + mFvLength) {
 | |
|         *NextFile = NULL;
 | |
|         return EFI_SUCCESS;
 | |
|       }
 | |
| 
 | |
|       *NextFile = CurrentFile;
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
|   }
 | |
|   //
 | |
|   // Verify current file is in range
 | |
|   //
 | |
|   if (((UINTN) CurrentFile < (UINTN) mFvHeader + mFvHeader->HeaderLength) ||
 | |
|       ((UINTN) CurrentFile + GetFfsFileLength(CurrentFile) > (UINTN) mFvHeader + mFvLength)
 | |
|      ) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
|   //
 | |
|   // Get next file, compensate for 8 byte alignment if necessary.
 | |
|   //
 | |
|   *NextFile = (EFI_FFS_FILE_HEADER *) ((((UINTN) CurrentFile - (UINTN) mFvHeader + GetFfsFileLength(CurrentFile) + 0x07) & (~(UINTN) 7)) + (UINT8 *) mFvHeader);
 | |
| 
 | |
|   //
 | |
|   // Verify file is in this FV.
 | |
|   //
 | |
|   if (((UINTN) *NextFile + GetFfsHeaderLength(*NextFile) >= (UINTN) mFvHeader + mFvLength) ||
 | |
|       ((UINTN) *NextFile + GetFfsFileLength (*NextFile) > (UINTN) mFvHeader + mFvLength)
 | |
|      ) {
 | |
|     *NextFile = NULL;
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
|   //
 | |
|   // Verify file is valid
 | |
|   //
 | |
|   Status = VerifyFfsFile (*NextFile);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     //
 | |
|     // no more files in this FV
 | |
|     //
 | |
|     *NextFile = NULL;
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| GetFileByName (
 | |
|   IN EFI_GUID                     *FileName,
 | |
|   OUT EFI_FFS_FILE_HEADER         **File
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Find a file by name.  The function will return NULL if the file is not found.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   FileName    The GUID file name of the file to search for.
 | |
|   File        Return pointer.  In the case of an error, contents are undefined.
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_SUCCESS             The function completed successfully.
 | |
|   EFI_ABORTED             An error was encountered.
 | |
|   EFI_INVALID_PARAMETER   One of the parameters was NULL.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_FFS_FILE_HEADER *CurrentFile;
 | |
|   EFI_STATUS          Status;
 | |
|   CHAR8               FileGuidString[80];
 | |
| 
 | |
|   //
 | |
|   // Verify library has been initialized.
 | |
|   //
 | |
|   if (mFvHeader == NULL || mFvLength == 0) {
 | |
|     return EFI_ABORTED;
 | |
|   }
 | |
|   //
 | |
|   // Verify input parameters
 | |
|   //
 | |
|   if (FileName == NULL || File == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
|   //
 | |
|   // File Guid String Name
 | |
|   //
 | |
|   PrintGuidToBuffer (FileName, (UINT8 *)FileGuidString, sizeof (FileGuidString), TRUE);
 | |
|   //
 | |
|   // Verify FV header
 | |
|   //
 | |
|   Status = VerifyFv (mFvHeader);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return EFI_ABORTED;
 | |
|   }
 | |
|   //
 | |
|   // Get the first file
 | |
|   //
 | |
|   Status = GetNextFile (NULL, &CurrentFile);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Error (NULL, 0, 0003, "error parsing FV image", "FFS file with Guid %s can't be found", FileGuidString);
 | |
|     return EFI_ABORTED;
 | |
|   }
 | |
|   //
 | |
|   // Loop as long as we have a valid file
 | |
|   //
 | |
|   while (CurrentFile) {
 | |
|     if (!CompareGuid (&CurrentFile->Name, FileName)) {
 | |
|       *File = CurrentFile;
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
| 
 | |
|     Status = GetNextFile (CurrentFile, &CurrentFile);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       Error (NULL, 0, 0003, "error parsing FV image", "FFS file with Guid %s can't be found", FileGuidString);
 | |
|       return EFI_ABORTED;
 | |
|     }
 | |
|   }
 | |
|   //
 | |
|   // File not found in this FV.
 | |
|   //
 | |
|   *File = NULL;
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| GetFileByType (
 | |
|   IN EFI_FV_FILETYPE              FileType,
 | |
|   IN UINTN                        Instance,
 | |
|   OUT EFI_FFS_FILE_HEADER         **File
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Find a file by type and instance.  An instance of 1 is the first instance.
 | |
|   The function will return NULL if a matching file cannot be found.
 | |
|   File type EFI_FV_FILETYPE_ALL means any file type is valid.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   FileType    Type of file to search for.
 | |
|   Instance    Instace of the file type to return.
 | |
|   File        Return pointer.  In the case of an error, contents are undefined.
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_SUCCESS             The function completed successfully.
 | |
|   EFI_ABORTED             An error was encountered.
 | |
|   EFI_INVALID_PARAMETER   One of the parameters was NULL.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_FFS_FILE_HEADER *CurrentFile;
 | |
|   EFI_STATUS          Status;
 | |
|   UINTN               FileCount;
 | |
| 
 | |
|   //
 | |
|   // Verify library has been initialized.
 | |
|   //
 | |
|   if (mFvHeader == NULL || mFvLength == 0) {
 | |
|     return EFI_ABORTED;
 | |
|   }
 | |
|   //
 | |
|   // Verify input parameters
 | |
|   //
 | |
|   if (File == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
|   //
 | |
|   // Verify FV header
 | |
|   //
 | |
|   Status = VerifyFv (mFvHeader);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return EFI_ABORTED;
 | |
|   }
 | |
|   //
 | |
|   // Initialize the number of matching files found.
 | |
|   //
 | |
|   FileCount = 0;
 | |
| 
 | |
|   //
 | |
|   // Get the first file
 | |
|   //
 | |
|   Status = GetNextFile (NULL, &CurrentFile);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Error (NULL, 0, 0003, "error parsing FV image", "FFS file with FileType 0x%x can't be found", FileType);
 | |
|     return EFI_ABORTED;
 | |
|   }
 | |
|   //
 | |
|   // Loop as long as we have a valid file
 | |
|   //
 | |
|   while (CurrentFile) {
 | |
|     if (FileType == EFI_FV_FILETYPE_ALL || CurrentFile->Type == FileType) {
 | |
|       FileCount++;
 | |
|     }
 | |
| 
 | |
|     if (FileCount == Instance) {
 | |
|       *File = CurrentFile;
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
| 
 | |
|     Status = GetNextFile (CurrentFile, &CurrentFile);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       Error (NULL, 0, 0003, "error parsing FV image", "FFS file with FileType 0x%x can't be found", FileType);
 | |
|       return EFI_ABORTED;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   *File = NULL;
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 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
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Helper function to search a sequence of sections from the section pointed
 | |
|   by FirstSection to SearchEnd for the Instance-th section of type SectionType.
 | |
|   The current counter is saved in StartIndex and when the section is found, it's
 | |
|   saved in Section. GUID-defined sections, if special processing is not required,
 | |
|   are searched recursively in a depth-first manner.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   FirstSection The first section to start searching from.
 | |
|   SearchEnd    The end address to stop search.
 | |
|   SectionType  The type of section to search.
 | |
|   StartIndex   The current counter is saved.
 | |
|   Instance     The requested n-th section number.
 | |
|   Section      The found section returned.
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_SUCCESS             The function completed successfully.
 | |
|   EFI_NOT_FOUND           The section is not found.
 | |
| --*/
 | |
| {
 | |
|   EFI_FILE_SECTION_POINTER  CurrentSection;
 | |
|   EFI_FILE_SECTION_POINTER  InnerSection;
 | |
|   EFI_STATUS                Status;
 | |
|   UINTN                     SectionSize;
 | |
|   UINT16                    GuidSecAttr;
 | |
|   UINT16                    GuidDataOffset;
 | |
| 
 | |
|   GuidSecAttr = 0;
 | |
|   GuidDataOffset = 0;
 | |
|   CurrentSection = FirstSection;
 | |
| 
 | |
|   while ((UINTN) CurrentSection.CommonHeader < (UINTN) SearchEnd) {
 | |
|     if (CurrentSection.CommonHeader->Type == SectionType) {
 | |
|       (*StartIndex)++;
 | |
|     }
 | |
| 
 | |
|     if (*StartIndex == Instance) {
 | |
|       *Section = CurrentSection;
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
|     //
 | |
|     // If the requesting section is not GUID-defined and
 | |
|     // we find a GUID-defined section that doesn't need
 | |
|     // special processing, go ahead to search the requesting
 | |
|     // section inside the GUID-defined section.
 | |
|     //
 | |
|     if (CurrentSection.CommonHeader->Type == EFI_SECTION_GUID_DEFINED) {
 | |
|       if (GetLength(CurrentSection.CommonHeader->Size) == 0xffffff) {
 | |
|         GuidSecAttr = CurrentSection.GuidDefinedSection2->Attributes;
 | |
|         GuidDataOffset = CurrentSection.GuidDefinedSection2->DataOffset;
 | |
|       } else {
 | |
|         GuidSecAttr = CurrentSection.GuidDefinedSection->Attributes;
 | |
|         GuidDataOffset = CurrentSection.GuidDefinedSection->DataOffset;
 | |
|       }
 | |
|     }
 | |
|     if (SectionType != EFI_SECTION_GUID_DEFINED &&
 | |
|         CurrentSection.CommonHeader->Type == EFI_SECTION_GUID_DEFINED &&
 | |
|         !(GuidSecAttr & EFI_GUIDED_SECTION_PROCESSING_REQUIRED)) {
 | |
|       InnerSection.CommonHeader = (EFI_COMMON_SECTION_HEADER *)
 | |
|         ((UINTN) CurrentSection.CommonHeader + GuidDataOffset);
 | |
|       SectionSize = GetSectionFileLength(CurrentSection.CommonHeader);
 | |
|       Status = SearchSectionByType (
 | |
|                  InnerSection,
 | |
|                  (UINT8 *) ((UINTN) CurrentSection.CommonHeader + SectionSize),
 | |
|                  SectionType,
 | |
|                  StartIndex,
 | |
|                  Instance,
 | |
|                  Section
 | |
|                  );
 | |
|       if (!EFI_ERROR (Status)) {
 | |
|         return EFI_SUCCESS;
 | |
|       }
 | |
|     }
 | |
|     //
 | |
|     // Find next section (including compensating for alignment issues.
 | |
|     //
 | |
|     CurrentSection.CommonHeader = (EFI_COMMON_SECTION_HEADER *) ((((UINTN) CurrentSection.CommonHeader) + GetSectionFileLength(CurrentSection.CommonHeader) + 0x03) & (~(UINTN) 3));
 | |
|   }
 | |
| 
 | |
|   return EFI_NOT_FOUND;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| GetSectionByType (
 | |
|   IN EFI_FFS_FILE_HEADER          *File,
 | |
|   IN EFI_SECTION_TYPE             SectionType,
 | |
|   IN UINTN                        Instance,
 | |
|   OUT EFI_FILE_SECTION_POINTER    *Section
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Find a section in a file by type and instance.  An instance of 1 is the first 
 | |
|   instance.  The function will return NULL if a matching section cannot be found.
 | |
|   GUID-defined sections, if special processing is not needed, are handled in a
 | |
|   depth-first manner.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   File        The file to search.
 | |
|   SectionType Type of file to search for.
 | |
|   Instance    Instace of the section to return.
 | |
|   Section     Return pointer.  In the case of an error, contents are undefined.
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_SUCCESS             The function completed successfully.
 | |
|   EFI_ABORTED             An error was encountered.
 | |
|   EFI_INVALID_PARAMETER   One of the parameters was NULL.
 | |
|   EFI_NOT_FOUND           No found.
 | |
| --*/
 | |
| {
 | |
|   EFI_FILE_SECTION_POINTER  CurrentSection;
 | |
|   EFI_STATUS                Status;
 | |
|   UINTN                     SectionCount;
 | |
| 
 | |
|   //
 | |
|   // Verify input parameters
 | |
|   //
 | |
|   if (File == NULL || Instance == 0) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
|   //
 | |
|   // Verify FFS header
 | |
|   //
 | |
|   Status = VerifyFfsFile (File);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Error (NULL, 0, 0006, "invalid FFS file", NULL);
 | |
|     return EFI_ABORTED;
 | |
|   }
 | |
|   //
 | |
|   // Initialize the number of matching sections found.
 | |
|   //
 | |
|   SectionCount = 0;
 | |
| 
 | |
|   //
 | |
|   // Get the first section
 | |
|   //
 | |
|   CurrentSection.CommonHeader = (EFI_COMMON_SECTION_HEADER *) ((UINTN) File + GetFfsHeaderLength(File));
 | |
|   
 | |
|   //
 | |
|   // Depth-first manner to find section file.
 | |
|   //
 | |
|   Status = SearchSectionByType (
 | |
|              CurrentSection,
 | |
|              (UINT8 *) ((UINTN) File + GetFfsFileLength (File)),
 | |
|              SectionType,
 | |
|              &SectionCount,
 | |
|              Instance,
 | |
|              Section
 | |
|              );
 | |
| 
 | |
|   if (!EFI_ERROR (Status)) {
 | |
|     return EFI_SUCCESS;
 | |
|   } else {
 | |
|     //
 | |
|     // Section not found
 | |
|     //
 | |
|     (*Section).Code16Section = NULL;
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| }
 | |
| //
 | |
| // will not parse compressed sections
 | |
| //
 | |
| EFI_STATUS
 | |
| VerifyFv (
 | |
|   IN EFI_FIRMWARE_VOLUME_HEADER   *FvHeader
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Verify the current pointer points to a valid FV header.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   FvHeader     Pointer to an alleged FV file.
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_SUCCESS             The FV header is valid.
 | |
|   EFI_VOLUME_CORRUPTED    The FV header is not valid.
 | |
|   EFI_INVALID_PARAMETER   A required parameter was NULL.
 | |
|   EFI_ABORTED             Operation aborted.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   UINT16  Checksum;
 | |
| 
 | |
|   //
 | |
|   // Verify input parameters
 | |
|   //
 | |
|   if (FvHeader == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if (FvHeader->Signature != EFI_FVH_SIGNATURE) {
 | |
|     Error (NULL, 0, 0006, "invalid FV header signature", NULL);
 | |
|     return EFI_VOLUME_CORRUPTED;
 | |
|   }
 | |
|   //
 | |
|   // Verify header checksum
 | |
|   //
 | |
|   Checksum = CalculateSum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16));
 | |
| 
 | |
|   if (Checksum != 0) {
 | |
|     Error (NULL, 0, 0006, "invalid FV header checksum", NULL);
 | |
|     return EFI_ABORTED;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| VerifyFfsFile (
 | |
|   IN EFI_FFS_FILE_HEADER  *FfsHeader
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Verify the current pointer points to a FFS file header.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   FfsHeader     Pointer to an alleged FFS file.
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_SUCCESS           The Ffs header is valid.
 | |
|   EFI_NOT_FOUND         This "file" is the beginning of free space.
 | |
|   EFI_VOLUME_CORRUPTED  The Ffs header is not valid.
 | |
|   EFI_ABORTED           The erase polarity is not known.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   BOOLEAN             ErasePolarity;
 | |
|   EFI_STATUS          Status;
 | |
|   EFI_FFS_FILE_HEADER2 BlankHeader;
 | |
|   UINT8               Checksum;
 | |
|   UINT32              FileLength;
 | |
|   UINT8               SavedChecksum;
 | |
|   UINT8               SavedState;
 | |
|   UINT8               FileGuidString[80];
 | |
|   UINT32              FfsHeaderSize;
 | |
| 
 | |
|   //
 | |
|   // Verify library has been initialized.
 | |
|   //
 | |
|   if (mFvHeader == NULL || mFvLength == 0) {
 | |
|     return EFI_ABORTED;
 | |
|   }
 | |
|   //
 | |
|   // Verify FV header
 | |
|   //
 | |
|   Status = VerifyFv (mFvHeader);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return EFI_ABORTED;
 | |
|   }
 | |
|   //
 | |
|   // Get the erase polarity.
 | |
|   //
 | |
|   Status = GetErasePolarity (&ErasePolarity);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return EFI_ABORTED;
 | |
|   }
 | |
| 
 | |
|   FfsHeaderSize = GetFfsHeaderLength(FfsHeader);
 | |
|   //
 | |
|   // Check if we have free space
 | |
|   //
 | |
|   if (ErasePolarity) {
 | |
|     memset (&BlankHeader, -1, FfsHeaderSize);
 | |
|   } else {
 | |
|     memset (&BlankHeader, 0, FfsHeaderSize);
 | |
|   }
 | |
| 
 | |
|   if (memcmp (&BlankHeader, FfsHeader, FfsHeaderSize) == 0) {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
|   //
 | |
|   // Convert the GUID to a string so we can at least report which file
 | |
|   // if we find an error.
 | |
|   //
 | |
|   PrintGuidToBuffer (&FfsHeader->Name, FileGuidString, sizeof (FileGuidString), TRUE);
 | |
|   //
 | |
|   // Verify file header checksum
 | |
|   //
 | |
|   SavedState = FfsHeader->State;
 | |
|   FfsHeader->State = 0;
 | |
|   SavedChecksum = FfsHeader->IntegrityCheck.Checksum.File;
 | |
|   FfsHeader->IntegrityCheck.Checksum.File = 0;
 | |
|   Checksum = CalculateSum8 ((UINT8 *) FfsHeader, FfsHeaderSize);
 | |
|   FfsHeader->State = SavedState;
 | |
|   FfsHeader->IntegrityCheck.Checksum.File = SavedChecksum;
 | |
|   if (Checksum != 0) {
 | |
|     Error (NULL, 0, 0006, "invalid FFS file header checksum", "Ffs file with Guid %s", FileGuidString);
 | |
|     return EFI_ABORTED;
 | |
|   }
 | |
|   //
 | |
|   // Verify file checksum
 | |
|   //
 | |
|   if (FfsHeader->Attributes & FFS_ATTRIB_CHECKSUM) {
 | |
|     //
 | |
|     // Verify file data checksum
 | |
|     //
 | |
|     FileLength          = GetFfsFileLength (FfsHeader);
 | |
|     Checksum            = CalculateSum8 ((UINT8 *) ((UINT8 *)FfsHeader + FfsHeaderSize), FileLength - FfsHeaderSize);
 | |
|     Checksum            = Checksum + FfsHeader->IntegrityCheck.Checksum.File;
 | |
|     if (Checksum != 0) {
 | |
|       Error (NULL, 0, 0006, "invalid FFS file checksum", "Ffs file with Guid %s", FileGuidString);
 | |
|       return EFI_ABORTED;
 | |
|     }
 | |
|   } else {
 | |
|     //
 | |
|     // File does not have a checksum
 | |
|     // Verify contents are 0xAA as spec'd
 | |
|     //
 | |
|     if (FfsHeader->IntegrityCheck.Checksum.File != FFS_FIXED_CHECKSUM) {
 | |
|       Error (NULL, 0, 0006, "invalid fixed FFS file header checksum", "Ffs file with Guid %s", FileGuidString);
 | |
|       return EFI_ABORTED;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| UINT32
 | |
| GetFfsHeaderLength(
 | |
|    IN EFI_FFS_FILE_HEADER *FfsHeader
 | |
|    )
 | |
| {
 | |
|   if (FfsHeader == NULL) {
 | |
|     return 0;
 | |
|   }
 | |
|   if (FfsHeader->Attributes & FFS_ATTRIB_LARGE_FILE) {
 | |
|     return sizeof(EFI_FFS_FILE_HEADER2);
 | |
|   }
 | |
|   return sizeof(EFI_FFS_FILE_HEADER);
 | |
| }
 | |
| 
 | |
| UINT32
 | |
| GetSectionHeaderLength(
 | |
|    IN EFI_COMMON_SECTION_HEADER *SectionHeader
 | |
|    )
 | |
| {
 | |
|   if (SectionHeader == NULL) {
 | |
|     return 0;
 | |
|   }
 | |
|   if (GetLength(SectionHeader->Size) == 0xffffff) {
 | |
|     return sizeof(EFI_COMMON_SECTION_HEADER2);
 | |
|   }
 | |
|   return sizeof(EFI_COMMON_SECTION_HEADER);
 | |
| }
 | |
| 
 | |
| UINT32
 | |
| GetFfsFileLength (
 | |
|   EFI_FFS_FILE_HEADER *FfsHeader
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Get FFS file length including FFS header.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   FfsHeader   Pointer to EFI_FFS_FILE_HEADER.
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   UINT32      Length of FFS file header.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   if (FfsHeader == NULL) {
 | |
|     return 0;
 | |
|   }
 | |
|   if (FfsHeader->Attributes & FFS_ATTRIB_LARGE_FILE) {
 | |
|     return (UINT32) ((EFI_FFS_FILE_HEADER2 *)FfsHeader)->ExtendedSize;
 | |
|   } else {
 | |
|     return GetLength(FfsHeader->Size);
 | |
|   }
 | |
| }
 | |
| 
 | |
| UINT32
 | |
| GetSectionFileLength (
 | |
|   EFI_COMMON_SECTION_HEADER *SectionHeader
 | |
|   )
 | |
| {
 | |
|   UINT32 Length;
 | |
|   if (SectionHeader == NULL) {
 | |
|     return 0;
 | |
|   }
 | |
|   Length = GetLength(SectionHeader->Size);
 | |
|   if (Length == 0xffffff) {
 | |
|     Length = ((EFI_COMMON_SECTION_HEADER2 *)SectionHeader)->ExtendedSize;
 | |
|   }
 | |
|   return Length;
 | |
| }
 | |
| 
 | |
| UINT32
 | |
| GetLength (
 | |
|   UINT8     *ThreeByteLength
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Converts a three byte length value into a UINT32.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   ThreeByteLength   Pointer to the first of the 3 byte length.
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   UINT32      Size of the section
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   UINT32  Length;
 | |
| 
 | |
|   if (ThreeByteLength == NULL) {
 | |
|     return 0;
 | |
|   }
 | |
| 
 | |
|   Length  = *((UINT32 *) ThreeByteLength);
 | |
|   Length  = Length & 0x00FFFFFF;
 | |
| 
 | |
|   return Length;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| GetErasePolarity (
 | |
|   OUT BOOLEAN   *ErasePolarity
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   This function returns with the FV erase polarity.  If the erase polarity
 | |
|   for a bit is 1, the function return TRUE.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   ErasePolarity   A pointer to the erase polarity.
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_SUCCESS              The function completed successfully.
 | |
|   EFI_INVALID_PARAMETER    One of the input parameters was invalid.
 | |
|   EFI_ABORTED              Operation aborted.
 | |
|   
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   //
 | |
|   // Verify library has been initialized.
 | |
|   //
 | |
|   if (mFvHeader == NULL || mFvLength == 0) {
 | |
|     return EFI_ABORTED;
 | |
|   }
 | |
|   //
 | |
|   // Verify FV header
 | |
|   //
 | |
|   Status = VerifyFv (mFvHeader);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return EFI_ABORTED;
 | |
|   }
 | |
|   //
 | |
|   // Verify input parameters.
 | |
|   //
 | |
|   if (ErasePolarity == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if (mFvHeader->Attributes & EFI_FVB2_ERASE_POLARITY) {
 | |
|     *ErasePolarity = TRUE;
 | |
|   } else {
 | |
|     *ErasePolarity = FALSE;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| UINT8
 | |
| GetFileState (
 | |
|   IN BOOLEAN              ErasePolarity,
 | |
|   IN EFI_FFS_FILE_HEADER  *FfsHeader
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   This function returns a the highest state bit in the FFS that is set.
 | |
|   It in no way validate the FFS file.
 | |
| 
 | |
| Arguments:
 | |
|   
 | |
|   ErasePolarity The erase polarity for the file state bits.
 | |
|   FfsHeader     Pointer to a FFS file.
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   UINT8   The hightest set state of the file.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   UINT8 FileState;
 | |
|   UINT8 HighestBit;
 | |
| 
 | |
|   FileState = FfsHeader->State;
 | |
| 
 | |
|   if (ErasePolarity) {
 | |
|     FileState = (UINT8)~FileState;
 | |
|   }
 | |
| 
 | |
|   HighestBit = 0x80;
 | |
|   while (HighestBit != 0 && (HighestBit & FileState) == 0) {
 | |
|     HighestBit >>= 1;
 | |
|   }
 | |
| 
 | |
|   return HighestBit;
 | |
| }
 |