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