This CapsuleApp can help perform capsule update in UEFI shell environment.
It can also dump capsule information, capsule status variable,
ESRT and FMP.
Cc: Feng Tian <feng.tian@intel.com>
Cc: Star Zeng <star.zeng@intel.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
Cc: Chao Zhang <chao.b.zhang@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jiewen Yao <jiewen.yao@intel.com>
Reviewed-by: Liming Gao <liming.gao@intel.com>
Reviewed-by: Michael Kinney <michael.d.kinney@intel.com>
Tested-by: Michael Kinney <michael.d.kinney@intel.com>
--- /dev/null
+/** @file\r
+ A shell application that triggers capsule update process.\r
+\r
+ Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <Uefi.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/PrintLib.h>\r
+#include <Protocol/LoadedImage.h>\r
+#include <Protocol/SimpleFileSystem.h>\r
+#include <Protocol/ShellParameters.h>\r
+#include <Guid/FileInfo.h>\r
+#include <Guid/Gpt.h>\r
+\r
+#define MAX_ARG_NUM 11\r
+\r
+UINTN Argc;\r
+CHAR16 **Argv;\r
+\r
+/**\r
+\r
+ This function parse application ARG.\r
+\r
+ @return Status\r
+**/\r
+EFI_STATUS\r
+GetArg (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters;\r
+\r
+ Status = gBS->HandleProtocol (\r
+ gImageHandle,\r
+ &gEfiShellParametersProtocolGuid,\r
+ (VOID**)&ShellParameters\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Argc = ShellParameters->Argc;\r
+ Argv = ShellParameters->Argv;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Return File System Volume containing this shell application.\r
+\r
+ @return File System Volume containing this shell application.\r
+**/\r
+EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *\r
+GetMyVol (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;\r
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Vol;\r
+\r
+ Status = gBS->HandleProtocol (\r
+ gImageHandle,\r
+ &gEfiLoadedImageProtocolGuid,\r
+ (VOID **)&LoadedImage\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ Status = gBS->HandleProtocol (\r
+ LoadedImage->DeviceHandle,\r
+ &gEfiSimpleFileSystemProtocolGuid,\r
+ (VOID **)&Vol\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ return Vol;\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+/**\r
+ Read a file from this volume.\r
+\r
+ @param[in] Vol File System Volume\r
+ @param[in] FileName The file to be read.\r
+ @param[out] BufferSize The file buffer size\r
+ @param[out] Buffer The file buffer\r
+\r
+ @retval EFI_SUCCESS Read file successfully\r
+ @retval EFI_NOT_FOUND File not found\r
+**/\r
+EFI_STATUS\r
+ReadFileFromVol (\r
+ IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Vol,\r
+ IN CHAR16 *FileName,\r
+ OUT UINTN *BufferSize,\r
+ OUT VOID **Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_FILE_HANDLE RootDir;\r
+ EFI_FILE_HANDLE Handle;\r
+ UINTN FileInfoSize;\r
+ EFI_FILE_INFO *FileInfo;\r
+ UINTN TempBufferSize;\r
+ VOID *TempBuffer;\r
+\r
+ //\r
+ // Open the root directory\r
+ //\r
+ Status = Vol->OpenVolume (Vol, &RootDir);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Open the file\r
+ //\r
+ Status = RootDir->Open (\r
+ RootDir,\r
+ &Handle,\r
+ FileName,\r
+ EFI_FILE_MODE_READ,\r
+ 0\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ RootDir->Close (RootDir);\r
+ return Status;\r
+ }\r
+\r
+ RootDir->Close (RootDir);\r
+\r
+ //\r
+ // Get the file information\r
+ //\r
+ FileInfoSize = sizeof(EFI_FILE_INFO) + 1024;\r
+\r
+ FileInfo = AllocateZeroPool (FileInfoSize);\r
+ if (FileInfo == NULL) {\r
+ Handle->Close (Handle);\r
+ return Status;\r
+ }\r
+\r
+ Status = Handle->GetInfo (\r
+ Handle,\r
+ &gEfiFileInfoGuid,\r
+ &FileInfoSize,\r
+ FileInfo\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ Handle->Close (Handle);\r
+ gBS->FreePool (FileInfo);\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Allocate buffer for the file data. The last CHAR16 is for L'\0'\r
+ //\r
+ TempBufferSize = (UINTN) FileInfo->FileSize + sizeof(CHAR16);\r
+ TempBuffer = AllocateZeroPool (TempBufferSize);\r
+ if (TempBuffer == NULL) {\r
+ Handle->Close (Handle);\r
+ gBS->FreePool (FileInfo);\r
+ return Status;\r
+ }\r
+\r
+ gBS->FreePool (FileInfo);\r
+\r
+ //\r
+ // Read the file data to the buffer\r
+ //\r
+ Status = Handle->Read (\r
+ Handle,\r
+ &TempBufferSize,\r
+ TempBuffer\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ Handle->Close (Handle);\r
+ gBS->FreePool (TempBuffer);\r
+ return Status;\r
+ }\r
+\r
+ Handle->Close (Handle);\r
+\r
+ *BufferSize = TempBufferSize;\r
+ *Buffer = TempBuffer;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Read a file.\r
+ If ScanFs is FLASE, it will use this Vol as default Fs.\r
+ If ScanFs is TRUE, it will scan all FS and check the file.\r
+ If there is only one file match the name, it will be read.\r
+ If there is more than one file match the name, it will return Error.\r
+\r
+ @param[in] ThisVol File System Volume\r
+ @param[in] FileName The file to be read.\r
+ @param[out] BufferSize The file buffer size\r
+ @param[out] Buffer The file buffer\r
+ @param[in] ScanFs Need Scan all FS\r
+\r
+ @retval EFI_SUCCESS Read file successfully\r
+ @retval EFI_NOT_FOUND File not found\r
+ @retval EFI_NO_MAPPING There is duplicated files found\r
+**/\r
+EFI_STATUS\r
+ReadFileToBufferEx (\r
+ IN OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL **ThisVol,\r
+ IN CHAR16 *FileName,\r
+ OUT UINTN *BufferSize,\r
+ OUT VOID **Buffer,\r
+ IN BOOLEAN ScanFs\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Vol;\r
+ UINTN TempBufferSize;\r
+ VOID *TempBuffer;\r
+ UINTN NoHandles;\r
+ EFI_HANDLE *HandleBuffer;\r
+ UINTN Index;\r
+\r
+ //\r
+ // Check parameters\r
+ //\r
+ if ((FileName == NULL) || (Buffer == NULL) || (ThisVol == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // not scan fs\r
+ //\r
+ if (!ScanFs) {\r
+ if (*ThisVol == NULL) {\r
+ *ThisVol = GetMyVol ();\r
+ if (*ThisVol == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+ //\r
+ // Read file directly from Vol\r
+ //\r
+ return ReadFileFromVol (*ThisVol, FileName, BufferSize, Buffer);\r
+ }\r
+\r
+ //\r
+ // need scan fs\r
+ //\r
+\r
+ //\r
+ // Get all Vol handle\r
+ //\r
+ Status = gBS->LocateHandleBuffer (\r
+ ByProtocol,\r
+ &gEfiSimpleFileSystemProtocolGuid,\r
+ NULL,\r
+ &NoHandles,\r
+ &HandleBuffer\r
+ );\r
+ if (EFI_ERROR (Status) && (NoHandles == 0)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ //\r
+ // Walk through each Vol\r
+ //\r
+ *ThisVol = NULL;\r
+ *BufferSize = 0;\r
+ *Buffer = NULL;\r
+ for (Index = 0; Index < NoHandles; Index++) {\r
+ Status = gBS->HandleProtocol (\r
+ HandleBuffer[Index],\r
+ &gEfiSimpleFileSystemProtocolGuid,\r
+ (VOID **)&Vol\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ continue;\r
+ }\r
+\r
+ Status = ReadFileFromVol (Vol, FileName, &TempBufferSize, &TempBuffer);\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Read file OK, check duplication\r
+ //\r
+ if (*ThisVol != NULL) {\r
+ //\r
+ // Find the duplicated file\r
+ //\r
+ gBS->FreePool (TempBuffer);\r
+ gBS->FreePool (*Buffer);\r
+ Print (L"Duplicated FileName found!\n");\r
+ return EFI_NO_MAPPING;\r
+ } else {\r
+ //\r
+ // Record value\r
+ //\r
+ *ThisVol = Vol;\r
+ *BufferSize = TempBufferSize;\r
+ *Buffer = TempBuffer;\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // Scan Fs done\r
+ //\r
+ if (*ThisVol == NULL) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ //\r
+ // Done\r
+ //\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Read a file.\r
+\r
+ @param[in] FileName The file to be read.\r
+ @param[out] BufferSize The file buffer size\r
+ @param[out] Buffer The file buffer\r
+\r
+ @retval EFI_SUCCESS Read file successfully\r
+ @retval EFI_NOT_FOUND File not found\r
+**/\r
+EFI_STATUS\r
+ReadFileToBuffer (\r
+ IN CHAR16 *FileName,\r
+ OUT UINTN *BufferSize,\r
+ OUT VOID **Buffer\r
+ )\r
+{\r
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Vol;\r
+ Vol = NULL;\r
+ return ReadFileToBufferEx(&Vol, FileName, BufferSize, Buffer, FALSE);\r
+}\r
+\r
+/**\r
+ Write a file.\r
+\r
+ @param[in] FileName The file to be written.\r
+ @param[in] BufferSize The file buffer size\r
+ @param[in] Buffer The file buffer\r
+\r
+ @retval EFI_SUCCESS Write file successfully\r
+**/\r
+EFI_STATUS\r
+WriteFileFromBuffer (\r
+ IN CHAR16 *FileName,\r
+ IN UINTN BufferSize,\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_FILE_HANDLE RootDir;\r
+ EFI_FILE_HANDLE Handle;\r
+ UINTN TempBufferSize;\r
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Vol;\r
+\r
+ Vol = GetMyVol();\r
+ if (Vol == NULL) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ //\r
+ // Open the root directory\r
+ //\r
+ Status = Vol->OpenVolume (Vol, &RootDir);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Open the file\r
+ //\r
+ Status = RootDir->Open (\r
+ RootDir,\r
+ &Handle,\r
+ FileName,\r
+ EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE| EFI_FILE_MODE_CREATE,\r
+ 0\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ RootDir->Close (RootDir);\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Delete file\r
+ //\r
+ Status = Handle->Delete(Handle);\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Open the file again\r
+ //\r
+ Status = RootDir->Open (\r
+ RootDir,\r
+ &Handle,\r
+ FileName,\r
+ EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE| EFI_FILE_MODE_CREATE,\r
+ 0\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ RootDir->Close (RootDir);\r
+ return Status;\r
+ }\r
+\r
+ RootDir->Close (RootDir);\r
+\r
+ //\r
+ // Write the file data from the buffer\r
+ //\r
+ TempBufferSize = BufferSize;\r
+ Status = Handle->Write (\r
+ Handle,\r
+ &TempBufferSize,\r
+ Buffer\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ Handle->Close (Handle);\r
+ return Status;\r
+ }\r
+\r
+ Handle->Close (Handle);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
--- /dev/null
+/** @file\r
+ A shell application that triggers capsule update process.\r
+\r
+ Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <Uefi.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/PrintLib.h>\r
+#include <Protocol/LoadedImage.h>\r
+#include <Protocol/SimpleFileSystem.h>\r
+#include <Protocol/GraphicsOutput.h>\r
+#include <Guid/FileInfo.h>\r
+#include <Guid/Gpt.h>\r
+#include <Guid/GlobalVariable.h>\r
+#include <Guid/CapsuleReport.h>\r
+#include <Guid/SystemResourceTable.h>\r
+#include <Guid/FmpCapsule.h>\r
+#include <IndustryStandard/WindowsUxCapsule.h>\r
+\r
+#define CAPSULE_HEADER_SIZE 0x20\r
+\r
+#define NESTED_CAPSULE_HEADER_SIZE SIZE_4KB\r
+#define SYSTEM_FIRMWARE_FLAG 0x50000\r
+#define DEVICE_FIRMWARE_FLAG 0x78010\r
+\r
+#define EFI_CAPSULE_FROM_FILE_DIR L"\\EFI\\UpdateCapsule\\"\r
+#define EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED 0x0000000000000004\r
+\r
+#define MAJOR_VERSION 1\r
+#define MINOR_VERSION 0\r
+\r
+#define MAX_CAPSULE_NUM 10\r
+\r
+extern UINTN Argc;\r
+extern CHAR16 **Argv;\r
+\r
+//\r
+// Define how many block descriptors we want to test with.\r
+//\r
+UINTN NumberOfDescriptors = 1;\r
+UINTN CapsuleFirstIndex;\r
+UINTN CapsuleLastIndex;\r
+\r
+/**\r
+ Dump capsule information\r
+\r
+ @param[in] CapsuleName The name of the capsule image.\r
+\r
+ @retval EFI_SUCCESS The capsule information is dumped.\r
+ @retval EFI_UNSUPPORTED Input parameter is not valid.\r
+**/\r
+EFI_STATUS\r
+DumpCapsule (\r
+ IN CHAR16 *CapsuleName\r
+ );\r
+\r
+/**\r
+ Dump capsule status variable.\r
+\r
+ @retval EFI_SUCCESS The capsule status variable is dumped.\r
+ @retval EFI_UNSUPPORTED Input parameter is not valid.\r
+**/\r
+EFI_STATUS\r
+DmpCapsuleStatusVariable (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Dump FMP protocol info.\r
+**/\r
+VOID\r
+DumpFmpData (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Dump ESRT info.\r
+**/\r
+VOID\r
+DumpEsrtData (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Read a file.\r
+\r
+ @param[in] FileName The file to be read.\r
+ @param[out] BufferSize The file buffer size\r
+ @param[out] Buffer The file buffer\r
+\r
+ @retval EFI_SUCCESS Read file successfully\r
+ @retval EFI_NOT_FOUND File not found\r
+**/\r
+EFI_STATUS\r
+ReadFileToBuffer (\r
+ IN CHAR16 *FileName,\r
+ OUT UINTN *BufferSize,\r
+ OUT VOID **Buffer\r
+ );\r
+\r
+/**\r
+ Write a file.\r
+\r
+ @param[in] FileName The file to be written.\r
+ @param[in] BufferSize The file buffer size\r
+ @param[in] Buffer The file buffer\r
+\r
+ @retval EFI_SUCCESS Write file successfully\r
+**/\r
+EFI_STATUS\r
+WriteFileFromBuffer (\r
+ IN CHAR16 *FileName,\r
+ IN UINTN BufferSize,\r
+ IN VOID *Buffer\r
+ );\r
+\r
+/**\r
+\r
+ This function parse application ARG.\r
+\r
+ @return Status\r
+**/\r
+EFI_STATUS\r
+GetArg (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Create UX capsule.\r
+\r
+ @retval EFI_SUCCESS The capsule header is appended.\r
+ @retval EFI_UNSUPPORTED Input parameter is not valid.\r
+ @retval EFI_OUT_OF_RESOURCES No enough resource to create UX capsule.\r
+**/\r
+EFI_STATUS\r
+CreateBmpFmp (\r
+ VOID\r
+ )\r
+{\r
+ CHAR16 *OutputCapsuleName;\r
+ VOID *BmpBuffer;\r
+ UINTN FileSize;\r
+ CHAR16 *BmpName;\r
+ UINT8 *FullCapsuleBuffer;\r
+ UINTN FullCapsuleBufferSize;\r
+ EFI_DISPLAY_CAPSULE *DisplayCapsule;\r
+ EFI_STATUS Status;\r
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop;\r
+\r
+ Status = gBS->LocateProtocol(&gEfiGraphicsOutputProtocolGuid, NULL, (VOID **)&Gop);\r
+ if (EFI_ERROR(Status)) {\r
+ Print(L"CapsuleApp: NO GOP is found.\n");\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ Print(L"Current GOP: Mode - %d, ", Gop->Mode->Mode);\r
+ Print(L"HorizontalResolution - %d, ", Gop->Mode->Info->HorizontalResolution);\r
+ Print(L"VerticalResolution - %d\n", Gop->Mode->Info->VerticalResolution);\r
+ // HorizontalResolution >= BMP_IMAGE_HEADER.PixelWidth\r
+ // VerticalResolution >= BMP_IMAGE_HEADER.PixelHeight\r
+\r
+ if (Argc != 5) {\r
+ Print(L"CapsuleApp: Invalid Parameter.\n");\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ if (StrCmp(Argv[3], L"-O") != 0) {\r
+ Print(L"CapsuleApp: NO output capsule name.\n");\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ OutputCapsuleName = Argv[4];\r
+\r
+ BmpBuffer = NULL;\r
+ FileSize = 0;\r
+ FullCapsuleBuffer = NULL;\r
+\r
+ BmpName = Argv[2];\r
+ Status = ReadFileToBuffer(BmpName, &FileSize, &BmpBuffer);\r
+ if (EFI_ERROR(Status)) {\r
+ Print(L"CapsuleApp: BMP image (%s) is not found.\n", BmpName);\r
+ goto Done;\r
+ }\r
+\r
+ FullCapsuleBufferSize = sizeof(EFI_DISPLAY_CAPSULE) + FileSize;\r
+ FullCapsuleBuffer = AllocatePool(FullCapsuleBufferSize);\r
+ if (FullCapsuleBuffer == NULL) {\r
+ Print(L"CapsuleApp: Capsule Buffer size (0x%x) too big.\n", FullCapsuleBufferSize);\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Done;\r
+ }\r
+\r
+ DisplayCapsule = (EFI_DISPLAY_CAPSULE *)FullCapsuleBuffer;\r
+ CopyGuid(&DisplayCapsule->CapsuleHeader.CapsuleGuid, &gWindowsUxCapsuleGuid);\r
+ DisplayCapsule->CapsuleHeader.HeaderSize = sizeof(DisplayCapsule->CapsuleHeader);\r
+ DisplayCapsule->CapsuleHeader.Flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET;\r
+ DisplayCapsule->CapsuleHeader.CapsuleImageSize = (UINT32)FullCapsuleBufferSize;\r
+\r
+ DisplayCapsule->ImagePayload.Version = 1;\r
+ DisplayCapsule->ImagePayload.Checksum = 0;\r
+ DisplayCapsule->ImagePayload.ImageType = 0; // BMP\r
+ DisplayCapsule->ImagePayload.Reserved = 0;\r
+ DisplayCapsule->ImagePayload.Mode = Gop->Mode->Mode;\r
+ DisplayCapsule->ImagePayload.OffsetX = 0;\r
+ DisplayCapsule->ImagePayload.OffsetY = 0;\r
+\r
+ CopyMem((DisplayCapsule + 1), BmpBuffer, FileSize);\r
+\r
+ DisplayCapsule->ImagePayload.Checksum = CalculateCheckSum8(FullCapsuleBuffer, FullCapsuleBufferSize);\r
+\r
+ Status = WriteFileFromBuffer(OutputCapsuleName, FullCapsuleBufferSize, FullCapsuleBuffer);\r
+ Print(L"CapsuleApp: Write %s %r\n", OutputCapsuleName, Status);\r
+\r
+Done:\r
+ if (BmpBuffer != NULL) {\r
+ FreePool(BmpBuffer);\r
+ }\r
+\r
+ if (FullCapsuleBuffer != NULL) {\r
+ FreePool(FullCapsuleBuffer);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Get ImageTypeId in the FMP capsule header.\r
+\r
+ @param[in] CapsuleHeader The FMP capsule image header.\r
+\r
+ @return ImageTypeId\r
+**/\r
+EFI_GUID *\r
+GetCapsuleImageTypeId (\r
+ IN EFI_CAPSULE_HEADER *CapsuleHeader\r
+ )\r
+{\r
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;\r
+ UINT64 *ItemOffsetList;\r
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;\r
+\r
+ FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);\r
+ ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);\r
+ if (FmpCapsuleHeader->PayloadItemCount == 0) {\r
+ return NULL;\r
+ }\r
+ ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[FmpCapsuleHeader->EmbeddedDriverCount]);\r
+ return &ImageHeader->UpdateImageTypeId;\r
+}\r
+\r
+/**\r
+ Get ESRT FwType according to ImageTypeId\r
+\r
+ @param[in] ImageTypeId ImageTypeId of an FMP capsule.\r
+\r
+ @return ESRT FwType\r
+**/\r
+UINT32\r
+GetEsrtFwType (\r
+ IN EFI_GUID *ImageTypeId\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SYSTEM_RESOURCE_TABLE *Esrt;\r
+ EFI_SYSTEM_RESOURCE_ENTRY *EsrtEntry;\r
+ UINTN Index;\r
+\r
+ //\r
+ // Check ESRT\r
+ //\r
+ Status = EfiGetSystemConfigurationTable(&gEfiSystemResourceTableGuid, (VOID **)&Esrt);\r
+ if (!EFI_ERROR(Status)) {\r
+ ASSERT(Esrt != NULL);\r
+ EsrtEntry = (VOID *)(Esrt + 1);\r
+ for (Index = 0; Index < Esrt->FwResourceCount; Index++, EsrtEntry++) {\r
+ if (CompareGuid(&EsrtEntry->FwClass, ImageTypeId)) {\r
+ return EsrtEntry->FwType;\r
+ }\r
+ }\r
+ }\r
+\r
+ return ESRT_FW_TYPE_UNKNOWN;\r
+}\r
+\r
+/**\r
+ Append a capsule header on top of current image.\r
+ This function follows Windows UEFI Firmware Update Platform document.\r
+\r
+ @retval EFI_SUCCESS The capsule header is appended.\r
+ @retval EFI_UNSUPPORTED Input parameter is not valid.\r
+ @retval EFI_OUT_OF_RESOURCES No enough resource to append capsule header.\r
+**/\r
+EFI_STATUS\r
+CreateNestedFmp (\r
+ VOID\r
+ )\r
+{\r
+ CHAR16 *OutputCapsuleName;\r
+ VOID *CapsuleBuffer;\r
+ UINTN FileSize;\r
+ CHAR16 *CapsuleName;\r
+ UINT8 *FullCapsuleBuffer;\r
+ UINTN FullCapsuleBufferSize;\r
+ EFI_CAPSULE_HEADER *NestedCapsuleHeader;\r
+ EFI_GUID *ImageTypeId;\r
+ UINT32 FwType;\r
+ EFI_STATUS Status;\r
+\r
+ if (Argc != 5) {\r
+ Print(L"CapsuleApp: Invalid Parameter.\n");\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ if (StrCmp(Argv[3], L"-O") != 0) {\r
+ Print(L"CapsuleApp: NO output capsule name.\n");\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ OutputCapsuleName = Argv[4];\r
+\r
+ CapsuleBuffer = NULL;\r
+ FileSize = 0;\r
+ FullCapsuleBuffer = NULL;\r
+\r
+ CapsuleName = Argv[2];\r
+ Status = ReadFileToBuffer(CapsuleName, &FileSize, &CapsuleBuffer);\r
+ if (EFI_ERROR(Status)) {\r
+ Print(L"CapsuleApp: Capsule image (%s) is not found.\n", CapsuleName);\r
+ goto Done;\r
+ }\r
+\r
+ ImageTypeId = GetCapsuleImageTypeId(CapsuleBuffer);\r
+ if (ImageTypeId == NULL) {\r
+ Print(L"CapsuleApp: Capsule ImageTypeId is not found.\n");\r
+ goto Done;\r
+ }\r
+ FwType = GetEsrtFwType(ImageTypeId);\r
+ if ((FwType != ESRT_FW_TYPE_SYSTEMFIRMWARE) && (FwType != ESRT_FW_TYPE_DEVICEFIRMWARE)) {\r
+ Print(L"CapsuleApp: Capsule FwType is invalid.\n");\r
+ goto Done;\r
+ }\r
+\r
+ FullCapsuleBufferSize = NESTED_CAPSULE_HEADER_SIZE + FileSize;\r
+ FullCapsuleBuffer = AllocatePool(FullCapsuleBufferSize);\r
+ if (FullCapsuleBuffer == NULL) {\r
+ Print(L"CapsuleApp: Capsule Buffer size (0x%x) too big.\n", FullCapsuleBufferSize);\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Done;\r
+ }\r
+\r
+ NestedCapsuleHeader = (EFI_CAPSULE_HEADER *)FullCapsuleBuffer;\r
+ ZeroMem(NestedCapsuleHeader, NESTED_CAPSULE_HEADER_SIZE);\r
+ CopyGuid(&NestedCapsuleHeader->CapsuleGuid, ImageTypeId);\r
+ NestedCapsuleHeader->HeaderSize = NESTED_CAPSULE_HEADER_SIZE;\r
+ NestedCapsuleHeader->Flags = (FwType == ESRT_FW_TYPE_DEVICEFIRMWARE) ? SYSTEM_FIRMWARE_FLAG : DEVICE_FIRMWARE_FLAG;\r
+ NestedCapsuleHeader->CapsuleImageSize = (UINT32)FullCapsuleBufferSize;\r
+\r
+ CopyMem((UINT8 *)NestedCapsuleHeader + NestedCapsuleHeader->HeaderSize, CapsuleBuffer, FileSize);\r
+\r
+ Status = WriteFileFromBuffer(OutputCapsuleName, FullCapsuleBufferSize, FullCapsuleBuffer);\r
+ Print(L"CapsuleApp: Write %s %r\n", OutputCapsuleName, Status);\r
+\r
+Done:\r
+ if (CapsuleBuffer != NULL) {\r
+ FreePool(CapsuleBuffer);\r
+ }\r
+\r
+ if (FullCapsuleBuffer != NULL) {\r
+ FreePool(FullCapsuleBuffer);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Clear capsule status variable.\r
+\r
+ @retval EFI_SUCCESS The capsule status variable is cleared.\r
+**/\r
+EFI_STATUS\r
+ClearCapsuleStatusVariable (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 Index;\r
+ CHAR16 CapsuleVarName[20];\r
+ CHAR16 *TempVarName;\r
+\r
+ StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CapsuleVarName[0]), L"Capsule");\r
+ TempVarName = CapsuleVarName + StrLen (CapsuleVarName);\r
+ Index = 0;\r
+\r
+ while (TRUE) {\r
+ UnicodeSPrint (TempVarName, 5 * sizeof(CHAR16), L"%04x", Index);\r
+\r
+ Status = gRT->SetVariable (\r
+ CapsuleVarName,\r
+ &gEfiCapsuleReportGuid,\r
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+ 0,\r
+ (VOID *)NULL\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ //\r
+ // There is no capsule variables, quit\r
+ //\r
+ break;\r
+ }\r
+\r
+ Index++;\r
+ if (Index > 0xFFFF) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Build Gather list for a list of capsule images.\r
+\r
+ @param[in] CapsuleBuffer An array of pointer to capsule images\r
+ @param[in] FileSize An array of UINTN to capsule images size\r
+ @param[in] CapsuleNum The count of capsule images\r
+ @param[out] BlockDescriptors The block descriptors for the capsule images\r
+\r
+ @retval EFI_SUCCESS The block descriptors for the capsule images are constructed.\r
+**/\r
+EFI_STATUS\r
+BuildGatherList (\r
+ IN VOID **CapsuleBuffer,\r
+ IN UINTN *FileSize,\r
+ IN UINTN CapsuleNum,\r
+ OUT EFI_CAPSULE_BLOCK_DESCRIPTOR **BlockDescriptors\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors1;\r
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors2;\r
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptorPre;\r
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptorsHeader;\r
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr;\r
+ UINT8 *TempDataPtr;\r
+ UINTN SizeLeft;\r
+ UINTN Size;\r
+ INT32 Count;\r
+ INT32 Number;\r
+ UINTN Index;\r
+\r
+ TempBlockPtr = NULL;\r
+ BlockDescriptors1 = NULL;\r
+ BlockDescriptors2 = NULL;\r
+ BlockDescriptorPre = NULL;\r
+ BlockDescriptorsHeader = NULL;\r
+\r
+ for (Index = 0; Index < CapsuleNum; Index++) {\r
+ //\r
+ // Allocate memory for the descriptors.\r
+ //\r
+ if (NumberOfDescriptors == 1) {\r
+ Count = 2;\r
+ } else {\r
+ Count = (INT32)(NumberOfDescriptors + 2) / 2;\r
+ }\r
+\r
+ Size = Count * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);\r
+ BlockDescriptors1 = AllocateRuntimeZeroPool (Size);\r
+ if (BlockDescriptors1 == NULL) {\r
+ Print (L"CapsuleApp: failed to allocate memory for descriptors\n");\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ERREXIT;\r
+ } else {\r
+ Print (L"CapsuleApp: creating capsule descriptors at 0x%X\n", (UINTN) BlockDescriptors1);\r
+ Print (L"CapsuleApp: capsule data starts at 0x%X with size 0x%X\n", (UINTN) CapsuleBuffer, FileSize);\r
+ }\r
+\r
+ //\r
+ // Record descirptor header\r
+ //\r
+ if (Index == 0) {\r
+ BlockDescriptorsHeader = BlockDescriptors1;\r
+ }\r
+\r
+ if (BlockDescriptorPre != NULL) {\r
+ BlockDescriptorPre->Union.ContinuationPointer = (UINTN) BlockDescriptors1;\r
+ BlockDescriptorPre->Length = 0;\r
+ }\r
+\r
+ //\r
+ // Fill them in\r
+ //\r
+ TempBlockPtr = BlockDescriptors1;\r
+ TempDataPtr = CapsuleBuffer[Index];\r
+ SizeLeft = FileSize[Index];\r
+ for (Number = 0; (Number < Count - 1) && (SizeLeft != 0); Number++) {\r
+ //\r
+ // Divide remaining data in half\r
+ //\r
+ if (NumberOfDescriptors != 1) {\r
+ if (SizeLeft == 1) {\r
+ Size = 1;\r
+ } else {\r
+ Size = SizeLeft / 2;\r
+ }\r
+ } else {\r
+ Size = SizeLeft;\r
+ }\r
+ TempBlockPtr->Union.DataBlock = (UINTN)TempDataPtr;\r
+ TempBlockPtr->Length = Size;\r
+ Print (L"CapsuleApp: capsule block/size 0x%X/0x%X\n", (UINTN) TempDataPtr, Size);\r
+ SizeLeft -= Size;\r
+ TempDataPtr += Size;\r
+ TempBlockPtr++;\r
+ }\r
+\r
+ //\r
+ // Allocate the second list, point the first block's last entry to point\r
+ // to this one, and fill this one in. Worst case is that the previous\r
+ // list only had one element that pointed here, so we need at least two\r
+ // elements -- one to point to all the data, another to terminate the list.\r
+ //\r
+ if ((NumberOfDescriptors != 1) && (SizeLeft != 0)) {\r
+ Count = (INT32)(NumberOfDescriptors + 2) - Count;\r
+ if (Count == 1) {\r
+ Count++;\r
+ }\r
+\r
+ Size = Count * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);\r
+ BlockDescriptors2 = AllocateRuntimeZeroPool (Size);\r
+ if (BlockDescriptors2 == NULL) {\r
+ Print (L"CapsuleApp: failed to allocate memory for descriptors\n");\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ERREXIT;\r
+ }\r
+\r
+ //\r
+ // Point the first list's last element to point to this second list.\r
+ //\r
+ TempBlockPtr->Union.ContinuationPointer = (UINTN) BlockDescriptors2;\r
+\r
+ TempBlockPtr->Length = 0;\r
+ TempBlockPtr = BlockDescriptors2;\r
+ for (Number = 0; Number < Count - 1; Number++) {\r
+ //\r
+ // If second-to-last one, then dump rest to this element\r
+ //\r
+ if (Number == (Count - 2)) {\r
+ Size = SizeLeft;\r
+ } else {\r
+ //\r
+ // Divide remaining data in half\r
+ //\r
+ if (SizeLeft == 1) {\r
+ Size = 1;\r
+ } else {\r
+ Size = SizeLeft / 2;\r
+ }\r
+ }\r
+\r
+ TempBlockPtr->Union.DataBlock = (UINTN)TempDataPtr;\r
+ TempBlockPtr->Length = Size;\r
+ Print (L"CapsuleApp: capsule block/size 0x%X/0x%X\n", (UINTN) TempDataPtr, Size);\r
+ SizeLeft -= Size;\r
+ TempDataPtr += Size;\r
+ TempBlockPtr++;\r
+ if (SizeLeft == 0) {\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ BlockDescriptorPre = TempBlockPtr;\r
+ BlockDescriptors1 = NULL;\r
+ }\r
+\r
+ //\r
+ // Null-terminate.\r
+ //\r
+ if (TempBlockPtr != NULL) {\r
+ TempBlockPtr->Union.ContinuationPointer = (UINTN)NULL;\r
+ TempBlockPtr->Length = 0;\r
+ *BlockDescriptors = BlockDescriptorsHeader;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+\r
+ERREXIT:\r
+ if (BlockDescriptors1 != NULL) {\r
+ FreePool(BlockDescriptors1);\r
+ }\r
+\r
+ if (BlockDescriptors2 != NULL) {\r
+ FreePool(BlockDescriptors2);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Clear the Gather list for a list of capsule images.\r
+\r
+ @param[in] BlockDescriptors The block descriptors for the capsule images\r
+ @param[in] CapsuleNum The count of capsule images\r
+**/\r
+VOID\r
+CleanGatherList (\r
+ IN EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors,\r
+ IN UINTN CapsuleNum\r
+ )\r
+{\r
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr;\r
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr1;\r
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr2;\r
+ UINTN Index;\r
+\r
+ if (BlockDescriptors != NULL) {\r
+ TempBlockPtr1 = BlockDescriptors;\r
+ while (1){\r
+ TempBlockPtr = TempBlockPtr1;\r
+ for (Index = 0; Index < CapsuleNum; Index++) {\r
+ if (TempBlockPtr[Index].Length == 0) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (TempBlockPtr[Index].Union.ContinuationPointer == (UINTN)NULL) {\r
+ break;\r
+ }\r
+\r
+ TempBlockPtr2 = (VOID *) ((UINTN) TempBlockPtr->Union.ContinuationPointer);\r
+ FreePool(TempBlockPtr1);\r
+ TempBlockPtr1 = TempBlockPtr2;\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Print APP usage.\r
+**/\r
+VOID\r
+PrintUsage (\r
+ VOID\r
+ )\r
+{\r
+ Print(L"CapsuleApp: usage\n");\r
+ Print(L" CapsuleApp <Capsule...>\n");\r
+ Print(L" CapsuleApp -S\n");\r
+ Print(L" CapsuleApp -C\n");\r
+ Print(L" CapsuleApp -P\n");\r
+ Print(L" CapsuleApp -E\n");\r
+ Print(L" CapsuleApp -G <BMP> -O <Capsule>\n");\r
+ Print(L" CapsuleApp -N <Capsule> -O <NestedCapsule>\n");\r
+ Print(L" CapsuleApp -D <Capsule>\n");\r
+ Print(L"Parameter:\n");\r
+ Print(L" -S: Dump capsule report variable (EFI_CAPSULE_REPORT_GUID),\n");\r
+ Print(L" which is defined in UEFI specification.\n");\r
+ Print(L" -C: Clear capsule report variable (EFI_CAPSULE_RPORT_GUID),\n");\r
+ Print(L" which is defined in UEFI specification.\n");\r
+ Print(L" -P: Dump UEFI FMP protocol info.\n");\r
+ Print(L" -E: Dump UEFI ESRT table info.\n");\r
+ Print(L" -G: Convert a BMP file to be a UX capsule,\n");\r
+ Print(L" according to Windows Firmware Update document\n");\r
+ Print(L" -N: Append a Capsule Header to an existing capsule image,\n");\r
+ Print(L" according to Windows Firmware Update document\n");\r
+ Print(L" -O: Output new Capsule file name\n");\r
+ Print(L" -D: Dump Capsule image header information and FMP header information,\n");\r
+ Print(L" if it is an FMP capsule.\n");\r
+}\r
+\r
+/**\r
+ Update Capsule image.\r
+\r
+ @param[in] ImageHandle The image handle.\r
+ @param[in] SystemTable The system table.\r
+\r
+ @retval EFI_SUCCESS Command completed successfully.\r
+ @retval EFI_INVALID_PARAMETER Command usage error.\r
+ @retval EFI_NOT_FOUND The input file can't be found.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UefiMain (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN FileSize[MAX_CAPSULE_NUM];\r
+ VOID *CapsuleBuffer[MAX_CAPSULE_NUM];\r
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors;\r
+ EFI_CAPSULE_HEADER *CapsuleHeaderArray[MAX_CAPSULE_NUM + 1];\r
+ UINT64 MaxCapsuleSize;\r
+ EFI_RESET_TYPE ResetType;\r
+ BOOLEAN NeedReset;\r
+ CHAR16 *CapsuleName;\r
+ UINTN CapsuleNum;\r
+ UINTN Index;\r
+\r
+ Status = GetArg();\r
+ if (EFI_ERROR(Status)) {\r
+ Print(L"Please use UEFI SHELL to run this application!\n", Status);\r
+ return Status;\r
+ }\r
+ if (Argc < 2) {\r
+ PrintUsage();\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ if (StrCmp(Argv[1], L"-D") == 0) {\r
+ Status = DumpCapsule(Argv[2]);\r
+ return Status;\r
+ }\r
+ if (StrCmp(Argv[1], L"-G") == 0) {\r
+ Status = CreateBmpFmp();\r
+ return Status;\r
+ }\r
+ if (StrCmp(Argv[1], L"-N") == 0) {\r
+ Status = CreateNestedFmp();\r
+ return Status;\r
+ }\r
+ if (StrCmp(Argv[1], L"-S") == 0) {\r
+ Status = DmpCapsuleStatusVariable();\r
+ return EFI_SUCCESS;\r
+ }\r
+ if (StrCmp(Argv[1], L"-C") == 0) {\r
+ Status = ClearCapsuleStatusVariable();\r
+ return Status;\r
+ }\r
+ if (StrCmp(Argv[1], L"-P") == 0) {\r
+ DumpFmpData();\r
+ return EFI_SUCCESS;\r
+ }\r
+ if (StrCmp(Argv[1], L"-E") == 0) {\r
+ DumpEsrtData();\r
+ return EFI_SUCCESS;\r
+ }\r
+ CapsuleFirstIndex = 1;\r
+ CapsuleLastIndex = Argc - 1;\r
+ CapsuleNum = CapsuleLastIndex - CapsuleFirstIndex + 1;\r
+\r
+ if (CapsuleFirstIndex > CapsuleLastIndex) {\r
+ Print(L"CapsuleApp: NO capsule image.\n");\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ if (CapsuleNum > MAX_CAPSULE_NUM) {\r
+ Print(L"CapsuleApp: Too many capsule images.\n");\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ ZeroMem(&CapsuleBuffer, sizeof(CapsuleBuffer));\r
+ ZeroMem(&FileSize, sizeof(FileSize));\r
+ BlockDescriptors = NULL;\r
+\r
+ for (Index = 0; Index < CapsuleNum; Index++) {\r
+ CapsuleName = Argv[CapsuleFirstIndex + Index];\r
+ Status = ReadFileToBuffer(CapsuleName, &FileSize[Index], &CapsuleBuffer[Index]);\r
+ if (EFI_ERROR(Status)) {\r
+ Print(L"CapsuleApp: capsule image (%s) is not found.\n", CapsuleName);\r
+ goto Done;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Every capsule use 2 descriptor 1 for data 1 for end\r
+ //\r
+ Status = BuildGatherList(CapsuleBuffer, FileSize, CapsuleNum, &BlockDescriptors);\r
+ if (EFI_ERROR(Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // Call the runtime service capsule.\r
+ //\r
+ NeedReset = FALSE;\r
+ for (Index = 0; Index < CapsuleNum; Index++) {\r
+ CapsuleHeaderArray[Index] = (EFI_CAPSULE_HEADER *) CapsuleBuffer[Index];\r
+ if ((CapsuleHeaderArray[Index]->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {\r
+ NeedReset = TRUE;\r
+ }\r
+ }\r
+ CapsuleHeaderArray[CapsuleNum] = NULL;\r
+\r
+ //\r
+ // Inquire platform capability of UpdateCapsule.\r
+ //\r
+ Status = gRT->QueryCapsuleCapabilities (CapsuleHeaderArray, CapsuleNum, &MaxCapsuleSize, &ResetType);\r
+ if (EFI_ERROR(Status)) {\r
+ Print (L"CapsuleApp: failed to query capsule capability - %r\n", Status);\r
+ goto Done;\r
+ }\r
+\r
+ for (Index = 0; Index < CapsuleNum; Index++) {\r
+ if (FileSize[Index] > MaxCapsuleSize) {\r
+ Print (L"CapsuleApp: capsule is too large to update, %ld is allowed\n", MaxCapsuleSize);\r
+ Status = EFI_UNSUPPORTED;\r
+ goto Done;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Check whether the input capsule image has the flag of persist across system reset.\r
+ //\r
+ if (NeedReset) {\r
+ Status = gRT->UpdateCapsule(CapsuleHeaderArray,CapsuleNum,(UINTN) BlockDescriptors);\r
+ if (Status != EFI_SUCCESS) {\r
+ Print (L"CapsuleApp: failed to update capsule - %r\n", Status);\r
+ goto Done;\r
+ }\r
+ //\r
+ // For capsule who has reset flag, after calling UpdateCapsule service,triger a\r
+ // system reset to process capsule persist across a system reset.\r
+ //\r
+ gRT->ResetSystem (ResetType, EFI_SUCCESS, 0, NULL);\r
+ } else {\r
+ //\r
+ // For capsule who has no reset flag, only call UpdateCapsule Service without a\r
+ // system reset. The service will process the capsule immediately.\r
+ //\r
+ Status = gRT->UpdateCapsule (CapsuleHeaderArray,CapsuleNum,(UINTN) BlockDescriptors);\r
+ if (Status != EFI_SUCCESS) {\r
+ Print (L"CapsuleApp: failed to update capsule - %r\n", Status);\r
+ }\r
+ }\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+Done:\r
+ for (Index = 0; Index < CapsuleNum; Index++) {\r
+ if (CapsuleBuffer[Index] != NULL) {\r
+ FreePool (CapsuleBuffer[Index]);\r
+ }\r
+ }\r
+\r
+ CleanGatherList(BlockDescriptors, CapsuleNum);\r
+\r
+ return Status;\r
+}\r
--- /dev/null
+## @file\r
+# A shell application that triggers capsule update process.\r
+#\r
+# This application can trigger capsule update process. It can also\r
+# generate capsule image, or dump capsule variable information.\r
+#\r
+# Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010006\r
+ BASE_NAME = CapsuleApp\r
+ MODULE_UNI_FILE = CapsuleApp.uni\r
+ FILE_GUID = 4CEF31DA-8682-4274-9CC4-AEE7516A5E7B\r
+ MODULE_TYPE = UEFI_APPLICATION\r
+ VERSION_STRING = 1.0\r
+ ENTRY_POINT = UefiMain\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64\r
+#\r
+\r
+[Sources]\r
+ CapsuleApp.c\r
+ CapsuleDump.c\r
+ AppSupport.c\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ MdeModulePkg/MdeModulePkg.dec\r
+\r
+[Guids]\r
+ gEfiFileInfoGuid\r
+ gEfiPartTypeSystemPartGuid\r
+ gEfiGlobalVariableGuid\r
+ gEfiCapsuleReportGuid\r
+ gEfiFmpCapsuleGuid\r
+ gWindowsUxCapsuleGuid\r
+ gEfiCertTypeRsa2048Sha256Guid\r
+ gEfiCertPkcs7Guid\r
+ gEfiSystemResourceTableGuid\r
+\r
+[Protocols]\r
+ gEfiLoadedImageProtocolGuid\r
+ gEfiSimpleFileSystemProtocolGuid\r
+ gEfiGraphicsOutputProtocolGuid\r
+ gEfiFirmwareManagementProtocolGuid\r
+ gEfiShellParametersProtocolGuid\r
+\r
+[LibraryClasses]\r
+ BaseLib\r
+ UefiApplicationEntryPoint\r
+ DebugLib\r
+ MemoryAllocationLib\r
+ UefiBootServicesTableLib\r
+ UefiRuntimeServicesTableLib\r
+ UefiLib\r
+ PrintLib\r
+\r
+[UserExtensions.TianoCore."ExtraFiles"]\r
+ CapsuleAppExtra.uni\r
--- /dev/null
+// /** @file\r
+// A shell application that triggers capsule update process.\r
+//\r
+// This application can trigger capsule update process. It can also\r
+// generate capsule image, or dump capsule variable information.\r
+//\r
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>\r
+//\r
+// This program and the accompanying materials\r
+// are licensed and made available under the terms and conditions of the BSD License\r
+// which accompanies this distribution. The full text of the license may be found at\r
+// http://opensource.org/licenses/bsd-license.php\r
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+//\r
+// **/\r
+\r
+\r
+#string STR_MODULE_ABSTRACT #language en-US "A shell application that triggers capsule update process."\r
+\r
+#string STR_MODULE_DESCRIPTION #language en-US "This application can trigger capsule update process. It can also generate capsule image, or dump capsule variable information."\r
+\r
--- /dev/null
+// /** @file\r
+// CapsuleApp Localized Strings and Content\r
+//\r
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>\r
+//\r
+// This program and the accompanying materials\r
+// are licensed and made available under the terms and conditions of the BSD License\r
+// which accompanies this distribution. The full text of the license may be found at\r
+// http://opensource.org/licenses/bsd-license.php\r
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+//\r
+// **/\r
+\r
+#string STR_PROPERTIES_MODULE_NAME\r
+#language en-US\r
+"Capsule Application"\r
+\r
+\r
--- /dev/null
+/** @file\r
+ Dump Capsule image information.\r
+\r
+ Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <PiDxe.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/PrintLib.h>\r
+#include <Protocol/FirmwareManagement.h>\r
+#include <Guid/ImageAuthentication.h>\r
+#include <Guid/CapsuleReport.h>\r
+#include <Guid/SystemResourceTable.h>\r
+#include <Guid/FmpCapsule.h>\r
+#include <IndustryStandard/WindowsUxCapsule.h>\r
+\r
+/**\r
+ Read a file.\r
+\r
+ @param[in] FileName The file to be read.\r
+ @param[in] BufferSize The file buffer size\r
+ @param[in] Buffer The file buffer\r
+\r
+ @retval EFI_SUCCESS Read file successfully\r
+ @retval EFI_NOT_FOUND File not found\r
+**/\r
+EFI_STATUS\r
+ReadFileToBuffer (\r
+ IN CHAR16 *FileName,\r
+ OUT UINTN *BufferSize,\r
+ OUT VOID **Buffer\r
+ );\r
+\r
+/**\r
+ Dump UX capsule information.\r
+\r
+ @param[in] CapsuleHeader The UX capsule header\r
+**/\r
+VOID\r
+DumpUxCapsule (\r
+ IN EFI_CAPSULE_HEADER *CapsuleHeader\r
+ )\r
+{\r
+ EFI_DISPLAY_CAPSULE *DisplayCapsule;\r
+ DisplayCapsule = (EFI_DISPLAY_CAPSULE *)CapsuleHeader;\r
+ Print(L"[UxCapusule]\n");\r
+ Print(L"CapsuleHeader:\n");\r
+ Print(L" CapsuleGuid - %g\n", &DisplayCapsule->CapsuleHeader.CapsuleGuid);\r
+ Print(L" HeaderSize - 0x%x\n", DisplayCapsule->CapsuleHeader.HeaderSize);\r
+ Print(L" Flags - 0x%x\n", DisplayCapsule->CapsuleHeader.Flags);\r
+ Print(L" CapsuleImageSize - 0x%x\n", DisplayCapsule->CapsuleHeader.CapsuleImageSize);\r
+ Print(L"ImagePayload:\n");\r
+ Print(L" Version - 0x%x\n", DisplayCapsule->ImagePayload.Version);\r
+ Print(L" Checksum - 0x%x\n", DisplayCapsule->ImagePayload.Checksum);\r
+ Print(L" ImageType - 0x%x\n", DisplayCapsule->ImagePayload.ImageType);\r
+ Print(L" Mode - 0x%x\n", DisplayCapsule->ImagePayload.Mode);\r
+ Print(L" OffsetX - 0x%x\n", DisplayCapsule->ImagePayload.OffsetX);\r
+ Print(L" OffsetY - 0x%x\n", DisplayCapsule->ImagePayload.OffsetY);\r
+}\r
+\r
+/**\r
+ Dump FMP image authentication information.\r
+\r
+ @param[in] Image The FMP capsule image\r
+ @param[in] ImageSize The size of the FMP capsule image in bytes.\r
+\r
+ @return the size of FMP authentication.\r
+**/\r
+UINTN\r
+DumpImageAuthentication (\r
+ IN VOID *Image,\r
+ IN UINTN ImageSize\r
+ )\r
+{\r
+ EFI_FIRMWARE_IMAGE_AUTHENTICATION *ImageAuthentication;\r
+\r
+ ImageAuthentication = Image;\r
+ if (CompareGuid(&ImageAuthentication->AuthInfo.CertType, &gEfiCertPkcs7Guid) ||\r
+ CompareGuid(&ImageAuthentication->AuthInfo.CertType, &gEfiCertTypeRsa2048Sha256Guid)) {\r
+ Print(L"[ImageAuthentication]\n");\r
+ Print(L" MonotonicCount - 0x%lx\n", ImageAuthentication->MonotonicCount);\r
+ Print(L"WIN_CERTIFICATE:\n");\r
+ Print(L" dwLength - 0x%x\n", ImageAuthentication->AuthInfo.Hdr.dwLength);\r
+ Print(L" wRevision - 0x%x\n", ImageAuthentication->AuthInfo.Hdr.wRevision);\r
+ Print(L" wCertificateType - 0x%x\n", ImageAuthentication->AuthInfo.Hdr.wCertificateType);\r
+ Print(L" CertType - %g\n", &ImageAuthentication->AuthInfo.CertType);\r
+ return sizeof(ImageAuthentication->MonotonicCount) + ImageAuthentication->AuthInfo.Hdr.dwLength;\r
+ } else {\r
+ return 0;\r
+ }\r
+}\r
+\r
+/**\r
+ Dump a non-nested FMP capsule.\r
+\r
+ @param[in] CapsuleHeader A pointer to CapsuleHeader\r
+**/\r
+VOID\r
+DumpFmpCapsule (\r
+ IN EFI_CAPSULE_HEADER *CapsuleHeader\r
+ )\r
+{\r
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;\r
+ UINT64 *ItemOffsetList;\r
+ UINTN Index;\r
+ UINTN Count;\r
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *FmpImageHeader;\r
+\r
+ Print(L"[FmpCapusule]\n");\r
+ Print(L"CapsuleHeader:\n");\r
+ Print(L" CapsuleGuid - %g\n", &CapsuleHeader->CapsuleGuid);\r
+ Print(L" HeaderSize - 0x%x\n", CapsuleHeader->HeaderSize);\r
+ Print(L" Flags - 0x%x\n", CapsuleHeader->Flags);\r
+ Print(L" CapsuleImageSize - 0x%x\n", CapsuleHeader->CapsuleImageSize);\r
+\r
+ FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);\r
+ ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);\r
+ Print(L"FmpHeader:\n");\r
+ Print(L" Version - 0x%x\n", FmpCapsuleHeader->Version);\r
+ Print(L" EmbeddedDriverCount - 0x%x\n", FmpCapsuleHeader->EmbeddedDriverCount);\r
+ Print(L" PayloadItemCount - 0x%x\n", FmpCapsuleHeader->PayloadItemCount);\r
+ Count = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;\r
+ for (Index = 0; Index < Count; Index++) {\r
+ Print(L" Offset[%d] - 0x%x\n", Index, ItemOffsetList[Index]);\r
+ }\r
+\r
+ for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < Count; Index++) {\r
+ Print(L"FmpPayload[%d] ImageHeader:\n", Index);\r
+ FmpImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);\r
+ Print(L" Version - 0x%x\n", FmpImageHeader->Version);\r
+ Print(L" UpdateImageTypeId - %g\n", &FmpImageHeader->UpdateImageTypeId);\r
+ Print(L" UpdateImageIndex - 0x%x\n", FmpImageHeader->UpdateImageIndex);\r
+ Print(L" UpdateImageSize - 0x%x\n", FmpImageHeader->UpdateImageSize);\r
+ Print(L" UpdateVendorCodeSize - 0x%x\n", FmpImageHeader->UpdateVendorCodeSize);\r
+ if (FmpImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {\r
+ Print(L" UpdateHardwareInstance - 0x%lx\n", FmpImageHeader->UpdateHardwareInstance);\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Return if there is a FMP header below capsule header.\r
+\r
+ @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER\r
+\r
+ @retval TRUE There is a FMP header below capsule header.\r
+ @retval FALSE There is not a FMP header below capsule header\r
+**/\r
+BOOLEAN\r
+IsNestedFmpCapsule (\r
+ IN EFI_CAPSULE_HEADER *CapsuleHeader\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SYSTEM_RESOURCE_TABLE *Esrt;\r
+ EFI_SYSTEM_RESOURCE_ENTRY *EsrtEntry;\r
+ UINTN Index;\r
+ BOOLEAN EsrtGuidFound;\r
+ EFI_CAPSULE_HEADER *NestedCapsuleHeader;\r
+ UINTN NestedCapsuleSize;\r
+\r
+ //\r
+ // Check ESRT\r
+ //\r
+ EsrtGuidFound = FALSE;\r
+ Status = EfiGetSystemConfigurationTable(&gEfiSystemResourceTableGuid, (VOID **)&Esrt);\r
+ if (!EFI_ERROR(Status)) {\r
+ ASSERT (Esrt != NULL);\r
+ EsrtEntry = (VOID *)(Esrt + 1);\r
+ for (Index = 0; Index < Esrt->FwResourceCount; Index++, EsrtEntry++) {\r
+ if (CompareGuid(&EsrtEntry->FwClass, &CapsuleHeader->CapsuleGuid)) {\r
+ EsrtGuidFound = TRUE;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (!EsrtGuidFound) {\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Check nested capsule header\r
+ // FMP GUID after ESRT one\r
+ //\r
+ NestedCapsuleHeader = (EFI_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);\r
+ NestedCapsuleSize = (UINTN)CapsuleHeader + CapsuleHeader->HeaderSize - (UINTN)NestedCapsuleHeader;\r
+ if (NestedCapsuleSize < sizeof(EFI_CAPSULE_HEADER)) {\r
+ return FALSE;\r
+ }\r
+ if (!CompareGuid(&NestedCapsuleHeader->CapsuleGuid, &gEfiFmpCapsuleGuid)) {\r
+ return FALSE;\r
+ }\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Dump capsule information\r
+\r
+ @param[in] CapsuleName The name of the capsule image.\r
+\r
+ @retval EFI_SUCCESS The capsule information is dumped.\r
+ @retval EFI_UNSUPPORTED Input parameter is not valid.\r
+**/\r
+EFI_STATUS\r
+DumpCapsule (\r
+ IN CHAR16 *CapsuleName\r
+ )\r
+{\r
+ VOID *Buffer;\r
+ UINTN FileSize;\r
+ EFI_CAPSULE_HEADER *CapsuleHeader;\r
+ EFI_STATUS Status;\r
+\r
+ Status = ReadFileToBuffer(CapsuleName, &FileSize, &Buffer);\r
+ if (EFI_ERROR(Status)) {\r
+ Print(L"CapsuleApp: Capsule (%s) is not found.\n", CapsuleName);\r
+ goto Done;\r
+ }\r
+\r
+ CapsuleHeader = Buffer;\r
+ if (CompareGuid(&CapsuleHeader->CapsuleGuid, &gWindowsUxCapsuleGuid)) {\r
+ DumpUxCapsule(CapsuleHeader);\r
+ Status = EFI_SUCCESS;\r
+ goto Done;\r
+ }\r
+\r
+ if (CompareGuid(&CapsuleHeader->CapsuleGuid, &gEfiFmpCapsuleGuid)) {\r
+ DumpFmpCapsule(CapsuleHeader);\r
+ }\r
+ if (IsNestedFmpCapsule(CapsuleHeader)) {\r
+ Print(L"[NestedCapusule]\n");\r
+ Print(L"CapsuleHeader:\n");\r
+ Print(L" CapsuleGuid - %g\n", &CapsuleHeader->CapsuleGuid);\r
+ Print(L" HeaderSize - 0x%x\n", CapsuleHeader->HeaderSize);\r
+ Print(L" Flags - 0x%x\n", CapsuleHeader->Flags);\r
+ Print(L" CapsuleImageSize - 0x%x\n", CapsuleHeader->CapsuleImageSize);\r
+ DumpFmpCapsule((EFI_CAPSULE_HEADER *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize));\r
+ }\r
+\r
+Done:\r
+ FreePool(Buffer);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Dump capsule status variable.\r
+\r
+ @retval EFI_SUCCESS The capsule status variable is dumped.\r
+ @retval EFI_UNSUPPORTED Input parameter is not valid.\r
+**/\r
+EFI_STATUS\r
+DmpCapsuleStatusVariable (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 Index;\r
+ CHAR16 CapsuleVarName[20];\r
+ CHAR16 *TempVarName;\r
+ EFI_CAPSULE_RESULT_VARIABLE_HEADER *CapsuleResult;\r
+ EFI_CAPSULE_RESULT_VARIABLE_FMP *CapsuleResultFmp;\r
+ UINTN CapsuleFileNameSize;\r
+ CHAR16 CapsuleIndexData[12];\r
+ CHAR16 *CapsuleIndex;\r
+\r
+ Status = GetVariable2(\r
+ L"CapsuleMax",\r
+ &gEfiCapsuleReportGuid,\r
+ (VOID **)&CapsuleIndex,\r
+ NULL\r
+ );\r
+ if (!EFI_ERROR(Status)) {\r
+ CopyMem(CapsuleIndexData, CapsuleIndex, 11 * sizeof(CHAR16));\r
+ CapsuleIndexData[11] = 0;\r
+ Print(L"CapsuleMax - %s\n", CapsuleIndexData);\r
+ FreePool(CapsuleIndex);\r
+ }\r
+ Status = GetVariable2(\r
+ L"CapsuleLast",\r
+ &gEfiCapsuleReportGuid,\r
+ (VOID **)&CapsuleIndex,\r
+ NULL\r
+ );\r
+ if (!EFI_ERROR(Status)) {\r
+ CopyMem(CapsuleIndexData, CapsuleIndex, 11 * sizeof(CHAR16));\r
+ CapsuleIndexData[11] = 0;\r
+ Print(L"CapsuleLast - %s\n", CapsuleIndexData);\r
+ FreePool(CapsuleIndex);\r
+ }\r
+\r
+\r
+ StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CapsuleVarName[0]), L"Capsule");\r
+ TempVarName = CapsuleVarName + StrLen (CapsuleVarName);\r
+ Index = 0;\r
+\r
+ while (TRUE) {\r
+ UnicodeSPrint (TempVarName, 5 * sizeof(CHAR16), L"%04x", Index);\r
+\r
+ Status = GetVariable2 (\r
+ CapsuleVarName,\r
+ &gEfiCapsuleReportGuid,\r
+ (VOID **) &CapsuleResult,\r
+ NULL\r
+ );\r
+ if (Status == EFI_NOT_FOUND) {\r
+ break;\r
+ } else if (EFI_ERROR(Status)) {\r
+ continue;\r
+ }\r
+ ASSERT (CapsuleResult != NULL);\r
+\r
+ //\r
+ // display capsule process status\r
+ //\r
+ if (CapsuleResult->VariableTotalSize >= sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER)) {\r
+ Print (L"CapsuleName: %s\n", CapsuleVarName);\r
+ Print (L" Capsule Guid: %g\n", &CapsuleResult->CapsuleGuid);\r
+ Print (L" Capsule ProcessedTime: %t\n", &CapsuleResult->CapsuleProcessed);\r
+ Print (L" Capsule Status: %r\n", CapsuleResult->CapsuleStatus);\r
+ }\r
+\r
+ if (CompareGuid(&CapsuleResult->CapsuleGuid, &gEfiFmpCapsuleGuid)) {\r
+ if (CapsuleResult->VariableTotalSize >= sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER) + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP)) {\r
+ CapsuleResultFmp = (EFI_CAPSULE_RESULT_VARIABLE_FMP *)(CapsuleResult + 1);\r
+ Print(L" Capsule FMP Version: 0x%x\n", CapsuleResultFmp->Version);\r
+ Print(L" Capsule FMP PayloadIndex: 0x%x\n", CapsuleResultFmp->PayloadIndex);\r
+ Print(L" Capsule FMP UpdateImageIndex: 0x%x\n", CapsuleResultFmp->UpdateImageIndex);\r
+ Print(L" Capsule FMP UpdateImageTypeId: %g\n", &CapsuleResultFmp->UpdateImageTypeId);\r
+ if (CapsuleResult->VariableTotalSize > sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER) + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP)) {\r
+ Print(L" Capsule FMP CapsuleFileName: %s\n", (CapsuleResultFmp + 1));\r
+ CapsuleFileNameSize = StrSize((CHAR16 *)(CapsuleResultFmp + 1));\r
+ if (CapsuleResult->VariableTotalSize > sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER) + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP) + CapsuleFileNameSize) {\r
+ Print(L" Capsule FMP CapsuleTarget: %s\n", (UINT8 *)(CapsuleResultFmp + 1) + CapsuleFileNameSize);\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ FreePool(CapsuleResult);\r
+\r
+ Index++;\r
+ if (Index > 0xFFFF) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+CHAR8 *mFwTypeString[] = {\r
+ "Unknown",\r
+ "SystemFirmware",\r
+ "DeviceFirmware",\r
+ "UefiDriver",\r
+};\r
+\r
+CHAR8 *mLastAttemptStatusString[] = {\r
+ "Success",\r
+ "Error: Unsuccessful",\r
+ "Error: Insufficient Resources",\r
+ "Error: Incorrect Version",\r
+ "Error: Invalid Format",\r
+ "Error: Auth Error",\r
+ "Error: Power Event AC",\r
+ "Error: Power Event Battery",\r
+};\r
+\r
+/**\r
+ Convert FwType to a string.\r
+\r
+ @param[in] FwType FwType in ESRT\r
+\r
+ @return a string for FwType.\r
+**/\r
+CHAR8 *\r
+FwTypeToString (\r
+ IN UINT32 FwType\r
+ )\r
+{\r
+ if (FwType < sizeof(mFwTypeString) / sizeof(mFwTypeString[0])) {\r
+ return mFwTypeString[FwType];\r
+ } else {\r
+ return "Invalid";\r
+ }\r
+}\r
+\r
+/**\r
+ Convert LastAttemptStatus to a string.\r
+\r
+ @param[in] LastAttemptStatus LastAttemptStatus in FMP or ESRT\r
+\r
+ @return a string for LastAttemptStatus.\r
+**/\r
+CHAR8 *\r
+LastAttemptStatusToString (\r
+ IN UINT32 LastAttemptStatus\r
+ )\r
+{\r
+ if (LastAttemptStatus < sizeof(mLastAttemptStatusString) / sizeof(mLastAttemptStatusString[0])) {\r
+ return mLastAttemptStatusString[LastAttemptStatus];\r
+ } else {\r
+ return "Error: Unknown";\r
+ }\r
+}\r
+\r
+/**\r
+ Dump ESRT entry.\r
+\r
+ @param[in] EsrtEntry ESRT entry\r
+**/\r
+VOID\r
+DumpEsrtEntry (\r
+ IN EFI_SYSTEM_RESOURCE_ENTRY *EsrtEntry\r
+ )\r
+{\r
+ Print(L" FwClass - %g\n", &EsrtEntry->FwClass);\r
+ Print(L" FwType - 0x%x (%a)\n", EsrtEntry->FwType, FwTypeToString(EsrtEntry->FwType));\r
+ Print(L" FwVersion - 0x%x\n", EsrtEntry->FwVersion);\r
+ Print(L" LowestSupportedFwVersion - 0x%x\n", EsrtEntry->LowestSupportedFwVersion);\r
+ Print(L" CapsuleFlags - 0x%x\n", EsrtEntry->CapsuleFlags);\r
+ Print(L" PERSIST_ACROSS_RESET - 0x%x\n", EsrtEntry->CapsuleFlags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET);\r
+ Print(L" POPULATE_SYSTEM_TABLE - 0x%x\n", EsrtEntry->CapsuleFlags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE);\r
+ Print(L" INITIATE_RESET - 0x%x\n", EsrtEntry->CapsuleFlags & CAPSULE_FLAGS_INITIATE_RESET);\r
+ Print(L" LastAttemptVersion - 0x%x\n", EsrtEntry->LastAttemptVersion);\r
+ Print(L" LastAttemptStatus - 0x%x (%a)\n", EsrtEntry->LastAttemptStatus, LastAttemptStatusToString(EsrtEntry->LastAttemptStatus));\r
+}\r
+\r
+/**\r
+ Dump ESRT table.\r
+\r
+ @param[in] Esrt ESRT table\r
+**/\r
+VOID\r
+DumpEsrt (\r
+ IN EFI_SYSTEM_RESOURCE_TABLE *Esrt\r
+ )\r
+{\r
+ UINTN Index;\r
+ EFI_SYSTEM_RESOURCE_ENTRY *EsrtEntry;\r
+\r
+ if (Esrt == NULL) {\r
+ return ;\r
+ }\r
+\r
+ Print(L"EFI_SYSTEM_RESOURCE_TABLE:\n");\r
+ Print(L"FwResourceCount - 0x%x\n", Esrt->FwResourceCount);\r
+ Print(L"FwResourceCountMax - 0x%x\n", Esrt->FwResourceCountMax);\r
+ Print(L"FwResourceVersion - 0x%lx\n", Esrt->FwResourceVersion);\r
+\r
+ EsrtEntry = (VOID *)(Esrt + 1);\r
+ for (Index = 0; Index < Esrt->FwResourceCount; Index++) {\r
+ Print(L"EFI_SYSTEM_RESOURCE_ENTRY (%d):\n", Index);\r
+ DumpEsrtEntry(EsrtEntry);\r
+ EsrtEntry++;\r
+ }\r
+}\r
+\r
+/**\r
+ Dump ESRT info.\r
+**/\r
+VOID\r
+DumpEsrtData (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SYSTEM_RESOURCE_TABLE *Esrt;\r
+\r
+ Print(L"##############\n");\r
+ Print(L"# ESRT TABLE #\n");\r
+ Print(L"##############\n");\r
+\r
+ Status = EfiGetSystemConfigurationTable (&gEfiSystemResourceTableGuid, (VOID **)&Esrt);\r
+ if (EFI_ERROR(Status)) {\r
+ Print(L"ESRT - %r\n", Status);\r
+ return;\r
+ }\r
+ DumpEsrt(Esrt);\r
+ Print(L"\n");\r
+}\r
+\r
+/**\r
+ Dump FMP information.\r
+\r
+ @param[in] ImageInfoSize The size of ImageInfo, in bytes.\r
+ @param[in] ImageInfo A pointer to EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
+ @param[in] DescriptorVersion The version of EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
+ @param[in] DescriptorCount The count of EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
+ @param[in] DescriptorSize The size of an individual EFI_FIRMWARE_IMAGE_DESCRIPTOR, in bytes.\r
+ @param[in] PackageVersion The version of package.\r
+ @param[in] PackageVersionName The version name of package.\r
+**/\r
+VOID\r
+DumpFmpImageInfo (\r
+ IN UINTN ImageInfoSize,\r
+ IN EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageInfo,\r
+ IN UINT32 DescriptorVersion,\r
+ IN UINT8 DescriptorCount,\r
+ IN UINTN DescriptorSize,\r
+ IN UINT32 PackageVersion,\r
+ IN CHAR16 *PackageVersionName\r
+ )\r
+{\r
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR *CurrentImageInfo;\r
+ UINTN Index;\r
+\r
+ Print(L" DescriptorVersion - 0x%x\n", DescriptorVersion);\r
+ Print(L" DescriptorCount - 0x%x\n", DescriptorCount);\r
+ Print(L" DescriptorSize - 0x%x\n", DescriptorSize);\r
+ Print(L" PackageVersion - 0x%x\n", PackageVersion);\r
+ Print(L" PackageVersionName - \"%s\"\n", PackageVersionName);\r
+ CurrentImageInfo = ImageInfo;\r
+ for (Index = 0; Index < DescriptorCount; Index++) {\r
+ Print(L" ImageDescriptor (%d)\n", Index);\r
+ Print(L" ImageIndex - 0x%x\n", CurrentImageInfo->ImageIndex);\r
+ Print(L" ImageTypeId - %g\n", &CurrentImageInfo->ImageTypeId);\r
+ Print(L" ImageId - 0x%lx\n", CurrentImageInfo->ImageId);\r
+ Print(L" ImageIdName - \"%s\"\n", CurrentImageInfo->ImageIdName);\r
+ Print(L" Version - 0x%x\n", CurrentImageInfo->Version);\r
+ Print(L" VersionName - \"%s\"\n", CurrentImageInfo->VersionName);\r
+ Print(L" Size - 0x%x\n", CurrentImageInfo->Size);\r
+ Print(L" AttributesSupported - 0x%lx\n", CurrentImageInfo->AttributesSupported);\r
+ Print(L" IMAGE_UPDATABLE - 0x%lx\n", CurrentImageInfo->AttributesSupported & IMAGE_ATTRIBUTE_IMAGE_UPDATABLE);\r
+ Print(L" RESET_REQUIRED - 0x%lx\n", CurrentImageInfo->AttributesSupported & IMAGE_ATTRIBUTE_RESET_REQUIRED);\r
+ Print(L" AUTHENTICATION_REQUIRED - 0x%lx\n", CurrentImageInfo->AttributesSupported & IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED);\r
+ Print(L" IN_USE - 0x%lx\n", CurrentImageInfo->AttributesSupported & IMAGE_ATTRIBUTE_IN_USE);\r
+ Print(L" UEFI_IMAGE - 0x%lx\n", CurrentImageInfo->AttributesSupported & IMAGE_ATTRIBUTE_UEFI_IMAGE);\r
+ Print(L" AttributesSetting - 0x%lx\n", CurrentImageInfo->AttributesSetting);\r
+ Print(L" IMAGE_UPDATABLE - 0x%lx\n", CurrentImageInfo->AttributesSetting & IMAGE_ATTRIBUTE_IMAGE_UPDATABLE);\r
+ Print(L" RESET_REQUIRED - 0x%lx\n", CurrentImageInfo->AttributesSetting & IMAGE_ATTRIBUTE_RESET_REQUIRED);\r
+ Print(L" AUTHENTICATION_REQUIRED - 0x%lx\n", CurrentImageInfo->AttributesSetting & IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED);\r
+ Print(L" IN_USE - 0x%lx\n", CurrentImageInfo->AttributesSetting & IMAGE_ATTRIBUTE_IN_USE);\r
+ Print(L" UEFI_IMAGE - 0x%lx\n", CurrentImageInfo->AttributesSetting & IMAGE_ATTRIBUTE_UEFI_IMAGE);\r
+ Print(L" Compatibilities - 0x%lx\n", CurrentImageInfo->Compatibilities);\r
+ Print(L" COMPATIB_CHECK_SUPPORTED - 0x%lx\n", CurrentImageInfo->Compatibilities & IMAGE_COMPATIBILITY_CHECK_SUPPORTED);\r
+ if (DescriptorVersion > 1) {\r
+ Print(L" LowestSupportedImageVersion - 0x%x\n", CurrentImageInfo->LowestSupportedImageVersion);\r
+ if (DescriptorVersion > 2) {\r
+ Print(L" LastAttemptVersion - 0x%x\n", CurrentImageInfo->LastAttemptVersion);\r
+ Print(L" LastAttemptStatus - 0x%x (%a)\n", CurrentImageInfo->LastAttemptStatus, LastAttemptStatusToString(CurrentImageInfo->LastAttemptStatus));\r
+ Print(L" HardwareInstance - 0x%lx\n", CurrentImageInfo->HardwareInstance);\r
+ }\r
+ }\r
+ //\r
+ // Use DescriptorSize to move ImageInfo Pointer to stay compatible with different ImageInfo version\r
+ //\r
+ CurrentImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)CurrentImageInfo + DescriptorSize);\r
+ }\r
+}\r
+\r
+/**\r
+ Dump FMP package information.\r
+\r
+ @param[in] PackageVersion The version of package.\r
+ @param[in] PackageVersionName The version name of package.\r
+ @param[in] PackageVersionNameMaxLen The maximum length of PackageVersionName.\r
+ @param[in] AttributesSupported Package attributes that are supported by this device.\r
+ @param[in] AttributesSetting Package attributes.\r
+**/\r
+VOID\r
+DumpFmpPackageInfo (\r
+ IN UINT32 PackageVersion,\r
+ IN CHAR16 *PackageVersionName,\r
+ IN UINT32 PackageVersionNameMaxLen,\r
+ IN UINT64 AttributesSupported,\r
+ IN UINT64 AttributesSetting\r
+ )\r
+{\r
+ Print(L" PackageVersion - 0x%x\n", PackageVersion);\r
+ Print(L" PackageVersionName - \"%s\"\n", PackageVersionName);\r
+ Print(L" PackageVersionNameMaxLen - 0x%x\n", PackageVersionNameMaxLen);\r
+ Print(L" AttributesSupported - 0x%lx\n", AttributesSupported);\r
+ Print(L" IMAGE_UPDATABLE - 0x%lx\n", AttributesSupported & IMAGE_ATTRIBUTE_IMAGE_UPDATABLE);\r
+ Print(L" RESET_REQUIRED - 0x%lx\n", AttributesSupported & IMAGE_ATTRIBUTE_RESET_REQUIRED);\r
+ Print(L" AUTHENTICATION_REQUIRED - 0x%lx\n", AttributesSupported & IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED);\r
+ Print(L" AttributesSetting - 0x%lx\n", AttributesSetting);\r
+ Print(L" IMAGE_UPDATABLE - 0x%lx\n", AttributesSetting & IMAGE_ATTRIBUTE_IMAGE_UPDATABLE);\r
+ Print(L" RESET_REQUIRED - 0x%lx\n", AttributesSetting & IMAGE_ATTRIBUTE_RESET_REQUIRED);\r
+ Print(L" AUTHENTICATION_REQUIRED - 0x%lx\n", AttributesSetting & IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED);\r
+}\r
+\r
+/**\r
+ Dump FMP protocol info.\r
+**/\r
+VOID\r
+DumpFmpData (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;\r
+ EFI_HANDLE *HandleBuffer;\r
+ UINTN NumberOfHandles;\r
+ UINTN Index;\r
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf;\r
+ UINTN ImageInfoSize;\r
+ UINT32 FmpImageInfoDescriptorVer;\r
+ UINT8 FmpImageInfoCount;\r
+ UINTN DescriptorSize;\r
+ UINT32 PackageVersion;\r
+ CHAR16 *PackageVersionName;\r
+ UINT32 PackageVersionNameMaxLen;\r
+ UINT64 AttributesSupported;\r
+ UINT64 AttributesSetting;\r
+\r
+ Print(L"############\n");\r
+ Print(L"# FMP DATA #\n");\r
+ Print(L"############\n");\r
+ Status = gBS->LocateHandleBuffer (\r
+ ByProtocol,\r
+ &gEfiFirmwareManagementProtocolGuid,\r
+ NULL,\r
+ &NumberOfHandles,\r
+ &HandleBuffer\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ Print(L"FMP protocol - %r\n", EFI_NOT_FOUND);\r
+ return;\r
+ }\r
+\r
+ for (Index = 0; Index < NumberOfHandles; Index++) {\r
+ Status = gBS->HandleProtocol(\r
+ HandleBuffer[Index],\r
+ &gEfiFirmwareManagementProtocolGuid,\r
+ (VOID **)&Fmp\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ continue;\r
+ }\r
+\r
+ ImageInfoSize = 0;\r
+ Status = Fmp->GetImageInfo (\r
+ Fmp,\r
+ &ImageInfoSize,\r
+ NULL,\r
+ NULL,\r
+ NULL,\r
+ NULL,\r
+ NULL,\r
+ NULL\r
+ );\r
+ if (Status != EFI_BUFFER_TOO_SMALL) {\r
+ continue;\r
+ }\r
+\r
+ FmpImageInfoBuf = NULL;\r
+ FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);\r
+ if (FmpImageInfoBuf == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto EXIT;\r
+ }\r
+\r
+ PackageVersionName = NULL;\r
+ Status = Fmp->GetImageInfo (\r
+ Fmp,\r
+ &ImageInfoSize, // ImageInfoSize\r
+ FmpImageInfoBuf, // ImageInfo\r
+ &FmpImageInfoDescriptorVer, // DescriptorVersion\r
+ &FmpImageInfoCount, // DescriptorCount\r
+ &DescriptorSize, // DescriptorSize\r
+ &PackageVersion, // PackageVersion\r
+ &PackageVersionName // PackageVersionName\r
+ );\r
+\r
+ //\r
+ // If FMP GetInformation interface failed, skip this resource\r
+ //\r
+ if (EFI_ERROR(Status)) {\r
+ Print(L"FMP (%d) ImageInfo - %r\n", Index, Status);\r
+ FreePool(FmpImageInfoBuf);\r
+ continue;\r
+ }\r
+\r
+ Print(L"FMP (%d) ImageInfo:\n", Index);\r
+ DumpFmpImageInfo(\r
+ ImageInfoSize, // ImageInfoSize\r
+ FmpImageInfoBuf, // ImageInfo\r
+ FmpImageInfoDescriptorVer, // DescriptorVersion\r
+ FmpImageInfoCount, // DescriptorCount\r
+ DescriptorSize, // DescriptorSize\r
+ PackageVersion, // PackageVersion\r
+ PackageVersionName // PackageVersionName\r
+ );\r
+\r
+ if (PackageVersionName != NULL) {\r
+ FreePool(PackageVersionName);\r
+ }\r
+ FreePool(FmpImageInfoBuf);\r
+\r
+ //\r
+ // Get package info\r
+ //\r
+ PackageVersionName = NULL;\r
+ Status = Fmp->GetPackageInfo (\r
+ Fmp,\r
+ &PackageVersion, // PackageVersion\r
+ &PackageVersionName, // PackageVersionName\r
+ &PackageVersionNameMaxLen, // PackageVersionNameMaxLen\r
+ &AttributesSupported, // AttributesSupported\r
+ &AttributesSetting // AttributesSetting\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ Print(L"FMP (%d) PackageInfo - %r\n", Index, Status);\r
+ } else {\r
+ Print(L"FMP (%d) ImageInfo:\n", Index);\r
+ DumpFmpPackageInfo(\r
+ PackageVersion, // PackageVersion\r
+ PackageVersionName, // PackageVersionName\r
+ PackageVersionNameMaxLen, // PackageVersionNameMaxLen\r
+ AttributesSupported, // AttributesSupported\r
+ AttributesSetting // AttributesSetting\r
+ );\r
+\r
+ if (PackageVersionName != NULL) {\r
+ FreePool(PackageVersionName);\r
+ }\r
+ }\r
+ }\r
+ Print(L"\n");\r
+\r
+EXIT:\r
+ FreePool(HandleBuffer);\r
+}\r