git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@9397 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			1668 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1668 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
| 
 | |
| Copyright (c) 1999 - 2008, Intel Corporation
 | |
| All rights reserved. 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.
 | |
| 
 | |
| Module Name:
 | |
| 
 | |
|   FirmwareVolumeBuffer.c
 | |
| 
 | |
| Abstract:
 | |
| 
 | |
|   EFI Firmware Volume routines which work on a Fv image in buffers.
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "FirmwareVolumeBufferLib.h"
 | |
| #include "BinderFuncs.h"
 | |
| 
 | |
| //
 | |
| // Local macros
 | |
| //
 | |
| #define EFI_TEST_FFS_ATTRIBUTES_BIT(FvbAttributes, TestAttributes, Bit) \
 | |
|     ( \
 | |
|       (BOOLEAN) ( \
 | |
|           (FvbAttributes & EFI_FVB2_ERASE_POLARITY) ? (((~TestAttributes) & Bit) == Bit) : ((TestAttributes & Bit) == Bit) \
 | |
|         ) \
 | |
|     )
 | |
| 
 | |
| 
 | |
| //
 | |
| // Local prototypes
 | |
| //
 | |
| 
 | |
| STATIC
 | |
| UINT16
 | |
| FvBufCalculateChecksum16 (
 | |
|   IN UINT16       *Buffer,
 | |
|   IN UINTN        Size
 | |
|   );
 | |
| 
 | |
| STATIC
 | |
| UINT8
 | |
| FvBufCalculateChecksum8 (
 | |
|   IN UINT8        *Buffer,
 | |
|   IN UINTN        Size
 | |
|   );
 | |
| 
 | |
| //
 | |
| // Procedures start
 | |
| //
 | |
| 
 | |
| EFI_STATUS
 | |
