From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga04.intel.com (mga04.intel.com [192.55.52.120]) (using TLSv1 with cipher CAMELLIA256-SHA (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 565C51A1E31 for ; Tue, 25 Oct 2016 19:19:36 -0700 (PDT) Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga104.fm.intel.com with ESMTP; 25 Oct 2016 19:19:35 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.31,548,1473145200"; d="scan'208,217";a="777722174" Received: from fmsmsx104.amr.corp.intel.com ([10.18.124.202]) by FMSMGA003.fm.intel.com with ESMTP; 25 Oct 2016 19:19:35 -0700 Received: from shsmsx104.ccr.corp.intel.com (10.239.4.70) by fmsmsx104.amr.corp.intel.com (10.18.124.202) with Microsoft SMTP Server (TLS) id 14.3.248.2; Tue, 25 Oct 2016 19:19:32 -0700 Received: from shsmsx102.ccr.corp.intel.com ([169.254.2.206]) by SHSMSX104.ccr.corp.intel.com ([169.254.5.209]) with mapi id 14.03.0248.002; Wed, 26 Oct 2016 10:19:30 +0800 From: "Yao, Jiewen" To: "Kinney, Michael D" , "edk2-devel@lists.01.org" CC: "Tian, Feng" , "Zeng, Star" , "Gao, Liming" , "Zhang, Chao B" Thread-Topic: [PATCH V4 08/15] MdeModulePkg/CapsuleApp: Add CapsuleApp application. Thread-Index: AQHSLxcocLuInjtGFUORDU1djxWVaaC519bg//+eogCAAInu4A== Date: Wed, 26 Oct 2016 02:19:29 +0000 Message-ID: <74D8A39837DF1E4DA445A8C0B3885C50386B7588@shsmsx102.ccr.corp.intel.com> References: <1477189240-11336-1-git-send-email-jiewen.yao@intel.com> <1477189240-11336-9-git-send-email-jiewen.yao@intel.com> <74D8A39837DF1E4DA445A8C0B3885C50386B73AC@shsmsx102.ccr.corp.intel.com> In-Reply-To: Accept-Language: zh-CN, en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-originating-ip: [10.239.127.40] MIME-Version: 1.0 X-Content-Filtered-By: Mailman/MimeDel 2.1.21 Subject: Re: [PATCH V4 08/15] MdeModulePkg/CapsuleApp: Add CapsuleApp application. X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 26 Oct 2016 02:19:36 -0000 Content-Language: en-US Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable That is good idea. I will add more description. From: Kinney, Michael D Sent: Wednesday, October 26, 2016 10:05 AM To: Yao, Jiewen ; edk2-devel@lists.01.org; Kinney, Mi= chael D Cc: Tian, Feng ; Zeng, Star ; Gao= , Liming ; Zhang, Chao B Subject: RE: [PATCH V4 08/15] MdeModulePkg/CapsuleApp: Add CapsuleApp appli= cation. Jiewen, Thanks for the details. Can you add some more help information for Capsule= App so the usage of the flags you keep are clear. I agree that keeping fla= gs that support some unit tests makes sense. Mike From: Yao, Jiewen Sent: Tuesday, October 25, 2016 5:42 PM To: Kinney, Michael D >; edk2-devel@lists.01.org Cc: Tian, Feng >; Zeng, Sta= r >; Gao, Liming >; Zhang, Chao B > Subject: RE: [PATCH V4 08/15] MdeModulePkg/CapsuleApp: Add CapsuleApp appli= cation. Comments inline: From: Kinney, Michael D Sent: Wednesday, October 26, 2016 7:26 AM To: Yao, Jiewen >; edk2-d= evel@lists.01.org; Kinney, Michael D > Cc: Tian, Feng >; Zeng, Sta= r >; Gao, Liming >; Zhang, Chao B > Subject: RE: [PATCH V4 08/15] MdeModulePkg/CapsuleApp: Add CapsuleApp appli= cation. Hi Jiewen, When I run the CapsuleApp.efi, it shows the following help: CapsuleApp: usage CapsuleApp [-NR] CapsuleApp -S CapsuleApp -C CapsuleApp -P CapsuleApp -E CapsuleApp -G -O CapsuleApp -N -O CapsuleApp -D|-DS Parameter: -NR: No Reset. -S: Dump capsule status. -C: Clear capsule status. -P: Dump FMP protocol info. -E: Dump ESRT table info. -G: Input BMP file name -N: Append Capsule Header accroding to Windows Firmware Update -O: Output Capsule file name -D: Dump Capsule I have verified that that standard use case for Galileo Gen 2 works: CapsuleApp.efi QUARKFIRMWAREUPDATECAPSULEFMPPKCS7.Cap I then explored some of the other options and there are some that do not work as expected: 1) If I set the no reset flag (-NR), it still resets. CapsuleApp.efi QUARKFIRMWAREUPDATECAPSULEFMPPKCS7.Cap -NR [Jiewen] This flag/code is inherit from the original EDKI code. I made a mistake that I thought it should work. But not actually because I just realize the reset process is moved to Capsu= leService driver. I will remove [NR] flag totally. 2) Because (1) does not work, the flags to view or operate on a previously Loaded capsule cannot be used such as -S, -C, -N, -O, -D. So I do not know if any of these flags work. Have you tested them? [Jiewen] Yes, any of these flags are new added by me to assist Capsule proc= ess debug. All of below are validated. None of them are related to [NR] -S: Dump capsule status. // The capsule status variable is defined by UE= FI spec. Just dump the variable. No touch capsule image. -C: Clear capsule status. // The capsule status variable is defined by U= EFI spec. Just clear the variable. No touch capsule image. -N: Append Capsule Header accroding to Windows Firmware Update // this i= s to follow "Windows Firmware Update" document to append a header. We need = input a capsule image and out a new capsule image. So we can test the neste= d capsule image. No capsule service is called. Just append header and gener= ate a new image. -O: Output Capsule file name // -O is an option working with others such= as "-G -O ", or "-N -O " -D: Dump Capsule // this is just dump the capsule image information. If you find some do not work, please let me know and I will fix them. 3) What does -G do? I do not see a standard way to update only a BMP logo image in this series of patches. If that is not really functional, then the code and help for -G should be removed. [Jiewen] Yes, any of these flags are new added by me to assist Capsule proc= ess debug. -G: Input BMP file name // this is to follow "windows firmware update" d= ocument to wrap a BMP file to be a UX capsule. So that end user may see a p= icture during capsule process, ideally. The prerequisite is that the platfo= rm need have a valid console. This UX capsule is already supported in IntelFrameworkModulePkg\Library\Dxe= CapsuleLib. I think this app just provides the capability to generate a UX capsule for = unit test. I think this is useful and I suggest we keep it. If you find it does not work, please let me know and I will fix it. 4) Typo in help for -N flag. "accroding" should be "according". [Jiewen] Thank you. Fixed. Mike > -----Original Message----- > From: Yao, Jiewen > Sent: Saturday, October 22, 2016 7:21 PM > To: edk2-devel@lists.01.org > Cc: Tian, Feng >; Zeng, S= tar >; Kinney, Michael > D >; Gao, L= iming >; Zhang, Chao B > > > Subject: [PATCH V4 08/15] MdeModulePkg/CapsuleApp: Add CapsuleApp applica= tion. > > This CapsuleApp can help perform capsule update in UEFI shell environment= . > It can also dump capsule information, capsule status variable, ESRT and F= MP. > > Cc: Feng Tian > > Cc: Star Zeng > > Cc: Michael D Kinney > > Cc: Liming Gao > > Cc: Chao Zhang > > Contributed-under: TianoCore Contribution Agreement 1.0 > Signed-off-by: Jiewen Yao > > Reviewed-by: Liming Gao > > --- > MdeModulePkg/Application/CapsuleApp/AppSupport.c | 445 ++++++++++ > MdeModulePkg/Application/CapsuleApp/CapsuleApp.c | 853 ++++++++++= ++++++++++ > MdeModulePkg/Application/CapsuleApp/CapsuleApp.inf | 71 ++ > MdeModulePkg/Application/CapsuleApp/CapsuleApp.uni | 22 + > MdeModulePkg/Application/CapsuleApp/CapsuleAppExtra.uni | 19 + > MdeModulePkg/Application/CapsuleApp/CapsuleDump.c | 740 ++++++++++= +++++++ > 6 files changed, 2150 insertions(+) > > diff --git a/MdeModulePkg/Application/CapsuleApp/AppSupport.c > b/MdeModulePkg/Application/CapsuleApp/AppSupport.c > new file mode 100644 > index 0000000..90ca1fd > --- /dev/null > +++ b/MdeModulePkg/Application/CapsuleApp/AppSupport.c > @@ -0,0 +1,445 @@ > +/** @file > + A shell application that triggers capsule update process. > + > + Copyright (c) 2016, Intel Corporation. All rights reserved.
> + This program and the accompanying materials > + are licensed and made available under the terms and conditions of the = BSD License > + which accompanies this distribution. The full text of the license may= be found at > + http://opensource.org/licenses/bsd-license.php > + > + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR I= MPLIED. > + > +**/ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#define MAX_ARG_NUM 11 > + > +UINTN Argc; > +CHAR16 **Argv; > + > +/** > + > + This function parse application ARG. > + > + @return Status > +**/ > +EFI_STATUS > +GetArg ( > + VOID > + ) > +{ > + EFI_STATUS Status; > + EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters; > + > + Status =3D gBS->HandleProtocol ( > + gImageHandle, > + &gEfiShellParametersProtocolGuid, > + (VOID**)&ShellParameters > + ); > + if (EFI_ERROR(Status)) { > + return Status; > + } > + > + Argc =3D ShellParameters->Argc; > + Argv =3D ShellParameters->Argv; > + return EFI_SUCCESS; > +} > + > +/** > + Return File System Volume containing this shell application. > + > + @return File System Volume containing this shell application. > +**/ > +EFI_SIMPLE_FILE_SYSTEM_PROTOCOL * > +GetMyVol ( > + VOID > + ) > +{ > + EFI_STATUS Status; > + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; > + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Vol; > + > + Status =3D gBS->HandleProtocol ( > + gImageHandle, > + &gEfiLoadedImageProtocolGuid, > + (VOID **)&LoadedImage > + ); > + ASSERT_EFI_ERROR (Status); > + > + Status =3D gBS->HandleProtocol ( > + LoadedImage->DeviceHandle, > + &gEfiSimpleFileSystemProtocolGuid, > + (VOID **)&Vol > + ); > + if (!EFI_ERROR (Status)) { > + return Vol; > + } > + > + return NULL; > +} > + > +/** > + Read a file from this volume. > + > + @param Vol File System Volume > + @param FileName The file to be read. > + @param BufferSize The file buffer size > + @param Buffer The file buffer > + > + @retval EFI_SUCCESS Read file successfully > + @retval EFI_NOT_FOUND File not found > +**/ > +EFI_STATUS > +ReadFileFromVol ( > + IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Vol, > + IN CHAR16 *FileName, > + OUT UINTN *BufferSize, > + OUT VOID **Buffer > + ) > +{ > + EFI_STATUS Status; > + EFI_FILE_HANDLE RootDir; > + EFI_FILE_HANDLE Handle; > + UINTN FileInfoSize; > + EFI_FILE_INFO *FileInfo; > + UINTN TempBufferSize; > + VOID *TempBuffer; > + > + // > + // Open the root directory > + // > + Status =3D Vol->OpenVolume (Vol, &RootDir); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + // > + // Open the file > + // > + Status =3D RootDir->Open ( > + RootDir, > + &Handle, > + FileName, > + EFI_FILE_MODE_READ, > + 0 > + ); > + if (EFI_ERROR (Status)) { > + RootDir->Close (RootDir); > + return Status; > + } > + > + RootDir->Close (RootDir); > + > + // > + // Get the file information > + // > + FileInfoSize =3D sizeof(EFI_FILE_INFO) + 1024; > + > + FileInfo =3D AllocateZeroPool (FileInfoSize); > + if (FileInfo =3D=3D NULL) { > + Handle->Close (Handle); > + return Status; > + } > + > + Status =3D Handle->GetInfo ( > + Handle, > + &gEfiFileInfoGuid, > + &FileInfoSize, > + FileInfo > + ); > + if (EFI_ERROR (Status)) { > + Handle->Close (Handle); > + gBS->FreePool (FileInfo); > + return Status; > + } > + > + // > + // Allocate buffer for the file data. The last CHAR16 is for L'\0' > + // > + TempBufferSize =3D (UINTN) FileInfo->FileSize + sizeof(CHAR16); > + TempBuffer =3D AllocateZeroPool (TempBufferSize); > + if (TempBuffer =3D=3D NULL) { > + Handle->Close (Handle); > + gBS->FreePool (FileInfo); > + return Status; > + } > + > + gBS->FreePool (FileInfo); > + > + // > + // Read the file data to the buffer > + // > + Status =3D Handle->Read ( > + Handle, > + &TempBufferSize, > + TempBuffer > + ); > + if (EFI_ERROR (Status)) { > + Handle->Close (Handle); > + gBS->FreePool (TempBuffer); > + return Status; > + } > + > + Handle->Close (Handle); > + > + *BufferSize =3D TempBufferSize; > + *Buffer =3D TempBuffer; > + return EFI_SUCCESS; > +} > + > +/** > + Read a file. > + If ScanFs is FLASE, it will use this Vol as default Fs. > + If ScanFs is TRUE, it will scan all FS and check the file. > + If there is only one file match the name, it will be read. > + If there is more than one file match the name, it will return Error. > + > + @param ThisVol File System Volume > + @param FileName The file to be read. > + @param BufferSize The file buffer size > + @param Buffer The file buffer > + @param ScanFs Need Scan all FS > + > + @retval EFI_SUCCESS Read file successfully > + @retval EFI_NOT_FOUND File not found > + @retval EFI_NO_MAPPING There is duplicated files found > +**/ > +EFI_STATUS > +ReadFileToBufferEx ( > + IN OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL **ThisVol, > + IN CHAR16 *FileName, > + OUT UINTN *BufferSize, > + OUT VOID **Buffer, > + IN BOOLEAN ScanFs > + ) > +{ > + EFI_STATUS Status; > + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Vol; > + UINTN TempBufferSize; > + VOID *TempBuffer; > + UINTN NoHandles; > + EFI_HANDLE *HandleBuffer; > + UINTN Index; > + > + // > + // Check parameters > + // > + if ((FileName =3D=3D NULL) || (Buffer =3D=3D NULL) || (ThisVol =3D=3D = NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // not scan fs > + // > + if (!ScanFs) { > + if (*ThisVol =3D=3D NULL) { > + *ThisVol =3D GetMyVol (); > + if (*ThisVol =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + } > + // > + // Read file directly from Vol > + // > + return ReadFileFromVol (*ThisVol, FileName, BufferSize, Buffer); > + } > + > + // > + // need scan fs > + // > + > + // > + // Get all Vol handle > + // > + Status =3D gBS->LocateHandleBuffer ( > + ByProtocol, > + &gEfiSimpleFileSystemProtocolGuid, > + NULL, > + &NoHandles, > + &HandleBuffer > + ); > + if (EFI_ERROR (Status) && (NoHandles =3D=3D 0)) { > + return EFI_NOT_FOUND; > + } > + > + // > + // Walk through each Vol > + // > + *ThisVol =3D NULL; > + *BufferSize =3D 0; > + *Buffer =3D NULL; > + for (Index =3D 0; Index < NoHandles; Index++) { > + Status =3D gBS->HandleProtocol ( > + HandleBuffer[Index], > + &gEfiSimpleFileSystemProtocolGuid, > + (VOID **)&Vol > + ); > + if (EFI_ERROR(Status)) { > + continue; > + } > + > + Status =3D ReadFileFromVol (Vol, FileName, &TempBufferSize, &TempBuf= fer); > + if (!EFI_ERROR (Status)) { > + // > + // Read file OK, check duplication > + // > + if (*ThisVol !=3D NULL) { > + // > + // Find the duplicated file > + // > + gBS->FreePool (TempBuffer); > + gBS->FreePool (*Buffer); > + Print (L"Duplicated FileName found!\n"); > + return EFI_NO_MAPPING; > + } else { > + // > + // Record value > + // > + *ThisVol =3D Vol; > + *BufferSize =3D TempBufferSize; > + *Buffer =3D TempBuffer; > + } > + } > + } > + > + // > + // Scan Fs done > + // > + if (*ThisVol =3D=3D NULL) { > + return EFI_NOT_FOUND; > + } > + > + // > + // Done > + // > + return EFI_SUCCESS; > +} > + > +/** > + Read a file. > + > + @param FileName The file to be read. > + @param BufferSize The file buffer size > + @param Buffer The file buffer > + > + @retval EFI_SUCCESS Read file successfully > + @retval EFI_NOT_FOUND File not found > +**/ > +EFI_STATUS > +ReadFileToBuffer ( > + IN CHAR16 *FileName, > + OUT UINTN *BufferSize, > + OUT VOID **Buffer > + ) > +{ > + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Vol; > + Vol =3D NULL; > + return ReadFileToBufferEx(&Vol, FileName, BufferSize, Buffer, FALSE); > +} > + > +/** > + Write a file. > + > + @param FileName The file to be written. > + @param BufferSize The file buffer size > + @param Buffer The file buffer > + > + @retval EFI_SUCCESS Write file successfully > +**/ > +EFI_STATUS > +WriteFileFromBuffer( > + IN CHAR16 *FileName, > + IN UINTN BufferSize, > + IN VOID *Buffer > + ) > +{ > + EFI_STATUS Status; > + EFI_FILE_HANDLE RootDir; > + EFI_FILE_HANDLE Handle; > + UINTN TempBufferSize; > + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Vol; > + > + Vol =3D GetMyVol(); > + > + // > + // Open the root directory > + // > + Status =3D Vol->OpenVolume (Vol, &RootDir); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + // > + // Open the file > + // > + Status =3D RootDir->Open ( > + RootDir, > + &Handle, > + FileName, > + EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE| EFI_FILE= _MODE_CREATE, > + 0 > + ); > + if (EFI_ERROR (Status)) { > + RootDir->Close (RootDir); > + return Status; > + } > + > + // > + // Delete file > + // > + Status =3D Handle->Delete(Handle); > + if (EFI_ERROR(Status)) { > + return Status; > + } > + > + // > + // Open the file again > + // > + Status =3D RootDir->Open ( > + RootDir, > + &Handle, > + FileName, > + EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE| EFI_FILE= _MODE_CREATE, > + 0 > + ); > + if (EFI_ERROR (Status)) { > + RootDir->Close (RootDir); > + return Status; > + } > + > + RootDir->Close (RootDir); > + > + // > + // Write the file data from the buffer > + // > + TempBufferSize =3D BufferSize; > + Status =3D Handle->Write ( > + Handle, > + &TempBufferSize, > + Buffer > + ); > + if (EFI_ERROR (Status)) { > + Handle->Close (Handle); > + return Status; > + } > + > + Handle->Close (Handle); > + > + return EFI_SUCCESS; > +} > + > diff --git a/MdeModulePkg/Application/CapsuleApp/CapsuleApp.c > b/MdeModulePkg/Application/CapsuleApp/CapsuleApp.c > new file mode 100644 > index 0000000..6bb778a > --- /dev/null > +++ b/MdeModulePkg/Application/CapsuleApp/CapsuleApp.c > @@ -0,0 +1,853 @@ > +/** @file > + A shell application that triggers capsule update process. > + > + Copyright (c) 2016, Intel Corporation. All rights reserved.
> + This program and the accompanying materials > + are licensed and made available under the terms and conditions of the = BSD License > + which accompanies this distribution. The full text of the license may= be found at > + http://opensource.org/licenses/bsd-license.php > + > + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR I= MPLIED. > + > +**/ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#define CAPSULE_HEADER_SIZE 0x20 > + > +#define NESTED_CAPSULE_HEADER_SIZE SIZE_4KB > +#define SYSTEM_FIRMWARE_FLAG 0x50000 > +#define DEVICE_FIRMWARE_FLAG 0x78010 > + > +#define EFI_CAPSULE_FROM_FILE_DIR L"\\EFI\\Upd= ateCapsule\\" > +#define EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED 0x0000000000= 000004 > + > +#define MAJOR_VERSION 1 > +#define MINOR_VERSION 0 > + > +#define MAX_CAPSULE_NUM 10 > + > +extern UINTN Argc; > +extern CHAR16 **Argv; > + > +// > +// Define how many block descriptors we want to test with. > +// > +UINTN NumberOfDescriptors =3D 1; > +UINTN CapsuleFirstIndex; > +UINTN CapsuleLastIndex; > + > +/** > + Dump capsule information > + > + @retval EFI_SUCCESS The capsule information is dumped. > + @retval EFI_UNSUPPORTED Input parameter is not valid. > +**/ > +EFI_STATUS > +DumpCapsule( > + VOID > + ); > + > +/** > + Dump capsule status variable. > + > + @retval EFI_SUCCESS The capsule status variable is dumped. > + @retval EFI_UNSUPPORTED Input parameter is not valid. > +**/ > +EFI_STATUS > +DmpCapsuleStatusVariable( > + VOID > + ); > + > +/** > + Dump FMP protocol info. > +**/ > +VOID > +DumpFmpData( > + VOID > + ); > + > +/** > + Dump ESRT info. > +**/ > +VOID > +DumpEsrtData( > + VOID > + ); > + > +/** > + Read a file. > + > + @param FileName The file to be read. > + @param BufferSize The file buffer size > + @param Buffer The file buffer > + > + @retval EFI_SUCCESS Read file successfully > + @retval EFI_NOT_FOUND File not found > +**/ > +EFI_STATUS > +ReadFileToBuffer( > + IN CHAR16 *FileName, > + OUT UINTN *BufferSize, > + OUT VOID **Buffer > + ); > + > +/** > + Write a file. > + > + @param FileName The file to be written. > + @param BufferSize The file buffer size > + @param Buffer The file buffer > + > + @retval EFI_SUCCESS Write file successfully > +**/ > +EFI_STATUS > +WriteFileFromBuffer( > + IN CHAR16 *FileName, > + IN UINTN BufferSize, > + IN VOID *Buffer > + ); > + > +/** > + > + This function parse application ARG. > + > + @return Status > +**/ > +EFI_STATUS > +GetArg ( > + VOID > + ); > + > +/** > + Create UX capsule. > + > + @retval EFI_SUCCESS The capsule header is appended. > + @retval EFI_UNSUPPORTED Input parameter is not valid. > + @retval EFI_OUT_OF_RESOURCES No enough resource to create UX capsule= . > +**/ > +EFI_STATUS > +CreateBmpFmp( > + VOID > + ) > +{ > + CHAR16 *OutputCapsuleName; > + VOID *BmpBuffer; > + UINTN FileSize; > + CHAR16 *BmpName; > + UINT8 *FullCapsuleBuffer; > + UINTN FullCapsuleBufferSize; > + EFI_DISPLAY_CAPSULE *DisplayCapsule; > + EFI_STATUS Status; > + EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop; > + > + Status =3D gBS->LocateProtocol(&gEfiGraphicsOutputProtocolGuid, NULL, = (VOID **)&Gop); > + if (EFI_ERROR(Status)) { > + Print(L"CapsuleApp: NO GOP is found.\n"); > + return EFI_UNSUPPORTED; > + } > + Print(L"Current GOP: Mode - %d, ", Gop->Mode->Mode); > + Print(L"HorizontalResolution - %d, ", Gop->Mode->Info->HorizontalResol= ution); > + Print(L"VerticalResolution - %d\n", Gop->Mode->Info->VerticalResolutio= n); > + // HorizontalResolution >=3D BMP_IMAGE_HEADER.PixelWidth > + // VerticalResolution >=3D BMP_IMAGE_HEADER.PixelHeight > + > + if (Argc !=3D 5) { > + Print(L"CapsuleApp: Invalid Parameter.\n"); > + return EFI_UNSUPPORTED; > + } > + > + if (StrCmp(Argv[3], L"-O") !=3D 0) { > + Print(L"CapsuleApp: NO output capsule name.\n"); > + return EFI_UNSUPPORTED; > + } > + OutputCapsuleName =3D Argv[4]; > + > + BmpBuffer =3D NULL; > + FileSize =3D 0; > + FullCapsuleBuffer =3D NULL; > + > + BmpName =3D Argv[2]; > + Status =3D ReadFileToBuffer(BmpName, &FileSize, &BmpBuffer); > + if (EFI_ERROR(Status)) { > + Print(L"CapsuleApp: BMP image (%s) is not found.\n", BmpName); > + goto Done; > + } > + > + FullCapsuleBufferSize =3D sizeof(EFI_DISPLAY_CAPSULE) + FileSize; > + FullCapsuleBuffer =3D AllocatePool(FullCapsuleBufferSize); > + if (FullCapsuleBuffer =3D=3D NULL) { > + Print(L"CapsuleApp: Capsule Buffer size (0x%x) too big.\n", > FullCapsuleBufferSize); > + Status =3D EFI_OUT_OF_RESOURCES; > + goto Done; > + } > + > + DisplayCapsule =3D (EFI_DISPLAY_CAPSULE *)FullCapsuleBuffer; > + CopyGuid(&DisplayCapsule->CapsuleHeader.CapsuleGuid, &gWindowsUxCapsul= eGuid); > + DisplayCapsule->CapsuleHeader.HeaderSize =3D sizeof(DisplayCapsule->Ca= psuleHeader); > + DisplayCapsule->CapsuleHeader.Flags =3D CAPSULE_FLAGS_PERSIST_ACROSS_R= ESET; > + DisplayCapsule->CapsuleHeader.CapsuleImageSize =3D (UINT32)FullCapsule= BufferSize; > + > + DisplayCapsule->ImagePayload.Version =3D 1; > + DisplayCapsule->ImagePayload.Checksum =3D 0; > + DisplayCapsule->ImagePayload.ImageType =3D 0; // BMP > + DisplayCapsule->ImagePayload.Reserved =3D 0; > + DisplayCapsule->ImagePayload.Mode =3D Gop->Mode->Mode; > + DisplayCapsule->ImagePayload.OffsetX =3D 0; > + DisplayCapsule->ImagePayload.OffsetY =3D 0; > + > + CopyMem((DisplayCapsule + 1), BmpBuffer, FileSize); > + > + DisplayCapsule->ImagePayload.Checksum =3D CalculateCheckSum8(FullCapsu= leBuffer, > FullCapsuleBufferSize); > + > + Status =3D WriteFileFromBuffer(OutputCapsuleName, FullCapsuleBufferSiz= e, > FullCapsuleBuffer); > + Print(L"CapsuleApp: Write %s %r\n", OutputCapsuleName, Status); > + > +Done: > + if (BmpBuffer !=3D NULL) { > + FreePool(BmpBuffer); > + } > + > + if (FullCapsuleBuffer !=3D NULL) { > + FreePool(FullCapsuleBuffer); > + } > + > + return Status; > +} > + > +/** > + Get ImageTypeId in the FMP capsule header. > + > + @param CapsuleHeader The FMP capsule image header. > + > + @return ImageTypeId > +**/ > +EFI_GUID * > +GetCapsuleImageTypeId( > + IN EFI_CAPSULE_HEADER *CapsuleHeader > + ) > +{ > + EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader; > + UINT64 *ItemOffsetList; > + EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader; > + > + FmpCapsuleHeader =3D (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8= *)CapsuleHeader > + CapsuleHeader->HeaderSize); > + ItemOffsetList =3D (UINT64 *)(FmpCapsuleHeader + 1); > + if (FmpCapsuleHeader->PayloadItemCount =3D=3D 0) { > + return NULL; > + } > + ImageHeader =3D (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT= 8 > *)FmpCapsuleHeader + ItemOffsetList[FmpCapsuleHeader->EmbeddedDriverCount= ]); > + return &ImageHeader->UpdateImageTypeId; > +} > + > +/** > + Get ESRT FwType according to ImageTypeId > + > + @param ImageTypeId ImageTypeId of an FMP capsule. > + > + @return ESRT FwType > +**/ > +UINT32 > +GetEsrtFwType( > + IN EFI_GUID *ImageTypeId > + ) > +{ > + EFI_STATUS Status; > + EFI_SYSTEM_RESOURCE_TABLE *Esrt; > + EFI_SYSTEM_RESOURCE_ENTRY *EsrtEntry; > + UINTN Index; > + > + // > + // Check ESRT > + // > + Status =3D EfiGetSystemConfigurationTable(&gEfiSystemResourceTableGuid= , (VOID > **)&Esrt); > + if (!EFI_ERROR(Status)) { > + EsrtEntry =3D (VOID *)(Esrt + 1); > + for (Index =3D 0; Index < Esrt->FwResourceCount; Index++, EsrtEntry+= +) { > + if (CompareGuid(&EsrtEntry->FwClass, ImageTypeId)) { > + return EsrtEntry->FwType; > + } > + } > + } > + > + return ESRT_FW_TYPE_UNKNOWN; > +} > + > +/** > + Append a capsule header on top of current image. > + This function follows Windows UEFI Firmware Update Platform document. > + > + @retval EFI_SUCCESS The capsule header is appended. > + @retval EFI_UNSUPPORTED Input parameter is not valid. > + @retval EFI_OUT_OF_RESOURCES No enough resource to append capsule he= ader. > +**/ > +EFI_STATUS > +CreateNestedFmp( > + VOID > + ) > +{ > + CHAR16 *OutputCapsuleName; > + VOID *CapsuleBuffer; > + UINTN FileSize; > + CHAR16 *CapsuleName; > + UINT8 *FullCapsuleBuffer; > + UINTN FullCapsuleBufferSize; > + EFI_CAPSULE_HEADER *NestedCapsuleHeader; > + EFI_GUID *ImageTypeId; > + UINT32 FwType; > + EFI_STATUS Status; > + > + if (Argc !=3D 5) { > + Print(L"CapsuleApp: Invalid Parameter.\n"); > + return EFI_UNSUPPORTED; > + } > + > + if (StrCmp(Argv[3], L"-O") !=3D 0) { > + Print(L"CapsuleApp: NO output capsule name.\n"); > + return EFI_UNSUPPORTED; > + } > + OutputCapsuleName =3D Argv[4]; > + > + CapsuleBuffer =3D NULL; > + FileSize =3D 0; > + FullCapsuleBuffer =3D NULL; > + > + CapsuleName =3D Argv[2]; > + Status =3D ReadFileToBuffer(CapsuleName, &FileSize, &CapsuleBuffer); > + if (EFI_ERROR(Status)) { > + Print(L"CapsuleApp: Capsule image (%s) is not found.\n", CapsuleName= ); > + goto Done; > + } > + > + ImageTypeId =3D GetCapsuleImageTypeId(CapsuleBuffer); > + if (ImageTypeId =3D=3D NULL) { > + Print(L"CapsuleApp: Capsule ImageTypeId is not found.\n"); > + goto Done; > + } > + FwType =3D GetEsrtFwType(ImageTypeId); > + if ((FwType !=3D ESRT_FW_TYPE_SYSTEMFIRMWARE) && (FwType !=3D > ESRT_FW_TYPE_DEVICEFIRMWARE)) { > + Print(L"CapsuleApp: Capsule FwType is invalid.\n"); > + goto Done; > + } > + > + FullCapsuleBufferSize =3D NESTED_CAPSULE_HEADER_SIZE + FileSize; > + FullCapsuleBuffer =3D AllocatePool(FullCapsuleBufferSize); > + if (FullCapsuleBuffer =3D=3D NULL) { > + Print(L"CapsuleApp: Capsule Buffer size (0x%x) too big.\n", > FullCapsuleBufferSize); > + Status =3D EFI_OUT_OF_RESOURCES; > + goto Done; > + } > + > + NestedCapsuleHeader =3D (EFI_CAPSULE_HEADER *)FullCapsuleBuffer; > + ZeroMem(NestedCapsuleHeader, NESTED_CAPSULE_HEADER_SIZE); > + CopyGuid(&NestedCapsuleHeader->CapsuleGuid, ImageTypeId); > + NestedCapsuleHeader->HeaderSize =3D NESTED_CAPSULE_HEADER_SIZE; > + NestedCapsuleHeader->Flags =3D (FwType =3D=3D ESRT_FW_TYPE_DEVICEFIRMW= ARE) ? > SYSTEM_FIRMWARE_FLAG : DEVICE_FIRMWARE_FLAG; > + NestedCapsuleHeader->CapsuleImageSize =3D (UINT32)FullCapsuleBufferSiz= e; > + > + CopyMem((UINT8 *)NestedCapsuleHeader + NestedCapsuleHeader->HeaderSize= , > CapsuleBuffer, FileSize); > + > + Status =3D WriteFileFromBuffer(OutputCapsuleName, FullCapsuleBufferSiz= e, > FullCapsuleBuffer); > + Print(L"CapsuleApp: Write %s %r\n", OutputCapsuleName, Status); > + > +Done: > + if (CapsuleBuffer !=3D NULL) { > + FreePool(CapsuleBuffer); > + } > + > + if (FullCapsuleBuffer !=3D NULL) { > + FreePool(FullCapsuleBuffer); > + } > + > + return Status; > +} > + > + > +/** > + Clear capsule status variable. > + > + @retval EFI_SUCCESS The capsule status variable is cleared. > +**/ > +EFI_STATUS > +ClearCapsuleStatusVariable( > + VOID > + ) > +{ > + EFI_STATUS Status; > + UINT32 Index; > + CHAR16 CapsuleVarName[20]; > + CHAR16 *TempVarName; > + > + StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CapsuleVarName[= 0]), > L"Capsule"); > + TempVarName =3D CapsuleVarName + StrLen (CapsuleVarName); > + Index =3D 0; > + > + while (TRUE) { > + UnicodeSPrint (TempVarName, 5 * sizeof(CHAR16), L"%04x", Index); > + > + Status =3D gRT->SetVariable ( > + CapsuleVarName, > + &gEfiCapsuleReportGuid, > + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACC= ESS | > EFI_VARIABLE_BOOTSERVICE_ACCESS, > + 0, > + (VOID *)NULL > + ); > + if (EFI_ERROR(Status)) { > + // > + // There is no capsule variables, quit > + // > + break; > + } > + > + Index++; > + if (Index > 0xFFFF) { > + break; > + } > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + Build Gather list for a list of capsule images. > + > + @param[in] CapsuleBuffer An array of pointer to capsule images > + @param[in] FileSize An array of UINTN to capsule images size > + @param[in] CapsuleNum The count of capsule images > + @param[out] BlockDescriptors The block descriptors for the capsule ima= ges > + > + @retval EFI_SUCCESS The block descriptors for the capsule images are c= onstructed. > +**/ > +EFI_STATUS > +BuildGatherList( > + IN VOID **CapsuleBuffer, > + IN UINTN *FileSize, > + IN UINTN CapsuleNum, > + OUT EFI_CAPSULE_BLOCK_DESCRIPTOR **BlockDescriptors > + ) > +{ > + EFI_STATUS Status; > + EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors1; > + EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors2; > + EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptorPre; > + EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptorsHeader; > + EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr; > + UINT8 *TempDataPtr; > + UINTN SizeLeft; > + UINTN Size; > + INT32 Count; > + INT32 Number; > + UINTN Index; > + > + TempBlockPtr =3D NULL; > + BlockDescriptors1 =3D NULL; > + BlockDescriptors2 =3D NULL; > + BlockDescriptorPre =3D NULL; > + BlockDescriptorsHeader =3D NULL; > + > + for (Index =3D 0; Index < CapsuleNum; Index++) { > + // > + // Allocate memory for the descriptors. > + // > + if (NumberOfDescriptors =3D=3D 1) { > + Count =3D 2; > + } else { > + Count =3D (INT32)(NumberOfDescriptors + 2) / 2; > + } > + > + Size =3D Count * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR)= ; > + BlockDescriptors1 =3D AllocateRuntimeZeroPool (Size); > + if (BlockDescriptors1 =3D=3D NULL) { > + Print (L"CapsuleApp: failed to allocate memory for descriptors\n")= ; > + Status =3D EFI_OUT_OF_RESOURCES; > + goto ERREXIT; > + } else { > + Print (L"CapsuleApp: creating capsule descriptors at 0x%X\n", (UIN= TN) > BlockDescriptors1); > + Print (L"CapsuleApp: capsule data starts at 0x%X with siz= e 0x%X\n", > (UINTN) CapsuleBuffer, FileSize); > + } > + > + // > + // Record descirptor header > + // > + if (Index =3D=3D 0) { > + BlockDescriptorsHeader =3D BlockDescriptors1; > + } > + > + if (BlockDescriptorPre !=3D NULL) { > + BlockDescriptorPre->Union.ContinuationPointer =3D (UINTN) BlockDes= criptors1; > + BlockDescriptorPre->Length =3D 0; > + } > + > + // > + // Fill them in > + // > + TempBlockPtr =3D BlockDescriptors1; > + TempDataPtr =3D CapsuleBuffer[Index]; > + SizeLeft =3D FileSize[Index]; > + for (Number =3D 0; (Number < Count - 1) && (SizeLeft !=3D 0); Number= ++) { > + // > + // Divide remaining data in half > + // > + if (NumberOfDescriptors !=3D 1) { > + if (SizeLeft =3D=3D 1) { > + Size =3D 1; > + } else { > + Size =3D SizeLeft / 2; > + } > + } else { > + Size =3D SizeLeft; > + } > + TempBlockPtr->Union.DataBlock =3D (UINTN)TempDataPtr; > + TempBlockPtr->Length =3D Size; > + Print (L"CapsuleApp: capsule block/size 0x%X/0x%X\n",= (UINTN) > TempDataPtr, Size); > + SizeLeft -=3D Size; > + TempDataPtr +=3D Size; > + TempBlockPtr++; > + } > + > + // > + // Allocate the second list, point the first block's last entry to p= oint > + // to this one, and fill this one in. Worst case is that the previou= s > + // list only had one element that pointed here, so we need at least = two > + // elements -- one to point to all the data, another to terminate th= e list. > + // > + if ((NumberOfDescriptors !=3D 1) && (SizeLeft !=3D 0)) { > + Count =3D (INT32)(NumberOfDescriptors + 2) - Count; > + if (Count =3D=3D 1) { > + Count++; > + } > + > + Size =3D Count * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR= ); > + BlockDescriptors2 =3D AllocateRuntimeZeroPool (Size); > + if (BlockDescriptors2 =3D=3D NULL) { > + Print (L"CapsuleApp: failed to allocate memory for descriptors\n= "); > + Status =3D EFI_OUT_OF_RESOURCES; > + goto ERREXIT; > + } > + > + // > + // Point the first list's last element to point to this second lis= t. > + // > + TempBlockPtr->Union.ContinuationPointer =3D (UINTN) BlockDescrip= tors2; > + > + TempBlockPtr->Length =3D 0; > + TempBlockPtr =3D BlockDescriptors2; > + for (Number =3D 0; Number < Count - 1; Number++) { > + // > + // If second-to-last one, then dump rest to this element > + // > + if (Number =3D=3D (Count - 2)) { > + Size =3D SizeLeft; > + } else { > + // > + // Divide remaining data in half > + // > + if (SizeLeft =3D=3D 1) { > + Size =3D 1; > + } else { > + Size =3D SizeLeft / 2; > + } > + } > + > + TempBlockPtr->Union.DataBlock =3D (UINTN)TempDataPtr; > + TempBlockPtr->Length =3D Size; > + Print (L"CapsuleApp: capsule block/size 0x%X/0x%X\n= ", (UINTN) > TempDataPtr, Size); > + SizeLeft -=3D Size; > + TempDataPtr +=3D Size; > + TempBlockPtr++; > + if (SizeLeft =3D=3D 0) { > + break; > + } > + } > + } > + > + BlockDescriptorPre =3D TempBlockPtr; > + BlockDescriptors1 =3D NULL; > + } > + > + // > + // Null-terminate. > + // > + if (TempBlockPtr !=3D NULL) { > + TempBlockPtr->Union.ContinuationPointer =3D (UINTN)NULL; > + TempBlockPtr->Length =3D 0; > + *BlockDescriptors =3D BlockDescriptorsHeader; > + } > + > + return EFI_SUCCESS; > + > +ERREXIT: > + if (BlockDescriptors1 !=3D NULL) { > + FreePool(BlockDescriptors1); > + } > + > + if (BlockDescriptors2 !=3D NULL) { > + FreePool(BlockDescriptors2); > + } > + > + return Status; > +} > + > +/** > + Clear the Gather list for a list of capsule images. > + > + @param[in] BlockDescriptors The block descriptors for the capsule ima= ges > + @param[in] CapsuleNum The count of capsule images > +**/ > +VOID > +CleanGatherList( > + IN EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors, > + IN UINTN CapsuleNum > + ) > +{ > + EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr; > + EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr1; > + EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr2; > + UINTN Index; > + > + if (BlockDescriptors !=3D NULL) { > + TempBlockPtr1 =3D BlockDescriptors; > + while (1){ > + TempBlockPtr =3D TempBlockPtr1; > + for (Index =3D 0; Index < CapsuleNum; Index++) { > + if (TempBlockPtr[Index].Length =3D=3D 0) { > + break; > + } > + } > + > + if (TempBlockPtr[Index].Union.ContinuationPointer =3D=3D (UINTN)NU= LL) { > + break; > + } > + > + TempBlockPtr2 =3D (VOID *) ((UINTN) TempBlockPtr->Union.Continuati= onPointer); > + FreePool(TempBlockPtr1); > + TempBlockPtr1 =3D TempBlockPtr2; > + } > + } > +} > + > +/** > + Print APP usage. > +**/ > +VOID > +PrintUsage ( > + VOID > + ) > +{ > + Print(L"CapsuleApp: usage\n"); > + Print(L" CapsuleApp [-NR]\n"); > + Print(L" CapsuleApp -S\n"); > + Print(L" CapsuleApp -C\n"); > + Print(L" CapsuleApp -P\n"); > + Print(L" CapsuleApp -E\n"); > + Print(L" CapsuleApp -G -O \n"); > + Print(L" CapsuleApp -N -O \n"); > + Print(L" CapsuleApp -D|-DS \n"); > + Print(L"Parameter:\n"); > + Print(L" -NR: No Reset.\n"); > + Print(L" -S: Dump capsule status.\n"); > + Print(L" -C: Clear capsule status.\n"); > + Print(L" -P: Dump FMP protocol info.\n"); > + Print(L" -E: Dump ESRT table info.\n"); > + Print(L" -G: Input BMP file name\n"); > + Print(L" -N: Append Capsule Header accroding to Windows Firmware Upd= ate\n"); > + Print(L" -O: Output Capsule file name\n"); > + Print(L" -D: Dump Capsule\n"); > +} > + > +/** > + Update Capsule image. > + > + @param[in] ImageHandle The image handle. > + @param[in] SystemTable The system table. > + > + @retval EFI_SUCCESS Command completed successfully. > + @retval EFI_INVALID_PARAMETER Command usage error. > + @retval EFI_NOT_FOUND The input file can't be found. > +**/ > +EFI_STATUS > +EFIAPI > +UefiMain ( > + IN EFI_HANDLE ImageHandle, > + IN EFI_SYSTEM_TABLE *SystemTable > + ) > +{ > + EFI_STATUS Status; > + UINTN FileSize[MAX_CAPSULE_NUM]; > + VOID *CapsuleBuffer[MAX_CAPSULE_NUM]; > + EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors; > + EFI_CAPSULE_HEADER *CapsuleHeaderArray[MAX_CAPSULE_NUM + 1= ]; > + UINT64 MaxCapsuleSize; > + EFI_RESET_TYPE ResetType; > + BOOLEAN NeedReset; > + BOOLEAN NoReset; > + CHAR16 *CapsuleName; > + UINTN CapsuleNum; > + UINTN Index; > + > + Status =3D GetArg(); > + if (EFI_ERROR(Status)) { > + Print(L"Please use UEFI SHELL to run this application!\n", Status); > + return Status; > + } > + if (Argc < 2) { > + PrintUsage(); > + return EFI_INVALID_PARAMETER; > + } > + if (StrCmp(Argv[1], L"-D") =3D=3D 0) { > + Status =3D DumpCapsule(); > + return Status; > + } > + if (StrCmp(Argv[1], L"-G") =3D=3D 0) { > + Status =3D CreateBmpFmp(); > + return Status; > + } > + if (StrCmp(Argv[1], L"-N") =3D=3D 0) { > + Status =3D CreateNestedFmp(); > + return Status; > + } > + if (StrCmp(Argv[1], L"-S") =3D=3D 0) { > + Status =3D DmpCapsuleStatusVariable(); > + return EFI_SUCCESS; > + } > + if (StrCmp(Argv[1], L"-C") =3D=3D 0) { > + Status =3D ClearCapsuleStatusVariable(); > + return Status; > + } > + if (StrCmp(Argv[1], L"-P") =3D=3D 0) { > + DumpFmpData(); > + return EFI_SUCCESS; > + } > + if (StrCmp(Argv[1], L"-E") =3D=3D 0) { > + DumpEsrtData(); > + return EFI_SUCCESS; > + } > + CapsuleFirstIndex =3D 1; > + if (StrCmp(Argv[Argc - 1], L"-NR") =3D=3D 0) { > + NoReset =3D TRUE; > + CapsuleLastIndex =3D Argc - 2; > + } else { > + NoReset =3D FALSE; > + CapsuleLastIndex =3D Argc - 1; > + } > + CapsuleNum =3D CapsuleLastIndex - CapsuleFirstIndex + 1; > + > + if (CapsuleFirstIndex > CapsuleLastIndex) { > + Print(L"CapsuleApp: NO capsule image.\n"); > + return EFI_UNSUPPORTED; > + } > + if (CapsuleNum > MAX_CAPSULE_NUM) { > + Print(L"CapsuleApp: Too many capsule images.\n"); > + return EFI_UNSUPPORTED; > + } > + > + ZeroMem(&CapsuleBuffer, sizeof(CapsuleBuffer)); > + ZeroMem(&FileSize, sizeof(FileSize)); > + BlockDescriptors =3D NULL; > + > + for (Index =3D 0; Index < CapsuleNum; Index++) { > + CapsuleName =3D Argv[CapsuleFirstIndex + Index]; > + Status =3D ReadFileToBuffer(CapsuleName, &FileSize[Index], &CapsuleB= uffer[Index]); > + if (EFI_ERROR(Status)) { > + Print(L"CapsuleApp: capsule image (%s) is not found.\n", CapsuleNa= me); > + goto Done; > + } > + } > + > + // > + // Every capsule use 2 descriptor 1 for data 1 for end > + // > + Status =3D BuildGatherList(CapsuleBuffer, FileSize, CapsuleNum, &Block= Descriptors); > + if (EFI_ERROR(Status)) { > + goto Done; > + } > + > + // > + // Call the runtime service capsule. > + // > + NeedReset =3D FALSE; > + for (Index =3D 0; Index < CapsuleNum; Index++) { > + CapsuleHeaderArray[Index] =3D (EFI_CAPSULE_HEADER *) CapsuleBuffer[I= ndex]; > + if ((CapsuleHeaderArray[Index]->Flags & CAPSULE_FLAGS_PERSIST_ACROSS= _RESET) !=3D 0) > { > + NeedReset =3D TRUE; > + } > + } > + CapsuleHeaderArray[CapsuleNum] =3D NULL; > + if (NoReset) { > + NeedReset =3D FALSE; > + } > + > + // > + // Inquire platform capability of UpdateCapsule. > + // > + Status =3D gRT->QueryCapsuleCapabilities (CapsuleHeaderArray, CapsuleN= um, > &MaxCapsuleSize, &ResetType); > + if (EFI_ERROR(Status)) { > + Print (L"CapsuleApp: failed to query capsule capability - %r\n", Sta= tus); > + goto Done; > + } > + > + for (Index =3D 0; Index < CapsuleNum; Index++) { > + if (FileSize[Index] > MaxCapsuleSize) { > + Print (L"CapsuleApp: capsule is too large to update, %ld is allowe= d\n", > MaxCapsuleSize); > + Status =3D EFI_UNSUPPORTED; > + goto Done; > + } > + } > + > + // > + // Check whether the input capsule image has the flag of persist acros= s system > reset. > + // > + if (NeedReset) { > + Status =3D gRT->UpdateCapsule(CapsuleHeaderArray,CapsuleNum,(UINTN) > BlockDescriptors); > + if (Status !=3D EFI_SUCCESS) { > + Print (L"CapsuleApp: failed to update capsule - %r\n", Status); > + goto Done; > + } > + // > + // For capsule who has reset flag, after calling UpdateCapsule servi= ce,triger a > + // system reset to process capsule persist across a system reset. > + // > + gRT->ResetSystem (ResetType, EFI_SUCCESS, 0, NULL); > + } else { > + // > + // For capsule who has no reset flag, only call UpdateCapsule Servic= e without a > + // system reset. The service will process the capsule immediately. > + // > + Status =3D gRT->UpdateCapsule (CapsuleHeaderArray,CapsuleNum,(UINTN) > BlockDescriptors); > + if (Status !=3D EFI_SUCCESS) { > + Print (L"CapsuleApp: failed to update capsule - %r\n", Status); > + } > + } > + > + Status =3D EFI_SUCCESS; > + > +Done: > + for (Index =3D 0; Index < CapsuleNum; Index++) { > + if (CapsuleBuffer[Index] !=3D NULL) { > + FreePool (CapsuleBuffer[Index]); > + } > + } > + > + CleanGatherList(BlockDescriptors, CapsuleNum); > + > + return Status; > +} > diff --git a/MdeModulePkg/Application/CapsuleApp/CapsuleApp.inf > b/MdeModulePkg/Application/CapsuleApp/CapsuleApp.inf > new file mode 100644 > index 0000000..2084e5f > --- /dev/null > +++ b/MdeModulePkg/Application/CapsuleApp/CapsuleApp.inf > @@ -0,0 +1,71 @@ > +## @file > +# A shell application that triggers capsule update process. > +# > +# This application can trigger capsule update process. It can also > +# generate capsule image, or dump capsule variable information. > +# > +# Copyright (c) 2016, Intel Corporation. All rights reserved.
> +# This program and the accompanying materials > +# are licensed and made available under the terms and conditions of the= BSD License > +# which accompanies this distribution. The full text of the license ma= y be found at > +# http://opensource.org/licenses/bsd-license.php > +# > +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR = IMPLIED. > +# > +## > + > +[Defines] > + INF_VERSION =3D 0x00010006 > + BASE_NAME =3D CapsuleApp > + MODULE_UNI_FILE =3D CapsuleApp.uni > + FILE_GUID =3D 4CEF31DA-8682-4274-9CC4-AEE7516A5E7= B > + MODULE_TYPE =3D UEFI_APPLICATION > + VERSION_STRING =3D 1.0 > + ENTRY_POINT =3D UefiMain > + > +# > +# The following information is for reference only and not required by th= e build tools. > +# > +# VALID_ARCHITECTURES =3D IA32 X64 > +# > + > +[Sources] > + CapsuleApp.c > + CapsuleDump.c > + AppSupport.c > + > +[Packages] > + MdePkg/MdePkg.dec > + MdeModulePkg/MdeModulePkg.dec > + > +[Guids] > + gEfiFileInfoGuid > + gEfiPartTypeSystemPartGuid > + gEfiGlobalVariableGuid > + gEfiCapsuleReportGuid > + gEfiFmpCapsuleGuid > + gWindowsUxCapsuleGuid > + gEfiCertTypeRsa2048Sha256Guid > + gEfiCertPkcs7Guid > + gEfiSystemResourceTableGuid > + > +[Protocols] > + gEfiLoadedImageProtocolGuid > + gEfiSimpleFileSystemProtocolGuid > + gEfiGraphicsOutputProtocolGuid > + gEfiFirmwareManagementProtocolGuid > + gEfiShellParametersProtocolGuid > + > +[LibraryClasses] > + BaseLib > + UefiApplicationEntryPoint > + DebugLib > + MemoryAllocationLib > + UefiBootServicesTableLib > + UefiRuntimeServicesTableLib > + UefiLib > + PrintLib > + > +[UserExtensions.TianoCore."ExtraFiles"] > + CapsuleAppExtra.uni > diff --git a/MdeModulePkg/Application/CapsuleApp/CapsuleApp.uni > b/MdeModulePkg/Application/CapsuleApp/CapsuleApp.uni > new file mode 100644 > index 0000000..54d6e12 > --- /dev/null > +++ b/MdeModulePkg/Application/CapsuleApp/CapsuleApp.uni > @@ -0,0 +1,22 @@ > +// /** @file > +// A shell application that triggers capsule update process. > +// > +// This application can trigger capsule update process. It can also > +// generate capsule image, or dump capsule variable information. > +// > +// Copyright (c) 2016, Intel Corporation. All rights reserved.
> +// > +// This program and the accompanying materials > +// are licensed and made available under the terms and conditions of the= BSD License > +// which accompanies this distribution. The full text of the license may= be found at > +// http://opensource.org/licenses/bsd-license.php > +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR = IMPLIED. > +// > +// **/ > + > + > +#string STR_MODULE_ABSTRACT #language en-US "A shell applica= tion that > triggers capsule update process." > + > +#string STR_MODULE_DESCRIPTION #language en-US "This applicatio= n can trigger > capsule update process. It can also generate capsule image, or dump capsu= le variable > information." > + > diff --git a/MdeModulePkg/Application/CapsuleApp/CapsuleAppExtra.uni > b/MdeModulePkg/Application/CapsuleApp/CapsuleAppExtra.uni > new file mode 100644 > index 0000000..b5a8840 > --- /dev/null > +++ b/MdeModulePkg/Application/CapsuleApp/CapsuleAppExtra.uni > @@ -0,0 +1,19 @@ > +// /** @file > +// CapsuleApp Localized Strings and Content > +// > +// Copyright (c) 2016, Intel Corporation. All rights reserved.
> +// > +// This program and the accompanying materials > +// are licensed and made available under the terms and conditions of the= BSD License > +// which accompanies this distribution. The full text of the license may= be found at > +// http://opensource.org/licenses/bsd-license.php > +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR = IMPLIED. > +// > +// **/ > + > +#string STR_PROPERTIES_MODULE_NAME > +#language en-US > +"Capsule Application" > + > + > diff --git a/MdeModulePkg/Application/CapsuleApp/CapsuleDump.c > b/MdeModulePkg/Application/CapsuleApp/CapsuleDump.c > new file mode 100644 > index 0000000..b383fe1 > --- /dev/null > +++ b/MdeModulePkg/Application/CapsuleApp/CapsuleDump.c > @@ -0,0 +1,740 @@ > +/** @file > + Dump Capsule image information. > + > + Copyright (c) 2016, Intel Corporation. All rights reserved.
> + This program and the accompanying materials > + are licensed and made available under the terms and conditions of the = BSD License > + which accompanies this distribution. The full text of the license may= be found at > + http://opensource.org/licenses/bsd-license.php > + > + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR I= MPLIED. > + > +**/ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +/** > + Read a file. > + > + @param FileName The file to be read. > + @param BufferSize The file buffer size > + @param Buffer The file buffer > + > + @retval EFI_SUCCESS Read file successfully > + @retval EFI_NOT_FOUND File not found > +**/ > +EFI_STATUS > +ReadFileToBuffer( > + IN CHAR16 *FileName, > + OUT UINTN *BufferSize, > + OUT VOID **Buffer > + ); > + > +extern UINTN Argc; > +extern CHAR16 *Argv[]; > + > +/** > + Dump UX capsule information. > + > + @param CapsuleHeader The UX capsule header > +**/ > +VOID > +DumpUxCapsule( > + IN EFI_CAPSULE_HEADER *CapsuleHeader > + ) > +{ > + EFI_DISPLAY_CAPSULE *DisplayCapsule; > + DisplayCapsule =3D (EFI_DISPLAY_CAPSULE *)CapsuleHeader; > + Print(L"[UxCapusule]\n"); > + Print(L"CapsuleHeader:\n"); > + Print(L" CapsuleGuid - %g\n", &DisplayCapsule->CapsuleHeader.Cap= suleGuid); > + Print(L" HeaderSize - 0x%x\n", DisplayCapsule->CapsuleHeader.He= aderSize); > + Print(L" Flags - 0x%x\n", DisplayCapsule->CapsuleHeader.Fl= ags); > + Print(L" CapsuleImageSize - 0x%x\n", DisplayCapsule- > >CapsuleHeader.CapsuleImageSize); > + Print(L"ImagePayload:\n"); > + Print(L" Version - 0x%x\n", DisplayCapsule->ImagePayload.Ver= sion); > + Print(L" Checksum - 0x%x\n", DisplayCapsule->ImagePayload.Che= cksum); > + Print(L" ImageType - 0x%x\n", DisplayCapsule->ImagePayload.Ima= geType); > + Print(L" Mode - 0x%x\n", DisplayCapsule->ImagePayload.Mod= e); > + Print(L" OffsetX - 0x%x\n", DisplayCapsule->ImagePayload.Off= setX); > + Print(L" OffsetY - 0x%x\n", DisplayCapsule->ImagePayload.Off= setY); > +} > + > +/** > + Dump FMP image authentication information. > + > + @param Image The FMP capsule image > + @param ImageSize The size of the FMP capsule image in bytes. > + > + @return the size of FMP authentication. > +**/ > +UINTN > +DumpImageAuthentication( > + IN VOID *Image, > + IN UINTN ImageSize > + ) > +{ > + EFI_FIRMWARE_IMAGE_AUTHENTICATION *ImageAuthentication; > + > + ImageAuthentication =3D Image; > + if (CompareGuid(&ImageAuthentication->AuthInfo.CertType, &gEfiCertPkcs= 7Guid) || > + CompareGuid(&ImageAuthentication->AuthInfo.CertType, > &gEfiCertTypeRsa2048Sha256Guid)) { > + Print(L"[ImageAuthentication]\n"); > + Print(L" MonotonicCount - 0x%lx\n", ImageAuthentication->Monotoni= cCount); > + Print(L"WIN_CERTIFICATE:\n"); > + Print(L" dwLength - 0x%x\n", ImageAuthentication->AuthInfo.= Hdr.dwLength); > + Print(L" wRevision - 0x%x\n", ImageAuthentication- > >AuthInfo.Hdr.wRevision); > + Print(L" wCertificateType - 0x%x\n", ImageAuthentication- > >AuthInfo.Hdr.wCertificateType); > + Print(L" CertType - %g\n", &ImageAuthentication->AuthInfo.C= ertType); > + return sizeof(ImageAuthentication->MonotonicCount) + ImageAuthentica= tion- > >AuthInfo.Hdr.dwLength; > + } else { > + return 0; > + } > +} > + > +/** > + Dump a non-nested FMP capsule. > + > + @param CapsuleHeader A pointer to CapsuleHeader > +**/ > +VOID > +DumpFmpCapsule( > + IN EFI_CAPSULE_HEADER *CapsuleHeader > + ) > +{ > + EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader; > + UINT64 *ItemOffsetList; > + UINTN Index; > + UINTN Count; > + EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *FmpImageHeader; > + > + Print(L"[FmpCapusule]\n"); > + Print(L"CapsuleHeader:\n"); > + Print(L" CapsuleGuid - %g\n", &CapsuleHeader->CapsuleGuid); > + Print(L" HeaderSize - 0x%x\n", CapsuleHeader->HeaderSize); > + Print(L" Flags - 0x%x\n", CapsuleHeader->Flags); > + Print(L" CapsuleImageSize - 0x%x\n", CapsuleHeader->CapsuleImageSize)= ; > + > + FmpCapsuleHeader =3D (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8= *)CapsuleHeader > + CapsuleHeader->HeaderSize); > + ItemOffsetList =3D (UINT64 *)(FmpCapsuleHeader + 1); > + Print(L"FmpHeader:\n"); > + Print(L" Version - 0x%x\n", FmpCapsuleHeader->Version); > + Print(L" EmbeddedDriverCount - 0x%x\n", FmpCapsuleHeader->EmbeddedDri= verCount); > + Print(L" PayloadItemCount - 0x%x\n", FmpCapsuleHeader->PayloadItem= Count); > + Count =3D FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->Pa= yloadItemCount; > + for (Index =3D 0; Index < Count; Index++) { > + Print(L" Offset[%d] - 0x%x\n", Index, ItemOffsetList[Inde= x]); > + } > + > + for (Index =3D FmpCapsuleHeader->EmbeddedDriverCount; Index < Count; I= ndex++) { > + Print(L"FmpPayload[%d] ImageHeader:\n", Index); > + FmpImageHeader =3D (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)(= (UINT8 > *)FmpCapsuleHeader + ItemOffsetList[Index]); > + Print(L" Version - 0x%x\n", FmpImageHeader->Version)= ; > + Print(L" UpdateImageTypeId - %g\n", &FmpImageHeader->UpdateIma= geTypeId); > + Print(L" UpdateImageIndex - 0x%x\n", FmpImageHeader->UpdateIm= ageIndex); > + Print(L" UpdateImageSize - 0x%x\n", FmpImageHeader->UpdateIm= ageSize); > + Print(L" UpdateVendorCodeSize - 0x%x\n", FmpImageHeader->UpdateVe= ndorCodeSize); > + if (FmpImageHeader->Version >=3D > EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) { > + Print(L" UpdateHardwareInstance - 0x%lx\n", FmpImageHeader- > >UpdateHardwareInstance); > + } > + } > +} > + > +/** > + Return if there is a FMP header below capsule header. > + > + @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER > + > + @retval TRUE There is a FMP header below capsule header. > + @retval FALSE There is not a FMP header below capsule header > +**/ > +BOOLEAN > +IsNestedFmpCapsule( > + IN EFI_CAPSULE_HEADER *CapsuleHeader > + ) > +{ > + EFI_STATUS Status; > + EFI_SYSTEM_RESOURCE_TABLE *Esrt; > + EFI_SYSTEM_RESOURCE_ENTRY *EsrtEntry; > + UINTN Index; > + BOOLEAN EsrtGuidFound; > + EFI_CAPSULE_HEADER *NestedCapsuleHeader; > + UINTN NestedCapsuleSize; > + > + // > + // Check ESRT > + // > + EsrtGuidFound =3D FALSE; > + Status =3D EfiGetSystemConfigurationTable(&gEfiSystemResourceTableGuid= , (VOID > **)&Esrt); > + if (!EFI_ERROR(Status)) { > + EsrtEntry =3D (VOID *)(Esrt + 1); > + for (Index =3D 0; Index < Esrt->FwResourceCount; Index++, EsrtEntry+= +) { > + if (CompareGuid(&EsrtEntry->FwClass, &CapsuleHeader->CapsuleGuid))= { > + EsrtGuidFound =3D TRUE; > + break; > + } > + } > + } > + > + if (!EsrtGuidFound) { > + return FALSE; > + } > + > + // > + // Check nested capsule header > + // FMP GUID after ESRT one > + // > + NestedCapsuleHeader =3D (EFI_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader = + CapsuleHeader- > >HeaderSize); > + NestedCapsuleSize =3D (UINTN)CapsuleHeader + CapsuleHeader->HeaderSize= - > (UINTN)NestedCapsuleHeader; > + if (NestedCapsuleSize < sizeof(EFI_CAPSULE_HEADER)) { > + return FALSE; > + } > + if (!CompareGuid(&NestedCapsuleHeader->CapsuleGuid, &gEfiFmpCapsuleGui= d)) { > + return FALSE; > + } > + return TRUE; > +} > + > +/** > + Dump capsule information > + > + @retval EFI_SUCCESS The capsule information is dumped. > + @retval EFI_UNSUPPORTED Input parameter is not valid. > +**/ > +EFI_STATUS > +DumpCapsule( > + VOID > + ) > +{ > + CHAR16 *CapsuleName; > + VOID *Buffer; > + UINTN FileSize; > + EFI_CAPSULE_HEADER *CapsuleHeader; > + EFI_STATUS Status; > + > + if (Argc !=3D 3) { > + Print(L"CapsuleApp: Invalid Parameter.\n"); > + return EFI_UNSUPPORTED; > + } > + > + CapsuleName =3D Argv[2]; > + Status =3D ReadFileToBuffer(CapsuleName, &FileSize, &Buffer); > + if (EFI_ERROR(Status)) { > + Print(L"CapsuleApp: Capsule (%s) is not found.\n", CapsuleName); > + goto Done; > + } > + > + CapsuleHeader =3D Buffer; > + if (CompareGuid(&CapsuleHeader->CapsuleGuid, &gWindowsUxCapsuleGuid)) = { > + DumpUxCapsule(CapsuleHeader); > + Status =3D EFI_SUCCESS; > + goto Done; > + } > + > + if (CompareGuid(&CapsuleHeader->CapsuleGuid, &gEfiFmpCapsuleGuid)) { > + DumpFmpCapsule(CapsuleHeader); > + } > + if (IsNestedFmpCapsule(CapsuleHeader)) { > + Print(L"[NestedCapusule]\n"); > + Print(L"CapsuleHeader:\n"); > + Print(L" CapsuleGuid - %g\n", &CapsuleHeader->CapsuleGuid); > + Print(L" HeaderSize - 0x%x\n", CapsuleHeader->HeaderSize); > + Print(L" Flags - 0x%x\n", CapsuleHeader->Flags); > + Print(L" CapsuleImageSize - 0x%x\n", CapsuleHeader->CapsuleImageSiz= e); > + DumpFmpCapsule((EFI_CAPSULE_HEADER *)((UINTN)CapsuleHeader + Capsule= Header- > >HeaderSize)); > + } > + > +Done: > + FreePool(Buffer); > + return Status; > +} > + > +/** > + Dump capsule status variable. > + > + @retval EFI_SUCCESS The capsule status variable is dumped. > + @retval EFI_UNSUPPORTED Input parameter is not valid. > +**/ > +EFI_STATUS > +DmpCapsuleStatusVariable( > + VOID > + ) > +{ > + EFI_STATUS Status; > + UINT32 Index; > + CHAR16 CapsuleVarName[20]; > + CHAR16 *TempVarName; > + EFI_CAPSULE_RESULT_VARIABLE_HEADER *CapsuleResult; > + EFI_CAPSULE_RESULT_VARIABLE_FMP *CapsuleResultFmp; > + UINTN CapsuleFileNameSize; > + CHAR16 CapsuleIndexData[12]; > + CHAR16 *CapsuleIndex; > + > + Status =3D GetVariable2( > + L"CapsuleMax", > + &gEfiCapsuleReportGuid, > + (VOID **)&CapsuleIndex, > + NULL > + ); > + if (!EFI_ERROR(Status)) { > + CopyMem(CapsuleIndexData, CapsuleIndex, 11 * sizeof(CHAR16)); > + CapsuleIndexData[11] =3D 0; > + Print(L"CapsuleMax - %s\n", CapsuleIndexData); > + FreePool(CapsuleIndex); > + } > + Status =3D GetVariable2( > + L"CapsuleLast", > + &gEfiCapsuleReportGuid, > + (VOID **)&CapsuleIndex, > + NULL > + ); > + if (!EFI_ERROR(Status)) { > + CopyMem(CapsuleIndexData, CapsuleIndex, 11 * sizeof(CHAR16)); > + CapsuleIndexData[11] =3D 0; > + Print(L"CapsuleLast - %s\n", CapsuleIndexData); > + FreePool(CapsuleIndex); > + } > + > + > + StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CapsuleVarName[= 0]), > L"Capsule"); > + TempVarName =3D CapsuleVarName + StrLen (CapsuleVarName); > + Index =3D 0; > + > + while (TRUE) { > + UnicodeSPrint (TempVarName, 5 * sizeof(CHAR16), L"%04x", Index); > + > + Status =3D GetVariable2 ( > + CapsuleVarName, > + &gEfiCapsuleReportGuid, > + (VOID **) &CapsuleResult, > + NULL > + ); > + if (Status =3D=3D EFI_NOT_FOUND) { > + break; > + } else if (EFI_ERROR(Status)) { > + continue; > + } > + > + // > + // display capsule process status > + // > + if (CapsuleResult->VariableTotalSize >=3D > sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER)) { > + Print (L"CapsuleName: %s\n", CapsuleVarName); > + Print (L" Capsule Guid: %g\n", &CapsuleResult->CapsuleGuid); > + Print (L" Capsule ProcessedTime: %t\n", &CapsuleResult->CapsulePr= ocessed); > + Print (L" Capsule Status: %r\n", CapsuleResult->CapsuleStatus); > + } > + > + if (CompareGuid(&CapsuleResult->CapsuleGuid, &gEfiFmpCapsuleGuid)) { > + if (CapsuleResult->VariableTotalSize >=3D > sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER) + sizeof(EFI_CAPSULE_RESULT_VA= RIABLE_FMP)) { > + CapsuleResultFmp =3D (EFI_CAPSULE_RESULT_VARIABLE_FMP *)(Capsule= Result + 1); > + Print(L" Capsule FMP Version: 0x%x\n", CapsuleResultFmp->Versio= n); > + Print(L" Capsule FMP PayloadIndex: 0x%x\n", CapsuleResultFmp->P= ayloadIndex); > + Print(L" Capsule FMP UpdateImageIndex: 0x%x\n", CapsuleResultFm= p- > >UpdateImageIndex); > + Print(L" Capsule FMP UpdateImageTypeId: %g\n", &CapsuleResultFm= p- > >UpdateImageTypeId); > + if (CapsuleResult->VariableTotalSize > > sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER) + sizeof(EFI_CAPSULE_RESULT_VA= RIABLE_FMP)) { > + Print(L" Capsule FMP CapsuleFileName: %s\n", (CapsuleResultFm= p + 1)); > + CapsuleFileNameSize =3D StrSize((CHAR16 *)(CapsuleResultFmp + = 1)); > + if (CapsuleResult->VariableTotalSize > > sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER) + sizeof(EFI_CAPSULE_RESULT_VA= RIABLE_FMP) + > CapsuleFileNameSize) { > + Print(L" Capsule FMP CapsuleTarget: %s\n", (UINT8 *)(Capsul= eResultFmp + > 1) + CapsuleFileNameSize); > + } > + } > + } > + } > + > + FreePool(CapsuleResult); > + > + Index++; > + if (Index > 0xFFFF) { > + break; > + } > + } > + > + return EFI_SUCCESS; > +} > + > +CHAR8 *mFwTypeString[] =3D { > + "Unknown", > + "SystemFirmware", > + "DeviceFirmware", > + "UefiDriver", > +}; > + > +CHAR8 *mLastAttemptStatusString[] =3D { > + "Success", > + "Error: Unsuccessful", > + "Error: Insufficient Resources", > + "Error: Incorrect Version", > + "Error: Invalid Format", > + "Error: Auth Error", > + "Error: Power Event AC", > + "Error: Power Event Battery", > +}; > + > +/** > + Convert FwType to a string. > + > + @param FwType FwType in ESRT > + > + @return a string for FwType. > +**/ > +CHAR8 * > +FwTypeToString( > + IN UINT32 FwType > + ) > +{ > + if (FwType < sizeof(mFwTypeString) / sizeof(mFwTypeString[0])) { > + return mFwTypeString[FwType]; > + } else { > + return "Invalid"; > + } > +} > + > +/** > + Convert LastAttemptStatus to a string. > + > + @param LastAttemptStatus LastAttemptStatus in FMP or ESRT > + > + @return a string for LastAttemptStatus. > +**/ > +CHAR8 * > +LastAttemptStatusToString( > + IN UINT32 LastAttemptStatus > + ) > +{ > + if (LastAttemptStatus < sizeof(mLastAttemptStatusString) / > sizeof(mLastAttemptStatusString[0])) { > + return mLastAttemptStatusString[LastAttemptStatus]; > + } else { > + return "Error: Unknown"; > + } > +} > + > +/** > + Dump ESRT entry. > + > + @param EsrtEntry ESRT entry > +**/ > +VOID > +DumpEsrtEntry( > + IN EFI_SYSTEM_RESOURCE_ENTRY *EsrtEntry > + ) > +{ > + Print(L" FwClass - %g\n", &EsrtEntry->FwClass); > + Print(L" FwType - 0x%x (%a)\n", EsrtEntry->FwType, > FwTypeToString(EsrtEntry->FwType)); > + Print(L" FwVersion - 0x%x\n", EsrtEntry->FwVersion); > + Print(L" LowestSupportedFwVersion - 0x%x\n", EsrtEntry->LowestSupport= edFwVersion); > + Print(L" CapsuleFlags - 0x%x\n", EsrtEntry->CapsuleFlags)= ; > + Print(L" PERSIST_ACROSS_RESET - 0x%x\n", EsrtEntry->CapsuleFlags = & > CAPSULE_FLAGS_PERSIST_ACROSS_RESET); > + Print(L" POPULATE_SYSTEM_TABLE - 0x%x\n", EsrtEntry->CapsuleFlags = & > CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE); > + Print(L" INITIATE_RESET - 0x%x\n", EsrtEntry->CapsuleFlags = & > CAPSULE_FLAGS_INITIATE_RESET); > + Print(L" LastAttemptVersion - 0x%x\n", EsrtEntry->LastAttemptVe= rsion); > + Print(L" LastAttemptStatus - 0x%x (%a)\n", EsrtEntry->LastAtte= mptStatus, > LastAttemptStatusToString(EsrtEntry->LastAttemptStatus)); > +} > + > +/** > + Dump ESRT table. > + > + @param Esrt ESRT table > +**/ > +VOID > +DumpEsrt( > + IN EFI_SYSTEM_RESOURCE_TABLE *Esrt > + ) > +{ > + UINTN Index; > + EFI_SYSTEM_RESOURCE_ENTRY *EsrtEntry; > + > + Print(L"EFI_SYSTEM_RESOURCE_TABLE:\n"); > + Print(L"FwResourceCount - 0x%x\n", Esrt->FwResourceCount); > + Print(L"FwResourceCountMax - 0x%x\n", Esrt->FwResourceCountMax); > + Print(L"FwResourceVersion - 0x%lx\n", Esrt->FwResourceVersion); > + > + EsrtEntry =3D (VOID *)(Esrt + 1); > + for (Index =3D 0; Index < Esrt->FwResourceCount; Index++) { > + Print(L"EFI_SYSTEM_RESOURCE_ENTRY (%d):\n", Index); > + DumpEsrtEntry(EsrtEntry); > + EsrtEntry++; > + } > +} > + > +/** > + Dump ESRT info. > +**/ > +VOID > +DumpEsrtData ( > + VOID > + ) > +{ > + EFI_STATUS Status; > + EFI_SYSTEM_RESOURCE_TABLE *Esrt; > + > + Print(L"##############\n"); > + Print(L"# ESRT TABLE #\n"); > + Print(L"##############\n"); > + > + Status =3D EfiGetSystemConfigurationTable (&gEfiSystemResourceTableGui= d, (VOID > **)&Esrt); > + if (EFI_ERROR(Status)) { > + Print(L"ESRT - %r\n", Status); > + return; > + } > + DumpEsrt(Esrt); > + Print(L"\n"); > +} > + > +/** > + Dump FMP information. > + > + @param ImageInfoSize The size of ImageInfo, in bytes. > + @param ImageInfo A pointer to EFI_FIRMWARE_IMAGE_DESCRIPTOR. > + @param DescriptorVersion The version of EFI_FIRMWARE_IMAGE_DESCRIPTO= R. > + @param DescriptorCount The count of EFI_FIRMWARE_IMAGE_DESCRIPTOR. > + @param DescriptorSize The size of an individual EFI_FIRMWARE_IMAG= E_DESCRIPTOR, > in bytes. > + @param PackageVersion The version of package. > + @param PackageVersionName The version name of package. > +**/ > +VOID > +DumpFmpImageInfo( > + IN UINTN ImageInfoSize, > + IN EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageInfo, > + IN UINT32 DescriptorVersion, > + IN UINT8 DescriptorCount, > + IN UINTN DescriptorSize, > + IN UINT32 PackageVersion, > + IN CHAR16 *PackageVersionName > + ) > +{ > + EFI_FIRMWARE_IMAGE_DESCRIPTOR *CurrentImageInfo; > + UINTN Index; > + > + Print(L" DescriptorVersion - 0x%x\n", DescriptorVersion); > + Print(L" DescriptorCount - 0x%x\n", DescriptorCount); > + Print(L" DescriptorSize - 0x%x\n", DescriptorSize); > + Print(L" PackageVersion - 0x%x\n", PackageVersion); > + Print(L" PackageVersionName - \"%s\"\n", PackageVersionName); > + CurrentImageInfo =3D ImageInfo; > + for (Index =3D 0; Index < DescriptorCount; Index++) { > + Print(L" ImageDescriptor (%d)\n", Index); > + Print(L" ImageIndex - 0x%x\n", CurrentImageInfo-= >ImageIndex); > + Print(L" ImageTypeId - %g\n", &CurrentImageInfo->= ImageTypeId); > + Print(L" ImageId - 0x%lx\n", CurrentImageInfo= ->ImageId); > + Print(L" ImageIdName - \"%s\"\n", CurrentImageInf= o- > >ImageIdName); > + Print(L" Version - 0x%x\n", CurrentImageInfo-= >Version); > + Print(L" VersionName - \"%s\"\n", CurrentImageInf= o- > >VersionName); > + Print(L" Size - 0x%x\n", CurrentImageInfo-= >Size); > + Print(L" AttributesSupported - 0x%lx\n", CurrentImageInfo= - > >AttributesSupported); > + Print(L" IMAGE_UPDATABLE - 0x%lx\n", CurrentImageInfo= - > >AttributesSupported & IMAGE_ATTRIBUTE_IMAGE_UPDATABLE); > + Print(L" RESET_REQUIRED - 0x%lx\n", CurrentImageInfo= - > >AttributesSupported & IMAGE_ATTRIBUTE_RESET_REQUIRED); > + Print(L" AUTHENTICATION_REQUIRED - 0x%lx\n", CurrentImageInfo= - > >AttributesSupported & IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED); > + Print(L" IN_USE - 0x%lx\n", CurrentImageInfo= - > >AttributesSupported & IMAGE_ATTRIBUTE_IN_USE); > + Print(L" UEFI_IMAGE - 0x%lx\n", CurrentImageInfo= - > >AttributesSupported & IMAGE_ATTRIBUTE_UEFI_IMAGE); > + Print(L" AttributesSetting - 0x%lx\n", CurrentImageInfo= - > >AttributesSetting); > + Print(L" IMAGE_UPDATABLE - 0x%lx\n", CurrentImageInfo= - > >AttributesSetting & IMAGE_ATTRIBUTE_IMAGE_UPDATABLE); > + Print(L" RESET_REQUIRED - 0x%lx\n", CurrentImageInfo= - > >AttributesSetting & IMAGE_ATTRIBUTE_RESET_REQUIRED); > + Print(L" AUTHENTICATION_REQUIRED - 0x%lx\n", CurrentImageInfo= - > >AttributesSetting & IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED); > + Print(L" IN_USE - 0x%lx\n", CurrentImageInfo= - > >AttributesSetting & IMAGE_ATTRIBUTE_IN_USE); > + Print(L" UEFI_IMAGE - 0x%lx\n", CurrentImageInfo= - > >AttributesSetting & IMAGE_ATTRIBUTE_UEFI_IMAGE); > + Print(L" Compatibilities - 0x%lx\n", CurrentImageInfo= - > >Compatibilities); > + Print(L" COMPATIB_CHECK_SUPPORTED - 0x%lx\n", CurrentImageInfo= - > >Compatibilities & IMAGE_COMPATIBILITY_CHECK_SUPPORTED); > + if (DescriptorVersion > 1) { > + Print(L" LowestSupportedImageVersion - 0x%x\n", CurrentImageInf= o- > >LowestSupportedImageVersion); > + if (DescriptorVersion > 2) { > + Print(L" LastAttemptVersion - 0x%x\n", CurrentImageI= nfo- > >LastAttemptVersion); > + Print(L" LastAttemptStatus - 0x%x (%a)\n", CurrentI= mageInfo- > >LastAttemptStatus, LastAttemptStatusToString(CurrentImageInfo->LastAttem= ptStatus)); > + Print(L" HardwareInstance - 0x%lx\n", CurrentImage= Info- > >HardwareInstance); > + } > + } > + // > + // Use DescriptorSize to move ImageInfo Pointer to stay compatible w= ith different > ImageInfo version > + // > + CurrentImageInfo =3D (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)Curr= entImageInfo + > DescriptorSize); > + } > +} > + > +/** > + Dump FMP package information. > + > + @param PackageVersion The version of package. > + @param PackageVersionName The version name of package. > + @param PackageVersionNameMaxLen The maximum length of PackageVersion= Name. > + @param AttributesSupported Package attributes that are supporte= d by this > device. > + @param AttributesSetting Package attributes. > +**/ > +VOID > +DumpFmpPackageInfo( > + IN UINT32 PackageVersion, > + IN CHAR16 *PackageVersionName, > + IN UINT32 PackageVersionNameMaxLen, > + IN UINT64 AttributesSupported, > + IN UINT64 AttributesSetting > + ) > +{ > + Print(L" PackageVersion - 0x%x\n", PackageVersion); > + Print(L" PackageVersionName - \"%s\"\n", PackageVersionName)= ; > + Print(L" PackageVersionNameMaxLen - 0x%x\n", PackageVersionNameMax= Len); > + Print(L" AttributesSupported - 0x%lx\n", AttributesSupported)= ; > + Print(L" IMAGE_UPDATABLE - 0x%lx\n", AttributesSupported = & > IMAGE_ATTRIBUTE_IMAGE_UPDATABLE); > + Print(L" RESET_REQUIRED - 0x%lx\n", AttributesSupported = & > IMAGE_ATTRIBUTE_RESET_REQUIRED); > + Print(L" AUTHENTICATION_REQUIRED - 0x%lx\n", AttributesSupported = & > IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED); > + Print(L" AttributesSetting - 0x%lx\n", AttributesSetting); > + Print(L" IMAGE_UPDATABLE - 0x%lx\n", AttributesSetting & > IMAGE_ATTRIBUTE_IMAGE_UPDATABLE); > + Print(L" RESET_REQUIRED - 0x%lx\n", AttributesSetting & > IMAGE_ATTRIBUTE_RESET_REQUIRED); > + Print(L" AUTHENTICATION_REQUIRED - 0x%lx\n", AttributesSetting & > IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED); > +} > + > +/** > + Dump FMP protocol info. > +**/ > +VOID > +DumpFmpData ( > + VOID > + ) > +{ > + EFI_STATUS Status; > + EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp; > + EFI_HANDLE *HandleBuffer; > + UINTN NumberOfHandles; > + UINTN Index; > + EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf; > + UINTN ImageInfoSize; > + UINT32 FmpImageInfoDescriptorVe= r; > + UINT8 FmpImageInfoCount; > + UINTN DescriptorSize; > + UINT32 PackageVersion; > + CHAR16 *PackageVersionName; > + UINT32 PackageVersionNameMaxLen= ; > + UINT64 AttributesSupported; > + UINT64 AttributesSetting; > + > + Print(L"############\n"); > + Print(L"# FMP DATA #\n"); > + Print(L"############\n"); > + Status =3D gBS->LocateHandleBuffer ( > + ByProtocol, > + &gEfiFirmwareManagementProtocolGuid, > + NULL, > + &NumberOfHandles, > + &HandleBuffer > + ); > + if (EFI_ERROR(Status)) { > + Print(L"FMP protocol - %r\n", EFI_NOT_FOUND); > + return; > + } > + > + for (Index =3D 0; Index < NumberOfHandles; Index++) { > + Status =3D gBS->HandleProtocol( > + HandleBuffer[Index], > + &gEfiFirmwareManagementProtocolGuid, > + (VOID **)&Fmp > + ); > + if (EFI_ERROR(Status)) { > + continue; > + } > + > + ImageInfoSize =3D 0; > + Status =3D Fmp->GetImageInfo ( > + Fmp, > + &ImageInfoSize, > + NULL, > + NULL, > + NULL, > + NULL, > + NULL, > + NULL > + ); > + if (Status !=3D EFI_BUFFER_TOO_SMALL) { > + continue; > + } > + > + FmpImageInfoBuf =3D NULL; > + FmpImageInfoBuf =3D AllocateZeroPool (ImageInfoSize); > + if (FmpImageInfoBuf =3D=3D NULL) { > + Status =3D EFI_OUT_OF_RESOURCES; > + goto EXIT; > + } > + > + PackageVersionName =3D NULL; > + Status =3D Fmp->GetImageInfo ( > + Fmp, > + &ImageInfoSize, // ImageInfoSize > + FmpImageInfoBuf, // ImageInfo > + &FmpImageInfoDescriptorVer, // DescriptorVersion > + &FmpImageInfoCount, // DescriptorCount > + &DescriptorSize, // DescriptorSize > + &PackageVersion, // PackageVersion > + &PackageVersionName // PackageVersionName > + ); > + > + // > + // If FMP GetInformation interface failed, skip this resource > + // > + if (EFI_ERROR(Status)) { > + Print(L"FMP (%d) ImageInfo - %r\n", Index, Status); > + FreePool(FmpImageInfoBuf); > + continue; > + } > + > + Print(L"FMP (%d) ImageInfo:\n", Index); > + DumpFmpImageInfo( > + ImageInfoSize, // ImageInfoSize > + FmpImageInfoBuf, // ImageInfo > + FmpImageInfoDescriptorVer, // DescriptorVersion > + FmpImageInfoCount, // DescriptorCount > + DescriptorSize, // DescriptorSize > + PackageVersion, // PackageVersion > + PackageVersionName // PackageVersionName > + ); > + > + if (PackageVersionName !=3D NULL) { > + FreePool(PackageVersionName); > + } > + FreePool(FmpImageInfoBuf); > + > + // > + // Get package info > + // > + PackageVersionName =3D NULL; > + Status =3D Fmp->GetPackageInfo ( > + Fmp, > + &PackageVersion, // PackageVersion > + &PackageVersionName, // PackageVersionName > + &PackageVersionNameMaxLen, // PackageVersionNameM= axLen > + &AttributesSupported, // AttributesSupported > + &AttributesSetting // AttributesSetting > + ); > + if (EFI_ERROR(Status)) { > + Print(L"FMP (%d) PackageInfo - %r\n", Index, Status); > + } else { > + Print(L"FMP (%d) ImageInfo:\n", Index); > + DumpFmpPackageInfo( > + PackageVersion, // PackageVersion > + PackageVersionName, // PackageVersionName > + PackageVersionNameMaxLen, // PackageVersionNameMaxLen > + AttributesSupported, // AttributesSupported > + AttributesSetting // AttributesSetting > + ); > + > + if (PackageVersionName !=3D NULL) { > + FreePool(PackageVersionName); > + } > + } > + } > + Print(L"\n"); > + > +EXIT: > + FreePool(HandleBuffer); > +} > -- > 2.7.4.windows.1