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