Signed-off-by : Chao Zhang <chao.b.zhang@intel.com> Reviewed-by : Gao Liming <liming.gao@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@14779 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			521 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			521 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  Capsule Library instance to process capsule images.
 | 
						|
 | 
						|
  Copyright (c) 2007 - 2013, 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 <PiDxe.h>
 | 
						|
 | 
						|
#include <Guid/Capsule.h>
 | 
						|
#include <Guid/FmpCapsule.h>
 | 
						|
 | 
						|
#include <Library/DebugLib.h>
 | 
						|
#include <Library/BaseMemoryLib.h>
 | 
						|
#include <Library/DxeServicesTableLib.h>
 | 
						|
#include <Library/MemoryAllocationLib.h>
 | 
						|
#include <Library/CapsuleLib.h>
 | 
						|
#include <Library/GenericBdsLib.h>
 | 
						|
#include <Library/UefiBootServicesTableLib.h>
 | 
						|
#include <Library/BaseLib.h>
 | 
						|
#include <Library/DevicePathLib.h>
 | 
						|
 | 
						|
#include <Protocol/FirmwareManagement.h>
 | 
						|
#include <Protocol/DevicePath.h>
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Function indicate the current completion progress of the firmware
 | 
						|
  update. Platform may override with own specific progress function.
 | 
						|
 | 
						|
  @param  Completion    A value between 1 and 100 indicating the current completion progress of the firmware update
 | 
						|
 | 
						|
  @retval EFI_SUCESS    Input capsule is a correct FMP capsule.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
