REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3737 Apply uncrustify changes to .c/.h files in the MdeModulePkg package Cc: Andrew Fish <afish@apple.com> Cc: Leif Lindholm <leif@nuviainc.com> Cc: Michael D Kinney <michael.d.kinney@intel.com> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com> Reviewed-by: Liming Gao <gaoliming@byosoft.com.cn>
		
			
				
	
	
		
			1048 lines
		
	
	
		
			31 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1048 lines
		
	
	
		
			31 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  A shell application that triggers capsule update process.
 | 
						|
 | 
						|
  Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
 | 
						|
  SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include "CapsuleApp.h"
 | 
						|
 | 
						|
//
 | 
						|
// Define how many block descriptors we want to test with.
 | 
						|
//
 | 
						|
UINTN  NumberOfDescriptors = 1;
 | 
						|
UINTN  CapsuleFirstIndex;
 | 
						|
UINTN  CapsuleLastIndex;
 | 
						|
 | 
						|
/**
 | 
						|
  Create UX capsule.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The capsule header is appended.
 | 
						|
  @retval EFI_UNSUPPORTED        Input parameter is not valid.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES   No enough resource to create UX capsule.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
CreateBmpFmp (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  CHAR16                                *OutputCapsuleName;
 | 
						|
  VOID                                  *BmpBuffer;
 | 
						|
  UINTN                                 FileSize;
 | 
						|
  CHAR16                                *BmpName;
 | 
						|
  UINT8                                 *FullCapsuleBuffer;
 | 
						|
  UINTN                                 FullCapsuleBufferSize;
 | 
						|
  EFI_DISPLAY_CAPSULE                   *DisplayCapsule;
 | 
						|
  EFI_STATUS                            Status;
 | 
						|
  EFI_GRAPHICS_OUTPUT_PROTOCOL          *Gop;
 | 
						|
  EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  *Info;
 | 
						|
  EFI_GRAPHICS_OUTPUT_BLT_PIXEL         *GopBlt;
 | 
						|
  UINTN                                 GopBltSize;
 | 
						|
  UINTN                                 Height;
 | 
						|
  UINTN                                 Width;
 | 
						|
 | 
						|
  Status = gBS->LocateProtocol (&gEfiGraphicsOutputProtocolGuid, NULL, (VOID **)&Gop);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    Print (L"CapsuleApp: NO GOP is found.\n");
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  Info = Gop->Mode->Info;
 | 
						|
  Print (L"Current GOP: Mode - %d, ", Gop->Mode->Mode);
 | 
						|
  Print (L"HorizontalResolution - %d, ", Info->HorizontalResolution);
 | 
						|
  Print (L"VerticalResolution - %d\n", Info->VerticalResolution);
 | 
						|
  // HorizontalResolution >= BMP_IMAGE_HEADER.PixelWidth
 | 
						|
  // VerticalResolution   >= BMP_IMAGE_HEADER.PixelHeight
 | 
						|
 | 
						|
  if (Argc != 5) {
 | 
						|
    Print (L"CapsuleApp: Incorrect parameter count.\n");
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  if (StrCmp (Argv[3], L"-O") != 0) {
 | 
						|
    Print (L"CapsuleApp: NO output capsule name.\n");
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  OutputCapsuleName = Argv[4];
 | 
						|
 | 
						|
  BmpBuffer         = NULL;
 | 
						|
  FileSize          = 0;
 | 
						|
  FullCapsuleBuffer = NULL;
 | 
						|
 | 
						|
  BmpName = Argv[2];
 | 
						|
  Status  = ReadFileToBuffer (BmpName, &FileSize, &BmpBuffer);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    Print (L"CapsuleApp: BMP image (%s) is not found.\n", BmpName);
 | 
						|
    goto Done;
 | 
						|
  }
 | 
						|
 | 
						|
  GopBlt = NULL;
 | 
						|
  Status = TranslateBmpToGopBlt (
 | 
						|
             BmpBuffer,
 | 
						|
             FileSize,
 | 
						|
             &GopBlt,
 | 
						|
             &GopBltSize,
 | 
						|
             &Height,
 | 
						|
             &Width
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    Print (L"CapsuleApp: BMP image (%s) is not valid.\n", BmpName);
 | 
						|
    goto Done;
 | 
						|
  }
 | 
						|
 | 
						|
  if (GopBlt != NULL) {
 | 
						|
    FreePool (GopBlt);
 | 
						|
  }
 | 
						|
 | 
						|
  Print (L"BMP image (%s), Width - %d, Height - %d\n", BmpName, Width, Height);
 | 
						|
 | 
						|
  if (Height > Info->VerticalResolution) {
 | 
						|
    Status = EFI_INVALID_PARAMETER;
 | 
						|
    Print (L"CapsuleApp: BMP image (%s) height is larger than current resolution.\n", BmpName);
 | 
						|
    goto Done;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Width > Info->HorizontalResolution) {
 | 
						|
    Status = EFI_INVALID_PARAMETER;
 | 
						|
    Print (L"CapsuleApp: BMP image (%s) width is larger than current resolution.\n", BmpName);
 | 
						|
    goto Done;
 | 
						|
  }
 | 
						|
 | 
						|
  FullCapsuleBufferSize = sizeof (EFI_DISPLAY_CAPSULE) + FileSize;
 | 
						|
  FullCapsuleBuffer     = AllocatePool (FullCapsuleBufferSize);
 | 
						|
  if (FullCapsuleBuffer == NULL) {
 | 
						|
    Print (L"CapsuleApp: Capsule Buffer size (0x%x) too big.\n", FullCapsuleBufferSize);
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto Done;
 | 
						|
  }
 | 
						|
 | 
						|
  DisplayCapsule = (EFI_DISPLAY_CAPSULE *)FullCapsuleBuffer;
 | 
						|
  CopyGuid (&DisplayCapsule->CapsuleHeader.CapsuleGuid, &gWindowsUxCapsuleGuid);
 | 
						|
  DisplayCapsule->CapsuleHeader.HeaderSize       = sizeof (DisplayCapsule->CapsuleHeader);
 | 
						|
  DisplayCapsule->CapsuleHeader.Flags            = CAPSULE_FLAGS_PERSIST_ACROSS_RESET;
 | 
						|
  DisplayCapsule->CapsuleHeader.CapsuleImageSize = (UINT32)FullCapsuleBufferSize;
 | 
						|
 | 
						|
  DisplayCapsule->ImagePayload.Version   = 1;
 | 
						|
  DisplayCapsule->ImagePayload.Checksum  = 0;
 | 
						|
  DisplayCapsule->ImagePayload.ImageType = 0; // BMP
 | 
						|
  DisplayCapsule->ImagePayload.Reserved  = 0;
 | 
						|
  DisplayCapsule->ImagePayload.Mode      = Gop->Mode->Mode;
 | 
						|
 | 
						|
  //
 | 
						|
  // Center the bitmap horizontally
 | 
						|
  //
 | 
						|
  DisplayCapsule->ImagePayload.OffsetX = (UINT32)((Info->HorizontalResolution - Width) / 2);
 | 
						|
 | 
						|
  //
 | 
						|
  // Put bitmap 3/4 down the display.  If bitmap is too tall, then align bottom
 | 
						|
  // of bitmap at bottom of display.
 | 
						|
  //
 | 
						|
  DisplayCapsule->ImagePayload.OffsetY =
 | 
						|
    MIN (
 | 
						|
      (UINT32)(Info->VerticalResolution - Height),
 | 
						|
      (UINT32)(((3 * Info->VerticalResolution) - (2 * Height)) / 4)
 | 
						|
      );
 | 
						|
 | 
						|
  Print (
 | 
						|
    L"BMP image (%s), OffsetX - %d, OffsetY - %d\n",
 | 
						|
    BmpName,
 | 
						|
    DisplayCapsule->ImagePayload.OffsetX,
 | 
						|
    DisplayCapsule->ImagePayload.OffsetY
 | 
						|
    );
 | 
						|
 | 
						|
  CopyMem ((DisplayCapsule + 1), BmpBuffer, FileSize);
 | 
						|
 | 
						|
  DisplayCapsule->ImagePayload.Checksum = CalculateCheckSum8 (FullCapsuleBuffer, FullCapsuleBufferSize);
 | 
						|
 | 
						|
  Status = WriteFileFromBuffer (OutputCapsuleName, FullCapsuleBufferSize, FullCapsuleBuffer);
 | 
						|
  Print (L"CapsuleApp: Write %s %r\n", OutputCapsuleName, Status);
 | 
						|
 | 
						|
Done:
 | 
						|
  if (BmpBuffer != NULL) {
 | 
						|
    FreePool (BmpBuffer);
 | 
						|
  }
 | 
						|
 | 
						|
  if (FullCapsuleBuffer != NULL) {
 | 
						|
    FreePool (FullCapsuleBuffer);
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Get ImageTypeId in the FMP capsule header.
 | 
						|
 | 
						|
  @param[in] CapsuleHeader  The FMP capsule image header.
 | 
						|
 | 
						|
  @return ImageTypeId
 | 
						|
**/
 | 
						|
