diff options
| author | kx <kx@radix.pro> | 2024-06-04 06:43:08 +0300 |
|---|---|---|
| committer | kx <kx@radix.pro> | 2024-06-04 06:43:08 +0300 |
| commit | 7e2ccccace24636f29ddc210b94606abd4c7e42b (patch) | |
| tree | 545d43ea12671048956cafeb12303e84d601e571 /MdeModulePkg/Application/CapsuleApp/CapsuleOnDisk.c | |
| parent | 27b044605cd5f6b33a3d231576003850b3fe305b (diff) | |
| download | edk2-trunk.tar.xz | |
Renormalized end-of-lines from master@27b044605cd5f6b33a3d231576003850b3fe305btrunk
Diffstat (limited to 'MdeModulePkg/Application/CapsuleApp/CapsuleOnDisk.c')
| -rw-r--r-- | MdeModulePkg/Application/CapsuleApp/CapsuleOnDisk.c | 1714 |
1 files changed, 857 insertions, 857 deletions
diff --git a/MdeModulePkg/Application/CapsuleApp/CapsuleOnDisk.c b/MdeModulePkg/Application/CapsuleApp/CapsuleOnDisk.c index 5ce5a50f7b..41e4c21a35 100644 --- a/MdeModulePkg/Application/CapsuleApp/CapsuleOnDisk.c +++ b/MdeModulePkg/Application/CapsuleApp/CapsuleOnDisk.c @@ -1,857 +1,857 @@ -/** @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;
-}
+/** @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; +} |