Update_Image_Progress (
 | 
						|
   IN UINTN Completion
 | 
						|
)
 | 
						|
{
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Validate Fmp capsules layout.
 | 
						|
 | 
						|
  @param  CapsuleHeader    Points to a capsule header.
 | 
						|
 | 
						|
  @retval EFI_SUCESS                     Input capsule is a correct FMP capsule.
 | 
						|
  @retval EFI_INVALID_PARAMETER  Input capsule is not a correct FMP capsule.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
ValidateFmpCapsule (
 | 
						|
  IN EFI_CAPSULE_HEADER *CapsuleHeader
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER       *FmpCapsuleHeader;
 | 
						|
  UINT8                                        *EndOfCapsule;
 | 
						|
  EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
 | 
						|
  UINT8                                        *EndOfPayload;
 | 
						|
  UINT64                                       *ItemOffsetList;
 | 
						|
  UINT32                                       ItemNum;
 | 
						|
  UINTN                                        Index;
 | 
						|
 | 
						|
  FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize);
 | 
						|
  EndOfCapsule     = (UINT8 *) CapsuleHeader + CapsuleHeader->CapsuleImageSize;
 | 
						|
 | 
						|
  if (FmpCapsuleHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
  ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
 | 
						|
 | 
						|
  ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;
 | 
						|
 | 
						|
  if (ItemNum == FmpCapsuleHeader->EmbeddedDriverCount) {
 | 
						|
    //
 | 
						|
    // No payload element 
 | 
						|
    //
 | 
						|
    if (((UINT8 *)FmpCapsuleHeader + ItemOffsetList[ItemNum - 1]) < EndOfCapsule) {
 | 
						|
      return EFI_SUCCESS;
 | 
						|
    } else {
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (FmpCapsuleHeader->PayloadItemCount != 0) {
 | 
						|
    //
 | 
						|
    // Check if the last payload is within capsule image range
 | 
						|
    //
 | 
						|
    ImageHeader  = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[ItemNum - 1]);
 | 
						|
    EndOfPayload = (UINT8 *)(ImageHeader + 1) + ImageHeader->UpdateImageSize + ImageHeader->UpdateVendorCodeSize;
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // No driver & payload element in FMP
 | 
						|
    //
 | 
						|
    EndOfPayload = (UINT8 *)(FmpCapsuleHeader + 1);
 | 
						|
  }
 | 
						|
 | 
						|
  if (EndOfPayload != EndOfCapsule) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // All the address in ItemOffsetList must be stored in ascending order
 | 
						|
  //
 | 
						|
  if (ItemNum >= 2) {
 | 
						|
    for (Index = 0; Index < ItemNum - 1; Index++) {
 | 
						|
      if (ItemOffsetList[Index] >= ItemOffsetList[Index + 1]) {
 | 
						|
        return EFI_INVALID_PARAMETER;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Process Firmware management protocol data capsule.  
 | 
						|
 | 
						|
  @param  CapsuleHeader         Points to a capsule header.
 | 
						|
 | 
						|
  @retval EFI_SUCESS            Process Capsule Image successfully.
 | 
						|
  @retval EFI_UNSUPPORTED       Capsule image is not supported by the firmware.
 | 
						|
  @retval EFI_VOLUME_CORRUPTED  FV volume in the capsule is corrupted.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  Not enough memory.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
ProcessFmpCapsuleImage (
 | 
						|
  IN EFI_CAPSULE_HEADER *CapsuleHeader
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                                    Status;
 | 
						|
  EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER        *FmpCapsuleHeader;
 | 
						|
  UINT8                                         *EndOfCapsule;
 | 
						|
  EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER  *ImageHeader;
 | 
						|
  EFI_HANDLE                                    ImageHandle;
 | 
						|
  UINT64                                        *ItemOffsetList;
 | 
						|
  UINT32                                        ItemNum;
 | 
						|
  UINTN                                         Index;
 | 
						|
  UINTN                                         ExitDataSize;
 | 
						|
  EFI_HANDLE                                    *HandleBuffer;
 | 
						|
  EFI_FIRMWARE_MANAGEMENT_PROTOCOL              *Fmp;
 | 
						|
  UINTN                                         NumberOfHandles;
 | 
						|
  UINTN                                         DescriptorSize;
 | 
						|
  UINT8                                         FmpImageInfoCount;
 | 
						|
  UINT32                                        FmpImageInfoDescriptorVer;
 | 
						|
  UINTN                                         ImageInfoSize;
 | 
						|
  UINT32                                        PackageVersion;
 | 
						|
  CHAR16                                        *PackageVersionName;
 | 
						|
  CHAR16                                        *AbortReason;
 | 
						|
  EFI_FIRMWARE_IMAGE_DESCRIPTOR                 *FmpImageInfoBuf;
 | 
						|
  EFI_FIRMWARE_IMAGE_DESCRIPTOR                 *TempFmpImageInfo;
 | 
						|
  UINTN                                         DriverLen;
 | 
						|
  UINTN                                         Index1;
 | 
						|
  UINTN                                         Index2;
 | 
						|
  MEMMAP_DEVICE_PATH                            MemMapNode;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL                      *DriverDevicePath;
 | 
						|
 | 
						|
  Status           = EFI_SUCCESS;
 | 
						|
  HandleBuffer     = NULL;
 | 
						|
  ExitDataSize     = 0;
 | 
						|
  DriverDevicePath = NULL;
 | 
						|
 | 
						|
  FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize);
 | 
						|
  EndOfCapsule     = (UINT8 *) CapsuleHeader + CapsuleHeader->CapsuleImageSize;
 | 
						|
 | 
						|
  if (FmpCapsuleHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
  ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
 | 
						|
 | 
						|
  ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;
 | 
						|
 | 
						|
  //
 | 
						|
  // capsule in which driver count and payload count are both zero is not processed.
 | 
						|
  //
 | 
						|
  if (ItemNum == 0) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // 1. ConnectAll to ensure 
 | 
						|
  //    All the communication protocol required by driver in capsule installed 
 | 
						|
  //    All FMP protocols are installed
 | 
						|
  //
 | 
						|
  BdsLibConnectAll();
 | 
						|
 | 
						|
 | 
						|
  //
 | 
						|
  // 2. Try to load & start all the drivers within capsule 
 | 
						|
  //
 | 
						|
  SetDevicePathNodeLength (&MemMapNode.Header, sizeof (MemMapNode));
 | 
						|
  MemMapNode.Header.Type     = HARDWARE_DEVICE_PATH;
 | 
						|
  MemMapNode.Header.SubType  = HW_MEMMAP_DP;
 | 
						|
  MemMapNode.MemoryType      = EfiBootServicesCode;
 | 
						|
  MemMapNode.StartingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)CapsuleHeader;
 | 
						|
  MemMapNode.EndingAddress   = (EFI_PHYSICAL_ADDRESS)(UINTN)((UINT8 *)CapsuleHeader + CapsuleHeader->CapsuleImageSize - 1);
 | 
						|
 | 
						|
  DriverDevicePath = AppendDevicePathNode (NULL, &MemMapNode.Header);
 | 
						|
  if (DriverDevicePath == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  for (Index = 0; Index < FmpCapsuleHeader->EmbeddedDriverCount; Index++) {
 | 
						|
    if (FmpCapsuleHeader->PayloadItemCount == 0 && Index == (UINTN)FmpCapsuleHeader->EmbeddedDriverCount - 1) {
 | 
						|
      //
 | 
						|
      // When driver is last element in the ItemOffsetList array, the driver size is calculated by reference CapsuleImageSize in EFI_CAPSULE_HEADER
 | 
						|
      //
 | 
						|
      DriverLen = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize - (UINTN)ItemOffsetList[Index];
 | 
						|
    } else {
 | 
						|
      DriverLen = (UINTN)ItemOffsetList[Index + 1] - (UINTN)ItemOffsetList[Index];
 | 
						|
    }
 | 
						|
 | 
						|
    Status = gBS->LoadImage(
 | 
						|
                    FALSE,
 | 
						|
                    gImageHandle,
 | 
						|
                    DriverDevicePath,
 | 
						|
                    (UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index],
 | 
						|
                    DriverLen,
 | 
						|
                    &ImageHandle
 | 
						|
                    );
 | 
						|
    if (EFI_ERROR(Status)) {
 | 
						|
      goto EXIT;
 | 
						|
    }
 | 
						|
 | 
						|
    Status = gBS->StartImage(
 | 
						|
                    ImageHandle, 
 | 
						|
                    &ExitDataSize, 
 | 
						|
                    NULL
 | 
						|
                    );
 | 
						|
    if (EFI_ERROR(Status)) {
 | 
						|
      DEBUG ((DEBUG_ERROR, "Driver Return Status = %r\n", Status));
 | 
						|
      goto EXIT;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Connnect all again to connect drivers within capsule 
 | 
						|
  //
 | 
						|
  if (FmpCapsuleHeader->EmbeddedDriverCount > 0) {
 | 
						|
    BdsLibConnectAll();
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // 3. Route payload to right FMP instance
 | 
						|
  //
 | 
						|
  Status = gBS->LocateHandleBuffer (
 | 
						|
                  ByProtocol,
 | 
						|
                  &gEfiFirmwareManagementProtocolGuid,
 | 
						|
                  NULL,
 | 
						|
                  &NumberOfHandles,
 | 
						|
                  &HandleBuffer
 | 
						|
                  );
 | 
						|
 | 
						|
  if (!EFI_ERROR(Status)) {
 | 
						|
    for(Index1 = 0; Index1 < NumberOfHandles; Index1++) {
 | 
						|
      Status = gBS->HandleProtocol(
 | 
						|
                      HandleBuffer[Index1],
 | 
						|
                      &gEfiFirmwareManagementProtocolGuid,
 | 
						|
                      (VOID **)&Fmp
 | 
						|
                      );
 | 
						|
      if (EFI_ERROR(Status)) {
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
 | 
						|
      ImageInfoSize = 0;
 | 
						|
      Status = Fmp->GetImageInfo (
 | 
						|
                      Fmp,
 | 
						|
                      &ImageInfoSize,
 | 
						|
                      NULL,
 | 
						|
                      NULL,
 | 
						|
                      NULL,
 | 
						|
                      NULL,
 | 
						|
                      NULL,
 | 
						|
                      NULL
 | 
						|
                      );
 | 
						|
      if (Status != EFI_BUFFER_TOO_SMALL) {
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
 | 
						|
      FmpImageInfoBuf = NULL;
 | 
						|
      FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);
 | 
						|
      if (FmpImageInfoBuf == NULL) {
 | 
						|
        Status = EFI_OUT_OF_RESOURCES;
 | 
						|
        goto EXIT;
 | 
						|
      }
 | 
						|
 | 
						|
      PackageVersionName = NULL;
 | 
						|
      Status = Fmp->GetImageInfo (
 | 
						|
                      Fmp,
 | 
						|
                      &ImageInfoSize,               // ImageInfoSize
 | 
						|
                      FmpImageInfoBuf,              // ImageInfo
 | 
						|
                      &FmpImageInfoDescriptorVer,   // DescriptorVersion
 | 
						|
                      &FmpImageInfoCount,           // DescriptorCount
 | 
						|
                      &DescriptorSize,              // DescriptorSize
 | 
						|
                      &PackageVersion,              // PackageVersion
 | 
						|
                      &PackageVersionName           // PackageVersionName
 | 
						|
                      );
 | 
						|
 | 
						|
      //
 | 
						|
      // If FMP GetInformation interface failed, skip this resource
 | 
						|
      //
 | 
						|
      if (EFI_ERROR(Status)) {
 | 
						|
        FreePool(FmpImageInfoBuf);
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
 | 
						|
      if (PackageVersionName != NULL) {
 | 
						|
        FreePool(PackageVersionName);
 | 
						|
      }
 | 
						|
 | 
						|
      TempFmpImageInfo = FmpImageInfoBuf;
 | 
						|
      for (Index2 = 0; Index2 < FmpImageInfoCount; Index2++) {
 | 
						|
        //
 | 
						|
        // Check all the payload entry in capsule payload list 
 | 
						|
        //
 | 
						|
        for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < ItemNum; Index++) {
 | 
						|
          ImageHeader  = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);
 | 
						|
          if (CompareGuid(&ImageHeader->UpdateImageTypeId, &TempFmpImageInfo->ImageTypeId) &&
 | 
						|
              ImageHeader->UpdateImageIndex == TempFmpImageInfo->ImageIndex) {
 | 
						|
            AbortReason = NULL;
 | 
						|
            if (ImageHeader->UpdateVendorCodeSize == 0) {
 | 
						|
              Status = Fmp->SetImage(
 | 
						|
                              Fmp,
 | 
						|
                              TempFmpImageInfo->ImageIndex,           // ImageIndex
 | 
						|
                              (UINT8 *)(ImageHeader + 1),             // Image
 | 
						|
                              ImageHeader->UpdateImageSize,           // ImageSize
 | 
						|
                              NULL,                                   // VendorCode
 | 
						|
                              Update_Image_Progress,                  // Progress
 | 
						|
                              &AbortReason                            // AbortReason
 | 
						|
                              );
 | 
						|
            } else {
 | 
						|
              Status = Fmp->SetImage(
 | 
						|
                              Fmp,
 | 
						|
                              TempFmpImageInfo->ImageIndex,                                          // ImageIndex
 | 
						|
                              (UINT8 *)(ImageHeader + 1),                                            // Image
 | 
						|
                              ImageHeader->UpdateImageSize,                                          // ImageSize
 | 
						|
                              (UINT8 *)((UINT8 *) (ImageHeader + 1) + ImageHeader->UpdateImageSize), // VendorCode
 | 
						|
                              Update_Image_Progress,                                                 // Progress
 | 
						|
                              &AbortReason                                                           // AbortReason
 | 
						|
                              );
 | 
						|
            }
 | 
						|
            if (AbortReason != NULL) {
 | 
						|
              DEBUG ((EFI_D_ERROR, "%s\n", AbortReason));
 | 
						|
              FreePool(AbortReason);
 | 
						|
            }
 | 
						|
          }
 | 
						|
        }
 | 
						|
        //
 | 
						|
        // Use DescriptorSize to move ImageInfo Pointer to stay compatible with different ImageInfo version
 | 
						|
        //
 | 
						|
        TempFmpImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)TempFmpImageInfo + DescriptorSize);
 | 
						|
      }
 | 
						|
      FreePool(FmpImageInfoBuf);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
EXIT:
 | 
						|
 | 
						|
  if (HandleBuffer != NULL) {
 | 
						|
    FreePool(HandleBuffer);
 | 
						|
  }
 | 
						|
 | 
						|
  if (DriverDevicePath != NULL) {
 | 
						|
    FreePool(DriverDevicePath);
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Those capsules supported by the firmwares.
 | 
						|
 | 
						|
  @param  CapsuleHeader    Points to a capsule header.
 | 
						|
 | 
						|
  @retval EFI_SUCESS       Input capsule is supported by firmware.
 | 
						|
  @retval EFI_UNSUPPORTED  Input capsule is not supported by the firmware.
 | 
						|
  @retval EFI_INVALID_PARAMETER Input capsule layout is not correct
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
SupportCapsuleImage (
 | 
						|
  IN EFI_CAPSULE_HEADER *CapsuleHeader
 | 
						|
  )
 | 
						|
{
 | 
						|
  if (CompareGuid (&gEfiCapsuleGuid, &CapsuleHeader->CapsuleGuid)) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  if (CompareGuid (&gEfiFmpCapsuleGuid, &CapsuleHeader->CapsuleGuid)) {
 | 
						|
    //
 | 
						|
    // Check layout of FMP capsule
 | 
						|
    //
 | 
						|
    return ValidateFmpCapsule(CapsuleHeader);
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_UNSUPPORTED;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  The firmware implements to process the capsule image.
 | 
						|
 | 
						|
  @param  CapsuleHeader         Points to a capsule header.
 | 
						|
 | 
						|
  @retval EFI_SUCESS            Process Capsule Image successfully.
 | 
						|
  @retval EFI_UNSUPPORTED       Capsule image is not supported by the firmware.
 | 
						|
  @retval EFI_VOLUME_CORRUPTED  FV volume in the capsule is corrupted.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  Not enough memory.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
ProcessCapsuleImage (
 | 
						|
  IN EFI_CAPSULE_HEADER *CapsuleHeader
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT32                       Length;
 | 
						|
  EFI_FIRMWARE_VOLUME_HEADER   *FvImage;
 | 
						|
  EFI_FIRMWARE_VOLUME_HEADER   *ProcessedFvImage;
 | 
						|
  EFI_STATUS                   Status;
 | 
						|
  EFI_HANDLE                   FvProtocolHandle;
 | 
						|
  UINT32                       FvAlignment;
 | 
						|
 | 
						|
  FvImage = NULL;
 | 
						|
  ProcessedFvImage = NULL;
 | 
						|
  Status  = EFI_SUCCESS;
 | 
						|
 | 
						|
  if (SupportCapsuleImage (CapsuleHeader) != EFI_SUCCESS) {
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check FMP capsule layout
 | 
						|
  //
 | 
						|
  if (CompareGuid (&gEfiFmpCapsuleGuid, &CapsuleHeader->CapsuleGuid)){
 | 
						|
    Status = ValidateFmpCapsule(CapsuleHeader);
 | 
						|
    if (EFI_ERROR(Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Press EFI FMP Capsule
 | 
						|
    //
 | 
						|
    return ProcessFmpCapsuleImage(CapsuleHeader);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Skip the capsule header, move to the Firware Volume
 | 
						|
  //
 | 
						|
  FvImage = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize);
 | 
						|
  Length  = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize;
 | 
						|
 | 
						|
  while (Length != 0) {
 | 
						|
    //
 | 
						|
    // Point to the next firmware volume header, and then
 | 
						|
    // call the DXE service to process it.
 | 
						|
    //
 | 
						|
    if (FvImage->FvLength > (UINTN) Length) {
 | 
						|
      //
 | 
						|
      // Notes: need to stuff this status somewhere so that the
 | 
						|
      // error can be detected at OS runtime
 | 
						|
      //
 | 
						|
      Status = EFI_VOLUME_CORRUPTED;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    FvAlignment = 1 << ((FvImage->Attributes & EFI_FVB2_ALIGNMENT) >> 16);
 | 
						|
    //
 | 
						|
    // FvAlignment must be more than 8 bytes required by FvHeader structure.
 | 
						|
    //
 | 
						|
    if (FvAlignment < 8) {
 | 
						|
      FvAlignment = 8;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // Check FvImage Align is required.
 | 
						|
    //
 | 
						|
    if (((UINTN) FvImage % FvAlignment) == 0) {
 | 
						|
      ProcessedFvImage = FvImage;
 | 
						|
    } else {
 | 
						|
      //
 | 
						|
      // Allocate new aligned buffer to store FvImage.
 | 
						|
      //
 | 
						|
      ProcessedFvImage = (EFI_FIRMWARE_VOLUME_HEADER *) AllocateAlignedPages ((UINTN) EFI_SIZE_TO_PAGES ((UINTN) FvImage->FvLength), (UINTN) FvAlignment);
 | 
						|
      if (ProcessedFvImage == NULL) {
 | 
						|
        Status = EFI_OUT_OF_RESOURCES;
 | 
						|
        break;
 | 
						|
      }
 | 
						|
      CopyMem (ProcessedFvImage, FvImage, (UINTN) FvImage->FvLength);
 | 
						|
    }
 | 
						|
 | 
						|
    Status = gDS->ProcessFirmwareVolume (
 | 
						|
                  (VOID *) ProcessedFvImage,
 | 
						|
                  (UINTN) ProcessedFvImage->FvLength,
 | 
						|
                  &FvProtocolHandle
 | 
						|
                  );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // Call the dispatcher to dispatch any drivers from the produced firmware volume
 | 
						|
    //
 | 
						|
    gDS->Dispatch ();
 | 
						|
    //
 | 
						|
    // On to the next FV in the capsule
 | 
						|
    //
 | 
						|
    Length -= (UINT32) FvImage->FvLength;
 | 
						|
    FvImage = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINT8 *) FvImage + FvImage->FvLength);
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 |