IntelSiliconPkg: Replace BSD License with BSD+Patent License
[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 BlockDescriptors = NULL;
920 MapFsStr = NULL;
921 CapsuleNum = 0;
922
923 Status = GetArg();
924 if (EFI_ERROR(Status)) {
925 Print(L"Please use UEFI SHELL to run this application!\n", Status);
926 return Status;
927 }
928 if (Argc < 2) {
929 PrintUsage();
930 return EFI_UNSUPPORTED;
931 }
932 if (StrCmp(Argv[1], L"-D") == 0) {
933 if (Argc != 3) {
934 Print(L"CapsuleApp: Incorrect parameter count.\n");
935 return EFI_UNSUPPORTED;
936 }
937 Status = DumpCapsule(Argv[2]);
938 return Status;
939 }
940 if (StrCmp(Argv[1], L"-G") == 0) {
941 Status = CreateBmpFmp();
942 return Status;
943 }
944 if (StrCmp(Argv[1], L"-N") == 0) {
945 Status = CreateNestedFmp();
946 return Status;
947 }
948 if (StrCmp(Argv[1], L"-S") == 0) {
949 Status = DumpCapsuleStatusVariable();
950 return EFI_SUCCESS;
951 }
952 if (StrCmp(Argv[1], L"-C") == 0) {
953 Status = ClearCapsuleStatusVariable();
954 return Status;
955 }
956 if (StrCmp(Argv[1], L"-P") == 0) {
957 if (Argc == 2) {
958 DumpFmpData();
959 }
960 if (Argc >= 3) {
961 if (StrCmp(Argv[2], L"GET") != 0) {
962 Print(L"CapsuleApp: Unrecognized option(%s).\n", Argv[2]);
963 return EFI_UNSUPPORTED;
964 } else {
965 if (Argc != 7) {
966 Print(L"CapsuleApp: Incorrect parameter count.\n");
967 return EFI_UNSUPPORTED;
968 }
969
970 //
971 // FMP->GetImage()
972 //
973 RStatus = StrToGuid (Argv[3], &ImageTypeId);
974 if (RETURN_ERROR (RStatus) || (Argv[3][GUID_STRING_LENGTH] != L'\0')) {
975 Print (L"Invalid ImageTypeId - %s\n", Argv[3]);
976 return EFI_INVALID_PARAMETER;
977 }
978 ImageIndex = StrDecimalToUintn(Argv[4]);
979 if (StrCmp(Argv[5], L"-O") != 0) {
980 Print(L"CapsuleApp: NO output file name.\n");
981 return EFI_UNSUPPORTED;
982 }
983 DumpFmpImage(&ImageTypeId, ImageIndex, Argv[6]);
984 }
985 }
986 return EFI_SUCCESS;
987 }
988
989 if (StrCmp(Argv[1], L"-E") == 0) {
990 DumpEsrtData();
991 return EFI_SUCCESS;
992 }
993
994 if (StrCmp(Argv[1], L"-L") == 0) {
995 if (Argc >= 3 && StrCmp(Argv[2], L"INFO") == 0) {
996 DumpProvisionedCapsule(TRUE);
997 } else {
998 DumpProvisionedCapsule(FALSE);
999 }
1000 return EFI_SUCCESS;
1001 }
1002
1003 if (StrCmp(Argv[1], L"-F") == 0) {
1004 DumpAllEfiSysPartition();
1005 return EFI_SUCCESS;
1006 }
1007
1008 if (Argv[1][0] == L'-') {
1009 Print(L"CapsuleApp: Unrecognized option(%s).\n", Argv[1]);
1010 return EFI_UNSUPPORTED;
1011 }
1012
1013 CapsuleFirstIndex = 1;
1014 NoReset = FALSE;
1015 CapsuleOnDisk = FALSE;
1016 ParaOdIndex = 0;
1017 ParaNrIndex = 0;
1018
1019 for (Index = 1; Index < Argc; Index++) {
1020 if (StrCmp(Argv[Index], L"-OD") == 0) {
1021 ParaOdIndex = Index;
1022 CapsuleOnDisk = TRUE;
1023 } else if (StrCmp(Argv[Index], L"-NR") == 0) {
1024 ParaNrIndex = Index;
1025 NoReset = TRUE;
1026 }
1027 }
1028
1029 if (ParaOdIndex != 0) {
1030 if (ParaOdIndex == Argc - 1) {
1031 MapFsStr = NULL;
1032 } else if (ParaOdIndex == Argc - 2) {
1033 MapFsStr = Argv[Argc-1];
1034 } else {
1035 Print (L"CapsuleApp: Invalid Position for -OD Options\n");
1036 Status = EFI_INVALID_PARAMETER;
1037 goto Done;
1038 }
1039
1040 if (ParaNrIndex != 0) {
1041 if (ParaNrIndex + 1 == ParaOdIndex) {
1042 CapsuleLastIndex = ParaNrIndex - 1;
1043 } else {
1044 Print (L"CapsuleApp: Invalid Position for -NR Options\n");
1045 Status = EFI_INVALID_PARAMETER;
1046 goto Done;
1047 }
1048 } else {
1049 CapsuleLastIndex = ParaOdIndex - 1;
1050 }
1051 } else {
1052 if (ParaNrIndex != 0) {
1053 if (ParaNrIndex == Argc -1) {
1054 CapsuleLastIndex = ParaNrIndex - 1;
1055 } else {
1056 Print (L"CapsuleApp: Invalid Position for -NR Options\n");
1057 Status = EFI_INVALID_PARAMETER;
1058 goto Done;
1059 }
1060 } else {
1061 CapsuleLastIndex = Argc - 1;
1062 }
1063 }
1064
1065 CapsuleNum = CapsuleLastIndex - CapsuleFirstIndex + 1;
1066
1067 if (CapsuleFirstIndex > CapsuleLastIndex) {
1068 Print(L"CapsuleApp: NO capsule image.\n");
1069 return EFI_UNSUPPORTED;
1070 }
1071 if (CapsuleNum > MAX_CAPSULE_NUM) {
1072 Print(L"CapsuleApp: Too many capsule images.\n");
1073 return EFI_UNSUPPORTED;
1074 }
1075
1076 ZeroMem(&CapsuleBuffer, sizeof(CapsuleBuffer));
1077 ZeroMem(&CapsuleBufferSize, sizeof(CapsuleBufferSize));
1078 BlockDescriptors = NULL;
1079
1080 for (Index = 0; Index < CapsuleNum; Index++) {
1081 CapsuleName = Argv[CapsuleFirstIndex + Index];
1082 Status = ReadFileToBuffer(CapsuleName, &CapsuleBufferSize[Index], &CapsuleBuffer[Index]);
1083 if (EFI_ERROR(Status)) {
1084 Print(L"CapsuleApp: capsule image (%s) is not found.\n", CapsuleName);
1085 goto Done;
1086 }
1087 if (!IsValidCapsuleHeader (CapsuleBuffer[Index], CapsuleBufferSize[Index])) {
1088 Print(L"CapsuleApp: Capsule image (%s) is not a valid capsule.\n", CapsuleName);
1089 return EFI_INVALID_PARAMETER;
1090 }
1091 CapsuleNames[Index] = CapsuleName;
1092 }
1093
1094 //
1095 // Every capsule use 2 descriptor 1 for data 1 for end
1096 //
1097 Status = BuildGatherList(CapsuleBuffer, CapsuleBufferSize, CapsuleNum, &BlockDescriptors);
1098 if (EFI_ERROR(Status)) {
1099 goto Done;
1100 }
1101
1102 //
1103 // Call the runtime service capsule.
1104 //
1105 NeedReset = FALSE;
1106 for (Index = 0; Index < CapsuleNum; Index++) {
1107 CapsuleHeaderArray[Index] = (EFI_CAPSULE_HEADER *) CapsuleBuffer[Index];
1108 if ((CapsuleHeaderArray[Index]->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {
1109 NeedReset = TRUE;
1110 }
1111 }
1112 CapsuleHeaderArray[CapsuleNum] = NULL;
1113
1114 //
1115 // Inquire platform capability of UpdateCapsule.
1116 //
1117 Status = gRT->QueryCapsuleCapabilities (CapsuleHeaderArray, CapsuleNum, &MaxCapsuleSize, &ResetType);
1118 if (EFI_ERROR(Status)) {
1119 Print (L"CapsuleApp: failed to query capsule capability - %r\n", Status);
1120 goto Done;
1121 }
1122
1123 for (Index = 0; Index < CapsuleNum; Index++) {
1124 if (CapsuleBufferSize[Index] > MaxCapsuleSize) {
1125 Print (L"CapsuleApp: capsule is too large to update, %ld is allowed\n", MaxCapsuleSize);
1126 Status = EFI_UNSUPPORTED;
1127 goto Done;
1128 }
1129 }
1130
1131 //
1132 // Check whether is capsule on disk.
1133 //
1134 if (CapsuleOnDisk) {
1135 Status = ProcessCapsuleOnDisk (CapsuleBuffer, CapsuleBufferSize, CapsuleNames, MapFsStr, CapsuleNum);
1136 if (Status != EFI_SUCCESS) {
1137 Print (L"CapsuleApp: failed to update capsule - %r\n", Status);
1138 goto Done;
1139 } else {
1140 if (!NoReset) {
1141 gRT->ResetSystem (ResetType, EFI_SUCCESS, 0, NULL);
1142 } else {
1143 goto Done;
1144 }
1145 }
1146 }
1147
1148 //
1149 // Check whether the input capsule image has the flag of persist across system reset.
1150 //
1151 if (NeedReset) {
1152 Status = gRT->UpdateCapsule(CapsuleHeaderArray,CapsuleNum,(UINTN) BlockDescriptors);
1153 if (Status != EFI_SUCCESS) {
1154 Print (L"CapsuleApp: failed to update capsule - %r\n", Status);
1155 goto Done;
1156 }
1157 //
1158 // For capsule with CAPSULE_FLAGS_PERSIST_ACROSS_RESET + CAPSULE_FLAGS_INITIATE_RESET,
1159 // a system reset should have been triggered by gRT->UpdateCapsule() calling above.
1160 //
1161 // For capsule with CAPSULE_FLAGS_PERSIST_ACROSS_RESET and without CAPSULE_FLAGS_INITIATE_RESET,
1162 // check if -NR (no-reset) has been specified or not.
1163 //
1164 if (!NoReset) {
1165 //
1166 // For capsule who has reset flag and no -NR (no-reset) has been specified, after calling UpdateCapsule service,
1167 // trigger a system reset to process capsule persist across a system reset.
1168 //
1169 gRT->ResetSystem (ResetType, EFI_SUCCESS, 0, NULL);
1170 }
1171 } else {
1172 //
1173 // For capsule who has no reset flag, only call UpdateCapsule Service without a
1174 // system reset. The service will process the capsule immediately.
1175 //
1176 Status = gRT->UpdateCapsule (CapsuleHeaderArray,CapsuleNum,(UINTN) BlockDescriptors);
1177 if (Status != EFI_SUCCESS) {
1178 Print (L"CapsuleApp: failed to update capsule - %r\n", Status);
1179 }
1180 }
1181
1182 Status = EFI_SUCCESS;
1183
1184 Done:
1185 for (Index = 0; Index < CapsuleNum; Index++) {
1186 if (CapsuleBuffer[Index] != NULL) {
1187 FreePool (CapsuleBuffer[Index]);
1188 }
1189 }
1190
1191 CleanGatherList(BlockDescriptors, CapsuleNum);
1192
1193 return Status;
1194 }