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>
		
			
				
	
	
		
			858 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			858 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  Process Capsule On Disk.
 | 
						|
 | 
						|
  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
 | 
						|
  SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include "CapsuleApp.h"
 | 
						|
 | 
						|
EFI_GUID  mCapsuleOnDiskBootOptionGuid = {
 | 
						|
  0x4CC29BB7, 0x2413, 0x40A2, { 0xB0, 0x6D, 0x25, 0x3E, 0x37, 0x10, 0xF5, 0x32 }
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
  Get file name from file path.
 | 
						|
 | 
						|
  @param  FilePath    File path.
 | 
						|
 | 
						|
  @return Pointer to file name.
 | 
						|
 | 
						|
**/
 | 
						|
CHAR16 *
 | 
						|
GetFileNameFromPath (
 | 
						|
  CHAR16  *FilePath
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS          Status;
 | 
						|
  EFI_SHELL_PROTOCOL  *ShellProtocol;
 | 
						|
  SHELL_FILE_HANDLE   Handle;
 | 
						|
  EFI_FILE_INFO       *FileInfo;
 | 
						|
 | 
						|
  ShellProtocol = GetShellProtocol ();
 | 
						|
  if (ShellProtocol == NULL) {
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Open file by FileName.
 | 
						|
  //
 | 
						|
  Status = ShellProtocol->OpenFileByName (
 | 
						|
                            FilePath,
 | 
						|
                            &Handle,
 | 
						|
                            EFI_FILE_MODE_READ
 | 
						|
                            );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Get file name from EFI_FILE_INFO.
 | 
						|
  //
 | 
						|
  FileInfo = ShellProtocol->GetFileInfo (Handle);
 | 
						|
  ShellProtocol->CloseFile (Handle);
 | 
						|
  if (FileInfo == NULL) {
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  return FileInfo->FileName;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Check if the device path is EFI system Partition.
 | 
						|
 | 
						|
  @param  DevicePath    The ESP device path.
 | 
						|
 | 
						|
  @retval TRUE    DevicePath is a device path for ESP.
 | 
						|
  @retval FALSE   DevicePath is not a device path for ESP.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
IsEfiSysPartitionDevicePath (
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL  *DevicePath
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL  *TempDevicePath;
 | 
						|
  HARDDRIVE_DEVICE_PATH     *Hd;
 | 
						|
  EFI_HANDLE                Handle;
 | 
						|
 | 
						|
  //
 | 
						|
  // 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);
 | 
						|
    return EFI_ERROR (Status) ? FALSE : TRUE;
 | 
						|
  } else {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Dump all EFI System Partition.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
DumpAllEfiSysPartition (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_HANDLE                *SimpleFileSystemHandles;
 | 
						|
  UINTN                     NumberSimpleFileSystemHandles;
 | 
						|
  UINTN                     Index;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
 | 
						|
  UINTN                     NumberEfiSystemPartitions;
 | 
						|
  EFI_SHELL_PROTOCOL        *ShellProtocol;
 | 
						|
 | 
						|
  NumberEfiSystemPartitions = 0;
 | 
						|
 | 
						|
  ShellProtocol = GetShellProtocol ();
 | 
						|
  if (ShellProtocol == NULL) {
 | 
						|
    Print (L"Get Shell Protocol Fail\n");
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  Print (L"EFI System Partition list:\n");
 | 
						|
 | 
						|
  gBS->LocateHandleBuffer (
 | 
						|
         ByProtocol,
 | 
						|
         &gEfiSimpleFileSystemProtocolGuid,
 | 
						|
         NULL,
 | 
						|
         &NumberSimpleFileSystemHandles,
 | 
						|
         &SimpleFileSystemHandles
 | 
						|
         );
 | 
						|
 | 
						|
  for (Index = 0; Index < NumberSimpleFileSystemHandles; Index++) {
 | 
						|
    DevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]);
 | 
						|
    if (IsEfiSysPartitionDevicePath (DevicePath)) {
 | 
						|
      NumberEfiSystemPartitions++;
 | 
						|
      Print (L"    %s\n        %s\n", ShellProtocol->GetMapFromDevicePath (&DevicePath), ConvertDevicePathToText (DevicePath, TRUE, TRUE));
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (NumberEfiSystemPartitions == 0) {
 | 
						|
    Print (L"    No ESP found.\n");
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Check if capsule is provisioned.
 | 
						|
 | 
						|
  @retval TRUE    Capsule is provisioned previously.
 | 
						|
  @retval FALSE   No capsule is provisioned.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
IsCapsuleProvisioned (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  UINT64      OsIndication;
 | 
						|
  UINTN       DataSize;
 | 
						|
 | 
						|
  OsIndication = 0;
 | 
						|
  DataSize     = sizeof (UINT64);
 | 
						|
  Status       = gRT->GetVariable (
 | 
						|
                        L"OsIndications",
 | 
						|
                        &gEfiGlobalVariableGuid,
 | 
						|
                        NULL,
 | 
						|
                        &DataSize,
 | 
						|
                        &OsIndication
 | 
						|
                        );
 | 
						|
  if (!EFI_ERROR (Status) &&
 | 
						|
      ((OsIndication & EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED) != 0))
 | 
						|
  {
 | 
						|
    return TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Get one active Efi System Partition.
 | 
						|
 | 
						|
  @param[out] FsDevicePath   The device path of Fs
 | 
						|
  @param[out] Fs             The file system within EfiSysPartition
 | 
						|
 | 
						|
  @retval EFI_SUCCESS     Get file system successfully
 | 
						|
  @retval EFI_NOT_FOUND   No valid file system found
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
GetEfiSysPartition (
 | 
						|
  OUT EFI_DEVICE_PATH_PROTOCOL         **FsDevicePath,
 | 
						|
  OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  **Fs
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_HANDLE                *SimpleFileSystemHandles;
 | 
						|
  UINTN                     NumberSimpleFileSystemHandles;
 | 
						|
  UINTN                     Index;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
 | 
						|
  EFI_STATUS                Status;
 | 
						|
 | 
						|
  Status = gBS->LocateHandleBuffer (
 | 
						|
                  ByProtocol,
 | 
						|
                  &gEfiSimpleFileSystemProtocolGuid,
 | 
						|
                  NULL,
 | 
						|
                  &NumberSimpleFileSystemHandles,
 | 
						|
                  &SimpleFileSystemHandles
 | 
						|
                  );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
 | 
						|
  for (Index = 0; Index < NumberSimpleFileSystemHandles; Index++) {
 | 
						|
    DevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]);
 | 
						|
    if (IsEfiSysPartitionDevicePath (DevicePath)) {
 | 
						|
      Status = gBS->HandleProtocol (SimpleFileSystemHandles[Index], &gEfiSimpleFileSystemProtocolGuid, (VOID **)Fs);
 | 
						|
      if (!EFI_ERROR (Status)) {
 | 
						|
        *FsDevicePath = DevicePath;
 | 
						|
        return EFI_SUCCESS;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_NOT_FOUND;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Check if Active Efi System Partition within GPT is in the device path.
 | 
						|
 | 
						|
  @param[in]  DevicePath     The device path
 | 
						|
  @param[out] FsDevicePath   The device path of Fs
 | 
						|
  @param[out] Fs             The file system within EfiSysPartition
 | 
						|
 | 
						|
  @retval EFI_SUCCESS    Get file system successfully
 | 
						|
  @retval EFI_NOT_FOUND  No valid file system found
 | 
						|
  @retval others         Get file system failed
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
GetEfiSysPartitionFromDevPath (
 | 
						|
  IN  EFI_DEVICE_PATH_PROTOCOL         *DevicePath,
 | 
						|
  OUT EFI_DEVICE_PATH_PROTOCOL         **FsDevicePath,
 | 
						|
  OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  **Fs
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL  *TempDevicePath;
 | 
						|
  HARDDRIVE_DEVICE_PATH     *Hd;
 | 
						|
  EFI_HANDLE                Handle;
 | 
						|
 | 
						|
  //
 | 
						|
  // 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)) {
 | 
						|
        *FsDevicePath = DevicePathFromHandle (Handle);
 | 
						|
        return EFI_SUCCESS;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_NOT_FOUND;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Get SimpleFileSystem from boot option file path.
 | 
						|
 | 
						|
  @param[in]  DevicePath     The file path of boot option
 | 
						|
  @param[out] FullPath       The full device path of boot device
 | 
						|
  @param[out] Fs             The file system within EfiSysPartition
 | 
						|
 | 
						|
  @retval EFI_SUCCESS    Get file system successfully
 | 
						|
  @retval EFI_NOT_FOUND  No valid file system found
 | 
						|
  @retval others         Get file system failed
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
GetEfiSysPartitionFromBootOptionFilePath (
 | 
						|
  IN  EFI_DEVICE_PATH_PROTOCOL         *DevicePath,
 | 
						|
  OUT EFI_DEVICE_PATH_PROTOCOL         **FullPath,
 | 
						|
  OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  **Fs
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL  *CurFullPath;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL  *PreFullPath;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL  *FsFullPath;
 | 
						|
 | 
						|
  CurFullPath = NULL;
 | 
						|
  FsFullPath  = 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  *DevicePathStr;
 | 
						|
 | 
						|
    DevicePathStr = ConvertDevicePathToText (CurFullPath, TRUE, TRUE);
 | 
						|
    if (DevicePathStr != NULL) {
 | 
						|
      DEBUG ((DEBUG_INFO, "Full device path %s\n", DevicePathStr));
 | 
						|
      FreePool (DevicePathStr);
 | 
						|
    }
 | 
						|
 | 
						|
    DEBUG_CODE_END ();
 | 
						|
 | 
						|
    Status = GetEfiSysPartitionFromDevPath (CurFullPath, &FsFullPath, Fs);
 | 
						|
  } while (EFI_ERROR (Status));
 | 
						|
 | 
						|
  if (*Fs != NULL) {
 | 
						|
    *FullPath = FsFullPath;
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  } else {
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Get a valid SimpleFileSystem within EFI system partition.
 | 
						|
 | 
						|
  @param[in]  Map             The FS mapping capsule write to
 | 
						|
  @param[out] BootNext        The value of BootNext Variable
 | 
						|
  @param[out] Fs              The file system within EfiSysPartition
 | 
						|
  @param[out] UpdateBootNext  The flag to indicate whether update BootNext Variable
 | 
						|
 | 
						|
  @retval EFI_SUCCESS    Get FS successfully
 | 
						|
  @retval EFI_NOT_FOUND  No valid FS found
 | 
						|
  @retval others         Get FS failed
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
GetUpdateFileSystem (
 | 
						|
  IN  CHAR16                           *Map,
 | 
						|
  OUT UINT16                           *BootNext,
 | 
						|
  OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  **Fs,
 | 
						|
  OUT BOOLEAN                          *UpdateBootNext
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                      Status;
 | 
						|
  CHAR16                          BootOptionName[20];
 | 
						|
  UINTN                           Index;
 | 
						|
  CONST EFI_DEVICE_PATH_PROTOCOL  *MappedDevicePath;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL        *DevicePath;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL        *FullPath;
 | 
						|
  UINT16                          *BootNextData;
 | 
						|
  EFI_BOOT_MANAGER_LOAD_OPTION    BootNextOption;
 | 
						|
  EFI_BOOT_MANAGER_LOAD_OPTION    *BootOptionBuffer;
 | 
						|
  UINTN                           BootOptionCount;
 | 
						|
  EFI_SHELL_PROTOCOL              *ShellProtocol;
 | 
						|
  EFI_BOOT_MANAGER_LOAD_OPTION    NewOption;
 | 
						|
 | 
						|
  MappedDevicePath = NULL;
 | 
						|
  BootOptionBuffer = NULL;
 | 
						|
 | 
						|
  ShellProtocol = GetShellProtocol ();
 | 
						|
  if (ShellProtocol == NULL) {
 | 
						|
    Print (L"Get Shell Protocol Fail\n");
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // 1. If Fs is not assigned and there are capsule provisioned before,
 | 
						|
  // Get EFI system partition from BootNext.
 | 
						|
  //
 | 
						|
  if (IsCapsuleProvisioned () && (Map == NULL)) {
 | 
						|
    Status = GetVariable2 (
 | 
						|
               L"BootNext",
 | 
						|
               &gEfiGlobalVariableGuid,
 | 
						|
               (VOID **)&BootNextData,
 | 
						|
               NULL
 | 
						|
               );
 | 
						|
    if (EFI_ERROR (Status) || (BootNextData == NULL)) {
 | 
						|
      Print (L"Get Boot Next Data Fail. Status = %r\n", Status);
 | 
						|
      return EFI_NOT_FOUND;
 | 
						|
    } else {
 | 
						|
      UnicodeSPrint (BootOptionName, sizeof (BootOptionName), L"Boot%04x", *BootNextData);
 | 
						|
      Status = EfiBootManagerVariableToLoadOption (BootOptionName, &BootNextOption);
 | 
						|
      if (!EFI_ERROR (Status)) {
 | 
						|
        DevicePath = BootNextOption.FilePath;
 | 
						|
        Status     = GetEfiSysPartitionFromBootOptionFilePath (DevicePath, &FullPath, Fs);
 | 
						|
        if (!EFI_ERROR (Status)) {
 | 
						|
          *UpdateBootNext = FALSE;
 | 
						|
          Print (L"Get EFI system partition from BootNext : %s\n", BootNextOption.Description);
 | 
						|
          Print (L"%s %s\n", ShellProtocol->GetMapFromDevicePath (&FullPath), ConvertDevicePathToText (FullPath, TRUE, TRUE));
 | 
						|
          return EFI_SUCCESS;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check if Map is valid.
 | 
						|
  //
 | 
						|
  if (Map != NULL) {
 | 
						|
    MappedDevicePath = ShellProtocol->GetDevicePathFromMap (Map);
 | 
						|
    if (MappedDevicePath == NULL) {
 | 
						|
      Print (L"'%s' is not a valid mapping.\n", Map);
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    } else if (!IsEfiSysPartitionDevicePath (DuplicateDevicePath (MappedDevicePath))) {
 | 
						|
      Print (L"'%s' is not a EFI System Partition.\n", Map);
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // 2. Get EFI system partition form boot options.
 | 
						|
  //
 | 
						|
  BootOptionBuffer = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
 | 
						|
  if ((BootOptionBuffer == NULL) ||
 | 
						|
      ((BootOptionCount == 0) && (Map == NULL))
 | 
						|
      )
 | 
						|
  {
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
 | 
						|
  for (Index = 0; Index < BootOptionCount; Index++) {
 | 
						|
    //
 | 
						|
    // Get the boot option from the link list
 | 
						|
    //
 | 
						|
    DevicePath = BootOptionBuffer[Index].FilePath;
 | 
						|
 | 
						|
    //
 | 
						|
    // Skip inactive or legacy boot options
 | 
						|
    //
 | 
						|
    if (((BootOptionBuffer[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 ();
 | 
						|
 | 
						|
    Status = GetEfiSysPartitionFromBootOptionFilePath (DevicePath, &FullPath, Fs);
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
      if (Map == NULL) {
 | 
						|
        *BootNext       = (UINT16)BootOptionBuffer[Index].OptionNumber;
 | 
						|
        *UpdateBootNext = TRUE;
 | 
						|
        Print (L"Found EFI system partition on Boot%04x: %s\n", *BootNext, BootOptionBuffer[Index].Description);
 | 
						|
        Print (L"%s %s\n", ShellProtocol->GetMapFromDevicePath (&FullPath), ConvertDevicePathToText (FullPath, TRUE, TRUE));
 | 
						|
        return EFI_SUCCESS;
 | 
						|
      }
 | 
						|
 | 
						|
      if (StrnCmp (Map, ShellProtocol->GetMapFromDevicePath (&FullPath), StrLen (Map)) == 0) {
 | 
						|
        *BootNext       = (UINT16)BootOptionBuffer[Index].OptionNumber;
 | 
						|
        *UpdateBootNext = TRUE;
 | 
						|
        Print (L"Found Boot Option on %s : %s\n", Map, BootOptionBuffer[Index].Description);
 | 
						|
        return EFI_SUCCESS;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // 3. If no ESP is found on boot option, try to find a ESP and create boot option for it.
 | 
						|
  //
 | 
						|
  if (Map != NULL) {
 | 
						|
    //
 | 
						|
    // If map is assigned, try to get ESP from mapped Fs.
 | 
						|
    //
 | 
						|
    DevicePath = DuplicateDevicePath (MappedDevicePath);
 | 
						|
    Status     = GetEfiSysPartitionFromDevPath (DevicePath, &FullPath, Fs);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      Print (L"Error: Cannot get EFI system partition from '%s' - %r\n", Map, Status);
 | 
						|
      return EFI_NOT_FOUND;
 | 
						|
    }
 | 
						|
 | 
						|
    Print (L"Warning: Cannot find Boot Option on '%s'!\n", Map);
 | 
						|
  } else {
 | 
						|
    Status = GetEfiSysPartition (&DevicePath, Fs);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      Print (L"Error: Cannot find a EFI system partition!\n");
 | 
						|
      return EFI_NOT_FOUND;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  Print (L"Create Boot option for capsule on disk:\n");
 | 
						|
  Status = EfiBootManagerInitializeLoadOption (
 | 
						|
             &NewOption,
 | 
						|
             LoadOptionNumberUnassigned,
 | 
						|
             LoadOptionTypeBoot,
 | 
						|
             LOAD_OPTION_ACTIVE,
 | 
						|
             L"UEFI Capsule On Disk",
 | 
						|
             DevicePath,
 | 
						|
             (UINT8 *)&mCapsuleOnDiskBootOptionGuid,
 | 
						|
             sizeof (EFI_GUID)
 | 
						|
             );
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    Status = EfiBootManagerAddLoadOptionVariable (&NewOption, (UINTN)-1);
 | 
						|
    {
 | 
						|
      if (!EFI_ERROR (Status)) {
 | 
						|
        *UpdateBootNext = TRUE;
 | 
						|
        *BootNext       = (UINT16)NewOption.OptionNumber;
 | 
						|
        Print (L"  Boot%04x: %s\n", *BootNext, ConvertDevicePathToText (DevicePath, TRUE, TRUE));
 | 
						|
        return EFI_SUCCESS;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  Print (L"ERROR: Cannot create boot option! - %r\n", Status);
 | 
						|
 | 
						|
  return EFI_NOT_FOUND;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Write files to a given SimpleFileSystem.
 | 
						|
 | 
						|
  @param[in] Buffer          The buffer array
 | 
						|
  @param[in] BufferSize      The buffer size array
 | 
						|
  @param[in] FileName        The file name array
 | 
						|
  @param[in] BufferNum       The buffer number
 | 
						|
  @param[in] Fs              The SimpleFileSystem handle to be written
 | 
						|
 | 
						|
  @retval EFI_SUCCESS    Write file successfully
 | 
						|
  @retval EFI_NOT_FOUND  SFS protocol not found
 | 
						|
  @retval others         Write file failed
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
WriteUpdateFile (
 | 
						|
  IN  VOID                             **Buffer,
 | 
						|
  IN  UINTN                            *BufferSize,
 | 
						|
  IN  CHAR16                           **FileName,
 | 
						|
  IN  UINTN                            BufferNum,
 | 
						|
  IN  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  *Fs
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS         Status;
 | 
						|
  EFI_FILE           *Root;
 | 
						|
  EFI_FILE           *FileHandle;
 | 
						|
  EFI_FILE_PROTOCOL  *DirHandle;
 | 
						|
  UINT64             FileInfo;
 | 
						|
  VOID               *Filebuffer;
 | 
						|
  UINTN              FileSize;
 | 
						|
  UINTN              Index;
 | 
						|
 | 
						|
  DirHandle  = NULL;
 | 
						|
  FileHandle = NULL;
 | 
						|
  Index      = 0;
 | 
						|
 | 
						|
  //
 | 
						|
  // Open Root from SFS
 | 
						|
  //
 | 
						|
  Status = Fs->OpenVolume (Fs, &Root);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    Print (L"Cannot open volume. Status = %r\n", Status);
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Ensure that efi and updatecapsule directories exist
 | 
						|
  //
 | 
						|
  Status = Root->Open (Root, &DirHandle, L"\\EFI", EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE, 0);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    Status = Root->Open (Root, &DirHandle, L"\\EFI", EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, EFI_FILE_DIRECTORY);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      Print (L"Unable to create %s directory\n", L"\\EFI");
 | 
						|
      return EFI_NOT_FOUND;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  Status = Root->Open (Root, &DirHandle, EFI_CAPSULE_FILE_DIRECTORY, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE, 0);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    Status = Root->Open (Root, &DirHandle, EFI_CAPSULE_FILE_DIRECTORY, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, EFI_FILE_DIRECTORY);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      Print (L"Unable to create %s directory\n", EFI_CAPSULE_FILE_DIRECTORY);
 | 
						|
      return EFI_NOT_FOUND;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  for (Index = 0; Index < BufferNum; Index++) {
 | 
						|
    FileHandle = NULL;
 | 
						|
 | 
						|
    //
 | 
						|
    // Open UpdateCapsule file
 | 
						|
    //
 | 
						|
    Status = DirHandle->Open (DirHandle, &FileHandle, FileName[Index], EFI_FILE_MODE_CREATE | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ, 0);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      Print (L"Unable to create %s file\n", FileName[Index]);
 | 
						|
      return EFI_NOT_FOUND;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Empty the file contents
 | 
						|
    //
 | 
						|
    Status = FileHandleGetSize (FileHandle, &FileInfo);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      FileHandleClose (FileHandle);
 | 
						|
      Print (L"Error Reading %s\n", FileName[Index]);
 | 
						|
      return EFI_DEVICE_ERROR;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // If the file size is already 0, then it has been empty.
 | 
						|
    //
 | 
						|
    if (FileInfo != 0) {
 | 
						|
      //
 | 
						|
      // Set the file size to 0.
 | 
						|
      //
 | 
						|
      FileInfo = 0;
 | 
						|
      Status   = FileHandleSetSize (FileHandle, FileInfo);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        Print (L"Error Deleting %s\n", FileName[Index]);
 | 
						|
        FileHandleClose (FileHandle);
 | 
						|
        return Status;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Write Filebuffer to file
 | 
						|
    //
 | 
						|
    Filebuffer = Buffer[Index];
 | 
						|
    FileSize   = BufferSize[Index];
 | 
						|
    Status     = FileHandleWrite (FileHandle, &FileSize, Filebuffer);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      Print (L"Unable to write Capsule Update to %s, Status = %r\n", FileName[Index], Status);
 | 
						|
      return EFI_NOT_FOUND;
 | 
						|
    }
 | 
						|
 | 
						|
    Print (L"Succeed to write %s\n", FileName[Index]);
 | 
						|
    FileHandleClose (FileHandle);
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Set capsule status variable.
 | 
						|
 | 
						|
  @param[in] SetCap     Set or clear the capsule flag.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS   Succeed to set SetCap variable.
 | 
						|
  @retval others        Fail to set the variable.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
SetCapsuleStatusVariable (
 | 
						|
  BOOLEAN  SetCap
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  UINT64      OsIndication;
 | 
						|
  UINTN       DataSize;
 | 
						|
 | 
						|
  OsIndication = 0;
 | 
						|
  DataSize     = sizeof (UINT64);
 | 
						|
  Status       = gRT->GetVariable (
 | 
						|
                        L"OsIndications",
 | 
						|
                        &gEfiGlobalVariableGuid,
 | 
						|
                        NULL,
 | 
						|
                        &DataSize,
 | 
						|
                        &OsIndication
 | 
						|
                        );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    OsIndication = 0;
 | 
						|
  }
 | 
						|
 | 
						|
  if (SetCap) {
 | 
						|
    OsIndication |= ((UINT64)EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED);
 | 
						|
  } else {
 | 
						|
    OsIndication &= ~((UINT64)EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED);
 | 
						|
  }
 | 
						|
 | 
						|
  Status = gRT->SetVariable (
 | 
						|
                  L"OsIndications",
 | 
						|
                  &gEfiGlobalVariableGuid,
 | 
						|
                  EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
 | 
						|
                  sizeof (UINT64),
 | 
						|
                  &OsIndication
 | 
						|
                  );
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Check if Capsule On Disk is supported.
 | 
						|
 | 
						|
  @retval TRUE              Capsule On Disk is supported.
 | 
						|
  @retval FALSE             Capsule On Disk is not supported.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
IsCapsuleOnDiskSupported (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  UINT64      OsIndicationsSupported;
 | 
						|
  UINTN       DataSize;
 | 
						|
 | 
						|
  DataSize = sizeof (UINT64);
 | 
						|
  Status   = gRT->GetVariable (
 | 
						|
                    L"OsIndicationsSupported",
 | 
						|
                    &gEfiGlobalVariableGuid,
 | 
						|
                    NULL,
 | 
						|
                    &DataSize,
 | 
						|
                    &OsIndicationsSupported
 | 
						|
                    );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((OsIndicationsSupported & EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED) != 0) {
 | 
						|
    return TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Process Capsule On Disk.
 | 
						|
 | 
						|
  @param[in]  CapsuleBuffer       An array of pointer to capsule images
 | 
						|
  @param[in]  CapsuleBufferSize   An array of UINTN to capsule images size
 | 
						|
  @param[in]  FilePath            An array of capsule images file path
 | 
						|
  @param[in]  Map                 File system mapping string
 | 
						|
  @param[in]  CapsuleNum          The count of capsule images
 | 
						|
 | 
						|
  @retval EFI_SUCCESS       Capsule on disk success.
 | 
						|
  @retval others            Capsule on disk fail.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
ProcessCapsuleOnDisk (
 | 
						|
  IN VOID    **CapsuleBuffer,
 | 
						|
  IN UINTN   *CapsuleBufferSize,
 | 
						|
  IN CHAR16  **FilePath,
 | 
						|
  IN CHAR16  *Map,
 | 
						|
  IN UINTN   CapsuleNum
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                       Status;
 | 
						|
  UINT16                           BootNext;
 | 
						|
  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  *Fs;
 | 
						|
  BOOLEAN                          UpdateBootNext;
 | 
						|
  CHAR16                           *FileName[MAX_CAPSULE_NUM];
 | 
						|
  UINTN                            Index;
 | 
						|
 | 
						|
  //
 | 
						|
  // Check if Capsule On Disk is supported
 | 
						|
  //
 | 
						|
  if (!IsCapsuleOnDiskSupported ()) {
 | 
						|
    Print (L"CapsuleApp: Capsule On Disk is not supported.\n");
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Get a valid file system from boot path
 | 
						|
  //
 | 
						|
  Fs = NULL;
 | 
						|
 | 
						|
  Status = GetUpdateFileSystem (Map, &BootNext, &Fs, &UpdateBootNext);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    Print (L"CapsuleApp: cannot find a valid file system on boot devices. Status = %r\n", Status);
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Get file name from file path
 | 
						|
  //
 | 
						|
  for (Index = 0; Index < CapsuleNum; Index++) {
 | 
						|
    FileName[Index] = GetFileNameFromPath (FilePath[Index]);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Copy capsule image to '\efi\UpdateCapsule\'
 | 
						|
  //
 | 
						|
  Status = WriteUpdateFile (CapsuleBuffer, CapsuleBufferSize, FileName, CapsuleNum, Fs);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    Print (L"CapsuleApp: capsule image could not be copied for update.\n");
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Set variable then reset
 | 
						|
  //
 | 
						|
  Status = SetCapsuleStatusVariable (TRUE);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    Print (L"CapsuleApp: unable to set OSIndication variable.\n");
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  if (UpdateBootNext) {
 | 
						|
    Status = gRT->SetVariable (
 | 
						|
                    L"BootNext",
 | 
						|
                    &gEfiGlobalVariableGuid,
 | 
						|
                    EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
 | 
						|
                    sizeof (UINT16),
 | 
						|
                    &BootNext
 | 
						|
                    );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      Print (L"CapsuleApp: unable to set BootNext variable.\n");
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 |