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