mirror of
				https://git.proxmox.com/git/mirror_edk2
				synced 2025-11-04 07:34:13 +00:00 
			
		
		
		
	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>
		
			
				
	
	
		
			2014 lines
		
	
	
		
			62 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			2014 lines
		
	
	
		
			62 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  The implementation supports Capusle on Disk.
 | 
						|
 | 
						|
  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
 | 
						|
  SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include "CapsuleOnDisk.h"
 | 
						|
 | 
						|
/**
 | 
						|
  Return if this capsule is a capsule name capsule, based upon CapsuleHeader.
 | 
						|
 | 
						|
  @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER
 | 
						|
 | 
						|
  @retval TRUE  It is a capsule name capsule.
 | 
						|
  @retval FALSE It is not a capsule name capsule.
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
IsCapsuleNameCapsule (
 | 
						|
  IN EFI_CAPSULE_HEADER  *CapsuleHeader
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Check the integrity of the capsule name capsule.
 | 
						|
  If the capsule is vaild, return the physical address of each capsule name string.
 | 
						|
 | 
						|
  This routine assumes the capsule has been validated by IsValidCapsuleHeader(), so
 | 
						|
  capsule memory overflow is not going to happen in this routine.
 | 
						|
 | 
						|
  @param[in]  CapsuleHeader   Pointer to the capsule header of a capsule name capsule.
 | 
						|
  @param[out] CapsuleNameNum  Number of capsule name.
 | 
						|
 | 
						|
  @retval NULL                Capsule name capsule is not valid.
 | 
						|
  @retval CapsuleNameBuf      Array of capsule name physical address.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_PHYSICAL_ADDRESS *
 | 
						|
ValidateCapsuleNameCapsuleIntegrity (
 | 
						|
  IN  EFI_CAPSULE_HEADER  *CapsuleHeader,
 | 
						|
  OUT UINTN               *CapsuleNameNum
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT8                 *CapsuleNamePtr;
 | 
						|
  UINT8                 *CapsuleNameBufStart;
 | 
						|
  UINT8                 *CapsuleNameBufEnd;
 | 
						|
  UINTN                 Index;
 | 
						|
  UINTN                 StringSize;
 | 
						|
  EFI_PHYSICAL_ADDRESS  *CapsuleNameBuf;
 | 
						|
 | 
						|
  if (!IsCapsuleNameCapsule (CapsuleHeader)) {
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Total string size must be even.
 | 
						|
  //
 | 
						|
  if (((CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize) & BIT0) != 0) {
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  *CapsuleNameNum     = 0;
 | 
						|
  Index               = 0;
 | 
						|
  CapsuleNameBufStart = (UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize;
 | 
						|
 | 
						|
  //
 | 
						|
  // If strings are not aligned on a 16-bit boundary, reallocate memory for it.
 | 
						|
  //
 | 
						|
  if (((UINTN)CapsuleNameBufStart & BIT0) != 0) {
 | 
						|
    CapsuleNameBufStart = AllocateCopyPool (CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize, CapsuleNameBufStart);
 | 
						|
    if (CapsuleNameBufStart == NULL) {
 | 
						|
      return NULL;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  CapsuleNameBufEnd = CapsuleNameBufStart + CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize;
 | 
						|
 | 
						|
  CapsuleNamePtr = CapsuleNameBufStart;
 | 
						|
  while (CapsuleNamePtr < CapsuleNameBufEnd) {
 | 
						|
    StringSize      = StrnSizeS ((CHAR16 *)CapsuleNamePtr, (CapsuleNameBufEnd - CapsuleNamePtr)/sizeof (CHAR16));
 | 
						|
    CapsuleNamePtr += StringSize;
 | 
						|
    (*CapsuleNameNum)++;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Integrity check.
 | 
						|
  //
 | 
						|
  if (CapsuleNamePtr != CapsuleNameBufEnd) {
 | 
						|
    if (CapsuleNameBufStart != (UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize) {
 | 
						|
      FreePool (CapsuleNameBufStart);
 | 
						|
    }
 | 
						|
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  CapsuleNameBuf = AllocatePool (*CapsuleNameNum * sizeof (EFI_PHYSICAL_ADDRESS));
 | 
						|
  if (CapsuleNameBuf == NULL) {
 | 
						|
    if (CapsuleNameBufStart != (UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize) {
 | 
						|
      FreePool (CapsuleNameBufStart);
 | 
						|
    }
 | 
						|
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  CapsuleNamePtr = CapsuleNameBufStart;
 | 
						|
  while (CapsuleNamePtr < CapsuleNameBufEnd) {
 | 
						|
    StringSize            = StrnSizeS ((CHAR16 *)CapsuleNamePtr, (CapsuleNameBufEnd - CapsuleNamePtr)/sizeof (CHAR16));
 | 
						|
    CapsuleNameBuf[Index] = (EFI_PHYSICAL_ADDRESS)(UINTN)CapsuleNamePtr;
 | 
						|
    CapsuleNamePtr       += StringSize;
 | 
						|
    Index++;
 | 
						|
  }
 | 
						|
 | 
						|
  return CapsuleNameBuf;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This routine is called to upper case given unicode string.
 | 
						|
 | 
						|
  @param[in]   Str              String to upper case
 | 
						|
 | 
						|
  @retval upper cased string after process
 | 
						|
 | 
						|
**/
 | 
						|
static
 | 
						|
CHAR16 *
 | 
						|
