]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Application/CapsuleApp/CapsuleApp.c
5b8c14792884d1d8d0c2058784858b3d2470022d
[mirror_edk2.git] / MdeModulePkg / Application / CapsuleApp / CapsuleApp.c
1 /** @file
2 A shell application that triggers capsule update process.
3
4 Copyright (c) 2016, 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 <Protocol/LoadedImage.h>
25 #include <Protocol/SimpleFileSystem.h>
26 #include <Protocol/GraphicsOutput.h>
27 #include <Guid/FileInfo.h>
28 #include <Guid/Gpt.h>
29 #include <Guid/GlobalVariable.h>
30 #include <Guid/CapsuleReport.h>
31 #include <Guid/SystemResourceTable.h>
32 #include <Guid/FmpCapsule.h>
33 #include <IndustryStandard/WindowsUxCapsule.h>
34
35 #define CAPSULE_HEADER_SIZE 0x20
36
37 #define NESTED_CAPSULE_HEADER_SIZE SIZE_4KB
38 #define SYSTEM_FIRMWARE_FLAG 0x50000
39 #define DEVICE_FIRMWARE_FLAG 0x78010
40
41 #define MAJOR_VERSION 1
42 #define MINOR_VERSION 0
43
44 #define MAX_CAPSULE_NUM 10
45
46 extern UINTN Argc;
47 extern CHAR16 **Argv;
48
49 //
50 // Define how many block descriptors we want to test with.
51 //
52 UINTN NumberOfDescriptors = 1;
53 UINTN CapsuleFirstIndex;
54 UINTN CapsuleLastIndex;
55
56 /**
57 Dump capsule information
58
59 @param[in] CapsuleName The name of the capsule image.
60
61 @retval EFI_SUCCESS The capsule information is dumped.
62 @retval EFI_UNSUPPORTED Input parameter is not valid.
63 **/
64 EFI_STATUS
65 DumpCapsule (
66 IN CHAR16 *CapsuleName
67 );
68
69 /**
70 Dump capsule status variable.
71
72 @retval EFI_SUCCESS The capsule status variable is dumped.
73 @retval EFI_UNSUPPORTED Input parameter is not valid.
74 **/
75 EFI_STATUS
76 DmpCapsuleStatusVariable (
77 VOID
78 );
79
80 /**
81 Dump FMP protocol info.
82 **/
83 VOID
84 DumpFmpData (
85 VOID
86 );
87
88 /**
89 Dump FMP image data.
90
91 @param[in] ImageTypeId The ImageTypeId of the FMP image.
92 It is used to identify the FMP protocol.
93 @param[in] ImageIndex The ImageIndex of the FMP image.
94 It is the input parameter for FMP->GetImage().
95 @param[in] ImageName The file name to hold the output FMP image.
96 **/
97 VOID
98 DumpFmpImage (
99 IN EFI_GUID *ImageTypeId,
100 IN UINTN ImageIndex,
101 IN CHAR16 *ImageName
102 );
103
104 /**
105 Dump ESRT info.
106 **/
107 VOID
108 DumpEsrtData (
109 VOID
110 );
111
112 /**
113 Read a file.
114
115 @param[in] FileName The file to be read.
116 @param[out] BufferSize The file buffer size
117 @param[out] Buffer The file buffer
118
119 @retval EFI_SUCCESS Read file successfully
120 @retval EFI_NOT_FOUND File not found
121 **/
122 EFI_STATUS
123 ReadFileToBuffer (
124 IN CHAR16 *FileName,
125 OUT UINTN *BufferSize,
126 OUT VOID **Buffer
127 );
128
129 /**
130 Write a file.
131
132 @param[in] FileName The file to be written.
133 @param[in] BufferSize The file buffer size
134 @param[in] Buffer The file buffer
135
136 @retval EFI_SUCCESS Write file successfully
137 **/
138 EFI_STATUS
139 WriteFileFromBuffer (
140 IN CHAR16 *FileName,
141 IN UINTN BufferSize,
142 IN VOID *Buffer
143 );
144
145 /**
146 Converts a string to GUID value.
147 Guid Format is xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
148
149 @param[in] Str The registry format GUID string that contains the GUID value.
150 @param[out] Guid A pointer to the converted GUID value.
151
152 @retval EFI_SUCCESS The GUID string was successfully converted to the GUID value.
153 @retval EFI_UNSUPPORTED The input string is not in registry format.
154 @return others Some error occurred when converting part of GUID value.
155
156 **/
157 EFI_STATUS
158 InternalStrToGuid (
159 IN CHAR16 *Str,
160 OUT EFI_GUID *Guid
161 );
162
163 /**
164
165 This function parse application ARG.
166
167 @return Status
168 **/
169 EFI_STATUS
170 GetArg (
171 VOID
172 );
173
174 /**
175 Create UX capsule.
176
177 @retval EFI_SUCCESS The capsule header is appended.
178 @retval EFI_UNSUPPORTED Input parameter is not valid.
179 @retval EFI_OUT_OF_RESOURCES No enough resource to create UX capsule.
180 **/
181 EFI_STATUS
182 CreateBmpFmp (
183 VOID
184 )
185 {
186 CHAR16 *OutputCapsuleName;
187 VOID *BmpBuffer;
188 UINTN FileSize;
189 CHAR16 *BmpName;
190 UINT8 *FullCapsuleBuffer;
191 UINTN FullCapsuleBufferSize;
192 EFI_DISPLAY_CAPSULE *DisplayCapsule;
193 EFI_STATUS Status;
194 EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop;
195
196 Status = gBS->LocateProtocol(&gEfiGraphicsOutputProtocolGuid, NULL, (VOID **)&Gop);
197 if (EFI_ERROR(Status)) {
198 Print(L"CapsuleApp: NO GOP is found.\n");
199 return EFI_UNSUPPORTED;
200 }
201 Print(L"Current GOP: Mode - %d, ", Gop->Mode->Mode);
202 Print(L"HorizontalResolution - %d, ", Gop->Mode->Info->HorizontalResolution);
203 Print(L"VerticalResolution - %d\n", Gop->Mode->Info->VerticalResolution);
204 // HorizontalResolution >= BMP_IMAGE_HEADER.PixelWidth
205 // VerticalResolution >= BMP_IMAGE_HEADER.PixelHeight
206
207 if (Argc != 5) {
208 Print(L"CapsuleApp: Invalid Parameter.\n");
209 return EFI_UNSUPPORTED;
210 }
211
212 if (StrCmp(Argv[3], L"-O") != 0) {
213 Print(L"CapsuleApp: NO output capsule name.\n");
214 return EFI_UNSUPPORTED;
215 }
216 OutputCapsuleName = Argv[4];
217
218 BmpBuffer = NULL;
219 FileSize = 0;
220 FullCapsuleBuffer = NULL;
221
222 BmpName = Argv[2];
223 Status = ReadFileToBuffer(BmpName, &FileSize, &BmpBuffer);
224 if (EFI_ERROR(Status)) {
225 Print(L"CapsuleApp: BMP image (%s) is not found.\n", BmpName);
226 goto Done;
227 }
228
229 FullCapsuleBufferSize = sizeof(EFI_DISPLAY_CAPSULE) + FileSize;
230 FullCapsuleBuffer = AllocatePool(FullCapsuleBufferSize);
231 if (FullCapsuleBuffer == NULL) {
232 Print(L"CapsuleApp: Capsule Buffer size (0x%x) too big.\n", FullCapsuleBufferSize);
233 Status = EFI_OUT_OF_RESOURCES;
234 goto Done;
235 }
236
237 DisplayCapsule = (EFI_DISPLAY_CAPSULE *)FullCapsuleBuffer;
238 CopyGuid(&DisplayCapsule->CapsuleHeader.CapsuleGuid, &gWindowsUxCapsuleGuid);
239 DisplayCapsule->CapsuleHeader.HeaderSize = sizeof(DisplayCapsule->CapsuleHeader);
240 DisplayCapsule->CapsuleHeader.Flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET;
241 DisplayCapsule->CapsuleHeader.CapsuleImageSize = (UINT32)FullCapsuleBufferSize;
242
243 DisplayCapsule->ImagePayload.Version = 1;
244 DisplayCapsule->ImagePayload.Checksum = 0;
245 DisplayCapsule->ImagePayload.ImageType = 0; // BMP
246 DisplayCapsule->ImagePayload.Reserved = 0;
247 DisplayCapsule->ImagePayload.Mode = Gop->Mode->Mode;
248 DisplayCapsule->ImagePayload.OffsetX = 0;
249 DisplayCapsule->ImagePayload.OffsetY = 0;
250
251 CopyMem((DisplayCapsule + 1), BmpBuffer, FileSize);
252
253 DisplayCapsule->ImagePayload.Checksum = CalculateCheckSum8(FullCapsuleBuffer, FullCapsuleBufferSize);
254
255 Status = WriteFileFromBuffer(OutputCapsuleName, FullCapsuleBufferSize, FullCapsuleBuffer);
256 Print(L"CapsuleApp: Write %s %r\n", OutputCapsuleName, Status);
257
258 Done:
259 if (BmpBuffer != NULL) {
260 FreePool(BmpBuffer);
261 }
262
263 if (FullCapsuleBuffer != NULL) {
264 FreePool(FullCapsuleBuffer);
265 }
266
267 return Status;
268 }
269
270 /**
271 Get ImageTypeId in the FMP capsule header.
272
273 @param[in] CapsuleHeader The FMP capsule image header.
274
275 @return ImageTypeId
276 **/
277 EFI_GUID *
278 GetCapsuleImageTypeId (
279 IN EFI_CAPSULE_HEADER *CapsuleHeader
280 )
281 {
282 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;
283 UINT64 *ItemOffsetList;
284 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
285
286 FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);
287 ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
288 if (FmpCapsuleHeader->PayloadItemCount == 0) {
289 return NULL;
290 }
291 ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[FmpCapsuleHeader->EmbeddedDriverCount]);
292 return &ImageHeader->UpdateImageTypeId;
293 }
294
295 /**
296 Get ESRT FwType according to ImageTypeId
297
298 @param[in] ImageTypeId ImageTypeId of an FMP capsule.
299
300 @return ESRT FwType
301 **/
302 UINT32
303 GetEsrtFwType (
304 IN EFI_GUID *ImageTypeId
305 )
306 {
307 EFI_STATUS Status;
308 EFI_SYSTEM_RESOURCE_TABLE *Esrt;
309 EFI_SYSTEM_RESOURCE_ENTRY *EsrtEntry;
310 UINTN Index;
311
312 //
313 // Check ESRT
314 //
315 Status = EfiGetSystemConfigurationTable(&gEfiSystemResourceTableGuid, (VOID **)&Esrt);
316 if (!EFI_ERROR(Status)) {
317 ASSERT(Esrt != NULL);
318 EsrtEntry = (VOID *)(Esrt + 1);
319 for (Index = 0; Index < Esrt->FwResourceCount; Index++, EsrtEntry++) {
320 if (CompareGuid(&EsrtEntry->FwClass, ImageTypeId)) {
321 return EsrtEntry->FwType;
322 }
323 }
324 }
325
326 return ESRT_FW_TYPE_UNKNOWN;
327 }
328
329 /**
330 Append a capsule header on top of current image.
331 This function follows Windows UEFI Firmware Update Platform document.
332
333 @retval EFI_SUCCESS The capsule header is appended.
334 @retval EFI_UNSUPPORTED Input parameter is not valid.
335 @retval EFI_OUT_OF_RESOURCES No enough resource to append capsule header.
336 **/
337 EFI_STATUS
338 CreateNestedFmp (
339 VOID
340 )
341 {
342 CHAR16 *OutputCapsuleName;
343 VOID *CapsuleBuffer;
344 UINTN FileSize;
345 CHAR16 *CapsuleName;
346 UINT8 *FullCapsuleBuffer;
347 UINTN FullCapsuleBufferSize;
348 EFI_CAPSULE_HEADER *NestedCapsuleHeader;
349 EFI_GUID *ImageTypeId;
350 UINT32 FwType;
351 EFI_STATUS Status;
352
353 if (Argc != 5) {
354 Print(L"CapsuleApp: Invalid Parameter.\n");
355 return EFI_UNSUPPORTED;
356 }
357
358 if (StrCmp(Argv[3], L"-O") != 0) {
359 Print(L"CapsuleApp: NO output capsule name.\n");
360 return EFI_UNSUPPORTED;
361 }
362 OutputCapsuleName = Argv[4];
363
364 CapsuleBuffer = NULL;
365 FileSize = 0;
366 FullCapsuleBuffer = NULL;
367
368 CapsuleName = Argv[2];
369 Status = ReadFileToBuffer(CapsuleName, &FileSize, &CapsuleBuffer);
370 if (EFI_ERROR(Status)) {
371 Print(L"CapsuleApp: Capsule image (%s) is not found.\n", CapsuleName);
372 goto Done;
373 }
374
375 ImageTypeId = GetCapsuleImageTypeId(CapsuleBuffer);
376 if (ImageTypeId == NULL) {
377 Print(L"CapsuleApp: Capsule ImageTypeId is not found.\n");
378 goto Done;
379 }
380 FwType = GetEsrtFwType(ImageTypeId);
381 if ((FwType != ESRT_FW_TYPE_SYSTEMFIRMWARE) && (FwType != ESRT_FW_TYPE_DEVICEFIRMWARE)) {
382 Print(L"CapsuleApp: Capsule FwType is invalid.\n");
383 goto Done;
384 }
385
386 FullCapsuleBufferSize = NESTED_CAPSULE_HEADER_SIZE + FileSize;
387 FullCapsuleBuffer = AllocatePool(FullCapsuleBufferSize);
388 if (FullCapsuleBuffer == NULL) {
389 Print(L"CapsuleApp: Capsule Buffer size (0x%x) too big.\n", FullCapsuleBufferSize);
390 Status = EFI_OUT_OF_RESOURCES;
391 goto Done;
392 }
393
394 NestedCapsuleHeader = (EFI_CAPSULE_HEADER *)FullCapsuleBuffer;
395 ZeroMem(NestedCapsuleHeader, NESTED_CAPSULE_HEADER_SIZE);
396 CopyGuid(&NestedCapsuleHeader->CapsuleGuid, ImageTypeId);
397 NestedCapsuleHeader->HeaderSize = NESTED_CAPSULE_HEADER_SIZE;
398 NestedCapsuleHeader->Flags = (FwType == ESRT_FW_TYPE_DEVICEFIRMWARE) ? SYSTEM_FIRMWARE_FLAG : DEVICE_FIRMWARE_FLAG;
399 NestedCapsuleHeader->CapsuleImageSize = (UINT32)FullCapsuleBufferSize;
400
401 CopyMem((UINT8 *)NestedCapsuleHeader + NestedCapsuleHeader->HeaderSize, CapsuleBuffer, FileSize);
402
403 Status = WriteFileFromBuffer(OutputCapsuleName, FullCapsuleBufferSize, FullCapsuleBuffer);
404 Print(L"CapsuleApp: Write %s %r\n", OutputCapsuleName, Status);
405
406 Done:
407 if (CapsuleBuffer != NULL) {
408 FreePool(CapsuleBuffer);
409 }
410
411 if (FullCapsuleBuffer != NULL) {
412 FreePool(FullCapsuleBuffer);
413 }
414
415 return Status;
416 }
417
418
419 /**
420 Clear capsule status variable.
421
422 @retval EFI_SUCCESS The capsule status variable is cleared.
423 **/
424 EFI_STATUS
425 ClearCapsuleStatusVariable (
426 VOID
427 )
428 {
429 EFI_STATUS Status;
430 UINT32 Index;
431 CHAR16 CapsuleVarName[20];
432 CHAR16 *TempVarName;
433
434 StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CapsuleVarName[0]), L"Capsule");
435 TempVarName = CapsuleVarName + StrLen (CapsuleVarName);
436 Index = 0;
437
438 while (TRUE) {
439 UnicodeSPrint (TempVarName, 5 * sizeof(CHAR16), L"%04x", Index);
440
441 Status = gRT->SetVariable (
442 CapsuleVarName,
443 &gEfiCapsuleReportGuid,
444 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
445 0,
446 (VOID *)NULL
447 );
448 if (EFI_ERROR(Status)) {
449 //
450 // There is no capsule variables, quit
451 //
452 break;
453 }
454
455 Index++;
456 if (Index > 0xFFFF) {
457 break;
458 }
459 }
460
461 return EFI_SUCCESS;
462 }
463
464 /**
465 Build Gather list for a list of capsule images.
466
467 @param[in] CapsuleBuffer An array of pointer to capsule images
468 @param[in] FileSize An array of UINTN to capsule images size
469 @param[in] CapsuleNum The count of capsule images
470 @param[out] BlockDescriptors The block descriptors for the capsule images
471
472 @retval EFI_SUCCESS The block descriptors for the capsule images are constructed.
473 **/
474 EFI_STATUS
475 BuildGatherList (
476 IN VOID **CapsuleBuffer,
477 IN UINTN *FileSize,
478 IN UINTN CapsuleNum,
479 OUT EFI_CAPSULE_BLOCK_DESCRIPTOR **BlockDescriptors
480 )
481 {
482 EFI_STATUS Status;
483 EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors1;
484 EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors2;
485 EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptorPre;
486 EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptorsHeader;
487 EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr;
488 UINT8 *TempDataPtr;
489 UINTN SizeLeft;
490 UINTN Size;
491 INT32 Count;
492 INT32 Number;
493 UINTN Index;
494
495 TempBlockPtr = NULL;
496 BlockDescriptors1 = NULL;
497 BlockDescriptors2 = NULL;
498 BlockDescriptorPre = NULL;
499 BlockDescriptorsHeader = NULL;
500
501 for (Index = 0; Index < CapsuleNum; Index++) {
502 //
503 // Allocate memory for the descriptors.
504 //
505 if (NumberOfDescriptors == 1) {
506 Count = 2;
507 } else {
508 Count = (INT32)(NumberOfDescriptors + 2) / 2;
509 }
510
511 Size = Count * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);
512 BlockDescriptors1 = AllocateRuntimeZeroPool (Size);
513 if (BlockDescriptors1 == NULL) {
514 Print (L"CapsuleApp: failed to allocate memory for descriptors\n");
515 Status = EFI_OUT_OF_RESOURCES;
516 goto ERREXIT;
517 } else {
518 Print (L"CapsuleApp: creating capsule descriptors at 0x%X\n", (UINTN) BlockDescriptors1);
519 Print (L"CapsuleApp: capsule data starts at 0x%X with size 0x%X\n", (UINTN) CapsuleBuffer, FileSize);
520 }
521
522 //
523 // Record descirptor header
524 //
525 if (Index == 0) {
526 BlockDescriptorsHeader = BlockDescriptors1;
527 }
528
529 if (BlockDescriptorPre != NULL) {
530 BlockDescriptorPre->Union.ContinuationPointer = (UINTN) BlockDescriptors1;
531 BlockDescriptorPre->Length = 0;
532 }
533
534 //
535 // Fill them in
536 //
537 TempBlockPtr = BlockDescriptors1;
538 TempDataPtr = CapsuleBuffer[Index];
539 SizeLeft = FileSize[Index];
540 for (Number = 0; (Number < Count - 1) && (SizeLeft != 0); Number++) {
541 //
542 // Divide remaining data in half
543 //
544 if (NumberOfDescriptors != 1) {
545 if (SizeLeft == 1) {
546 Size = 1;
547 } else {
548 Size = SizeLeft / 2;
549 }
550 } else {
551 Size = SizeLeft;
552 }
553 TempBlockPtr->Union.DataBlock = (UINTN)TempDataPtr;
554 TempBlockPtr->Length = Size;
555 Print (L"CapsuleApp: capsule block/size 0x%X/0x%X\n", (UINTN) TempDataPtr, Size);
556 SizeLeft -= Size;
557 TempDataPtr += Size;
558 TempBlockPtr++;
559 }
560
561 //
562 // Allocate the second list, point the first block's last entry to point
563 // to this one, and fill this one in. Worst case is that the previous
564 // list only had one element that pointed here, so we need at least two
565 // elements -- one to point to all the data, another to terminate the list.
566 //
567 if ((NumberOfDescriptors != 1) && (SizeLeft != 0)) {
568 Count = (INT32)(NumberOfDescriptors + 2) - Count;
569 if (Count == 1) {
570 Count++;
571 }
572
573 Size = Count * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);
574 BlockDescriptors2 = AllocateRuntimeZeroPool (Size);
575 if (BlockDescriptors2 == NULL) {
576 Print (L"CapsuleApp: failed to allocate memory for descriptors\n");
577 Status = EFI_OUT_OF_RESOURCES;
578 goto ERREXIT;
579 }
580
581 //
582 // Point the first list's last element to point to this second list.
583 //
584 TempBlockPtr->Union.ContinuationPointer = (UINTN) BlockDescriptors2;
585
586 TempBlockPtr->Length = 0;
587 TempBlockPtr = BlockDescriptors2;
588 for (Number = 0; Number < Count - 1; Number++) {
589 //
590 // If second-to-last one, then dump rest to this element
591 //
592 if (Number == (Count - 2)) {
593 Size = SizeLeft;
594 } else {
595 //
596 // Divide remaining data in half
597 //
598 if (SizeLeft == 1) {
599 Size = 1;
600 } else {
601 Size = SizeLeft / 2;
602 }
603 }
604
605 TempBlockPtr->Union.DataBlock = (UINTN)TempDataPtr;
606 TempBlockPtr->Length = Size;
607 Print (L"CapsuleApp: capsule block/size 0x%X/0x%X\n", (UINTN) TempDataPtr, Size);
608 SizeLeft -= Size;
609 TempDataPtr += Size;
610 TempBlockPtr++;
611 if (SizeLeft == 0) {
612 break;
613 }
614 }
615 }
616
617 BlockDescriptorPre = TempBlockPtr;
618 BlockDescriptors1 = NULL;
619 }
620
621 //
622 // Null-terminate.
623 //
624 if (TempBlockPtr != NULL) {
625 TempBlockPtr->Union.ContinuationPointer = (UINTN)NULL;
626 TempBlockPtr->Length = 0;
627 *BlockDescriptors = BlockDescriptorsHeader;
628 }
629
630 return EFI_SUCCESS;
631
632 ERREXIT:
633 if (BlockDescriptors1 != NULL) {
634 FreePool(BlockDescriptors1);
635 }
636
637 if (BlockDescriptors2 != NULL) {
638 FreePool(BlockDescriptors2);
639 }
640
641 return Status;
642 }
643
644 /**
645 Clear the Gather list for a list of capsule images.
646
647 @param[in] BlockDescriptors The block descriptors for the capsule images
648 @param[in] CapsuleNum The count of capsule images
649 **/
650 VOID
651 CleanGatherList (
652 IN EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors,
653 IN UINTN CapsuleNum
654 )
655 {
656 EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr;
657 EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr1;
658 EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr2;
659 UINTN Index;
660
661 if (BlockDescriptors != NULL) {
662 TempBlockPtr1 = BlockDescriptors;
663 while (1){
664 TempBlockPtr = TempBlockPtr1;
665 for (Index = 0; Index < CapsuleNum; Index++) {
666 if (TempBlockPtr[Index].Length == 0) {
667 break;
668 }
669 }
670
671 if (TempBlockPtr[Index].Union.ContinuationPointer == (UINTN)NULL) {
672 break;
673 }
674
675 TempBlockPtr2 = (VOID *) ((UINTN) TempBlockPtr->Union.ContinuationPointer);
676 FreePool(TempBlockPtr1);
677 TempBlockPtr1 = TempBlockPtr2;
678 }
679 }
680 }
681
682 /**
683 Print APP usage.
684 **/
685 VOID
686 PrintUsage (
687 VOID
688 )
689 {
690 Print(L"CapsuleApp: usage\n");
691 Print(L" CapsuleApp <Capsule...>\n");
692 Print(L" CapsuleApp -S\n");
693 Print(L" CapsuleApp -C\n");
694 Print(L" CapsuleApp -P\n");
695 Print(L" CapsuleApp -E\n");
696 Print(L" CapsuleApp -G <BMP> -O <Capsule>\n");
697 Print(L" CapsuleApp -N <Capsule> -O <NestedCapsule>\n");
698 Print(L" CapsuleApp -D <Capsule>\n");
699 Print(L" CapsuleApp -P GET <ImageTypeId> <Index> -O <FileName>\n");
700 Print(L"Parameter:\n");
701 Print(L" -S: Dump capsule report variable (EFI_CAPSULE_REPORT_GUID),\n");
702 Print(L" which is defined in UEFI specification.\n");
703 Print(L" -C: Clear capsule report variable (EFI_CAPSULE_RPORT_GUID),\n");
704 Print(L" which is defined in UEFI specification.\n");
705 Print(L" -P: Dump UEFI FMP protocol info.\n");
706 Print(L" -E: Dump UEFI ESRT table info.\n");
707 Print(L" -G: Convert a BMP file to be a UX capsule,\n");
708 Print(L" according to Windows Firmware Update document\n");
709 Print(L" -N: Append a Capsule Header to an existing capsule image,\n");
710 Print(L" according to Windows Firmware Update document\n");
711 Print(L" -O: Output new Capsule file name\n");
712 Print(L" -D: Dump Capsule image header information and FMP header information,\n");
713 Print(L" if it is an 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_INVALID_PARAMETER Command usage error.
724 @retval EFI_NOT_FOUND The input file can't be found.
725 **/
726 EFI_STATUS
727 EFIAPI
728 UefiMain (
729 IN EFI_HANDLE ImageHandle,
730 IN EFI_SYSTEM_TABLE *SystemTable
731 )
732 {
733 EFI_STATUS Status;
734 UINTN FileSize[MAX_CAPSULE_NUM];
735 VOID *CapsuleBuffer[MAX_CAPSULE_NUM];
736 EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors;
737 EFI_CAPSULE_HEADER *CapsuleHeaderArray[MAX_CAPSULE_NUM + 1];
738 UINT64 MaxCapsuleSize;
739 EFI_RESET_TYPE ResetType;
740 BOOLEAN NeedReset;
741 CHAR16 *CapsuleName;
742 UINTN CapsuleNum;
743 UINTN Index;
744
745 Status = GetArg();
746 if (EFI_ERROR(Status)) {
747 Print(L"Please use UEFI SHELL to run this application!\n", Status);
748 return Status;
749 }
750 if (Argc < 2) {
751 PrintUsage();
752 return EFI_INVALID_PARAMETER;
753 }
754 if (StrCmp(Argv[1], L"-D") == 0) {
755 Status = DumpCapsule(Argv[2]);
756 return Status;
757 }
758 if (StrCmp(Argv[1], L"-G") == 0) {
759 Status = CreateBmpFmp();
760 return Status;
761 }
762 if (StrCmp(Argv[1], L"-N") == 0) {
763 Status = CreateNestedFmp();
764 return Status;
765 }
766 if (StrCmp(Argv[1], L"-S") == 0) {
767 Status = DmpCapsuleStatusVariable();
768 return EFI_SUCCESS;
769 }
770 if (StrCmp(Argv[1], L"-C") == 0) {
771 Status = ClearCapsuleStatusVariable();
772 return Status;
773 }
774 if (StrCmp(Argv[1], L"-P") == 0) {
775 if (Argc == 2) {
776 DumpFmpData();
777 }
778 if (Argc >= 3) {
779 if (StrCmp(Argv[2], L"GET") == 0) {
780 EFI_GUID ImageTypeId;
781 UINTN ImageIndex;
782 //
783 // FMP->GetImage()
784 //
785 Status = InternalStrToGuid(Argv[3], &ImageTypeId);
786 if (EFI_ERROR(Status)) {
787 Print (L"Invalid ImageTypeId - %s\n", Argv[3]);
788 return Status;
789 }
790 ImageIndex = StrDecimalToUintn(Argv[4]);
791 if (StrCmp(Argv[5], L"-O") == 0) {
792 DumpFmpImage(&ImageTypeId, ImageIndex, Argv[6]);
793 }
794 }
795 }
796 return EFI_SUCCESS;
797 }
798 if (StrCmp(Argv[1], L"-E") == 0) {
799 DumpEsrtData();
800 return EFI_SUCCESS;
801 }
802 CapsuleFirstIndex = 1;
803 CapsuleLastIndex = Argc - 1;
804 CapsuleNum = CapsuleLastIndex - CapsuleFirstIndex + 1;
805
806 if (CapsuleFirstIndex > CapsuleLastIndex) {
807 Print(L"CapsuleApp: NO capsule image.\n");
808 return EFI_UNSUPPORTED;
809 }
810 if (CapsuleNum > MAX_CAPSULE_NUM) {
811 Print(L"CapsuleApp: Too many capsule images.\n");
812 return EFI_UNSUPPORTED;
813 }
814
815 ZeroMem(&CapsuleBuffer, sizeof(CapsuleBuffer));
816 ZeroMem(&FileSize, sizeof(FileSize));
817 BlockDescriptors = NULL;
818
819 for (Index = 0; Index < CapsuleNum; Index++) {
820 CapsuleName = Argv[CapsuleFirstIndex + Index];
821 Status = ReadFileToBuffer(CapsuleName, &FileSize[Index], &CapsuleBuffer[Index]);
822 if (EFI_ERROR(Status)) {
823 Print(L"CapsuleApp: capsule image (%s) is not found.\n", CapsuleName);
824 goto Done;
825 }
826 }
827
828 //
829 // Every capsule use 2 descriptor 1 for data 1 for end
830 //
831 Status = BuildGatherList(CapsuleBuffer, FileSize, CapsuleNum, &BlockDescriptors);
832 if (EFI_ERROR(Status)) {
833 goto Done;
834 }
835
836 //
837 // Call the runtime service capsule.
838 //
839 NeedReset = FALSE;
840 for (Index = 0; Index < CapsuleNum; Index++) {
841 CapsuleHeaderArray[Index] = (EFI_CAPSULE_HEADER *) CapsuleBuffer[Index];
842 if ((CapsuleHeaderArray[Index]->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {
843 NeedReset = TRUE;
844 }
845 }
846 CapsuleHeaderArray[CapsuleNum] = NULL;
847
848 //
849 // Inquire platform capability of UpdateCapsule.
850 //
851 Status = gRT->QueryCapsuleCapabilities (CapsuleHeaderArray, CapsuleNum, &MaxCapsuleSize, &ResetType);
852 if (EFI_ERROR(Status)) {
853 Print (L"CapsuleApp: failed to query capsule capability - %r\n", Status);
854 goto Done;
855 }
856
857 for (Index = 0; Index < CapsuleNum; Index++) {
858 if (FileSize[Index] > MaxCapsuleSize) {
859 Print (L"CapsuleApp: capsule is too large to update, %ld is allowed\n", MaxCapsuleSize);
860 Status = EFI_UNSUPPORTED;
861 goto Done;
862 }
863 }
864
865 //
866 // Check whether the input capsule image has the flag of persist across system reset.
867 //
868 if (NeedReset) {
869 Status = gRT->UpdateCapsule(CapsuleHeaderArray,CapsuleNum,(UINTN) BlockDescriptors);
870 if (Status != EFI_SUCCESS) {
871 Print (L"CapsuleApp: failed to update capsule - %r\n", Status);
872 goto Done;
873 }
874 //
875 // For capsule who has reset flag, after calling UpdateCapsule service,triger a
876 // system reset to process capsule persist across a system reset.
877 //
878 gRT->ResetSystem (ResetType, EFI_SUCCESS, 0, NULL);
879 } else {
880 //
881 // For capsule who has no reset flag, only call UpdateCapsule Service without a
882 // system reset. The service will process the capsule immediately.
883 //
884 Status = gRT->UpdateCapsule (CapsuleHeaderArray,CapsuleNum,(UINTN) BlockDescriptors);
885 if (Status != EFI_SUCCESS) {
886 Print (L"CapsuleApp: failed to update capsule - %r\n", Status);
887 }
888 }
889
890 Status = EFI_SUCCESS;
891
892 Done:
893 for (Index = 0; Index < CapsuleNum; Index++) {
894 if (CapsuleBuffer[Index] != NULL) {
895 FreePool (CapsuleBuffer[Index]);
896 }
897 }
898
899 CleanGatherList(BlockDescriptors, CapsuleNum);
900
901 return Status;
902 }