| FvBufRemoveFileNew (
 | |
|   IN OUT VOID *Fv,
 | |
|   IN EFI_GUID *Name
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Clears out all files from the Fv buffer in memory
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   SourceFv - Address of the Fv in memory, this firmware volume volume will
 | |
|              be modified, if SourceFfsFile exists
 | |
|   SourceFfsFile - Input FFS file to replace
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_SUCCESS
 | |
|   EFI_NOT_FOUND
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS                  Status;
 | |
|   EFI_FFS_FILE_HEADER*        FileToRm;
 | |
|   UINTN                       FileToRmLength;
 | |
| 
 | |
|   Status = FvBufFindFileByName(
 | |
|     Fv,
 | |
|     Name,
 | |
|     (VOID **)&FileToRm
 | |
|     );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   FileToRmLength = FvBufExpand3ByteSize (FileToRm->Size);
 | |
| 
 | |
|   CommonLibBinderSetMem (
 | |
|     FileToRm,
 | |
|     FileToRmLength,
 | |
|     (((EFI_FIRMWARE_VOLUME_HEADER*)Fv)->Attributes & EFI_FVB2_ERASE_POLARITY)
 | |
|       ? 0xFF : 0
 | |
|     );
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| EFI_STATUS
 | |
| FvBufRemoveFile (
 | |
|   IN OUT VOID *Fv,
 | |
|   IN EFI_GUID *Name
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Clears out all files from the Fv buffer in memory
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   SourceFv - Address of the Fv in memory, this firmware volume volume will
 | |
|              be modified, if SourceFfsFile exists
 | |
|   SourceFfsFile - Input FFS file to replace
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_SUCCESS
 | |
|   EFI_NOT_FOUND
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS                  Status;
 | |
|   EFI_FFS_FILE_HEADER        *NextFile;
 | |
|   EFI_FIRMWARE_VOLUME_HEADER *TempFv;
 | |
|   UINTN                       FileKey;
 | |
|   UINTN                       FvLength;
 | |
| 
 | |
|   Status = FvBufFindFileByName(
 | |
|     Fv,
 | |
|     Name,
 | |
|     NULL
 | |
|     );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   Status = FvBufGetSize (Fv, &FvLength);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   TempFv = NULL;
 | |
|   Status = FvBufDuplicate (Fv, (VOID **)&TempFv);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   Status = FvBufClearAllFiles (TempFv);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   // TempFv has been allocated.  It must now be freed
 | |
|   // before returning.
 | |
| 
 | |
|   FileKey = 0;
 | |
|   while (TRUE) {
 | |
| 
 | |
|     Status = FvBufFindNextFile (Fv, &FileKey, (VOID **)&NextFile);
 | |
|     if (Status == EFI_NOT_FOUND) {
 | |
|       break;
 | |
|     } else if (EFI_ERROR (Status)) {
 | |
|       CommonLibBinderFree (TempFv);
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     if (CommonLibBinderCompareGuid (Name, &NextFile->Name)) {
 | |
|       continue;
 | |
|     }
 | |
|     else {
 | |
|       Status = FvBufAddFile (TempFv, NextFile);
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         CommonLibBinderFree (TempFv);
 | |
|         return Status;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   CommonLibBinderCopyMem (Fv, TempFv, FvLength);
 | |
|   CommonLibBinderFree (TempFv);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| EFI_STATUS
 | |
| FvBufChecksumFile (
 | |
|   IN OUT VOID *FfsFile
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Clears out all files from the Fv buffer in memory
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   SourceFfsFile - Input FFS file to update the checksum for
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_SUCCESS
 | |
|   EFI_NOT_FOUND
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_FFS_FILE_HEADER* File = (EFI_FFS_FILE_HEADER*)FfsFile;
 | |
|   EFI_FFS_FILE_STATE StateBackup;
 | |
|   UINT32 FileSize;
 | |
| 
 | |
|   FileSize = FvBufExpand3ByteSize (File->Size);
 | |
| 
 | |
|   //
 | |
|   // Fill in checksums and state, they must be 0 for checksumming.
 | |
|   //
 | |
|   File->IntegrityCheck.Checksum.Header = 0;
 | |
|   File->IntegrityCheck.Checksum.File = 0;
 | |
|   StateBackup = File->State;
 | |
|   File->State = 0;
 | |
| 
 | |
|   File->IntegrityCheck.Checksum.Header =
 | |
|     FvBufCalculateChecksum8 (
 | |
|       (UINT8 *) File,
 | |
|       sizeof (EFI_FFS_FILE_HEADER)
 | |
|       );
 | |
| 
 | |
|   if (File->Attributes & FFS_ATTRIB_CHECKSUM) {
 | |
|     File->IntegrityCheck.Checksum.File = FvBufCalculateChecksum8 (
 | |
|                                                 (VOID*)(File + 1),
 | |
|                                                 FileSize - sizeof (EFI_FFS_FILE_HEADER)
 | |
|                                                 );
 | |
|   } else {
 | |
|     File->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;
 | |
|   }
 | |
| 
 | |
|   File->State = StateBackup;
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| EFI_STATUS
 | |
| FvBufChecksumHeader (
 | |
|   IN OUT VOID *Fv
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Clears out all files from the Fv buffer in memory
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   SourceFv - Address of the Fv in memory, this firmware volume volume will
 | |
|              be modified, if SourceFfsFile exists
 | |
|   SourceFfsFile - Input FFS file to replace
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_SUCCESS
 | |
|   EFI_NOT_FOUND
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_FIRMWARE_VOLUME_HEADER* FvHeader = (EFI_FIRMWARE_VOLUME_HEADER*)Fv;
 | |
| 
 | |
|   FvHeader->Checksum = 0;
 | |
|   FvHeader->Checksum =
 | |
|     FvBufCalculateChecksum16 (
 | |
|       (UINT16*) FvHeader,
 | |
|       FvHeader->HeaderLength / sizeof (UINT16)
 | |
|       );
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| EFI_STATUS
 | |
| FvBufDuplicate (
 | |
|   IN VOID *SourceFv,
 | |
|   IN OUT VOID **DestinationFv
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Clears out all files from the Fv buffer in memory
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   SourceFv - Address of the Fv in memory
 | |
|   DestinationFv - Output for destination Fv
 | |
|     DestinationFv == NULL - invalid parameter
 | |
|     *DestinationFv == NULL - memory will be allocated
 | |
|     *DestinationFv != NULL - this address will be the destination
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_SUCCESS
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS Status;
 | |
|   UINTN size;
 | |
| 
 | |
|   if (DestinationFv == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   Status = FvBufGetSize (SourceFv, &size);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   if (*DestinationFv == NULL) {
 | |
|     *DestinationFv = CommonLibBinderAllocate (size);
 | |
|   }
 | |
| 
 | |
|   CommonLibBinderCopyMem (*DestinationFv, SourceFv, size);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| EFI_STATUS
 | |
| FvBufExtend (
 | |
|   IN VOID **Fv,
 | |
|   IN UINTN Size
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Extends a firmware volume by the given number of bytes.
 | |
| 
 | |
|   BUGBUG: Does not handle the case where the firmware volume has a
 | |
|           VTF (Volume Top File).  The VTF will not be moved to the
 | |
|           end of the extended FV.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   Fv - Source and destination firmware volume.
 | |
|        Note: The original firmware volume buffer is freed!
 | |
| 
 | |
|   Size - The minimum size that the firmware volume is to be extended by.
 | |
|          The FV may be extended more than this size.
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_SUCCESS
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS Status;
 | |
|   UINTN OldSize;
 | |
|   UINTN NewSize;
 | |
|   UINTN BlockCount;
 | |
|   VOID* NewFv;
 | |
| 
 | |
|   EFI_FIRMWARE_VOLUME_HEADER* hdr;
 | |
|   EFI_FV_BLOCK_MAP_ENTRY*     blk;
 | |
| 
 | |
|   Status = FvBufGetSize (*Fv, &OldSize);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Locate the block map in the fv header
 | |
|   //
 | |
|   hdr = (EFI_FIRMWARE_VOLUME_HEADER*)*Fv;
 | |
|   blk = hdr->BlockMap;
 | |
| 
 | |
|   //
 | |
|   // Calculate the number of blocks needed to achieve the requested
 | |
|   // size extension
 | |
|   //
 | |
|   BlockCount = ((Size + (blk->Length - 1)) / blk->Length);
 | |
| 
 | |
|   //
 | |
|   // Calculate the new size from the number of blocks that will be added
 | |
|   //
 | |
|   NewSize = OldSize + (BlockCount * blk->Length);
 | |
| 
 | |
|   NewFv = CommonLibBinderAllocate (NewSize);
 | |
|   if (NewFv == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Copy the old data
 | |
|   //
 | |
|   CommonLibBinderCopyMem (NewFv, *Fv, OldSize);
 | |
| 
 | |
|   //
 | |
|   // Free the old fv buffer
 | |
|   //
 | |
|   CommonLibBinderFree (*Fv);
 | |
| 
 | |
|   //
 | |
|   // Locate the block map in the new fv header
 | |
|   //
 | |
|   hdr = (EFI_FIRMWARE_VOLUME_HEADER*)NewFv;
 | |
|   hdr->FvLength = NewSize;
 | |
|   blk = hdr->BlockMap;
 | |
| 
 | |
|   //
 | |
|   // Update the block map for the new fv
 | |
|   //
 | |
|   blk->NumBlocks += (UINT32)BlockCount;
 | |
| 
 | |
|   //
 | |
|   // Update the FV header checksum
 | |
|   //
 | |
|   FvBufChecksumHeader (NewFv);
 | |
| 
 | |
|   //
 | |
|   // Clear out the new area of the FV
 | |
|   //
 | |
|   CommonLibBinderSetMem (
 | |
|     (UINT8*)NewFv + OldSize,
 | |
|     (NewSize - OldSize),
 | |
|     (hdr->Attributes & EFI_FVB2_ERASE_POLARITY) ? 0xFF : 0
 | |
|     );
 | |
| 
 | |
|   //
 | |
|   // Set output with new fv that was created
 | |
|   //
 | |
|   *Fv = NewFv;
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| 
 | |
| }
 | |
| 
 | |
| 
 | |
| EFI_STATUS
 | |
| FvBufClearAllFiles (
 | |
|   IN OUT VOID *Fv
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Clears out all files from the Fv buffer in memory
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   Fv - Address of the Fv in memory
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_SUCCESS
 | |
| 
 | |
| --*/
 | |
| 
 | |
| {
 | |
|   EFI_FIRMWARE_VOLUME_HEADER *hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv;
 | |
|   EFI_STATUS Status;
 | |
|   UINTN size = 0;
 | |
| 
 | |
|   Status = FvBufGetSize (Fv, &size);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   CommonLibBinderSetMem(
 | |
|     (UINT8*)hdr + hdr->HeaderLength,
 | |
|     size - hdr->HeaderLength,
 | |
|     (hdr->Attributes & EFI_FVB2_ERASE_POLARITY) ? 0xFF : 0
 | |
|     );
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| EFI_STATUS
 | |
| FvBufGetSize (
 | |
|   IN VOID *Fv,
 | |
|   OUT UINTN *Size
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Clears out all files from the Fv buffer in memory
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   Fv - Address of the Fv in memory
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_SUCCESS
 | |
| 
 | |
| --*/
 | |
| 
 | |
| {
 | |
|   EFI_FIRMWARE_VOLUME_HEADER *hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv;
 | |
|   EFI_FV_BLOCK_MAP_ENTRY *blk = hdr->BlockMap;
 | |
| 
 | |
|   *Size = 0;
 | |
| 
 | |
|   while (blk->Length != 0 || blk->NumBlocks != 0) {
 | |
|     *Size = *Size + (blk->Length * blk->NumBlocks);
 | |
|     if (*Size >= 0x40000000) {
 | |
|       // If size is greater than 1GB, then assume it is corrupted
 | |
|       return EFI_VOLUME_CORRUPTED;
 | |
|     }
 | |
|     blk++;
 | |
|   }
 | |
| 
 | |
|   if (*Size == 0) {
 | |
|     // If size is 0, then assume the volume is corrupted
 | |
|     return EFI_VOLUME_CORRUPTED;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| EFI_STATUS
 | |
| FvBufAddFile (
 | |
|   IN OUT VOID *Fv,
 | |
|   IN VOID *File
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Adds a new FFS file
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   Fv - Address of the Fv in memory
 | |
|   File - FFS file to add to Fv
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_SUCCESS
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_FIRMWARE_VOLUME_HEADER *hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv;
 | |
| 
 | |
|   EFI_FFS_FILE_HEADER *fhdr = NULL;
 | |
|   EFI_FVB_ATTRIBUTES FvbAttributes;
 | |
|   UINTN offset;
 | |
|   UINTN fsize;
 | |
|   UINTN newSize;
 | |
|   UINTN clearLoop;
 | |
| 
 | |
|   EFI_STATUS Status;
 | |
|   UINTN fvSize;
 | |
| 
 | |
|   Status = FvBufGetSize (Fv, &fvSize);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   FvbAttributes = hdr->Attributes;
 | |
|   newSize = FvBufExpand3ByteSize (((EFI_FFS_FILE_HEADER*)File)->Size);
 | |
| 
 | |
|   for(
 | |
|       offset = (UINTN)ALIGN_POINTER (hdr->HeaderLength, 8);
 | |
|       offset + newSize <= fvSize;
 | |
|       offset = (UINTN)ALIGN_POINTER (offset, 8)
 | |
|     ) {
 | |
| 
 | |
|     fhdr = (EFI_FFS_FILE_HEADER*) ((UINT8*)hdr + offset);
 | |
| 
 | |
|     if (EFI_TEST_FFS_ATTRIBUTES_BIT(
 | |
|           FvbAttributes,
 | |
|           fhdr->State,
 | |
|           EFI_FILE_HEADER_VALID
 | |
|         )
 | |
|       ) {
 | |
|       // BUGBUG: Need to make sure that the new file does not already
 | |
|       // exist.
 | |
| 
 | |
|       fsize = FvBufExpand3ByteSize (fhdr->Size);
 | |
|       if (fsize == 0 || (offset + fsize > fvSize)) {
 | |
|         return EFI_VOLUME_CORRUPTED;
 | |
|       }
 | |
| 
 | |
|       offset = offset + fsize;
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     clearLoop = 0;
 | |
|     while ((clearLoop < newSize) &&
 | |
|            (((UINT8*)fhdr)[clearLoop] ==
 | |
|              (UINT8)((hdr->Attributes & EFI_FVB2_ERASE_POLARITY) ? 0xFF : 0)
 | |
|            )
 | |
|           ) {
 | |
|       clearLoop++;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // We found a place in the FV which is empty and big enough for
 | |
|     // the new file
 | |
|     //
 | |
|     if (clearLoop >= newSize) {
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     offset = offset + 1; // Make some forward progress
 | |
|   }
 | |
| 
 | |
|   if (offset + newSize > fvSize) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   CommonLibBinderCopyMem (fhdr, File, newSize);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| EFI_STATUS
 | |
| FvBufAddFileWithExtend (
 | |
|   IN OUT VOID **Fv,
 | |
|   IN VOID *File
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Adds a new FFS file.  Extends the firmware volume if needed.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   Fv - Source and destination firmware volume.
 | |
|        Note: If the FV is extended, then the original firmware volume
 | |
|              buffer is freed!
 | |
| 
 | |
|   Size - The minimum size that the firmware volume is to be extended by.
 | |
|          The FV may be extended more than this size.
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_SUCCESS
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS Status;
 | |
|   EFI_FFS_FILE_HEADER* NewFile;
 | |
| 
 | |
|   NewFile = (EFI_FFS_FILE_HEADER*)File;
 | |
| 
 | |
|   //
 | |
|   // Try to add to the capsule volume
 | |
|   //
 | |
|   Status = FvBufAddFile (*Fv, NewFile);
 | |
|   if (Status == EFI_OUT_OF_RESOURCES) {
 | |
|     //
 | |
|     // Try to extend the capsule volume by the size of the file
 | |
|     //
 | |
|     Status = FvBufExtend (Fv, FvBufExpand3ByteSize (NewFile->Size));
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Now, try to add the file again
 | |
|     //
 | |
|     Status = FvBufAddFile (*Fv, NewFile);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| EFI_STATUS
 | |
| FvBufAddVtfFile (
 | |
|   IN OUT VOID *Fv,
 | |
|   IN VOID *File
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Adds a new FFS VFT (Volume Top File) file.  In other words, adds the
 | |
|   file to the end of the firmware volume.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   Fv - Address of the Fv in memory
 | |
|   File - FFS file to add to Fv
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_SUCCESS
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS Status;
 | |
| 
 | |
|   EFI_FIRMWARE_VOLUME_HEADER *hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv;
 | |
| 
 | |
|   EFI_FFS_FILE_HEADER* NewFile;
 | |
|   UINTN                NewFileSize;
 | |
| 
 | |
|   UINT8 erasedUint8;
 | |
|   UINTN clearLoop;
 | |
| 
 | |
|   EFI_FFS_FILE_HEADER *LastFile;
 | |
|   UINTN LastFileSize;
 | |
| 
 | |
|   UINTN fvSize;
 | |
|   UINTN Key;
 | |
| 
 | |
|   Status = FvBufGetSize (Fv, &fvSize);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   erasedUint8 = (UINT8)((hdr->Attributes & EFI_FVB2_ERASE_POLARITY) ? 0xFF : 0);
 | |
|   NewFileSize = FvBufExpand3ByteSize (((EFI_FFS_FILE_HEADER*)File)->Size);
 | |
| 
 | |
|   if (NewFileSize != (UINTN)ALIGN_POINTER (NewFileSize, 8)) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Find the last file in the FV
 | |
|   //
 | |
|   Key = 0;
 | |
|   LastFile = NULL;
 | |
|   LastFileSize = 0;
 | |
|   do {
 | |
|     Status = FvBufFindNextFile (Fv, &Key, (VOID **)&LastFile);
 | |
|     LastFileSize = FvBufExpand3ByteSize (((EFI_FFS_FILE_HEADER*)File)->Size);
 | |
|   } while (!EFI_ERROR (Status));
 | |
| 
 | |
|   //
 | |
|   // If no files were found, then we start at the beginning of the FV
 | |
|   //
 | |
|   if (LastFile == NULL) {
 | |
|     LastFile = (EFI_FFS_FILE_HEADER*)((UINT8*)hdr + hdr->HeaderLength);
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // We want to put the new file (VTF) at the end of the FV
 | |
|   //
 | |
|   NewFile = (EFI_FFS_FILE_HEADER*)((UINT8*)hdr + (fvSize - NewFileSize));
 | |
| 
 | |
|   //
 | |
|   // Check to see if there is enough room for the VTF after the last file
 | |
|   // found in the FV
 | |
|   //
 | |
|   if ((UINT8*)NewFile < ((UINT8*)LastFile + LastFileSize)) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Loop to determine if the end of the FV is empty
 | |
|   //
 | |
|   clearLoop = 0;
 | |
|   while ((clearLoop < NewFileSize) &&
 | |
|          (((UINT8*)NewFile)[clearLoop] == erasedUint8)
 | |
|         ) {
 | |
|     clearLoop++;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Check to see if there was not enough room for the file
 | |
|   //
 | |
|   if (clearLoop < NewFileSize) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   CommonLibBinderCopyMem (NewFile, File, NewFileSize);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| VOID
 | |
| FvBufCompact3ByteSize (
 | |
|   OUT VOID* SizeDest,
 | |
|   IN UINT32 Size
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Expands the 3 byte size commonly used in Firmware Volume data structures
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   Size - Address of the 3 byte array representing the size
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   UINT32
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   ((UINT8*)SizeDest)[0] = (UINT8)Size;
 | |
|   ((UINT8*)SizeDest)[1] = (UINT8)(Size >> 8);
 | |
|   ((UINT8*)SizeDest)[2] = (UINT8)(Size >> 16);
 | |
| }
 | |
| 
 | |
| UINT32
 | |
| FvBufExpand3ByteSize (
 | |
|   IN VOID* Size
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Expands the 3 byte size commonly used in Firmware Volume data structures
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   Size - Address of the 3 byte array representing the size
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   UINT32
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   return (((UINT8*)Size)[2] << 16) +
 | |
|          (((UINT8*)Size)[1] << 8) +
 | |
|          ((UINT8*)Size)[0];
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| FvBufFindNextFile (
 | |
|   IN VOID *Fv,
 | |
|   IN OUT UINTN *Key,
 | |
|   OUT VOID **File
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Iterates through the files contained within the firmware volume
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   Fv - Address of the Fv in memory
 | |
|   Key - Should be 0 to get the first file.  After that, it should be
 | |
|         passed back in without modifying it's contents to retrieve
 | |
|         subsequent files.
 | |
|   File - Output file pointer
 | |
|     File == NULL - invalid parameter
 | |
|     otherwise - *File will be update to the location of the file
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_SUCCESS
 | |
|   EFI_NOT_FOUND
 | |
|   EFI_VOLUME_CORRUPTED
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_FIRMWARE_VOLUME_HEADER *hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv;
 | |
| 
 | |
|   EFI_FFS_FILE_HEADER *fhdr = NULL;
 | |
|   EFI_FVB_ATTRIBUTES FvbAttributes;
 | |
|   UINTN fsize;
 | |
| 
 | |
|   EFI_STATUS Status;
 | |
|   UINTN fvSize;
 | |
| 
 | |
|   if (Fv == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   Status = FvBufGetSize (Fv, &fvSize);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   if (*Key == 0) {
 | |
|     *Key = hdr->HeaderLength;
 | |
|   }
 | |
| 
 | |
|   FvbAttributes = hdr->Attributes;
 | |
| 
 | |
|   for(
 | |
|       *Key = (UINTN)ALIGN_POINTER (*Key, 8);
 | |
|       (*Key + sizeof (*fhdr)) < fvSize;
 | |
|       *Key = (UINTN)ALIGN_POINTER (*Key, 8)
 | |
|     ) {
 | |
| 
 | |
|     fhdr = (EFI_FFS_FILE_HEADER*) ((UINT8*)hdr + *Key);
 | |
|     fsize = FvBufExpand3ByteSize (fhdr->Size);
 | |
| 
 | |
|     if (!EFI_TEST_FFS_ATTRIBUTES_BIT(
 | |
|           FvbAttributes,
 | |
|           fhdr->State,
 | |
|           EFI_FILE_HEADER_VALID
 | |
|         ) ||
 | |
|         EFI_TEST_FFS_ATTRIBUTES_BIT(
 | |
|           FvbAttributes,
 | |
|           fhdr->State,
 | |
|           EFI_FILE_HEADER_INVALID
 | |
|         )
 | |
|       ) {
 | |
|       *Key = *Key + 1; // Make some forward progress
 | |
|       continue;
 | |
|     } else if(
 | |
|         EFI_TEST_FFS_ATTRIBUTES_BIT(
 | |
|           FvbAttributes,
 | |
|           fhdr->State,
 | |
|           EFI_FILE_MARKED_FOR_UPDATE
 | |
|         ) ||
 | |
|         EFI_TEST_FFS_ATTRIBUTES_BIT(
 | |
|           FvbAttributes,
 | |
|           fhdr->State,
 | |
|           EFI_FILE_DELETED
 | |
|         )
 | |
|       ) {
 | |
|       *Key = *Key + fsize;
 | |
|       continue;
 | |
|     } else if (EFI_TEST_FFS_ATTRIBUTES_BIT(
 | |
|           FvbAttributes,
 | |
|           fhdr->State,
 | |
|           EFI_FILE_DATA_VALID
 | |
|         )
 | |
|       ) {
 | |
|       *File = (UINT8*)hdr + *Key;
 | |
|       *Key = *Key + fsize;
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
| 
 | |
|     *Key = *Key + 1; // Make some forward progress
 | |
|   }
 | |
| 
 | |
|   return EFI_NOT_FOUND;
 | |
| }
 | |
| 
 | |
| 
 | |
| EFI_STATUS
 | |
| FvBufFindFileByName (
 | |
|   IN VOID *Fv,
 | |
|   IN EFI_GUID *Name,
 | |
|   OUT VOID **File
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Searches the Fv for a file by its name
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   Fv - Address of the Fv in memory
 | |
|   Name - Guid filename to search for in the firmware volume
 | |
|   File - Output file pointer
 | |
|     File == NULL - Only determine if the file exists, based on return
 | |
|                    value from the function call.
 | |
|     otherwise - *File will be update to the location of the file
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_SUCCESS
 | |
|   EFI_NOT_FOUND
 | |
|   EFI_VOLUME_CORRUPTED
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS Status;
 | |
|   UINTN Key;
 | |
|   EFI_FFS_FILE_HEADER *NextFile;
 | |
| 
 | |
|   Key = 0;
 | |
|   while (TRUE) {
 | |
|     Status = FvBufFindNextFile (Fv, &Key, (VOID **)&NextFile);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     if (CommonLibBinderCompareGuid (Name, &NextFile->Name)) {
 | |
|       if (File != NULL) {
 | |
|         *File = NextFile;
 | |
|       }
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return EFI_NOT_FOUND;
 | |
| }
 | |
| 
 | |
| 
 | |
| EFI_STATUS
 | |
| FvBufFindFileByType (
 | |
|   IN VOID *Fv,
 | |
|   IN EFI_FV_FILETYPE Type,
 | |
|   OUT VOID **File
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Searches the Fv for a file by its type
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   Fv - Address of the Fv in memory
 | |
|   Type - FFS FILE type to search for
 | |
|   File - Output file pointer
 | |
|     (File == NULL) -> Only determine if the file exists, based on return
 | |
|                       value from the function call.
 | |
|     otherwise -> *File will be update to the location of the file
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_SUCCESS
 | |
|   EFI_NOT_FOUND
 | |
|   EFI_VOLUME_CORRUPTED
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS Status;
 | |
|   UINTN Key;
 | |
|   EFI_FFS_FILE_HEADER *NextFile;
 | |
| 
 | |
|   Key = 0;
 | |
|   while (TRUE) {
 | |
|     Status = FvBufFindNextFile (Fv, &Key, (VOID **)&NextFile);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     if (Type == NextFile->Type) {
 | |
|       if (File != NULL) {
 | |
|         *File = NextFile;
 | |
|       }
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return EFI_NOT_FOUND;
 | |
| }
 | |
| 
 | |
| 
 | |
| EFI_STATUS
 | |
| FvBufGetFileRawData (
 | |
|   IN  VOID*     FfsFile,
 | |
|   OUT VOID**    RawData,
 | |
|   OUT UINTN*    RawDataSize
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Searches the requested file for raw data.
 | |
| 
 | |
|   This routine either returns all the payload of a EFI_FV_FILETYPE_RAW file,
 | |
|   or finds the EFI_SECTION_RAW section within the file and returns its data.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   FfsFile - Address of the FFS file in memory
 | |
|   RawData - Pointer to the raw data within the file
 | |
|             (This is NOT allocated.  It is within the file.)
 | |
|   RawDataSize - Size of the raw data within the file
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_STATUS
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS Status;
 | |
|   EFI_FFS_FILE_HEADER* File;
 | |
|   EFI_RAW_SECTION* Section;
 | |
| 
 | |
|   File = (EFI_FFS_FILE_HEADER*)FfsFile;
 | |
| 
 | |
|   //
 | |
|   // Is the file type == EFI_FV_FILETYPE_RAW?
 | |
|   //
 | |
|   if (File->Type == EFI_FV_FILETYPE_RAW) {
 | |
|     //
 | |
|     // Raw filetypes don't have sections, so we just return the raw data
 | |
|     //
 | |
|     *RawData = (VOID*)(File + 1);
 | |
|     *RawDataSize = FvBufExpand3ByteSize (File->Size) - sizeof (*File);
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Within the file, we now need to find the EFI_SECTION_RAW section.
 | |
|   //
 | |
|   Status = FvBufFindSectionByType (File, EFI_SECTION_RAW, (VOID **)&Section);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   *RawData = (VOID*)(Section + 1);
 | |
|   *RawDataSize =
 | |
|     FvBufExpand3ByteSize (Section->Size) - sizeof (*Section);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| 
 | |
| }
 | |
| 
 | |
| 
 | |
| EFI_STATUS
 | |
| FvBufPackageFreeformRawFile (
 | |
|   IN EFI_GUID*  Filename,
 | |
|   IN VOID*      RawData,
 | |
|   IN UINTN      RawDataSize,
 | |
|   OUT VOID**    FfsFile
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Packages up a FFS file containing the input raw data.
 | |
| 
 | |
|   The file created will have a type of EFI_FV_FILETYPE_FREEFORM, and will
 | |
|   contain one EFI_FV_FILETYPE_RAW section.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   RawData - Pointer to the raw data to be packed
 | |
|   RawDataSize - Size of the raw data to be packed
 | |
|   FfsFile - Address of the packaged FFS file.
 | |
|             Note: The called must deallocate this memory!
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_STATUS
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_FFS_FILE_HEADER* NewFile;
 | |
|   UINT32 NewFileSize;
 | |
|   EFI_RAW_SECTION* NewSection;
 | |
|   UINT32 NewSectionSize;
 | |
| 
 | |
|   //
 | |
|   // The section size is the DataSize + the size of the section header
 | |
|   //
 | |
|   NewSectionSize = (UINT32)sizeof (EFI_RAW_SECTION) + (UINT32)RawDataSize;
 | |
| 
 | |
|   //
 | |
|   // The file size is the size of the file header + the section size
 | |
|   //
 | |
|   NewFileSize = sizeof (EFI_FFS_FILE_HEADER) + NewSectionSize;
 | |
| 
 | |
|   //
 | |
|   // Try to allocate a buffer to build the new FFS file in
 | |
|   //
 | |
|   NewFile = CommonLibBinderAllocate (NewFileSize);
 | |
|   if (NewFile == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   CommonLibBinderSetMem (NewFile, NewFileSize, 0);
 | |
| 
 | |
|   //
 | |
|   // The NewSection follow right after the FFS file header
 | |
|   //
 | |
|   NewSection = (EFI_RAW_SECTION*)(NewFile + 1);
 | |
|   FvBufCompact3ByteSize (NewSection->Size, NewSectionSize);
 | |
|   NewSection->Type = EFI_SECTION_RAW;
 | |
| 
 | |
|   //
 | |
|   // Copy the actual file data into the buffer
 | |
|   //
 | |
|   CommonLibBinderCopyMem (NewSection + 1, RawData, RawDataSize);
 | |
| 
 | |
|   //
 | |
|   // Initialize the FFS file header
 | |
|   //
 | |
|   CommonLibBinderCopyMem (&NewFile->Name, Filename, sizeof (EFI_GUID));
 | |
|   FvBufCompact3ByteSize (NewFile->Size, NewFileSize);
 | |
|   NewFile->Type = EFI_FV_FILETYPE_FREEFORM;
 | |
|   NewFile->Attributes = 0;
 | |
|   NewFile->IntegrityCheck.Checksum.Header =
 | |
|     FvBufCalculateChecksum8 ((UINT8*)NewFile, sizeof (*NewFile));
 | |
|   NewFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;
 | |
|   NewFile->State = (UINT8)~( EFI_FILE_HEADER_CONSTRUCTION |
 | |
|                              EFI_FILE_HEADER_VALID |
 | |
|                              EFI_FILE_DATA_VALID
 | |
|                            );
 | |
| 
 | |
|   *FfsFile = NewFile;
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| EFI_STATUS
 | |
| FvBufFindNextSection (
 | |
|   IN VOID *SectionsStart,
 | |
|   IN UINTN TotalSectionsSize,
 | |
|   IN OUT UINTN *Key,
 | |
|   OUT VOID **Section
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Iterates through the sections contained within a given array of sections
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   SectionsStart - Address of the start of the FFS sections array
 | |
|   TotalSectionsSize - Total size of all the sections
 | |
|   Key - Should be 0 to get the first section.  After that, it should be
 | |
|         passed back in without modifying it's contents to retrieve
 | |
|         subsequent files.
 | |
|   Section - Output section pointer
 | |
|     (Section == NULL) -> invalid parameter
 | |
|     otherwise -> *Section will be update to the location of the file
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_SUCCESS
 | |
|   EFI_NOT_FOUND
 | |
|   EFI_VOLUME_CORRUPTED
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_COMMON_SECTION_HEADER *sectionHdr;
 | |
|   UINTN sectionSize;
 | |
| 
 | |
|   *Key = (UINTN)ALIGN_POINTER (*Key, 4); // Sections are DWORD aligned
 | |
| 
 | |
|   if ((*Key + sizeof (*sectionHdr)) > TotalSectionsSize) {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   sectionHdr = (EFI_COMMON_SECTION_HEADER*)((UINT8*)SectionsStart + *Key);
 | |
|   sectionSize = FvBufExpand3ByteSize (sectionHdr->Size);
 | |
| 
 | |
|   if (sectionSize < sizeof (EFI_COMMON_SECTION_HEADER)) {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   if ((*Key + sectionSize) > TotalSectionsSize) {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   *Section = (UINT8*)sectionHdr;
 | |
|   *Key = *Key + sectionSize;
 | |
|   return EFI_SUCCESS;
 | |
| 
 | |
| }
 | |
| 
 | |
| 
 | |
| EFI_STATUS
 | |
| FvBufCountSections (
 | |
|   IN VOID* FfsFile,
 | |
|   IN UINTN* Count
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Searches the FFS file and counts the number of sections found.
 | |
|   The sections are NOT recursed.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   FfsFile - Address of the FFS file in memory
 | |
|   Count - The location to store the section count in
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_SUCCESS
 | |
|   EFI_NOT_FOUND
 | |
|   EFI_VOLUME_CORRUPTED
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS                 Status;
 | |
|   UINTN                      Key;
 | |
|   VOID*                      SectionStart;
 | |
|   UINTN                      TotalSectionsSize;
 | |
|   EFI_COMMON_SECTION_HEADER* NextSection;
 | |
| 
 | |
|   SectionStart = (VOID*)((UINTN)FfsFile + sizeof (EFI_FFS_FILE_HEADER));
 | |
|   TotalSectionsSize =
 | |
|     FvBufExpand3ByteSize (((EFI_FFS_FILE_HEADER*)FfsFile)->Size) -
 | |
|     sizeof (EFI_FFS_FILE_HEADER);
 | |
|   Key = 0;
 | |
|   *Count = 0;
 | |
|   while (TRUE) {
 | |
|     Status = FvBufFindNextSection (
 | |
|                SectionStart,
 | |
|                TotalSectionsSize,
 | |
|                &Key,
 | |
|                (VOID **)&NextSection
 | |
|                );
 | |
|     if (Status == EFI_NOT_FOUND) {
 | |
|       return EFI_SUCCESS;
 | |
|     } else if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Increment the section counter
 | |
|     //
 | |
|     *Count += 1;
 | |
| 
 | |
|   }
 | |
| 
 | |
|   return EFI_NOT_FOUND;
 | |
| }
 | |
| 
 | |
| 
 | |
| EFI_STATUS
 | |
| FvBufFindSectionByType (
 | |
|   IN VOID *FfsFile,
 | |
|   IN UINT8 Type,
 | |
|   OUT VOID **Section
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Searches the FFS file for a section by its type
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   FfsFile - Address of the FFS file in memory
 | |
|   Type - FFS FILE section type to search for
 | |
|   Section - Output section pointer
 | |
|     (Section == NULL) -> Only determine if the section exists, based on return
 | |
|                          value from the function call.
 | |
|     otherwise -> *Section will be update to the location of the file
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_SUCCESS
 | |
|   EFI_NOT_FOUND
 | |
|   EFI_VOLUME_CORRUPTED
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS Status;
 | |
|   UINTN Key;
 | |
|   VOID*                      SectionStart;
 | |
|   UINTN                      TotalSectionsSize;
 | |
|   EFI_COMMON_SECTION_HEADER* NextSection;
 | |
| 
 | |
|   SectionStart = (VOID*)((UINTN)FfsFile + sizeof (EFI_FFS_FILE_HEADER));
 | |
|   TotalSectionsSize =
 | |
|     FvBufExpand3ByteSize (((EFI_FFS_FILE_HEADER*)FfsFile)->Size) -
 | |
|     sizeof (EFI_FFS_FILE_HEADER);
 | |
|   Key = 0;
 | |
|   while (TRUE) {
 | |
|     Status = FvBufFindNextSection (
 | |
|                SectionStart,
 | |
|                TotalSectionsSize,
 | |
|                &Key,
 | |
|                (VOID **)&NextSection
 | |
|                );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     if (Type == NextSection->Type) {
 | |
|       if (Section != NULL) {
 | |
|         *Section = NextSection;
 | |
|       }
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return EFI_NOT_FOUND;
 | |
| }
 | |
| 
 | |
| 
 | |
| EFI_STATUS
 | |
| FvBufShrinkWrap (
 | |
|   IN VOID *Fv
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Shrinks a firmware volume (in place) to provide a minimal FV.
 | |
| 
 | |
|   BUGBUG: Does not handle the case where the firmware volume has a
 | |
|           VTF (Volume Top File).  The VTF will not be moved to the
 | |
|           end of the extended FV.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   Fv - Firmware volume.
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_SUCCESS
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS Status;
 | |
|   UINTN OldSize;
 | |
|   UINT32 BlockCount;
 | |
|   UINT32 NewBlockSize = 128;
 | |
|   UINTN Key;
 | |
|   EFI_FFS_FILE_HEADER* FileIt;
 | |
|   VOID* EndOfLastFile;
 | |
| 
 | |
|   EFI_FIRMWARE_VOLUME_HEADER* FvHdr;
 | |
| 
 | |
|   Status = FvBufGetSize (Fv, &OldSize);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   Status = FvBufUnifyBlockSizes (Fv, NewBlockSize);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Locate the block map in the fv header
 | |
|   //
 | |
|   FvHdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv;
 | |
| 
 | |
|   //
 | |
|   // Find the end of the last file
 | |
|   //
 | |
|   Key = 0;
 | |
|   EndOfLastFile = (UINT8*)FvHdr + FvHdr->FvLength;
 | |
|   while (!EFI_ERROR (FvBufFindNextFile (Fv, &Key, (VOID **)&FileIt))) {
 | |
|     EndOfLastFile =
 | |
|       (VOID*)((UINT8*)FileIt + FvBufExpand3ByteSize (FileIt->Size));
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Set the BlockCount to have the minimal number of blocks for the Fv.
 | |
|   //
 | |
|   BlockCount = (UINT32)((UINTN)EndOfLastFile - (UINTN)Fv);
 | |
|   BlockCount = BlockCount + NewBlockSize - 1;
 | |
|   BlockCount = BlockCount / NewBlockSize;
 | |
| 
 | |
|   //
 | |
|   // Adjust the block count to shrink the Fv in place.
 | |
|   //
 | |
|   FvHdr->BlockMap[0].NumBlocks = BlockCount;
 | |
|   FvHdr->FvLength = BlockCount * NewBlockSize;
 | |
| 
 | |
|   //
 | |
|   // Update the FV header checksum
 | |
|   //
 | |
|   FvBufChecksumHeader (Fv);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| 
 | |
| }
 | |
| 
 | |
| 
 | |
| EFI_STATUS
 | |
| FvBufUnifyBlockSizes (
 | |
|   IN OUT VOID *Fv,
 | |
|   IN UINTN BlockSize
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Searches the FFS file for a section by its type
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   Fv - Address of the Fv in memory
 | |
|   BlockSize - The size of the blocks to convert the Fv to.  If the total size
 | |
|               of the Fv is not evenly divisible by this size, then
 | |
|               EFI_INVALID_PARAMETER will be returned.
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_SUCCESS
 | |
|   EFI_NOT_FOUND
 | |
|   EFI_VOLUME_CORRUPTED
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_FIRMWARE_VOLUME_HEADER *hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv;
 | |
|   EFI_FV_BLOCK_MAP_ENTRY *blk = hdr->BlockMap;
 | |
|   UINT32 Size;
 | |
| 
 | |
|   Size = 0;
 | |
| 
 | |
|   //
 | |
|   // Scan through the block map list, performing error checking, and adding
 | |
|   // up the total Fv size.
 | |
|   //
 | |
|   while( blk->Length != 0 ||
 | |
|          blk->NumBlocks != 0
 | |
|        ) {
 | |
|     Size = Size + (blk->Length * blk->NumBlocks);
 | |
|     blk++;
 | |
|     if ((UINT8*)blk > ((UINT8*)hdr + hdr->HeaderLength)) {
 | |
|       return EFI_VOLUME_CORRUPTED;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Make sure that the Fv size is a multiple of the new block size.
 | |
|   //
 | |
|   if ((Size % BlockSize) != 0) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Zero out the entire block map.
 | |
|   //
 | |
|   CommonLibBinderSetMem (
 | |
|     &hdr->BlockMap,
 | |
|     (UINTN)blk - (UINTN)&hdr->BlockMap,
 | |
|     0
 | |
|     );
 | |
| 
 | |
|   //
 | |
|   // Write out the single block map entry.
 | |
|   //
 | |
|   hdr->BlockMap[0].Length = (UINT32)BlockSize;
 | |
|   hdr->BlockMap[0].NumBlocks = Size / (UINT32)BlockSize;
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| UINT16
 | |
| FvBufCalculateSum16 (
 | |
|   IN UINT16       *Buffer,
 | |
|   IN UINTN        Size
 | |
|   )
 | |
| /*++
 | |
|   
 | |
| Routine Description:
 | |
| 
 | |
|   This function calculates the UINT16 sum for the requested region.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   Buffer      Pointer to buffer containing byte data of component.
 | |
|   Size        Size of the buffer
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   The 16 bit checksum
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   UINTN   Index;
 | |
|   UINT16  Sum;
 | |
| 
 | |
|   Sum = 0;
 | |
| 
 | |
|   //
 | |
|   // Perform the word sum for buffer
 | |
|   //
 | |
|   for (Index = 0; Index < Size; Index++) {
 | |
|     Sum = (UINT16) (Sum + Buffer[Index]);
 | |
|   }
 | |
| 
 | |
|   return (UINT16) Sum;
 | |
| }
 | |
| 
 | |
| 
 | |
| STATIC
 | |
| UINT16
 | |
| FvBufCalculateChecksum16 (
 | |
|   IN UINT16       *Buffer,
 | |
|   IN UINTN        Size
 | |
|   )
 | |
| /*++
 | |
|   
 | |
| Routine Description::
 | |
| 
 | |
|   This function calculates the value needed for a valid UINT16 checksum
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   Buffer      Pointer to buffer containing byte data of component.
 | |
|   Size        Size of the buffer
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   The 16 bit checksum value needed.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   return (UINT16)(0x10000 - FvBufCalculateSum16 (Buffer, Size));
 | |
| }
 | |
| 
 | |
| 
 | |
| STATIC
 | |
| UINT8
 | |
| FvBufCalculateSum8 (
 | |
|   IN UINT8  *Buffer,
 | |
|   IN UINTN  Size
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Description:
 | |
| 
 | |
|   This function calculates the UINT8 sum for the requested region.
 | |
| 
 | |
| Input:
 | |
| 
 | |
|   Buffer      Pointer to buffer containing byte data of component.
 | |
|   Size        Size of the buffer
 | |
| 
 | |
| Return:
 | |
| 
 | |
|   The 8 bit checksum value needed.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   UINTN   Index;
 | |
|   UINT8   Sum;
 | |
| 
 | |
|   Sum = 0;
 | |
| 
 | |
|   //
 | |
|   // Perform the byte sum for buffer
 | |
|   //
 | |
|   for (Index = 0; Index < Size; Index++) {
 | |
|     Sum = (UINT8) (Sum + Buffer[Index]);
 | |
|   }
 | |
| 
 | |
|   return Sum;
 | |
| }
 | |
| 
 | |
| 
 | |
| STATIC
 | |
| UINT8
 | |
| FvBufCalculateChecksum8 (
 | |
|   IN UINT8        *Buffer,
 | |
|   IN UINTN        Size
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Description:
 | |
| 
 | |
|   This function calculates the value needed for a valid UINT8 checksum
 | |
| 
 | |
| Input:
 | |
| 
 | |
|   Buffer      Pointer to buffer containing byte data of component.
 | |
|   Size        Size of the buffer
 | |
| 
 | |
| Return:
 | |
| 
 | |
|   The 8 bit checksum value needed.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   return (UINT8)(0x100 - FvBufCalculateSum8 (Buffer, Size));
 | |
| }
 | |
| 
 | |
| 
 |