UpperCaseString (
 | 
						|
  IN CHAR16  *Str
 | 
						|
  )
 | 
						|
{
 | 
						|
  CHAR16  *Cptr;
 | 
						|
 | 
						|
  for (Cptr = Str; *Cptr != L'\0'; Cptr++) {
 | 
						|
    if ((L'a' <= *Cptr) && (*Cptr <= L'z')) {
 | 
						|
      *Cptr = *Cptr - L'a' + L'A';
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return Str;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This routine is used to return substring before period '.' or '\0'
 | 
						|
  Caller should respsonsible of substr space allocation & free
 | 
						|
 | 
						|
  @param[in]   Str              String to check
 | 
						|
  @param[out]  SubStr           First part of string before period or '\0'
 | 
						|
  @param[out]  SubStrLen        Length of first part of string
 | 
						|
 | 
						|
**/
 | 
						|
static
 | 
						|
VOID
 | 
						|
GetSubStringBeforePeriod (
 | 
						|
  IN  CHAR16  *Str,
 | 
						|
  OUT CHAR16  *SubStr,
 | 
						|
  OUT UINTN   *SubStrLen
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN  Index;
 | 
						|
 | 
						|
  for (Index = 0; Str[Index] != L'.' && Str[Index] != L'\0'; Index++) {
 | 
						|
    SubStr[Index] = Str[Index];
 | 
						|
  }
 | 
						|
 | 
						|
  SubStr[Index] = L'\0';
 | 
						|
  *SubStrLen    = Index;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This routine pad the string in tail with input character.
 | 
						|
 | 
						|
  @param[in]   StrBuf            Str buffer to be padded, should be enough room for
 | 
						|
  @param[in]   PadLen            Expected padding length
 | 
						|
  @param[in]   Character         Character used to pad
 | 
						|
 | 
						|
**/
 | 
						|
static
 | 
						|
VOID
 | 
						|
PadStrInTail (
 | 
						|
  IN CHAR16  *StrBuf,
 | 
						|
  IN UINTN   PadLen,
 | 
						|
  IN CHAR16  Character
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN  Index;
 | 
						|
 | 
						|
  for (Index = 0; StrBuf[Index] != L'\0'; Index++) {
 | 
						|
  }
 | 
						|
 | 
						|
  while (PadLen != 0) {
 | 
						|
    StrBuf[Index] = Character;
 | 
						|
    Index++;
 | 
						|
    PadLen--;
 | 
						|
  }
 | 
						|
 | 
						|
  StrBuf[Index] = L'\0';
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This routine find the offset of the last period '.' of string. If No period exists
 | 
						|
  function FileNameExtension is set to L'\0'
 | 
						|
 | 
						|
  @param[in]  FileName           File name to split between last period
 | 
						|
  @param[out] FileNameFirst      First FileName before last period
 | 
						|
  @param[out] FileNameExtension  FileName after last period
 | 
						|
 | 
						|
**/
 | 
						|
static
 | 
						|
VOID
 | 
						|
SplitFileNameExtension (
 | 
						|
  IN CHAR16   *FileName,
 | 
						|
  OUT CHAR16  *FileNameFirst,
 | 
						|
  OUT CHAR16  *FileNameExtension
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN  Index;
 | 
						|
  UINTN  StringLen;
 | 
						|
 | 
						|
  StringLen = StrnLenS (FileName, MAX_FILE_NAME_SIZE);
 | 
						|
  for (Index = StringLen; Index > 0 && FileName[Index] != L'.'; Index--) {
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // No period exists. No FileName Extension
 | 
						|
  //
 | 
						|
  if ((Index == 0) && (FileName[Index] != L'.')) {
 | 
						|
    FileNameExtension[0] = L'\0';
 | 
						|
    Index                = StringLen;
 | 
						|
  } else {
 | 
						|
    StrCpyS (FileNameExtension, MAX_FILE_NAME_SIZE, &FileName[Index+1]);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Copy First file name
 | 
						|
  //
 | 
						|
  StrnCpyS (FileNameFirst, MAX_FILE_NAME_SIZE, FileName, Index);
 | 
						|
  FileNameFirst[Index] = L'\0';
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This routine is called to get all boot options in the order determnined by:
 | 
						|
    1. "OptionBuf"
 | 
						|
    2. "BootOrder"
 | 
						|
 | 
						|
  @param[out] OptionBuf           BootList buffer to all boot options returned
 | 
						|
  @param[out] OptionCount         BootList count of all boot options returned
 | 
						|
 | 
						|
  @retval EFI_SUCCESS             There is no error when processing capsule
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
GetBootOptionInOrder (
 | 
						|
  OUT EFI_BOOT_MANAGER_LOAD_OPTION  **OptionBuf,
 | 
						|
  OUT UINTN                         *OptionCount
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                    Status;
 | 
						|
  UINTN                         DataSize;
 | 
						|
  UINT16                        BootNext;
 | 
						|
  CHAR16                        BootOptionName[20];
 | 
						|
  EFI_BOOT_MANAGER_LOAD_OPTION  *BootOrderOptionBuf;
 | 
						|
  UINTN                         BootOrderCount;
 | 
						|
  EFI_BOOT_MANAGER_LOAD_OPTION  BootNextOptionEntry;
 | 
						|
  UINTN                         BootNextCount;
 | 
						|
  EFI_BOOT_MANAGER_LOAD_OPTION  *TempBuf;
 | 
						|
 | 
						|
  BootOrderOptionBuf = NULL;
 | 
						|
  TempBuf            = NULL;
 | 
						|
  BootNextCount      = 0;
 | 
						|
  BootOrderCount     = 0;
 | 
						|
  *OptionBuf         = NULL;
 | 
						|
  *OptionCount       = 0;
 | 
						|
 | 
						|
  //
 | 
						|
  // First Get BootOption from "BootNext"
 | 
						|
  //
 | 
						|
  DataSize = sizeof (BootNext);
 | 
						|
  Status   = gRT->GetVariable (
 | 
						|
                    EFI_BOOT_NEXT_VARIABLE_NAME,
 | 
						|
                    &gEfiGlobalVariableGuid,
 | 
						|
                    NULL,
 | 
						|
                    &DataSize,
 | 
						|
                    (VOID *)&BootNext
 | 
						|
                    );
 | 
						|
  //
 | 
						|
  // BootNext variable is a single UINT16
 | 
						|
  //
 | 
						|
  if (!EFI_ERROR (Status) && (DataSize == sizeof (UINT16))) {
 | 
						|
    //
 | 
						|
    // Add the boot next boot option
 | 
						|
    //
 | 
						|
    UnicodeSPrint (BootOptionName, sizeof (BootOptionName), L"Boot%04x", BootNext);
 | 
						|
    ZeroMem (&BootNextOptionEntry, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
 | 
						|
    Status = EfiBootManagerVariableToLoadOption (BootOptionName, &BootNextOptionEntry);
 | 
						|
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
      BootNextCount = 1;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Second get BootOption from "BootOrder"
 | 
						|
  //
 | 
						|
  BootOrderOptionBuf = EfiBootManagerGetLoadOptions (&BootOrderCount, LoadOptionTypeBoot);
 | 
						|
  if ((BootNextCount == 0) && (BootOrderCount == 0)) {
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // At least one BootOption is found
 | 
						|
  //
 | 
						|
  TempBuf = AllocatePool (sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (BootNextCount + BootOrderCount));
 | 
						|
  if (TempBuf != NULL) {
 | 
						|
    if (BootNextCount == 1) {
 | 
						|
      CopyMem (TempBuf, &BootNextOptionEntry, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
 | 
						|
    }
 | 
						|
 | 
						|
    if (BootOrderCount > 0) {
 | 
						|
      CopyMem (TempBuf + BootNextCount, BootOrderOptionBuf, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * BootOrderCount);
 | 
						|
    }
 | 
						|
 | 
						|
    *OptionBuf   = TempBuf;
 | 
						|
    *OptionCount = BootNextCount + BootOrderCount;
 | 
						|
    Status       = EFI_SUCCESS;
 | 
						|
  } else {
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  FreePool (BootOrderOptionBuf);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This routine is called to get boot option by OptionNumber.
 | 
						|
 | 
						|
  @param[in] Number               The OptionNumber of boot option
 | 
						|
  @param[out] OptionBuf           BootList buffer to all boot options returned
 | 
						|
 | 
						|
  @retval EFI_SUCCESS             There is no error when getting boot option
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
GetBootOptionByNumber (
 | 
						|
  IN  UINT16                        Number,
 | 
						|
  OUT EFI_BOOT_MANAGER_LOAD_OPTION  **OptionBuf
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                    Status;
 | 
						|
  CHAR16                        BootOptionName[20];
 | 
						|
  EFI_BOOT_MANAGER_LOAD_OPTION  BootOption;
 | 
						|
 | 
						|
  UnicodeSPrint (BootOptionName, sizeof (BootOptionName), L"Boot%04x", Number);
 | 
						|
  ZeroMem (&BootOption, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
 | 
						|
  Status = EfiBootManagerVariableToLoadOption (BootOptionName, &BootOption);
 | 
						|
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    *OptionBuf = AllocatePool (sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
 | 
						|
    if (*OptionBuf != NULL) {
 | 
						|
      CopyMem (*OptionBuf, &BootOption, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
 | 
						|
      Status = EFI_SUCCESS;
 | 
						|
    } else {
 | 
						|
      Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Get Active EFI System Partition within GPT based on device path.
 | 
						|
 | 
						|
  @param[in] DevicePath    Device path to find a active EFI System Partition
 | 
						|
  @param[out] FsHandle     BootList points to all boot options returned
 | 
						|
 | 
						|
  @retval EFI_SUCCESS      Active EFI System Partition is succesfully found
 | 
						|
  @retval EFI_NOT_FOUND    No Active EFI System Partition is found
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
GetEfiSysPartitionFromDevPath (
 | 
						|
  IN EFI_DEVICE_PATH_PROTOCOL  *DevicePath,
 | 
						|
  OUT EFI_HANDLE               *FsHandle
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                       Status;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL         *TempDevicePath;
 | 
						|
  HARDDRIVE_DEVICE_PATH            *Hd;
 | 
						|
  EFI_HANDLE                       Handle;
 | 
						|
  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  *Fs;
 | 
						|
 | 
						|
  //
 | 
						|
  // Check if the device path contains GPT node
 | 
						|
  //
 | 
						|
  TempDevicePath = DevicePath;
 | 
						|
  while (!IsDevicePathEnd (TempDevicePath)) {
 | 
						|
    if ((DevicePathType (TempDevicePath) == MEDIA_DEVICE_PATH) &&
 | 
						|
        (DevicePathSubType (TempDevicePath) == MEDIA_HARDDRIVE_DP))
 | 
						|
    {
 | 
						|
      Hd = (HARDDRIVE_DEVICE_PATH *)TempDevicePath;
 | 
						|
      if (Hd->MBRType == MBR_TYPE_EFI_PARTITION_TABLE_HEADER) {
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    TempDevicePath = NextDevicePathNode (TempDevicePath);
 | 
						|
  }
 | 
						|
 | 
						|
  if (!IsDevicePathEnd (TempDevicePath)) {
 | 
						|
    //
 | 
						|
    // Search for EFI system partition protocol on full device path in Boot Option
 | 
						|
    //
 | 
						|
    Status = gBS->LocateDevicePath (&gEfiPartTypeSystemPartGuid, &DevicePath, &Handle);
 | 
						|
 | 
						|
    //
 | 
						|
    // Search for simple file system on this handler
 | 
						|
    //
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
      Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs);
 | 
						|
      if (!EFI_ERROR (Status)) {
 | 
						|
        *FsHandle = Handle;
 | 
						|
        return EFI_SUCCESS;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_NOT_FOUND;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This routine is called to get Simple File System protocol on the first EFI system partition found in
 | 
						|
  active boot option. The boot option list is detemined in order by
 | 
						|
    1. "BootNext"
 | 
						|
    2. "BootOrder"
 | 
						|
 | 
						|
  @param[in]       MaxRetry           Max Connection Retry. Stall 100ms between each connection try to ensure
 | 
						|
                                      device like USB can get enumerated.
 | 
						|
  @param[in, out]  LoadOptionNumber   On input, specify the boot option to get EFI system partition.
 | 
						|
                                      On output, return the OptionNumber of the boot option where EFI
 | 
						|
                                      system partition is got from.
 | 
						|
  @param[out]      FsFsHandle         Simple File System Protocol found on first active EFI system partition
 | 
						|
 | 
						|
  @retval EFI_SUCCESS     Simple File System protocol found for EFI system partition
 | 
						|
  @retval EFI_NOT_FOUND   No Simple File System protocol found for EFI system partition
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
GetEfiSysPartitionFromActiveBootOption (
 | 
						|
  IN UINTN        MaxRetry,
 | 
						|
  IN OUT UINT16   **LoadOptionNumber,
 | 
						|
  OUT EFI_HANDLE  *FsHandle
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                    Status;
 | 
						|
  EFI_BOOT_MANAGER_LOAD_OPTION  *BootOptionBuf;
 | 
						|
  UINTN                         BootOptionNum;
 | 
						|
  UINTN                         Index;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL      *DevicePath;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL      *CurFullPath;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL      *PreFullPath;
 | 
						|
 | 
						|
  *FsHandle   = NULL;
 | 
						|
  CurFullPath = NULL;
 | 
						|
 | 
						|
  if (*LoadOptionNumber != NULL) {
 | 
						|
    BootOptionNum = 1;
 | 
						|
    Status        = GetBootOptionByNumber (**LoadOptionNumber, &BootOptionBuf);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      DEBUG ((DEBUG_ERROR, "GetBootOptionByIndex Failed %x! No BootOption available for connection\n", Status));
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    Status = GetBootOptionInOrder (&BootOptionBuf, &BootOptionNum);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      DEBUG ((DEBUG_ERROR, "GetBootOptionInOrder Failed %x! No BootOption available for connection\n", Status));
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Search BootOptionList to check if it is an active boot option with EFI system partition
 | 
						|
  //  1. Connect device path
 | 
						|
  //  2. expend short/plug in devicepath
 | 
						|
  //  3. LoadImage
 | 
						|
  //
 | 
						|
  for (Index = 0; Index < BootOptionNum; Index++) {
 | 
						|
    //
 | 
						|
    // Get the boot option from the link list
 | 
						|
    //
 | 
						|
    DevicePath = BootOptionBuf[Index].FilePath;
 | 
						|
 | 
						|
    //
 | 
						|
    // Skip inactive or legacy boot options
 | 
						|
    //
 | 
						|
    if (((BootOptionBuf[Index].Attributes & LOAD_OPTION_ACTIVE) == 0) ||
 | 
						|
        (DevicePathType (DevicePath) == BBS_DEVICE_PATH))
 | 
						|
    {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    DEBUG_CODE_BEGIN ();
 | 
						|
    CHAR16  *DevicePathStr;
 | 
						|
 | 
						|
    DevicePathStr = ConvertDevicePathToText (DevicePath, TRUE, TRUE);
 | 
						|
    if (DevicePathStr != NULL) {
 | 
						|
      DEBUG ((DEBUG_INFO, "Try BootOption %s\n", DevicePathStr));
 | 
						|
      FreePool (DevicePathStr);
 | 
						|
    } else {
 | 
						|
      DEBUG ((DEBUG_INFO, "DevicePathToStr failed\n"));
 | 
						|
    }
 | 
						|
 | 
						|
    DEBUG_CODE_END ();
 | 
						|
 | 
						|
    CurFullPath = NULL;
 | 
						|
    //
 | 
						|
    // Try every full device Path generated from bootoption
 | 
						|
    //
 | 
						|
    do {
 | 
						|
      PreFullPath = CurFullPath;
 | 
						|
      CurFullPath = EfiBootManagerGetNextLoadOptionDevicePath (DevicePath, CurFullPath);
 | 
						|
 | 
						|
      if (PreFullPath != NULL) {
 | 
						|
        FreePool (PreFullPath);
 | 
						|
      }
 | 
						|
 | 
						|
      if (CurFullPath == NULL) {
 | 
						|
        //
 | 
						|
        // No Active EFI system partition is found in BootOption device path
 | 
						|
        //
 | 
						|
        Status = EFI_NOT_FOUND;
 | 
						|
        break;
 | 
						|
      }
 | 
						|
 | 
						|
      DEBUG_CODE_BEGIN ();
 | 
						|
      CHAR16  *DevicePathStr1;
 | 
						|
 | 
						|
      DevicePathStr1 = ConvertDevicePathToText (CurFullPath, TRUE, TRUE);
 | 
						|
      if (DevicePathStr1 != NULL) {
 | 
						|
        DEBUG ((DEBUG_INFO, "Full device path %s\n", DevicePathStr1));
 | 
						|
        FreePool (DevicePathStr1);
 | 
						|
      }
 | 
						|
 | 
						|
      DEBUG_CODE_END ();
 | 
						|
 | 
						|
      //
 | 
						|
      // Make sure the boot option device path connected.
 | 
						|
      // Only handle first device in boot option. Other optional device paths are described as OSV specific
 | 
						|
      // FullDevice could contain extra directory & file info. So don't check connection status here.
 | 
						|
      //
 | 
						|
      EfiBootManagerConnectDevicePath (CurFullPath, NULL);
 | 
						|
      Status = GetEfiSysPartitionFromDevPath (CurFullPath, FsHandle);
 | 
						|
 | 
						|
      //
 | 
						|
      // Some relocation device like USB need more time to get enumerated
 | 
						|
      //
 | 
						|
      while (EFI_ERROR (Status) && MaxRetry > 0) {
 | 
						|
        EfiBootManagerConnectDevicePath (CurFullPath, NULL);
 | 
						|
 | 
						|
        //
 | 
						|
        // Search for EFI system partition protocol on full device path in Boot Option
 | 
						|
        //
 | 
						|
        Status = GetEfiSysPartitionFromDevPath (CurFullPath, FsHandle);
 | 
						|
        if (!EFI_ERROR (Status)) {
 | 
						|
          break;
 | 
						|
        }
 | 
						|
 | 
						|
        DEBUG ((DEBUG_ERROR, "GetEfiSysPartitionFromDevPath Loop %x\n", Status));
 | 
						|
        //
 | 
						|
        // Stall 100ms if connection failed to ensure USB stack is ready
 | 
						|
        //
 | 
						|
        gBS->Stall (100000);
 | 
						|
        MaxRetry--;
 | 
						|
      }
 | 
						|
    } while (EFI_ERROR (Status));
 | 
						|
 | 
						|
    //
 | 
						|
    // Find a qualified Simple File System
 | 
						|
    //
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Return the OptionNumber of the boot option where EFI system partition is got from
 | 
						|
  //
 | 
						|
  if (*LoadOptionNumber == NULL) {
 | 
						|
    *LoadOptionNumber = AllocateCopyPool (sizeof (UINT16), (UINT16 *)&BootOptionBuf[Index].OptionNumber);
 | 
						|
    if (*LoadOptionNumber == NULL) {
 | 
						|
      Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // No qualified EFI system partition found
 | 
						|
  //
 | 
						|
  if (*FsHandle == NULL) {
 | 
						|
    Status = EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
 | 
						|
  DEBUG_CODE_BEGIN ();
 | 
						|
  CHAR16  *DevicePathStr2;
 | 
						|
 | 
						|
  if (*FsHandle != NULL) {
 | 
						|
    DevicePathStr2 = ConvertDevicePathToText (CurFullPath, TRUE, TRUE);
 | 
						|
    if (DevicePathStr2 != NULL) {
 | 
						|
      DEBUG ((DEBUG_INFO, "Found Active EFI System Partion on %s\n", DevicePathStr2));
 | 
						|
      FreePool (DevicePathStr2);
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    DEBUG ((DEBUG_INFO, "Failed to found Active EFI System Partion\n"));
 | 
						|
  }
 | 
						|
 | 
						|
  DEBUG_CODE_END ();
 | 
						|
 | 
						|
  if (CurFullPath != NULL) {
 | 
						|
    FreePool (CurFullPath);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Free BootOption Buffer
 | 
						|
  //
 | 
						|
  for (Index = 0; Index < BootOptionNum; Index++) {
 | 
						|
    if (BootOptionBuf[Index].Description != NULL) {
 | 
						|
      FreePool (BootOptionBuf[Index].Description);
 | 
						|
    }
 | 
						|
 | 
						|
    if (BootOptionBuf[Index].FilePath != NULL) {
 | 
						|
      FreePool (BootOptionBuf[Index].FilePath);
 | 
						|
    }
 | 
						|
 | 
						|
    if (BootOptionBuf[Index].OptionalData != NULL) {
 | 
						|
      FreePool (BootOptionBuf[Index].OptionalData);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  FreePool (BootOptionBuf);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This routine is called to get all file infos with in a given dir & with given file attribute, the file info is listed in
 | 
						|
  alphabetical order described in UEFI spec.
 | 
						|
 | 
						|
  @param[in]  Dir                 Directory file handler
 | 
						|
  @param[in]  FileAttr            Attribute of file to be red from directory
 | 
						|
  @param[out] FileInfoList        File images info list red from directory
 | 
						|
  @param[out] FileNum             File images number red from directory
 | 
						|
 | 
						|
  @retval EFI_SUCCESS             File FileInfo list in the given
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
GetFileInfoListInAlphabetFromDir (
 | 
						|
  IN EFI_FILE_HANDLE  Dir,
 | 
						|
  IN UINT64           FileAttr,
 | 
						|
  OUT LIST_ENTRY      *FileInfoList,
 | 
						|
  OUT UINTN           *FileNum
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS       Status;
 | 
						|
  FILE_INFO_ENTRY  *NewFileInfoEntry;
 | 
						|
  FILE_INFO_ENTRY  *TempFileInfoEntry;
 | 
						|
  EFI_FILE_INFO    *FileInfo;
 | 
						|
  CHAR16           *NewFileName;
 | 
						|
  CHAR16           *ListedFileName;
 | 
						|
  CHAR16           *NewFileNameExtension;
 | 
						|
  CHAR16           *ListedFileNameExtension;
 | 
						|
  CHAR16           *TempNewSubStr;
 | 
						|
  CHAR16           *TempListedSubStr;
 | 
						|
  LIST_ENTRY       *Link;
 | 
						|
  BOOLEAN          NoFile;
 | 
						|
  UINTN            FileCount;
 | 
						|
  UINTN            IndexNew;
 | 
						|
  UINTN            IndexListed;
 | 
						|
  UINTN            NewSubStrLen;
 | 
						|
  UINTN            ListedSubStrLen;
 | 
						|
  INTN             SubStrCmpResult;
 | 
						|
 | 
						|
  Status                  = EFI_SUCCESS;
 | 
						|
  NewFileName             = NULL;
 | 
						|
  ListedFileName          = NULL;
 | 
						|
  NewFileNameExtension    = NULL;
 | 
						|
  ListedFileNameExtension = NULL;
 | 
						|
  TempNewSubStr           = NULL;
 | 
						|
  TempListedSubStr        = NULL;
 | 
						|
  FileInfo                = NULL;
 | 
						|
  NoFile                  = FALSE;
 | 
						|
  FileCount               = 0;
 | 
						|
 | 
						|
  InitializeListHead (FileInfoList);
 | 
						|
 | 
						|
  TempNewSubStr    = (CHAR16 *)AllocateZeroPool (MAX_FILE_NAME_SIZE);
 | 
						|
  TempListedSubStr = (CHAR16 *)AllocateZeroPool (MAX_FILE_NAME_SIZE);
 | 
						|
 | 
						|
  if ((TempNewSubStr == NULL) || (TempListedSubStr == NULL)) {
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  for ( Status = FileHandleFindFirstFile (Dir, &FileInfo)
 | 
						|
        ; !EFI_ERROR (Status) && !NoFile
 | 
						|
        ; Status = FileHandleFindNextFile (Dir, FileInfo, &NoFile)
 | 
						|
        )
 | 
						|
  {
 | 
						|
    if (FileInfo == NULL) {
 | 
						|
      goto EXIT;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Skip file with mismatching File attribute
 | 
						|
    //
 | 
						|
    if ((FileInfo->Attribute & (FileAttr)) == 0) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    NewFileInfoEntry = NULL;
 | 
						|
    NewFileInfoEntry = (FILE_INFO_ENTRY *)AllocateZeroPool (sizeof (FILE_INFO_ENTRY));
 | 
						|
    if (NewFileInfoEntry == NULL) {
 | 
						|
      Status = EFI_OUT_OF_RESOURCES;
 | 
						|
      goto EXIT;
 | 
						|
    }
 | 
						|
 | 
						|
    NewFileInfoEntry->Signature = FILE_INFO_SIGNATURE;
 | 
						|
    NewFileInfoEntry->FileInfo  = AllocateCopyPool ((UINTN)FileInfo->Size, FileInfo);
 | 
						|
    if (NewFileInfoEntry->FileInfo == NULL) {
 | 
						|
      FreePool (NewFileInfoEntry);
 | 
						|
      Status = EFI_OUT_OF_RESOURCES;
 | 
						|
      goto EXIT;
 | 
						|
    }
 | 
						|
 | 
						|
    NewFileInfoEntry->FileNameFirstPart = (CHAR16 *)AllocateZeroPool (MAX_FILE_NAME_SIZE);
 | 
						|
    if (NewFileInfoEntry->FileNameFirstPart == NULL) {
 | 
						|
      FreePool (NewFileInfoEntry->FileInfo);
 | 
						|
      FreePool (NewFileInfoEntry);
 | 
						|
      Status = EFI_OUT_OF_RESOURCES;
 | 
						|
      goto EXIT;
 | 
						|
    }
 | 
						|
 | 
						|
    NewFileInfoEntry->FileNameSecondPart = (CHAR16 *)AllocateZeroPool (MAX_FILE_NAME_SIZE);
 | 
						|
    if (NewFileInfoEntry->FileNameSecondPart == NULL) {
 | 
						|
      FreePool (NewFileInfoEntry->FileInfo);
 | 
						|
      FreePool (NewFileInfoEntry->FileNameFirstPart);
 | 
						|
      FreePool (NewFileInfoEntry);
 | 
						|
      Status = EFI_OUT_OF_RESOURCES;
 | 
						|
      goto EXIT;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Splitter the whole New file name into 2 parts between the last period L'.' into NewFileName NewFileExtension
 | 
						|
    // If no period in the whole file name. NewFileExtension is set to L'\0'
 | 
						|
    //
 | 
						|
    NewFileName          = NewFileInfoEntry->FileNameFirstPart;
 | 
						|
    NewFileNameExtension = NewFileInfoEntry->FileNameSecondPart;
 | 
						|
    SplitFileNameExtension (FileInfo->FileName, NewFileName, NewFileNameExtension);
 | 
						|
    UpperCaseString (NewFileName);
 | 
						|
    UpperCaseString (NewFileNameExtension);
 | 
						|
 | 
						|
    //
 | 
						|
    // Insert capsule file in alphabetical ordered list
 | 
						|
    //
 | 
						|
    for (Link = FileInfoList->ForwardLink; Link != FileInfoList; Link = Link->ForwardLink) {
 | 
						|
      //
 | 
						|
      // Get the FileInfo from the link list
 | 
						|
      //
 | 
						|
      TempFileInfoEntry       = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);
 | 
						|
      ListedFileName          = TempFileInfoEntry->FileNameFirstPart;
 | 
						|
      ListedFileNameExtension = TempFileInfoEntry->FileNameSecondPart;
 | 
						|
 | 
						|
      //
 | 
						|
      // Follow rule in UEFI spec 8.5.5 to compare file name
 | 
						|
      //
 | 
						|
      IndexListed = 0;
 | 
						|
      IndexNew    = 0;
 | 
						|
      while (TRUE) {
 | 
						|
        //
 | 
						|
        // First compare each substrings in NewFileName & ListedFileName between periods
 | 
						|
        //
 | 
						|
        GetSubStringBeforePeriod (&NewFileName[IndexNew], TempNewSubStr, &NewSubStrLen);
 | 
						|
        GetSubStringBeforePeriod (&ListedFileName[IndexListed], TempListedSubStr, &ListedSubStrLen);
 | 
						|
        if (NewSubStrLen > ListedSubStrLen) {
 | 
						|
          //
 | 
						|
          // Substr in NewFileName is longer. Pad tail with SPACE
 | 
						|
          //
 | 
						|
          PadStrInTail (TempListedSubStr, NewSubStrLen - ListedSubStrLen, L' ');
 | 
						|
        } else if (NewSubStrLen < ListedSubStrLen) {
 | 
						|
          //
 | 
						|
          // Substr in ListedFileName is longer. Pad tail with SPACE
 | 
						|
          //
 | 
						|
          PadStrInTail (TempNewSubStr, ListedSubStrLen - NewSubStrLen, L' ');
 | 
						|
        }
 | 
						|
 | 
						|
        SubStrCmpResult = StrnCmp (TempNewSubStr, TempListedSubStr, MAX_FILE_NAME_LEN);
 | 
						|
        if (SubStrCmpResult != 0) {
 | 
						|
          break;
 | 
						|
        }
 | 
						|
 | 
						|
        //
 | 
						|
        // Move to skip this substring
 | 
						|
        //
 | 
						|
        IndexNew    += NewSubStrLen;
 | 
						|
        IndexListed += ListedSubStrLen;
 | 
						|
        //
 | 
						|
        // Reach File First Name end
 | 
						|
        //
 | 
						|
        if ((NewFileName[IndexNew] == L'\0') || (ListedFileName[IndexListed] == L'\0')) {
 | 
						|
          break;
 | 
						|
        }
 | 
						|
 | 
						|
        //
 | 
						|
        // Skip the period L'.'
 | 
						|
        //
 | 
						|
        IndexNew++;
 | 
						|
        IndexListed++;
 | 
						|
      }
 | 
						|
 | 
						|
      if (SubStrCmpResult < 0) {
 | 
						|
        //
 | 
						|
        // NewFileName is smaller. Find the right place to insert New file
 | 
						|
        //
 | 
						|
        break;
 | 
						|
      } else if (SubStrCmpResult == 0) {
 | 
						|
        //
 | 
						|
        // 2 cases whole NewFileName is smaller than ListedFileName
 | 
						|
        //   1. if NewFileName == ListedFileName. Continue to compare FileNameExtension
 | 
						|
        //   2. if NewFileName is shorter than ListedFileName
 | 
						|
        //
 | 
						|
        if (NewFileName[IndexNew] == L'\0') {
 | 
						|
          if ((ListedFileName[IndexListed] != L'\0') || (StrnCmp (NewFileNameExtension, ListedFileNameExtension, MAX_FILE_NAME_LEN) < 0)) {
 | 
						|
            break;
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      // Other case, ListedFileName is smaller. Continue to compare the next file in the list
 | 
						|
      //
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // If Find an entry in the list whose name is bigger than new FileInfo in alphabet order
 | 
						|
    //    Insert it before this entry
 | 
						|
    // else
 | 
						|
    //    Insert at the tail of this list (Link = FileInfoList)
 | 
						|
    //
 | 
						|
    InsertTailList (Link, &NewFileInfoEntry->Link);
 | 
						|
 | 
						|
    FileCount++;
 | 
						|
  }
 | 
						|
 | 
						|
  *FileNum = FileCount;
 | 
						|
 | 
						|
EXIT:
 | 
						|
 | 
						|
  if (TempNewSubStr != NULL) {
 | 
						|
    FreePool (TempNewSubStr);
 | 
						|
  }
 | 
						|
 | 
						|
  if (TempListedSubStr != NULL) {
 | 
						|
    FreePool (TempListedSubStr);
 | 
						|
  }
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    while (!IsListEmpty (FileInfoList)) {
 | 
						|
      Link = FileInfoList->ForwardLink;
 | 
						|
      RemoveEntryList (Link);
 | 
						|
 | 
						|
      TempFileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);
 | 
						|
 | 
						|
      FreePool (TempFileInfoEntry->FileInfo);
 | 
						|
      FreePool (TempFileInfoEntry->FileNameFirstPart);
 | 
						|
      FreePool (TempFileInfoEntry->FileNameSecondPart);
 | 
						|
      FreePool (TempFileInfoEntry);
 | 
						|
    }
 | 
						|
 | 
						|
    *FileNum = 0;
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This routine is called to get all qualified image from file from an given directory
 | 
						|
  in alphabetic order. All the file image is copied to allocated boottime memory.
 | 
						|
  Caller should free these memory
 | 
						|
 | 
						|
  @param[in]  Dir            Directory file handler
 | 
						|
  @param[in]  FileAttr       Attribute of file to be red from directory
 | 
						|
  @param[out] FilePtr        File images Info buffer red from directory
 | 
						|
  @param[out] FileNum        File images number red from directory
 | 
						|
 | 
						|
  @retval EFI_SUCCESS  Succeed to get all capsules in alphabetic order.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
GetFileImageInAlphabetFromDir (
 | 
						|
  IN EFI_FILE_HANDLE  Dir,
 | 
						|
  IN UINT64           FileAttr,
 | 
						|
  OUT IMAGE_INFO      **FilePtr,
 | 
						|
  OUT UINTN           *FileNum
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS       Status;
 | 
						|
  LIST_ENTRY       *Link;
 | 
						|
  EFI_FILE_HANDLE  FileHandle;
 | 
						|
  FILE_INFO_ENTRY  *FileInfoEntry;
 | 
						|
  EFI_FILE_INFO    *FileInfo;
 | 
						|
  UINTN            FileCount;
 | 
						|
  IMAGE_INFO       *TempFilePtrBuf;
 | 
						|
  UINTN            Size;
 | 
						|
  LIST_ENTRY       FileInfoList;
 | 
						|
 | 
						|
  FileHandle     = NULL;
 | 
						|
  FileCount      = 0;
 | 
						|
  TempFilePtrBuf = NULL;
 | 
						|
  *FilePtr       = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // Get file list in Dir in alphabetical order
 | 
						|
  //
 | 
						|
  Status = GetFileInfoListInAlphabetFromDir (
 | 
						|
             Dir,
 | 
						|
             FileAttr,
 | 
						|
             &FileInfoList,
 | 
						|
             &FileCount
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "GetFileInfoListInAlphabetFromDir Failed!\n"));
 | 
						|
    goto EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  if (FileCount == 0) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "No file found in Dir!\n"));
 | 
						|
    Status = EFI_NOT_FOUND;
 | 
						|
    goto EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  TempFilePtrBuf = (IMAGE_INFO *)AllocateZeroPool (sizeof (IMAGE_INFO) * FileCount);
 | 
						|
  if (TempFilePtrBuf == NULL) {
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Read all files from FileInfoList to BS memory
 | 
						|
  //
 | 
						|
  FileCount = 0;
 | 
						|
  for (Link = FileInfoList.ForwardLink; Link != &FileInfoList; Link = Link->ForwardLink) {
 | 
						|
    //
 | 
						|
    // Get FileInfo from the link list
 | 
						|
    //
 | 
						|
    FileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);
 | 
						|
    FileInfo      = FileInfoEntry->FileInfo;
 | 
						|
 | 
						|
    Status = Dir->Open (
 | 
						|
                    Dir,
 | 
						|
                    &FileHandle,
 | 
						|
                    FileInfo->FileName,
 | 
						|
                    EFI_FILE_MODE_READ,
 | 
						|
                    0
 | 
						|
                    );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    Size                                   = (UINTN)FileInfo->FileSize;
 | 
						|
    TempFilePtrBuf[FileCount].ImageAddress = AllocateZeroPool (Size);
 | 
						|
    if (TempFilePtrBuf[FileCount].ImageAddress == NULL) {
 | 
						|
      DEBUG ((DEBUG_ERROR, "Fail to allocate memory for capsule. Stop processing the rest.\n"));
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    Status = FileHandle->Read (
 | 
						|
                           FileHandle,
 | 
						|
                           &Size,
 | 
						|
                           TempFilePtrBuf[FileCount].ImageAddress
 | 
						|
                           );
 | 
						|
 | 
						|
    FileHandle->Close (FileHandle);
 | 
						|
 | 
						|
    //
 | 
						|
    // Skip read error file
 | 
						|
    //
 | 
						|
    if (EFI_ERROR (Status) || (Size != (UINTN)FileInfo->FileSize)) {
 | 
						|
      //
 | 
						|
      // Remove this error file info accordingly
 | 
						|
      // & move Link to BackLink
 | 
						|
      //
 | 
						|
      Link = RemoveEntryList (Link);
 | 
						|
      Link = Link->BackLink;
 | 
						|
 | 
						|
      FreePool (FileInfoEntry->FileInfo);
 | 
						|
      FreePool (FileInfoEntry->FileNameFirstPart);
 | 
						|
      FreePool (FileInfoEntry->FileNameSecondPart);
 | 
						|
      FreePool (FileInfoEntry);
 | 
						|
 | 
						|
      FreePool (TempFilePtrBuf[FileCount].ImageAddress);
 | 
						|
      TempFilePtrBuf[FileCount].ImageAddress = NULL;
 | 
						|
      TempFilePtrBuf[FileCount].FileInfo     = NULL;
 | 
						|
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    TempFilePtrBuf[FileCount].FileInfo = FileInfo;
 | 
						|
    FileCount++;
 | 
						|
  }
 | 
						|
 | 
						|
  DEBUG_CODE_BEGIN ();
 | 
						|
  for (Link = FileInfoList.ForwardLink; Link != &FileInfoList; Link = Link->ForwardLink) {
 | 
						|
    FileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);
 | 
						|
    FileInfo      = FileInfoEntry->FileInfo;
 | 
						|
    DEBUG ((DEBUG_INFO, "Successfully read capsule file %s from disk.\n", FileInfo->FileName));
 | 
						|
  }
 | 
						|
 | 
						|
  DEBUG_CODE_END ();
 | 
						|
 | 
						|
EXIT:
 | 
						|
 | 
						|
  *FilePtr = TempFilePtrBuf;
 | 
						|
  *FileNum = FileCount;
 | 
						|
 | 
						|
  //
 | 
						|
  // FileInfo will be freed by Calller
 | 
						|
  //
 | 
						|
  while (!IsListEmpty (&FileInfoList)) {
 | 
						|
    Link = FileInfoList.ForwardLink;
 | 
						|
    RemoveEntryList (Link);
 | 
						|
 | 
						|
    FileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);
 | 
						|
 | 
						|
    FreePool (FileInfoEntry->FileNameFirstPart);
 | 
						|
    FreePool (FileInfoEntry->FileNameSecondPart);
 | 
						|
    FreePool (FileInfoEntry);
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This routine is called to remove all qualified image from file from an given directory.
 | 
						|
 | 
						|
  @param[in] Dir                  Directory file handler
 | 
						|
  @param[in] FileAttr             Attribute of files to be deleted
 | 
						|
 | 
						|
  @retval EFI_SUCCESS  Succeed to remove all files from an given directory.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
RemoveFileFromDir (
 | 
						|
  IN EFI_FILE_HANDLE  Dir,
 | 
						|
  IN UINT64           FileAttr
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS       Status;
 | 
						|
  LIST_ENTRY       *Link;
 | 
						|
  LIST_ENTRY       FileInfoList;
 | 
						|
  EFI_FILE_HANDLE  FileHandle;
 | 
						|
  FILE_INFO_ENTRY  *FileInfoEntry;
 | 
						|
  EFI_FILE_INFO    *FileInfo;
 | 
						|
  UINTN            FileCount;
 | 
						|
 | 
						|
  FileHandle = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // Get file list in Dir in alphabetical order
 | 
						|
  //
 | 
						|
  Status = GetFileInfoListInAlphabetFromDir (
 | 
						|
             Dir,
 | 
						|
             FileAttr,
 | 
						|
             &FileInfoList,
 | 
						|
             &FileCount
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "GetFileInfoListInAlphabetFromDir Failed!\n"));
 | 
						|
    goto EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  if (FileCount == 0) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "No file found in Dir!\n"));
 | 
						|
    Status = EFI_NOT_FOUND;
 | 
						|
    goto EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Delete all files with given attribute in Dir
 | 
						|
  //
 | 
						|
  for (Link = FileInfoList.ForwardLink; Link != &(FileInfoList); Link = Link->ForwardLink) {
 | 
						|
    //
 | 
						|
    // Get FileInfo from the link list
 | 
						|
    //
 | 
						|
    FileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);
 | 
						|
    FileInfo      = FileInfoEntry->FileInfo;
 | 
						|
 | 
						|
    Status = Dir->Open (
 | 
						|
                    Dir,
 | 
						|
                    &FileHandle,
 | 
						|
                    FileInfo->FileName,
 | 
						|
                    EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE,
 | 
						|
                    0
 | 
						|
                    );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    Status = FileHandle->Delete (FileHandle);
 | 
						|
  }
 | 
						|
 | 
						|
EXIT:
 | 
						|
 | 
						|
  while (!IsListEmpty (&FileInfoList)) {
 | 
						|
    Link = FileInfoList.ForwardLink;
 | 
						|
    RemoveEntryList (Link);
 | 
						|
 | 
						|
    FileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);
 | 
						|
 | 
						|
    FreePool (FileInfoEntry->FileInfo);
 | 
						|
    FreePool (FileInfoEntry);
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This routine is called to get all caspules from file. The capsule file image is
 | 
						|
  copied to BS memory. Caller is responsible to free them.
 | 
						|
 | 
						|
  @param[in]    MaxRetry             Max Connection Retry. Stall 100ms between each connection try to ensure
 | 
						|
                                     devices like USB can get enumerated.
 | 
						|
  @param[out]   CapsulePtr           Copied Capsule file Image Info buffer
 | 
						|
  @param[out]   CapsuleNum           CapsuleNumber
 | 
						|
  @param[out]   FsHandle             File system handle
 | 
						|
  @param[out]   LoadOptionNumber     OptionNumber of boot option
 | 
						|
 | 
						|
  @retval EFI_SUCCESS  Succeed to get all capsules.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
GetAllCapsuleOnDisk (
 | 
						|
  IN  UINTN       MaxRetry,
 | 
						|
  OUT IMAGE_INFO  **CapsulePtr,
 | 
						|
  OUT UINTN       *CapsuleNum,
 | 
						|
  OUT EFI_HANDLE  *FsHandle,
 | 
						|
  OUT UINT16      *LoadOptionNumber
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                       Status;
 | 
						|
  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  *Fs;
 | 
						|
  EFI_FILE_HANDLE                  RootDir;
 | 
						|
  EFI_FILE_HANDLE                  FileDir;
 | 
						|
  UINT16                           *TempOptionNumber;
 | 
						|
 | 
						|
  TempOptionNumber = NULL;
 | 
						|
  *CapsuleNum      = 0;
 | 
						|
 | 
						|
  Status = GetEfiSysPartitionFromActiveBootOption (MaxRetry, &TempOptionNumber, FsHandle);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = gBS->HandleProtocol (*FsHandle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = Fs->OpenVolume (Fs, &RootDir);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = RootDir->Open (
 | 
						|
                      RootDir,
 | 
						|
                      &FileDir,
 | 
						|
                      EFI_CAPSULE_FILE_DIRECTORY,
 | 
						|
                      EFI_FILE_MODE_READ,
 | 
						|
                      0
 | 
						|
                      );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "CodLibGetAllCapsuleOnDisk fail to open RootDir!\n"));
 | 
						|
    RootDir->Close (RootDir);
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  RootDir->Close (RootDir);
 | 
						|
 | 
						|
  //
 | 
						|
  // Only Load files with EFI_FILE_SYSTEM or EFI_FILE_ARCHIVE attribute
 | 
						|
  // ignore EFI_FILE_READ_ONLY, EFI_FILE_HIDDEN, EFI_FILE_RESERVED, EFI_FILE_DIRECTORY
 | 
						|
  //
 | 
						|
  Status = GetFileImageInAlphabetFromDir (
 | 
						|
             FileDir,
 | 
						|
             EFI_FILE_SYSTEM | EFI_FILE_ARCHIVE,
 | 
						|
             CapsulePtr,
 | 
						|
             CapsuleNum
 | 
						|
             );
 | 
						|
  DEBUG ((DEBUG_INFO, "GetFileImageInAlphabetFromDir status %x\n", Status));
 | 
						|
 | 
						|
  //
 | 
						|
  // Always remove file to avoid deadloop in capsule process
 | 
						|
  //
 | 
						|
  Status = RemoveFileFromDir (FileDir, EFI_FILE_SYSTEM | EFI_FILE_ARCHIVE);
 | 
						|
  DEBUG ((DEBUG_INFO, "RemoveFileFromDir status %x\n", Status));
 | 
						|
 | 
						|
  FileDir->Close (FileDir);
 | 
						|
 | 
						|
  if (LoadOptionNumber != NULL) {
 | 
						|
    *LoadOptionNumber = *TempOptionNumber;
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Build Gather list for a list of capsule images.
 | 
						|
 | 
						|
  @param[in]  CapsuleBuffer    An array of pointer to capsule images
 | 
						|
  @param[in]  CapsuleSize      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                          *CapsuleSize,
 | 
						|
  IN UINTN                          CapsuleNum,
 | 
						|
  OUT EFI_CAPSULE_BLOCK_DESCRIPTOR  **BlockDescriptors
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                    Status;
 | 
						|
  EFI_CAPSULE_BLOCK_DESCRIPTOR  *BlockDescriptors1;
 | 
						|
  EFI_CAPSULE_BLOCK_DESCRIPTOR  *BlockDescriptorPre;
 | 
						|
  EFI_CAPSULE_BLOCK_DESCRIPTOR  *BlockDescriptorsHeader;
 | 
						|
  UINTN                         Index;
 | 
						|
 | 
						|
  BlockDescriptors1      = NULL;
 | 
						|
  BlockDescriptorPre     = NULL;
 | 
						|
  BlockDescriptorsHeader = NULL;
 | 
						|
 | 
						|
  for (Index = 0; Index < CapsuleNum; Index++) {
 | 
						|
    //
 | 
						|
    // Allocate memory for the descriptors.
 | 
						|
    //
 | 
						|
    BlockDescriptors1 = AllocateZeroPool (2 * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR));
 | 
						|
    if (BlockDescriptors1 == NULL) {
 | 
						|
      DEBUG ((DEBUG_ERROR, "BuildGatherList: failed to allocate memory for descriptors\n"));
 | 
						|
      Status = EFI_OUT_OF_RESOURCES;
 | 
						|
      goto ERREXIT;
 | 
						|
    } else {
 | 
						|
      DEBUG ((DEBUG_INFO, "BuildGatherList: creating capsule descriptors at 0x%X\n", (UINTN)BlockDescriptors1));
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Record descirptor header
 | 
						|
    //
 | 
						|
    if (Index == 0) {
 | 
						|
      BlockDescriptorsHeader = BlockDescriptors1;
 | 
						|
    }
 | 
						|
 | 
						|
    if (BlockDescriptorPre != NULL) {
 | 
						|
      BlockDescriptorPre->Union.ContinuationPointer = (UINTN)BlockDescriptors1;
 | 
						|
      BlockDescriptorPre->Length                    = 0;
 | 
						|
    }
 | 
						|
 | 
						|
    BlockDescriptors1->Union.DataBlock = (UINTN)CapsuleBuffer[Index];
 | 
						|
    BlockDescriptors1->Length          = CapsuleSize[Index];
 | 
						|
 | 
						|
    BlockDescriptorPre = BlockDescriptors1 + 1;
 | 
						|
    BlockDescriptors1  = NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Null-terminate.
 | 
						|
  //
 | 
						|
  if (BlockDescriptorPre != NULL) {
 | 
						|
    BlockDescriptorPre->Union.ContinuationPointer = (UINTN)NULL;
 | 
						|
    BlockDescriptorPre->Length                    = 0;
 | 
						|
    *BlockDescriptors                             = BlockDescriptorsHeader;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
 | 
						|
ERREXIT:
 | 
						|
  if (BlockDescriptors1 != NULL) {
 | 
						|
    FreePool (BlockDescriptors1);
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This routine is called to check if CapsuleOnDisk flag in OsIndications Variable
 | 
						|
  is enabled.
 | 
						|
 | 
						|
  @retval TRUE     Flag is enabled
 | 
						|
  @retval FALSE    Flag is not enabled
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
EFIAPI
 | 
						|
CoDCheckCapsuleOnDiskFlag (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  UINT64      OsIndication;
 | 
						|
  UINTN       DataSize;
 | 
						|
 | 
						|
  //
 | 
						|
  // Check File Capsule Delivery Supported Flag in OsIndication variable
 | 
						|
  //
 | 
						|
  OsIndication = 0;
 | 
						|
  DataSize     = sizeof (UINT64);
 | 
						|
  Status       = gRT->GetVariable (
 | 
						|
                        EFI_OS_INDICATIONS_VARIABLE_NAME,
 | 
						|
                        &gEfiGlobalVariableGuid,
 | 
						|
                        NULL,
 | 
						|
                        &DataSize,
 | 
						|
                        &OsIndication
 | 
						|
                        );
 | 
						|
  if (!EFI_ERROR (Status) &&
 | 
						|
      ((OsIndication & EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED) != 0))
 | 
						|
  {
 | 
						|
    return TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This routine is called to clear CapsuleOnDisk flags including OsIndications and BootNext variable.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS   All Capsule On Disk flags are cleared
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
CoDClearCapsuleOnDiskFlag (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  UINT64      OsIndication;
 | 
						|
  UINTN       DataSize;
 | 
						|
 | 
						|
  //
 | 
						|
  // Reset File Capsule Delivery Supported Flag in OsIndication variable
 | 
						|
  //
 | 
						|
  OsIndication = 0;
 | 
						|
  DataSize     = sizeof (UINT64);
 | 
						|
  Status       = gRT->GetVariable (
 | 
						|
                        EFI_OS_INDICATIONS_VARIABLE_NAME,
 | 
						|
                        &gEfiGlobalVariableGuid,
 | 
						|
                        NULL,
 | 
						|
                        &DataSize,
 | 
						|
                        &OsIndication
 | 
						|
                        );
 | 
						|
  if (EFI_ERROR (Status) ||
 | 
						|
      ((OsIndication & EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED) == 0))
 | 
						|
  {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  OsIndication &= ~((UINT64)EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED);
 | 
						|
  Status        = gRT->SetVariable (
 | 
						|
                         EFI_OS_INDICATIONS_VARIABLE_NAME,
 | 
						|
                         &gEfiGlobalVariableGuid,
 | 
						|
                         EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
 | 
						|
                         sizeof (UINT64),
 | 
						|
                         &OsIndication
 | 
						|
                         );
 | 
						|
  ASSERT (!EFI_ERROR (Status));
 | 
						|
 | 
						|
  //
 | 
						|
  // Delete BootNext variable. Capsule Process may reset system, so can't rely on Bds to clear this variable
 | 
						|
  //
 | 
						|
  Status = gRT->SetVariable (
 | 
						|
                  EFI_BOOT_NEXT_VARIABLE_NAME,
 | 
						|
                  &gEfiGlobalVariableGuid,
 | 
						|
                  0,
 | 
						|
                  0,
 | 
						|
                  NULL
 | 
						|
                  );
 | 
						|
  ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND);
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This routine is called to clear CapsuleOnDisk Relocation Info variable.
 | 
						|
  Total Capsule On Disk length is recorded in this variable
 | 
						|
 | 
						|
  @retval EFI_SUCCESS   Capsule On Disk flags are cleared
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
CoDClearCapsuleRelocationInfo (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  return gRT->SetVariable (
 | 
						|
                COD_RELOCATION_INFO_VAR_NAME,
 | 
						|
                &gEfiCapsuleVendorGuid,
 | 
						|
                0,
 | 
						|
                0,
 | 
						|
                NULL
 | 
						|
                );
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Relocate Capsule on Disk from EFI system partition to a platform-specific NV storage device
 | 
						|
  with BlockIo protocol. Relocation device path, identified by PcdCodRelocationDevPath, must
 | 
						|
  be a full device path.
 | 
						|
  Device enumeration like USB costs time, user can input MaxRetry to tell function to retry.
 | 
						|
  Function will stall 100ms between each retry.
 | 
						|
 | 
						|
  Side Effects:
 | 
						|
    Content corruption. Block IO write directly touches low level write. Orignal partitions, file systems
 | 
						|
    of the relocation device will be corrupted.
 | 
						|
 | 
						|
  @param[in]    MaxRetry             Max Connection Retry. Stall 100ms between each connection try to ensure
 | 
						|
                                     devices like USB can get enumerated.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS   Capsule on Disk images are sucessfully relocated to the platform-specific device.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
RelocateCapsuleToDisk (
 | 
						|
  UINTN  MaxRetry
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                       Status;
 | 
						|
  UINTN                            CapsuleOnDiskNum;
 | 
						|
  UINTN                            Index;
 | 
						|
  UINTN                            DataSize;
 | 
						|
  UINT64                           TotalImageSize;
 | 
						|
  UINT64                           TotalImageNameSize;
 | 
						|
  IMAGE_INFO                       *CapsuleOnDiskBuf;
 | 
						|
  EFI_HANDLE                       Handle;
 | 
						|
  EFI_HANDLE                       TempHandle;
 | 
						|
  EFI_HANDLE                       *HandleBuffer;
 | 
						|
  UINTN                            NumberOfHandles;
 | 
						|
  EFI_BLOCK_IO_PROTOCOL            *BlockIo;
 | 
						|
  UINT8                            *CapsuleDataBuf;
 | 
						|
  UINT8                            *CapsulePtr;
 | 
						|
  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  *Fs;
 | 
						|
  EFI_FILE_HANDLE                  RootDir;
 | 
						|
  EFI_FILE_HANDLE                  TempCodFile;
 | 
						|
  UINT64                           TempCodFileSize;
 | 
						|
  EFI_DEVICE_PATH                  *TempDevicePath;
 | 
						|
  BOOLEAN                          RelocationInfo;
 | 
						|
  UINT16                           LoadOptionNumber;
 | 
						|
  EFI_CAPSULE_HEADER               FileNameCapsuleHeader;
 | 
						|
 | 
						|
  RootDir          = NULL;
 | 
						|
  TempCodFile      = NULL;
 | 
						|
  HandleBuffer     = NULL;
 | 
						|
  CapsuleDataBuf   = NULL;
 | 
						|
  CapsuleOnDiskBuf = NULL;
 | 
						|
  NumberOfHandles  = 0;
 | 
						|
 | 
						|
  DEBUG ((DEBUG_INFO, "CapsuleOnDisk RelocateCapsule Enter\n"));
 | 
						|
 | 
						|
  //
 | 
						|
  // 1. Load all Capsule On Disks in to memory
 | 
						|
  //
 | 
						|
  Status = GetAllCapsuleOnDisk (MaxRetry, &CapsuleOnDiskBuf, &CapsuleOnDiskNum, &Handle, &LoadOptionNumber);
 | 
						|
  if (EFI_ERROR (Status) || (CapsuleOnDiskNum == 0) || (CapsuleOnDiskBuf == NULL)) {
 | 
						|
    DEBUG ((DEBUG_INFO, "RelocateCapsule: GetAllCapsuleOnDisk Status - 0x%x\n", Status));
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // 2. Connect platform special device path as relocation device.
 | 
						|
  // If no platform special device path specified or the device path is invalid, use the EFI system partition where
 | 
						|
  // stores the capsules as relocation device.
 | 
						|
  //
 | 
						|
  if (IsDevicePathValid ((EFI_DEVICE_PATH *)PcdGetPtr (PcdCodRelocationDevPath), PcdGetSize (PcdCodRelocationDevPath))) {
 | 
						|
    Status = EfiBootManagerConnectDevicePath ((EFI_DEVICE_PATH *)PcdGetPtr (PcdCodRelocationDevPath), &TempHandle);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      DEBUG ((DEBUG_ERROR, "RelocateCapsule: EfiBootManagerConnectDevicePath Status - 0x%x\n", Status));
 | 
						|
      goto EXIT;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Connect all the child handle. Partition & FAT drivers are allowed in this case
 | 
						|
    //
 | 
						|
    gBS->ConnectController (TempHandle, NULL, NULL, TRUE);
 | 
						|
    Status = gBS->LocateHandleBuffer (
 | 
						|
                    ByProtocol,
 | 
						|
                    &gEfiSimpleFileSystemProtocolGuid,
 | 
						|
                    NULL,
 | 
						|
                    &NumberOfHandles,
 | 
						|
                    &HandleBuffer
 | 
						|
                    );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      DEBUG ((DEBUG_ERROR, "RelocateCapsule: LocateHandleBuffer Status - 0x%x\n", Status));
 | 
						|
      goto EXIT;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Find first Simple File System Handle which can match PcdCodRelocationDevPath
 | 
						|
    //
 | 
						|
    for (Index = 0; Index < NumberOfHandles; Index++) {
 | 
						|
      Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&TempDevicePath);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
 | 
						|
      DataSize = GetDevicePathSize ((EFI_DEVICE_PATH *)PcdGetPtr (PcdCodRelocationDevPath)) - sizeof (EFI_DEVICE_PATH);
 | 
						|
      if (0 == CompareMem ((EFI_DEVICE_PATH *)PcdGetPtr (PcdCodRelocationDevPath), TempDevicePath, DataSize)) {
 | 
						|
        Handle = HandleBuffer[Index];
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    FreePool (HandleBuffer);
 | 
						|
 | 
						|
    if (Index == NumberOfHandles) {
 | 
						|
      DEBUG ((DEBUG_ERROR, "RelocateCapsule: No simple file system protocol found.\n"));
 | 
						|
      Status = EFI_NOT_FOUND;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);
 | 
						|
  if (EFI_ERROR (Status) || BlockIo->Media->ReadOnly) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "Fail to find Capsule on Disk relocation BlockIo device or device is ReadOnly!\n"));
 | 
						|
    goto EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check if device used to relocate Capsule On Disk is big enough
 | 
						|
  //
 | 
						|
  TotalImageSize     = 0;
 | 
						|
  TotalImageNameSize = 0;
 | 
						|
  for (Index = 0; Index < CapsuleOnDiskNum; Index++) {
 | 
						|
    //
 | 
						|
    // Overflow check
 | 
						|
    //
 | 
						|
    if (MAX_ADDRESS - (UINTN)TotalImageSize <= CapsuleOnDiskBuf[Index].FileInfo->FileSize) {
 | 
						|
      Status = EFI_INVALID_PARAMETER;
 | 
						|
      goto EXIT;
 | 
						|
    }
 | 
						|
 | 
						|
    if (MAX_ADDRESS - (UINTN)TotalImageNameSize <= StrSize (CapsuleOnDiskBuf[Index].FileInfo->FileName)) {
 | 
						|
      Status = EFI_INVALID_PARAMETER;
 | 
						|
      goto EXIT;
 | 
						|
    }
 | 
						|
 | 
						|
    TotalImageSize     += CapsuleOnDiskBuf[Index].FileInfo->FileSize;
 | 
						|
    TotalImageNameSize += StrSize (CapsuleOnDiskBuf[Index].FileInfo->FileName);
 | 
						|
    DEBUG ((DEBUG_INFO, "RelocateCapsule: %x Size %x\n", CapsuleOnDiskBuf[Index].FileInfo->FileName, CapsuleOnDiskBuf[Index].FileInfo->FileSize));
 | 
						|
  }
 | 
						|
 | 
						|
  DEBUG ((DEBUG_INFO, "RelocateCapsule: TotalImageSize %x\n", TotalImageSize));
 | 
						|
  DEBUG ((DEBUG_INFO, "RelocateCapsule: TotalImageNameSize %x\n", TotalImageNameSize));
 | 
						|
 | 
						|
  if ((MAX_ADDRESS - (UINTN)TotalImageNameSize <= sizeof (UINT64) * 2) ||
 | 
						|
      (MAX_ADDRESS - (UINTN)TotalImageSize <= (UINTN)TotalImageNameSize + sizeof (UINT64) * 2))
 | 
						|
  {
 | 
						|
    Status = EFI_INVALID_PARAMETER;
 | 
						|
    goto EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  TempCodFileSize = sizeof (UINT64) + TotalImageSize + sizeof (EFI_CAPSULE_HEADER) + TotalImageNameSize;
 | 
						|
 | 
						|
  //
 | 
						|
  // Check if CapsuleTotalSize. There could be reminder, so use LastBlock number directly
 | 
						|
  //
 | 
						|
  if (DivU64x32 (TempCodFileSize, BlockIo->Media->BlockSize) > BlockIo->Media->LastBlock) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "RelocateCapsule: Relocation device isn't big enough to hold all Capsule on Disk!\n"));
 | 
						|
    DEBUG ((DEBUG_ERROR, "TotalImageSize = %x\n", TotalImageSize));
 | 
						|
    DEBUG ((DEBUG_ERROR, "TotalImageNameSize = %x\n", TotalImageNameSize));
 | 
						|
    DEBUG ((DEBUG_ERROR, "RelocationDev BlockSize = %x LastBlock = %x\n", BlockIo->Media->BlockSize, BlockIo->Media->LastBlock));
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  CapsuleDataBuf = AllocatePool ((UINTN)TempCodFileSize);
 | 
						|
  if (CapsuleDataBuf == NULL) {
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // First UINT64 reserved for total image size, including capsule name capsule.
 | 
						|
  //
 | 
						|
  *(UINT64 *)CapsuleDataBuf = TotalImageSize + sizeof (EFI_CAPSULE_HEADER) + TotalImageNameSize;
 | 
						|
 | 
						|
  //
 | 
						|
  // Line up all the Capsule on Disk and write to relocation disk at one time. It could save some time in disk write
 | 
						|
  //
 | 
						|
  for (Index = 0, CapsulePtr = CapsuleDataBuf + sizeof (UINT64); Index < CapsuleOnDiskNum; Index++) {
 | 
						|
    CopyMem (CapsulePtr, CapsuleOnDiskBuf[Index].ImageAddress, (UINTN)CapsuleOnDiskBuf[Index].FileInfo->FileSize);
 | 
						|
    CapsulePtr += CapsuleOnDiskBuf[Index].FileInfo->FileSize;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Line the capsule header for capsule name capsule.
 | 
						|
  //
 | 
						|
  CopyGuid (&FileNameCapsuleHeader.CapsuleGuid, &gEdkiiCapsuleOnDiskNameGuid);
 | 
						|
  FileNameCapsuleHeader.CapsuleImageSize = (UINT32)TotalImageNameSize + sizeof (EFI_CAPSULE_HEADER);
 | 
						|
  FileNameCapsuleHeader.Flags            = CAPSULE_FLAGS_PERSIST_ACROSS_RESET;
 | 
						|
  FileNameCapsuleHeader.HeaderSize       = sizeof (EFI_CAPSULE_HEADER);
 | 
						|
  CopyMem (CapsulePtr, &FileNameCapsuleHeader, FileNameCapsuleHeader.HeaderSize);
 | 
						|
  CapsulePtr += FileNameCapsuleHeader.HeaderSize;
 | 
						|
 | 
						|
  //
 | 
						|
  // Line up all the Capsule file names.
 | 
						|
  //
 | 
						|
  for (Index = 0; Index < CapsuleOnDiskNum; Index++) {
 | 
						|
    CopyMem (CapsulePtr, CapsuleOnDiskBuf[Index].FileInfo->FileName, StrSize (CapsuleOnDiskBuf[Index].FileInfo->FileName));
 | 
						|
    CapsulePtr += StrSize (CapsuleOnDiskBuf[Index].FileInfo->FileName);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // 5. Flash all Capsules on Disk to TempCoD.tmp under RootDir
 | 
						|
  //
 | 
						|
  Status = Fs->OpenVolume (Fs, &RootDir);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "RelocateCapsule: OpenVolume error. %x\n", Status));
 | 
						|
    goto EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = RootDir->Open (
 | 
						|
                      RootDir,
 | 
						|
                      &TempCodFile,
 | 
						|
                      (CHAR16 *)PcdGetPtr (PcdCoDRelocationFileName),
 | 
						|
                      EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE,
 | 
						|
                      0
 | 
						|
                      );
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    //
 | 
						|
    // Error handling code to prevent malicious code to hold this file to block capsule on disk
 | 
						|
    //
 | 
						|
    TempCodFile->Delete (TempCodFile);
 | 
						|
  }
 | 
						|
 | 
						|
  Status = RootDir->Open (
 | 
						|
                      RootDir,
 | 
						|
                      &TempCodFile,
 | 
						|
                      (CHAR16 *)PcdGetPtr (PcdCoDRelocationFileName),
 | 
						|
                      EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE,
 | 
						|
                      0
 | 
						|
                      );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "RelocateCapsule: Open TemCoD.tmp error. %x\n", Status));
 | 
						|
    goto EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Always write at the begining of TempCap file
 | 
						|
  //
 | 
						|
  DataSize = (UINTN)TempCodFileSize;
 | 
						|
  Status   = TempCodFile->Write (
 | 
						|
                            TempCodFile,
 | 
						|
                            &DataSize,
 | 
						|
                            CapsuleDataBuf
 | 
						|
                            );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "RelocateCapsule: Write TemCoD.tmp error. %x\n", Status));
 | 
						|
    goto EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  if (DataSize != TempCodFileSize) {
 | 
						|
    Status = EFI_DEVICE_ERROR;
 | 
						|
    goto EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Save Capsule On Disk relocation info to "CodRelocationInfo" Var
 | 
						|
  // It is used in next reboot by TCB
 | 
						|
  //
 | 
						|
  RelocationInfo = TRUE;
 | 
						|
  Status         = gRT->SetVariable (
 | 
						|
                          COD_RELOCATION_INFO_VAR_NAME,
 | 
						|
                          &gEfiCapsuleVendorGuid,
 | 
						|
                          EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
 | 
						|
                          sizeof (BOOLEAN),
 | 
						|
                          &RelocationInfo
 | 
						|
                          );
 | 
						|
  //
 | 
						|
  // Save the LoadOptionNumber of the boot option, where the capsule is relocated,
 | 
						|
  // into "CodRelocationLoadOption" var. It is used in next reboot after capsule is
 | 
						|
  // updated out of TCB to remove the TempCoDFile.
 | 
						|
  //
 | 
						|
  Status = gRT->SetVariable (
 | 
						|
                  COD_RELOCATION_LOAD_OPTION_VAR_NAME,
 | 
						|
                  &gEfiCapsuleVendorGuid,
 | 
						|
                  EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
 | 
						|
                  sizeof (UINT16),
 | 
						|
                  &LoadOptionNumber
 | 
						|
                  );
 | 
						|
 | 
						|
EXIT:
 | 
						|
 | 
						|
  if (CapsuleDataBuf != NULL) {
 | 
						|
    FreePool (CapsuleDataBuf);
 | 
						|
  }
 | 
						|
 | 
						|
  if (CapsuleOnDiskBuf != NULL) {
 | 
						|
    //
 | 
						|
    // Free resources allocated by CodLibGetAllCapsuleOnDisk
 | 
						|
    //
 | 
						|
    for (Index = 0; Index < CapsuleOnDiskNum; Index++ ) {
 | 
						|
      FreePool (CapsuleOnDiskBuf[Index].ImageAddress);
 | 
						|
      FreePool (CapsuleOnDiskBuf[Index].FileInfo);
 | 
						|
    }
 | 
						|
 | 
						|
    FreePool (CapsuleOnDiskBuf);
 | 
						|
  }
 | 
						|
 | 
						|
  if (TempCodFile != NULL) {
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      TempCodFile->Delete (TempCodFile);
 | 
						|
    } else {
 | 
						|
      TempCodFile->Close (TempCodFile);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (RootDir != NULL) {
 | 
						|
    RootDir->Close (RootDir);
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  For the platforms that support Capsule In Ram, reuse the Capsule In Ram to deliver capsule.
 | 
						|
  Relocate Capsule On Disk to memory and call UpdateCapsule().
 | 
						|
  Device enumeration like USB costs time, user can input MaxRetry to tell function to retry.
 | 
						|
  Function will stall 100ms between each retry.
 | 
						|
 | 
						|
  @param[in]    MaxRetry             Max Connection Retry. Stall 100ms between each connection try to ensure
 | 
						|
                                     devices like USB can get enumerated.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS   Deliver capsule through Capsule In Ram successfully.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
RelocateCapsuleToRam (
 | 
						|
  UINTN  MaxRetry
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                    Status;
 | 
						|
  UINTN                         CapsuleOnDiskNum;
 | 
						|
  IMAGE_INFO                    *CapsuleOnDiskBuf;
 | 
						|
  EFI_HANDLE                    Handle;
 | 
						|
  EFI_CAPSULE_BLOCK_DESCRIPTOR  *BlockDescriptors;
 | 
						|
  VOID                          **CapsuleBuffer;
 | 
						|
  UINTN                         *CapsuleSize;
 | 
						|
  EFI_CAPSULE_HEADER            *FileNameCapsule;
 | 
						|
  UINTN                         Index;
 | 
						|
  UINT8                         *StringBuf;
 | 
						|
  UINTN                         StringSize;
 | 
						|
  UINTN                         TotalStringSize;
 | 
						|
  UINTN                         CapsulesToProcess;
 | 
						|
 | 
						|
  CapsuleOnDiskBuf = NULL;
 | 
						|
  BlockDescriptors = NULL;
 | 
						|
  CapsuleBuffer    = NULL;
 | 
						|
  CapsuleSize      = NULL;
 | 
						|
  FileNameCapsule  = NULL;
 | 
						|
  TotalStringSize  = 0;
 | 
						|
 | 
						|
  //
 | 
						|
  // 1. Load all Capsule On Disks into memory
 | 
						|
  //
 | 
						|
  Status = GetAllCapsuleOnDisk (MaxRetry, &CapsuleOnDiskBuf, &CapsuleOnDiskNum, &Handle, NULL);
 | 
						|
  if (EFI_ERROR (Status) || (CapsuleOnDiskNum == 0) || (CapsuleOnDiskBuf == NULL)) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "GetAllCapsuleOnDisk Status - 0x%x\n", Status));
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // 2. Add a capsule for Capsule file name strings
 | 
						|
  //
 | 
						|
  CapsuleBuffer = AllocateZeroPool ((CapsuleOnDiskNum + 1) * sizeof (VOID *));
 | 
						|
  if (CapsuleBuffer == NULL) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "Fail to allocate memory for capsules.\n"));
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  CapsuleSize = AllocateZeroPool ((CapsuleOnDiskNum + 1) * sizeof (UINTN));
 | 
						|
  if (CapsuleSize == NULL) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "Fail to allocate memory for capsules.\n"));
 | 
						|
    FreePool (CapsuleBuffer);
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  for (Index = 0; Index < CapsuleOnDiskNum; Index++) {
 | 
						|
    CapsuleBuffer[Index] = (VOID *)(UINTN)CapsuleOnDiskBuf[Index].ImageAddress;
 | 
						|
    CapsuleSize[Index]   = (UINTN)CapsuleOnDiskBuf[Index].FileInfo->FileSize;
 | 
						|
    TotalStringSize     += StrSize (CapsuleOnDiskBuf[Index].FileInfo->FileName);
 | 
						|
  }
 | 
						|
 | 
						|
  // If Persist Across Reset isn't supported, skip the file name strings capsule
 | 
						|
  if (!FeaturePcdGet (PcdSupportUpdateCapsuleReset)) {
 | 
						|
    CapsulesToProcess = CapsuleOnDiskNum;
 | 
						|
    goto BuildGather;
 | 
						|
  }
 | 
						|
 | 
						|
  CapsulesToProcess = CapsuleOnDiskNum + 1;
 | 
						|
 | 
						|
  FileNameCapsule = AllocateZeroPool (sizeof (EFI_CAPSULE_HEADER) + TotalStringSize);
 | 
						|
  if (FileNameCapsule == NULL) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "Fail to allocate memory for name capsule.\n"));
 | 
						|
    FreePool (CapsuleBuffer);
 | 
						|
    FreePool (CapsuleSize);
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  FileNameCapsule->CapsuleImageSize = (UINT32)(sizeof (EFI_CAPSULE_HEADER) + TotalStringSize);
 | 
						|
  FileNameCapsule->Flags            = CAPSULE_FLAGS_PERSIST_ACROSS_RESET;
 | 
						|
  FileNameCapsule->HeaderSize       = sizeof (EFI_CAPSULE_HEADER);
 | 
						|
  CopyGuid (&(FileNameCapsule->CapsuleGuid), &gEdkiiCapsuleOnDiskNameGuid);
 | 
						|
 | 
						|
  StringBuf = (UINT8 *)FileNameCapsule + FileNameCapsule->HeaderSize;
 | 
						|
  for (Index = 0; Index < CapsuleOnDiskNum; Index++) {
 | 
						|
    StringSize = StrSize (CapsuleOnDiskBuf[Index].FileInfo->FileName);
 | 
						|
    CopyMem (StringBuf, CapsuleOnDiskBuf[Index].FileInfo->FileName, StringSize);
 | 
						|
    StringBuf += StringSize;
 | 
						|
  }
 | 
						|
 | 
						|
  CapsuleBuffer[CapsuleOnDiskNum] = FileNameCapsule;
 | 
						|
  CapsuleSize[CapsuleOnDiskNum]   = TotalStringSize + sizeof (EFI_CAPSULE_HEADER);
 | 
						|
 | 
						|
  //
 | 
						|
  // 3. Build Gather list for the capsules
 | 
						|
  //
 | 
						|
BuildGather:
 | 
						|
  Status = BuildGatherList (CapsuleBuffer, CapsuleSize, CapsulesToProcess, &BlockDescriptors);
 | 
						|
  if (EFI_ERROR (Status) || (BlockDescriptors == NULL)) {
 | 
						|
    FreePool (CapsuleBuffer);
 | 
						|
    FreePool (CapsuleSize);
 | 
						|
    if (FileNameCapsule != NULL) {
 | 
						|
      FreePool (FileNameCapsule);
 | 
						|
    }
 | 
						|
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // 4. Call UpdateCapsule() service
 | 
						|
  //
 | 
						|
  Status = gRT->UpdateCapsule (
 | 
						|
                  (EFI_CAPSULE_HEADER **)CapsuleBuffer,
 | 
						|
                  CapsulesToProcess,
 | 
						|
                  (UINTN)BlockDescriptors
 | 
						|
                  );
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Relocate Capsule on Disk from EFI system partition.
 | 
						|
 | 
						|
  Two solution to deliver Capsule On Disk:
 | 
						|
  Solution A: If PcdCapsuleInRamSupport is enabled, relocate Capsule On Disk to memory and call UpdateCapsule().
 | 
						|
  Solution B: If PcdCapsuleInRamSupport is disabled, relocate Capsule On Disk to a platform-specific NV storage
 | 
						|
  device with BlockIo protocol.
 | 
						|
 | 
						|
  Device enumeration like USB costs time, user can input MaxRetry to tell function to retry.
 | 
						|
  Function will stall 100ms between each retry.
 | 
						|
 | 
						|
  Side Effects:
 | 
						|
    Capsule Delivery Supported Flag in OsIndication variable and BootNext variable will be cleared.
 | 
						|
    Solution B: Content corruption. Block IO write directly touches low level write. Orignal partitions, file
 | 
						|
  systems of the relocation device will be corrupted.
 | 
						|
 | 
						|
  @param[in]    MaxRetry             Max Connection Retry. Stall 100ms between each connection try to ensure
 | 
						|
                                     devices like USB can get enumerated. Input 0 means no retry.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS   Capsule on Disk images are successfully relocated.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
CoDRelocateCapsule (
 | 
						|
  UINTN  MaxRetry
 | 
						|
  )
 | 
						|
{
 | 
						|
  if (!PcdGetBool (PcdCapsuleOnDiskSupport)) {
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Clear CapsuleOnDisk Flag firstly.
 | 
						|
  //
 | 
						|
  CoDClearCapsuleOnDiskFlag ();
 | 
						|
 | 
						|
  //
 | 
						|
  // If Capsule In Ram is supported, delivery capsules through memory
 | 
						|
  //
 | 
						|
  if (PcdGetBool (PcdCapsuleInRamSupport)) {
 | 
						|
    DEBUG ((DEBUG_INFO, "Capsule In Ram is supported, call gRT->UpdateCapsule().\n"));
 | 
						|
    return RelocateCapsuleToRam (MaxRetry);
 | 
						|
  } else {
 | 
						|
    DEBUG ((DEBUG_INFO, "Reallcoate all Capsule on Disks to %s in RootDir.\n", (CHAR16 *)PcdGetPtr (PcdCoDRelocationFileName)));
 | 
						|
    return RelocateCapsuleToDisk (MaxRetry);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Remove the temp file from the root of EFI System Partition.
 | 
						|
  Device enumeration like USB costs time, user can input MaxRetry to tell function to retry.
 | 
						|
  Function will stall 100ms between each retry.
 | 
						|
 | 
						|
  @param[in]    MaxRetry             Max Connection Retry. Stall 100ms between each connection try to ensure
 | 
						|
                                     devices like USB can get enumerated. Input 0 means no retry.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS   Remove the temp file successfully.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
CoDRemoveTempFile (
 | 
						|
  UINTN  MaxRetry
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                       Status;
 | 
						|
  UINTN                            DataSize;
 | 
						|
  UINT16                           *LoadOptionNumber;
 | 
						|
  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  *Fs;
 | 
						|
  EFI_HANDLE                       FsHandle;
 | 
						|
  EFI_FILE_HANDLE                  RootDir;
 | 
						|
  EFI_FILE_HANDLE                  TempCodFile;
 | 
						|
 | 
						|
  RootDir     = NULL;
 | 
						|
  TempCodFile = NULL;
 | 
						|
  DataSize    = sizeof (UINT16);
 | 
						|
 | 
						|
  LoadOptionNumber = AllocatePool (sizeof (UINT16));
 | 
						|
  if (LoadOptionNumber == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check if capsule files are relocated
 | 
						|
  //
 | 
						|
  Status = gRT->GetVariable (
 | 
						|
                  COD_RELOCATION_LOAD_OPTION_VAR_NAME,
 | 
						|
                  &gEfiCapsuleVendorGuid,
 | 
						|
                  NULL,
 | 
						|
                  &DataSize,
 | 
						|
                  (VOID *)LoadOptionNumber
 | 
						|
                  );
 | 
						|
  if (EFI_ERROR (Status) || (DataSize != sizeof (UINT16))) {
 | 
						|
    goto EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Get the EFI file system from the boot option where the capsules are relocated
 | 
						|
  //
 | 
						|
  Status = GetEfiSysPartitionFromActiveBootOption (MaxRetry, &LoadOptionNumber, &FsHandle);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = gBS->HandleProtocol (FsHandle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = Fs->OpenVolume (Fs, &RootDir);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Delete the TempCoDFile
 | 
						|
  //
 | 
						|
  Status = RootDir->Open (
 | 
						|
                      RootDir,
 | 
						|
                      &TempCodFile,
 | 
						|
                      (CHAR16 *)PcdGetPtr (PcdCoDRelocationFileName),
 | 
						|
                      EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE,
 | 
						|
                      0
 | 
						|
                      );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  TempCodFile->Delete (TempCodFile);
 | 
						|
 | 
						|
  //
 | 
						|
  // Clear "CoDRelocationLoadOption" variable
 | 
						|
  //
 | 
						|
  Status = gRT->SetVariable (
 | 
						|
                  COD_RELOCATION_LOAD_OPTION_VAR_NAME,
 | 
						|
                  &gEfiCapsuleVendorGuid,
 | 
						|
                  0,
 | 
						|
                  0,
 | 
						|
                  NULL
 | 
						|
                  );
 | 
						|
 | 
						|
EXIT:
 | 
						|
  if (LoadOptionNumber != NULL) {
 | 
						|
    FreePool (LoadOptionNumber);
 | 
						|
  }
 | 
						|
 | 
						|
  if (RootDir != NULL) {
 | 
						|
    RootDir->Close (RootDir);
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 |