EFI_GUID *
 | 
						|
GetCapsuleImageTypeId (
 | 
						|
  IN EFI_CAPSULE_HEADER  *CapsuleHeader
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER        *FmpCapsuleHeader;
 | 
						|
  UINT64                                        *ItemOffsetList;
 | 
						|
  EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER  *ImageHeader;
 | 
						|
 | 
						|
  FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);
 | 
						|
  ItemOffsetList   = (UINT64 *)(FmpCapsuleHeader + 1);
 | 
						|
  if (FmpCapsuleHeader->PayloadItemCount == 0) {
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[FmpCapsuleHeader->EmbeddedDriverCount]);
 | 
						|
  return &ImageHeader->UpdateImageTypeId;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Get ESRT FwType according to ImageTypeId
 | 
						|
 | 
						|
  @param[in]  ImageTypeId   ImageTypeId of an FMP capsule.
 | 
						|
 | 
						|
  @return ESRT FwType
 | 
						|
**/
 | 
						|
UINT32
 | 
						|
GetEsrtFwType (
 | 
						|
  IN  EFI_GUID  *ImageTypeId
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                 Status;
 | 
						|
  EFI_SYSTEM_RESOURCE_TABLE  *Esrt;
 | 
						|
  EFI_SYSTEM_RESOURCE_ENTRY  *EsrtEntry;
 | 
						|
  UINTN                      Index;
 | 
						|
 | 
						|
  //
 | 
						|
  // Check ESRT
 | 
						|
  //
 | 
						|
  Status = EfiGetSystemConfigurationTable (&gEfiSystemResourceTableGuid, (VOID **)&Esrt);
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    ASSERT (Esrt != NULL);
 | 
						|
    EsrtEntry = (VOID *)(Esrt + 1);
 | 
						|
    for (Index = 0; Index < Esrt->FwResourceCount; Index++, EsrtEntry++) {
 | 
						|
      if (CompareGuid (&EsrtEntry->FwClass, ImageTypeId)) {
 | 
						|
        return EsrtEntry->FwType;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return ESRT_FW_TYPE_UNKNOWN;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Validate if it is valid capsule header
 | 
						|
 | 
						|
  This function assumes the caller provided correct CapsuleHeader pointer
 | 
						|
  and CapsuleSize.
 | 
						|
 | 
						|
  This function validates the fields in EFI_CAPSULE_HEADER.
 | 
						|
 | 
						|
  @param[in] CapsuleHeader  Points to a capsule header.
 | 
						|
  @param[in] CapsuleSize    Size of the whole capsule image.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
IsValidCapsuleHeader (
 | 
						|
  IN EFI_CAPSULE_HEADER  *CapsuleHeader,
 | 
						|
  IN UINT64              CapsuleSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  if (CapsuleSize < sizeof (EFI_CAPSULE_HEADER)) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  if (CapsuleHeader->CapsuleImageSize != CapsuleSize) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  if (CapsuleHeader->HeaderSize > CapsuleHeader->CapsuleImageSize) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  if (CapsuleHeader->HeaderSize < sizeof (EFI_CAPSULE_HEADER)) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Return if this CapsuleGuid is a FMP capsule GUID or not.
 | 
						|
 | 
						|
  @param[in] CapsuleGuid A pointer to EFI_GUID
 | 
						|
 | 
						|
  @retval TRUE  It is a FMP capsule GUID.
 | 
						|
  @retval FALSE It is not a FMP capsule GUID.
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
IsFmpCapsuleGuid (
 | 
						|
  IN EFI_GUID  *CapsuleGuid
 | 
						|
  )
 | 
						|
{
 | 
						|
  if (CompareGuid (&gEfiFmpCapsuleGuid, CapsuleGuid)) {
 | 
						|
    return TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Append a capsule header on top of current image.
 | 
						|
  This function follows Windows UEFI Firmware Update Platform document.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The capsule header is appended.
 | 
						|
  @retval EFI_UNSUPPORTED        Input parameter is not valid.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES   No enough resource to append capsule header.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
CreateNestedFmp (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  CHAR16              *OutputCapsuleName;
 | 
						|
  VOID                *CapsuleBuffer;
 | 
						|
  UINTN               FileSize;
 | 
						|
  CHAR16              *CapsuleName;
 | 
						|
  UINT8               *FullCapsuleBuffer;
 | 
						|
  UINTN               FullCapsuleBufferSize;
 | 
						|
  EFI_CAPSULE_HEADER  *NestedCapsuleHeader;
 | 
						|
  EFI_GUID            *ImageTypeId;
 | 
						|
  UINT32              FwType;
 | 
						|
  EFI_STATUS          Status;
 | 
						|
 | 
						|
  if (Argc != 5) {
 | 
						|
    Print (L"CapsuleApp: Incorrect parameter count.\n");
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  if (StrCmp (Argv[3], L"-O") != 0) {
 | 
						|
    Print (L"CapsuleApp: NO output capsule name.\n");
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  OutputCapsuleName = Argv[4];
 | 
						|
 | 
						|
  CapsuleBuffer     = NULL;
 | 
						|
  FileSize          = 0;
 | 
						|
  FullCapsuleBuffer = NULL;
 | 
						|
 | 
						|
  CapsuleName = Argv[2];
 | 
						|
  Status      = ReadFileToBuffer (CapsuleName, &FileSize, &CapsuleBuffer);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    Print (L"CapsuleApp: Capsule image (%s) is not found.\n", CapsuleName);
 | 
						|
    goto Done;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!IsValidCapsuleHeader (CapsuleBuffer, FileSize)) {
 | 
						|
    Print (L"CapsuleApp: Capsule image (%s) is not a valid capsule.\n", CapsuleName);
 | 
						|
    Status = EFI_INVALID_PARAMETER;
 | 
						|
    goto Done;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!IsFmpCapsuleGuid (&((EFI_CAPSULE_HEADER *)CapsuleBuffer)->CapsuleGuid)) {
 | 
						|
    Print (L"CapsuleApp: Capsule image (%s) is not a FMP capsule.\n", CapsuleName);
 | 
						|
    Status = EFI_INVALID_PARAMETER;
 | 
						|
    goto Done;
 | 
						|
  }
 | 
						|
 | 
						|
  ImageTypeId = GetCapsuleImageTypeId (CapsuleBuffer);
 | 
						|
  if (ImageTypeId == NULL) {
 | 
						|
    Print (L"CapsuleApp: Capsule ImageTypeId is not found.\n");
 | 
						|
    Status = EFI_INVALID_PARAMETER;
 | 
						|
    goto Done;
 | 
						|
  }
 | 
						|
 | 
						|
  FwType = GetEsrtFwType (ImageTypeId);
 | 
						|
  if ((FwType != ESRT_FW_TYPE_SYSTEMFIRMWARE) && (FwType != ESRT_FW_TYPE_DEVICEFIRMWARE)) {
 | 
						|
    Print (L"CapsuleApp: Capsule FwType is invalid.\n");
 | 
						|
    Status = EFI_INVALID_PARAMETER;
 | 
						|
    goto Done;
 | 
						|
  }
 | 
						|
 | 
						|
  FullCapsuleBufferSize = NESTED_CAPSULE_HEADER_SIZE + FileSize;
 | 
						|
  FullCapsuleBuffer     = AllocatePool (FullCapsuleBufferSize);
 | 
						|
  if (FullCapsuleBuffer == NULL) {
 | 
						|
    Print (L"CapsuleApp: Capsule Buffer size (0x%x) too big.\n", FullCapsuleBufferSize);
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto Done;
 | 
						|
  }
 | 
						|
 | 
						|
  NestedCapsuleHeader = (EFI_CAPSULE_HEADER *)FullCapsuleBuffer;
 | 
						|
  ZeroMem (NestedCapsuleHeader, NESTED_CAPSULE_HEADER_SIZE);
 | 
						|
  CopyGuid (&NestedCapsuleHeader->CapsuleGuid, ImageTypeId);
 | 
						|
  NestedCapsuleHeader->HeaderSize       = NESTED_CAPSULE_HEADER_SIZE;
 | 
						|
  NestedCapsuleHeader->Flags            = (FwType == ESRT_FW_TYPE_SYSTEMFIRMWARE) ? SYSTEM_FIRMWARE_FLAG : DEVICE_FIRMWARE_FLAG;
 | 
						|
  NestedCapsuleHeader->CapsuleImageSize = (UINT32)FullCapsuleBufferSize;
 | 
						|
 | 
						|
  CopyMem ((UINT8 *)NestedCapsuleHeader + NestedCapsuleHeader->HeaderSize, CapsuleBuffer, FileSize);
 | 
						|
 | 
						|
  Status = WriteFileFromBuffer (OutputCapsuleName, FullCapsuleBufferSize, FullCapsuleBuffer);
 | 
						|
  Print (L"CapsuleApp: Write %s %r\n", OutputCapsuleName, Status);
 | 
						|
 | 
						|
Done:
 | 
						|
  if (CapsuleBuffer != NULL) {
 | 
						|
    FreePool (CapsuleBuffer);
 | 
						|
  }
 | 
						|
 | 
						|
  if (FullCapsuleBuffer != NULL) {
 | 
						|
    FreePool (FullCapsuleBuffer);
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Clear capsule status variable.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The capsule status variable is cleared.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
ClearCapsuleStatusVariable (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  UINT32      Index;
 | 
						|
  CHAR16      CapsuleVarName[20];
 | 
						|
  CHAR16      *TempVarName;
 | 
						|
  BOOLEAN     Found;
 | 
						|
 | 
						|
  StrCpyS (CapsuleVarName, sizeof (CapsuleVarName)/sizeof (CapsuleVarName[0]), L"Capsule");
 | 
						|
  TempVarName = CapsuleVarName + StrLen (CapsuleVarName);
 | 
						|
  Index       = 0;
 | 
						|
 | 
						|
  Found = FALSE;
 | 
						|
  while (TRUE) {
 | 
						|
    UnicodeSPrint (TempVarName, 5 * sizeof (CHAR16), L"%04x", Index);
 | 
						|
 | 
						|
    Status = gRT->SetVariable (
 | 
						|
                    CapsuleVarName,
 | 
						|
                    &gEfiCapsuleReportGuid,
 | 
						|
                    EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
 | 
						|
                    0,
 | 
						|
                    (VOID *)NULL
 | 
						|
                    );
 | 
						|
    if (Status == EFI_NOT_FOUND) {
 | 
						|
      //
 | 
						|
      // There is no more capsule variables, quit
 | 
						|
      //
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    Found = TRUE;
 | 
						|
 | 
						|
    Print (L"Clear %s %r\n", CapsuleVarName, Status);
 | 
						|
 | 
						|
    Index++;
 | 
						|
    if (Index > 0xFFFF) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (!Found) {
 | 
						|
    Print (L"No any Capsule#### variable found\n");
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Build Gather list for a list of capsule images.
 | 
						|
 | 
						|
  @param[in]  CapsuleBuffer    An array of pointer to capsule images
 | 
						|
  @param[in]  FileSize         An array of UINTN to capsule images size
 | 
						|
  @param[in]  CapsuleNum       The count of capsule images
 | 
						|
  @param[out] BlockDescriptors The block descriptors for the capsule images
 | 
						|
 | 
						|
  @retval EFI_SUCCESS The block descriptors for the capsule images are constructed.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
BuildGatherList (
 | 
						|
  IN VOID                           **CapsuleBuffer,
 | 
						|
  IN UINTN                          *FileSize,
 | 
						|
  IN UINTN                          CapsuleNum,
 | 
						|
  OUT EFI_CAPSULE_BLOCK_DESCRIPTOR  **BlockDescriptors
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                    Status;
 | 
						|
  EFI_CAPSULE_BLOCK_DESCRIPTOR  *BlockDescriptors1;
 | 
						|
  EFI_CAPSULE_BLOCK_DESCRIPTOR  *BlockDescriptors2;
 | 
						|
  EFI_CAPSULE_BLOCK_DESCRIPTOR  *BlockDescriptorPre;
 | 
						|
  EFI_CAPSULE_BLOCK_DESCRIPTOR  *BlockDescriptorsHeader;
 | 
						|
  EFI_CAPSULE_BLOCK_DESCRIPTOR  *TempBlockPtr;
 | 
						|
  UINT8                         *TempDataPtr;
 | 
						|
  UINTN                         SizeLeft;
 | 
						|
  UINTN                         Size;
 | 
						|
  INT32                         Count;
 | 
						|
  INT32                         Number;
 | 
						|
  UINTN                         Index;
 | 
						|
 | 
						|
  TempBlockPtr           = NULL;
 | 
						|
  BlockDescriptors1      = NULL;
 | 
						|
  BlockDescriptors2      = NULL;
 | 
						|
  BlockDescriptorPre     = NULL;
 | 
						|
  BlockDescriptorsHeader = NULL;
 | 
						|
 | 
						|
  for (Index = 0; Index < CapsuleNum; Index++) {
 | 
						|
    //
 | 
						|
    // Allocate memory for the descriptors.
 | 
						|
    //
 | 
						|
    if (NumberOfDescriptors == 1) {
 | 
						|
      Count = 2;
 | 
						|
    } else {
 | 
						|
      Count = (INT32)(NumberOfDescriptors + 2) / 2;
 | 
						|
    }
 | 
						|
 | 
						|
    Size              = Count * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);
 | 
						|
    BlockDescriptors1 = AllocateRuntimeZeroPool (Size);
 | 
						|
    if (BlockDescriptors1 == NULL) {
 | 
						|
      Print (L"CapsuleApp: failed to allocate memory for descriptors\n");
 | 
						|
      Status = EFI_OUT_OF_RESOURCES;
 | 
						|
      goto ERREXIT;
 | 
						|
    } else {
 | 
						|
      Print (L"CapsuleApp: creating capsule descriptors at 0x%X\n", (UINTN)BlockDescriptors1);
 | 
						|
      Print (L"CapsuleApp: capsule data starts          at 0x%X with size 0x%X\n", (UINTN)CapsuleBuffer[Index], FileSize[Index]);
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Record descriptor header
 | 
						|
    //
 | 
						|
    if (Index == 0) {
 | 
						|
      BlockDescriptorsHeader = BlockDescriptors1;
 | 
						|
    }
 | 
						|
 | 
						|
    if (BlockDescriptorPre != NULL) {
 | 
						|
      BlockDescriptorPre->Union.ContinuationPointer = (UINTN)BlockDescriptors1;
 | 
						|
      BlockDescriptorPre->Length                    = 0;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Fill them in
 | 
						|
    //
 | 
						|
    TempBlockPtr = BlockDescriptors1;
 | 
						|
    TempDataPtr  = CapsuleBuffer[Index];
 | 
						|
    SizeLeft     = FileSize[Index];
 | 
						|
    for (Number = 0; (Number < Count - 1) && (SizeLeft != 0); Number++) {
 | 
						|
      //
 | 
						|
      // Divide remaining data in half
 | 
						|
      //
 | 
						|
      if (NumberOfDescriptors != 1) {
 | 
						|
        if (SizeLeft == 1) {
 | 
						|
          Size = 1;
 | 
						|
        } else {
 | 
						|
          Size = SizeLeft / 2;
 | 
						|
        }
 | 
						|
      } else {
 | 
						|
        Size = SizeLeft;
 | 
						|
      }
 | 
						|
 | 
						|
      TempBlockPtr->Union.DataBlock = (UINTN)TempDataPtr;
 | 
						|
      TempBlockPtr->Length          = Size;
 | 
						|
      Print (L"CapsuleApp: capsule block/size              0x%X/0x%X\n", (UINTN)TempDataPtr, Size);
 | 
						|
      SizeLeft    -= Size;
 | 
						|
      TempDataPtr += Size;
 | 
						|
      TempBlockPtr++;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Allocate the second list, point the first block's last entry to point
 | 
						|
    // to this one, and fill this one in. Worst case is that the previous
 | 
						|
    // list only had one element that pointed here, so we need at least two
 | 
						|
    // elements -- one to point to all the data, another to terminate the list.
 | 
						|
    //
 | 
						|
    if ((NumberOfDescriptors != 1) && (SizeLeft != 0)) {
 | 
						|
      Count = (INT32)(NumberOfDescriptors + 2) - Count;
 | 
						|
      if (Count == 1) {
 | 
						|
        Count++;
 | 
						|
      }
 | 
						|
 | 
						|
      Size              = Count * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);
 | 
						|
      BlockDescriptors2 = AllocateRuntimeZeroPool (Size);
 | 
						|
      if (BlockDescriptors2 == NULL) {
 | 
						|
        Print (L"CapsuleApp: failed to allocate memory for descriptors\n");
 | 
						|
        Status = EFI_OUT_OF_RESOURCES;
 | 
						|
        goto ERREXIT;
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      // Point the first list's last element to point to this second list.
 | 
						|
      //
 | 
						|
      TempBlockPtr->Union.ContinuationPointer = (UINTN)BlockDescriptors2;
 | 
						|
 | 
						|
      TempBlockPtr->Length = 0;
 | 
						|
      TempBlockPtr         = BlockDescriptors2;
 | 
						|
      for (Number = 0; Number < Count - 1; Number++) {
 | 
						|
        //
 | 
						|
        // If second-to-last one, then dump rest to this element
 | 
						|
        //
 | 
						|
        if (Number == (Count - 2)) {
 | 
						|
          Size = SizeLeft;
 | 
						|
        } else {
 | 
						|
          //
 | 
						|
          // Divide remaining data in half
 | 
						|
          //
 | 
						|
          if (SizeLeft == 1) {
 | 
						|
            Size = 1;
 | 
						|
          } else {
 | 
						|
            Size = SizeLeft / 2;
 | 
						|
          }
 | 
						|
        }
 | 
						|
 | 
						|
        TempBlockPtr->Union.DataBlock = (UINTN)TempDataPtr;
 | 
						|
        TempBlockPtr->Length          = Size;
 | 
						|
        Print (L"CapsuleApp: capsule block/size              0x%X/0x%X\n", (UINTN)TempDataPtr, Size);
 | 
						|
        SizeLeft    -= Size;
 | 
						|
        TempDataPtr += Size;
 | 
						|
        TempBlockPtr++;
 | 
						|
        if (SizeLeft == 0) {
 | 
						|
          break;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    BlockDescriptorPre = TempBlockPtr;
 | 
						|
    BlockDescriptors1  = NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Null-terminate.
 | 
						|
  //
 | 
						|
  if (TempBlockPtr != NULL) {
 | 
						|
    TempBlockPtr->Union.ContinuationPointer = (UINTN)NULL;
 | 
						|
    TempBlockPtr->Length                    = 0;
 | 
						|
    *BlockDescriptors                       = BlockDescriptorsHeader;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
 | 
						|
ERREXIT:
 | 
						|
  if (BlockDescriptors1 != NULL) {
 | 
						|
    FreePool (BlockDescriptors1);
 | 
						|
  }
 | 
						|
 | 
						|
  if (BlockDescriptors2 != NULL) {
 | 
						|
    FreePool (BlockDescriptors2);
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Clear the Gather list for a list of capsule images.
 | 
						|
 | 
						|
  @param[in]  BlockDescriptors The block descriptors for the capsule images
 | 
						|
  @param[in]  CapsuleNum       The count of capsule images
 | 
						|
**/
 | 
						|
VOID
 | 
						|
CleanGatherList (
 | 
						|
  IN EFI_CAPSULE_BLOCK_DESCRIPTOR  *BlockDescriptors,
 | 
						|
  IN UINTN                         CapsuleNum
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_CAPSULE_BLOCK_DESCRIPTOR  *TempBlockPtr;
 | 
						|
  EFI_CAPSULE_BLOCK_DESCRIPTOR  *TempBlockPtr1;
 | 
						|
  EFI_CAPSULE_BLOCK_DESCRIPTOR  *TempBlockPtr2;
 | 
						|
  UINTN                         Index;
 | 
						|
 | 
						|
  if (BlockDescriptors != NULL) {
 | 
						|
    TempBlockPtr1 = BlockDescriptors;
 | 
						|
    while (1) {
 | 
						|
      TempBlockPtr = TempBlockPtr1;
 | 
						|
      for (Index = 0; Index < CapsuleNum; Index++) {
 | 
						|
        if (TempBlockPtr[Index].Length == 0) {
 | 
						|
          break;
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      if (TempBlockPtr[Index].Union.ContinuationPointer == (UINTN)NULL) {
 | 
						|
        break;
 | 
						|
      }
 | 
						|
 | 
						|
      TempBlockPtr2 = (VOID *)((UINTN)TempBlockPtr[Index].Union.ContinuationPointer);
 | 
						|
      FreePool (TempBlockPtr1);
 | 
						|
      TempBlockPtr1 = TempBlockPtr2;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Print APP usage.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
PrintUsage (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  Print (L"CapsuleApp:  usage\n");
 | 
						|
  Print (L"  CapsuleApp <Capsule...> [-NR] [-OD [FSx]]\n");
 | 
						|
  Print (L"  CapsuleApp -S\n");
 | 
						|
  Print (L"  CapsuleApp -C\n");
 | 
						|
  Print (L"  CapsuleApp -P\n");
 | 
						|
  Print (L"  CapsuleApp -E\n");
 | 
						|
  Print (L"  CapsuleApp -L\n");
 | 
						|
  Print (L"  CapsuleApp -L INFO\n");
 | 
						|
  Print (L"  CapsuleApp -F\n");
 | 
						|
  Print (L"  CapsuleApp -G <BMP> -O <Capsule>\n");
 | 
						|
  Print (L"  CapsuleApp -N <Capsule> -O <NestedCapsule>\n");
 | 
						|
  Print (L"  CapsuleApp -D <Capsule>\n");
 | 
						|
  Print (L"  CapsuleApp -P GET <ImageTypeId> <Index> -O <FileName>\n");
 | 
						|
  Print (L"Parameter:\n");
 | 
						|
  Print (L"  -NR: No reset will be triggered for the capsule\n");
 | 
						|
  Print (L"       with CAPSULE_FLAGS_PERSIST_ACROSS_RESET and without CAPSULE_FLAGS_INITIATE_RESET.\n");
 | 
						|
  Print (L"  -OD: Delivery of Capsules via file on Mass Storage device.\n");
 | 
						|
  Print (L"  -S:  Dump capsule report variable (EFI_CAPSULE_REPORT_GUID),\n");
 | 
						|
  Print (L"       which is defined in UEFI specification.\n");
 | 
						|
  Print (L"  -C:  Clear capsule report variable (EFI_CAPSULE_REPORT_GUID),\n");
 | 
						|
  Print (L"       which is defined in UEFI specification.\n");
 | 
						|
  Print (L"  -P:  Dump UEFI FMP protocol info, or get image with specified\n");
 | 
						|
  Print (L"       ImageTypeId and Index (decimal format) to a file if 'GET'\n");
 | 
						|
  Print (L"       option is used.\n");
 | 
						|
  Print (L"  -E:  Dump UEFI ESRT table info.\n");
 | 
						|
  Print (L"  -L:  Dump provisioned capsule image information.\n");
 | 
						|
  Print (L"  -F:  Dump all EFI System Partition.\n");
 | 
						|
  Print (L"  -G:  Convert a BMP file to be an UX capsule,\n");
 | 
						|
  Print (L"       according to Windows Firmware Update document\n");
 | 
						|
  Print (L"  -N:  Append a Capsule Header to an existing FMP capsule image\n");
 | 
						|
  Print (L"       with its ImageTypeId supported by the system,\n");
 | 
						|
  Print (L"       according to Windows Firmware Update document\n");
 | 
						|
  Print (L"  -O:  Output new Capsule file name\n");
 | 
						|
  Print (L"  -D:  Dump Capsule image header information, image payload\n");
 | 
						|
  Print (L"       information if it is an UX capsule and FMP header\n");
 | 
						|
  Print (L"       information if it is a FMP capsule.\n");
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Update Capsule image.
 | 
						|
 | 
						|
  @param[in]  ImageHandle     The image handle.
 | 
						|
  @param[in]  SystemTable     The system table.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            Command completed successfully.
 | 
						|
  @retval EFI_UNSUPPORTED        Command usage unsupported.
 | 
						|
  @retval EFI_INVALID_PARAMETER  Command usage invalid.
 | 
						|
  @retval EFI_NOT_FOUND          The input file can't be found.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UefiMain (
 | 
						|
  IN EFI_HANDLE        ImageHandle,
 | 
						|
  IN EFI_SYSTEM_TABLE  *SystemTable
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                    Status;
 | 
						|
  RETURN_STATUS                 RStatus;
 | 
						|
  UINTN                         CapsuleBufferSize[MAX_CAPSULE_NUM];
 | 
						|
  VOID                          *CapsuleBuffer[MAX_CAPSULE_NUM];
 | 
						|
  EFI_CAPSULE_BLOCK_DESCRIPTOR  *BlockDescriptors;
 | 
						|
  EFI_CAPSULE_HEADER            *CapsuleHeaderArray[MAX_CAPSULE_NUM + 1];
 | 
						|
  UINT64                        MaxCapsuleSize;
 | 
						|
  EFI_RESET_TYPE                ResetType;
 | 
						|
  BOOLEAN                       NeedReset;
 | 
						|
  BOOLEAN                       NoReset;
 | 
						|
  BOOLEAN                       CapsuleOnDisk;
 | 
						|
  CHAR16                        *CapsuleName;
 | 
						|
  CHAR16                        *CapsuleNames[MAX_CAPSULE_NUM];
 | 
						|
  CHAR16                        *MapFsStr;
 | 
						|
  UINTN                         CapsuleNum;
 | 
						|
  UINTN                         Index;
 | 
						|
  UINTN                         ParaOdIndex;
 | 
						|
  UINTN                         ParaNrIndex;
 | 
						|
  EFI_GUID                      ImageTypeId;
 | 
						|
  UINTN                         ImageIndex;
 | 
						|
 | 
						|
  BlockDescriptors = NULL;
 | 
						|
  MapFsStr         = NULL;
 | 
						|
  CapsuleNum       = 0;
 | 
						|
 | 
						|
  Status = GetArg ();
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    Print (L"Please use UEFI SHELL to run this application!\n", Status);
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Argc < 2) {
 | 
						|
    PrintUsage ();
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  if (StrCmp (Argv[1], L"-D") == 0) {
 | 
						|
    if (Argc != 3) {
 | 
						|
      Print (L"CapsuleApp: Incorrect parameter count.\n");
 | 
						|
      return EFI_UNSUPPORTED;
 | 
						|
    }
 | 
						|
 | 
						|
    Status = DumpCapsule (Argv[2]);
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  if (StrCmp (Argv[1], L"-G") == 0) {
 | 
						|
    Status = CreateBmpFmp ();
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  if (StrCmp (Argv[1], L"-N") == 0) {
 | 
						|
    Status = CreateNestedFmp ();
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  if (StrCmp (Argv[1], L"-S") == 0) {
 | 
						|
    Status = DumpCapsuleStatusVariable ();
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  if (StrCmp (Argv[1], L"-C") == 0) {
 | 
						|
    Status = ClearCapsuleStatusVariable ();
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  if (StrCmp (Argv[1], L"-P") == 0) {
 | 
						|
    if (Argc == 2) {
 | 
						|
      DumpFmpData ();
 | 
						|
    }
 | 
						|
 | 
						|
    if (Argc >= 3) {
 | 
						|
      if (StrCmp (Argv[2], L"GET") != 0) {
 | 
						|
        Print (L"CapsuleApp: Unrecognized option(%s).\n", Argv[2]);
 | 
						|
        return EFI_UNSUPPORTED;
 | 
						|
      } else {
 | 
						|
        if (Argc != 7) {
 | 
						|
          Print (L"CapsuleApp: Incorrect parameter count.\n");
 | 
						|
          return EFI_UNSUPPORTED;
 | 
						|
        }
 | 
						|
 | 
						|
        //
 | 
						|
        // FMP->GetImage()
 | 
						|
        //
 | 
						|
        RStatus = StrToGuid (Argv[3], &ImageTypeId);
 | 
						|
        if (RETURN_ERROR (RStatus) || (Argv[3][GUID_STRING_LENGTH] != L'\0')) {
 | 
						|
          Print (L"Invalid ImageTypeId - %s\n", Argv[3]);
 | 
						|
          return EFI_INVALID_PARAMETER;
 | 
						|
        }
 | 
						|
 | 
						|
        ImageIndex = StrDecimalToUintn (Argv[4]);
 | 
						|
        if (StrCmp (Argv[5], L"-O") != 0) {
 | 
						|
          Print (L"CapsuleApp: NO output file name.\n");
 | 
						|
          return EFI_UNSUPPORTED;
 | 
						|
        }
 | 
						|
 | 
						|
        DumpFmpImage (&ImageTypeId, ImageIndex, Argv[6]);
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  if (StrCmp (Argv[1], L"-E") == 0) {
 | 
						|
    DumpEsrtData ();
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  if (StrCmp (Argv[1], L"-L") == 0) {
 | 
						|
    if ((Argc >= 3) && (StrCmp (Argv[2], L"INFO") == 0)) {
 | 
						|
      DumpProvisionedCapsule (TRUE);
 | 
						|
    } else {
 | 
						|
      DumpProvisionedCapsule (FALSE);
 | 
						|
    }
 | 
						|
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  if (StrCmp (Argv[1], L"-F") == 0) {
 | 
						|
    DumpAllEfiSysPartition ();
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Argv[1][0] == L'-') {
 | 
						|
    Print (L"CapsuleApp: Unrecognized option(%s).\n", Argv[1]);
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  CapsuleFirstIndex = 1;
 | 
						|
  NoReset           = FALSE;
 | 
						|
  CapsuleOnDisk     = FALSE;
 | 
						|
  ParaOdIndex       = 0;
 | 
						|
  ParaNrIndex       = 0;
 | 
						|
 | 
						|
  for (Index = 1; Index < Argc; Index++) {
 | 
						|
    if (StrCmp (Argv[Index], L"-OD") == 0) {
 | 
						|
      ParaOdIndex   = Index;
 | 
						|
      CapsuleOnDisk = TRUE;
 | 
						|
    } else if (StrCmp (Argv[Index], L"-NR") == 0) {
 | 
						|
      ParaNrIndex = Index;
 | 
						|
      NoReset     = TRUE;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (ParaOdIndex > ParaNrIndex) {
 | 
						|
    if (ParaNrIndex != 0) {
 | 
						|
      CapsuleLastIndex = ParaNrIndex - 1;
 | 
						|
    } else {
 | 
						|
      CapsuleLastIndex = ParaOdIndex - 1;
 | 
						|
    }
 | 
						|
 | 
						|
    if (ParaOdIndex == Argc -1) {
 | 
						|
      MapFsStr = NULL;
 | 
						|
    } else if (ParaOdIndex == Argc - 2) {
 | 
						|
      MapFsStr = Argv[Argc-1];
 | 
						|
    } else {
 | 
						|
      Print (L"CapsuleApp: Cannot specify more than one FS mapping!\n");
 | 
						|
      Status = EFI_INVALID_PARAMETER;
 | 
						|
      goto Done;
 | 
						|
    }
 | 
						|
  } else if (ParaOdIndex < ParaNrIndex) {
 | 
						|
    if (ParaOdIndex != 0) {
 | 
						|
      CapsuleLastIndex = ParaOdIndex - 1;
 | 
						|
      if (ParaOdIndex == ParaNrIndex - 1) {
 | 
						|
        MapFsStr = NULL;
 | 
						|
      } else if (ParaOdIndex == ParaNrIndex - 2) {
 | 
						|
        MapFsStr = Argv[ParaOdIndex + 1];
 | 
						|
      } else {
 | 
						|
        Print (L"CapsuleApp: Cannot specify more than one FS mapping!\n");
 | 
						|
        Status = EFI_INVALID_PARAMETER;
 | 
						|
        goto Done;
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      CapsuleLastIndex = ParaNrIndex - 1;
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    CapsuleLastIndex = Argc - 1;
 | 
						|
  }
 | 
						|
 | 
						|
  CapsuleNum = CapsuleLastIndex - CapsuleFirstIndex + 1;
 | 
						|
 | 
						|
  if (CapsuleFirstIndex > CapsuleLastIndex) {
 | 
						|
    Print (L"CapsuleApp: NO capsule image.\n");
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  if (CapsuleNum > MAX_CAPSULE_NUM) {
 | 
						|
    Print (L"CapsuleApp: Too many capsule images.\n");
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  ZeroMem (&CapsuleBuffer, sizeof (CapsuleBuffer));
 | 
						|
  ZeroMem (&CapsuleBufferSize, sizeof (CapsuleBufferSize));
 | 
						|
  BlockDescriptors = NULL;
 | 
						|
 | 
						|
  for (Index = 0; Index < CapsuleNum; Index++) {
 | 
						|
    CapsuleName = Argv[CapsuleFirstIndex + Index];
 | 
						|
    Status      = ReadFileToBuffer (CapsuleName, &CapsuleBufferSize[Index], &CapsuleBuffer[Index]);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      Print (L"CapsuleApp: capsule image (%s) is not found.\n", CapsuleName);
 | 
						|
      goto Done;
 | 
						|
    }
 | 
						|
 | 
						|
    if (!IsValidCapsuleHeader (CapsuleBuffer[Index], CapsuleBufferSize[Index])) {
 | 
						|
      Print (L"CapsuleApp: Capsule image (%s) is not a valid capsule.\n", CapsuleName);
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
 | 
						|
    CapsuleNames[Index] = CapsuleName;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Every capsule use 2 descriptor 1 for data 1 for end
 | 
						|
  //
 | 
						|
  Status = BuildGatherList (CapsuleBuffer, CapsuleBufferSize, CapsuleNum, &BlockDescriptors);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto Done;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Call the runtime service capsule.
 | 
						|
  //
 | 
						|
  NeedReset = FALSE;
 | 
						|
  for (Index = 0; Index < CapsuleNum; Index++) {
 | 
						|
    CapsuleHeaderArray[Index] = (EFI_CAPSULE_HEADER *)CapsuleBuffer[Index];
 | 
						|
    if ((CapsuleHeaderArray[Index]->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {
 | 
						|
      NeedReset = TRUE;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  CapsuleHeaderArray[CapsuleNum] = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // Inquire platform capability of UpdateCapsule.
 | 
						|
  //
 | 
						|
  Status = gRT->QueryCapsuleCapabilities (CapsuleHeaderArray, CapsuleNum, &MaxCapsuleSize, &ResetType);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    Print (L"CapsuleApp: failed to query capsule capability - %r\n", Status);
 | 
						|
    goto Done;
 | 
						|
  }
 | 
						|
 | 
						|
  for (Index = 0; Index < CapsuleNum; Index++) {
 | 
						|
    if (CapsuleBufferSize[Index] > MaxCapsuleSize) {
 | 
						|
      Print (L"CapsuleApp: capsule is too large to update, %ld is allowed\n", MaxCapsuleSize);
 | 
						|
      Status = EFI_UNSUPPORTED;
 | 
						|
      goto Done;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check whether is capsule on disk.
 | 
						|
  //
 | 
						|
  if (CapsuleOnDisk) {
 | 
						|
    Status = ProcessCapsuleOnDisk (CapsuleBuffer, CapsuleBufferSize, CapsuleNames, MapFsStr, CapsuleNum);
 | 
						|
    if (Status != EFI_SUCCESS) {
 | 
						|
      Print (L"CapsuleApp: failed to update capsule - %r\n", Status);
 | 
						|
      goto Done;
 | 
						|
    } else {
 | 
						|
      if (!NoReset) {
 | 
						|
        gRT->ResetSystem (ResetType, EFI_SUCCESS, 0, NULL);
 | 
						|
      } else {
 | 
						|
        goto Done;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check whether the input capsule image has the flag of persist across system reset.
 | 
						|
  //
 | 
						|
  if (NeedReset) {
 | 
						|
    Status = gRT->UpdateCapsule (CapsuleHeaderArray, CapsuleNum, (UINTN)BlockDescriptors);
 | 
						|
    if (Status != EFI_SUCCESS) {
 | 
						|
      Print (L"CapsuleApp: failed to update capsule - %r\n", Status);
 | 
						|
      goto Done;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // For capsule with CAPSULE_FLAGS_PERSIST_ACROSS_RESET + CAPSULE_FLAGS_INITIATE_RESET,
 | 
						|
    // a system reset should have been triggered by gRT->UpdateCapsule() calling above.
 | 
						|
    //
 | 
						|
    // For capsule with CAPSULE_FLAGS_PERSIST_ACROSS_RESET and without CAPSULE_FLAGS_INITIATE_RESET,
 | 
						|
    // check if -NR (no-reset) has been specified or not.
 | 
						|
    //
 | 
						|
    if (!NoReset) {
 | 
						|
      //
 | 
						|
      // For capsule who has reset flag and no -NR (no-reset) has been specified, after calling UpdateCapsule service,
 | 
						|
      // trigger a system reset to process capsule persist across a system reset.
 | 
						|
      //
 | 
						|
      gRT->ResetSystem (ResetType, EFI_SUCCESS, 0, NULL);
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // For capsule who has no reset flag, only call UpdateCapsule Service without a
 | 
						|
    // system reset. The service will process the capsule immediately.
 | 
						|
    //
 | 
						|
    Status = gRT->UpdateCapsule (CapsuleHeaderArray, CapsuleNum, (UINTN)BlockDescriptors);
 | 
						|
    if (Status != EFI_SUCCESS) {
 | 
						|
      Print (L"CapsuleApp: failed to update capsule - %r\n", Status);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
Done:
 | 
						|
  for (Index = 0; Index < CapsuleNum; Index++) {
 | 
						|
    if (CapsuleBuffer[Index] != NULL) {
 | 
						|
      FreePool (CapsuleBuffer[Index]);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  CleanGatherList (BlockDescriptors, CapsuleNum);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 |