2 A shell application that triggers capsule update process.
4 Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include <Library/BaseLib.h>
11 #include <Library/DebugLib.h>
12 #include <Library/BaseMemoryLib.h>
13 #include <Library/MemoryAllocationLib.h>
14 #include <Library/UefiBootServicesTableLib.h>
15 #include <Library/UefiRuntimeServicesTableLib.h>
16 #include <Library/UefiLib.h>
17 #include <Library/PrintLib.h>
18 #include <Library/BmpSupportLib.h>
19 #include <Protocol/GraphicsOutput.h>
20 #include <Guid/GlobalVariable.h>
21 #include <Guid/CapsuleReport.h>
22 #include <Guid/SystemResourceTable.h>
23 #include <Guid/FmpCapsule.h>
24 #include <IndustryStandard/WindowsUxCapsule.h>
26 #define CAPSULE_HEADER_SIZE 0x20
28 #define NESTED_CAPSULE_HEADER_SIZE SIZE_4KB
29 #define SYSTEM_FIRMWARE_FLAG 0x50000
30 #define DEVICE_FIRMWARE_FLAG 0x78010
32 #define MAJOR_VERSION 1
33 #define MINOR_VERSION 0
35 #define MAX_CAPSULE_NUM 10
41 // Define how many block descriptors we want to test with.
43 UINTN NumberOfDescriptors
= 1;
44 UINTN CapsuleFirstIndex
;
45 UINTN CapsuleLastIndex
;
48 Dump capsule information
50 @param[in] CapsuleName The name of the capsule image.
52 @retval EFI_SUCCESS The capsule information is dumped.
53 @retval EFI_UNSUPPORTED Input parameter is not valid.
57 IN CHAR16
*CapsuleName
61 Dump capsule status variable.
63 @retval EFI_SUCCESS The capsule status variable is dumped.
64 @retval EFI_UNSUPPORTED Input parameter is not valid.
67 DumpCapsuleStatusVariable (
72 Dump FMP protocol info.
82 @param[in] ImageTypeId The ImageTypeId of the FMP image.
83 It is used to identify the FMP protocol.
84 @param[in] ImageIndex The ImageIndex of the FMP image.
85 It is the input parameter for FMP->GetImage().
86 @param[in] ImageName The file name to hold the output FMP image.
90 IN EFI_GUID
*ImageTypeId
,
104 Dump Provisioned Capsule.
106 @param[in] DumpCapsuleInfo The flag to indicate whether to dump the capsule inforomation.
109 DumpProvisionedCapsule (
110 IN BOOLEAN DumpCapsuleInfo
114 Dump all EFI System Partition.
117 DumpAllEfiSysPartition (
122 Process Capsule On Disk.
124 @param[in] CapsuleBuffer An array of pointer to capsule images
125 @param[in] CapsuleBufferSize An array of UINTN to capsule images size
126 @param[in] FilePath An array of capsule images file path
127 @param[in] Map File system mapping string
128 @param[in] CapsuleNum The count of capsule images
130 @retval EFI_SUCCESS Capsule on disk success.
131 @retval others Capsule on disk fail.
135 ProcessCapsuleOnDisk (
136 IN VOID
**CapsuleBuffer
,
137 IN UINTN
*CapsuleBufferSize
,
138 IN CHAR16
**FilePath
,
146 @param[in] FileName The file to be read.
147 @param[out] BufferSize The file buffer size
148 @param[out] Buffer The file buffer
150 @retval EFI_SUCCESS Read file successfully
151 @retval EFI_NOT_FOUND Shell protocol or file not found
152 @retval others Read file failed
157 OUT UINTN
*BufferSize
,
164 @param[in] FileName The file to be written.
165 @param[in] BufferSize The file buffer size
166 @param[in] Buffer The file buffer
168 @retval EFI_SUCCESS Write file successfully
169 @retval EFI_NOT_FOUND Shell protocol not found
170 @retval others Write file failed
173 WriteFileFromBuffer (
181 This function parse application ARG.
193 @retval EFI_SUCCESS The capsule header is appended.
194 @retval EFI_UNSUPPORTED Input parameter is not valid.
195 @retval EFI_OUT_OF_RESOURCES No enough resource to create UX capsule.
202 CHAR16
*OutputCapsuleName
;
206 UINT8
*FullCapsuleBuffer
;
207 UINTN FullCapsuleBufferSize
;
208 EFI_DISPLAY_CAPSULE
*DisplayCapsule
;
210 EFI_GRAPHICS_OUTPUT_PROTOCOL
*Gop
;
211 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION
*Info
;
212 EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*GopBlt
;
217 Status
= gBS
->LocateProtocol(&gEfiGraphicsOutputProtocolGuid
, NULL
, (VOID
**)&Gop
);
218 if (EFI_ERROR(Status
)) {
219 Print(L
"CapsuleApp: NO GOP is found.\n");
220 return EFI_UNSUPPORTED
;
222 Info
= Gop
->Mode
->Info
;
223 Print(L
"Current GOP: Mode - %d, ", Gop
->Mode
->Mode
);
224 Print(L
"HorizontalResolution - %d, ", Info
->HorizontalResolution
);
225 Print(L
"VerticalResolution - %d\n", Info
->VerticalResolution
);
226 // HorizontalResolution >= BMP_IMAGE_HEADER.PixelWidth
227 // VerticalResolution >= BMP_IMAGE_HEADER.PixelHeight
230 Print(L
"CapsuleApp: Incorrect parameter count.\n");
231 return EFI_UNSUPPORTED
;
234 if (StrCmp(Argv
[3], L
"-O") != 0) {
235 Print(L
"CapsuleApp: NO output capsule name.\n");
236 return EFI_UNSUPPORTED
;
238 OutputCapsuleName
= Argv
[4];
242 FullCapsuleBuffer
= NULL
;
245 Status
= ReadFileToBuffer(BmpName
, &FileSize
, &BmpBuffer
);
246 if (EFI_ERROR(Status
)) {
247 Print(L
"CapsuleApp: BMP image (%s) is not found.\n", BmpName
);
252 Status
= TranslateBmpToGopBlt (
260 if (EFI_ERROR(Status
)) {
261 Print(L
"CapsuleApp: BMP image (%s) is not valid.\n", BmpName
);
264 if (GopBlt
!= NULL
) {
267 Print(L
"BMP image (%s), Width - %d, Height - %d\n", BmpName
, Width
, Height
);
269 if (Height
> Info
->VerticalResolution
) {
270 Status
= EFI_INVALID_PARAMETER
;
271 Print(L
"CapsuleApp: BMP image (%s) height is larger than current resolution.\n", BmpName
);
274 if (Width
> Info
->HorizontalResolution
) {
275 Status
= EFI_INVALID_PARAMETER
;
276 Print(L
"CapsuleApp: BMP image (%s) width is larger than current resolution.\n", BmpName
);
280 FullCapsuleBufferSize
= sizeof(EFI_DISPLAY_CAPSULE
) + FileSize
;
281 FullCapsuleBuffer
= AllocatePool(FullCapsuleBufferSize
);
282 if (FullCapsuleBuffer
== NULL
) {
283 Print(L
"CapsuleApp: Capsule Buffer size (0x%x) too big.\n", FullCapsuleBufferSize
);
284 Status
= EFI_OUT_OF_RESOURCES
;
288 DisplayCapsule
= (EFI_DISPLAY_CAPSULE
*)FullCapsuleBuffer
;
289 CopyGuid(&DisplayCapsule
->CapsuleHeader
.CapsuleGuid
, &gWindowsUxCapsuleGuid
);
290 DisplayCapsule
->CapsuleHeader
.HeaderSize
= sizeof(DisplayCapsule
->CapsuleHeader
);
291 DisplayCapsule
->CapsuleHeader
.Flags
= CAPSULE_FLAGS_PERSIST_ACROSS_RESET
;
292 DisplayCapsule
->CapsuleHeader
.CapsuleImageSize
= (UINT32
)FullCapsuleBufferSize
;
294 DisplayCapsule
->ImagePayload
.Version
= 1;
295 DisplayCapsule
->ImagePayload
.Checksum
= 0;
296 DisplayCapsule
->ImagePayload
.ImageType
= 0; // BMP
297 DisplayCapsule
->ImagePayload
.Reserved
= 0;
298 DisplayCapsule
->ImagePayload
.Mode
= Gop
->Mode
->Mode
;
301 // Center the bitmap horizontally
303 DisplayCapsule
->ImagePayload
.OffsetX
= (UINT32
)((Info
->HorizontalResolution
- Width
) / 2);
306 // Put bitmap 3/4 down the display. If bitmap is too tall, then align bottom
307 // of bitmap at bottom of display.
309 DisplayCapsule
->ImagePayload
.OffsetY
=
311 (UINT32
)(Info
->VerticalResolution
- Height
),
312 (UINT32
)(((3 * Info
->VerticalResolution
) - (2 * Height
)) / 4)
315 Print(L
"BMP image (%s), OffsetX - %d, OffsetY - %d\n",
317 DisplayCapsule
->ImagePayload
.OffsetX
,
318 DisplayCapsule
->ImagePayload
.OffsetY
321 CopyMem((DisplayCapsule
+ 1), BmpBuffer
, FileSize
);
323 DisplayCapsule
->ImagePayload
.Checksum
= CalculateCheckSum8(FullCapsuleBuffer
, FullCapsuleBufferSize
);
325 Status
= WriteFileFromBuffer(OutputCapsuleName
, FullCapsuleBufferSize
, FullCapsuleBuffer
);
326 Print(L
"CapsuleApp: Write %s %r\n", OutputCapsuleName
, Status
);
329 if (BmpBuffer
!= NULL
) {
333 if (FullCapsuleBuffer
!= NULL
) {
334 FreePool(FullCapsuleBuffer
);
341 Get ImageTypeId in the FMP capsule header.
343 @param[in] CapsuleHeader The FMP capsule image header.
348 GetCapsuleImageTypeId (
349 IN EFI_CAPSULE_HEADER
*CapsuleHeader
352 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
*FmpCapsuleHeader
;
353 UINT64
*ItemOffsetList
;
354 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
*ImageHeader
;
356 FmpCapsuleHeader
= (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
*)((UINT8
*)CapsuleHeader
+ CapsuleHeader
->HeaderSize
);
357 ItemOffsetList
= (UINT64
*)(FmpCapsuleHeader
+ 1);
358 if (FmpCapsuleHeader
->PayloadItemCount
== 0) {
361 ImageHeader
= (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
*)((UINT8
*)FmpCapsuleHeader
+ ItemOffsetList
[FmpCapsuleHeader
->EmbeddedDriverCount
]);
362 return &ImageHeader
->UpdateImageTypeId
;
366 Get ESRT FwType according to ImageTypeId
368 @param[in] ImageTypeId ImageTypeId of an FMP capsule.
374 IN EFI_GUID
*ImageTypeId
378 EFI_SYSTEM_RESOURCE_TABLE
*Esrt
;
379 EFI_SYSTEM_RESOURCE_ENTRY
*EsrtEntry
;
385 Status
= EfiGetSystemConfigurationTable(&gEfiSystemResourceTableGuid
, (VOID
**)&Esrt
);
386 if (!EFI_ERROR(Status
)) {
387 ASSERT(Esrt
!= NULL
);
388 EsrtEntry
= (VOID
*)(Esrt
+ 1);
389 for (Index
= 0; Index
< Esrt
->FwResourceCount
; Index
++, EsrtEntry
++) {
390 if (CompareGuid(&EsrtEntry
->FwClass
, ImageTypeId
)) {
391 return EsrtEntry
->FwType
;
396 return ESRT_FW_TYPE_UNKNOWN
;
400 Validate if it is valid capsule header
402 This function assumes the caller provided correct CapsuleHeader pointer
405 This function validates the fields in EFI_CAPSULE_HEADER.
407 @param[in] CapsuleHeader Points to a capsule header.
408 @param[in] CapsuleSize Size of the whole capsule image.
412 IsValidCapsuleHeader (
413 IN EFI_CAPSULE_HEADER
*CapsuleHeader
,
414 IN UINT64 CapsuleSize
417 if (CapsuleSize
< sizeof (EFI_CAPSULE_HEADER
)) {
420 if (CapsuleHeader
->CapsuleImageSize
!= CapsuleSize
) {
423 if (CapsuleHeader
->HeaderSize
> CapsuleHeader
->CapsuleImageSize
) {
426 if (CapsuleHeader
->HeaderSize
< sizeof (EFI_CAPSULE_HEADER
)) {
434 Return if this CapsuleGuid is a FMP capsule GUID or not.
436 @param[in] CapsuleGuid A pointer to EFI_GUID
438 @retval TRUE It is a FMP capsule GUID.
439 @retval FALSE It is not a FMP capsule GUID.
443 IN EFI_GUID
*CapsuleGuid
446 if (CompareGuid(&gEfiFmpCapsuleGuid
, CapsuleGuid
)) {
454 Append a capsule header on top of current image.
455 This function follows Windows UEFI Firmware Update Platform document.
457 @retval EFI_SUCCESS The capsule header is appended.
458 @retval EFI_UNSUPPORTED Input parameter is not valid.
459 @retval EFI_OUT_OF_RESOURCES No enough resource to append capsule header.
466 CHAR16
*OutputCapsuleName
;
470 UINT8
*FullCapsuleBuffer
;
471 UINTN FullCapsuleBufferSize
;
472 EFI_CAPSULE_HEADER
*NestedCapsuleHeader
;
473 EFI_GUID
*ImageTypeId
;
478 Print(L
"CapsuleApp: Incorrect parameter count.\n");
479 return EFI_UNSUPPORTED
;
482 if (StrCmp(Argv
[3], L
"-O") != 0) {
483 Print(L
"CapsuleApp: NO output capsule name.\n");
484 return EFI_UNSUPPORTED
;
486 OutputCapsuleName
= Argv
[4];
488 CapsuleBuffer
= NULL
;
490 FullCapsuleBuffer
= NULL
;
492 CapsuleName
= Argv
[2];
493 Status
= ReadFileToBuffer(CapsuleName
, &FileSize
, &CapsuleBuffer
);
494 if (EFI_ERROR(Status
)) {
495 Print(L
"CapsuleApp: Capsule image (%s) is not found.\n", CapsuleName
);
498 if (!IsValidCapsuleHeader (CapsuleBuffer
, FileSize
)) {
499 Print(L
"CapsuleApp: Capsule image (%s) is not a valid capsule.\n", CapsuleName
);
500 Status
= EFI_INVALID_PARAMETER
;
504 if (!IsFmpCapsuleGuid (&((EFI_CAPSULE_HEADER
*) CapsuleBuffer
)->CapsuleGuid
)) {
505 Print(L
"CapsuleApp: Capsule image (%s) is not a FMP capsule.\n", CapsuleName
);
506 Status
= EFI_INVALID_PARAMETER
;
510 ImageTypeId
= GetCapsuleImageTypeId(CapsuleBuffer
);
511 if (ImageTypeId
== NULL
) {
512 Print(L
"CapsuleApp: Capsule ImageTypeId is not found.\n");
513 Status
= EFI_INVALID_PARAMETER
;
516 FwType
= GetEsrtFwType(ImageTypeId
);
517 if ((FwType
!= ESRT_FW_TYPE_SYSTEMFIRMWARE
) && (FwType
!= ESRT_FW_TYPE_DEVICEFIRMWARE
)) {
518 Print(L
"CapsuleApp: Capsule FwType is invalid.\n");
519 Status
= EFI_INVALID_PARAMETER
;
523 FullCapsuleBufferSize
= NESTED_CAPSULE_HEADER_SIZE
+ FileSize
;
524 FullCapsuleBuffer
= AllocatePool(FullCapsuleBufferSize
);
525 if (FullCapsuleBuffer
== NULL
) {
526 Print(L
"CapsuleApp: Capsule Buffer size (0x%x) too big.\n", FullCapsuleBufferSize
);
527 Status
= EFI_OUT_OF_RESOURCES
;
531 NestedCapsuleHeader
= (EFI_CAPSULE_HEADER
*)FullCapsuleBuffer
;
532 ZeroMem(NestedCapsuleHeader
, NESTED_CAPSULE_HEADER_SIZE
);
533 CopyGuid(&NestedCapsuleHeader
->CapsuleGuid
, ImageTypeId
);
534 NestedCapsuleHeader
->HeaderSize
= NESTED_CAPSULE_HEADER_SIZE
;
535 NestedCapsuleHeader
->Flags
= (FwType
== ESRT_FW_TYPE_SYSTEMFIRMWARE
) ? SYSTEM_FIRMWARE_FLAG
: DEVICE_FIRMWARE_FLAG
;
536 NestedCapsuleHeader
->CapsuleImageSize
= (UINT32
)FullCapsuleBufferSize
;
538 CopyMem((UINT8
*)NestedCapsuleHeader
+ NestedCapsuleHeader
->HeaderSize
, CapsuleBuffer
, FileSize
);
540 Status
= WriteFileFromBuffer(OutputCapsuleName
, FullCapsuleBufferSize
, FullCapsuleBuffer
);
541 Print(L
"CapsuleApp: Write %s %r\n", OutputCapsuleName
, Status
);
544 if (CapsuleBuffer
!= NULL
) {
545 FreePool(CapsuleBuffer
);
548 if (FullCapsuleBuffer
!= NULL
) {
549 FreePool(FullCapsuleBuffer
);
557 Clear capsule status variable.
559 @retval EFI_SUCCESS The capsule status variable is cleared.
562 ClearCapsuleStatusVariable (
568 CHAR16 CapsuleVarName
[20];
572 StrCpyS (CapsuleVarName
, sizeof(CapsuleVarName
)/sizeof(CapsuleVarName
[0]), L
"Capsule");
573 TempVarName
= CapsuleVarName
+ StrLen (CapsuleVarName
);
578 UnicodeSPrint (TempVarName
, 5 * sizeof(CHAR16
), L
"%04x", Index
);
580 Status
= gRT
->SetVariable (
582 &gEfiCapsuleReportGuid
,
583 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
,
587 if (Status
== EFI_NOT_FOUND
) {
589 // There is no more capsule variables, quit
595 Print (L
"Clear %s %r\n", CapsuleVarName
, Status
);
598 if (Index
> 0xFFFF) {
604 Print (L
"No any Capsule#### variable found\n");
611 Build Gather list for a list of capsule images.
613 @param[in] CapsuleBuffer An array of pointer to capsule images
614 @param[in] FileSize An array of UINTN to capsule images size
615 @param[in] CapsuleNum The count of capsule images
616 @param[out] BlockDescriptors The block descriptors for the capsule images
618 @retval EFI_SUCCESS The block descriptors for the capsule images are constructed.
622 IN VOID
**CapsuleBuffer
,
625 OUT EFI_CAPSULE_BLOCK_DESCRIPTOR
**BlockDescriptors
629 EFI_CAPSULE_BLOCK_DESCRIPTOR
*BlockDescriptors1
;
630 EFI_CAPSULE_BLOCK_DESCRIPTOR
*BlockDescriptors2
;
631 EFI_CAPSULE_BLOCK_DESCRIPTOR
*BlockDescriptorPre
;
632 EFI_CAPSULE_BLOCK_DESCRIPTOR
*BlockDescriptorsHeader
;
633 EFI_CAPSULE_BLOCK_DESCRIPTOR
*TempBlockPtr
;
642 BlockDescriptors1
= NULL
;
643 BlockDescriptors2
= NULL
;
644 BlockDescriptorPre
= NULL
;
645 BlockDescriptorsHeader
= NULL
;
647 for (Index
= 0; Index
< CapsuleNum
; Index
++) {
649 // Allocate memory for the descriptors.
651 if (NumberOfDescriptors
== 1) {
654 Count
= (INT32
)(NumberOfDescriptors
+ 2) / 2;
657 Size
= Count
* sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR
);
658 BlockDescriptors1
= AllocateRuntimeZeroPool (Size
);
659 if (BlockDescriptors1
== NULL
) {
660 Print (L
"CapsuleApp: failed to allocate memory for descriptors\n");
661 Status
= EFI_OUT_OF_RESOURCES
;
664 Print (L
"CapsuleApp: creating capsule descriptors at 0x%X\n", (UINTN
) BlockDescriptors1
);
665 Print (L
"CapsuleApp: capsule data starts at 0x%X with size 0x%X\n", (UINTN
) CapsuleBuffer
[Index
], FileSize
[Index
]);
669 // Record descirptor header
672 BlockDescriptorsHeader
= BlockDescriptors1
;
675 if (BlockDescriptorPre
!= NULL
) {
676 BlockDescriptorPre
->Union
.ContinuationPointer
= (UINTN
) BlockDescriptors1
;
677 BlockDescriptorPre
->Length
= 0;
683 TempBlockPtr
= BlockDescriptors1
;
684 TempDataPtr
= CapsuleBuffer
[Index
];
685 SizeLeft
= FileSize
[Index
];
686 for (Number
= 0; (Number
< Count
- 1) && (SizeLeft
!= 0); Number
++) {
688 // Divide remaining data in half
690 if (NumberOfDescriptors
!= 1) {
699 TempBlockPtr
->Union
.DataBlock
= (UINTN
)TempDataPtr
;
700 TempBlockPtr
->Length
= Size
;
701 Print (L
"CapsuleApp: capsule block/size 0x%X/0x%X\n", (UINTN
) TempDataPtr
, Size
);
708 // Allocate the second list, point the first block's last entry to point
709 // to this one, and fill this one in. Worst case is that the previous
710 // list only had one element that pointed here, so we need at least two
711 // elements -- one to point to all the data, another to terminate the list.
713 if ((NumberOfDescriptors
!= 1) && (SizeLeft
!= 0)) {
714 Count
= (INT32
)(NumberOfDescriptors
+ 2) - Count
;
719 Size
= Count
* sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR
);
720 BlockDescriptors2
= AllocateRuntimeZeroPool (Size
);
721 if (BlockDescriptors2
== NULL
) {
722 Print (L
"CapsuleApp: failed to allocate memory for descriptors\n");
723 Status
= EFI_OUT_OF_RESOURCES
;
728 // Point the first list's last element to point to this second list.
730 TempBlockPtr
->Union
.ContinuationPointer
= (UINTN
) BlockDescriptors2
;
732 TempBlockPtr
->Length
= 0;
733 TempBlockPtr
= BlockDescriptors2
;
734 for (Number
= 0; Number
< Count
- 1; Number
++) {
736 // If second-to-last one, then dump rest to this element
738 if (Number
== (Count
- 2)) {
742 // Divide remaining data in half
751 TempBlockPtr
->Union
.DataBlock
= (UINTN
)TempDataPtr
;
752 TempBlockPtr
->Length
= Size
;
753 Print (L
"CapsuleApp: capsule block/size 0x%X/0x%X\n", (UINTN
) TempDataPtr
, Size
);
763 BlockDescriptorPre
= TempBlockPtr
;
764 BlockDescriptors1
= NULL
;
770 if (TempBlockPtr
!= NULL
) {
771 TempBlockPtr
->Union
.ContinuationPointer
= (UINTN
)NULL
;
772 TempBlockPtr
->Length
= 0;
773 *BlockDescriptors
= BlockDescriptorsHeader
;
779 if (BlockDescriptors1
!= NULL
) {
780 FreePool(BlockDescriptors1
);
783 if (BlockDescriptors2
!= NULL
) {
784 FreePool(BlockDescriptors2
);
791 Clear the Gather list for a list of capsule images.
793 @param[in] BlockDescriptors The block descriptors for the capsule images
794 @param[in] CapsuleNum The count of capsule images
798 IN EFI_CAPSULE_BLOCK_DESCRIPTOR
*BlockDescriptors
,
802 EFI_CAPSULE_BLOCK_DESCRIPTOR
*TempBlockPtr
;
803 EFI_CAPSULE_BLOCK_DESCRIPTOR
*TempBlockPtr1
;
804 EFI_CAPSULE_BLOCK_DESCRIPTOR
*TempBlockPtr2
;
807 if (BlockDescriptors
!= NULL
) {
808 TempBlockPtr1
= BlockDescriptors
;
810 TempBlockPtr
= TempBlockPtr1
;
811 for (Index
= 0; Index
< CapsuleNum
; Index
++) {
812 if (TempBlockPtr
[Index
].Length
== 0) {
817 if (TempBlockPtr
[Index
].Union
.ContinuationPointer
== (UINTN
)NULL
) {
821 TempBlockPtr2
= (VOID
*) ((UINTN
) TempBlockPtr
[Index
].Union
.ContinuationPointer
);
822 FreePool(TempBlockPtr1
);
823 TempBlockPtr1
= TempBlockPtr2
;
836 Print(L
"CapsuleApp: usage\n");
837 Print(L
" CapsuleApp <Capsule...> [-NR] [-OD [FSx]]\n");
838 Print(L
" CapsuleApp -S\n");
839 Print(L
" CapsuleApp -C\n");
840 Print(L
" CapsuleApp -P\n");
841 Print(L
" CapsuleApp -E\n");
842 Print(L
" CapsuleApp -L\n");
843 Print(L
" CapsuleApp -L INFO\n");
844 Print(L
" CapsuleApp -F\n");
845 Print(L
" CapsuleApp -G <BMP> -O <Capsule>\n");
846 Print(L
" CapsuleApp -N <Capsule> -O <NestedCapsule>\n");
847 Print(L
" CapsuleApp -D <Capsule>\n");
848 Print(L
" CapsuleApp -P GET <ImageTypeId> <Index> -O <FileName>\n");
849 Print(L
"Parameter:\n");
850 Print(L
" -NR: No reset will be triggered for the capsule\n");
851 Print(L
" with CAPSULE_FLAGS_PERSIST_ACROSS_RESET and without CAPSULE_FLAGS_INITIATE_RESET.\n");
852 Print(L
" -OD: Delivery of Capsules via file on Mass Storage device.");
853 Print(L
" -S: Dump capsule report variable (EFI_CAPSULE_REPORT_GUID),\n");
854 Print(L
" which is defined in UEFI specification.\n");
855 Print(L
" -C: Clear capsule report variable (EFI_CAPSULE_REPORT_GUID),\n");
856 Print(L
" which is defined in UEFI specification.\n");
857 Print(L
" -P: Dump UEFI FMP protocol info, or get image with specified\n");
858 Print(L
" ImageTypeId and Index (decimal format) to a file if 'GET'\n");
859 Print(L
" option is used.\n");
860 Print(L
" -E: Dump UEFI ESRT table info.\n");
861 Print(L
" -L: Dump provisioned capsule image information.\n");
862 Print(L
" -F: Dump all EFI System Partition.\n");
863 Print(L
" -G: Convert a BMP file to be an UX capsule,\n");
864 Print(L
" according to Windows Firmware Update document\n");
865 Print(L
" -N: Append a Capsule Header to an existing FMP capsule image\n");
866 Print(L
" with its ImageTypeId supported by the system,\n");
867 Print(L
" according to Windows Firmware Update document\n");
868 Print(L
" -O: Output new Capsule file name\n");
869 Print(L
" -D: Dump Capsule image header information, image payload\n");
870 Print(L
" information if it is an UX capsule and FMP header\n");
871 Print(L
" information if it is a FMP capsule.\n");
875 Update Capsule image.
877 @param[in] ImageHandle The image handle.
878 @param[in] SystemTable The system table.
880 @retval EFI_SUCCESS Command completed successfully.
881 @retval EFI_UNSUPPORTED Command usage unsupported.
882 @retval EFI_INVALID_PARAMETER Command usage invalid.
883 @retval EFI_NOT_FOUND The input file can't be found.
888 IN EFI_HANDLE ImageHandle
,
889 IN EFI_SYSTEM_TABLE
*SystemTable
893 RETURN_STATUS RStatus
;
894 UINTN CapsuleBufferSize
[MAX_CAPSULE_NUM
];
895 VOID
*CapsuleBuffer
[MAX_CAPSULE_NUM
];
896 EFI_CAPSULE_BLOCK_DESCRIPTOR
*BlockDescriptors
;
897 EFI_CAPSULE_HEADER
*CapsuleHeaderArray
[MAX_CAPSULE_NUM
+ 1];
898 UINT64 MaxCapsuleSize
;
899 EFI_RESET_TYPE ResetType
;
902 BOOLEAN CapsuleOnDisk
;
904 CHAR16
*CapsuleNames
[MAX_CAPSULE_NUM
];
910 EFI_GUID ImageTypeId
;
913 BlockDescriptors
= NULL
;
918 if (EFI_ERROR(Status
)) {
919 Print(L
"Please use UEFI SHELL to run this application!\n", Status
);
924 return EFI_UNSUPPORTED
;
926 if (StrCmp(Argv
[1], L
"-D") == 0) {
928 Print(L
"CapsuleApp: Incorrect parameter count.\n");
929 return EFI_UNSUPPORTED
;
931 Status
= DumpCapsule(Argv
[2]);
934 if (StrCmp(Argv
[1], L
"-G") == 0) {
935 Status
= CreateBmpFmp();
938 if (StrCmp(Argv
[1], L
"-N") == 0) {
939 Status
= CreateNestedFmp();
942 if (StrCmp(Argv
[1], L
"-S") == 0) {
943 Status
= DumpCapsuleStatusVariable();
946 if (StrCmp(Argv
[1], L
"-C") == 0) {
947 Status
= ClearCapsuleStatusVariable();
950 if (StrCmp(Argv
[1], L
"-P") == 0) {
955 if (StrCmp(Argv
[2], L
"GET") != 0) {
956 Print(L
"CapsuleApp: Unrecognized option(%s).\n", Argv
[2]);
957 return EFI_UNSUPPORTED
;
960 Print(L
"CapsuleApp: Incorrect parameter count.\n");
961 return EFI_UNSUPPORTED
;
967 RStatus
= StrToGuid (Argv
[3], &ImageTypeId
);
968 if (RETURN_ERROR (RStatus
) || (Argv
[3][GUID_STRING_LENGTH
] != L
'\0')) {
969 Print (L
"Invalid ImageTypeId - %s\n", Argv
[3]);
970 return EFI_INVALID_PARAMETER
;
972 ImageIndex
= StrDecimalToUintn(Argv
[4]);
973 if (StrCmp(Argv
[5], L
"-O") != 0) {
974 Print(L
"CapsuleApp: NO output file name.\n");
975 return EFI_UNSUPPORTED
;
977 DumpFmpImage(&ImageTypeId
, ImageIndex
, Argv
[6]);
983 if (StrCmp(Argv
[1], L
"-E") == 0) {
988 if (StrCmp(Argv
[1], L
"-L") == 0) {
989 if (Argc
>= 3 && StrCmp(Argv
[2], L
"INFO") == 0) {
990 DumpProvisionedCapsule(TRUE
);
992 DumpProvisionedCapsule(FALSE
);
997 if (StrCmp(Argv
[1], L
"-F") == 0) {
998 DumpAllEfiSysPartition();
1002 if (Argv
[1][0] == L
'-') {
1003 Print(L
"CapsuleApp: Unrecognized option(%s).\n", Argv
[1]);
1004 return EFI_UNSUPPORTED
;
1007 CapsuleFirstIndex
= 1;
1009 CapsuleOnDisk
= FALSE
;
1013 for (Index
= 1; Index
< Argc
; Index
++) {
1014 if (StrCmp(Argv
[Index
], L
"-OD") == 0) {
1015 ParaOdIndex
= Index
;
1016 CapsuleOnDisk
= TRUE
;
1017 } else if (StrCmp(Argv
[Index
], L
"-NR") == 0) {
1018 ParaNrIndex
= Index
;
1023 if (ParaOdIndex
!= 0) {
1024 if (ParaOdIndex
== Argc
- 1) {
1026 } else if (ParaOdIndex
== Argc
- 2) {
1027 MapFsStr
= Argv
[Argc
-1];
1029 Print (L
"CapsuleApp: Invalid Position for -OD Options\n");
1030 Status
= EFI_INVALID_PARAMETER
;
1034 if (ParaNrIndex
!= 0) {
1035 if (ParaNrIndex
+ 1 == ParaOdIndex
) {
1036 CapsuleLastIndex
= ParaNrIndex
- 1;
1038 Print (L
"CapsuleApp: Invalid Position for -NR Options\n");
1039 Status
= EFI_INVALID_PARAMETER
;
1043 CapsuleLastIndex
= ParaOdIndex
- 1;
1046 if (ParaNrIndex
!= 0) {
1047 if (ParaNrIndex
== Argc
-1) {
1048 CapsuleLastIndex
= ParaNrIndex
- 1;
1050 Print (L
"CapsuleApp: Invalid Position for -NR Options\n");
1051 Status
= EFI_INVALID_PARAMETER
;
1055 CapsuleLastIndex
= Argc
- 1;
1059 CapsuleNum
= CapsuleLastIndex
- CapsuleFirstIndex
+ 1;
1061 if (CapsuleFirstIndex
> CapsuleLastIndex
) {
1062 Print(L
"CapsuleApp: NO capsule image.\n");
1063 return EFI_UNSUPPORTED
;
1065 if (CapsuleNum
> MAX_CAPSULE_NUM
) {
1066 Print(L
"CapsuleApp: Too many capsule images.\n");
1067 return EFI_UNSUPPORTED
;
1070 ZeroMem(&CapsuleBuffer
, sizeof(CapsuleBuffer
));
1071 ZeroMem(&CapsuleBufferSize
, sizeof(CapsuleBufferSize
));
1072 BlockDescriptors
= NULL
;
1074 for (Index
= 0; Index
< CapsuleNum
; Index
++) {
1075 CapsuleName
= Argv
[CapsuleFirstIndex
+ Index
];
1076 Status
= ReadFileToBuffer(CapsuleName
, &CapsuleBufferSize
[Index
], &CapsuleBuffer
[Index
]);
1077 if (EFI_ERROR(Status
)) {
1078 Print(L
"CapsuleApp: capsule image (%s) is not found.\n", CapsuleName
);
1081 if (!IsValidCapsuleHeader (CapsuleBuffer
[Index
], CapsuleBufferSize
[Index
])) {
1082 Print(L
"CapsuleApp: Capsule image (%s) is not a valid capsule.\n", CapsuleName
);
1083 return EFI_INVALID_PARAMETER
;
1085 CapsuleNames
[Index
] = CapsuleName
;
1089 // Every capsule use 2 descriptor 1 for data 1 for end
1091 Status
= BuildGatherList(CapsuleBuffer
, CapsuleBufferSize
, CapsuleNum
, &BlockDescriptors
);
1092 if (EFI_ERROR(Status
)) {
1097 // Call the runtime service capsule.
1100 for (Index
= 0; Index
< CapsuleNum
; Index
++) {
1101 CapsuleHeaderArray
[Index
] = (EFI_CAPSULE_HEADER
*) CapsuleBuffer
[Index
];
1102 if ((CapsuleHeaderArray
[Index
]->Flags
& CAPSULE_FLAGS_PERSIST_ACROSS_RESET
) != 0) {
1106 CapsuleHeaderArray
[CapsuleNum
] = NULL
;
1109 // Inquire platform capability of UpdateCapsule.
1111 Status
= gRT
->QueryCapsuleCapabilities (CapsuleHeaderArray
, CapsuleNum
, &MaxCapsuleSize
, &ResetType
);
1112 if (EFI_ERROR(Status
)) {
1113 Print (L
"CapsuleApp: failed to query capsule capability - %r\n", Status
);
1117 for (Index
= 0; Index
< CapsuleNum
; Index
++) {
1118 if (CapsuleBufferSize
[Index
] > MaxCapsuleSize
) {
1119 Print (L
"CapsuleApp: capsule is too large to update, %ld is allowed\n", MaxCapsuleSize
);
1120 Status
= EFI_UNSUPPORTED
;
1126 // Check whether is capsule on disk.
1128 if (CapsuleOnDisk
) {
1129 Status
= ProcessCapsuleOnDisk (CapsuleBuffer
, CapsuleBufferSize
, CapsuleNames
, MapFsStr
, CapsuleNum
);
1130 if (Status
!= EFI_SUCCESS
) {
1131 Print (L
"CapsuleApp: failed to update capsule - %r\n", Status
);
1135 gRT
->ResetSystem (ResetType
, EFI_SUCCESS
, 0, NULL
);
1143 // Check whether the input capsule image has the flag of persist across system reset.
1146 Status
= gRT
->UpdateCapsule(CapsuleHeaderArray
,CapsuleNum
,(UINTN
) BlockDescriptors
);
1147 if (Status
!= EFI_SUCCESS
) {
1148 Print (L
"CapsuleApp: failed to update capsule - %r\n", Status
);
1152 // For capsule with CAPSULE_FLAGS_PERSIST_ACROSS_RESET + CAPSULE_FLAGS_INITIATE_RESET,
1153 // a system reset should have been triggered by gRT->UpdateCapsule() calling above.
1155 // For capsule with CAPSULE_FLAGS_PERSIST_ACROSS_RESET and without CAPSULE_FLAGS_INITIATE_RESET,
1156 // check if -NR (no-reset) has been specified or not.
1160 // For capsule who has reset flag and no -NR (no-reset) has been specified, after calling UpdateCapsule service,
1161 // trigger a system reset to process capsule persist across a system reset.
1163 gRT
->ResetSystem (ResetType
, EFI_SUCCESS
, 0, NULL
);
1167 // For capsule who has no reset flag, only call UpdateCapsule Service without a
1168 // system reset. The service will process the capsule immediately.
1170 Status
= gRT
->UpdateCapsule (CapsuleHeaderArray
,CapsuleNum
,(UINTN
) BlockDescriptors
);
1171 if (Status
!= EFI_SUCCESS
) {
1172 Print (L
"CapsuleApp: failed to update capsule - %r\n", Status
);
1176 Status
= EFI_SUCCESS
;
1179 for (Index
= 0; Index
< CapsuleNum
; Index
++) {
1180 if (CapsuleBuffer
[Index
] != NULL
) {
1181 FreePool (CapsuleBuffer
[Index
]);
1185 CleanGatherList(BlockDescriptors
, CapsuleNum
);