Home | History | Annotate | Download | only in CdExpressPei
      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