2 A shell application that triggers capsule update process.
4 Copyright (c) 2016 - 2018, 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/CapsuleReport.h>
27 #include <Guid/SystemResourceTable.h>
28 #include <Guid/FmpCapsule.h>
29 #include <IndustryStandard/WindowsUxCapsule.h>
31 #define CAPSULE_HEADER_SIZE 0x20
33 #define NESTED_CAPSULE_HEADER_SIZE SIZE_4KB
34 #define SYSTEM_FIRMWARE_FLAG 0x50000
35 #define DEVICE_FIRMWARE_FLAG 0x78010
37 #define MAJOR_VERSION 1
38 #define MINOR_VERSION 0
40 #define MAX_CAPSULE_NUM 10
46 // Define how many block descriptors we want to test with.
48 UINTN NumberOfDescriptors
= 1;
49 UINTN CapsuleFirstIndex
;
50 UINTN CapsuleLastIndex
;
53 Dump capsule information
55 @param[in] CapsuleName The name of the capsule image.
57 @retval EFI_SUCCESS The capsule information is dumped.
58 @retval EFI_UNSUPPORTED Input parameter is not valid.
62 IN CHAR16
*CapsuleName
66 Dump capsule status variable.
68 @retval EFI_SUCCESS The capsule status variable is dumped.
69 @retval EFI_UNSUPPORTED Input parameter is not valid.
72 DumpCapsuleStatusVariable (
77 Dump FMP protocol info.
87 @param[in] ImageTypeId The ImageTypeId of the FMP image.
88 It is used to identify the FMP protocol.
89 @param[in] ImageIndex The ImageIndex of the FMP image.
90 It is the input parameter for FMP->GetImage().
91 @param[in] ImageName The file name to hold the output FMP image.
95 IN EFI_GUID
*ImageTypeId
,
111 @param[in] FileName The file to be read.
112 @param[out] BufferSize The file buffer size
113 @param[out] Buffer The file buffer
115 @retval EFI_SUCCESS Read file successfully
116 @retval EFI_NOT_FOUND Shell protocol or file not found
117 @retval others Read file failed
122 OUT UINTN
*BufferSize
,
129 @param[in] FileName The file to be written.
130 @param[in] BufferSize The file buffer size
131 @param[in] Buffer The file buffer
133 @retval EFI_SUCCESS Write file successfully
134 @retval EFI_NOT_FOUND Shell protocol not found
135 @retval others Write file failed
138 WriteFileFromBuffer (
146 This function parse application ARG.
158 @retval EFI_SUCCESS The capsule header is appended.
159 @retval EFI_UNSUPPORTED Input parameter is not valid.
160 @retval EFI_OUT_OF_RESOURCES No enough resource to create UX capsule.
167 CHAR16
*OutputCapsuleName
;
171 UINT8
*FullCapsuleBuffer
;
172 UINTN FullCapsuleBufferSize
;
173 EFI_DISPLAY_CAPSULE
*DisplayCapsule
;
175 EFI_GRAPHICS_OUTPUT_PROTOCOL
*Gop
;
176 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION
*Info
;
177 EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*GopBlt
;
182 Status
= gBS
->LocateProtocol(&gEfiGraphicsOutputProtocolGuid
, NULL
, (VOID
**)&Gop
);
183 if (EFI_ERROR(Status
)) {
184 Print(L
"CapsuleApp: NO GOP is found.\n");
185 return EFI_UNSUPPORTED
;
187 Info
= Gop
->Mode
->Info
;
188 Print(L
"Current GOP: Mode - %d, ", Gop
->Mode
->Mode
);
189 Print(L
"HorizontalResolution - %d, ", Info
->HorizontalResolution
);
190 Print(L
"VerticalResolution - %d\n", Info
->VerticalResolution
);
191 // HorizontalResolution >= BMP_IMAGE_HEADER.PixelWidth
192 // VerticalResolution >= BMP_IMAGE_HEADER.PixelHeight
195 Print(L
"CapsuleApp: Incorrect parameter count.\n");
196 return EFI_UNSUPPORTED
;
199 if (StrCmp(Argv
[3], L
"-O") != 0) {
200 Print(L
"CapsuleApp: NO output capsule name.\n");
201 return EFI_UNSUPPORTED
;
203 OutputCapsuleName
= Argv
[4];
207 FullCapsuleBuffer
= NULL
;
210 Status
= ReadFileToBuffer(BmpName
, &FileSize
, &BmpBuffer
);
211 if (EFI_ERROR(Status
)) {
212 Print(L
"CapsuleApp: BMP image (%s) is not found.\n", BmpName
);
217 Status
= TranslateBmpToGopBlt (
225 if (EFI_ERROR(Status
)) {
226 Print(L
"CapsuleApp: BMP image (%s) is not valid.\n", BmpName
);
229 if (GopBlt
!= NULL
) {
232 Print(L
"BMP image (%s), Width - %d, Height - %d\n", BmpName
, Width
, Height
);
234 if (Height
> Info
->VerticalResolution
) {
235 Status
= EFI_INVALID_PARAMETER
;
236 Print(L
"CapsuleApp: BMP image (%s) height is larger than current resolution.\n", BmpName
);
239 if (Width
> Info
->HorizontalResolution
) {
240 Status
= EFI_INVALID_PARAMETER
;
241 Print(L
"CapsuleApp: BMP image (%s) width is larger than current resolution.\n", BmpName
);
245 FullCapsuleBufferSize
= sizeof(EFI_DISPLAY_CAPSULE
) + FileSize
;
246 FullCapsuleBuffer
= AllocatePool(FullCapsuleBufferSize
);
247 if (FullCapsuleBuffer
== NULL
) {
248 Print(L
"CapsuleApp: Capsule Buffer size (0x%x) too big.\n", FullCapsuleBufferSize
);
249 Status
= EFI_OUT_OF_RESOURCES
;
253 DisplayCapsule
= (EFI_DISPLAY_CAPSULE
*)FullCapsuleBuffer
;
254 CopyGuid(&DisplayCapsule
->CapsuleHeader
.CapsuleGuid
, &gWindowsUxCapsuleGuid
);
255 DisplayCapsule
->CapsuleHeader
.HeaderSize
= sizeof(DisplayCapsule
->CapsuleHeader
);
256 DisplayCapsule
->CapsuleHeader
.Flags
= CAPSULE_FLAGS_PERSIST_ACROSS_RESET
;
257 DisplayCapsule
->CapsuleHeader
.CapsuleImageSize
= (UINT32
)FullCapsuleBufferSize
;
259 DisplayCapsule
->ImagePayload
.Version
= 1;
260 DisplayCapsule
->ImagePayload
.Checksum
= 0;
261 DisplayCapsule
->ImagePayload
.ImageType
= 0; // BMP
262 DisplayCapsule
->ImagePayload
.Reserved
= 0;
263 DisplayCapsule
->ImagePayload
.Mode
= Gop
->Mode
->Mode
;
266 // Center the bitmap horizontally
268 DisplayCapsule
->ImagePayload
.OffsetX
= (UINT32
)((Info
->HorizontalResolution
- Width
) / 2);
271 // Put bitmap 3/4 down the display. If bitmap is too tall, then align bottom
272 // of bitmap at bottom of display.
274 DisplayCapsule
->ImagePayload
.OffsetY
=
276 (UINT32
)(Info
->VerticalResolution
- Height
),
277 (UINT32
)(((3 * Info
->VerticalResolution
) - (2 * Height
)) / 4)
280 Print(L
"BMP image (%s), OffsetX - %d, OffsetY - %d\n",
282 DisplayCapsule
->ImagePayload
.OffsetX
,
283 DisplayCapsule
->ImagePayload
.OffsetY
286 CopyMem((DisplayCapsule
+ 1), BmpBuffer
, FileSize
);
288 DisplayCapsule
->ImagePayload
.Checksum
= CalculateCheckSum8(FullCapsuleBuffer
, FullCapsuleBufferSize
);
290 Status
= WriteFileFromBuffer(OutputCapsuleName
, FullCapsuleBufferSize
, FullCapsuleBuffer
);
291 Print(L
"CapsuleApp: Write %s %r\n", OutputCapsuleName
, Status
);
294 if (BmpBuffer
!= NULL
) {
298 if (FullCapsuleBuffer
!= NULL
) {
299 FreePool(FullCapsuleBuffer
);
306 Get ImageTypeId in the FMP capsule header.
308 @param[in] CapsuleHeader The FMP capsule image header.
313 GetCapsuleImageTypeId (
314 IN EFI_CAPSULE_HEADER
*CapsuleHeader
317 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
*FmpCapsuleHeader
;
318 UINT64
*ItemOffsetList
;
319 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
*ImageHeader
;
321 FmpCapsuleHeader
= (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
*)((UINT8
*)CapsuleHeader
+ CapsuleHeader
->HeaderSize
);
322 ItemOffsetList
= (UINT64
*)(FmpCapsuleHeader
+ 1);
323 if (FmpCapsuleHeader
->PayloadItemCount
== 0) {
326 ImageHeader
= (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
*)((UINT8
*)FmpCapsuleHeader
+ ItemOffsetList
[FmpCapsuleHeader
->EmbeddedDriverCount
]);
327 return &ImageHeader
->UpdateImageTypeId
;
331 Get ESRT FwType according to ImageTypeId
333 @param[in] ImageTypeId ImageTypeId of an FMP capsule.
339 IN EFI_GUID
*ImageTypeId
343 EFI_SYSTEM_RESOURCE_TABLE
*Esrt
;
344 EFI_SYSTEM_RESOURCE_ENTRY
*EsrtEntry
;
350 Status
= EfiGetSystemConfigurationTable(&gEfiSystemResourceTableGuid
, (VOID
**)&Esrt
);
351 if (!EFI_ERROR(Status
)) {
352 ASSERT(Esrt
!= NULL
);
353 EsrtEntry
= (VOID
*)(Esrt
+ 1);
354 for (Index
= 0; Index
< Esrt
->FwResourceCount
; Index
++, EsrtEntry
++) {
355 if (CompareGuid(&EsrtEntry
->FwClass
, ImageTypeId
)) {
356 return EsrtEntry
->FwType
;
361 return ESRT_FW_TYPE_UNKNOWN
;
365 Validate if it is valid capsule header
367 This function assumes the caller provided correct CapsuleHeader pointer
370 This function validates the fields in EFI_CAPSULE_HEADER.
372 @param[in] CapsuleHeader Points to a capsule header.
373 @param[in] CapsuleSize Size of the whole capsule image.
377 IsValidCapsuleHeader (
378 IN EFI_CAPSULE_HEADER
*CapsuleHeader
,
379 IN UINT64 CapsuleSize
382 if (CapsuleSize
< sizeof (EFI_CAPSULE_HEADER
)) {
385 if (CapsuleHeader
->CapsuleImageSize
!= CapsuleSize
) {
388 if (CapsuleHeader
->HeaderSize
> CapsuleHeader
->CapsuleImageSize
) {
391 if (CapsuleHeader
->HeaderSize
< sizeof (EFI_CAPSULE_HEADER
)) {
399 Return if this CapsuleGuid is a FMP capsule GUID or not.
401 @param[in] CapsuleGuid A pointer to EFI_GUID
403 @retval TRUE It is a FMP capsule GUID.
404 @retval FALSE It is not a FMP capsule GUID.
408 IN EFI_GUID
*CapsuleGuid
411 if (CompareGuid(&gEfiFmpCapsuleGuid
, CapsuleGuid
)) {
419 Append a capsule header on top of current image.
420 This function follows Windows UEFI Firmware Update Platform document.
422 @retval EFI_SUCCESS The capsule header is appended.
423 @retval EFI_UNSUPPORTED Input parameter is not valid.
424 @retval EFI_OUT_OF_RESOURCES No enough resource to append capsule header.
431 CHAR16
*OutputCapsuleName
;
435 UINT8
*FullCapsuleBuffer
;
436 UINTN FullCapsuleBufferSize
;
437 EFI_CAPSULE_HEADER
*NestedCapsuleHeader
;
438 EFI_GUID
*ImageTypeId
;
443 Print(L
"CapsuleApp: Incorrect parameter count.\n");
444 return EFI_UNSUPPORTED
;
447 if (StrCmp(Argv
[3], L
"-O") != 0) {
448 Print(L
"CapsuleApp: NO output capsule name.\n");
449 return EFI_UNSUPPORTED
;
451 OutputCapsuleName
= Argv
[4];
453 CapsuleBuffer
= NULL
;
455 FullCapsuleBuffer
= NULL
;
457 CapsuleName
= Argv
[2];
458 Status
= ReadFileToBuffer(CapsuleName
, &FileSize
, &CapsuleBuffer
);
459 if (EFI_ERROR(Status
)) {
460 Print(L
"CapsuleApp: Capsule image (%s) is not found.\n", CapsuleName
);
463 if (!IsValidCapsuleHeader (CapsuleBuffer
, FileSize
)) {
464 Print(L
"CapsuleApp: Capsule image (%s) is not a valid capsule.\n", CapsuleName
);
465 Status
= EFI_INVALID_PARAMETER
;
469 if (!IsFmpCapsuleGuid (&((EFI_CAPSULE_HEADER
*) CapsuleBuffer
)->CapsuleGuid
)) {
470 Print(L
"CapsuleApp: Capsule image (%s) is not a FMP capsule.\n", CapsuleName
);
471 Status
= EFI_INVALID_PARAMETER
;
475 ImageTypeId
= GetCapsuleImageTypeId(CapsuleBuffer
);
476 if (ImageTypeId
== NULL
) {
477 Print(L
"CapsuleApp: Capsule ImageTypeId is not found.\n");
478 Status
= EFI_INVALID_PARAMETER
;
481 FwType
= GetEsrtFwType(ImageTypeId
);
482 if ((FwType
!= ESRT_FW_TYPE_SYSTEMFIRMWARE
) && (FwType
!= ESRT_FW_TYPE_DEVICEFIRMWARE
)) {
483 Print(L
"CapsuleApp: Capsule FwType is invalid.\n");
484 Status
= EFI_INVALID_PARAMETER
;
488 FullCapsuleBufferSize
= NESTED_CAPSULE_HEADER_SIZE
+ FileSize
;
489 FullCapsuleBuffer
= AllocatePool(FullCapsuleBufferSize
);
490 if (FullCapsuleBuffer
== NULL
) {
491 Print(L
"CapsuleApp: Capsule Buffer size (0x%x) too big.\n", FullCapsuleBufferSize
);
492 Status
= EFI_OUT_OF_RESOURCES
;
496 NestedCapsuleHeader
= (EFI_CAPSULE_HEADER
*)FullCapsuleBuffer
;
497 ZeroMem(NestedCapsuleHeader
, NESTED_CAPSULE_HEADER_SIZE
);
498 CopyGuid(&NestedCapsuleHeader
->CapsuleGuid
, ImageTypeId
);
499 NestedCapsuleHeader
->HeaderSize
= NESTED_CAPSULE_HEADER_SIZE
;
500 NestedCapsuleHeader
->Flags
= (FwType
== ESRT_FW_TYPE_SYSTEMFIRMWARE
) ? SYSTEM_FIRMWARE_FLAG
: DEVICE_FIRMWARE_FLAG
;
501 NestedCapsuleHeader
->CapsuleImageSize
= (UINT32
)FullCapsuleBufferSize
;
503 CopyMem((UINT8
*)NestedCapsuleHeader
+ NestedCapsuleHeader
->HeaderSize
, CapsuleBuffer
, FileSize
);
505 Status
= WriteFileFromBuffer(OutputCapsuleName
, FullCapsuleBufferSize
, FullCapsuleBuffer
);
506 Print(L
"CapsuleApp: Write %s %r\n", OutputCapsuleName
, Status
);
509 if (CapsuleBuffer
!= NULL
) {
510 FreePool(CapsuleBuffer
);
513 if (FullCapsuleBuffer
!= NULL
) {
514 FreePool(FullCapsuleBuffer
);
522 Clear capsule status variable.
524 @retval EFI_SUCCESS The capsule status variable is cleared.
527 ClearCapsuleStatusVariable (
533 CHAR16 CapsuleVarName
[20];
537 StrCpyS (CapsuleVarName
, sizeof(CapsuleVarName
)/sizeof(CapsuleVarName
[0]), L
"Capsule");
538 TempVarName
= CapsuleVarName
+ StrLen (CapsuleVarName
);
543 UnicodeSPrint (TempVarName
, 5 * sizeof(CHAR16
), L
"%04x", Index
);
545 Status
= gRT
->SetVariable (
547 &gEfiCapsuleReportGuid
,
548 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
,
552 if (Status
== EFI_NOT_FOUND
) {
554 // There is no more capsule variables, quit
560 Print (L
"Clear %s %r\n", CapsuleVarName
, Status
);
563 if (Index
> 0xFFFF) {
569 Print (L
"No any Capsule#### variable found\n");
576 Build Gather list for a list of capsule images.
578 @param[in] CapsuleBuffer An array of pointer to capsule images
579 @param[in] FileSize An array of UINTN to capsule images size
580 @param[in] CapsuleNum The count of capsule images
581 @param[out] BlockDescriptors The block descriptors for the capsule images
583 @retval EFI_SUCCESS The block descriptors for the capsule images are constructed.
587 IN VOID
**CapsuleBuffer
,
590 OUT EFI_CAPSULE_BLOCK_DESCRIPTOR
**BlockDescriptors
594 EFI_CAPSULE_BLOCK_DESCRIPTOR
*BlockDescriptors1
;
595 EFI_CAPSULE_BLOCK_DESCRIPTOR
*BlockDescriptors2
;
596 EFI_CAPSULE_BLOCK_DESCRIPTOR
*BlockDescriptorPre
;
597 EFI_CAPSULE_BLOCK_DESCRIPTOR
*BlockDescriptorsHeader
;
598 EFI_CAPSULE_BLOCK_DESCRIPTOR
*TempBlockPtr
;
607 BlockDescriptors1
= NULL
;
608 BlockDescriptors2
= NULL
;
609 BlockDescriptorPre
= NULL
;
610 BlockDescriptorsHeader
= NULL
;
612 for (Index
= 0; Index
< CapsuleNum
; Index
++) {
614 // Allocate memory for the descriptors.
616 if (NumberOfDescriptors
== 1) {
619 Count
= (INT32
)(NumberOfDescriptors
+ 2) / 2;
622 Size
= Count
* sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR
);
623 BlockDescriptors1
= AllocateRuntimeZeroPool (Size
);
624 if (BlockDescriptors1
== NULL
) {
625 Print (L
"CapsuleApp: failed to allocate memory for descriptors\n");
626 Status
= EFI_OUT_OF_RESOURCES
;
629 Print (L
"CapsuleApp: creating capsule descriptors at 0x%X\n", (UINTN
) BlockDescriptors1
);
630 Print (L
"CapsuleApp: capsule data starts at 0x%X with size 0x%X\n", (UINTN
) CapsuleBuffer
[Index
], FileSize
[Index
]);
634 // Record descirptor header
637 BlockDescriptorsHeader
= BlockDescriptors1
;
640 if (BlockDescriptorPre
!= NULL
) {
641 BlockDescriptorPre
->Union
.ContinuationPointer
= (UINTN
) BlockDescriptors1
;
642 BlockDescriptorPre
->Length
= 0;
648 TempBlockPtr
= BlockDescriptors1
;
649 TempDataPtr
= CapsuleBuffer
[Index
];
650 SizeLeft
= FileSize
[Index
];
651 for (Number
= 0; (Number
< Count
- 1) && (SizeLeft
!= 0); Number
++) {
653 // Divide remaining data in half
655 if (NumberOfDescriptors
!= 1) {
664 TempBlockPtr
->Union
.DataBlock
= (UINTN
)TempDataPtr
;
665 TempBlockPtr
->Length
= Size
;
666 Print (L
"CapsuleApp: capsule block/size 0x%X/0x%X\n", (UINTN
) TempDataPtr
, Size
);
673 // Allocate the second list, point the first block's last entry to point
674 // to this one, and fill this one in. Worst case is that the previous
675 // list only had one element that pointed here, so we need at least two
676 // elements -- one to point to all the data, another to terminate the list.
678 if ((NumberOfDescriptors
!= 1) && (SizeLeft
!= 0)) {
679 Count
= (INT32
)(NumberOfDescriptors
+ 2) - Count
;
684 Size
= Count
* sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR
);
685 BlockDescriptors2
= AllocateRuntimeZeroPool (Size
);
686 if (BlockDescriptors2
== NULL
) {
687 Print (L
"CapsuleApp: failed to allocate memory for descriptors\n");
688 Status
= EFI_OUT_OF_RESOURCES
;
693 // Point the first list's last element to point to this second list.
695 TempBlockPtr
->Union
.ContinuationPointer
= (UINTN
) BlockDescriptors2
;
697 TempBlockPtr
->Length
= 0;
698 TempBlockPtr
= BlockDescriptors2
;
699 for (Number
= 0; Number
< Count
- 1; Number
++) {
701 // If second-to-last one, then dump rest to this element
703 if (Number
== (Count
- 2)) {
707 // Divide remaining data in half
716 TempBlockPtr
->Union
.DataBlock
= (UINTN
)TempDataPtr
;
717 TempBlockPtr
->Length
= Size
;
718 Print (L
"CapsuleApp: capsule block/size 0x%X/0x%X\n", (UINTN
) TempDataPtr
, Size
);
728 BlockDescriptorPre
= TempBlockPtr
;
729 BlockDescriptors1
= NULL
;
735 if (TempBlockPtr
!= NULL
) {
736 TempBlockPtr
->Union
.ContinuationPointer
= (UINTN
)NULL
;
737 TempBlockPtr
->Length
= 0;
738 *BlockDescriptors
= BlockDescriptorsHeader
;
744 if (BlockDescriptors1
!= NULL
) {
745 FreePool(BlockDescriptors1
);
748 if (BlockDescriptors2
!= NULL
) {
749 FreePool(BlockDescriptors2
);
756 Clear the Gather list for a list of capsule images.
758 @param[in] BlockDescriptors The block descriptors for the capsule images
759 @param[in] CapsuleNum The count of capsule images
763 IN EFI_CAPSULE_BLOCK_DESCRIPTOR
*BlockDescriptors
,
767 EFI_CAPSULE_BLOCK_DESCRIPTOR
*TempBlockPtr
;
768 EFI_CAPSULE_BLOCK_DESCRIPTOR
*TempBlockPtr1
;
769 EFI_CAPSULE_BLOCK_DESCRIPTOR
*TempBlockPtr2
;
772 if (BlockDescriptors
!= NULL
) {
773 TempBlockPtr1
= BlockDescriptors
;
775 TempBlockPtr
= TempBlockPtr1
;
776 for (Index
= 0; Index
< CapsuleNum
; Index
++) {
777 if (TempBlockPtr
[Index
].Length
== 0) {
782 if (TempBlockPtr
[Index
].Union
.ContinuationPointer
== (UINTN
)NULL
) {
786 TempBlockPtr2
= (VOID
*) ((UINTN
) TempBlockPtr
[Index
].Union
.ContinuationPointer
);
787 FreePool(TempBlockPtr1
);
788 TempBlockPtr1
= TempBlockPtr2
;
801 Print(L
"CapsuleApp: usage\n");
802 Print(L
" CapsuleApp <Capsule...> [-NR]\n");
803 Print(L
" CapsuleApp -S\n");
804 Print(L
" CapsuleApp -C\n");
805 Print(L
" CapsuleApp -P\n");
806 Print(L
" CapsuleApp -E\n");
807 Print(L
" CapsuleApp -G <BMP> -O <Capsule>\n");
808 Print(L
" CapsuleApp -N <Capsule> -O <NestedCapsule>\n");
809 Print(L
" CapsuleApp -D <Capsule>\n");
810 Print(L
" CapsuleApp -P GET <ImageTypeId> <Index> -O <FileName>\n");
811 Print(L
"Parameter:\n");
812 Print(L
" -NR: No reset will be triggered for the capsule with\n");
813 Print(L
" CAPSULE_FLAGS_PERSIST_ACROSS_RESET and without\n");
814 Print(L
" CAPSULE_FLAGS_INITIATE_RESET.\n");
815 Print(L
" -S: Dump capsule report variable (EFI_CAPSULE_REPORT_GUID),\n");
816 Print(L
" which is defined in UEFI specification.\n");
817 Print(L
" -C: Clear capsule report variable (EFI_CAPSULE_REPORT_GUID),\n");
818 Print(L
" which is defined in UEFI specification.\n");
819 Print(L
" -P: Dump UEFI FMP protocol info, or get image with specified\n");
820 Print(L
" ImageTypeId and Index (decimal format) to a file if 'GET'\n");
821 Print(L
" option is used.\n");
822 Print(L
" -E: Dump UEFI ESRT table info.\n");
823 Print(L
" -G: Convert a BMP file to be an UX capsule,\n");
824 Print(L
" according to Windows Firmware Update document\n");
825 Print(L
" -N: Append a Capsule Header to an existing FMP capsule image\n");
826 Print(L
" with its ImageTypeId supported by the system,\n");
827 Print(L
" according to Windows Firmware Update document\n");
828 Print(L
" -O: Output new Capsule file name\n");
829 Print(L
" -D: Dump Capsule image header information, image payload\n");
830 Print(L
" information if it is an UX capsule and FMP header\n");
831 Print(L
" information if it is a FMP capsule.\n");
835 Update Capsule image.
837 @param[in] ImageHandle The image handle.
838 @param[in] SystemTable The system table.
840 @retval EFI_SUCCESS Command completed successfully.
841 @retval EFI_UNSUPPORTED Command usage unsupported.
842 @retval EFI_INVALID_PARAMETER Command usage invalid.
843 @retval EFI_NOT_FOUND The input file can't be found.
848 IN EFI_HANDLE ImageHandle
,
849 IN EFI_SYSTEM_TABLE
*SystemTable
853 RETURN_STATUS RStatus
;
854 UINTN FileSize
[MAX_CAPSULE_NUM
];
855 VOID
*CapsuleBuffer
[MAX_CAPSULE_NUM
];
856 EFI_CAPSULE_BLOCK_DESCRIPTOR
*BlockDescriptors
;
857 EFI_CAPSULE_HEADER
*CapsuleHeaderArray
[MAX_CAPSULE_NUM
+ 1];
858 UINT64 MaxCapsuleSize
;
859 EFI_RESET_TYPE ResetType
;
865 EFI_GUID ImageTypeId
;
869 if (EFI_ERROR(Status
)) {
870 Print(L
"Please use UEFI SHELL to run this application!\n", Status
);
875 return EFI_UNSUPPORTED
;
877 if (StrCmp(Argv
[1], L
"-D") == 0) {
879 Print(L
"CapsuleApp: Incorrect parameter count.\n");
880 return EFI_UNSUPPORTED
;
882 Status
= DumpCapsule(Argv
[2]);
885 if (StrCmp(Argv
[1], L
"-G") == 0) {
886 Status
= CreateBmpFmp();
889 if (StrCmp(Argv
[1], L
"-N") == 0) {
890 Status
= CreateNestedFmp();
893 if (StrCmp(Argv
[1], L
"-S") == 0) {
894 Status
= DumpCapsuleStatusVariable();
897 if (StrCmp(Argv
[1], L
"-C") == 0) {
898 Status
= ClearCapsuleStatusVariable();
901 if (StrCmp(Argv
[1], L
"-P") == 0) {
906 if (StrCmp(Argv
[2], L
"GET") != 0) {
907 Print(L
"CapsuleApp: Unrecognized option(%s).\n", Argv
[2]);
908 return EFI_UNSUPPORTED
;
911 Print(L
"CapsuleApp: Incorrect parameter count.\n");
912 return EFI_UNSUPPORTED
;
918 RStatus
= StrToGuid (Argv
[3], &ImageTypeId
);
919 if (RETURN_ERROR (RStatus
) || (Argv
[3][GUID_STRING_LENGTH
] != L
'\0')) {
920 Print (L
"Invalid ImageTypeId - %s\n", Argv
[3]);
921 return EFI_INVALID_PARAMETER
;
923 ImageIndex
= StrDecimalToUintn(Argv
[4]);
924 if (StrCmp(Argv
[5], L
"-O") != 0) {
925 Print(L
"CapsuleApp: NO output file name.\n");
926 return EFI_UNSUPPORTED
;
928 DumpFmpImage(&ImageTypeId
, ImageIndex
, Argv
[6]);
934 if (StrCmp(Argv
[1], L
"-E") == 0) {
939 if (Argv
[1][0] == L
'-') {
940 Print(L
"CapsuleApp: Unrecognized option(%s).\n", Argv
[1]);
941 return EFI_UNSUPPORTED
;
944 CapsuleFirstIndex
= 1;
946 if ((Argc
> 1) && (StrCmp(Argv
[Argc
- 1], L
"-NR") == 0)) {
948 CapsuleLastIndex
= Argc
- 2;
950 CapsuleLastIndex
= Argc
- 1;
952 CapsuleNum
= CapsuleLastIndex
- CapsuleFirstIndex
+ 1;
954 if (CapsuleFirstIndex
> CapsuleLastIndex
) {
955 Print(L
"CapsuleApp: NO capsule image.\n");
956 return EFI_UNSUPPORTED
;
958 if (CapsuleNum
> MAX_CAPSULE_NUM
) {
959 Print(L
"CapsuleApp: Too many capsule images.\n");
960 return EFI_UNSUPPORTED
;
963 ZeroMem(&CapsuleBuffer
, sizeof(CapsuleBuffer
));
964 ZeroMem(&FileSize
, sizeof(FileSize
));
965 BlockDescriptors
= NULL
;
967 for (Index
= 0; Index
< CapsuleNum
; Index
++) {
968 CapsuleName
= Argv
[CapsuleFirstIndex
+ Index
];
969 Status
= ReadFileToBuffer(CapsuleName
, &FileSize
[Index
], &CapsuleBuffer
[Index
]);
970 if (EFI_ERROR(Status
)) {
971 Print(L
"CapsuleApp: capsule image (%s) is not found.\n", CapsuleName
);
974 if (!IsValidCapsuleHeader (CapsuleBuffer
[Index
], FileSize
[Index
])) {
975 Print(L
"CapsuleApp: Capsule image (%s) is not a valid capsule.\n", CapsuleName
);
976 return EFI_INVALID_PARAMETER
;
981 // Every capsule use 2 descriptor 1 for data 1 for end
983 Status
= BuildGatherList(CapsuleBuffer
, FileSize
, CapsuleNum
, &BlockDescriptors
);
984 if (EFI_ERROR(Status
)) {
989 // Call the runtime service capsule.
992 for (Index
= 0; Index
< CapsuleNum
; Index
++) {
993 CapsuleHeaderArray
[Index
] = (EFI_CAPSULE_HEADER
*) CapsuleBuffer
[Index
];
994 if ((CapsuleHeaderArray
[Index
]->Flags
& CAPSULE_FLAGS_PERSIST_ACROSS_RESET
) != 0) {
998 CapsuleHeaderArray
[CapsuleNum
] = NULL
;
1001 // Inquire platform capability of UpdateCapsule.
1003 Status
= gRT
->QueryCapsuleCapabilities (CapsuleHeaderArray
, CapsuleNum
, &MaxCapsuleSize
, &ResetType
);
1004 if (EFI_ERROR(Status
)) {
1005 Print (L
"CapsuleApp: failed to query capsule capability - %r\n", Status
);
1009 for (Index
= 0; Index
< CapsuleNum
; Index
++) {
1010 if (FileSize
[Index
] > MaxCapsuleSize
) {
1011 Print (L
"CapsuleApp: capsule is too large to update, %ld is allowed\n", MaxCapsuleSize
);
1012 Status
= EFI_UNSUPPORTED
;
1018 // Check whether the input capsule image has the flag of persist across system reset.
1021 Status
= gRT
->UpdateCapsule(CapsuleHeaderArray
,CapsuleNum
,(UINTN
) BlockDescriptors
);
1022 if (Status
!= EFI_SUCCESS
) {
1023 Print (L
"CapsuleApp: failed to update capsule - %r\n", Status
);
1027 // For capsule with CAPSULE_FLAGS_PERSIST_ACROSS_RESET + CAPSULE_FLAGS_INITIATE_RESET,
1028 // a system reset should have been triggered by gRT->UpdateCapsule() calling above.
1030 // For capsule with CAPSULE_FLAGS_PERSIST_ACROSS_RESET and without CAPSULE_FLAGS_INITIATE_RESET,
1031 // check if -NR (no-reset) has been specified or not.
1035 // For capsule who has reset flag and no -NR (no-reset) has been specified, after calling UpdateCapsule service,
1036 // trigger a system reset to process capsule persist across a system reset.
1038 gRT
->ResetSystem (ResetType
, EFI_SUCCESS
, 0, NULL
);
1042 // For capsule who has no reset flag, only call UpdateCapsule Service without a
1043 // system reset. The service will process the capsule immediately.
1045 Status
= gRT
->UpdateCapsule (CapsuleHeaderArray
,CapsuleNum
,(UINTN
) BlockDescriptors
);
1046 if (Status
!= EFI_SUCCESS
) {
1047 Print (L
"CapsuleApp: failed to update capsule - %r\n", Status
);
1051 Status
= EFI_SUCCESS
;
1054 for (Index
= 0; Index
< CapsuleNum
; Index
++) {
1055 if (CapsuleBuffer
[Index
] != NULL
) {
1056 FreePool (CapsuleBuffer
[Index
]);
1060 CleanGatherList(BlockDescriptors
, CapsuleNum
);