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 } 903