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
9 #include "CapsuleApp.h"
12 // Define how many block descriptors we want to test with.
14 UINTN NumberOfDescriptors
= 1;
15 UINTN CapsuleFirstIndex
;
16 UINTN CapsuleLastIndex
;
21 @retval EFI_SUCCESS The capsule header is appended.
22 @retval EFI_UNSUPPORTED Input parameter is not valid.
23 @retval EFI_OUT_OF_RESOURCES No enough resource to create UX capsule.
30 CHAR16
*OutputCapsuleName
;
34 UINT8
*FullCapsuleBuffer
;
35 UINTN FullCapsuleBufferSize
;
36 EFI_DISPLAY_CAPSULE
*DisplayCapsule
;
38 EFI_GRAPHICS_OUTPUT_PROTOCOL
*Gop
;
39 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION
*Info
;
40 EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*GopBlt
;
45 Status
= gBS
->LocateProtocol(&gEfiGraphicsOutputProtocolGuid
, NULL
, (VOID
**)&Gop
);
46 if (EFI_ERROR(Status
)) {
47 Print(L
"CapsuleApp: NO GOP is found.\n");
48 return EFI_UNSUPPORTED
;
50 Info
= Gop
->Mode
->Info
;
51 Print(L
"Current GOP: Mode - %d, ", Gop
->Mode
->Mode
);
52 Print(L
"HorizontalResolution - %d, ", Info
->HorizontalResolution
);
53 Print(L
"VerticalResolution - %d\n", Info
->VerticalResolution
);
54 // HorizontalResolution >= BMP_IMAGE_HEADER.PixelWidth
55 // VerticalResolution >= BMP_IMAGE_HEADER.PixelHeight
58 Print(L
"CapsuleApp: Incorrect parameter count.\n");
59 return EFI_UNSUPPORTED
;
62 if (StrCmp(Argv
[3], L
"-O") != 0) {
63 Print(L
"CapsuleApp: NO output capsule name.\n");
64 return EFI_UNSUPPORTED
;
66 OutputCapsuleName
= Argv
[4];
70 FullCapsuleBuffer
= NULL
;
73 Status
= ReadFileToBuffer(BmpName
, &FileSize
, &BmpBuffer
);
74 if (EFI_ERROR(Status
)) {
75 Print(L
"CapsuleApp: BMP image (%s) is not found.\n", BmpName
);
80 Status
= TranslateBmpToGopBlt (
88 if (EFI_ERROR(Status
)) {
89 Print(L
"CapsuleApp: BMP image (%s) is not valid.\n", BmpName
);
95 Print(L
"BMP image (%s), Width - %d, Height - %d\n", BmpName
, Width
, Height
);
97 if (Height
> Info
->VerticalResolution
) {
98 Status
= EFI_INVALID_PARAMETER
;
99 Print(L
"CapsuleApp: BMP image (%s) height is larger than current resolution.\n", BmpName
);
102 if (Width
> Info
->HorizontalResolution
) {
103 Status
= EFI_INVALID_PARAMETER
;
104 Print(L
"CapsuleApp: BMP image (%s) width is larger than current resolution.\n", BmpName
);
108 FullCapsuleBufferSize
= sizeof(EFI_DISPLAY_CAPSULE
) + FileSize
;
109 FullCapsuleBuffer
= AllocatePool(FullCapsuleBufferSize
);
110 if (FullCapsuleBuffer
== NULL
) {
111 Print(L
"CapsuleApp: Capsule Buffer size (0x%x) too big.\n", FullCapsuleBufferSize
);
112 Status
= EFI_OUT_OF_RESOURCES
;
116 DisplayCapsule
= (EFI_DISPLAY_CAPSULE
*)FullCapsuleBuffer
;
117 CopyGuid(&DisplayCapsule
->CapsuleHeader
.CapsuleGuid
, &gWindowsUxCapsuleGuid
);
118 DisplayCapsule
->CapsuleHeader
.HeaderSize
= sizeof(DisplayCapsule
->CapsuleHeader
);
119 DisplayCapsule
->CapsuleHeader
.Flags
= CAPSULE_FLAGS_PERSIST_ACROSS_RESET
;
120 DisplayCapsule
->CapsuleHeader
.CapsuleImageSize
= (UINT32
)FullCapsuleBufferSize
;
122 DisplayCapsule
->ImagePayload
.Version
= 1;
123 DisplayCapsule
->ImagePayload
.Checksum
= 0;
124 DisplayCapsule
->ImagePayload
.ImageType
= 0; // BMP
125 DisplayCapsule
->ImagePayload
.Reserved
= 0;
126 DisplayCapsule
->ImagePayload
.Mode
= Gop
->Mode
->Mode
;
129 // Center the bitmap horizontally
131 DisplayCapsule
->ImagePayload
.OffsetX
= (UINT32
)((Info
->HorizontalResolution
- Width
) / 2);
134 // Put bitmap 3/4 down the display. If bitmap is too tall, then align bottom
135 // of bitmap at bottom of display.
137 DisplayCapsule
->ImagePayload
.OffsetY
=
139 (UINT32
)(Info
->VerticalResolution
- Height
),
140 (UINT32
)(((3 * Info
->VerticalResolution
) - (2 * Height
)) / 4)
143 Print(L
"BMP image (%s), OffsetX - %d, OffsetY - %d\n",
145 DisplayCapsule
->ImagePayload
.OffsetX
,
146 DisplayCapsule
->ImagePayload
.OffsetY
149 CopyMem((DisplayCapsule
+ 1), BmpBuffer
, FileSize
);
151 DisplayCapsule
->ImagePayload
.Checksum
= CalculateCheckSum8(FullCapsuleBuffer
, FullCapsuleBufferSize
);
153 Status
= WriteFileFromBuffer(OutputCapsuleName
, FullCapsuleBufferSize
, FullCapsuleBuffer
);
154 Print(L
"CapsuleApp: Write %s %r\n", OutputCapsuleName
, Status
);
157 if (BmpBuffer
!= NULL
) {
161 if (FullCapsuleBuffer
!= NULL
) {
162 FreePool(FullCapsuleBuffer
);
169 Get ImageTypeId in the FMP capsule header.
171 @param[in] CapsuleHeader The FMP capsule image header.
176 GetCapsuleImageTypeId (
177 IN EFI_CAPSULE_HEADER
*CapsuleHeader
180 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
*FmpCapsuleHeader
;
181 UINT64
*ItemOffsetList
;
182 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
*ImageHeader
;
184 FmpCapsuleHeader
= (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
*)((UINT8
*)CapsuleHeader
+ CapsuleHeader
->HeaderSize
);
185 ItemOffsetList
= (UINT64
*)(FmpCapsuleHeader
+ 1);
186 if (FmpCapsuleHeader
->PayloadItemCount
== 0) {
189 ImageHeader
= (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
*)((UINT8
*)FmpCapsuleHeader
+ ItemOffsetList
[FmpCapsuleHeader
->EmbeddedDriverCount
]);
190 return &ImageHeader
->UpdateImageTypeId
;
194 Get ESRT FwType according to ImageTypeId
196 @param[in] ImageTypeId ImageTypeId of an FMP capsule.
202 IN EFI_GUID
*ImageTypeId
206 EFI_SYSTEM_RESOURCE_TABLE
*Esrt
;
207 EFI_SYSTEM_RESOURCE_ENTRY
*EsrtEntry
;
213 Status
= EfiGetSystemConfigurationTable(&gEfiSystemResourceTableGuid
, (VOID
**)&Esrt
);
214 if (!EFI_ERROR(Status
)) {
215 ASSERT(Esrt
!= NULL
);
216 EsrtEntry
= (VOID
*)(Esrt
+ 1);
217 for (Index
= 0; Index
< Esrt
->FwResourceCount
; Index
++, EsrtEntry
++) {
218 if (CompareGuid(&EsrtEntry
->FwClass
, ImageTypeId
)) {
219 return EsrtEntry
->FwType
;
224 return ESRT_FW_TYPE_UNKNOWN
;
228 Validate if it is valid capsule header
230 This function assumes the caller provided correct CapsuleHeader pointer
233 This function validates the fields in EFI_CAPSULE_HEADER.
235 @param[in] CapsuleHeader Points to a capsule header.
236 @param[in] CapsuleSize Size of the whole capsule image.
240 IsValidCapsuleHeader (
241 IN EFI_CAPSULE_HEADER
*CapsuleHeader
,
242 IN UINT64 CapsuleSize
245 if (CapsuleSize
< sizeof (EFI_CAPSULE_HEADER
)) {
248 if (CapsuleHeader
->CapsuleImageSize
!= CapsuleSize
) {
251 if (CapsuleHeader
->HeaderSize
> CapsuleHeader
->CapsuleImageSize
) {
254 if (CapsuleHeader
->HeaderSize
< sizeof (EFI_CAPSULE_HEADER
)) {
262 Return if this CapsuleGuid is a FMP capsule GUID or not.
264 @param[in] CapsuleGuid A pointer to EFI_GUID
266 @retval TRUE It is a FMP capsule GUID.
267 @retval FALSE It is not a FMP capsule GUID.
271 IN EFI_GUID
*CapsuleGuid
274 if (CompareGuid(&gEfiFmpCapsuleGuid
, CapsuleGuid
)) {
282 Append a capsule header on top of current image.
283 This function follows Windows UEFI Firmware Update Platform document.
285 @retval EFI_SUCCESS The capsule header is appended.
286 @retval EFI_UNSUPPORTED Input parameter is not valid.
287 @retval EFI_OUT_OF_RESOURCES No enough resource to append capsule header.
294 CHAR16
*OutputCapsuleName
;
298 UINT8
*FullCapsuleBuffer
;
299 UINTN FullCapsuleBufferSize
;
300 EFI_CAPSULE_HEADER
*NestedCapsuleHeader
;
301 EFI_GUID
*ImageTypeId
;
306 Print(L
"CapsuleApp: Incorrect parameter count.\n");
307 return EFI_UNSUPPORTED
;
310 if (StrCmp(Argv
[3], L
"-O") != 0) {
311 Print(L
"CapsuleApp: NO output capsule name.\n");
312 return EFI_UNSUPPORTED
;
314 OutputCapsuleName
= Argv
[4];
316 CapsuleBuffer
= NULL
;
318 FullCapsuleBuffer
= NULL
;
320 CapsuleName
= Argv
[2];
321 Status
= ReadFileToBuffer(CapsuleName
, &FileSize
, &CapsuleBuffer
);
322 if (EFI_ERROR(Status
)) {
323 Print(L
"CapsuleApp: Capsule image (%s) is not found.\n", CapsuleName
);
326 if (!IsValidCapsuleHeader (CapsuleBuffer
, FileSize
)) {
327 Print(L
"CapsuleApp: Capsule image (%s) is not a valid capsule.\n", CapsuleName
);
328 Status
= EFI_INVALID_PARAMETER
;
332 if (!IsFmpCapsuleGuid (&((EFI_CAPSULE_HEADER
*) CapsuleBuffer
)->CapsuleGuid
)) {
333 Print(L
"CapsuleApp: Capsule image (%s) is not a FMP capsule.\n", CapsuleName
);
334 Status
= EFI_INVALID_PARAMETER
;
338 ImageTypeId
= GetCapsuleImageTypeId(CapsuleBuffer
);
339 if (ImageTypeId
== NULL
) {
340 Print(L
"CapsuleApp: Capsule ImageTypeId is not found.\n");
341 Status
= EFI_INVALID_PARAMETER
;
344 FwType
= GetEsrtFwType(ImageTypeId
);
345 if ((FwType
!= ESRT_FW_TYPE_SYSTEMFIRMWARE
) && (FwType
!= ESRT_FW_TYPE_DEVICEFIRMWARE
)) {
346 Print(L
"CapsuleApp: Capsule FwType is invalid.\n");
347 Status
= EFI_INVALID_PARAMETER
;
351 FullCapsuleBufferSize
= NESTED_CAPSULE_HEADER_SIZE
+ FileSize
;
352 FullCapsuleBuffer
= AllocatePool(FullCapsuleBufferSize
);
353 if (FullCapsuleBuffer
== NULL
) {
354 Print(L
"CapsuleApp: Capsule Buffer size (0x%x) too big.\n", FullCapsuleBufferSize
);
355 Status
= EFI_OUT_OF_RESOURCES
;
359 NestedCapsuleHeader
= (EFI_CAPSULE_HEADER
*)FullCapsuleBuffer
;
360 ZeroMem(NestedCapsuleHeader
, NESTED_CAPSULE_HEADER_SIZE
);
361 CopyGuid(&NestedCapsuleHeader
->CapsuleGuid
, ImageTypeId
);
362 NestedCapsuleHeader
->HeaderSize
= NESTED_CAPSULE_HEADER_SIZE
;
363 NestedCapsuleHeader
->Flags
= (FwType
== ESRT_FW_TYPE_SYSTEMFIRMWARE
) ? SYSTEM_FIRMWARE_FLAG
: DEVICE_FIRMWARE_FLAG
;
364 NestedCapsuleHeader
->CapsuleImageSize
= (UINT32
)FullCapsuleBufferSize
;
366 CopyMem((UINT8
*)NestedCapsuleHeader
+ NestedCapsuleHeader
->HeaderSize
, CapsuleBuffer
, FileSize
);
368 Status
= WriteFileFromBuffer(OutputCapsuleName
, FullCapsuleBufferSize
, FullCapsuleBuffer
);
369 Print(L
"CapsuleApp: Write %s %r\n", OutputCapsuleName
, Status
);
372 if (CapsuleBuffer
!= NULL
) {
373 FreePool(CapsuleBuffer
);
376 if (FullCapsuleBuffer
!= NULL
) {
377 FreePool(FullCapsuleBuffer
);
385 Clear capsule status variable.
387 @retval EFI_SUCCESS The capsule status variable is cleared.
390 ClearCapsuleStatusVariable (
396 CHAR16 CapsuleVarName
[20];
400 StrCpyS (CapsuleVarName
, sizeof(CapsuleVarName
)/sizeof(CapsuleVarName
[0]), L
"Capsule");
401 TempVarName
= CapsuleVarName
+ StrLen (CapsuleVarName
);
406 UnicodeSPrint (TempVarName
, 5 * sizeof(CHAR16
), L
"%04x", Index
);
408 Status
= gRT
->SetVariable (
410 &gEfiCapsuleReportGuid
,
411 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
,
415 if (Status
== EFI_NOT_FOUND
) {
417 // There is no more capsule variables, quit
423 Print (L
"Clear %s %r\n", CapsuleVarName
, Status
);
426 if (Index
> 0xFFFF) {
432 Print (L
"No any Capsule#### variable found\n");
439 Build Gather list for a list of capsule images.
441 @param[in] CapsuleBuffer An array of pointer to capsule images
442 @param[in] FileSize An array of UINTN to capsule images size
443 @param[in] CapsuleNum The count of capsule images
444 @param[out] BlockDescriptors The block descriptors for the capsule images
446 @retval EFI_SUCCESS The block descriptors for the capsule images are constructed.
450 IN VOID
**CapsuleBuffer
,
453 OUT EFI_CAPSULE_BLOCK_DESCRIPTOR
**BlockDescriptors
457 EFI_CAPSULE_BLOCK_DESCRIPTOR
*BlockDescriptors1
;
458 EFI_CAPSULE_BLOCK_DESCRIPTOR
*BlockDescriptors2
;
459 EFI_CAPSULE_BLOCK_DESCRIPTOR
*BlockDescriptorPre
;
460 EFI_CAPSULE_BLOCK_DESCRIPTOR
*BlockDescriptorsHeader
;
461 EFI_CAPSULE_BLOCK_DESCRIPTOR
*TempBlockPtr
;
470 BlockDescriptors1
= NULL
;
471 BlockDescriptors2
= NULL
;
472 BlockDescriptorPre
= NULL
;
473 BlockDescriptorsHeader
= NULL
;
475 for (Index
= 0; Index
< CapsuleNum
; Index
++) {
477 // Allocate memory for the descriptors.
479 if (NumberOfDescriptors
== 1) {
482 Count
= (INT32
)(NumberOfDescriptors
+ 2) / 2;
485 Size
= Count
* sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR
);
486 BlockDescriptors1
= AllocateRuntimeZeroPool (Size
);
487 if (BlockDescriptors1
== NULL
) {
488 Print (L
"CapsuleApp: failed to allocate memory for descriptors\n");
489 Status
= EFI_OUT_OF_RESOURCES
;
492 Print (L
"CapsuleApp: creating capsule descriptors at 0x%X\n", (UINTN
) BlockDescriptors1
);
493 Print (L
"CapsuleApp: capsule data starts at 0x%X with size 0x%X\n", (UINTN
) CapsuleBuffer
[Index
], FileSize
[Index
]);
497 // Record descriptor header
500 BlockDescriptorsHeader
= BlockDescriptors1
;
503 if (BlockDescriptorPre
!= NULL
) {
504 BlockDescriptorPre
->Union
.ContinuationPointer
= (UINTN
) BlockDescriptors1
;
505 BlockDescriptorPre
->Length
= 0;
511 TempBlockPtr
= BlockDescriptors1
;
512 TempDataPtr
= CapsuleBuffer
[Index
];
513 SizeLeft
= FileSize
[Index
];
514 for (Number
= 0; (Number
< Count
- 1) && (SizeLeft
!= 0); Number
++) {
516 // Divide remaining data in half
518 if (NumberOfDescriptors
!= 1) {
527 TempBlockPtr
->Union
.DataBlock
= (UINTN
)TempDataPtr
;
528 TempBlockPtr
->Length
= Size
;
529 Print (L
"CapsuleApp: capsule block/size 0x%X/0x%X\n", (UINTN
) TempDataPtr
, Size
);
536 // Allocate the second list, point the first block's last entry to point
537 // to this one, and fill this one in. Worst case is that the previous
538 // list only had one element that pointed here, so we need at least two
539 // elements -- one to point to all the data, another to terminate the list.
541 if ((NumberOfDescriptors
!= 1) && (SizeLeft
!= 0)) {
542 Count
= (INT32
)(NumberOfDescriptors
+ 2) - Count
;
547 Size
= Count
* sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR
);
548 BlockDescriptors2
= AllocateRuntimeZeroPool (Size
);
549 if (BlockDescriptors2
== NULL
) {
550 Print (L
"CapsuleApp: failed to allocate memory for descriptors\n");
551 Status
= EFI_OUT_OF_RESOURCES
;
556 // Point the first list's last element to point to this second list.
558 TempBlockPtr
->Union
.ContinuationPointer
= (UINTN
) BlockDescriptors2
;
560 TempBlockPtr
->Length
= 0;
561 TempBlockPtr
= BlockDescriptors2
;
562 for (Number
= 0; Number
< Count
- 1; Number
++) {
564 // If second-to-last one, then dump rest to this element
566 if (Number
== (Count
- 2)) {
570 // Divide remaining data in half
579 TempBlockPtr
->Union
.DataBlock
= (UINTN
)TempDataPtr
;
580 TempBlockPtr
->Length
= Size
;
581 Print (L
"CapsuleApp: capsule block/size 0x%X/0x%X\n", (UINTN
) TempDataPtr
, Size
);
591 BlockDescriptorPre
= TempBlockPtr
;
592 BlockDescriptors1
= NULL
;
598 if (TempBlockPtr
!= NULL
) {
599 TempBlockPtr
->Union
.ContinuationPointer
= (UINTN
)NULL
;
600 TempBlockPtr
->Length
= 0;
601 *BlockDescriptors
= BlockDescriptorsHeader
;
607 if (BlockDescriptors1
!= NULL
) {
608 FreePool(BlockDescriptors1
);
611 if (BlockDescriptors2
!= NULL
) {
612 FreePool(BlockDescriptors2
);
619 Clear the Gather list for a list of capsule images.
621 @param[in] BlockDescriptors The block descriptors for the capsule images
622 @param[in] CapsuleNum The count of capsule images
626 IN EFI_CAPSULE_BLOCK_DESCRIPTOR
*BlockDescriptors
,
630 EFI_CAPSULE_BLOCK_DESCRIPTOR
*TempBlockPtr
;
631 EFI_CAPSULE_BLOCK_DESCRIPTOR
*TempBlockPtr1
;
632 EFI_CAPSULE_BLOCK_DESCRIPTOR
*TempBlockPtr2
;
635 if (BlockDescriptors
!= NULL
) {
636 TempBlockPtr1
= BlockDescriptors
;
638 TempBlockPtr
= TempBlockPtr1
;
639 for (Index
= 0; Index
< CapsuleNum
; Index
++) {
640 if (TempBlockPtr
[Index
].Length
== 0) {
645 if (TempBlockPtr
[Index
].Union
.ContinuationPointer
== (UINTN
)NULL
) {
649 TempBlockPtr2
= (VOID
*) ((UINTN
) TempBlockPtr
[Index
].Union
.ContinuationPointer
);
650 FreePool(TempBlockPtr1
);
651 TempBlockPtr1
= TempBlockPtr2
;
664 Print(L
"CapsuleApp: usage\n");
665 Print(L
" CapsuleApp <Capsule...> [-NR] [-OD [FSx]]\n");
666 Print(L
" CapsuleApp -S\n");
667 Print(L
" CapsuleApp -C\n");
668 Print(L
" CapsuleApp -P\n");
669 Print(L
" CapsuleApp -E\n");
670 Print(L
" CapsuleApp -L\n");
671 Print(L
" CapsuleApp -L INFO\n");
672 Print(L
" CapsuleApp -F\n");
673 Print(L
" CapsuleApp -G <BMP> -O <Capsule>\n");
674 Print(L
" CapsuleApp -N <Capsule> -O <NestedCapsule>\n");
675 Print(L
" CapsuleApp -D <Capsule>\n");
676 Print(L
" CapsuleApp -P GET <ImageTypeId> <Index> -O <FileName>\n");
677 Print(L
"Parameter:\n");
678 Print(L
" -NR: No reset will be triggered for the capsule\n");
679 Print(L
" with CAPSULE_FLAGS_PERSIST_ACROSS_RESET and without CAPSULE_FLAGS_INITIATE_RESET.\n");
680 Print(L
" -OD: Delivery of Capsules via file on Mass Storage device.\n");
681 Print(L
" -S: Dump capsule report variable (EFI_CAPSULE_REPORT_GUID),\n");
682 Print(L
" which is defined in UEFI specification.\n");
683 Print(L
" -C: Clear capsule report variable (EFI_CAPSULE_REPORT_GUID),\n");
684 Print(L
" which is defined in UEFI specification.\n");
685 Print(L
" -P: Dump UEFI FMP protocol info, or get image with specified\n");
686 Print(L
" ImageTypeId and Index (decimal format) to a file if 'GET'\n");
687 Print(L
" option is used.\n");
688 Print(L
" -E: Dump UEFI ESRT table info.\n");
689 Print(L
" -L: Dump provisioned capsule image information.\n");
690 Print(L
" -F: Dump all EFI System Partition.\n");
691 Print(L
" -G: Convert a BMP file to be an UX capsule,\n");
692 Print(L
" according to Windows Firmware Update document\n");
693 Print(L
" -N: Append a Capsule Header to an existing FMP capsule image\n");
694 Print(L
" with its ImageTypeId supported by the system,\n");
695 Print(L
" according to Windows Firmware Update document\n");
696 Print(L
" -O: Output new Capsule file name\n");
697 Print(L
" -D: Dump Capsule image header information, image payload\n");
698 Print(L
" information if it is an UX capsule and FMP header\n");
699 Print(L
" information if it is a FMP capsule.\n");
703 Update Capsule image.
705 @param[in] ImageHandle The image handle.
706 @param[in] SystemTable The system table.
708 @retval EFI_SUCCESS Command completed successfully.
709 @retval EFI_UNSUPPORTED Command usage unsupported.
710 @retval EFI_INVALID_PARAMETER Command usage invalid.
711 @retval EFI_NOT_FOUND The input file can't be found.
716 IN EFI_HANDLE ImageHandle
,
717 IN EFI_SYSTEM_TABLE
*SystemTable
721 RETURN_STATUS RStatus
;
722 UINTN CapsuleBufferSize
[MAX_CAPSULE_NUM
];
723 VOID
*CapsuleBuffer
[MAX_CAPSULE_NUM
];
724 EFI_CAPSULE_BLOCK_DESCRIPTOR
*BlockDescriptors
;
725 EFI_CAPSULE_HEADER
*CapsuleHeaderArray
[MAX_CAPSULE_NUM
+ 1];
726 UINT64 MaxCapsuleSize
;
727 EFI_RESET_TYPE ResetType
;
730 BOOLEAN CapsuleOnDisk
;
732 CHAR16
*CapsuleNames
[MAX_CAPSULE_NUM
];
738 EFI_GUID ImageTypeId
;
741 BlockDescriptors
= NULL
;
746 if (EFI_ERROR(Status
)) {
747 Print(L
"Please use UEFI SHELL to run this application!\n", Status
);
752 return EFI_UNSUPPORTED
;
754 if (StrCmp(Argv
[1], L
"-D") == 0) {
756 Print(L
"CapsuleApp: Incorrect parameter count.\n");
757 return EFI_UNSUPPORTED
;
759 Status
= DumpCapsule(Argv
[2]);
762 if (StrCmp(Argv
[1], L
"-G") == 0) {
763 Status
= CreateBmpFmp();
766 if (StrCmp(Argv
[1], L
"-N") == 0) {
767 Status
= CreateNestedFmp();
770 if (StrCmp(Argv
[1], L
"-S") == 0) {
771 Status
= DumpCapsuleStatusVariable();
774 if (StrCmp(Argv
[1], L
"-C") == 0) {
775 Status
= ClearCapsuleStatusVariable();
778 if (StrCmp(Argv
[1], L
"-P") == 0) {
783 if (StrCmp(Argv
[2], L
"GET") != 0) {
784 Print(L
"CapsuleApp: Unrecognized option(%s).\n", Argv
[2]);
785 return EFI_UNSUPPORTED
;
788 Print(L
"CapsuleApp: Incorrect parameter count.\n");
789 return EFI_UNSUPPORTED
;
795 RStatus
= StrToGuid (Argv
[3], &ImageTypeId
);
796 if (RETURN_ERROR (RStatus
) || (Argv
[3][GUID_STRING_LENGTH
] != L
'\0')) {
797 Print (L
"Invalid ImageTypeId - %s\n", Argv
[3]);
798 return EFI_INVALID_PARAMETER
;
800 ImageIndex
= StrDecimalToUintn(Argv
[4]);
801 if (StrCmp(Argv
[5], L
"-O") != 0) {
802 Print(L
"CapsuleApp: NO output file name.\n");
803 return EFI_UNSUPPORTED
;
805 DumpFmpImage(&ImageTypeId
, ImageIndex
, Argv
[6]);
811 if (StrCmp(Argv
[1], L
"-E") == 0) {
816 if (StrCmp(Argv
[1], L
"-L") == 0) {
817 if (Argc
>= 3 && StrCmp(Argv
[2], L
"INFO") == 0) {
818 DumpProvisionedCapsule(TRUE
);
820 DumpProvisionedCapsule(FALSE
);
825 if (StrCmp(Argv
[1], L
"-F") == 0) {
826 DumpAllEfiSysPartition();
830 if (Argv
[1][0] == L
'-') {
831 Print(L
"CapsuleApp: Unrecognized option(%s).\n", Argv
[1]);
832 return EFI_UNSUPPORTED
;
835 CapsuleFirstIndex
= 1;
837 CapsuleOnDisk
= FALSE
;
841 for (Index
= 1; Index
< Argc
; Index
++) {
842 if (StrCmp(Argv
[Index
], L
"-OD") == 0) {
844 CapsuleOnDisk
= TRUE
;
845 } else if (StrCmp(Argv
[Index
], L
"-NR") == 0) {
851 if (ParaOdIndex
> ParaNrIndex
) {
852 if (ParaNrIndex
!= 0) {
853 CapsuleLastIndex
= ParaNrIndex
- 1;
855 CapsuleLastIndex
= ParaOdIndex
- 1;
858 if (ParaOdIndex
== Argc
-1) {
860 } else if (ParaOdIndex
== Argc
- 2) {
861 MapFsStr
= Argv
[Argc
-1];
863 Print (L
"CapsuleApp: Cannot specify more than one FS mapping!\n");
864 Status
= EFI_INVALID_PARAMETER
;
867 } else if (ParaOdIndex
< ParaNrIndex
) {
868 if (ParaOdIndex
!= 0) {
869 CapsuleLastIndex
= ParaOdIndex
- 1;
870 if (ParaOdIndex
== ParaNrIndex
- 1) {
872 } else if (ParaOdIndex
== ParaNrIndex
- 2) {
873 MapFsStr
= Argv
[ParaOdIndex
+ 1];
875 Print (L
"CapsuleApp: Cannot specify more than one FS mapping!\n");
876 Status
= EFI_INVALID_PARAMETER
;
880 CapsuleLastIndex
= ParaNrIndex
- 1;
883 CapsuleLastIndex
= Argc
- 1;
886 CapsuleNum
= CapsuleLastIndex
- CapsuleFirstIndex
+ 1;
888 if (CapsuleFirstIndex
> CapsuleLastIndex
) {
889 Print(L
"CapsuleApp: NO capsule image.\n");
890 return EFI_UNSUPPORTED
;
892 if (CapsuleNum
> MAX_CAPSULE_NUM
) {
893 Print(L
"CapsuleApp: Too many capsule images.\n");
894 return EFI_UNSUPPORTED
;
897 ZeroMem(&CapsuleBuffer
, sizeof(CapsuleBuffer
));
898 ZeroMem(&CapsuleBufferSize
, sizeof(CapsuleBufferSize
));
899 BlockDescriptors
= NULL
;
901 for (Index
= 0; Index
< CapsuleNum
; Index
++) {
902 CapsuleName
= Argv
[CapsuleFirstIndex
+ Index
];
903 Status
= ReadFileToBuffer(CapsuleName
, &CapsuleBufferSize
[Index
], &CapsuleBuffer
[Index
]);
904 if (EFI_ERROR(Status
)) {
905 Print(L
"CapsuleApp: capsule image (%s) is not found.\n", CapsuleName
);
908 if (!IsValidCapsuleHeader (CapsuleBuffer
[Index
], CapsuleBufferSize
[Index
])) {
909 Print(L
"CapsuleApp: Capsule image (%s) is not a valid capsule.\n", CapsuleName
);
910 return EFI_INVALID_PARAMETER
;
912 CapsuleNames
[Index
] = CapsuleName
;
916 // Every capsule use 2 descriptor 1 for data 1 for end
918 Status
= BuildGatherList(CapsuleBuffer
, CapsuleBufferSize
, CapsuleNum
, &BlockDescriptors
);
919 if (EFI_ERROR(Status
)) {
924 // Call the runtime service capsule.
927 for (Index
= 0; Index
< CapsuleNum
; Index
++) {
928 CapsuleHeaderArray
[Index
] = (EFI_CAPSULE_HEADER
*) CapsuleBuffer
[Index
];
929 if ((CapsuleHeaderArray
[Index
]->Flags
& CAPSULE_FLAGS_PERSIST_ACROSS_RESET
) != 0) {
933 CapsuleHeaderArray
[CapsuleNum
] = NULL
;
936 // Inquire platform capability of UpdateCapsule.
938 Status
= gRT
->QueryCapsuleCapabilities (CapsuleHeaderArray
, CapsuleNum
, &MaxCapsuleSize
, &ResetType
);
939 if (EFI_ERROR(Status
)) {
940 Print (L
"CapsuleApp: failed to query capsule capability - %r\n", Status
);
944 for (Index
= 0; Index
< CapsuleNum
; Index
++) {
945 if (CapsuleBufferSize
[Index
] > MaxCapsuleSize
) {
946 Print (L
"CapsuleApp: capsule is too large to update, %ld is allowed\n", MaxCapsuleSize
);
947 Status
= EFI_UNSUPPORTED
;
953 // Check whether is capsule on disk.
956 Status
= ProcessCapsuleOnDisk (CapsuleBuffer
, CapsuleBufferSize
, CapsuleNames
, MapFsStr
, CapsuleNum
);
957 if (Status
!= EFI_SUCCESS
) {
958 Print (L
"CapsuleApp: failed to update capsule - %r\n", Status
);
962 gRT
->ResetSystem (ResetType
, EFI_SUCCESS
, 0, NULL
);
970 // Check whether the input capsule image has the flag of persist across system reset.
973 Status
= gRT
->UpdateCapsule(CapsuleHeaderArray
,CapsuleNum
,(UINTN
) BlockDescriptors
);
974 if (Status
!= EFI_SUCCESS
) {
975 Print (L
"CapsuleApp: failed to update capsule - %r\n", Status
);
979 // For capsule with CAPSULE_FLAGS_PERSIST_ACROSS_RESET + CAPSULE_FLAGS_INITIATE_RESET,
980 // a system reset should have been triggered by gRT->UpdateCapsule() calling above.
982 // For capsule with CAPSULE_FLAGS_PERSIST_ACROSS_RESET and without CAPSULE_FLAGS_INITIATE_RESET,
983 // check if -NR (no-reset) has been specified or not.
987 // For capsule who has reset flag and no -NR (no-reset) has been specified, after calling UpdateCapsule service,
988 // trigger a system reset to process capsule persist across a system reset.
990 gRT
->ResetSystem (ResetType
, EFI_SUCCESS
, 0, NULL
);
994 // For capsule who has no reset flag, only call UpdateCapsule Service without a
995 // system reset. The service will process the capsule immediately.
997 Status
= gRT
->UpdateCapsule (CapsuleHeaderArray
,CapsuleNum
,(UINTN
) BlockDescriptors
);
998 if (Status
!= EFI_SUCCESS
) {
999 Print (L
"CapsuleApp: failed to update capsule - %r\n", Status
);
1003 Status
= EFI_SUCCESS
;
1006 for (Index
= 0; Index
< CapsuleNum
; Index
++) {
1007 if (CapsuleBuffer
[Index
] != NULL
) {
1008 FreePool (CapsuleBuffer
[Index
]);
1012 CleanGatherList(BlockDescriptors
, CapsuleNum
);