1/** @file 2 Recovery module. 3 4 Caution: This module requires additional review when modified. 5 This module will have external input - capsule image. 6 This external input must be validated carefully to avoid security issue like 7 buffer overflow, integer overflow. 8 9 ProcessRecoveryCapsule(), ProcessFmpCapsuleImage(), ProcessRecoveryImage(), 10 ValidateFmpCapsule() will receive untrusted input and do basic validation. 11 12Copyright (c) 2016, Intel Corporation. All rights reserved.<BR> 13This program and the accompanying materials 14are licensed and made available under the terms and conditions of the BSD License 15which accompanies this distribution. The full text of the license may be found at 16http://opensource.org/licenses/bsd-license.php 17 18THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 19WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 20 21**/ 22 23// 24// The package level header files this module uses 25// 26#include <Uefi.h> 27#include <PiPei.h> 28// 29// The protocols, PPI and GUID defintions for this module 30// 31#include <Ppi/MasterBootMode.h> 32#include <Ppi/BootInRecoveryMode.h> 33#include <Ppi/RecoveryModule.h> 34#include <Ppi/DeviceRecoveryModule.h> 35#include <Ppi/FirmwareVolumeInfo.h> 36#include <Guid/FirmwareFileSystem2.h> 37#include <Guid/FmpCapsule.h> 38#include <Guid/EdkiiSystemFmpCapsule.h> 39 40// 41// The Library classes this module consumes 42// 43#include <Library/DebugLib.h> 44#include <Library/PeimEntryPoint.h> 45#include <Library/PeiServicesLib.h> 46#include <Library/HobLib.h> 47#include <Library/BaseMemoryLib.h> 48#include <Library/MemoryAllocationLib.h> 49#include <Library/PcdLib.h> 50 51#include "RecoveryModuleLoadPei.h" 52 53/** 54 Loads a DXE capsule from some media into memory and updates the HOB table 55 with the DXE firmware volume information. 56 57 @param[in] PeiServices General-purpose services that are available to every PEIM. 58 @param[in] This Indicates the EFI_PEI_RECOVERY_MODULE_PPI instance. 59 60 @retval EFI_SUCCESS The capsule was loaded correctly. 61 @retval EFI_DEVICE_ERROR A device error occurred. 62 @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found. 63 64**/ 65EFI_STATUS 66EFIAPI 67LoadRecoveryCapsule ( 68 IN EFI_PEI_SERVICES **PeiServices, 69 IN EFI_PEI_RECOVERY_MODULE_PPI *This 70 ); 71 72EFI_PEI_RECOVERY_MODULE_PPI mRecoveryPpi = { 73 LoadRecoveryCapsule 74}; 75 76EFI_PEI_PPI_DESCRIPTOR mRecoveryPpiList = { 77 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), 78 &gEfiPeiRecoveryModulePpiGuid, 79 &mRecoveryPpi 80}; 81 82/** 83 Parse Config data file to get the updated data array. 84 85 @param[in] DataBuffer Config raw file buffer. 86 @param[in] BufferSize Size of raw buffer. 87 @param[in, out] ConfigHeader Pointer to the config header. 88 @param[in, out] RecoveryArray Pointer to the config of recovery data. 89 90 @retval EFI_NOT_FOUND No config data is found. 91 @retval EFI_OUT_OF_RESOURCES No enough memory is allocated. 92 @retval EFI_SUCCESS Parse the config file successfully. 93 94**/ 95EFI_STATUS 96ParseRecoveryDataFile ( 97 IN UINT8 *DataBuffer, 98 IN UINTN BufferSize, 99 IN OUT CONFIG_HEADER *ConfigHeader, 100 IN OUT RECOVERY_CONFIG_DATA **RecoveryArray 101 ); 102 103/** 104 Return if this FMP is a system FMP or a device FMP, based upon FmpImageInfo. 105 106 @param[in] FmpImageHeader A pointer to EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER 107 108 @return TRUE It is a system FMP. 109 @return FALSE It is a device FMP. 110**/ 111BOOLEAN 112IsSystemFmpImage ( 113 IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *FmpImageHeader 114 ) 115{ 116 GUID *Guid; 117 UINTN Count; 118 UINTN Index; 119 120 Guid = PcdGetPtr(PcdSystemFmpCapsuleImageTypeIdGuid); 121 Count = PcdGetSize(PcdSystemFmpCapsuleImageTypeIdGuid) / sizeof(GUID); 122 123 for (Index = 0; Index < Count; Index++, Guid++) { 124 if (CompareGuid(&FmpImageHeader->UpdateImageTypeId, Guid)) { 125 return TRUE; 126 } 127 } 128 129 return FALSE; 130} 131 132/** 133 Return if this CapsuleGuid is a FMP capsule GUID or not. 134 135 @param[in] CapsuleGuid A pointer to EFI_GUID 136 137 @return TRUE It is a FMP capsule GUID. 138 @return FALSE It is not a FMP capsule GUID. 139**/ 140BOOLEAN 141IsFmpCapsuleGuid ( 142 IN EFI_GUID *CapsuleGuid 143 ) 144{ 145 if (CompareGuid(&gEfiFmpCapsuleGuid, CapsuleGuid)) { 146 return TRUE; 147 } 148 149 return FALSE; 150} 151 152/** 153 This function assumes the input Capusule image already passes basic check in 154 ValidateFmpCapsule(). 155 156 Criteria of system FMP capsule is: 157 1) FmpCapsuleHeader->EmbeddedDriverCount is 0. 158 2) FmpCapsuleHeader->PayloadItemCount is not 0. 159 3) All ImageHeader->UpdateImageTypeId matches PcdSystemFmpCapsuleImageTypeIdGuid. 160 161 @param[in] CapsuleHeader Points to a capsule header. 162 163 @retval TRUE Input capsule is a correct system FMP capsule. 164 @retval FALSE Input capsule is not a correct system FMP capsule. 165**/ 166BOOLEAN 167IsSystemFmpCapsuleImage ( 168 IN EFI_CAPSULE_HEADER *CapsuleHeader 169 ) 170{ 171 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader; 172 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader; 173 UINT64 *ItemOffsetList; 174 UINT32 ItemNum; 175 UINTN Index; 176 177 FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize); 178 179 if (FmpCapsuleHeader->EmbeddedDriverCount != 0) { 180 return FALSE; 181 } 182 183 if (FmpCapsuleHeader->PayloadItemCount == 0) { 184 return FALSE; 185 } 186 187 ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount; 188 189 ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1); 190 191 for (Index = 0; Index < ItemNum; Index++) { 192 ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]); 193 if (!IsSystemFmpImage(ImageHeader)) { 194 return FALSE; 195 } 196 } 197 198 return TRUE; 199} 200 201/** 202 Validate if it is valid capsule header 203 204 This function assumes the caller provided correct CapsuleHeader pointer 205 and CapsuleSize. 206 207 This function validates the fields in EFI_CAPSULE_HEADER. 208 209 @param[in] CapsuleHeader Points to a capsule header. 210 @param[in] CapsuleSize Size of the whole capsule image. 211 212**/ 213BOOLEAN 214IsValidCapsuleHeader ( 215 IN EFI_CAPSULE_HEADER *CapsuleHeader, 216 IN UINT64 CapsuleSize 217 ) 218{ 219 if (CapsuleHeader->CapsuleImageSize != CapsuleSize) { 220 return FALSE; 221 } 222 if (CapsuleHeader->HeaderSize >= CapsuleHeader->CapsuleImageSize) { 223 return FALSE; 224 } 225 return TRUE; 226} 227 228/** 229 Validate Fmp capsules layout. 230 231 Caution: This function may receive untrusted input. 232 233 This function assumes the caller validated the capsule by using 234 IsValidCapsuleHeader(), so that all fields in EFI_CAPSULE_HEADER are correct. 235 The capsule buffer size is CapsuleHeader->CapsuleImageSize. 236 237 This function validates the fields in EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER 238 and EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER. 239 240 @param[in] CapsuleHeader Points to a capsule header. 241 @param[out] IsSystemFmp If it is a system FMP. 242 @param[out] EmbeddedDriverCount The EmbeddedDriverCount in the FMP capsule. 243 244 @retval EFI_SUCESS Input capsule is a correct FMP capsule. 245 @retval EFI_INVALID_PARAMETER Input capsule is not a correct FMP capsule. 246**/ 247EFI_STATUS 248ValidateFmpCapsule ( 249 IN EFI_CAPSULE_HEADER *CapsuleHeader, 250 OUT BOOLEAN *IsSystemFmp, OPTIONAL 251 OUT UINT16 *EmbeddedDriverCount OPTIONAL 252 ) 253{ 254 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader; 255 UINT8 *EndOfCapsule; 256 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader; 257 UINT8 *EndOfPayload; 258 UINT64 *ItemOffsetList; 259 UINT32 ItemNum; 260 UINTN Index; 261 UINTN FmpCapsuleSize; 262 UINTN FmpCapsuleHeaderSize; 263 UINT64 FmpImageSize; 264 UINTN FmpImageHeaderSize; 265 266 if (CapsuleHeader->HeaderSize >= CapsuleHeader->CapsuleImageSize) { 267 DEBUG((DEBUG_ERROR, "HeaderSize(0x%x) >= CapsuleImageSize(0x%x)\n", CapsuleHeader->HeaderSize, CapsuleHeader->CapsuleImageSize)); 268 return EFI_INVALID_PARAMETER; 269 } 270 271 FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize); 272 EndOfCapsule = (UINT8 *) CapsuleHeader + CapsuleHeader->CapsuleImageSize; 273 FmpCapsuleSize = (UINTN)EndOfCapsule - (UINTN)FmpCapsuleHeader; 274 275 if (FmpCapsuleSize < sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER)) { 276 DEBUG((DEBUG_ERROR, "FmpCapsuleSize(0x%x) < EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER\n", FmpCapsuleSize)); 277 return EFI_INVALID_PARAMETER; 278 } 279 280 // Check EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER 281 if (FmpCapsuleHeader->Version != EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) { 282 DEBUG((DEBUG_ERROR, "FmpCapsuleHeader->Version(0x%x) != EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION\n", FmpCapsuleHeader->Version)); 283 return EFI_INVALID_PARAMETER; 284 } 285 ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1); 286 287 // No overflow 288 ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount; 289 290 if ((FmpCapsuleSize - sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER))/sizeof(UINT64) < ItemNum) { 291 DEBUG((DEBUG_ERROR, "ItemNum(0x%x) too big\n", ItemNum)); 292 return EFI_INVALID_PARAMETER; 293 } 294 FmpCapsuleHeaderSize = sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER) + sizeof(UINT64)*ItemNum; 295 296 // Check ItemOffsetList 297 for (Index = 0; Index < ItemNum; Index++) { 298 if (ItemOffsetList[Index] >= FmpCapsuleSize) { 299 DEBUG((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) >= FmpCapsuleSize(0x%x)\n", Index, ItemOffsetList[Index], FmpCapsuleSize)); 300 return EFI_INVALID_PARAMETER; 301 } 302 if (ItemOffsetList[Index] < FmpCapsuleHeaderSize) { 303 DEBUG((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) < FmpCapsuleHeaderSize(0x%x)\n", Index, ItemOffsetList[Index], FmpCapsuleHeaderSize)); 304 return EFI_INVALID_PARAMETER; 305 } 306 // 307 // All the address in ItemOffsetList must be stored in ascending order 308 // 309 if (Index > 0) { 310 if (ItemOffsetList[Index] <= ItemOffsetList[Index - 1]) { 311 DEBUG((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) < ItemOffsetList[%d](0x%x)\n", Index, ItemOffsetList[Index], Index, ItemOffsetList[Index - 1])); 312 return EFI_INVALID_PARAMETER; 313 } 314 } 315 } 316 317 // Check EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER 318 for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < ItemNum; Index++) { 319 ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]); 320 if (Index == ItemNum - 1) { 321 EndOfPayload = (UINT8 *)((UINTN)EndOfCapsule - (UINTN)FmpCapsuleHeader); 322 } else { 323 EndOfPayload = (UINT8 *)(UINTN)ItemOffsetList[Index+1]; 324 } 325 FmpImageSize = (UINTN)EndOfPayload - ItemOffsetList[Index]; 326 327 if (FmpImageSize < OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance)) { 328 DEBUG((DEBUG_ERROR, "FmpImageSize(0x%lx) < EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER\n", FmpImageSize)); 329 return EFI_INVALID_PARAMETER; 330 } 331 FmpImageHeaderSize = sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER); 332 if ((ImageHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) || 333 (ImageHeader->Version < 1)) { 334 DEBUG((DEBUG_ERROR, "ImageHeader->Version(0x%x) Unknown\n", ImageHeader->Version)); 335 return EFI_INVALID_PARAMETER; 336 } 337 if (ImageHeader->Version < EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) { 338 FmpImageHeaderSize = OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance); 339 } 340 341 // No overflow 342 if (FmpImageSize != (UINT64)FmpImageHeaderSize + (UINT64)ImageHeader->UpdateImageSize + (UINT64)ImageHeader->UpdateVendorCodeSize) { 343 DEBUG((DEBUG_ERROR, "FmpImageSize(0x%lx) mismatch, UpdateImageSize(0x%x) UpdateVendorCodeSize(0x%x)\n", FmpImageSize, ImageHeader->UpdateImageSize, ImageHeader->UpdateVendorCodeSize)); 344 return EFI_INVALID_PARAMETER; 345 } 346 } 347 348 if (ItemNum == 0) { 349 // 350 // No driver & payload element in FMP 351 // 352 EndOfPayload = (UINT8 *)(FmpCapsuleHeader + 1); 353 if (EndOfPayload != EndOfCapsule) { 354 DEBUG((DEBUG_ERROR, "EndOfPayload(0x%x) mismatch, EndOfCapsule(0x%x)\n", EndOfPayload, EndOfCapsule)); 355 return EFI_INVALID_PARAMETER; 356 } 357 return EFI_UNSUPPORTED; 358 } 359 360 // 361 // Check in system FMP capsule 362 // 363 if (IsSystemFmp != NULL) { 364 *IsSystemFmp = IsSystemFmpCapsuleImage(CapsuleHeader); 365 } 366 367 if (EmbeddedDriverCount != NULL) { 368 *EmbeddedDriverCount = FmpCapsuleHeader->EmbeddedDriverCount; 369 } 370 371 return EFI_SUCCESS; 372} 373 374/** 375 Recovery module entrypoint 376 377 @param[in] FileHandle Handle of the file being invoked. 378 @param[in] PeiServices Describes the list of possible PEI Services. 379 380 @return EFI_SUCCESS Recovery module is initialized. 381**/ 382EFI_STATUS 383EFIAPI 384InitializeRecoveryModule ( 385 IN EFI_PEI_FILE_HANDLE FileHandle, 386 IN CONST EFI_PEI_SERVICES **PeiServices 387 ) 388{ 389 EFI_STATUS Status; 390 UINTN BootMode; 391 392 BootMode = GetBootModeHob(); 393 ASSERT(BootMode == BOOT_IN_RECOVERY_MODE); 394 395 Status = (**PeiServices).InstallPpi (PeiServices, &mRecoveryPpiList); 396 ASSERT_EFI_ERROR (Status); 397 398 return Status; 399} 400 401/** 402 Create hob and install FvInfo PPI for recovery capsule. 403 404 @param[in] FvImage Points to the DXE FV image. 405 @param[in] FvImageSize The length of the DXE FV image in bytes. 406 407 @retval EFI_SUCESS Create hob and install FvInfo PPI successfully. 408 @retval EFI_VOLUME_CORRUPTED The input data is not an FV. 409 @retval EFI_OUT_OF_RESOURCES No enough resource to process the input data. 410**/ 411EFI_STATUS 412EFIAPI 413CreateHobForRecoveryCapsule ( 414 IN VOID *FvImage, 415 IN UINTN FvImageSize 416 ) 417{ 418 EFI_FIRMWARE_VOLUME_HEADER *FvHeader; 419 UINT32 FvAlignment; 420 UINT64 FvLength; 421 VOID *NewFvBuffer; 422 423 // 424 // FvImage should be at its required alignment. 425 // 426 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) FvImage; 427 // 428 // Validate FV Header, if not as expected, return 429 // 430 if (ReadUnaligned32 (&FvHeader->Signature) != EFI_FVH_SIGNATURE) { 431 DEBUG((DEBUG_ERROR, "CreateHobForRecoveryCapsule (Fv Signature Error)\n")); 432 return EFI_VOLUME_CORRUPTED; 433 } 434 // 435 // If EFI_FVB2_WEAK_ALIGNMENT is set in the volume header then the first byte of the volume 436 // can be aligned on any power-of-two boundary. A weakly aligned volume can not be moved from 437 // its initial linked location and maintain its alignment. 438 // 439 if ((ReadUnaligned32 (&FvHeader->Attributes) & EFI_FVB2_WEAK_ALIGNMENT) != EFI_FVB2_WEAK_ALIGNMENT) { 440 // 441 // Get FvHeader alignment 442 // 443 FvAlignment = 1 << ((ReadUnaligned32 (&FvHeader->Attributes) & EFI_FVB2_ALIGNMENT) >> 16); 444 // 445 // FvAlignment must be greater than or equal to 8 bytes of the minimum FFS alignment value. 446 // 447 if (FvAlignment < 8) { 448 FvAlignment = 8; 449 } 450 // 451 // Allocate the aligned buffer for the FvImage. 452 // 453 if ((UINTN) FvHeader % FvAlignment != 0) { 454 DEBUG((DEBUG_INFO, "CreateHobForRecoveryCapsule (FvHeader 0x%lx is not aligned)\n", (UINT64)(UINTN)FvHeader)); 455 FvLength = ReadUnaligned64 (&FvHeader->FvLength); 456 NewFvBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES ((UINTN) FvLength), FvAlignment); 457 if (NewFvBuffer == NULL) { 458 DEBUG((DEBUG_ERROR, "CreateHobForRecoveryCapsule (Not enough resource to allocate 0x%lx bytes)\n", FvLength)); 459 return EFI_OUT_OF_RESOURCES; 460 } 461 CopyMem (NewFvBuffer, FvHeader, (UINTN) FvLength); 462 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER*) NewFvBuffer; 463 } 464 } 465 466 BuildFvHob((UINT64)(UINTN)FvHeader, FvHeader->FvLength); 467 DEBUG((DEBUG_INFO, "BuildFvHob (FV in recovery) - 0x%lx - 0x%lx\n", (UINT64)(UINTN)FvHeader, FvHeader->FvLength)); 468 469 PeiServicesInstallFvInfoPpi( 470 NULL, 471 (VOID *)FvHeader, 472 (UINT32)FvHeader->FvLength, 473 NULL, 474 NULL 475 ); 476 477 return EFI_SUCCESS; 478} 479 480/** 481 Create recovery context based upon System Firmware image and config file. 482 483 @param[in] SystemFirmwareImage Points to the System Firmware image. 484 @param[in] SystemFirmwareImageSize The length of the System Firmware image in bytes. 485 @param[in] ConfigImage Points to the config file image. 486 @param[in] ConfigImageSize The length of the config file image in bytes. 487 488 @retval EFI_SUCESS Process Recovery Image successfully. 489**/ 490EFI_STATUS 491RecoverImage ( 492 IN VOID *SystemFirmwareImage, 493 IN UINTN SystemFirmwareImageSize, 494 IN VOID *ConfigImage, 495 IN UINTN ConfigImageSize 496 ) 497{ 498 EFI_STATUS Status; 499 RECOVERY_CONFIG_DATA *ConfigData; 500 RECOVERY_CONFIG_DATA *RecoveryConfigData; 501 CONFIG_HEADER ConfigHeader; 502 UINTN Index; 503 504 if (ConfigImage == NULL) { 505 DEBUG((DEBUG_INFO, "RecoverImage (NoConfig)\n")); 506 Status = CreateHobForRecoveryCapsule( 507 SystemFirmwareImage, 508 SystemFirmwareImageSize 509 ); 510 return Status; 511 } 512 513 ConfigData = NULL; 514 ZeroMem (&ConfigHeader, sizeof(ConfigHeader)); 515 Status = ParseRecoveryDataFile ( 516 ConfigImage, 517 ConfigImageSize, 518 &ConfigHeader, 519 &ConfigData 520 ); 521 DEBUG((DEBUG_INFO, "ParseRecoveryDataFile - %r\n", Status)); 522 if (EFI_ERROR(Status)) { 523 return Status; 524 } 525 DEBUG((DEBUG_INFO, "ConfigHeader.NumOfRecovery - 0x%x\n", ConfigHeader.NumOfRecovery)); 526 DEBUG((DEBUG_INFO, "PcdEdkiiSystemFirmwareFileGuid - %g\n", PcdGetPtr(PcdEdkiiSystemFirmwareFileGuid))); 527 528 Index = 0; 529 RecoveryConfigData = ConfigData; 530 while (Index < ConfigHeader.NumOfRecovery) { 531 if (CompareGuid(&RecoveryConfigData->FileGuid, PcdGetPtr(PcdEdkiiSystemFirmwareFileGuid))) { 532 DEBUG((DEBUG_INFO, "FileGuid - %g (processing)\n", &RecoveryConfigData->FileGuid)); 533 Status = CreateHobForRecoveryCapsule ( 534 (UINT8 *)SystemFirmwareImage + RecoveryConfigData->ImageOffset, 535 RecoveryConfigData->Length 536 ); 537 // 538 // Shall updates be serialized so that if a recovery FV is not successfully completed, 539 // the remaining updates won't be performed. 540 // 541 if (EFI_ERROR (Status)) { 542 break; 543 } 544 } else { 545 DEBUG((DEBUG_INFO, "FileGuid - %g (ignored)\n", &RecoveryConfigData->FileGuid)); 546 } 547 548 Index++; 549 RecoveryConfigData++; 550 } 551 552 return Status; 553} 554 555/** 556 Process recovery image. 557 558 Caution: This function may receive untrusted input. 559 560 @param[in] Image Points to the recovery image. 561 @param[in] Length The length of the recovery image in bytes. 562 563 @retval EFI_SUCESS Process Recovery Image successfully. 564 @retval EFI_SECURITY_VIOLATION Recovery image is not processed due to security violation. 565**/ 566EFI_STATUS 567ProcessRecoveryImage ( 568 IN VOID *Image, 569 IN UINTN Length 570 ) 571{ 572 UINT32 LastAttemptVersion; 573 UINT32 LastAttemptStatus; 574 EFI_STATUS Status; 575 VOID *SystemFirmwareImage; 576 UINTN SystemFirmwareImageSize; 577 VOID *ConfigImage; 578 UINTN ConfigImageSize; 579 VOID *AuthenticatedImage; 580 UINTN AuthenticatedImageSize; 581 582 AuthenticatedImage = NULL; 583 AuthenticatedImageSize = 0; 584 585 Status = CapsuleAuthenticateSystemFirmware(Image, Length, TRUE, &LastAttemptVersion, &LastAttemptStatus, &AuthenticatedImage, &AuthenticatedImageSize); 586 if (EFI_ERROR(Status)) { 587 DEBUG((DEBUG_INFO, "CapsuleAuthenticateSystemFirmware - %r\n", Status)); 588 return Status; 589 } 590 591 ExtractSystemFirmwareImage(AuthenticatedImage, AuthenticatedImageSize, &SystemFirmwareImage, &SystemFirmwareImageSize); 592 ExtractConfigImage(AuthenticatedImage, AuthenticatedImageSize, &ConfigImage, &ConfigImageSize); 593 594 Status = RecoverImage(SystemFirmwareImage, SystemFirmwareImageSize, ConfigImage, ConfigImageSize); 595 if (EFI_ERROR(Status)) { 596 DEBUG((DEBUG_INFO, "RecoverImage - %r\n", Status)); 597 return Status; 598 } 599 600 return EFI_SUCCESS; 601} 602 603/** 604 Process Firmware management protocol data capsule. 605 606 Caution: This function may receive untrusted input. 607 608 This function assumes the caller validated the capsule by using 609 ValidateFmpCapsule(), so that all fields in EFI_CAPSULE_HEADER, 610 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER and 611 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER are correct. 612 613 @param[in] CapsuleHeader Points to a capsule header. 614 @param[in] IsSystemFmp If this capsule is a system FMP capsule. 615 616 @retval EFI_SUCESS Process Capsule Image successfully. 617 @retval EFI_UNSUPPORTED Capsule image is not supported by the firmware. 618 @retval EFI_VOLUME_CORRUPTED FV volume in the capsule is corrupted. 619 @retval EFI_OUT_OF_RESOURCES Not enough memory. 620**/ 621EFI_STATUS 622ProcessFmpCapsuleImage ( 623 IN EFI_CAPSULE_HEADER *CapsuleHeader, 624 IN BOOLEAN IsSystemFmp 625 ) 626{ 627 EFI_STATUS Status; 628 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader; 629 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader; 630 UINT8 *Image; 631 UINT64 *ItemOffsetList; 632 UINTN ItemIndex; 633 634 if (!IsSystemFmp) { 635 return EFI_UNSUPPORTED; 636 } 637 638 FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize); 639 ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1); 640 641 for (ItemIndex = 0; ItemIndex < FmpCapsuleHeader->PayloadItemCount; ItemIndex++) { 642 ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[ItemIndex]); 643 if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) { 644 Image = (UINT8 *)(ImageHeader + 1); 645 } else { 646 // 647 // If the EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER is version 1, only match ImageTypeId. 648 // Header should exclude UpdateHardwareInstance field 649 // 650 Image = (UINT8 *)ImageHeader + OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance); 651 } 652 653 Status = ProcessRecoveryImage (Image, ImageHeader->UpdateImageSize); 654 if (EFI_ERROR(Status)) { 655 return Status; 656 } 657 } 658 659 return EFI_SUCCESS; 660} 661 662/** 663 Process recovery capsule image. 664 665 Caution: This function may receive untrusted input. 666 667 @param[in] CapsuleBuffer The capsule image buffer. 668 @param[in] CapsuleSize The size of the capsule image in bytes. 669 670 @retval EFI_SUCCESS The recovery capsule is processed. 671 @retval EFI_SECURITY_VIOLATION The recovery capsule is not process because of security violation. 672 @retval EFI_NOT_FOUND The recovery capsule is not process because of unrecognization. 673**/ 674EFI_STATUS 675EFIAPI 676ProcessRecoveryCapsule ( 677 IN VOID *CapsuleBuffer, 678 IN UINTN CapsuleSize 679 ) 680{ 681 EFI_STATUS Status; 682 BOOLEAN IsSystemFmp; 683 EFI_CAPSULE_HEADER *CapsuleHeader; 684 685 CapsuleHeader = CapsuleBuffer; 686 if (!IsValidCapsuleHeader (CapsuleHeader, CapsuleSize)) { 687 DEBUG((DEBUG_ERROR, "CapsuleImageSize incorrect\n")); 688 return EFI_SECURITY_VIOLATION; 689 } 690 691 // 692 // Check FMP capsule layout 693 // 694 if (IsFmpCapsuleGuid(&CapsuleHeader->CapsuleGuid)) { 695 DEBUG((DEBUG_INFO, "CreateHobForRecoveryCapsule\n")); 696 697 DEBUG((DEBUG_INFO, "ProcessCapsuleImage for FmpCapsule ...\n")); 698 DEBUG((DEBUG_INFO, "ValidateFmpCapsule ...\n")); 699 Status = ValidateFmpCapsule(CapsuleHeader, &IsSystemFmp, NULL); 700 DEBUG((DEBUG_INFO, "ValidateFmpCapsule - %r\n", Status)); 701 if (EFI_ERROR(Status)) { 702 return Status; 703 } 704 705 // 706 // Press EFI FMP Capsule 707 // 708 DEBUG((DEBUG_INFO, "ProcessFmpCapsuleImage ...\n")); 709 Status = ProcessFmpCapsuleImage(CapsuleHeader, IsSystemFmp); 710 DEBUG((DEBUG_INFO, "ProcessFmpCapsuleImage - %r\n", Status)); 711 712 DEBUG((DEBUG_INFO, "CreateHobForRecoveryCapsule Done\n")); 713 return Status; 714 } 715 716 return EFI_UNSUPPORTED; 717} 718 719/** 720 Loads a DXE capsule from some media into memory and updates the HOB table 721 with the DXE firmware volume information. 722 723 @param[in] PeiServices General-purpose services that are available to every PEIM. 724 @param[in] This Indicates the EFI_PEI_RECOVERY_MODULE_PPI instance. 725 726 @retval EFI_SUCCESS The capsule was loaded correctly. 727 @retval EFI_DEVICE_ERROR A device error occurred. 728 @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found. 729 730**/ 731EFI_STATUS 732EFIAPI 733LoadRecoveryCapsule ( 734 IN EFI_PEI_SERVICES **PeiServices, 735 IN EFI_PEI_RECOVERY_MODULE_PPI *This 736 ) 737{ 738 EFI_STATUS Status; 739 EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *DeviceRecoveryPpi; 740 UINTN NumberRecoveryCapsules; 741 UINTN Instance; 742 UINTN CapsuleInstance; 743 UINTN CapsuleSize; 744 EFI_GUID CapsuleType; 745 VOID *CapsuleBuffer; 746 747 DEBUG((DEBUG_INFO | DEBUG_LOAD, "Recovery Entry\n")); 748 749 for (Instance = 0; ; Instance++) { 750 Status = PeiServicesLocatePpi ( 751 &gEfiPeiDeviceRecoveryModulePpiGuid, 752 Instance, 753 NULL, 754 (VOID **)&DeviceRecoveryPpi 755 ); 756 DEBUG ((DEBUG_ERROR, "LoadRecoveryCapsule - LocateRecoveryPpi (%d) - %r\n", Instance, Status)); 757 if (EFI_ERROR (Status)) { 758 break; 759 } 760 NumberRecoveryCapsules = 0; 761 Status = DeviceRecoveryPpi->GetNumberRecoveryCapsules ( 762 (EFI_PEI_SERVICES **)PeiServices, 763 DeviceRecoveryPpi, 764 &NumberRecoveryCapsules 765 ); 766 DEBUG ((DEBUG_ERROR, "LoadRecoveryCapsule - GetNumberRecoveryCapsules (%d) - %r\n", NumberRecoveryCapsules, Status)); 767 if (EFI_ERROR (Status)) { 768 continue; 769 } 770 for (CapsuleInstance = 1; CapsuleInstance <= NumberRecoveryCapsules; CapsuleInstance++) { 771 CapsuleSize = 0; 772 Status = DeviceRecoveryPpi->GetRecoveryCapsuleInfo ( 773 (EFI_PEI_SERVICES **)PeiServices, 774 DeviceRecoveryPpi, 775 FeaturePcdGet(PcdFrameworkCompatibilitySupport) ? CapsuleInstance - 1 : CapsuleInstance, 776 &CapsuleSize, 777 &CapsuleType 778 ); 779 DEBUG ((DEBUG_ERROR, "LoadRecoveryCapsule - GetRecoveryCapsuleInfo (%d - %x) - %r\n", CapsuleInstance, CapsuleSize, Status)); 780 if (EFI_ERROR (Status)) { 781 break; 782 } 783 784 CapsuleBuffer = AllocatePages (EFI_SIZE_TO_PAGES(CapsuleSize)); 785 if (CapsuleBuffer == NULL) { 786 DEBUG ((DEBUG_ERROR, "LoadRecoveryCapsule - AllocatePool fail\n")); 787 continue; 788 } 789 Status = DeviceRecoveryPpi->LoadRecoveryCapsule ( 790 (EFI_PEI_SERVICES **)PeiServices, 791 DeviceRecoveryPpi, 792 FeaturePcdGet(PcdFrameworkCompatibilitySupport) ? CapsuleInstance - 1 : CapsuleInstance, 793 CapsuleBuffer 794 ); 795 DEBUG ((DEBUG_ERROR, "LoadRecoveryCapsule - LoadRecoveryCapsule (%d) - %r\n", CapsuleInstance, Status)); 796 if (EFI_ERROR (Status)) { 797 FreePages (CapsuleBuffer, EFI_SIZE_TO_PAGES(CapsuleSize)); 798 break; 799 } 800 // 801 // good, load capsule buffer 802 // 803 Status = ProcessRecoveryCapsule (CapsuleBuffer, CapsuleSize); 804 return Status; 805 } 806 } 807 808 return EFI_NOT_FOUND; 809} 810