/** @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
+ Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\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 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
+#include "CapsuleApp.h"\r
\r
//\r
// Define how many block descriptors we want to test with.\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 FMP image data.\r
-\r
- @param[in] ImageTypeId The ImageTypeId of the FMP image.\r
- It is used to identify the FMP protocol.\r
- @param[in] ImageIndex The ImageIndex of the FMP image.\r
- It is the input parameter for FMP->GetImage().\r
- @param[in] ImageName The file name to hold the output FMP image.\r
-**/\r
-VOID\r
-DumpFmpImage (\r
- IN EFI_GUID *ImageTypeId,\r
- IN UINTN ImageIndex,\r
- IN CHAR16 *ImageName\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
- Converts a string to GUID value.\r
- Guid Format is xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\r
-\r
- @param[in] Str The registry format GUID string that contains the GUID value.\r
- @param[out] Guid A pointer to the converted GUID value.\r
-\r
- @retval EFI_SUCCESS The GUID string was successfully converted to the GUID value.\r
- @retval EFI_UNSUPPORTED The input string is not in registry format.\r
- @return others Some error occurred when converting part of GUID value.\r
-\r
-**/\r
-EFI_STATUS\r
-StrToGuid (\r
- IN CHAR16 *Str,\r
- OUT EFI_GUID *Guid\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
EFI_DISPLAY_CAPSULE *DisplayCapsule;\r
EFI_STATUS Status;\r
EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop;\r
+ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;\r
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *GopBlt;\r
+ UINTN GopBltSize;\r
+ UINTN Height;\r
+ UINTN Width;\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
+ Info = Gop->Mode->Info;\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
+ Print(L"HorizontalResolution - %d, ", Info->HorizontalResolution);\r
+ Print(L"VerticalResolution - %d\n", 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
+ Print(L"CapsuleApp: Incorrect parameter count.\n");\r
return EFI_UNSUPPORTED;\r
}\r
\r
goto Done;\r
}\r
\r
+ GopBlt = NULL;\r
+ Status = TranslateBmpToGopBlt (\r
+ BmpBuffer,\r
+ FileSize,\r
+ &GopBlt,\r
+ &GopBltSize,\r
+ &Height,\r
+ &Width\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ Print(L"CapsuleApp: BMP image (%s) is not valid.\n", BmpName);\r
+ goto Done;\r
+ }\r
+ if (GopBlt != NULL) {\r
+ FreePool (GopBlt);\r
+ }\r
+ Print(L"BMP image (%s), Width - %d, Height - %d\n", BmpName, Width, Height);\r
+\r
+ if (Height > Info->VerticalResolution) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ Print(L"CapsuleApp: BMP image (%s) height is larger than current resolution.\n", BmpName);\r
+ goto Done;\r
+ }\r
+ if (Width > Info->HorizontalResolution) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ Print(L"CapsuleApp: BMP image (%s) width is larger than current resolution.\n", BmpName);\r
+ goto Done;\r
+ }\r
+\r
FullCapsuleBufferSize = sizeof(EFI_DISPLAY_CAPSULE) + FileSize;\r
FullCapsuleBuffer = AllocatePool(FullCapsuleBufferSize);\r
if (FullCapsuleBuffer == NULL) {\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
+ //\r
+ // Center the bitmap horizontally\r
+ //\r
+ DisplayCapsule->ImagePayload.OffsetX = (UINT32)((Info->HorizontalResolution - Width) / 2);\r
+\r
+ //\r
+ // Put bitmap 3/4 down the display. If bitmap is too tall, then align bottom\r
+ // of bitmap at bottom of display.\r
+ //\r
+ DisplayCapsule->ImagePayload.OffsetY =\r
+ MIN (\r
+ (UINT32)(Info->VerticalResolution - Height),\r
+ (UINT32)(((3 * Info->VerticalResolution) - (2 * Height)) / 4)\r
+ );\r
+\r
+ Print(L"BMP image (%s), OffsetX - %d, OffsetY - %d\n",\r
+ BmpName,\r
+ DisplayCapsule->ImagePayload.OffsetX,\r
+ DisplayCapsule->ImagePayload.OffsetY\r
+ );\r
\r
CopyMem((DisplayCapsule + 1), BmpBuffer, FileSize);\r
\r
return ESRT_FW_TYPE_UNKNOWN;\r
}\r
\r
+/**\r
+ Validate if it is valid capsule header\r
+\r
+ This function assumes the caller provided correct CapsuleHeader pointer\r
+ and CapsuleSize.\r
+\r
+ This function validates the fields in EFI_CAPSULE_HEADER.\r
+\r
+ @param[in] CapsuleHeader Points to a capsule header.\r
+ @param[in] CapsuleSize Size of the whole capsule image.\r
+\r
+**/\r
+BOOLEAN\r
+IsValidCapsuleHeader (\r
+ IN EFI_CAPSULE_HEADER *CapsuleHeader,\r
+ IN UINT64 CapsuleSize\r
+ )\r
+{\r
+ if (CapsuleSize < sizeof (EFI_CAPSULE_HEADER)) {\r
+ return FALSE;\r
+ }\r
+ if (CapsuleHeader->CapsuleImageSize != CapsuleSize) {\r
+ return FALSE;\r
+ }\r
+ if (CapsuleHeader->HeaderSize > CapsuleHeader->CapsuleImageSize) {\r
+ return FALSE;\r
+ }\r
+ if (CapsuleHeader->HeaderSize < sizeof (EFI_CAPSULE_HEADER)) {\r
+ return FALSE;\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Return if this CapsuleGuid is a FMP capsule GUID or not.\r
+\r
+ @param[in] CapsuleGuid A pointer to EFI_GUID\r
+\r
+ @retval TRUE It is a FMP capsule GUID.\r
+ @retval FALSE It is not a FMP capsule GUID.\r
+**/\r
+BOOLEAN\r
+IsFmpCapsuleGuid (\r
+ IN EFI_GUID *CapsuleGuid\r
+ )\r
+{\r
+ if (CompareGuid(&gEfiFmpCapsuleGuid, CapsuleGuid)) {\r
+ return TRUE;\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
/**\r
Append a capsule header on top of current image.\r
This function follows Windows UEFI Firmware Update Platform document.\r
EFI_STATUS Status;\r
\r
if (Argc != 5) {\r
- Print(L"CapsuleApp: Invalid Parameter.\n");\r
+ Print(L"CapsuleApp: Incorrect parameter count.\n");\r
return EFI_UNSUPPORTED;\r
}\r
\r
Print(L"CapsuleApp: Capsule image (%s) is not found.\n", CapsuleName);\r
goto Done;\r
}\r
+ if (!IsValidCapsuleHeader (CapsuleBuffer, FileSize)) {\r
+ Print(L"CapsuleApp: Capsule image (%s) is not a valid capsule.\n", CapsuleName);\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Done;\r
+ }\r
+\r
+ if (!IsFmpCapsuleGuid (&((EFI_CAPSULE_HEADER *) CapsuleBuffer)->CapsuleGuid)) {\r
+ Print(L"CapsuleApp: Capsule image (%s) is not a FMP capsule.\n", CapsuleName);\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Done;\r
+ }\r
\r
ImageTypeId = GetCapsuleImageTypeId(CapsuleBuffer);\r
if (ImageTypeId == NULL) {\r
Print(L"CapsuleApp: Capsule ImageTypeId is not found.\n");\r
+ Status = EFI_INVALID_PARAMETER;\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
+ Status = EFI_INVALID_PARAMETER;\r
goto Done;\r
}\r
\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->Flags = (FwType == ESRT_FW_TYPE_SYSTEMFIRMWARE) ? SYSTEM_FIRMWARE_FLAG : DEVICE_FIRMWARE_FLAG;\r
NestedCapsuleHeader->CapsuleImageSize = (UINT32)FullCapsuleBufferSize;\r
\r
CopyMem((UINT8 *)NestedCapsuleHeader + NestedCapsuleHeader->HeaderSize, CapsuleBuffer, FileSize);\r
UINT32 Index;\r
CHAR16 CapsuleVarName[20];\r
CHAR16 *TempVarName;\r
+ BOOLEAN Found;\r
\r
StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CapsuleVarName[0]), L"Capsule");\r
TempVarName = CapsuleVarName + StrLen (CapsuleVarName);\r
Index = 0;\r
\r
+ Found = FALSE;\r
while (TRUE) {\r
UnicodeSPrint (TempVarName, 5 * sizeof(CHAR16), L"%04x", Index);\r
\r
0,\r
(VOID *)NULL\r
);\r
- if (EFI_ERROR(Status)) {\r
+ if (Status == EFI_NOT_FOUND) {\r
//\r
- // There is no capsule variables, quit\r
+ // There is no more capsule variables, quit\r
//\r
break;\r
}\r
+ Found = TRUE;\r
+\r
+ Print (L"Clear %s %r\n", CapsuleVarName, Status);\r
\r
Index++;\r
if (Index > 0xFFFF) {\r
}\r
}\r
\r
+ if (!Found) {\r
+ Print (L"No any Capsule#### variable found\n");\r
+ }\r
+\r
return EFI_SUCCESS;\r
}\r
\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
+ Print (L"CapsuleApp: capsule data starts at 0x%X with size 0x%X\n", (UINTN) CapsuleBuffer[Index], FileSize[Index]);\r
}\r
\r
//\r
- // Record descirptor header\r
+ // Record descriptor header\r
//\r
if (Index == 0) {\r
BlockDescriptorsHeader = BlockDescriptors1;\r
break;\r
}\r
\r
- TempBlockPtr2 = (VOID *) ((UINTN) TempBlockPtr->Union.ContinuationPointer);\r
+ TempBlockPtr2 = (VOID *) ((UINTN) TempBlockPtr[Index].Union.ContinuationPointer);\r
FreePool(TempBlockPtr1);\r
TempBlockPtr1 = TempBlockPtr2;\r
}\r
)\r
{\r
Print(L"CapsuleApp: usage\n");\r
- Print(L" CapsuleApp <Capsule...>\n");\r
+ Print(L" CapsuleApp <Capsule...> [-NR] [-OD [FSx]]\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 -L\n");\r
+ Print(L" CapsuleApp -L INFO\n");\r
+ Print(L" CapsuleApp -F\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" CapsuleApp -P GET <ImageTypeId> <Index> -O <FileName>\n");\r
Print(L"Parameter:\n");\r
+ Print(L" -NR: No reset will be triggered for the capsule\n");\r
+ Print(L" with CAPSULE_FLAGS_PERSIST_ACROSS_RESET and without CAPSULE_FLAGS_INITIATE_RESET.\n");\r
+ Print(L" -OD: Delivery of Capsules via file on Mass Storage device.\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" -C: Clear capsule report variable (EFI_CAPSULE_REPORT_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" -P: Dump UEFI FMP protocol info, or get image with specified\n");\r
+ Print(L" ImageTypeId and Index (decimal format) to a file if 'GET'\n");\r
+ Print(L" option is used.\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" -L: Dump provisioned capsule image information.\n");\r
+ Print(L" -F: Dump all EFI System Partition.\n");\r
+ Print(L" -G: Convert a BMP file to be an 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" -N: Append a Capsule Header to an existing FMP capsule image\n");\r
+ Print(L" with its ImageTypeId supported by the system,\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
+ Print(L" -D: Dump Capsule image header information, image payload\n");\r
+ Print(L" information if it is an UX capsule and FMP header\n");\r
+ Print(L" information if it is a FMP capsule.\n");\r
}\r
\r
/**\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_UNSUPPORTED Command usage unsupported.\r
+ @retval EFI_INVALID_PARAMETER Command usage invalid.\r
@retval EFI_NOT_FOUND The input file can't be found.\r
**/\r
EFI_STATUS\r
)\r
{\r
EFI_STATUS Status;\r
- UINTN FileSize[MAX_CAPSULE_NUM];\r
+ RETURN_STATUS RStatus;\r
+ UINTN CapsuleBufferSize[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
+ EFI_CAPSULE_HEADER *CapsuleHeaderArray[MAX_CAPSULE_NUM + 1];\r
+ UINT64 MaxCapsuleSize;\r
+ EFI_RESET_TYPE ResetType;\r
+ BOOLEAN NeedReset;\r
+ BOOLEAN NoReset;\r
+ BOOLEAN CapsuleOnDisk;\r
+ CHAR16 *CapsuleName;\r
+ CHAR16 *CapsuleNames[MAX_CAPSULE_NUM];\r
+ CHAR16 *MapFsStr;\r
+ UINTN CapsuleNum;\r
+ UINTN Index;\r
+ UINTN ParaOdIndex;\r
+ UINTN ParaNrIndex;\r
+ EFI_GUID ImageTypeId;\r
+ UINTN ImageIndex;\r
+\r
+ BlockDescriptors = NULL;\r
+ MapFsStr = NULL;\r
+ CapsuleNum = 0;\r
\r
Status = GetArg();\r
if (EFI_ERROR(Status)) {\r
}\r
if (Argc < 2) {\r
PrintUsage();\r
- return EFI_INVALID_PARAMETER;\r
+ return EFI_UNSUPPORTED;\r
}\r
if (StrCmp(Argv[1], L"-D") == 0) {\r
+ if (Argc != 3) {\r
+ Print(L"CapsuleApp: Incorrect parameter count.\n");\r
+ return EFI_UNSUPPORTED;\r
+ }\r
Status = DumpCapsule(Argv[2]);\r
return Status;\r
}\r
return Status;\r
}\r
if (StrCmp(Argv[1], L"-S") == 0) {\r
- Status = DmpCapsuleStatusVariable();\r
+ Status = DumpCapsuleStatusVariable();\r
return EFI_SUCCESS;\r
}\r
if (StrCmp(Argv[1], L"-C") == 0) {\r
DumpFmpData();\r
}\r
if (Argc >= 3) {\r
- if (StrCmp(Argv[2], L"GET") == 0) {\r
- EFI_GUID ImageTypeId;\r
- UINTN ImageIndex;\r
+ if (StrCmp(Argv[2], L"GET") != 0) {\r
+ Print(L"CapsuleApp: Unrecognized option(%s).\n", Argv[2]);\r
+ return EFI_UNSUPPORTED;\r
+ } else {\r
+ if (Argc != 7) {\r
+ Print(L"CapsuleApp: Incorrect parameter count.\n");\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
//\r
// FMP->GetImage()\r
//\r
- Status = StrToGuid(Argv[3], &ImageTypeId);\r
- if (EFI_ERROR(Status)) {\r
+ RStatus = StrToGuid (Argv[3], &ImageTypeId);\r
+ if (RETURN_ERROR (RStatus) || (Argv[3][GUID_STRING_LENGTH] != L'\0')) {\r
Print (L"Invalid ImageTypeId - %s\n", Argv[3]);\r
- return Status;\r
+ return EFI_INVALID_PARAMETER;\r
}\r
ImageIndex = StrDecimalToUintn(Argv[4]);\r
- if (StrCmp(Argv[5], L"-O") == 0) {\r
- DumpFmpImage(&ImageTypeId, ImageIndex, Argv[6]);\r
+ if (StrCmp(Argv[5], L"-O") != 0) {\r
+ Print(L"CapsuleApp: NO output file name.\n");\r
+ return EFI_UNSUPPORTED;\r
}\r
+ DumpFmpImage(&ImageTypeId, ImageIndex, Argv[6]);\r
}\r
}\r
return EFI_SUCCESS;\r
}\r
+\r
if (StrCmp(Argv[1], L"-E") == 0) {\r
DumpEsrtData();\r
return EFI_SUCCESS;\r
}\r
+\r
+ if (StrCmp(Argv[1], L"-L") == 0) {\r
+ if (Argc >= 3 && StrCmp(Argv[2], L"INFO") == 0) {\r
+ DumpProvisionedCapsule(TRUE);\r
+ } else {\r
+ DumpProvisionedCapsule(FALSE);\r
+ }\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if (StrCmp(Argv[1], L"-F") == 0) {\r
+ DumpAllEfiSysPartition();\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if (Argv[1][0] == L'-') {\r
+ Print(L"CapsuleApp: Unrecognized option(%s).\n", Argv[1]);\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
CapsuleFirstIndex = 1;\r
- CapsuleLastIndex = Argc - 1;\r
+ NoReset = FALSE;\r
+ CapsuleOnDisk = FALSE;\r
+ ParaOdIndex = 0;\r
+ ParaNrIndex = 0;\r
+\r
+ for (Index = 1; Index < Argc; Index++) {\r
+ if (StrCmp(Argv[Index], L"-OD") == 0) {\r
+ ParaOdIndex = Index;\r
+ CapsuleOnDisk = TRUE;\r
+ } else if (StrCmp(Argv[Index], L"-NR") == 0) {\r
+ ParaNrIndex = Index;\r
+ NoReset = TRUE;\r
+ }\r
+ }\r
+\r
+ if (ParaOdIndex > ParaNrIndex) {\r
+ if (ParaNrIndex != 0) {\r
+ CapsuleLastIndex = ParaNrIndex - 1;\r
+ } else {\r
+ CapsuleLastIndex = ParaOdIndex - 1;\r
+ }\r
+\r
+ if (ParaOdIndex == Argc -1) {\r
+ MapFsStr = NULL;\r
+ } else if (ParaOdIndex == Argc - 2) {\r
+ MapFsStr = Argv[Argc-1];\r
+ } else {\r
+ Print (L"CapsuleApp: Cannot specify more than one FS mapping!\n");\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Done;\r
+ }\r
+ } else if (ParaOdIndex < ParaNrIndex) {\r
+ if (ParaOdIndex != 0) {\r
+ CapsuleLastIndex = ParaOdIndex - 1;\r
+ if (ParaOdIndex == ParaNrIndex - 1) {\r
+ MapFsStr = NULL;\r
+ } else if (ParaOdIndex == ParaNrIndex - 2) {\r
+ MapFsStr = Argv[ParaOdIndex + 1];\r
+ } else {\r
+ Print (L"CapsuleApp: Cannot specify more than one FS mapping!\n");\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Done;\r
+ }\r
+ } else {\r
+ CapsuleLastIndex = ParaNrIndex - 1;\r
+ }\r
+ } else {\r
+ CapsuleLastIndex = Argc - 1;\r
+ }\r
+\r
CapsuleNum = CapsuleLastIndex - CapsuleFirstIndex + 1;\r
\r
if (CapsuleFirstIndex > CapsuleLastIndex) {\r
}\r
\r
ZeroMem(&CapsuleBuffer, sizeof(CapsuleBuffer));\r
- ZeroMem(&FileSize, sizeof(FileSize));\r
+ ZeroMem(&CapsuleBufferSize, sizeof(CapsuleBufferSize));\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
+ Status = ReadFileToBuffer(CapsuleName, &CapsuleBufferSize[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
+ if (!IsValidCapsuleHeader (CapsuleBuffer[Index], CapsuleBufferSize[Index])) {\r
+ Print(L"CapsuleApp: Capsule image (%s) is not a valid capsule.\n", CapsuleName);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ CapsuleNames[Index] = CapsuleName;\r
}\r
\r
//\r
// Every capsule use 2 descriptor 1 for data 1 for end\r
//\r
- Status = BuildGatherList(CapsuleBuffer, FileSize, CapsuleNum, &BlockDescriptors);\r
+ Status = BuildGatherList(CapsuleBuffer, CapsuleBufferSize, CapsuleNum, &BlockDescriptors);\r
if (EFI_ERROR(Status)) {\r
goto Done;\r
}\r
}\r
\r
for (Index = 0; Index < CapsuleNum; Index++) {\r
- if (FileSize[Index] > MaxCapsuleSize) {\r
+ if (CapsuleBufferSize[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 is capsule on disk.\r
+ //\r
+ if (CapsuleOnDisk) {\r
+ Status = ProcessCapsuleOnDisk (CapsuleBuffer, CapsuleBufferSize, CapsuleNames, MapFsStr, CapsuleNum);\r
+ if (Status != EFI_SUCCESS) {\r
+ Print (L"CapsuleApp: failed to update capsule - %r\n", Status);\r
+ goto Done;\r
+ } else {\r
+ if (!NoReset) {\r
+ gRT->ResetSystem (ResetType, EFI_SUCCESS, 0, NULL);\r
+ } else {\r
+ goto Done;\r
+ }\r
+ }\r
+ }\r
+\r
//\r
// Check whether the input capsule image has the flag of persist across system reset.\r
//\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
+ // For capsule with CAPSULE_FLAGS_PERSIST_ACROSS_RESET + CAPSULE_FLAGS_INITIATE_RESET,\r
+ // a system reset should have been triggered by gRT->UpdateCapsule() calling above.\r
//\r
- gRT->ResetSystem (ResetType, EFI_SUCCESS, 0, NULL);\r
+ // For capsule with CAPSULE_FLAGS_PERSIST_ACROSS_RESET and without CAPSULE_FLAGS_INITIATE_RESET,\r
+ // check if -NR (no-reset) has been specified or not.\r
+ //\r
+ if (!NoReset) {\r
+ //\r
+ // For capsule who has reset flag and no -NR (no-reset) has been specified, after calling UpdateCapsule service,\r
+ // trigger a system reset to process capsule persist across a system reset.\r
+ //\r
+ gRT->ResetSystem (ResetType, EFI_SUCCESS, 0, NULL);\r
+ }\r
} else {\r
//\r
// For capsule who has no reset flag, only call UpdateCapsule Service without a\r