1 /** @file 2 Source file for CD recovery PEIM 3 4 Copyright (c) 2006 - 2015, 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 8 of the BSD License which accompanies this distribution. The 9 full text of the license may be found at 10 http://opensource.org/licenses/bsd-license.php 11 12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 14 15 **/ 16 17 #include "PeiCdExpress.h" 18 19 PEI_CD_EXPRESS_PRIVATE_DATA *mPrivateData = NULL; 20 21 /** 22 Installs the Device Recovery Module PPI, Initialize BlockIo Ppi 23 installation notification 24 25 @param FileHandle The file handle of the image. 26 @param PeiServices General purpose services available to every PEIM. 27 28 @retval EFI_SUCCESS The function completed successfully. 29 @retval EFI_OUT_OF_RESOURCES There is not enough system memory. 30 31 **/ 32 EFI_STATUS 33 EFIAPI 34 CdExpressPeimEntry ( 35 IN EFI_PEI_FILE_HANDLE FileHandle, 36 IN CONST EFI_PEI_SERVICES **PeiServices 37 ) 38 { 39 EFI_STATUS Status; 40 PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData; 41 42 if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) { 43 return EFI_SUCCESS; 44 } 45 46 PrivateData = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (*PrivateData))); 47 if (PrivateData == NULL) { 48 return EFI_OUT_OF_RESOURCES; 49 } 50 51 // 52 // Initialize Private Data (to zero, as is required by subsequent operations) 53 // 54 ZeroMem (PrivateData, sizeof (*PrivateData)); 55 PrivateData->Signature = PEI_CD_EXPRESS_PRIVATE_DATA_SIGNATURE; 56 57 PrivateData->BlockBuffer = AllocatePages (EFI_SIZE_TO_PAGES (PEI_CD_BLOCK_SIZE)); 58 if (PrivateData->BlockBuffer == NULL) { 59 return EFI_OUT_OF_RESOURCES; 60 } 61 62 PrivateData->CapsuleCount = 0; 63 Status = UpdateBlocksAndVolumes (PrivateData, TRUE); 64 Status = UpdateBlocksAndVolumes (PrivateData, FALSE); 65 66 // 67 // Installs Ppi 68 // 69 PrivateData->DeviceRecoveryPpi.GetNumberRecoveryCapsules = GetNumberRecoveryCapsules; 70 PrivateData->DeviceRecoveryPpi.GetRecoveryCapsuleInfo = GetRecoveryCapsuleInfo; 71 PrivateData->DeviceRecoveryPpi.LoadRecoveryCapsule = LoadRecoveryCapsule; 72 73 PrivateData->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST); 74 PrivateData->PpiDescriptor.Guid = &gEfiPeiDeviceRecoveryModulePpiGuid; 75 PrivateData->PpiDescriptor.Ppi = &PrivateData->DeviceRecoveryPpi; 76 77 Status = PeiServicesInstallPpi (&PrivateData->PpiDescriptor); 78 if (EFI_ERROR (Status)) { 79 return EFI_OUT_OF_RESOURCES; 80 } 81 // 82 // PrivateData is allocated now, set it to the module variable 83 // 84 mPrivateData = PrivateData; 85 86 // 87 // Installs Block Io Ppi notification function 88 // 89 PrivateData->NotifyDescriptor.Flags = 90 ( 91 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK 92 ); 93 PrivateData->NotifyDescriptor.Guid = &gEfiPeiVirtualBlockIoPpiGuid; 94 PrivateData->NotifyDescriptor.Notify = BlockIoNotifyEntry; 95 96 PrivateData->NotifyDescriptor2.Flags = 97 ( 98 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | 99 EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST 100 ); 101 PrivateData->NotifyDescriptor2.Guid = &gEfiPeiVirtualBlockIo2PpiGuid; 102 PrivateData->NotifyDescriptor2.Notify = BlockIoNotifyEntry; 103 104 return PeiServicesNotifyPpi (&PrivateData->NotifyDescriptor); 105 106 } 107 108 /** 109 BlockIo installation notification function. 110 111 This function finds out all the current Block IO PPIs in the system and add them 112 into private data. 113 114 @param PeiServices Indirect reference to the PEI Services Table. 115 @param NotifyDescriptor Address of the notification descriptor data structure. 116 @param Ppi Address of the PPI that was installed. 117 118 @retval EFI_SUCCESS The function completes successfully. 119 120 **/ 121 EFI_STATUS 122 EFIAPI 123 BlockIoNotifyEntry ( 124 IN EFI_PEI_SERVICES **PeiServices, 125 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, 126 IN VOID *Ppi 127 ) 128 { 129 if (CompareGuid (NotifyDescriptor->Guid, &gEfiPeiVirtualBlockIo2PpiGuid)) { 130 UpdateBlocksAndVolumes (mPrivateData, TRUE); 131 } else { 132 UpdateBlocksAndVolumes (mPrivateData, FALSE); 133 } 134 135 return EFI_SUCCESS; 136 } 137 138 /** 139 Finds out all the current Block IO PPIs in the system and add them into private data. 140 141 @param PrivateData The private data structure that contains recovery module information. 142 @param BlockIo2 Boolean to show whether using BlockIo2 or BlockIo. 143 144 @retval EFI_SUCCESS The blocks and volumes are updated successfully. 145 146 **/ 147 EFI_STATUS 148 UpdateBlocksAndVolumes ( 149 IN OUT PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData, 150 IN BOOLEAN BlockIo2 151 ) 152 { 153 EFI_STATUS Status; 154 EFI_PEI_PPI_DESCRIPTOR *TempPpiDescriptor; 155 UINTN BlockIoPpiInstance; 156 EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi; 157 EFI_PEI_RECOVERY_BLOCK_IO2_PPI *BlockIo2Ppi; 158 UINTN NumberBlockDevices; 159 UINTN IndexBlockDevice; 160 EFI_PEI_BLOCK_IO_MEDIA Media; 161 EFI_PEI_BLOCK_IO2_MEDIA Media2; 162 EFI_PEI_SERVICES **PeiServices; 163 164 IndexBlockDevice = 0; 165 BlockIo2Ppi = NULL; 166 BlockIoPpi = NULL; 167 // 168 // Find out all Block Io Ppi instances within the system 169 // Assuming all device Block Io Peims are dispatched already 170 // 171 for (BlockIoPpiInstance = 0; BlockIoPpiInstance < PEI_CD_EXPRESS_MAX_BLOCK_IO_PPI; BlockIoPpiInstance++) { 172 if (BlockIo2) { 173 Status = PeiServicesLocatePpi ( 174 &gEfiPeiVirtualBlockIo2PpiGuid, 175 BlockIoPpiInstance, 176 &TempPpiDescriptor, 177 (VOID **) &BlockIo2Ppi 178 ); 179 } else { 180 Status = PeiServicesLocatePpi ( 181 &gEfiPeiVirtualBlockIoPpiGuid, 182 BlockIoPpiInstance, 183 &TempPpiDescriptor, 184 (VOID **) &BlockIoPpi 185 ); 186 } 187 if (EFI_ERROR (Status)) { 188 // 189 // Done with all Block Io Ppis 190 // 191 break; 192 } 193 194 PeiServices = (EFI_PEI_SERVICES **) GetPeiServicesTablePointer (); 195 if (BlockIo2) { 196 Status = BlockIo2Ppi->GetNumberOfBlockDevices ( 197 PeiServices, 198 BlockIo2Ppi, 199 &NumberBlockDevices 200 ); 201 } else { 202 Status = BlockIoPpi->GetNumberOfBlockDevices ( 203 PeiServices, 204 BlockIoPpi, 205 &NumberBlockDevices 206 ); 207 } 208 if (EFI_ERROR (Status) || (NumberBlockDevices == 0)) { 209 continue; 210 } 211 // 212 // Just retrieve the first block, should emulate all blocks. 213 // 214 for (IndexBlockDevice = 1; IndexBlockDevice <= NumberBlockDevices && PrivateData->CapsuleCount < PEI_CD_EXPRESS_MAX_CAPSULE_NUMBER; IndexBlockDevice ++) { 215 if (BlockIo2) { 216 Status = BlockIo2Ppi->GetBlockDeviceMediaInfo ( 217 PeiServices, 218 BlockIo2Ppi, 219 IndexBlockDevice, 220 &Media2 221 ); 222 if (EFI_ERROR (Status) || 223 !Media2.MediaPresent || 224 ((Media2.InterfaceType != MSG_ATAPI_DP) && (Media2.InterfaceType != MSG_USB_DP)) || 225 (Media2.BlockSize != PEI_CD_BLOCK_SIZE) 226 ) { 227 continue; 228 } 229 DEBUG ((EFI_D_INFO, "PeiCdExpress InterfaceType is %d\n", Media2.InterfaceType)); 230 DEBUG ((EFI_D_INFO, "PeiCdExpress MediaPresent is %d\n", Media2.MediaPresent)); 231 DEBUG ((EFI_D_INFO, "PeiCdExpress BlockSize is 0x%x\n", Media2.BlockSize)); 232 } else { 233 Status = BlockIoPpi->GetBlockDeviceMediaInfo ( 234 PeiServices, 235 BlockIoPpi, 236 IndexBlockDevice, 237 &Media 238 ); 239 if (EFI_ERROR (Status) || 240 !Media.MediaPresent || 241 ((Media.DeviceType != IdeCDROM) && (Media.DeviceType != UsbMassStorage)) || 242 (Media.BlockSize != PEI_CD_BLOCK_SIZE) 243 ) { 244 continue; 245 } 246 DEBUG ((EFI_D_INFO, "PeiCdExpress DeviceType is %d\n", Media.DeviceType)); 247 DEBUG ((EFI_D_INFO, "PeiCdExpress MediaPresent is %d\n", Media.MediaPresent)); 248 DEBUG ((EFI_D_INFO, "PeiCdExpress BlockSize is 0x%x\n", Media.BlockSize)); 249 } 250 251 DEBUG ((EFI_D_INFO, "PeiCdExpress Status is %d\n", Status)); 252 253 DEBUG ((EFI_D_INFO, "IndexBlockDevice is %d\n", IndexBlockDevice)); 254 PrivateData->CapsuleData[PrivateData->CapsuleCount].IndexBlock = IndexBlockDevice; 255 if (BlockIo2) { 256 PrivateData->CapsuleData[PrivateData->CapsuleCount].BlockIo2 = BlockIo2Ppi; 257 } else { 258 PrivateData->CapsuleData[PrivateData->CapsuleCount].BlockIo = BlockIoPpi; 259 } 260 Status = FindRecoveryCapsules (PrivateData); 261 DEBUG ((EFI_D_INFO, "Status is %d\n", Status)); 262 263 if (EFI_ERROR (Status)) { 264 continue; 265 } 266 267 PrivateData->CapsuleCount++; 268 } 269 270 } 271 272 return EFI_SUCCESS; 273 } 274 275 /** 276 Finds out the recovery capsule in the current volume. 277 278 @param PrivateData The private data structure that contains recovery module information. 279 280 @retval EFI_SUCCESS The recovery capsule is successfully found in the volume. 281 @retval EFI_NOT_FOUND The recovery capsule is not found in the volume. 282 283 **/ 284 EFI_STATUS 285 EFIAPI 286 FindRecoveryCapsules ( 287 IN OUT PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData 288 ) 289 { 290 EFI_STATUS Status; 291 UINTN Lba; 292 EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi; 293 EFI_PEI_RECOVERY_BLOCK_IO2_PPI *BlockIo2Ppi; 294 UINTN BufferSize; 295 UINT8 *Buffer; 296 UINT8 Type; 297 UINT8 *StandardID; 298 UINT32 RootDirLBA; 299 PEI_CD_EXPRESS_DIR_FILE_RECORD *RoorDirRecord; 300 UINTN VolumeSpaceSize; 301 BOOLEAN StartOfVolume; 302 UINTN OriginalLBA; 303 UINTN IndexBlockDevice; 304 305 Buffer = PrivateData->BlockBuffer; 306 BufferSize = PEI_CD_BLOCK_SIZE; 307 308 Lba = 16; 309 // 310 // The volume descriptor starts on Lba 16 311 // 312 IndexBlockDevice = PrivateData->CapsuleData[PrivateData->CapsuleCount].IndexBlock; 313 BlockIoPpi = PrivateData->CapsuleData[PrivateData->CapsuleCount].BlockIo; 314 BlockIo2Ppi = PrivateData->CapsuleData[PrivateData->CapsuleCount].BlockIo2; 315 316 VolumeSpaceSize = 0; 317 StartOfVolume = TRUE; 318 OriginalLBA = 16; 319 320 while (TRUE) { 321 SetMem (Buffer, BufferSize, 0); 322 if (BlockIo2Ppi != NULL) { 323 Status = BlockIo2Ppi->ReadBlocks ( 324 (EFI_PEI_SERVICES **) GetPeiServicesTablePointer (), 325 BlockIo2Ppi, 326 IndexBlockDevice, 327 Lba, 328 BufferSize, 329 Buffer 330 ); 331 } else { 332 Status = BlockIoPpi->ReadBlocks ( 333 (EFI_PEI_SERVICES **) GetPeiServicesTablePointer (), 334 BlockIoPpi, 335 IndexBlockDevice, 336 Lba, 337 BufferSize, 338 Buffer 339 ); 340 } 341 if (EFI_ERROR (Status)) { 342 return Status; 343 } 344 345 StandardID = (UINT8 *) (Buffer + PEI_CD_EXPRESS_STANDARD_ID_OFFSET); 346 if (!StringCmp (StandardID, (UINT8 *) PEI_CD_STANDARD_ID, PEI_CD_EXPRESS_STANDARD_ID_SIZE, TRUE)) { 347 break; 348 } 349 350 if (StartOfVolume) { 351 OriginalLBA = Lba; 352 StartOfVolume = FALSE; 353 } 354 355 Type = *(UINT8 *) (Buffer + PEI_CD_EXPRESS_VOLUME_TYPE_OFFSET); 356 if (Type == PEI_CD_EXPRESS_VOLUME_TYPE_TERMINATOR) { 357 if (VolumeSpaceSize == 0) { 358 break; 359 } else { 360 Lba = (OriginalLBA + VolumeSpaceSize); 361 VolumeSpaceSize = 0; 362 StartOfVolume = TRUE; 363 continue; 364 } 365 } 366 367 if (Type != PEI_CD_EXPRESS_VOLUME_TYPE_PRIMARY) { 368 Lba++; 369 continue; 370 } 371 372 VolumeSpaceSize = *(UINT32 *) (Buffer + PEI_CD_EXPRESS_VOLUME_SPACE_OFFSET); 373 374 RoorDirRecord = (PEI_CD_EXPRESS_DIR_FILE_RECORD *) (Buffer + PEI_CD_EXPRESS_ROOT_DIR_RECORD_OFFSET); 375 RootDirLBA = RoorDirRecord->LocationOfExtent[0]; 376 377 Status = RetrieveCapsuleFileFromRoot (PrivateData, BlockIoPpi, BlockIo2Ppi, IndexBlockDevice, RootDirLBA); 378 if (!EFI_ERROR (Status)) { 379 // 380 // Just look for the first primary descriptor 381 // 382 return EFI_SUCCESS; 383 } 384 385 Lba++; 386 } 387 388 return EFI_NOT_FOUND; 389 } 390 391 /** 392 Retrieves the recovery capsule in root directory of the current volume. 393 394 @param PrivateData The private data structure that contains recovery module information. 395 @param BlockIoPpi The Block IO PPI used to access the volume. 396 @param BlockIo2Ppi The Block IO 2 PPI used to access the volume. 397 @param IndexBlockDevice The index of current block device. 398 @param Lba The starting logic block address to retrieve capsule. 399 400 @retval EFI_SUCCESS The recovery capsule is successfully found in the volume. 401 @retval EFI_NOT_FOUND The recovery capsule is not found in the volume. 402 @retval Others 403 404 **/ 405 EFI_STATUS 406 EFIAPI 407 RetrieveCapsuleFileFromRoot ( 408 IN OUT PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData, 409 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi, 410 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *BlockIo2Ppi, 411 IN UINTN IndexBlockDevice, 412 IN UINT32 Lba 413 ) 414 { 415 EFI_STATUS Status; 416 UINTN BufferSize; 417 UINT8 *Buffer; 418 PEI_CD_EXPRESS_DIR_FILE_RECORD *FileRecord; 419 UINTN Index; 420 421 Buffer = PrivateData->BlockBuffer; 422 BufferSize = PEI_CD_BLOCK_SIZE; 423 424 SetMem (Buffer, BufferSize, 0); 425 426 if (BlockIo2Ppi != NULL) { 427 Status = BlockIo2Ppi->ReadBlocks ( 428 (EFI_PEI_SERVICES **) GetPeiServicesTablePointer (), 429 BlockIo2Ppi, 430 IndexBlockDevice, 431 Lba, 432 BufferSize, 433 Buffer 434 ); 435 } else { 436 Status = BlockIoPpi->ReadBlocks ( 437 (EFI_PEI_SERVICES **) GetPeiServicesTablePointer (), 438 BlockIoPpi, 439 IndexBlockDevice, 440 Lba, 441 BufferSize, 442 Buffer 443 ); 444 } 445 if (EFI_ERROR (Status)) { 446 return Status; 447 } 448 449 while (1) { 450 FileRecord = (PEI_CD_EXPRESS_DIR_FILE_RECORD *) Buffer; 451 452 if (FileRecord->Length == 0) { 453 break; 454 } 455 // 456 // Not intend to check other flag now 457 // 458 if ((FileRecord->Flag & PEI_CD_EXPRESS_DIR_FILE_REC_FLAG_ISDIR) != 0) { 459 Buffer += FileRecord->Length; 460 continue; 461 } 462 463 for (Index = 0; Index < FileRecord->FileIDLength; Index++) { 464 if (FileRecord->FileID[Index] == ';') { 465 break; 466 } 467 } 468 469 if (Index != (sizeof (PEI_RECOVERY_FILE_NAME) - 1)) { 470 Buffer += FileRecord->Length; 471 continue; 472 } 473 474 if (!StringCmp (FileRecord->FileID, (UINT8 *) PEI_RECOVERY_FILE_NAME, sizeof (PEI_RECOVERY_FILE_NAME) - 1, FALSE)) { 475 Buffer += FileRecord->Length; 476 continue; 477 } 478 479 PrivateData->CapsuleData[PrivateData->CapsuleCount].CapsuleStartLBA = FileRecord->LocationOfExtent[0]; 480 PrivateData->CapsuleData[PrivateData->CapsuleCount].CapsuleSize = 481 ( 482 FileRecord->DataLength[0] / 483 PEI_CD_BLOCK_SIZE + 484 1 485 ) * 486 PEI_CD_BLOCK_SIZE; 487 488 return EFI_SUCCESS; 489 } 490 491 return EFI_NOT_FOUND; 492 } 493 494 /** 495 Returns the number of DXE capsules residing on the device. 496 497 This function searches for DXE capsules from the associated device and returns 498 the number and maximum size in bytes of the capsules discovered. Entry 1 is 499 assumed to be the highest load priority and entry N is assumed to be the lowest 500 priority. 501 502 @param[in] PeiServices General-purpose services that are available 503 to every PEIM 504 @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI 505 instance. 506 @param[out] NumberRecoveryCapsules Pointer to a caller-allocated UINTN. On 507 output, *NumberRecoveryCapsules contains 508 the number of recovery capsule images 509 available for retrieval from this PEIM 510 instance. 511 512 @retval EFI_SUCCESS One or more capsules were discovered. 513 @retval EFI_DEVICE_ERROR A device error occurred. 514 @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found. 515 516 **/ 517 EFI_STATUS 518 EFIAPI 519 GetNumberRecoveryCapsules ( 520 IN EFI_PEI_SERVICES **PeiServices, 521 IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This, 522 OUT UINTN *NumberRecoveryCapsules 523 ) 524 { 525 PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData; 526 527 PrivateData = PEI_CD_EXPRESS_PRIVATE_DATA_FROM_THIS (This); 528 UpdateBlocksAndVolumes (PrivateData, TRUE); 529 UpdateBlocksAndVolumes (PrivateData, FALSE); 530 *NumberRecoveryCapsules = PrivateData->CapsuleCount; 531 532 if (*NumberRecoveryCapsules == 0) { 533 return EFI_NOT_FOUND; 534 } 535 536 return EFI_SUCCESS; 537 } 538 539 /** 540 Returns the size and type of the requested recovery capsule. 541 542 This function gets the size and type of the capsule specified by CapsuleInstance. 543 544 @param[in] PeiServices General-purpose services that are available to every PEIM 545 @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI 546 instance. 547 @param[in] CapsuleInstance Specifies for which capsule instance to retrieve 548 the information. This parameter must be between 549 one and the value returned by GetNumberRecoveryCapsules() 550 in NumberRecoveryCapsules. 551 @param[out] Size A pointer to a caller-allocated UINTN in which 552 the size of the requested recovery module is 553 returned. 554 @param[out] CapsuleType A pointer to a caller-allocated EFI_GUID in which 555 the type of the requested recovery capsule is 556 returned. The semantic meaning of the value 557 returned is defined by the implementation. 558 559 @retval EFI_SUCCESS One or more capsules were discovered. 560 @retval EFI_DEVICE_ERROR A device error occurred. 561 @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found. 562 563 **/ 564 EFI_STATUS 565 EFIAPI 566 GetRecoveryCapsuleInfo ( 567 IN EFI_PEI_SERVICES **PeiServices, 568 IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This, 569 IN UINTN CapsuleInstance, 570 OUT UINTN *Size, 571 OUT EFI_GUID *CapsuleType 572 ) 573 { 574 PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData; 575 UINTN NumberRecoveryCapsules; 576 EFI_STATUS Status; 577 578 Status = GetNumberRecoveryCapsules (PeiServices, This, &NumberRecoveryCapsules); 579 580 if (EFI_ERROR (Status)) { 581 return Status; 582 } 583 584 if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) { 585 CapsuleInstance = CapsuleInstance + 1; 586 } 587 588 if ((CapsuleInstance == 0) || (CapsuleInstance > NumberRecoveryCapsules)) { 589 return EFI_NOT_FOUND; 590 } 591 592 PrivateData = PEI_CD_EXPRESS_PRIVATE_DATA_FROM_THIS (This); 593 594 *Size = PrivateData->CapsuleData[CapsuleInstance - 1].CapsuleSize; 595 CopyMem ( 596 CapsuleType, 597 &gRecoveryOnDataCdGuid, 598 sizeof (EFI_GUID) 599 ); 600 601 return EFI_SUCCESS; 602 } 603 604 /** 605 Loads a DXE capsule from some media into memory. 606 607 This function, by whatever mechanism, retrieves a DXE capsule from some device 608 and loads it into memory. Note that the published interface is device neutral. 609 610 @param[in] PeiServices General-purpose services that are available 611 to every PEIM 612 @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI 613 instance. 614 @param[in] CapsuleInstance Specifies which capsule instance to retrieve. 615 @param[out] Buffer Specifies a caller-allocated buffer in which 616 the requested recovery capsule will be returned. 617 618 @retval EFI_SUCCESS The capsule was loaded correctly. 619 @retval EFI_DEVICE_ERROR A device error occurred. 620 @retval EFI_NOT_FOUND A requested recovery DXE capsule cannot be found. 621 622 **/ 623 EFI_STATUS 624 EFIAPI 625 LoadRecoveryCapsule ( 626 IN EFI_PEI_SERVICES **PeiServices, 627 IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This, 628 IN UINTN CapsuleInstance, 629 OUT VOID *Buffer 630 ) 631 { 632 EFI_STATUS Status; 633 PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData; 634 EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi; 635 EFI_PEI_RECOVERY_BLOCK_IO2_PPI *BlockIo2Ppi; 636 UINTN NumberRecoveryCapsules; 637 638 Status = GetNumberRecoveryCapsules (PeiServices, This, &NumberRecoveryCapsules); 639 640 if (EFI_ERROR (Status)) { 641 return Status; 642 } 643 644 if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) { 645 CapsuleInstance = CapsuleInstance + 1; 646 } 647 648 if ((CapsuleInstance == 0) || (CapsuleInstance > NumberRecoveryCapsules)) { 649 return EFI_NOT_FOUND; 650 } 651 652 PrivateData = PEI_CD_EXPRESS_PRIVATE_DATA_FROM_THIS (This); 653 BlockIoPpi = PrivateData->CapsuleData[CapsuleInstance - 1].BlockIo; 654 BlockIo2Ppi = PrivateData->CapsuleData[CapsuleInstance - 1].BlockIo2; 655 656 if (BlockIo2Ppi != NULL) { 657 Status = BlockIo2Ppi->ReadBlocks ( 658 PeiServices, 659 BlockIo2Ppi, 660 PrivateData->CapsuleData[CapsuleInstance - 1].IndexBlock, 661 PrivateData->CapsuleData[CapsuleInstance - 1].CapsuleStartLBA, 662 PrivateData->CapsuleData[CapsuleInstance - 1].CapsuleSize, 663 Buffer 664 ); 665 } else { 666 Status = BlockIoPpi->ReadBlocks ( 667 PeiServices, 668 BlockIoPpi, 669 PrivateData->CapsuleData[CapsuleInstance - 1].IndexBlock, 670 PrivateData->CapsuleData[CapsuleInstance - 1].CapsuleStartLBA, 671 PrivateData->CapsuleData[CapsuleInstance - 1].CapsuleSize, 672 Buffer 673 ); 674 } 675 return Status; 676 } 677 678 /** 679 This function compares two ASCII strings in case sensitive/insensitive way. 680 681 @param Source1 The first string. 682 @param Source2 The second string. 683 @param Size The maximum comparison length. 684 @param CaseSensitive Flag to indicate whether the comparison is case sensitive. 685 686 @retval TRUE The two strings are the same. 687 @retval FALSE The two string are not the same. 688 689 **/ 690 BOOLEAN 691 StringCmp ( 692 IN UINT8 *Source1, 693 IN UINT8 *Source2, 694 IN UINTN Size, 695 IN BOOLEAN CaseSensitive 696 ) 697 { 698 UINTN Index; 699 UINT8 Dif; 700 701 for (Index = 0; Index < Size; Index++) { 702 if (Source1[Index] == Source2[Index]) { 703 continue; 704 } 705 706 if (!CaseSensitive) { 707 Dif = (UINT8) ((Source1[Index] > Source2[Index]) ? (Source1[Index] - Source2[Index]) : (Source2[Index] - Source1[Index])); 708 if (Dif == ('a' - 'A')) { 709 continue; 710 } 711 } 712 713 return FALSE; 714 } 715 716 return TRUE; 717 } 718