1 /** @file 2 Capsule Library instance to process capsule images. 3 4 Copyright (c) 2007 - 2013, Intel Corporation. All rights reserved.<BR> 5 6 This program and the accompanying materials 7 are licensed and made available under the terms and conditions of the BSD License 8 which accompanies this distribution. The full text of the license may be found at 9 http://opensource.org/licenses/bsd-license.php 10 11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13 14 **/ 15 #include <PiDxe.h> 16 17 #include <Guid/Capsule.h> 18 #include <Guid/FmpCapsule.h> 19 20 #include <Library/DebugLib.h> 21 #include <Library/BaseMemoryLib.h> 22 #include <Library/DxeServicesTableLib.h> 23 #include <Library/MemoryAllocationLib.h> 24 #include <Library/CapsuleLib.h> 25 #include <Library/GenericBdsLib.h> 26 #include <Library/UefiBootServicesTableLib.h> 27 #include <Library/BaseLib.h> 28 #include <Library/DevicePathLib.h> 29 30 #include <Protocol/FirmwareManagement.h> 31 #include <Protocol/DevicePath.h> 32 33 34 /** 35 Function indicate the current completion progress of the firmware 36 update. Platform may override with own specific progress function. 37 38 @param Completion A value between 1 and 100 indicating the current completion progress of the firmware update 39 40 @retval EFI_SUCESS Input capsule is a correct FMP capsule. 41 **/ 42 EFI_STATUS 43 EFIAPI 44 Update_Image_Progress ( 45 IN UINTN Completion 46 ) 47 { 48 return EFI_SUCCESS; 49 } 50 51 52 /** 53 Validate Fmp capsules layout. 54 55 @param CapsuleHeader Points to a capsule header. 56 57 @retval EFI_SUCESS Input capsule is a correct FMP capsule. 58 @retval EFI_INVALID_PARAMETER Input capsule is not a correct FMP capsule. 59 **/ 60 EFI_STATUS 61 ValidateFmpCapsule ( 62 IN EFI_CAPSULE_HEADER *CapsuleHeader 63 ) 64 { 65 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader; 66 UINT8 *EndOfCapsule; 67 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader; 68 UINT8 *EndOfPayload; 69 UINT64 *ItemOffsetList; 70 UINT32 ItemNum; 71 UINTN Index; 72 73 FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize); 74 EndOfCapsule = (UINT8 *) CapsuleHeader + CapsuleHeader->CapsuleImageSize; 75 76 if (FmpCapsuleHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) { 77 return EFI_INVALID_PARAMETER; 78 } 79 ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1); 80 81 ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount; 82 83 if (ItemNum == FmpCapsuleHeader->EmbeddedDriverCount) { 84 // 85 // No payload element 86 // 87 if (((UINT8 *)FmpCapsuleHeader + ItemOffsetList[ItemNum - 1]) < EndOfCapsule) { 88 return EFI_SUCCESS; 89 } else { 90 return EFI_INVALID_PARAMETER; 91 } 92 } 93 94 if (FmpCapsuleHeader->PayloadItemCount != 0) { 95 // 96 // Check if the last payload is within capsule image range 97 // 98 ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[ItemNum - 1]); 99 EndOfPayload = (UINT8 *)(ImageHeader + 1) + ImageHeader->UpdateImageSize + ImageHeader->UpdateVendorCodeSize; 100 } else { 101 // 102 // No driver & payload element in FMP 103 // 104 EndOfPayload = (UINT8 *)(FmpCapsuleHeader + 1); 105 } 106 107 if (EndOfPayload != EndOfCapsule) { 108 return EFI_INVALID_PARAMETER; 109 } 110 111 // 112 // All the address in ItemOffsetList must be stored in ascending order 113 // 114 if (ItemNum >= 2) { 115 for (Index = 0; Index < ItemNum - 1; Index++) { 116 if (ItemOffsetList[Index] >= ItemOffsetList[Index + 1]) { 117 return EFI_INVALID_PARAMETER; 118 } 119 } 120 } 121 122 return EFI_SUCCESS; 123 } 124 125 /** 126 Process Firmware management protocol data capsule. 127 128 @param CapsuleHeader Points to a capsule header. 129 130 @retval EFI_SUCESS Process Capsule Image successfully. 131 @retval EFI_UNSUPPORTED Capsule image is not supported by the firmware. 132 @retval EFI_VOLUME_CORRUPTED FV volume in the capsule is corrupted. 133 @retval EFI_OUT_OF_RESOURCES Not enough memory. 134 **/ 135 EFI_STATUS 136 ProcessFmpCapsuleImage ( 137 IN EFI_CAPSULE_HEADER *CapsuleHeader 138 ) 139 { 140 EFI_STATUS Status; 141 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader; 142 UINT8 *EndOfCapsule; 143 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader; 144 EFI_HANDLE ImageHandle; 145 UINT64 *ItemOffsetList; 146 UINT32 ItemNum; 147 UINTN Index; 148 UINTN ExitDataSize; 149 EFI_HANDLE *HandleBuffer; 150 EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp; 151 UINTN NumberOfHandles; 152 UINTN DescriptorSize; 153 UINT8 FmpImageInfoCount; 154 UINT32 FmpImageInfoDescriptorVer; 155 UINTN ImageInfoSize; 156 UINT32 PackageVersion; 157 CHAR16 *PackageVersionName; 158 CHAR16 *AbortReason; 159 EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf; 160 EFI_FIRMWARE_IMAGE_DESCRIPTOR *TempFmpImageInfo; 161 UINTN DriverLen; 162 UINTN Index1; 163 UINTN Index2; 164 MEMMAP_DEVICE_PATH MemMapNode; 165 EFI_DEVICE_PATH_PROTOCOL *DriverDevicePath; 166 167 Status = EFI_SUCCESS; 168 HandleBuffer = NULL; 169 ExitDataSize = 0; 170 DriverDevicePath = NULL; 171 172 FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize); 173 EndOfCapsule = (UINT8 *) CapsuleHeader + CapsuleHeader->CapsuleImageSize; 174 175 if (FmpCapsuleHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) { 176 return EFI_INVALID_PARAMETER; 177 } 178 ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1); 179 180 ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount; 181 182 // 183 // capsule in which driver count and payload count are both zero is not processed. 184 // 185 if (ItemNum == 0) { 186 return EFI_SUCCESS; 187 } 188 189 // 190 // 1. ConnectAll to ensure 191 // All the communication protocol required by driver in capsule installed 192 // All FMP protocols are installed 193 // 194 BdsLibConnectAll(); 195 196 197 // 198 // 2. Try to load & start all the drivers within capsule 199 // 200 SetDevicePathNodeLength (&MemMapNode.Header, sizeof (MemMapNode)); 201 MemMapNode.Header.Type = HARDWARE_DEVICE_PATH; 202 MemMapNode.Header.SubType = HW_MEMMAP_DP; 203 MemMapNode.MemoryType = EfiBootServicesCode; 204 MemMapNode.StartingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)CapsuleHeader; 205 MemMapNode.EndingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)((UINT8 *)CapsuleHeader + CapsuleHeader->CapsuleImageSize - 1); 206 207 DriverDevicePath = AppendDevicePathNode (NULL, &MemMapNode.Header); 208 if (DriverDevicePath == NULL) { 209 return EFI_OUT_OF_RESOURCES; 210 } 211 212 for (Index = 0; Index < FmpCapsuleHeader->EmbeddedDriverCount; Index++) { 213 if (FmpCapsuleHeader->PayloadItemCount == 0 && Index == (UINTN)FmpCapsuleHeader->EmbeddedDriverCount - 1) { 214 // 215 // When driver is last element in the ItemOffsetList array, the driver size is calculated by reference CapsuleImageSize in EFI_CAPSULE_HEADER 216 // 217 DriverLen = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize - (UINTN)ItemOffsetList[Index]; 218 } else { 219 DriverLen = (UINTN)ItemOffsetList[Index + 1] - (UINTN)ItemOffsetList[Index]; 220 } 221 222 Status = gBS->LoadImage( 223 FALSE, 224 gImageHandle, 225 DriverDevicePath, 226 (UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index], 227 DriverLen, 228 &ImageHandle 229 ); 230 if (EFI_ERROR(Status)) { 231 goto EXIT; 232 } 233 234 Status = gBS->StartImage( 235 ImageHandle, 236 &ExitDataSize, 237 NULL 238 ); 239 if (EFI_ERROR(Status)) { 240 DEBUG ((DEBUG_ERROR, "Driver Return Status = %r\n", Status)); 241 goto EXIT; 242 } 243 } 244 245 // 246 // Connnect all again to connect drivers within capsule 247 // 248 if (FmpCapsuleHeader->EmbeddedDriverCount > 0) { 249 BdsLibConnectAll(); 250 } 251 252 // 253 // 3. Route payload to right FMP instance 254 // 255 Status = gBS->LocateHandleBuffer ( 256 ByProtocol, 257 &gEfiFirmwareManagementProtocolGuid, 258 NULL, 259 &NumberOfHandles, 260 &HandleBuffer 261 ); 262 263 if (!EFI_ERROR(Status)) { 264 for(Index1 = 0; Index1 < NumberOfHandles; Index1++) { 265 Status = gBS->HandleProtocol( 266 HandleBuffer[Index1], 267 &gEfiFirmwareManagementProtocolGuid, 268 (VOID **)&Fmp 269 ); 270 if (EFI_ERROR(Status)) { 271 continue; 272 } 273 274 ImageInfoSize = 0; 275 Status = Fmp->GetImageInfo ( 276 Fmp, 277 &ImageInfoSize, 278 NULL, 279 NULL, 280 NULL, 281 NULL, 282 NULL, 283 NULL 284 ); 285 if (Status != EFI_BUFFER_TOO_SMALL) { 286 continue; 287 } 288 289 FmpImageInfoBuf = NULL; 290 FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize); 291 if (FmpImageInfoBuf == NULL) { 292 Status = EFI_OUT_OF_RESOURCES; 293 goto EXIT; 294 } 295 296 PackageVersionName = NULL; 297 Status = Fmp->GetImageInfo ( 298 Fmp, 299 &ImageInfoSize, // ImageInfoSize 300 FmpImageInfoBuf, // ImageInfo 301 &FmpImageInfoDescriptorVer, // DescriptorVersion 302 &FmpImageInfoCount, // DescriptorCount 303 &DescriptorSize, // DescriptorSize 304 &PackageVersion, // PackageVersion 305 &PackageVersionName // PackageVersionName 306 ); 307 308 // 309 // If FMP GetInformation interface failed, skip this resource 310 // 311 if (EFI_ERROR(Status)) { 312 FreePool(FmpImageInfoBuf); 313 continue; 314 } 315 316 if (PackageVersionName != NULL) { 317 FreePool(PackageVersionName); 318 } 319 320 TempFmpImageInfo = FmpImageInfoBuf; 321 for (Index2 = 0; Index2 < FmpImageInfoCount; Index2++) { 322 // 323 // Check all the payload entry in capsule payload list 324 // 325 for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < ItemNum; Index++) { 326 ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]); 327 if (CompareGuid(&ImageHeader->UpdateImageTypeId, &TempFmpImageInfo->ImageTypeId) && 328 ImageHeader->UpdateImageIndex == TempFmpImageInfo->ImageIndex) { 329 AbortReason = NULL; 330 if (ImageHeader->UpdateVendorCodeSize == 0) { 331 Status = Fmp->SetImage( 332 Fmp, 333 TempFmpImageInfo->ImageIndex, // ImageIndex 334 (UINT8 *)(ImageHeader + 1), // Image 335 ImageHeader->UpdateImageSize, // ImageSize 336 NULL, // VendorCode 337 Update_Image_Progress, // Progress 338 &AbortReason // AbortReason 339 ); 340 } else { 341 Status = Fmp->SetImage( 342 Fmp, 343 TempFmpImageInfo->ImageIndex, // ImageIndex 344 (UINT8 *)(ImageHeader + 1), // Image 345 ImageHeader->UpdateImageSize, // ImageSize 346 (UINT8 *)((UINT8 *) (ImageHeader + 1) + ImageHeader->UpdateImageSize), // VendorCode 347 Update_Image_Progress, // Progress 348 &AbortReason // AbortReason 349 ); 350 } 351 if (AbortReason != NULL) { 352 DEBUG ((EFI_D_ERROR, "%s\n", AbortReason)); 353 FreePool(AbortReason); 354 } 355 } 356 } 357 // 358 // Use DescriptorSize to move ImageInfo Pointer to stay compatible with different ImageInfo version 359 // 360 TempFmpImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)TempFmpImageInfo + DescriptorSize); 361 } 362 FreePool(FmpImageInfoBuf); 363 } 364 } 365 366 EXIT: 367 368 if (HandleBuffer != NULL) { 369 FreePool(HandleBuffer); 370 } 371 372 if (DriverDevicePath != NULL) { 373 FreePool(DriverDevicePath); 374 } 375 376 return Status; 377 } 378 379 /** 380 Those capsules supported by the firmwares. 381 382 @param CapsuleHeader Points to a capsule header. 383 384 @retval EFI_SUCESS Input capsule is supported by firmware. 385 @retval EFI_UNSUPPORTED Input capsule is not supported by the firmware. 386 @retval EFI_INVALID_PARAMETER Input capsule layout is not correct 387 **/ 388 EFI_STATUS 389 EFIAPI 390 SupportCapsuleImage ( 391 IN EFI_CAPSULE_HEADER *CapsuleHeader 392 ) 393 { 394 if (CompareGuid (&gEfiCapsuleGuid, &CapsuleHeader->CapsuleGuid)) { 395 return EFI_SUCCESS; 396 } 397 398 if (CompareGuid (&gEfiFmpCapsuleGuid, &CapsuleHeader->CapsuleGuid)) { 399 // 400 // Check layout of FMP capsule 401 // 402 return ValidateFmpCapsule(CapsuleHeader); 403 } 404 405 return EFI_UNSUPPORTED; 406 } 407 408 /** 409 The firmware implements to process the capsule image. 410 411 @param CapsuleHeader Points to a capsule header. 412 413 @retval EFI_SUCESS Process Capsule Image successfully. 414 @retval EFI_UNSUPPORTED Capsule image is not supported by the firmware. 415 @retval EFI_VOLUME_CORRUPTED FV volume in the capsule is corrupted. 416 @retval EFI_OUT_OF_RESOURCES Not enough memory. 417 **/ 418 EFI_STATUS 419 EFIAPI 420 ProcessCapsuleImage ( 421 IN EFI_CAPSULE_HEADER *CapsuleHeader 422 ) 423 { 424 UINT32 Length; 425 EFI_FIRMWARE_VOLUME_HEADER *FvImage; 426 EFI_FIRMWARE_VOLUME_HEADER *ProcessedFvImage; 427 EFI_STATUS Status; 428 EFI_HANDLE FvProtocolHandle; 429 UINT32 FvAlignment; 430 431 FvImage = NULL; 432 ProcessedFvImage = NULL; 433 Status = EFI_SUCCESS; 434 435 if (SupportCapsuleImage (CapsuleHeader) != EFI_SUCCESS) { 436 return EFI_UNSUPPORTED; 437 } 438 439 // 440 // Check FMP capsule layout 441 // 442 if (CompareGuid (&gEfiFmpCapsuleGuid, &CapsuleHeader->CapsuleGuid)){ 443 Status = ValidateFmpCapsule(CapsuleHeader); 444 if (EFI_ERROR(Status)) { 445 return Status; 446 } 447 448 // 449 // Press EFI FMP Capsule 450 // 451 return ProcessFmpCapsuleImage(CapsuleHeader); 452 } 453 454 // 455 // Skip the capsule header, move to the Firware Volume 456 // 457 FvImage = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize); 458 Length = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize; 459 460 while (Length != 0) { 461 // 462 // Point to the next firmware volume header, and then 463 // call the DXE service to process it. 464 // 465 if (FvImage->FvLength > (UINTN) Length) { 466 // 467 // Notes: need to stuff this status somewhere so that the 468 // error can be detected at OS runtime 469 // 470 Status = EFI_VOLUME_CORRUPTED; 471 break; 472 } 473 474 FvAlignment = 1 << ((FvImage->Attributes & EFI_FVB2_ALIGNMENT) >> 16); 475 // 476 // FvAlignment must be more than 8 bytes required by FvHeader structure. 477 // 478 if (FvAlignment < 8) { 479 FvAlignment = 8; 480 } 481 // 482 // Check FvImage Align is required. 483 // 484 if (((UINTN) FvImage % FvAlignment) == 0) { 485 ProcessedFvImage = FvImage; 486 } else { 487 // 488 // Allocate new aligned buffer to store FvImage. 489 // 490 ProcessedFvImage = (EFI_FIRMWARE_VOLUME_HEADER *) AllocateAlignedPages ((UINTN) EFI_SIZE_TO_PAGES ((UINTN) FvImage->FvLength), (UINTN) FvAlignment); 491 if (ProcessedFvImage == NULL) { 492 Status = EFI_OUT_OF_RESOURCES; 493 break; 494 } 495 CopyMem (ProcessedFvImage, FvImage, (UINTN) FvImage->FvLength); 496 } 497 498 Status = gDS->ProcessFirmwareVolume ( 499 (VOID *) ProcessedFvImage, 500 (UINTN) ProcessedFvImage->FvLength, 501 &FvProtocolHandle 502 ); 503 if (EFI_ERROR (Status)) { 504 break; 505 } 506 // 507 // Call the dispatcher to dispatch any drivers from the produced firmware volume 508 // 509 gDS->Dispatch (); 510 // 511 // On to the next FV in the capsule 512 // 513 Length -= (UINT32) FvImage->FvLength; 514 FvImage = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINT8 *) FvImage + FvImage->FvLength); 515 } 516 517 return Status; 518 } 519 520 521