2 A shell application that triggers capsule update process.
4 Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include <Library/BaseLib.h>
17 #include <Library/DebugLib.h>
18 #include <Library/BaseMemoryLib.h>
19 #include <Library/MemoryAllocationLib.h>
20 #include <Library/UefiBootServicesTableLib.h>
21 #include <Library/UefiRuntimeServicesTableLib.h>
22 #include <Library/UefiLib.h>
23 #include <Library/PrintLib.h>
24 #include <Library/BmpSupportLib.h>
25 #include <Protocol/GraphicsOutput.h>
26 #include <Guid/GlobalVariable.h>
27 #include <Guid/CapsuleReport.h>
28 #include <Guid/SystemResourceTable.h>
29 #include <Guid/FmpCapsule.h>
30 #include <IndustryStandard/WindowsUxCapsule.h>
32 #define CAPSULE_HEADER_SIZE 0x20
34 #define NESTED_CAPSULE_HEADER_SIZE SIZE_4KB
35 #define SYSTEM_FIRMWARE_FLAG 0x50000
36 #define DEVICE_FIRMWARE_FLAG 0x78010
38 #define MAJOR_VERSION 1
39 #define MINOR_VERSION 0
41 #define MAX_CAPSULE_NUM 10
47 // Define how many block descriptors we want to test with.
49 UINTN NumberOfDescriptors
= 1;
50 UINTN CapsuleFirstIndex
;
51 UINTN CapsuleLastIndex
;
54 Dump capsule information
56 @param[in] CapsuleName The name of the capsule image.
58 @retval EFI_SUCCESS The capsule information is dumped.
59 @retval EFI_UNSUPPORTED Input parameter is not valid.
63 IN CHAR16
*CapsuleName
67 Dump capsule status variable.
69 @retval EFI_SUCCESS The capsule status variable is dumped.
70 @retval EFI_UNSUPPORTED Input parameter is not valid.
73 DumpCapsuleStatusVariable (
78 Dump FMP protocol info.
88 @param[in] ImageTypeId The ImageTypeId of the FMP image.
89 It is used to identify the FMP protocol.
90 @param[in] ImageIndex The ImageIndex of the FMP image.
91 It is the input parameter for FMP->GetImage().
92 @param[in] ImageName The file name to hold the output FMP image.
96 IN EFI_GUID
*ImageTypeId
,
110 Dump Provisioned Capsule.
112 @param[in] DumpCapsuleInfo The flag to indicate whether to dump the capsule inforomation.
115 DumpProvisionedCapsule (
116 IN BOOLEAN DumpCapsuleInfo
120 Dump all EFI System Partition.
123 DumpAllEfiSysPartition (
128 Process Capsule On Disk.
130 @param[in] CapsuleBuffer An array of pointer to capsule images
131 @param[in] CapsuleBufferSize An array of UINTN to capsule images size
132 @param[in] FilePath An array of capsule images file path
133 @param[in] Map File system mapping string
134 @param[in] CapsuleNum The count of capsule images
136 @retval EFI_SUCCESS Capsule on disk success.
137 @retval others Capsule on disk fail.
141 ProcessCapsuleOnDisk (
142 IN VOID
**CapsuleBuffer
,
143 IN UINTN
*CapsuleBufferSize
,
144 IN CHAR16
**FilePath
,
152 @param[in] FileName The file to be read.
153 @param[out] BufferSize The file buffer size
154 @param[out] Buffer The file buffer
156 @retval EFI_SUCCESS Read file successfully
157 @retval EFI_NOT_FOUND Shell protocol or file not found
158 @retval others Read file failed
163 OUT UINTN
*BufferSize
,
170 @param[in] FileName The file to be written.
171 @param[in] BufferSize The file buffer size
172 @param[in] Buffer The file buffer
174 @retval EFI_SUCCESS Write file successfully
175 @retval EFI_NOT_FOUND Shell protocol not found
176 @retval others Write file failed
179 WriteFileFromBuffer (
187 This function parse application ARG.
199 @retval EFI_SUCCESS The capsule header is appended.
200 @retval EFI_UNSUPPORTED Input parameter is not valid.
201 @retval EFI_OUT_OF_RESOURCES No enough resource to create UX capsule.
208 CHAR16
*OutputCapsuleName
;
212 UINT8
*FullCapsuleBuffer
;
213 UINTN FullCapsuleBufferSize
;
214 EFI_DISPLAY_CAPSULE
*DisplayCapsule
;
216 EFI_GRAPHICS_OUTPUT_PROTOCOL
*Gop
;
217 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION
*Info
;
218 EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*GopBlt
;
223 Status
= gBS
->LocateProtocol(&gEfiGraphicsOutputProtocolGuid
, NULL
, (VOID
**)&Gop
);
224 if (EFI_ERROR(Status
)) {
225 Print(L
"CapsuleApp: NO GOP is found.\n");
226 return EFI_UNSUPPORTED
;
228 Info
= Gop
->Mode
->Info
;
229 Print(L
"Current GOP: Mode - %d, ", Gop
->Mode
->Mode
);
230 Print(L
"HorizontalResolution - %d, ", Info
->HorizontalResolution
);
231 Print(L
"VerticalResolution - %d\n", Info
->VerticalResolution
);
232 // HorizontalResolution >= BMP_IMAGE_HEADER.PixelWidth
233 // VerticalResolution >= BMP_IMAGE_HEADER.PixelHeight
236 Print(L
"CapsuleApp: Incorrect parameter count.\n");
237 return EFI_UNSUPPORTED
;
240 if (StrCmp(Argv
[3], L
"-O") != 0) {
241 Print(L
"CapsuleApp: NO output capsule name.\n");
242 return EFI_UNSUPPORTED
;
244 OutputCapsuleName
= Argv
[4];
248 FullCapsuleBuffer
= NULL
;
251 Status
= ReadFileToBuffer(BmpName
, &FileSize
, &BmpBuffer
);
252 if (EFI_ERROR(Status
)) {
253 Print(L
"CapsuleApp: BMP image (%s) is not found.\n", BmpName
);
258 Status
= TranslateBmpToGopBlt (
266 if (EFI_ERROR(Status
)) {
267 Print(L
"CapsuleApp: BMP image (%s) is not valid.\n", BmpName
);
270 if (GopBlt
!= NULL
) {
273 Print(L
"BMP image (%s), Width - %d, Height - %d\n", BmpName
, Width
, Height
);
275 if (Height
> Info
->VerticalResolution
) {
276 Status
= EFI_INVALID_PARAMETER
;
277 Print(L
"CapsuleApp: BMP image (%s) height is larger than current resolution.\n", BmpName
);
280 if (Width
> Info
->HorizontalResolution
) {
281 Status
= EFI_INVALID_PARAMETER
;
282 Print(L
"CapsuleApp: BMP image (%s) width is larger than current resolution.\n", BmpName
);
286 FullCapsuleBufferSize
= sizeof(EFI_DISPLAY_CAPSULE
) + FileSize
;
287 FullCapsuleBuffer
= AllocatePool(FullCapsuleBufferSize
);
288 if (FullCapsuleBuffer
== NULL
) {
289 Print(L
"CapsuleApp: Capsule Buffer size (0x%x) too big.\n", FullCapsuleBufferSize
);
290 Status
= EFI_OUT_OF_RESOURCES
;
294 DisplayCapsule
= (EFI_DISPLAY_CAPSULE
*)FullCapsuleBuffer
;
295 CopyGuid(&DisplayCapsule
->CapsuleHeader
.CapsuleGuid
, &gWindowsUxCapsuleGuid
);
296 DisplayCapsule
->CapsuleHeader
.HeaderSize
= sizeof(DisplayCapsule
->CapsuleHeader
);
297 DisplayCapsule
->CapsuleHeader
.Flags
= CAPSULE_FLAGS_PERSIST_ACROSS_RESET
;
298 DisplayCapsule
->CapsuleHeader
.CapsuleImageSize
= (UINT32
)FullCapsuleBufferSize
;
300 DisplayCapsule
->ImagePayload
.Version
= 1;
301 DisplayCapsule
->ImagePayload
.Checksum
= 0;
302 DisplayCapsule
->ImagePayload
.ImageType
= 0; // BMP
303 DisplayCapsule
->ImagePayload
.Reserved
= 0;
304 DisplayCapsule
->ImagePayload
.Mode
= Gop
->Mode
->Mode
;
307 // Center the bitmap horizontally
309 DisplayCapsule
->ImagePayload
.OffsetX
= (UINT32
)((Info
->HorizontalResolution
- Width
) / 2);
312 // Put bitmap 3/4 down the display. If bitmap is too tall, then align bottom
313 // of bitmap at bottom of display.
315 DisplayCapsule
->ImagePayload
.OffsetY
=
317 (UINT32
)(Info
->VerticalResolution
- Height
),
318 (UINT32
)(((3 * Info
->VerticalResolution
) - (2 * Height
)) / 4)
321 Print(L
"BMP image (%s), OffsetX - %d, OffsetY - %d\n",
323 DisplayCapsule
->ImagePayload
.OffsetX
,
324 DisplayCapsule
->ImagePayload
.OffsetY
327 CopyMem((DisplayCapsule
+ 1), BmpBuffer
, FileSize
);
329 DisplayCapsule
->ImagePayload
.Checksum
= CalculateCheckSum8(FullCapsuleBuffer
, FullCapsuleBufferSize
);
331 Status
= WriteFileFromBuffer(OutputCapsuleName
, FullCapsuleBufferSize
, FullCapsuleBuffer
);
332 Print(L
"CapsuleApp: Write %s %r\n", OutputCapsuleName
, Status
);
335 if (BmpBuffer
!= NULL
) {
339 if (FullCapsuleBuffer
!= NULL
) {
340 FreePool(FullCapsuleBuffer
);
347 Get ImageTypeId in the FMP capsule header.
349 @param[in] CapsuleHeader The FMP capsule image header.
354 GetCapsuleImageTypeId (
355 IN EFI_CAPSULE_HEADER
*CapsuleHeader
358 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
*FmpCapsuleHeader
;
359 UINT64
*ItemOffsetList
;
360 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
*ImageHeader
;
362 FmpCapsuleHeader
= (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
*)((UINT8
*)CapsuleHeader
+ CapsuleHeader
->HeaderSize
);
363 ItemOffsetList
= (UINT64
*)(FmpCapsuleHeader
+ 1);
364 if (FmpCapsuleHeader
->PayloadItemCount
== 0) {
367 ImageHeader
= (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
*)((UINT8
*)FmpCapsuleHeader
+ ItemOffsetList
[FmpCapsuleHeader
->EmbeddedDriverCount
]);
368 return &ImageHeader
->UpdateImageTypeId
;
372 Get ESRT FwType according to ImageTypeId
374 @param[in] ImageTypeId ImageTypeId of an FMP capsule.
380 IN EFI_GUID
*ImageTypeId
384 EFI_SYSTEM_RESOURCE_TABLE
*Esrt
;
385 EFI_SYSTEM_RESOURCE_ENTRY
*EsrtEntry
;
391 Status
= EfiGetSystemConfigurationTable(&gEfiSystemResourceTableGuid
, (VOID
**)&Esrt
);
392 if (!EFI_ERROR(Status
)) {
393 ASSERT(Esrt
!= NULL
);
394 EsrtEntry
= (VOID
*)(Esrt
+ 1);
395 for (Index
= 0; Index
< Esrt
->FwResourceCount
; Index
++, EsrtEntry
++) {
396 if (CompareGuid(&EsrtEntry
->FwClass
, ImageTypeId
)) {
397 return EsrtEntry
->FwType
;
402 return ESRT_FW_TYPE_UNKNOWN
;
406 Validate if it is valid capsule header
408 This function assumes the caller provided correct CapsuleHeader pointer
411 This function validates the fields in EFI_CAPSULE_HEADER.
413 @param[in] CapsuleHeader Points to a capsule header.
414 @param[in] CapsuleSize Size of the whole capsule image.
418 IsValidCapsuleHeader (
419 IN EFI_CAPSULE_HEADER
*CapsuleHeader
,
420 IN UINT64 CapsuleSize
423 if (CapsuleSize
< sizeof (EFI_CAPSULE_HEADER
)) {
426 if (CapsuleHeader
->CapsuleImageSize
!= CapsuleSize
) {
429 if (CapsuleHeader
->HeaderSize
> CapsuleHeader
->CapsuleImageSize
) {
432 if (CapsuleHeader
->HeaderSize
< sizeof (EFI_CAPSULE_HEADER
)) {
440 Return if this CapsuleGuid is a FMP capsule GUID or not.
442 @param[in] CapsuleGuid A pointer to EFI_GUID
444 @retval TRUE It is a FMP capsule GUID.
445 @retval FALSE It is not a FMP capsule GUID.
449 IN EFI_GUID
*CapsuleGuid
452 if (CompareGuid(&gEfiFmpCapsuleGuid
, CapsuleGuid
)) {
460 Append a capsule header on top of current image.
461 This function follows Windows UEFI Firmware Update Platform document.
463 @retval EFI_SUCCESS The capsule header is appended.
464 @retval EFI_UNSUPPORTED Input parameter is not valid.
465 @retval EFI_OUT_OF_RESOURCES No enough resource to append capsule header.
472 CHAR16
*OutputCapsuleName
;
476 UINT8
*FullCapsuleBuffer
;
477 UINTN FullCapsuleBufferSize
;
478 EFI_CAPSULE_HEADER
*NestedCapsuleHeader
;
479 EFI_GUID
*ImageTypeId
;
484 Print(L
"CapsuleApp: Incorrect parameter count.\n");
485 return EFI_UNSUPPORTED
;
488 if (StrCmp(Argv
[3], L
"-O") != 0) {
489 Print(L
"CapsuleApp: NO output capsule name.\n");
490 return EFI_UNSUPPORTED
;
492 OutputCapsuleName
= Argv
[4];
494 CapsuleBuffer
= NULL
;
496 FullCapsuleBuffer
= NULL
;
498 CapsuleName
= Argv
[2];
499 Status
= ReadFileToBuffer(CapsuleName
, &FileSize
, &CapsuleBuffer
);
500 if (EFI_ERROR(Status
)) {
501 Print(L
"CapsuleApp: Capsule image (%s) is not found.\n", CapsuleName
);
504 if (!IsValidCapsuleHeader (CapsuleBuffer
, FileSize
)) {
505 Print(L
"CapsuleApp: Capsule image (%s) is not a valid capsule.\n", CapsuleName
);
506 Status
= EFI_INVALID_PARAMETER
;
510 if (!IsFmpCapsuleGuid (&((EFI_CAPSULE_HEADER
*) CapsuleBuffer
)->CapsuleGuid
)) {
511 Print(L
"CapsuleApp: Capsule image (%s) is not a FMP capsule.\n", CapsuleName
);
512 Status
= EFI_INVALID_PARAMETER
;
516 ImageTypeId
= GetCapsuleImageTypeId(CapsuleBuffer
);
517 if (ImageTypeId
== NULL
) {
518 Print(L
"CapsuleApp: Capsule ImageTypeId is not found.\n");
519 Status
= EFI_INVALID_PARAMETER
;
522 FwType
= GetEsrtFwType(ImageTypeId
);
523 if ((FwType
!= ESRT_FW_TYPE_SYSTEMFIRMWARE
) && (FwType
!= ESRT_FW_TYPE_DEVICEFIRMWARE
)) {
524 Print(L
"CapsuleApp: Capsule FwType is invalid.\n");
525 Status
= EFI_INVALID_PARAMETER
;
529 FullCapsuleBufferSize
= NESTED_CAPSULE_HEADER_SIZE
+ FileSize
;
530 FullCapsuleBuffer
= AllocatePool(FullCapsuleBufferSize
);
531 if (FullCapsuleBuffer
== NULL
) {
532 Print(L
"CapsuleApp: Capsule Buffer size (0x%x) too big.\n", FullCapsuleBufferSize
);
533 Status
= EFI_OUT_OF_RESOURCES
;
537 NestedCapsuleHeader
= (EFI_CAPSULE_HEADER
*)FullCapsuleBuffer
;
538 ZeroMem(NestedCapsuleHeader
, NESTED_CAPSULE_HEADER_SIZE
);
539 CopyGuid(&NestedCapsuleHeader
->CapsuleGuid
, ImageTypeId
);
540 NestedCapsuleHeader
->HeaderSize
= NESTED_CAPSULE_HEADER_SIZE
;
541 NestedCapsuleHeader
->Flags
= (FwType
== ESRT_FW_TYPE_SYSTEMFIRMWARE
) ? SYSTEM_FIRMWARE_FLAG
: DEVICE_FIRMWARE_FLAG
;
542 NestedCapsuleHeader
->CapsuleImageSize
= (UINT32
)FullCapsuleBufferSize
;
544 CopyMem((UINT8
*)NestedCapsuleHeader
+ NestedCapsuleHeader
->HeaderSize
, CapsuleBuffer
, FileSize
);
546 Status
= WriteFileFromBuffer(OutputCapsuleName
, FullCapsuleBufferSize
, FullCapsuleBuffer
);
547 Print(L
"CapsuleApp: Write %s %r\n", OutputCapsuleName
, Status
);
550 if (CapsuleBuffer
!= NULL
) {
551 FreePool(CapsuleBuffer
);
554 if (FullCapsuleBuffer
!= NULL
) {
555 FreePool(FullCapsuleBuffer
);
563 Clear capsule status variable.
565 @retval EFI_SUCCESS The capsule status variable is cleared.
568 ClearCapsuleStatusVariable (
574 CHAR16 CapsuleVarName
[20];
578 StrCpyS (CapsuleVarName
, sizeof(CapsuleVarName
)/sizeof(CapsuleVarName
[0]), L
"Capsule");
579 TempVarName
= CapsuleVarName
+ StrLen (CapsuleVarName
);
584 UnicodeSPrint (TempVarName
, 5 * sizeof(CHAR16
), L
"%04x", Index
);
586 Status
= gRT
->SetVariable (
588 &gEfiCapsuleReportGuid
,
589 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
,
593 if (Status
== EFI_NOT_FOUND
) {
595 // There is no more capsule variables, quit
601 Print (L
"Clear %s %r\n", CapsuleVarName
, Status
);
604 if (Index
> 0xFFFF) {
610 Print (L
"No any Capsule#### variable found\n");
617 Build Gather list for a list of capsule images.
619 @param[in] CapsuleBuffer An array of pointer to capsule images
620 @param[in] FileSize An array of UINTN to capsule images size
621 @param[in] CapsuleNum The count of capsule images
622 @param[out] BlockDescriptors The block descriptors for the capsule images
624 @retval EFI_SUCCESS The block descriptors for the capsule images are constructed.
628 IN VOID
**CapsuleBuffer
,
631 OUT EFI_CAPSULE_BLOCK_DESCRIPTOR
**BlockDescriptors
635 EFI_CAPSULE_BLOCK_DESCRIPTOR
*BlockDescriptors1
;
636 EFI_CAPSULE_BLOCK_DESCRIPTOR
*BlockDescriptors2
;
637 EFI_CAPSULE_BLOCK_DESCRIPTOR
*BlockDescriptorPre
;
638 EFI_CAPSULE_BLOCK_DESCRIPTOR
*BlockDescriptorsHeader
;
639 EFI_CAPSULE_BLOCK_DESCRIPTOR
*TempBlockPtr
;
648 BlockDescriptors1
= NULL
;
649 BlockDescriptors2
= NULL
;
650 BlockDescriptorPre
= NULL
;
651 BlockDescriptorsHeader
= NULL
;
653 for (Index
= 0; Index
< CapsuleNum
; Index
++) {
655 // Allocate memory for the descriptors.
657 if (NumberOfDescriptors
== 1) {
660 Count
= (INT32
)(NumberOfDescriptors
+ 2) / 2;
663 Size
= Count
* sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR
);
664 BlockDescriptors1
= AllocateRuntimeZeroPool (Size
);
665 if (BlockDescriptors1
== NULL
) {
666 Print (L
"CapsuleApp: failed to allocate memory for descriptors\n");
667 Status
= EFI_OUT_OF_RESOURCES
;
670 Print (L
"CapsuleApp: creating capsule descriptors at 0x%X\n", (UINTN
) BlockDescriptors1
);
671 Print (L
"CapsuleApp: capsule data starts at 0x%X with size 0x%X\n", (UINTN
) CapsuleBuffer
[Index
], FileSize
[Index
]);
675 // Record descirptor header
678 BlockDescriptorsHeader
= BlockDescriptors1
;
681 if (BlockDescriptorPre
!= NULL
) {
682 BlockDescriptorPre
->Union
.ContinuationPointer
= (UINTN
) BlockDescriptors1
;
683 BlockDescriptorPre
->Length
= 0;
689 TempBlockPtr
= BlockDescriptors1
;
690 TempDataPtr
= CapsuleBuffer
[Index
];
691 SizeLeft
= FileSize
[Index
];
692 for (Number
= 0; (Number
< Count
- 1) && (SizeLeft
!= 0); Number
++) {
694 // Divide remaining data in half
696 if (NumberOfDescriptors
!= 1) {
705 TempBlockPtr
->Union
.DataBlock
= (UINTN
)TempDataPtr
;
706 TempBlockPtr
->Length
= Size
;
707 Print (L
"CapsuleApp: capsule block/size 0x%X/0x%X\n", (UINTN
) TempDataPtr
, Size
);
714 // Allocate the second list, point the first block's last entry to point
715 // to this one, and fill this one in. Worst case is that the previous
716 // list only had one element that pointed here, so we need at least two
717 // elements -- one to point to all the data, another to terminate the list.
719 if ((NumberOfDescriptors
!= 1) && (SizeLeft
!= 0)) {
720 Count
= (INT32
)(NumberOfDescriptors
+ 2) - Count
;
725 Size
= Count
* sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR
);
726 BlockDescriptors2
= AllocateRuntimeZeroPool (Size
);
727 if (BlockDescriptors2
== NULL
) {
728 Print (L
"CapsuleApp: failed to allocate memory for descriptors\n");
729 Status
= EFI_OUT_OF_RESOURCES
;
734 // Point the first list's last element to point to this second list.
736 TempBlockPtr
->Union
.ContinuationPointer
= (UINTN
) BlockDescriptors2
;
738 TempBlockPtr
->Length
= 0;
739 TempBlockPtr
= BlockDescriptors2
;
740 for (Number
= 0; Number
< Count
- 1; Number
++) {
742 // If second-to-last one, then dump rest to this element
744 if (Number
== (Count
- 2)) {
748 // Divide remaining data in half
757 TempBlockPtr
->Union
.DataBlock
= (UINTN
)TempDataPtr
;
758 TempBlockPtr
->Length
= Size
;
759 Print (L
"CapsuleApp: capsule block/size 0x%X/0x%X\n", (UINTN
) TempDataPtr
, Size
);
769 BlockDescriptorPre
= TempBlockPtr
;
770 BlockDescriptors1
= NULL
;
776 if (TempBlockPtr
!= NULL
) {
777 TempBlockPtr
->Union
.ContinuationPointer
= (UINTN
)NULL
;
778 TempBlockPtr
->Length
= 0;
779 *BlockDescriptors
= BlockDescriptorsHeader
;
785 if (BlockDescriptors1
!= NULL
) {
786 FreePool(BlockDescriptors1
);
789 if (BlockDescriptors2
!= NULL
) {
790 FreePool(BlockDescriptors2
);
797 Clear the Gather list for a list of capsule images.
799 @param[in] BlockDescriptors The block descriptors for the capsule images
800 @param[in] CapsuleNum The count of capsule images
804 IN EFI_CAPSULE_BLOCK_DESCRIPTOR
*BlockDescriptors
,
808 EFI_CAPSULE_BLOCK_DESCRIPTOR
*TempBlockPtr
;
809 EFI_CAPSULE_BLOCK_DESCRIPTOR
*TempBlockPtr1
;
810 EFI_CAPSULE_BLOCK_DESCRIPTOR
*TempBlockPtr2
;
813 if (BlockDescriptors
!= NULL
) {
814 TempBlockPtr1
= BlockDescriptors
;
816 TempBlockPtr
= TempBlockPtr1
;
817 for (Index
= 0; Index
< CapsuleNum
; Index
++) {
818 if (TempBlockPtr
[Index
].Length
== 0) {
823 if (TempBlockPtr
[Index
].Union
.ContinuationPointer
== (UINTN
)NULL
) {
827 TempBlockPtr2
= (VOID
*) ((UINTN
) TempBlockPtr
[Index
].Union
.ContinuationPointer
);
828 FreePool(TempBlockPtr1
);
829 TempBlockPtr1
= TempBlockPtr2
;
842 Print(L
"CapsuleApp: usage\n");
843 Print(L
" CapsuleApp <Capsule...> [-NR] [-OD [FSx]]\n");
844 Print(L
" CapsuleApp -S\n");
845 Print(L
" CapsuleApp -C\n");
846 Print(L
" CapsuleApp -P\n");
847 Print(L
" CapsuleApp -E\n");
848 Print(L
" CapsuleApp -L\n");
849 Print(L
" CapsuleApp -L INFO\n");
850 Print(L
" CapsuleApp -F\n");
851 Print(L
" CapsuleApp -G <BMP> -O <Capsule>\n");
852 Print(L
" CapsuleApp -N <Capsule> -O <NestedCapsule>\n");
853 Print(L
" CapsuleApp -D <Capsule>\n");
854 Print(L
" CapsuleApp -P GET <ImageTypeId> <Index> -O <FileName>\n");
855 Print(L
"Parameter:\n");
856 Print(L
" -NR: No reset will be triggered for the capsule\n");
857 Print(L
" with CAPSULE_FLAGS_PERSIST_ACROSS_RESET and without CAPSULE_FLAGS_INITIATE_RESET.\n");
858 Print(L
" -OD: Delivery of Capsules via file on Mass Storage device.");
859 Print(L
" -S: Dump capsule report variable (EFI_CAPSULE_REPORT_GUID),\n");
860 Print(L
" which is defined in UEFI specification.\n");
861 Print(L
" -C: Clear capsule report variable (EFI_CAPSULE_REPORT_GUID),\n");
862 Print(L
" which is defined in UEFI specification.\n");
863 Print(L
" -P: Dump UEFI FMP protocol info, or get image with specified\n");
864 Print(L
" ImageTypeId and Index (decimal format) to a file if 'GET'\n");
865 Print(L
" option is used.\n");
866 Print(L
" -E: Dump UEFI ESRT table info.\n");
867 Print(L
" -L: Dump provisioned capsule image information.\n");
868 Print(L
" -F: Dump all EFI System Partition.\n");
869 Print(L
" -G: Convert a BMP file to be an UX capsule,\n");
870 Print(L
" according to Windows Firmware Update document\n");
871 Print(L
" -N: Append a Capsule Header to an existing FMP capsule image\n");
872 Print(L
" with its ImageTypeId supported by the system,\n");
873 Print(L
" according to Windows Firmware Update document\n");
874 Print(L
" -O: Output new Capsule file name\n");
875 Print(L
" -D: Dump Capsule image header information, image payload\n");
876 Print(L
" information if it is an UX capsule and FMP header\n");
877 Print(L
" information if it is a FMP capsule.\n");
881 Update Capsule image.
883 @param[in] ImageHandle The image handle.
884 @param[in] SystemTable The system table.
886 @retval EFI_SUCCESS Command completed successfully.
887 @retval EFI_UNSUPPORTED Command usage unsupported.
888 @retval EFI_INVALID_PARAMETER Command usage invalid.
889 @retval EFI_NOT_FOUND The input file can't be found.
894 IN EFI_HANDLE ImageHandle
,
895 IN EFI_SYSTEM_TABLE
*SystemTable
899 RETURN_STATUS RStatus
;
900 UINTN CapsuleBufferSize
[MAX_CAPSULE_NUM
];
901 VOID
*CapsuleBuffer
[MAX_CAPSULE_NUM
];
902 EFI_CAPSULE_BLOCK_DESCRIPTOR
*BlockDescriptors
;
903 EFI_CAPSULE_HEADER
*CapsuleHeaderArray
[MAX_CAPSULE_NUM
+ 1];
904 UINT64 MaxCapsuleSize
;
905 EFI_RESET_TYPE ResetType
;
908 BOOLEAN CapsuleOnDisk
;
910 CHAR16
*CapsuleNames
[MAX_CAPSULE_NUM
];
916 EFI_GUID ImageTypeId
;
919 BlockDescriptors
= NULL
;
924 if (EFI_ERROR(Status
)) {
925 Print(L
"Please use UEFI SHELL to run this application!\n", Status
);
930 return EFI_UNSUPPORTED
;
932 if (StrCmp(Argv
[1], L
"-D") == 0) {
934 Print(L
"CapsuleApp: Incorrect parameter count.\n");
935 return EFI_UNSUPPORTED
;
937 Status
= DumpCapsule(Argv
[2]);
940 if (StrCmp(Argv
[1], L
"-G") == 0) {
941 Status
= CreateBmpFmp();
944 if (StrCmp(Argv
[1], L
"-N") == 0) {
945 Status
= CreateNestedFmp();
948 if (StrCmp(Argv
[1], L
"-S") == 0) {
949 Status
= DumpCapsuleStatusVariable();
952 if (StrCmp(Argv
[1], L
"-C") == 0) {
953 Status
= ClearCapsuleStatusVariable();
956 if (StrCmp(Argv
[1], L
"-P") == 0) {
961 if (StrCmp(Argv
[2], L
"GET") != 0) {
962 Print(L
"CapsuleApp: Unrecognized option(%s).\n", Argv
[2]);
963 return EFI_UNSUPPORTED
;
966 Print(L
"CapsuleApp: Incorrect parameter count.\n");
967 return EFI_UNSUPPORTED
;
973 RStatus
= StrToGuid (Argv
[3], &ImageTypeId
);
974 if (RETURN_ERROR (RStatus
) || (Argv
[3][GUID_STRING_LENGTH
] != L
'\0')) {
975 Print (L
"Invalid ImageTypeId - %s\n", Argv
[3]);
976 return EFI_INVALID_PARAMETER
;
978 ImageIndex
= StrDecimalToUintn(Argv
[4]);
979 if (StrCmp(Argv
[5], L
"-O") != 0) {
980 Print(L
"CapsuleApp: NO output file name.\n");
981 return EFI_UNSUPPORTED
;
983 DumpFmpImage(&ImageTypeId
, ImageIndex
, Argv
[6]);
989 if (StrCmp(Argv
[1], L
"-E") == 0) {
994 if (StrCmp(Argv
[1], L
"-L") == 0) {
995 if (Argc
>= 3 && StrCmp(Argv
[2], L
"INFO") == 0) {
996 DumpProvisionedCapsule(TRUE
);
998 DumpProvisionedCapsule(FALSE
);
1003 if (StrCmp(Argv
[1], L
"-F") == 0) {
1004 DumpAllEfiSysPartition();
1008 if (Argv
[1][0] == L
'-') {
1009 Print(L
"CapsuleApp: Unrecognized option(%s).\n", Argv
[1]);
1010 return EFI_UNSUPPORTED
;
1013 CapsuleFirstIndex
= 1;
1015 CapsuleOnDisk
= FALSE
;
1019 for (Index
= 1; Index
< Argc
; Index
++) {
1020 if (StrCmp(Argv
[Index
], L
"-OD") == 0) {
1021 ParaOdIndex
= Index
;
1022 CapsuleOnDisk
= TRUE
;
1023 } else if (StrCmp(Argv
[Index
], L
"-NR") == 0) {
1024 ParaNrIndex
= Index
;
1029 if (ParaOdIndex
!= 0) {
1030 if (ParaOdIndex
== Argc
- 1) {
1032 } else if (ParaOdIndex
== Argc
- 2) {
1033 MapFsStr
= Argv
[Argc
-1];
1035 Print (L
"CapsuleApp: Invalid Position for -OD Options\n");
1036 Status
= EFI_INVALID_PARAMETER
;
1040 if (ParaNrIndex
!= 0) {
1041 if (ParaNrIndex
+ 1 == ParaOdIndex
) {
1042 CapsuleLastIndex
= ParaNrIndex
- 1;
1044 Print (L
"CapsuleApp: Invalid Position for -NR Options\n");
1045 Status
= EFI_INVALID_PARAMETER
;
1049 CapsuleLastIndex
= ParaOdIndex
- 1;
1052 if (ParaNrIndex
!= 0) {
1053 if (ParaNrIndex
== Argc
-1) {
1054 CapsuleLastIndex
= ParaNrIndex
- 1;
1056 Print (L
"CapsuleApp: Invalid Position for -NR Options\n");
1057 Status
= EFI_INVALID_PARAMETER
;
1061 CapsuleLastIndex
= Argc
- 1;
1065 CapsuleNum
= CapsuleLastIndex
- CapsuleFirstIndex
+ 1;
1067 if (CapsuleFirstIndex
> CapsuleLastIndex
) {
1068 Print(L
"CapsuleApp: NO capsule image.\n");
1069 return EFI_UNSUPPORTED
;
1071 if (CapsuleNum
> MAX_CAPSULE_NUM
) {
1072 Print(L
"CapsuleApp: Too many capsule images.\n");
1073 return EFI_UNSUPPORTED
;
1076 ZeroMem(&CapsuleBuffer
, sizeof(CapsuleBuffer
));
1077 ZeroMem(&CapsuleBufferSize
, sizeof(CapsuleBufferSize
));
1078 BlockDescriptors
= NULL
;
1080 for (Index
= 0; Index
< CapsuleNum
; Index
++) {
1081 CapsuleName
= Argv
[CapsuleFirstIndex
+ Index
];
1082 Status
= ReadFileToBuffer(CapsuleName
, &CapsuleBufferSize
[Index
], &CapsuleBuffer
[Index
]);
1083 if (EFI_ERROR(Status
)) {
1084 Print(L
"CapsuleApp: capsule image (%s) is not found.\n", CapsuleName
);
1087 if (!IsValidCapsuleHeader (CapsuleBuffer
[Index
], CapsuleBufferSize
[Index
])) {
1088 Print(L
"CapsuleApp: Capsule image (%s) is not a valid capsule.\n", CapsuleName
);
1089 return EFI_INVALID_PARAMETER
;
1091 CapsuleNames
[Index
] = CapsuleName
;
1095 // Every capsule use 2 descriptor 1 for data 1 for end
1097 Status
= BuildGatherList(CapsuleBuffer
, CapsuleBufferSize
, CapsuleNum
, &BlockDescriptors
);
1098 if (EFI_ERROR(Status
)) {
1103 // Call the runtime service capsule.
1106 for (Index
= 0; Index
< CapsuleNum
; Index
++) {
1107 CapsuleHeaderArray
[Index
] = (EFI_CAPSULE_HEADER
*) CapsuleBuffer
[Index
];
1108 if ((CapsuleHeaderArray
[Index
]->Flags
& CAPSULE_FLAGS_PERSIST_ACROSS_RESET
) != 0) {
1112 CapsuleHeaderArray
[CapsuleNum
] = NULL
;
1115 // Inquire platform capability of UpdateCapsule.
1117 Status
= gRT
->QueryCapsuleCapabilities (CapsuleHeaderArray
, CapsuleNum
, &MaxCapsuleSize
, &ResetType
);
1118 if (EFI_ERROR(Status
)) {
1119 Print (L
"CapsuleApp: failed to query capsule capability - %r\n", Status
);
1123 for (Index
= 0; Index
< CapsuleNum
; Index
++) {
1124 if (CapsuleBufferSize
[Index
] > MaxCapsuleSize
) {
1125 Print (L
"CapsuleApp: capsule is too large to update, %ld is allowed\n", MaxCapsuleSize
);
1126 Status
= EFI_UNSUPPORTED
;
1132 // Check whether is capsule on disk.
1134 if (CapsuleOnDisk
) {
1135 Status
= ProcessCapsuleOnDisk (CapsuleBuffer
, CapsuleBufferSize
, CapsuleNames
, MapFsStr
, CapsuleNum
);
1136 if (Status
!= EFI_SUCCESS
) {
1137 Print (L
"CapsuleApp: failed to update capsule - %r\n", Status
);
1141 gRT
->ResetSystem (ResetType
, EFI_SUCCESS
, 0, NULL
);
1149 // Check whether the input capsule image has the flag of persist across system reset.
1152 Status
= gRT
->UpdateCapsule(CapsuleHeaderArray
,CapsuleNum
,(UINTN
) BlockDescriptors
);
1153 if (Status
!= EFI_SUCCESS
) {
1154 Print (L
"CapsuleApp: failed to update capsule - %r\n", Status
);
1158 // For capsule with CAPSULE_FLAGS_PERSIST_ACROSS_RESET + CAPSULE_FLAGS_INITIATE_RESET,
1159 // a system reset should have been triggered by gRT->UpdateCapsule() calling above.
1161 // For capsule with CAPSULE_FLAGS_PERSIST_ACROSS_RESET and without CAPSULE_FLAGS_INITIATE_RESET,
1162 // check if -NR (no-reset) has been specified or not.
1166 // For capsule who has reset flag and no -NR (no-reset) has been specified, after calling UpdateCapsule service,
1167 // trigger a system reset to process capsule persist across a system reset.
1169 gRT
->ResetSystem (ResetType
, EFI_SUCCESS
, 0, NULL
);
1173 // For capsule who has no reset flag, only call UpdateCapsule Service without a
1174 // system reset. The service will process the capsule immediately.
1176 Status
= gRT
->UpdateCapsule (CapsuleHeaderArray
,CapsuleNum
,(UINTN
) BlockDescriptors
);
1177 if (Status
!= EFI_SUCCESS
) {
1178 Print (L
"CapsuleApp: failed to update capsule - %r\n", Status
);
1182 Status
= EFI_SUCCESS
;
1185 for (Index
= 0; Index
< CapsuleNum
; Index
++) {
1186 if (CapsuleBuffer
[Index
] != NULL
) {
1187 FreePool (CapsuleBuffer
[Index
]);
1191 CleanGatherList(BlockDescriptors
, CapsuleNum
);