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;
 | |
| }
 |