]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Application/CapsuleApp/CapsuleApp.c
896acd3304c90e11b8fdac33c1cd0d5aa51c91df
[mirror_edk2.git] / MdeModulePkg / Application / CapsuleApp / CapsuleApp.c
1 /** @file
2 A shell application that triggers capsule update process.
3
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
9
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.
12
13 **/
14
15 #include <Uefi.h>
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>
31
32 #define CAPSULE_HEADER_SIZE 0x20
33
34 #define NESTED_CAPSULE_HEADER_SIZE SIZE_4KB
35 #define SYSTEM_FIRMWARE_FLAG 0x50000
36 #define DEVICE_FIRMWARE_FLAG 0x78010
37
38 #define MAJOR_VERSION 1
39 #define MINOR_VERSION 0
40
41 #define MAX_CAPSULE_NUM 10
42
43 extern UINTN Argc;
44 extern CHAR16 **Argv;
45
46 //
47 // Define how many block descriptors we want to test with.
48 //
49 UINTN NumberOfDescriptors = 1;
50 UINTN CapsuleFirstIndex;
51 UINTN CapsuleLastIndex;
52
53 /**
54 Dump capsule information
55
56 @param[in] CapsuleName The name of the capsule image.
57
58 @retval EFI_SUCCESS The capsule information is dumped.
59 @retval EFI_UNSUPPORTED Input parameter is not valid.
60 **/
61 EFI_STATUS
62 DumpCapsule (
63 IN CHAR16 *CapsuleName
64 );
65
66 /**
67 Dump capsule status variable.
68
69 @retval EFI_SUCCESS The capsule status variable is dumped.
70 @retval EFI_UNSUPPORTED Input parameter is not valid.
71 **/
72 EFI_STATUS
73 DumpCapsuleStatusVariable (
74 VOID
75 );
76
77 /**
78 Dump FMP protocol info.
79 **/
80 VOID
81 DumpFmpData (
82 VOID
83 );
84
85 /**
86 Dump FMP image data.
87
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.
93 **/
94 VOID
95 DumpFmpImage (
96 IN EFI_GUID *ImageTypeId,
97 IN UINTN ImageIndex,
98 IN CHAR16 *ImageName
99 );
100
101 /**
102 Dump ESRT info.
103 **/
104 VOID
105 DumpEsrtData (
106 VOID
107 );
108
109 /**
110 Dump Provisioned Capsule.
111
112 @param[in] DumpCapsuleInfo The flag to indicate whether to dump the capsule inforomation.
113 **/
114 VOID
115 DumpProvisionedCapsule (
116 IN BOOLEAN DumpCapsuleInfo
117 );
118
119 /**
120 Dump all EFI System Partition.
121 **/
122 VOID
123 DumpAllEfiSysPartition (
124 VOID
125 );
126
127 /**
128 Process Capsule On Disk.
129
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
135
136 @retval EFI_SUCCESS Capsule on disk success.
137 @retval others Capsule on disk fail.
138
139 **/
140 EFI_STATUS
141 ProcessCapsuleOnDisk (
142 IN VOID **CapsuleBuffer,
143 IN UINTN *CapsuleBufferSize,
144 IN CHAR16 **FilePath,
145 IN CHAR16 *Map,
146 IN UINTN CapsuleNum
147 );
148
149 /**
150 Read a file.
151
152 @param[in] FileName The file to be read.
153 @param[out] BufferSize The file buffer size
154 @param[out] Buffer The file buffer
155
156 @retval EFI_SUCCESS Read file successfully
157 @retval EFI_NOT_FOUND Shell protocol or file not found
158 @retval others Read file failed
159 **/
160 EFI_STATUS
161 ReadFileToBuffer (
162 IN CHAR16 *FileName,
163 OUT UINTN *BufferSize,
164 OUT VOID **Buffer
165 );
166
167 /**
168 Write a file.
169
170 @param[in] FileName The file to be written.
171 @param[in] BufferSize The file buffer size
172 @param[in] Buffer The file buffer
173
174 @retval EFI_SUCCESS Write file successfully
175 @retval EFI_NOT_FOUND Shell protocol not found
176 @retval others Write file failed
177 **/
178 EFI_STATUS
179 WriteFileFromBuffer (
180 IN CHAR16 *FileName,
181 IN UINTN BufferSize,
182 IN VOID *Buffer
183 );
184
185 /**
186
187 This function parse application ARG.
188
189 @return Status
190 **/
191 EFI_STATUS
192 GetArg (
193 VOID
194 );
195
196 /**
197 Create UX capsule.
198
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.
202 **/
203 EFI_STATUS
204 CreateBmpFmp (
205 VOID
206 )
207 {
208 CHAR16 *OutputCapsuleName;
209 VOID *BmpBuffer;
210 UINTN FileSize;
211 CHAR16 *BmpName;
212 UINT8 *FullCapsuleBuffer;
213 UINTN FullCapsuleBufferSize;
214 EFI_DISPLAY_CAPSULE *DisplayCapsule;
215 EFI_STATUS Status;
216 EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop;
217 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
218 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *GopBlt;
219 UINTN GopBltSize;
220 UINTN Height;
221 UINTN Width;
222
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;
227 }
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
234
235 if (Argc != 5) {
236 Print(L"CapsuleApp: Incorrect parameter count.\n");
237 return EFI_UNSUPPORTED;
238 }
239
240 if (StrCmp(Argv[3], L"-O") != 0) {
241 Print(L"CapsuleApp: NO output capsule name.\n");
242 return EFI_UNSUPPORTED;
243 }
244 OutputCapsuleName = Argv[4];
245
246 BmpBuffer = NULL;
247 FileSize = 0;
248 FullCapsuleBuffer = NULL;
249
250 BmpName = Argv[2];
251 Status = ReadFileToBuffer(BmpName, &FileSize, &BmpBuffer);
252 if (EFI_ERROR(Status)) {
253 Print(L"CapsuleApp: BMP image (%s) is not found.\n", BmpName);
254 goto Done;
255 }
256
257 GopBlt = NULL;
258 Status = TranslateBmpToGopBlt (
259 BmpBuffer,
260 FileSize,
261 &GopBlt,
262 &GopBltSize,
263 &Height,
264 &Width
265 );
266 if (EFI_ERROR(Status)) {
267 Print(L"CapsuleApp: BMP image (%s) is not valid.\n", BmpName);
268 goto Done;
269 }
270 if (GopBlt != NULL) {
271 FreePool (GopBlt);
272 }
273 Print(L"BMP image (%s), Width - %d, Height - %d\n", BmpName, Width, Height);
274
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);
278 goto Done;
279 }
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);
283 goto Done;
284 }
285
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;
291 goto Done;
292 }
293
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;
299
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;
305
306 //
307 // Center the bitmap horizontally
308 //
309 DisplayCapsule->ImagePayload.OffsetX = (UINT32)((Info->HorizontalResolution - Width) / 2);
310
311 //
312 // Put bitmap 3/4 down the display. If bitmap is too tall, then align bottom
313 // of bitmap at bottom of display.
314 //
315 DisplayCapsule->ImagePayload.OffsetY =
316 MIN (
317 (UINT32)(Info->VerticalResolution - Height),
318 (UINT32)(((3 * Info->VerticalResolution) - (2 * Height)) / 4)
319 );
320
321 Print(L"BMP image (%s), OffsetX - %d, OffsetY - %d\n",
322 BmpName,
323 DisplayCapsule->ImagePayload.OffsetX,
324 DisplayCapsule->ImagePayload.OffsetY
325 );
326
327 CopyMem((DisplayCapsule + 1), BmpBuffer, FileSize);
328
329 DisplayCapsule->ImagePayload.Checksum = CalculateCheckSum8(FullCapsuleBuffer, FullCapsuleBufferSize);
330
331 Status = WriteFileFromBuffer(OutputCapsuleName, FullCapsuleBufferSize, FullCapsuleBuffer);
332 Print(L"CapsuleApp: Write %s %r\n", OutputCapsuleName, Status);
333
334 Done:
335 if (BmpBuffer != NULL) {
336 FreePool(BmpBuffer);
337 }
338
339 if (FullCapsuleBuffer != NULL) {
340 FreePool(FullCapsuleBuffer);
341 }
342
343 return Status;
344 }
345
346 /**
347 Get ImageTypeId in the FMP capsule header.
348
349 @param[in] CapsuleHeader The FMP capsule image header.
350
351 @return ImageTypeId
352 **/
353 EFI_GUID *
354 GetCapsuleImageTypeId (
355 IN EFI_CAPSULE_HEADER *CapsuleHeader
356 )
357 {
358 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;
359 UINT64 *ItemOffsetList;
360 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
361
362 FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);
363 ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
364 if (FmpCapsuleHeader->PayloadItemCount == 0) {
365 return NULL;
366 }
367 ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[FmpCapsuleHeader->EmbeddedDriverCount]);
368 return &ImageHeader->UpdateImageTypeId;
369 }
370
371 /**
372 Get ESRT FwType according to ImageTypeId
373
374 @param[in] ImageTypeId ImageTypeId of an FMP capsule.
375
376 @return ESRT FwType
377 **/
378 UINT32
379 GetEsrtFwType (
380 IN EFI_GUID *ImageTypeId
381 )
382 {
383 EFI_STATUS Status;
384 EFI_SYSTEM_RESOURCE_TABLE *Esrt;
385 EFI_SYSTEM_RESOURCE_ENTRY *EsrtEntry;
386 UINTN Index;
387
388 //
389 // Check ESRT
390 //
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;
398 }
399 }
400 }
401
402 return ESRT_FW_TYPE_UNKNOWN;
403 }
404
405 /**
406 Validate if it is valid capsule header
407
408 This function assumes the caller provided correct CapsuleHeader pointer
409 and CapsuleSize.
410
411 This function validates the fields in EFI_CAPSULE_HEADER.
412
413 @param[in] CapsuleHeader Points to a capsule header.
414 @param[in] CapsuleSize Size of the whole capsule image.
415
416 **/
417 BOOLEAN
418 IsValidCapsuleHeader (
419 IN EFI_CAPSULE_HEADER *CapsuleHeader,
420 IN UINT64 CapsuleSize
421 )
422 {
423 if (CapsuleSize < sizeof (EFI_CAPSULE_HEADER)) {
424 return FALSE;
425 }
426 if (CapsuleHeader->CapsuleImageSize != CapsuleSize) {
427 return FALSE;
428 }
429 if (CapsuleHeader->HeaderSize > CapsuleHeader->CapsuleImageSize) {
430 return FALSE;
431 }
432 if (CapsuleHeader->HeaderSize < sizeof (EFI_CAPSULE_HEADER)) {
433 return FALSE;
434 }
435
436 return TRUE;
437 }
438
439 /**
440 Return if this CapsuleGuid is a FMP capsule GUID or not.
441
442 @param[in] CapsuleGuid A pointer to EFI_GUID
443
444 @retval TRUE It is a FMP capsule GUID.
445 @retval FALSE It is not a FMP capsule GUID.
446 **/
447 BOOLEAN
448 IsFmpCapsuleGuid (
449 IN EFI_GUID *CapsuleGuid
450 )
451 {
452 if (CompareGuid(&gEfiFmpCapsuleGuid, CapsuleGuid)) {
453 return TRUE;
454 }
455
456 return FALSE;
457 }
458
459 /**
460 Append a capsule header on top of current image.
461 This function follows Windows UEFI Firmware Update Platform document.
462
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.
466 **/
467 EFI_STATUS
468 CreateNestedFmp (
469 VOID
470 )
471 {
472 CHAR16 *OutputCapsuleName;
473 VOID *CapsuleBuffer;
474 UINTN FileSize;
475 CHAR16 *CapsuleName;
476 UINT8 *FullCapsuleBuffer;
477 UINTN FullCapsuleBufferSize;
478 EFI_CAPSULE_HEADER *NestedCapsuleHeader;
479 EFI_GUID *ImageTypeId;
480 UINT32 FwType;
481 EFI_STATUS Status;
482
483 if (Argc != 5) {
484 Print(L"CapsuleApp: Incorrect parameter count.\n");
485 return EFI_UNSUPPORTED;
486 }
487
488 if (StrCmp(Argv[3], L"-O") != 0) {
489 Print(L"CapsuleApp: NO output capsule name.\n");
490 return EFI_UNSUPPORTED;
491 }
492 OutputCapsuleName = Argv[4];
493
494 CapsuleBuffer = NULL;
495 FileSize = 0;
496 FullCapsuleBuffer = NULL;
497
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);
502 goto Done;
503 }
504 if (!IsValidCapsuleHeader (CapsuleBuffer, FileSize)) {
505 Print(L"CapsuleApp: Capsule image (%s) is not a valid capsule.\n", CapsuleName);
506 Status = EFI_INVALID_PARAMETER;
507 goto Done;
508 }
509
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;
513 goto Done;
514 }
515
516 ImageTypeId = GetCapsuleImageTypeId(CapsuleBuffer);
517 if (ImageTypeId == NULL) {
518 Print(L"CapsuleApp: Capsule ImageTypeId is not found.\n");
519 Status = EFI_INVALID_PARAMETER;
520 goto Done;
521 }
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;
526 goto Done;
527 }
528
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;
534 goto Done;
535 }
536
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;
543
544 CopyMem((UINT8 *)NestedCapsuleHeader + NestedCapsuleHeader->HeaderSize, CapsuleBuffer, FileSize);
545
546 Status = WriteFileFromBuffer(OutputCapsuleName, FullCapsuleBufferSize, FullCapsuleBuffer);
547 Print(L"CapsuleApp: Write %s %r\n", OutputCapsuleName, Status);
548
549 Done:
550 if (CapsuleBuffer != NULL) {
551 FreePool(CapsuleBuffer);
552 }
553
554 if (FullCapsuleBuffer != NULL) {
555 FreePool(FullCapsuleBuffer);
556 }
557
558 return Status;
559 }
560
561
562 /**
563 Clear capsule status variable.
564
565 @retval EFI_SUCCESS The capsule status variable is cleared.
566 **/
567 EFI_STATUS
568 ClearCapsuleStatusVariable (
569 VOID
570 )
571 {
572 EFI_STATUS Status;
573 UINT32 Index;
574 CHAR16 CapsuleVarName[20];
575 CHAR16 *TempVarName;
576 BOOLEAN Found;
577
578 StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CapsuleVarName[0]), L"Capsule");
579 TempVarName = CapsuleVarName + StrLen (CapsuleVarName);
580 Index = 0;
581
582 Found = FALSE;
583 while (TRUE) {
584 UnicodeSPrint (TempVarName, 5 * sizeof(CHAR16), L"%04x", Index);
585
586 Status = gRT->SetVariable (
587 CapsuleVarName,
588 &gEfiCapsuleReportGuid,
589 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
590 0,
591 (VOID *)NULL
592 );
593 if (Status == EFI_NOT_FOUND) {
594 //
595 // There is no more capsule variables, quit
596 //
597 break;
598 }
599 Found = TRUE;
600
601 Print (L"Clear %s %r\n", CapsuleVarName, Status);
602
603 Index++;
604 if (Index > 0xFFFF) {
605 break;
606 }
607 }
608
609 if (!Found) {
610 Print (L"No any Capsule#### variable found\n");
611 }
612
613 return EFI_SUCCESS;
614 }
615
616 /**
617 Build Gather list for a list of capsule images.
618
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
623
624 @retval EFI_SUCCESS The block descriptors for the capsule images are constructed.
625 **/
626 EFI_STATUS
627 BuildGatherList (
628 IN VOID **CapsuleBuffer,
629 IN UINTN *FileSize,
630 IN UINTN CapsuleNum,
631 OUT EFI_CAPSULE_BLOCK_DESCRIPTOR **BlockDescriptors
632 )
633 {
634 EFI_STATUS Status;
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;
640 UINT8 *TempDataPtr;
641 UINTN SizeLeft;
642 UINTN Size;
643 INT32 Count;
644 INT32 Number;
645 UINTN Index;
646
647 TempBlockPtr = NULL;
648 BlockDescriptors1 = NULL;
649 BlockDescriptors2 = NULL;
650 BlockDescriptorPre = NULL;
651 BlockDescriptorsHeader = NULL;
652
653 for (Index = 0; Index < CapsuleNum; Index++) {
654 //
655 // Allocate memory for the descriptors.
656 //
657 if (NumberOfDescriptors == 1) {
658 Count = 2;
659 } else {
660 Count = (INT32)(NumberOfDescriptors + 2) / 2;
661 }
662
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;
668 goto ERREXIT;
669 } else {
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]);
672 }
673
674 //
675 // Record descirptor header
676 //
677 if (Index == 0) {
678 BlockDescriptorsHeader = BlockDescriptors1;
679 }
680
681 if (BlockDescriptorPre != NULL) {
682 BlockDescriptorPre->Union.ContinuationPointer = (UINTN) BlockDescriptors1;
683 BlockDescriptorPre->Length = 0;
684 }
685
686 //
687 // Fill them in
688 //
689 TempBlockPtr = BlockDescriptors1;
690 TempDataPtr = CapsuleBuffer[Index];
691 SizeLeft = FileSize[Index];
692 for (Number = 0; (Number < Count - 1) && (SizeLeft != 0); Number++) {
693 //
694 // Divide remaining data in half
695 //
696 if (NumberOfDescriptors != 1) {
697 if (SizeLeft == 1) {
698 Size = 1;
699 } else {
700 Size = SizeLeft / 2;
701 }
702 } else {
703 Size = SizeLeft;
704 }
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);
708 SizeLeft -= Size;
709 TempDataPtr += Size;
710 TempBlockPtr++;
711 }
712
713 //
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.
718 //
719 if ((NumberOfDescriptors != 1) && (SizeLeft != 0)) {
720 Count = (INT32)(NumberOfDescriptors + 2) - Count;
721 if (Count == 1) {
722 Count++;
723 }
724
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;
730 goto ERREXIT;
731 }
732
733 //
734 // Point the first list's last element to point to this second list.
735 //
736 TempBlockPtr->Union.ContinuationPointer = (UINTN) BlockDescriptors2;
737
738 TempBlockPtr->Length = 0;
739 TempBlockPtr = BlockDescriptors2;
740 for (Number = 0; Number < Count - 1; Number++) {
741 //
742 // If second-to-last one, then dump rest to this element
743 //
744 if (Number == (Count - 2)) {
745 Size = SizeLeft;
746 } else {
747 //
748 // Divide remaining data in half
749 //
750 if (SizeLeft == 1) {
751 Size = 1;
752 } else {
753 Size = SizeLeft / 2;
754 }
755 }
756
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);
760 SizeLeft -= Size;
761 TempDataPtr += Size;
762 TempBlockPtr++;
763 if (SizeLeft == 0) {
764 break;
765 }
766 }
767 }
768
769 BlockDescriptorPre = TempBlockPtr;
770 BlockDescriptors1 = NULL;
771 }
772
773 //
774 // Null-terminate.
775 //
776 if (TempBlockPtr != NULL) {
777 TempBlockPtr->Union.ContinuationPointer = (UINTN)NULL;
778 TempBlockPtr->Length = 0;
779 *BlockDescriptors = BlockDescriptorsHeader;
780 }
781
782 return EFI_SUCCESS;
783
784 ERREXIT:
785 if (BlockDescriptors1 != NULL) {
786 FreePool(BlockDescriptors1);
787 }
788
789 if (BlockDescriptors2 != NULL) {
790 FreePool(BlockDescriptors2);
791 }
792
793 return Status;
794 }
795
796 /**
797 Clear the Gather list for a list of capsule images.
798
799 @param[in] BlockDescriptors The block descriptors for the capsule images
800 @param[in] CapsuleNum The count of capsule images
801 **/
802 VOID
803 CleanGatherList (
804 IN EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors,
805 IN UINTN CapsuleNum
806 )
807 {
808 EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr;
809 EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr1;
810 EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr2;
811 UINTN Index;
812
813 if (BlockDescriptors != NULL) {
814 TempBlockPtr1 = BlockDescriptors;
815 while (1){
816 TempBlockPtr = TempBlockPtr1;
817 for (Index = 0; Index < CapsuleNum; Index++) {
818 if (TempBlockPtr[Index].Length == 0) {
819 break;
820 }
821 }
822
823 if (TempBlockPtr[Index].Union.ContinuationPointer == (UINTN)NULL) {
824 break;
825 }
826
827 TempBlockPtr2 = (VOID *) ((UINTN) TempBlockPtr[Index].Union.ContinuationPointer);
828 FreePool(TempBlockPtr1);
829 TempBlockPtr1 = TempBlockPtr2;
830 }
831 }
832 }
833
834 /**
835 Print APP usage.
836 **/
837 VOID
838 PrintUsage (
839 VOID
840 )
841 {
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");
878 }
879
880 /**
881 Update Capsule image.
882
883 @param[in] ImageHandle The image handle.
884 @param[in] SystemTable The system table.
885
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.
890 **/
891 EFI_STATUS
892 EFIAPI
893 UefiMain (
894 IN EFI_HANDLE ImageHandle,
895 IN EFI_SYSTEM_TABLE *SystemTable
896 )
897 {
898 EFI_STATUS Status;
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;
906 BOOLEAN NeedReset;
907 BOOLEAN NoReset;
908 BOOLEAN CapsuleOnDisk;
909 CHAR16 *CapsuleName;
910 CHAR16 *CapsuleNames[MAX_CAPSULE_NUM];
911 CHAR16 *MapFsStr;
912 UINTN CapsuleNum;
913 UINTN Index;
914 UINTN ParaOdIndex;
915 UINTN ParaNrIndex;
916 EFI_GUID ImageTypeId;
917 UINTN ImageIndex;
918
919 MapFsStr = NULL;
920 CapsuleNum = 0;
921
922 Status = GetArg();
923 if (EFI_ERROR(Status)) {
924 Print(L"Please use UEFI SHELL to run this application!\n", Status);
925 return Status;
926 }
927 if (Argc < 2) {
928 PrintUsage();
929 return EFI_UNSUPPORTED;
930 }
931 if (StrCmp(Argv[1], L"-D") == 0) {
932 if (Argc != 3) {
933 Print(L"CapsuleApp: Incorrect parameter count.\n");
934 return EFI_UNSUPPORTED;
935 }
936 Status = DumpCapsule(Argv[2]);
937 return Status;
938 }
939 if (StrCmp(Argv[1], L"-G") == 0) {
940 Status = CreateBmpFmp();
941 return Status;
942 }
943 if (StrCmp(Argv[1], L"-N") == 0) {
944 Status = CreateNestedFmp();
945 return Status;
946 }
947 if (StrCmp(Argv[1], L"-S") == 0) {
948 Status = DumpCapsuleStatusVariable();
949 return EFI_SUCCESS;
950 }
951 if (StrCmp(Argv[1], L"-C") == 0) {
952 Status = ClearCapsuleStatusVariable();
953 return Status;
954 }
955 if (StrCmp(Argv[1], L"-P") == 0) {
956 if (Argc == 2) {
957 DumpFmpData();
958 }
959 if (Argc >= 3) {
960 if (StrCmp(Argv[2], L"GET") != 0) {
961 Print(L"CapsuleApp: Unrecognized option(%s).\n", Argv[2]);
962 return EFI_UNSUPPORTED;
963 } else {
964 if (Argc != 7) {
965 Print(L"CapsuleApp: Incorrect parameter count.\n");
966 return EFI_UNSUPPORTED;
967 }
968
969 //
970 // FMP->GetImage()
971 //
972 RStatus = StrToGuid (Argv[3], &ImageTypeId);
973 if (RETURN_ERROR (RStatus) || (Argv[3][GUID_STRING_LENGTH] != L'\0')) {
974 Print (L"Invalid ImageTypeId - %s\n", Argv[3]);
975 return EFI_INVALID_PARAMETER;
976 }
977 ImageIndex = StrDecimalToUintn(Argv[4]);
978 if (StrCmp(Argv[5], L"-O") != 0) {
979 Print(L"CapsuleApp: NO output file name.\n");
980 return EFI_UNSUPPORTED;
981 }
982 DumpFmpImage(&ImageTypeId, ImageIndex, Argv[6]);
983 }
984 }
985 return EFI_SUCCESS;
986 }
987
988 if (StrCmp(Argv[1], L"-E") == 0) {
989 DumpEsrtData();
990 return EFI_SUCCESS;
991 }
992
993 if (StrCmp(Argv[1], L"-L") == 0) {
994 if (Argc >= 3 && StrCmp(Argv[2], L"INFO") == 0) {
995 DumpProvisionedCapsule(TRUE);
996 } else {
997 DumpProvisionedCapsule(FALSE);
998 }
999 return EFI_SUCCESS;
1000 }
1001
1002 if (StrCmp(Argv[1], L"-F") == 0) {
1003 DumpAllEfiSysPartition();
1004 return EFI_SUCCESS;
1005 }
1006
1007 if (Argv[1][0] == L'-') {
1008 Print(L"CapsuleApp: Unrecognized option(%s).\n", Argv[1]);
1009 return EFI_UNSUPPORTED;
1010 }
1011
1012 CapsuleFirstIndex = 1;
1013 NoReset = FALSE;
1014 CapsuleOnDisk = FALSE;
1015 ParaOdIndex = 0;
1016 ParaNrIndex = 0;
1017
1018 for (Index = 1; Index < Argc; Index++) {
1019 if (StrCmp(Argv[Index], L"-OD") == 0) {
1020 ParaOdIndex = Index;
1021 CapsuleOnDisk = TRUE;
1022 } else if (StrCmp(Argv[Index], L"-NR") == 0) {
1023 ParaNrIndex = Index;
1024 NoReset = TRUE;
1025 }
1026 }
1027
1028 if (ParaOdIndex != 0) {
1029 if (ParaOdIndex == Argc - 1) {
1030 MapFsStr = NULL;
1031 } else if (ParaOdIndex == Argc - 2) {
1032 MapFsStr = Argv[Argc-1];
1033 } else {
1034 Print (L"CapsuleApp: Invalid Position for -OD Options\n");
1035 Status = EFI_INVALID_PARAMETER;
1036 goto Done;
1037 }
1038
1039 if (ParaNrIndex != 0) {
1040 if (ParaNrIndex + 1 == ParaOdIndex) {
1041 CapsuleLastIndex = ParaNrIndex - 1;
1042 } else {
1043 Print (L"CapsuleApp: Invalid Position for -NR Options\n");
1044 Status = EFI_INVALID_PARAMETER;
1045 goto Done;
1046 }
1047 } else {
1048 CapsuleLastIndex = ParaOdIndex - 1;
1049 }
1050 } else {
1051 if (ParaNrIndex != 0) {
1052 if (ParaNrIndex == Argc -1) {
1053 CapsuleLastIndex = ParaNrIndex - 1;
1054 } else {
1055 Print (L"CapsuleApp: Invalid Position for -NR Options\n");
1056 Status = EFI_INVALID_PARAMETER;
1057 goto Done;
1058 }
1059 } else {
1060 CapsuleLastIndex = Argc - 1;
1061 }
1062 }
1063
1064 CapsuleNum = CapsuleLastIndex - CapsuleFirstIndex + 1;
1065
1066 if (CapsuleFirstIndex > CapsuleLastIndex) {
1067 Print(L"CapsuleApp: NO capsule image.\n");
1068 return EFI_UNSUPPORTED;
1069 }
1070 if (CapsuleNum > MAX_CAPSULE_NUM) {
1071 Print(L"CapsuleApp: Too many capsule images.\n");
1072 return EFI_UNSUPPORTED;
1073 }
1074
1075 ZeroMem(&CapsuleBuffer, sizeof(CapsuleBuffer));
1076 ZeroMem(&CapsuleBufferSize, sizeof(CapsuleBufferSize));
1077 BlockDescriptors = NULL;
1078
1079 for (Index = 0; Index < CapsuleNum; Index++) {
1080 CapsuleName = Argv[CapsuleFirstIndex + Index];
1081 Status = ReadFileToBuffer(CapsuleName, &CapsuleBufferSize[Index], &CapsuleBuffer[Index]);
1082 if (EFI_ERROR(Status)) {
1083 Print(L"CapsuleApp: capsule image (%s) is not found.\n", CapsuleName);
1084 goto Done;
1085 }
1086 if (!IsValidCapsuleHeader (CapsuleBuffer[Index], CapsuleBufferSize[Index])) {
1087 Print(L"CapsuleApp: Capsule image (%s) is not a valid capsule.\n", CapsuleName);
1088 return EFI_INVALID_PARAMETER;
1089 }
1090 CapsuleNames[Index] = CapsuleName;
1091 }
1092
1093 //
1094 // Every capsule use 2 descriptor 1 for data 1 for end
1095 //
1096 Status = BuildGatherList(CapsuleBuffer, CapsuleBufferSize, CapsuleNum, &BlockDescriptors);
1097 if (EFI_ERROR(Status)) {
1098 goto Done;
1099 }
1100
1101 //
1102 // Call the runtime service capsule.
1103 //
1104 NeedReset = FALSE;
1105 for (Index = 0; Index < CapsuleNum; Index++) {
1106 CapsuleHeaderArray[Index] = (EFI_CAPSULE_HEADER *) CapsuleBuffer[Index];
1107 if ((CapsuleHeaderArray[Index]->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {
1108 NeedReset = TRUE;
1109 }
1110 }
1111 CapsuleHeaderArray[CapsuleNum] = NULL;
1112
1113 //
1114 // Inquire platform capability of UpdateCapsule.
1115 //
1116 Status = gRT->QueryCapsuleCapabilities (CapsuleHeaderArray, CapsuleNum, &MaxCapsuleSize, &ResetType);
1117 if (EFI_ERROR(Status)) {
1118 Print (L"CapsuleApp: failed to query capsule capability - %r\n", Status);
1119 goto Done;
1120 }
1121
1122 for (Index = 0; Index < CapsuleNum; Index++) {
1123 if (CapsuleBufferSize[Index] > MaxCapsuleSize) {
1124 Print (L"CapsuleApp: capsule is too large to update, %ld is allowed\n", MaxCapsuleSize);
1125 Status = EFI_UNSUPPORTED;
1126 goto Done;
1127 }
1128 }
1129
1130 //
1131 // Check whether is capsule on disk.
1132 //
1133 if (CapsuleOnDisk) {
1134 Status = ProcessCapsuleOnDisk (CapsuleBuffer, CapsuleBufferSize, CapsuleNames, MapFsStr, CapsuleNum);
1135 if (Status != EFI_SUCCESS) {
1136 Print (L"CapsuleApp: failed to update capsule - %r\n", Status);
1137 goto Done;
1138 } else {
1139 if (!NoReset) {
1140 gRT->ResetSystem (ResetType, EFI_SUCCESS, 0, NULL);
1141 } else {
1142 goto Done;
1143 }
1144 }
1145 }
1146
1147 //
1148 // Check whether the input capsule image has the flag of persist across system reset.
1149 //
1150 if (NeedReset) {
1151 Status = gRT->UpdateCapsule(CapsuleHeaderArray,CapsuleNum,(UINTN) BlockDescriptors);
1152 if (Status != EFI_SUCCESS) {
1153 Print (L"CapsuleApp: failed to update capsule - %r\n", Status);
1154 goto Done;
1155 }
1156 //
1157 // For capsule with CAPSULE_FLAGS_PERSIST_ACROSS_RESET + CAPSULE_FLAGS_INITIATE_RESET,
1158 // a system reset should have been triggered by gRT->UpdateCapsule() calling above.
1159 //
1160 // For capsule with CAPSULE_FLAGS_PERSIST_ACROSS_RESET and without CAPSULE_FLAGS_INITIATE_RESET,
1161 // check if -NR (no-reset) has been specified or not.
1162 //
1163 if (!NoReset) {
1164 //
1165 // For capsule who has reset flag and no -NR (no-reset) has been specified, after calling UpdateCapsule service,
1166 // trigger a system reset to process capsule persist across a system reset.
1167 //
1168 gRT->ResetSystem (ResetType, EFI_SUCCESS, 0, NULL);
1169 }
1170 } else {
1171 //
1172 // For capsule who has no reset flag, only call UpdateCapsule Service without a
1173 // system reset. The service will process the capsule immediately.
1174 //
1175 Status = gRT->UpdateCapsule (CapsuleHeaderArray,CapsuleNum,(UINTN) BlockDescriptors);
1176 if (Status != EFI_SUCCESS) {
1177 Print (L"CapsuleApp: failed to update capsule - %r\n", Status);
1178 }
1179 }
1180
1181 Status = EFI_SUCCESS;
1182
1183 Done:
1184 for (Index = 0; Index < CapsuleNum; Index++) {
1185 if (CapsuleBuffer[Index] != NULL) {
1186 FreePool (CapsuleBuffer[Index]);
1187 }
1188 }
1189
1190 CleanGatherList(BlockDescriptors, CapsuleNum);
1191
1192 return Status;
1193 }