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
;
51 Info
= Gop
->Mode
->Info
;
52 Print (L
"Current GOP: Mode - %d, ", Gop
->Mode
->Mode
);
53 Print (L
"HorizontalResolution - %d, ", Info
->HorizontalResolution
);
54 Print (L
"VerticalResolution - %d\n", Info
->VerticalResolution
);
55 // HorizontalResolution >= BMP_IMAGE_HEADER.PixelWidth
56 // VerticalResolution >= BMP_IMAGE_HEADER.PixelHeight
59 Print (L
"CapsuleApp: Incorrect parameter count.\n");
60 return EFI_UNSUPPORTED
;
63 if (StrCmp (Argv
[3], L
"-O") != 0) {
64 Print (L
"CapsuleApp: NO output capsule name.\n");
65 return EFI_UNSUPPORTED
;
68 OutputCapsuleName
= Argv
[4];
72 FullCapsuleBuffer
= NULL
;
75 Status
= ReadFileToBuffer (BmpName
, &FileSize
, &BmpBuffer
);
76 if (EFI_ERROR (Status
)) {
77 Print (L
"CapsuleApp: BMP image (%s) is not found.\n", BmpName
);
82 Status
= TranslateBmpToGopBlt (
90 if (EFI_ERROR (Status
)) {
91 Print (L
"CapsuleApp: BMP image (%s) is not valid.\n", BmpName
);
99 Print (L
"BMP image (%s), Width - %d, Height - %d\n", BmpName
, Width
, Height
);
101 if (Height
> Info
->VerticalResolution
) {
102 Status
= EFI_INVALID_PARAMETER
;
103 Print (L
"CapsuleApp: BMP image (%s) height is larger than current resolution.\n", BmpName
);
107 if (Width
> Info
->HorizontalResolution
) {
108 Status
= EFI_INVALID_PARAMETER
;
109 Print (L
"CapsuleApp: BMP image (%s) width is larger than current resolution.\n", BmpName
);
113 FullCapsuleBufferSize
= sizeof (EFI_DISPLAY_CAPSULE
) + FileSize
;
114 FullCapsuleBuffer
= AllocatePool (FullCapsuleBufferSize
);
115 if (FullCapsuleBuffer
== NULL
) {
116 Print (L
"CapsuleApp: Capsule Buffer size (0x%x) too big.\n", FullCapsuleBufferSize
);
117 Status
= EFI_OUT_OF_RESOURCES
;
121 DisplayCapsule
= (EFI_DISPLAY_CAPSULE
*)FullCapsuleBuffer
;
122 CopyGuid (&DisplayCapsule
->CapsuleHeader
.CapsuleGuid
, &gWindowsUxCapsuleGuid
);
123 DisplayCapsule
->CapsuleHeader
.HeaderSize
= sizeof (DisplayCapsule
->CapsuleHeader
);
124 DisplayCapsule
->CapsuleHeader
.Flags
= CAPSULE_FLAGS_PERSIST_ACROSS_RESET
;
125 DisplayCapsule
->CapsuleHeader
.CapsuleImageSize
= (UINT32
)FullCapsuleBufferSize
;
127 DisplayCapsule
->ImagePayload
.Version
= 1;
128 DisplayCapsule
->ImagePayload
.Checksum
= 0;
129 DisplayCapsule
->ImagePayload
.ImageType
= 0; // BMP
130 DisplayCapsule
->ImagePayload
.Reserved
= 0;
131 DisplayCapsule
->ImagePayload
.Mode
= Gop
->Mode
->Mode
;
134 // Center the bitmap horizontally
136 DisplayCapsule
->ImagePayload
.OffsetX
= (UINT32
)((Info
->HorizontalResolution
- Width
) / 2);
139 // Put bitmap 3/4 down the display. If bitmap is too tall, then align bottom
140 // of bitmap at bottom of display.
142 DisplayCapsule
->ImagePayload
.OffsetY
=
144 (UINT32
)(Info
->VerticalResolution
- Height
),
145 (UINT32
)(((3 * Info
->VerticalResolution
) - (2 * Height
)) / 4)
149 L
"BMP image (%s), OffsetX - %d, OffsetY - %d\n",
151 DisplayCapsule
->ImagePayload
.OffsetX
,
152 DisplayCapsule
->ImagePayload
.OffsetY
155 CopyMem ((DisplayCapsule
+ 1), BmpBuffer
, FileSize
);
157 DisplayCapsule
->ImagePayload
.Checksum
= CalculateCheckSum8 (FullCapsuleBuffer
, FullCapsuleBufferSize
);
159 Status
= WriteFileFromBuffer (OutputCapsuleName
, FullCapsuleBufferSize
, FullCapsuleBuffer
);
160 Print (L
"CapsuleApp: Write %s %r\n", OutputCapsuleName
, Status
);
163 if (BmpBuffer
!= NULL
) {
164 FreePool (BmpBuffer
);
167 if (FullCapsuleBuffer
!= NULL
) {
168 FreePool (FullCapsuleBuffer
);
175 Get ImageTypeId in the FMP capsule header.
177 @param[in] CapsuleHeader The FMP capsule image header.
182 GetCapsuleImageTypeId (
183 IN EFI_CAPSULE_HEADER
*CapsuleHeader
186 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
*FmpCapsuleHeader
;
187 UINT64
*ItemOffsetList
;
188 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
*ImageHeader
;
190 FmpCapsuleHeader
= (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
*)((UINT8
*)CapsuleHeader
+ CapsuleHeader
->HeaderSize
);
191 ItemOffsetList
= (UINT64
*)(FmpCapsuleHeader
+ 1);
192 if (FmpCapsuleHeader
->PayloadItemCount
== 0) {
196 ImageHeader
= (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
*)((UINT8
*)FmpCapsuleHeader
+ ItemOffsetList
[FmpCapsuleHeader
->EmbeddedDriverCount
]);
197 return &ImageHeader
->UpdateImageTypeId
;
201 Get ESRT FwType according to ImageTypeId
203 @param[in] ImageTypeId ImageTypeId of an FMP capsule.
209 IN EFI_GUID
*ImageTypeId
213 EFI_SYSTEM_RESOURCE_TABLE
*Esrt
;
214 EFI_SYSTEM_RESOURCE_ENTRY
*EsrtEntry
;
220 Status
= EfiGetSystemConfigurationTable (&gEfiSystemResourceTableGuid
, (VOID
**)&Esrt
);
221 if (!EFI_ERROR (Status
)) {
222 ASSERT (Esrt
!= NULL
);
223 EsrtEntry
= (VOID
*)(Esrt
+ 1);
224 for (Index
= 0; Index
< Esrt
->FwResourceCount
; Index
++, EsrtEntry
++) {
225 if (CompareGuid (&EsrtEntry
->FwClass
, ImageTypeId
)) {
226 return EsrtEntry
->FwType
;
231 return ESRT_FW_TYPE_UNKNOWN
;
235 Validate if it is valid capsule header
237 This function assumes the caller provided correct CapsuleHeader pointer
240 This function validates the fields in EFI_CAPSULE_HEADER.
242 @param[in] CapsuleHeader Points to a capsule header.
243 @param[in] CapsuleSize Size of the whole capsule image.
247 IsValidCapsuleHeader (
248 IN EFI_CAPSULE_HEADER
*CapsuleHeader
,
249 IN UINT64 CapsuleSize
252 if (CapsuleSize
< sizeof (EFI_CAPSULE_HEADER
)) {
256 if (CapsuleHeader
->CapsuleImageSize
!= CapsuleSize
) {
260 if (CapsuleHeader
->HeaderSize
> CapsuleHeader
->CapsuleImageSize
) {
264 if (CapsuleHeader
->HeaderSize
< sizeof (EFI_CAPSULE_HEADER
)) {
272 Return if this CapsuleGuid is a FMP capsule GUID or not.
274 @param[in] CapsuleGuid A pointer to EFI_GUID
276 @retval TRUE It is a FMP capsule GUID.
277 @retval FALSE It is not a FMP capsule GUID.
281 IN EFI_GUID
*CapsuleGuid
284 if (CompareGuid (&gEfiFmpCapsuleGuid
, CapsuleGuid
)) {
292 Append a capsule header on top of current image.
293 This function follows Windows UEFI Firmware Update Platform document.
295 @retval EFI_SUCCESS The capsule header is appended.
296 @retval EFI_UNSUPPORTED Input parameter is not valid.
297 @retval EFI_OUT_OF_RESOURCES No enough resource to append capsule header.
304 CHAR16
*OutputCapsuleName
;
308 UINT8
*FullCapsuleBuffer
;
309 UINTN FullCapsuleBufferSize
;
310 EFI_CAPSULE_HEADER
*NestedCapsuleHeader
;
311 EFI_GUID
*ImageTypeId
;
316 Print (L
"CapsuleApp: Incorrect parameter count.\n");
317 return EFI_UNSUPPORTED
;
320 if (StrCmp (Argv
[3], L
"-O") != 0) {
321 Print (L
"CapsuleApp: NO output capsule name.\n");
322 return EFI_UNSUPPORTED
;
325 OutputCapsuleName
= Argv
[4];
327 CapsuleBuffer
= NULL
;
329 FullCapsuleBuffer
= NULL
;
331 CapsuleName
= Argv
[2];
332 Status
= ReadFileToBuffer (CapsuleName
, &FileSize
, &CapsuleBuffer
);
333 if (EFI_ERROR (Status
)) {
334 Print (L
"CapsuleApp: Capsule image (%s) is not found.\n", CapsuleName
);
338 if (!IsValidCapsuleHeader (CapsuleBuffer
, FileSize
)) {
339 Print (L
"CapsuleApp: Capsule image (%s) is not a valid capsule.\n", CapsuleName
);
340 Status
= EFI_INVALID_PARAMETER
;
344 if (!IsFmpCapsuleGuid (&((EFI_CAPSULE_HEADER
*)CapsuleBuffer
)->CapsuleGuid
)) {
345 Print (L
"CapsuleApp: Capsule image (%s) is not a FMP capsule.\n", CapsuleName
);
346 Status
= EFI_INVALID_PARAMETER
;
350 ImageTypeId
= GetCapsuleImageTypeId (CapsuleBuffer
);
351 if (ImageTypeId
== NULL
) {
352 Print (L
"CapsuleApp: Capsule ImageTypeId is not found.\n");
353 Status
= EFI_INVALID_PARAMETER
;
357 FwType
= GetEsrtFwType (ImageTypeId
);
358 if ((FwType
!= ESRT_FW_TYPE_SYSTEMFIRMWARE
) && (FwType
!= ESRT_FW_TYPE_DEVICEFIRMWARE
)) {
359 Print (L
"CapsuleApp: Capsule FwType is invalid.\n");
360 Status
= EFI_INVALID_PARAMETER
;
364 FullCapsuleBufferSize
= NESTED_CAPSULE_HEADER_SIZE
+ FileSize
;
365 FullCapsuleBuffer
= AllocatePool (FullCapsuleBufferSize
);
366 if (FullCapsuleBuffer
== NULL
) {
367 Print (L
"CapsuleApp: Capsule Buffer size (0x%x) too big.\n", FullCapsuleBufferSize
);
368 Status
= EFI_OUT_OF_RESOURCES
;
372 NestedCapsuleHeader
= (EFI_CAPSULE_HEADER
*)FullCapsuleBuffer
;
373 ZeroMem (NestedCapsuleHeader
, NESTED_CAPSULE_HEADER_SIZE
);
374 CopyGuid (&NestedCapsuleHeader
->CapsuleGuid
, ImageTypeId
);
375 NestedCapsuleHeader
->HeaderSize
= NESTED_CAPSULE_HEADER_SIZE
;
376 NestedCapsuleHeader
->Flags
= (FwType
== ESRT_FW_TYPE_SYSTEMFIRMWARE
) ? SYSTEM_FIRMWARE_FLAG
: DEVICE_FIRMWARE_FLAG
;
377 NestedCapsuleHeader
->CapsuleImageSize
= (UINT32
)FullCapsuleBufferSize
;
379 CopyMem ((UINT8
*)NestedCapsuleHeader
+ NestedCapsuleHeader
->HeaderSize
, CapsuleBuffer
, FileSize
);
381 Status
= WriteFileFromBuffer (OutputCapsuleName
, FullCapsuleBufferSize
, FullCapsuleBuffer
);
382 Print (L
"CapsuleApp: Write %s %r\n", OutputCapsuleName
, Status
);
385 if (CapsuleBuffer
!= NULL
) {
386 FreePool (CapsuleBuffer
);
389 if (FullCapsuleBuffer
!= NULL
) {
390 FreePool (FullCapsuleBuffer
);
397 Clear capsule status variable.
399 @retval EFI_SUCCESS The capsule status variable is cleared.
402 ClearCapsuleStatusVariable (
408 CHAR16 CapsuleVarName
[20];
412 StrCpyS (CapsuleVarName
, sizeof (CapsuleVarName
)/sizeof (CapsuleVarName
[0]), L
"Capsule");
413 TempVarName
= CapsuleVarName
+ StrLen (CapsuleVarName
);
418 UnicodeSPrint (TempVarName
, 5 * sizeof (CHAR16
), L
"%04x", Index
);
420 Status
= gRT
->SetVariable (
422 &gEfiCapsuleReportGuid
,
423 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
,
427 if (Status
== EFI_NOT_FOUND
) {
429 // There is no more capsule variables, quit
436 Print (L
"Clear %s %r\n", CapsuleVarName
, Status
);
439 if (Index
> 0xFFFF) {
445 Print (L
"No any Capsule#### variable found\n");
452 Build Gather list for a list of capsule images.
454 @param[in] CapsuleBuffer An array of pointer to capsule images
455 @param[in] FileSize An array of UINTN to capsule images size
456 @param[in] CapsuleNum The count of capsule images
457 @param[out] BlockDescriptors The block descriptors for the capsule images
459 @retval EFI_SUCCESS The block descriptors for the capsule images are constructed.
463 IN VOID
**CapsuleBuffer
,
466 OUT EFI_CAPSULE_BLOCK_DESCRIPTOR
**BlockDescriptors
470 EFI_CAPSULE_BLOCK_DESCRIPTOR
*BlockDescriptors1
;
471 EFI_CAPSULE_BLOCK_DESCRIPTOR
*BlockDescriptors2
;
472 EFI_CAPSULE_BLOCK_DESCRIPTOR
*BlockDescriptorPre
;
473 EFI_CAPSULE_BLOCK_DESCRIPTOR
*BlockDescriptorsHeader
;
474 EFI_CAPSULE_BLOCK_DESCRIPTOR
*TempBlockPtr
;
483 BlockDescriptors1
= NULL
;
484 BlockDescriptors2
= NULL
;
485 BlockDescriptorPre
= NULL
;
486 BlockDescriptorsHeader
= NULL
;
488 for (Index
= 0; Index
< CapsuleNum
; Index
++) {
490 // Allocate memory for the descriptors.
492 if (NumberOfDescriptors
== 1) {
495 Count
= (INT32
)(NumberOfDescriptors
+ 2) / 2;
498 Size
= Count
* sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR
);
499 BlockDescriptors1
= AllocateRuntimeZeroPool (Size
);
500 if (BlockDescriptors1
== NULL
) {
501 Print (L
"CapsuleApp: failed to allocate memory for descriptors\n");
502 Status
= EFI_OUT_OF_RESOURCES
;
505 Print (L
"CapsuleApp: creating capsule descriptors at 0x%X\n", (UINTN
)BlockDescriptors1
);
506 Print (L
"CapsuleApp: capsule data starts at 0x%X with size 0x%X\n", (UINTN
)CapsuleBuffer
[Index
], FileSize
[Index
]);
510 // Record descriptor header
513 BlockDescriptorsHeader
= BlockDescriptors1
;
516 if (BlockDescriptorPre
!= NULL
) {
517 BlockDescriptorPre
->Union
.ContinuationPointer
= (UINTN
)BlockDescriptors1
;
518 BlockDescriptorPre
->Length
= 0;
524 TempBlockPtr
= BlockDescriptors1
;
525 TempDataPtr
= CapsuleBuffer
[Index
];
526 SizeLeft
= FileSize
[Index
];
527 for (Number
= 0; (Number
< Count
- 1) && (SizeLeft
!= 0); Number
++) {
529 // Divide remaining data in half
531 if (NumberOfDescriptors
!= 1) {
541 TempBlockPtr
->Union
.DataBlock
= (UINTN
)TempDataPtr
;
542 TempBlockPtr
->Length
= Size
;
543 Print (L
"CapsuleApp: capsule block/size 0x%X/0x%X\n", (UINTN
)TempDataPtr
, Size
);
550 // Allocate the second list, point the first block's last entry to point
551 // to this one, and fill this one in. Worst case is that the previous
552 // list only had one element that pointed here, so we need at least two
553 // elements -- one to point to all the data, another to terminate the list.
555 if ((NumberOfDescriptors
!= 1) && (SizeLeft
!= 0)) {
556 Count
= (INT32
)(NumberOfDescriptors
+ 2) - Count
;
561 Size
= Count
* sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR
);
562 BlockDescriptors2
= AllocateRuntimeZeroPool (Size
);
563 if (BlockDescriptors2
== NULL
) {
564 Print (L
"CapsuleApp: failed to allocate memory for descriptors\n");
565 Status
= EFI_OUT_OF_RESOURCES
;
570 // Point the first list's last element to point to this second list.
572 TempBlockPtr
->Union
.ContinuationPointer
= (UINTN
)BlockDescriptors2
;
574 TempBlockPtr
->Length
= 0;
575 TempBlockPtr
= BlockDescriptors2
;
576 for (Number
= 0; Number
< Count
- 1; Number
++) {
578 // If second-to-last one, then dump rest to this element
580 if (Number
== (Count
- 2)) {
584 // Divide remaining data in half
593 TempBlockPtr
->Union
.DataBlock
= (UINTN
)TempDataPtr
;
594 TempBlockPtr
->Length
= Size
;
595 Print (L
"CapsuleApp: capsule block/size 0x%X/0x%X\n", (UINTN
)TempDataPtr
, Size
);
605 BlockDescriptorPre
= TempBlockPtr
;
606 BlockDescriptors1
= NULL
;
612 if (TempBlockPtr
!= NULL
) {
613 TempBlockPtr
->Union
.ContinuationPointer
= (UINTN
)NULL
;
614 TempBlockPtr
->Length
= 0;
615 *BlockDescriptors
= BlockDescriptorsHeader
;
621 if (BlockDescriptors1
!= NULL
) {
622 FreePool (BlockDescriptors1
);
625 if (BlockDescriptors2
!= NULL
) {
626 FreePool (BlockDescriptors2
);
633 Clear the Gather list for a list of capsule images.
635 @param[in] BlockDescriptors The block descriptors for the capsule images
636 @param[in] CapsuleNum The count of capsule images
640 IN EFI_CAPSULE_BLOCK_DESCRIPTOR
*BlockDescriptors
,
644 EFI_CAPSULE_BLOCK_DESCRIPTOR
*TempBlockPtr
;
645 EFI_CAPSULE_BLOCK_DESCRIPTOR
*TempBlockPtr1
;
646 EFI_CAPSULE_BLOCK_DESCRIPTOR
*TempBlockPtr2
;
649 if (BlockDescriptors
!= NULL
) {
650 TempBlockPtr1
= BlockDescriptors
;
652 TempBlockPtr
= TempBlockPtr1
;
653 for (Index
= 0; Index
< CapsuleNum
; Index
++) {
654 if (TempBlockPtr
[Index
].Length
== 0) {
659 if (TempBlockPtr
[Index
].Union
.ContinuationPointer
== (UINTN
)NULL
) {
663 TempBlockPtr2
= (VOID
*)((UINTN
)TempBlockPtr
[Index
].Union
.ContinuationPointer
);
664 FreePool (TempBlockPtr1
);
665 TempBlockPtr1
= TempBlockPtr2
;
678 Print (L
"CapsuleApp: usage\n");
679 Print (L
" CapsuleApp <Capsule...> [-NR] [-OD [FSx]]\n");
680 Print (L
" CapsuleApp -S\n");
681 Print (L
" CapsuleApp -C\n");
682 Print (L
" CapsuleApp -P\n");
683 Print (L
" CapsuleApp -E\n");
684 Print (L
" CapsuleApp -L\n");
685 Print (L
" CapsuleApp -L INFO\n");
686 Print (L
" CapsuleApp -F\n");
687 Print (L
" CapsuleApp -G <BMP> -O <Capsule>\n");
688 Print (L
" CapsuleApp -N <Capsule> -O <NestedCapsule>\n");
689 Print (L
" CapsuleApp -D <Capsule>\n");
690 Print (L
" CapsuleApp -P GET <ImageTypeId> <Index> -O <FileName>\n");
691 Print (L
"Parameter:\n");
692 Print (L
" -NR: No reset will be triggered for the capsule\n");
693 Print (L
" with CAPSULE_FLAGS_PERSIST_ACROSS_RESET and without CAPSULE_FLAGS_INITIATE_RESET.\n");
694 Print (L
" -OD: Delivery of Capsules via file on Mass Storage device.\n");
695 Print (L
" -S: Dump capsule report variable (EFI_CAPSULE_REPORT_GUID),\n");
696 Print (L
" which is defined in UEFI specification.\n");
697 Print (L
" -C: Clear capsule report variable (EFI_CAPSULE_REPORT_GUID),\n");
698 Print (L
" which is defined in UEFI specification.\n");
699 Print (L
" -P: Dump UEFI FMP protocol info, or get image with specified\n");
700 Print (L
" ImageTypeId and Index (decimal format) to a file if 'GET'\n");
701 Print (L
" option is used.\n");
702 Print (L
" -E: Dump UEFI ESRT table info.\n");
703 Print (L
" -L: Dump provisioned capsule image information.\n");
704 Print (L
" -F: Dump all EFI System Partition.\n");
705 Print (L
" -G: Convert a BMP file to be an UX capsule,\n");
706 Print (L
" according to Windows Firmware Update document\n");
707 Print (L
" -N: Append a Capsule Header to an existing FMP capsule image\n");
708 Print (L
" with its ImageTypeId supported by the system,\n");
709 Print (L
" according to Windows Firmware Update document\n");
710 Print (L
" -O: Output new Capsule file name\n");
711 Print (L
" -D: Dump Capsule image header information, image payload\n");
712 Print (L
" information if it is an UX capsule and FMP header\n");
713 Print (L
" information if it is a FMP capsule.\n");
717 Update Capsule image.
719 @param[in] ImageHandle The image handle.
720 @param[in] SystemTable The system table.
722 @retval EFI_SUCCESS Command completed successfully.
723 @retval EFI_UNSUPPORTED Command usage unsupported.
724 @retval EFI_INVALID_PARAMETER Command usage invalid.
725 @retval EFI_NOT_FOUND The input file can't be found.
730 IN EFI_HANDLE ImageHandle
,
731 IN EFI_SYSTEM_TABLE
*SystemTable
735 RETURN_STATUS RStatus
;
736 UINTN CapsuleBufferSize
[MAX_CAPSULE_NUM
];
737 VOID
*CapsuleBuffer
[MAX_CAPSULE_NUM
];
738 EFI_CAPSULE_BLOCK_DESCRIPTOR
*BlockDescriptors
;
739 EFI_CAPSULE_HEADER
*CapsuleHeaderArray
[MAX_CAPSULE_NUM
+ 1];
740 UINT64 MaxCapsuleSize
;
741 EFI_RESET_TYPE ResetType
;
744 BOOLEAN CapsuleOnDisk
;
746 CHAR16
*CapsuleNames
[MAX_CAPSULE_NUM
];
752 EFI_GUID ImageTypeId
;
755 BlockDescriptors
= NULL
;
760 if (EFI_ERROR (Status
)) {
761 Print (L
"Please use UEFI SHELL to run this application!\n", Status
);
767 return EFI_UNSUPPORTED
;
770 if (StrCmp (Argv
[1], L
"-D") == 0) {
772 Print (L
"CapsuleApp: Incorrect parameter count.\n");
773 return EFI_UNSUPPORTED
;
776 Status
= DumpCapsule (Argv
[2]);
780 if (StrCmp (Argv
[1], L
"-G") == 0) {
781 Status
= CreateBmpFmp ();
785 if (StrCmp (Argv
[1], L
"-N") == 0) {
786 Status
= CreateNestedFmp ();
790 if (StrCmp (Argv
[1], L
"-S") == 0) {
791 Status
= DumpCapsuleStatusVariable ();
795 if (StrCmp (Argv
[1], L
"-C") == 0) {
796 Status
= ClearCapsuleStatusVariable ();
800 if (StrCmp (Argv
[1], L
"-P") == 0) {
806 if (StrCmp (Argv
[2], L
"GET") != 0) {
807 Print (L
"CapsuleApp: Unrecognized option(%s).\n", Argv
[2]);
808 return EFI_UNSUPPORTED
;
811 Print (L
"CapsuleApp: Incorrect parameter count.\n");
812 return EFI_UNSUPPORTED
;
818 RStatus
= StrToGuid (Argv
[3], &ImageTypeId
);
819 if (RETURN_ERROR (RStatus
) || (Argv
[3][GUID_STRING_LENGTH
] != L
'\0')) {
820 Print (L
"Invalid ImageTypeId - %s\n", Argv
[3]);
821 return EFI_INVALID_PARAMETER
;
824 ImageIndex
= StrDecimalToUintn (Argv
[4]);
825 if (StrCmp (Argv
[5], L
"-O") != 0) {
826 Print (L
"CapsuleApp: NO output file name.\n");
827 return EFI_UNSUPPORTED
;
830 DumpFmpImage (&ImageTypeId
, ImageIndex
, Argv
[6]);
837 if (StrCmp (Argv
[1], L
"-E") == 0) {
842 if (StrCmp (Argv
[1], L
"-L") == 0) {
843 if ((Argc
>= 3) && (StrCmp (Argv
[2], L
"INFO") == 0)) {
844 DumpProvisionedCapsule (TRUE
);
846 DumpProvisionedCapsule (FALSE
);
852 if (StrCmp (Argv
[1], L
"-F") == 0) {
853 DumpAllEfiSysPartition ();
857 if (Argv
[1][0] == L
'-') {
858 Print (L
"CapsuleApp: Unrecognized option(%s).\n", Argv
[1]);
859 return EFI_UNSUPPORTED
;
862 CapsuleFirstIndex
= 1;
864 CapsuleOnDisk
= FALSE
;
868 for (Index
= 1; Index
< Argc
; Index
++) {
869 if (StrCmp (Argv
[Index
], L
"-OD") == 0) {
871 CapsuleOnDisk
= TRUE
;
872 } else if (StrCmp (Argv
[Index
], L
"-NR") == 0) {
878 if (ParaOdIndex
> ParaNrIndex
) {
879 if (ParaNrIndex
!= 0) {
880 CapsuleLastIndex
= ParaNrIndex
- 1;
882 CapsuleLastIndex
= ParaOdIndex
- 1;
885 if (ParaOdIndex
== Argc
-1) {
887 } else if (ParaOdIndex
== Argc
- 2) {
888 MapFsStr
= Argv
[Argc
-1];
890 Print (L
"CapsuleApp: Cannot specify more than one FS mapping!\n");
891 Status
= EFI_INVALID_PARAMETER
;
894 } else if (ParaOdIndex
< ParaNrIndex
) {
895 if (ParaOdIndex
!= 0) {
896 CapsuleLastIndex
= ParaOdIndex
- 1;
897 if (ParaOdIndex
== ParaNrIndex
- 1) {
899 } else if (ParaOdIndex
== ParaNrIndex
- 2) {
900 MapFsStr
= Argv
[ParaOdIndex
+ 1];
902 Print (L
"CapsuleApp: Cannot specify more than one FS mapping!\n");
903 Status
= EFI_INVALID_PARAMETER
;
907 CapsuleLastIndex
= ParaNrIndex
- 1;
910 CapsuleLastIndex
= Argc
- 1;
913 CapsuleNum
= CapsuleLastIndex
- CapsuleFirstIndex
+ 1;
915 if (CapsuleFirstIndex
> CapsuleLastIndex
) {
916 Print (L
"CapsuleApp: NO capsule image.\n");
917 return EFI_UNSUPPORTED
;
920 if (CapsuleNum
> MAX_CAPSULE_NUM
) {
921 Print (L
"CapsuleApp: Too many capsule images.\n");
922 return EFI_UNSUPPORTED
;
925 ZeroMem (&CapsuleBuffer
, sizeof (CapsuleBuffer
));
926 ZeroMem (&CapsuleBufferSize
, sizeof (CapsuleBufferSize
));
927 BlockDescriptors
= NULL
;
929 for (Index
= 0; Index
< CapsuleNum
; Index
++) {
930 CapsuleName
= Argv
[CapsuleFirstIndex
+ Index
];
931 Status
= ReadFileToBuffer (CapsuleName
, &CapsuleBufferSize
[Index
], &CapsuleBuffer
[Index
]);
932 if (EFI_ERROR (Status
)) {
933 Print (L
"CapsuleApp: capsule image (%s) is not found.\n", CapsuleName
);
937 if (!IsValidCapsuleHeader (CapsuleBuffer
[Index
], CapsuleBufferSize
[Index
])) {
938 Print (L
"CapsuleApp: Capsule image (%s) is not a valid capsule.\n", CapsuleName
);
939 return EFI_INVALID_PARAMETER
;
942 CapsuleNames
[Index
] = CapsuleName
;
946 // Every capsule use 2 descriptor 1 for data 1 for end
948 Status
= BuildGatherList (CapsuleBuffer
, CapsuleBufferSize
, CapsuleNum
, &BlockDescriptors
);
949 if (EFI_ERROR (Status
)) {
954 // Call the runtime service capsule.
957 for (Index
= 0; Index
< CapsuleNum
; Index
++) {
958 CapsuleHeaderArray
[Index
] = (EFI_CAPSULE_HEADER
*)CapsuleBuffer
[Index
];
959 if ((CapsuleHeaderArray
[Index
]->Flags
& CAPSULE_FLAGS_PERSIST_ACROSS_RESET
) != 0) {
964 CapsuleHeaderArray
[CapsuleNum
] = NULL
;
967 // Inquire platform capability of UpdateCapsule.
969 Status
= gRT
->QueryCapsuleCapabilities (CapsuleHeaderArray
, CapsuleNum
, &MaxCapsuleSize
, &ResetType
);
970 if (EFI_ERROR (Status
)) {
971 Print (L
"CapsuleApp: failed to query capsule capability - %r\n", Status
);
975 for (Index
= 0; Index
< CapsuleNum
; Index
++) {
976 if (CapsuleBufferSize
[Index
] > MaxCapsuleSize
) {
977 Print (L
"CapsuleApp: capsule is too large to update, %ld is allowed\n", MaxCapsuleSize
);
978 Status
= EFI_UNSUPPORTED
;
984 // Check whether is capsule on disk.
987 Status
= ProcessCapsuleOnDisk (CapsuleBuffer
, CapsuleBufferSize
, CapsuleNames
, MapFsStr
, CapsuleNum
);
988 if (Status
!= EFI_SUCCESS
) {
989 Print (L
"CapsuleApp: failed to update capsule - %r\n", Status
);
993 gRT
->ResetSystem (ResetType
, EFI_SUCCESS
, 0, NULL
);
1001 // Check whether the input capsule image has the flag of persist across system reset.
1004 Status
= gRT
->UpdateCapsule (CapsuleHeaderArray
, CapsuleNum
, (UINTN
)BlockDescriptors
);
1005 if (Status
!= EFI_SUCCESS
) {
1006 Print (L
"CapsuleApp: failed to update capsule - %r\n", Status
);
1011 // For capsule with CAPSULE_FLAGS_PERSIST_ACROSS_RESET + CAPSULE_FLAGS_INITIATE_RESET,
1012 // a system reset should have been triggered by gRT->UpdateCapsule() calling above.
1014 // For capsule with CAPSULE_FLAGS_PERSIST_ACROSS_RESET and without CAPSULE_FLAGS_INITIATE_RESET,
1015 // check if -NR (no-reset) has been specified or not.
1019 // For capsule who has reset flag and no -NR (no-reset) has been specified, after calling UpdateCapsule service,
1020 // trigger a system reset to process capsule persist across a system reset.
1022 gRT
->ResetSystem (ResetType
, EFI_SUCCESS
, 0, NULL
);
1026 // For capsule who has no reset flag, only call UpdateCapsule Service without a
1027 // system reset. The service will process the capsule immediately.
1029 Status
= gRT
->UpdateCapsule (CapsuleHeaderArray
, CapsuleNum
, (UINTN
)BlockDescriptors
);
1030 if (Status
!= EFI_SUCCESS
) {
1031 Print (L
"CapsuleApp: failed to update capsule - %r\n", Status
);
1035 Status
= EFI_SUCCESS
;
1038 for (Index
= 0; Index
< CapsuleNum
; Index
++) {
1039 if (CapsuleBuffer
[Index
] != NULL
) {
1040 FreePool (CapsuleBuffer
[Index
]);
1044 CleanGatherList (BlockDescriptors
, CapsuleNum
);