Home | History | Annotate | Download | only in FatPei
      1 /** @file
      2   FAT recovery PEIM entry point, Ppi Functions and FAT Api functions.
      3 
      4 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
      5 
      6 This program and the accompanying materials are licensed and made available
      7 under the terms and conditions of the BSD License which accompanies this
      8 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 
     16 #include "FatLitePeim.h"
     17 
     18 PEI_FAT_PRIVATE_DATA  *mPrivateData = NULL;
     19 
     20 /**
     21   BlockIo installation nofication function. Find out all the current BlockIO
     22   PPIs in the system and add them into private data. Assume there is
     23 
     24   @param  PeiServices             General purpose services available to every
     25                                   PEIM.
     26   @param  NotifyDescriptor        The typedef structure of the notification
     27                                   descriptor. Not used in this function.
     28   @param  Ppi                     The typedef structure of the PPI descriptor.
     29                                   Not used in this function.
     30 
     31   @retval EFI_SUCCESS             The function completed successfully.
     32 
     33 **/
     34 EFI_STATUS
     35 EFIAPI
     36 BlockIoNotifyEntry (
     37   IN EFI_PEI_SERVICES           **PeiServices,
     38   IN EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDescriptor,
     39   IN VOID                       *Ppi
     40   );
     41 
     42 
     43 /**
     44   Discover all the block I/O devices to find the FAT volume.
     45 
     46   @param  PrivateData             Global memory map for accessing global
     47                                   variables.
     48   @param  BlockIo2                Boolean to show whether using BlockIo2 or BlockIo
     49 
     50   @retval EFI_SUCCESS             The function completed successfully.
     51 
     52 **/
     53 EFI_STATUS
     54 UpdateBlocksAndVolumes (
     55   IN OUT PEI_FAT_PRIVATE_DATA            *PrivateData,
     56   IN     BOOLEAN                         BlockIo2
     57   )
     58 {
     59   EFI_STATUS                     Status;
     60   EFI_PEI_PPI_DESCRIPTOR         *TempPpiDescriptor;
     61   UINTN                          BlockIoPpiInstance;
     62   EFI_PEI_RECOVERY_BLOCK_IO_PPI  *BlockIoPpi;
     63   EFI_PEI_RECOVERY_BLOCK_IO2_PPI *BlockIo2Ppi;
     64   UINTN                          NumberBlockDevices;
     65   UINTN                          Index;
     66   EFI_PEI_BLOCK_IO_MEDIA         Media;
     67   EFI_PEI_BLOCK_IO2_MEDIA        Media2;
     68   PEI_FAT_VOLUME                 Volume;
     69   EFI_PEI_SERVICES               **PeiServices;
     70 
     71   PeiServices = (EFI_PEI_SERVICES **) GetPeiServicesTablePointer ();
     72   BlockIo2Ppi = NULL;
     73   BlockIoPpi  = NULL;
     74   //
     75   // Clean up caches
     76   //
     77   for (Index = 0; Index < PEI_FAT_CACHE_SIZE; Index++) {
     78     PrivateData->CacheBuffer[Index].Valid = FALSE;
     79   }
     80 
     81   PrivateData->BlockDeviceCount = 0;
     82 
     83   //
     84   // Find out all Block Io Ppi instances within the system
     85   // Assuming all device Block Io Peims are dispatched already
     86   //
     87   for (BlockIoPpiInstance = 0; BlockIoPpiInstance < PEI_FAT_MAX_BLOCK_IO_PPI; BlockIoPpiInstance++) {
     88     if (BlockIo2) {
     89       Status = PeiServicesLocatePpi (
     90                 &gEfiPeiVirtualBlockIo2PpiGuid,
     91                 BlockIoPpiInstance,
     92                 &TempPpiDescriptor,
     93                 (VOID **) &BlockIo2Ppi
     94                 );
     95     } else {
     96       Status = PeiServicesLocatePpi (
     97                 &gEfiPeiVirtualBlockIoPpiGuid,
     98                 BlockIoPpiInstance,
     99                 &TempPpiDescriptor,
    100                 (VOID **) &BlockIoPpi
    101                 );
    102     }
    103     if (EFI_ERROR (Status)) {
    104       //
    105       // Done with all Block Io Ppis
    106       //
    107       break;
    108     }
    109 
    110     if (BlockIo2) {
    111       Status = BlockIo2Ppi->GetNumberOfBlockDevices (
    112                               PeiServices,
    113                               BlockIo2Ppi,
    114                               &NumberBlockDevices
    115                               );
    116     } else {
    117       Status = BlockIoPpi->GetNumberOfBlockDevices (
    118                              PeiServices,
    119                              BlockIoPpi,
    120                              &NumberBlockDevices
    121                              );
    122     }
    123     if (EFI_ERROR (Status)) {
    124       continue;
    125     }
    126 
    127     for (Index = 1; Index <= NumberBlockDevices && PrivateData->BlockDeviceCount < PEI_FAT_MAX_BLOCK_DEVICE; Index++) {
    128 
    129       if (BlockIo2) {
    130         Status = BlockIo2Ppi->GetBlockDeviceMediaInfo (
    131                                 PeiServices,
    132                                 BlockIo2Ppi,
    133                                 Index,
    134                                 &Media2
    135                                 );
    136         if (EFI_ERROR (Status) || !Media2.MediaPresent) {
    137           continue;
    138         }
    139         PrivateData->BlockDevice[PrivateData->BlockDeviceCount].BlockIo2        = BlockIo2Ppi;
    140         PrivateData->BlockDevice[PrivateData->BlockDeviceCount].InterfaceType   = Media2.InterfaceType;
    141         PrivateData->BlockDevice[PrivateData->BlockDeviceCount].LastBlock       = Media2.LastBlock;
    142         PrivateData->BlockDevice[PrivateData->BlockDeviceCount].BlockSize       = Media2.BlockSize;
    143       } else {
    144         Status = BlockIoPpi->GetBlockDeviceMediaInfo (
    145                                PeiServices,
    146                                BlockIoPpi,
    147                                Index,
    148                                &Media
    149                                );
    150         if (EFI_ERROR (Status) || !Media.MediaPresent) {
    151           continue;
    152         }
    153         PrivateData->BlockDevice[PrivateData->BlockDeviceCount].BlockIo    = BlockIoPpi;
    154         PrivateData->BlockDevice[PrivateData->BlockDeviceCount].DevType    = Media.DeviceType;
    155         PrivateData->BlockDevice[PrivateData->BlockDeviceCount].LastBlock  = Media.LastBlock;
    156         PrivateData->BlockDevice[PrivateData->BlockDeviceCount].BlockSize  = (UINT32) Media.BlockSize;
    157       }
    158 
    159       PrivateData->BlockDevice[PrivateData->BlockDeviceCount].IoAlign = 0;
    160       //
    161       // Not used here
    162       //
    163       PrivateData->BlockDevice[PrivateData->BlockDeviceCount].Logical           = FALSE;
    164       PrivateData->BlockDevice[PrivateData->BlockDeviceCount].PartitionChecked  = FALSE;
    165 
    166       PrivateData->BlockDevice[PrivateData->BlockDeviceCount].PhysicalDevNo     = (UINT8) Index;
    167       PrivateData->BlockDeviceCount++;
    168     }
    169   }
    170   //
    171   // Find out all logical devices
    172   //
    173   FatFindPartitions (PrivateData);
    174 
    175   //
    176   // Build up file system volume array
    177   //
    178   PrivateData->VolumeCount = 0;
    179   for (Index = 0; Index < PrivateData->BlockDeviceCount; Index++) {
    180     Volume.BlockDeviceNo  = Index;
    181     Status                = FatGetBpbInfo (PrivateData, &Volume);
    182     if (Status == EFI_SUCCESS) {
    183       //
    184       // Add the detected volume to the volume array
    185       //
    186       CopyMem (
    187         (UINT8 *) &(PrivateData->Volume[PrivateData->VolumeCount]),
    188         (UINT8 *) &Volume,
    189         sizeof (PEI_FAT_VOLUME)
    190         );
    191       PrivateData->VolumeCount += 1;
    192       if (PrivateData->VolumeCount >= PEI_FAT_MAX_VOLUME) {
    193         break;
    194       }
    195     }
    196   }
    197 
    198   return EFI_SUCCESS;
    199 }
    200 
    201 
    202 /**
    203   BlockIo installation notification function. Find out all the current BlockIO
    204   PPIs in the system and add them into private data. Assume there is
    205 
    206   @param  PeiServices             General purpose services available to every
    207                                   PEIM.
    208   @param  NotifyDescriptor        The typedef structure of the notification
    209                                   descriptor. Not used in this function.
    210   @param  Ppi                     The typedef structure of the PPI descriptor.
    211                                   Not used in this function.
    212 
    213   @retval EFI_SUCCESS             The function completed successfully.
    214 
    215 **/
    216 EFI_STATUS
    217 EFIAPI
    218 BlockIoNotifyEntry (
    219   IN EFI_PEI_SERVICES           **PeiServices,
    220   IN EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDescriptor,
    221   IN VOID                       *Ppi
    222   )
    223 {
    224   if (CompareGuid (NotifyDescriptor->Guid, &gEfiPeiVirtualBlockIo2PpiGuid)) {
    225     UpdateBlocksAndVolumes (mPrivateData, TRUE);
    226   } else {
    227     UpdateBlocksAndVolumes (mPrivateData, FALSE);
    228   }
    229   return EFI_SUCCESS;
    230 }
    231 
    232 
    233 /**
    234   Installs the Device Recovery Module PPI, Initialize BlockIo Ppi
    235   installation notification
    236 
    237   @param  FileHandle              Handle of the file being invoked. Type
    238                                   EFI_PEI_FILE_HANDLE is defined in
    239                                   FfsFindNextFile().
    240   @param  PeiServices             Describes the list of possible PEI Services.
    241 
    242   @retval EFI_SUCCESS             The entry point was executed successfully.
    243   @retval EFI_OUT_OF_RESOURCES    There is no enough memory to complete the
    244                                   operations.
    245 
    246 **/
    247 EFI_STATUS
    248 EFIAPI
    249 FatPeimEntry (
    250   IN EFI_PEI_FILE_HANDLE       FileHandle,
    251   IN CONST EFI_PEI_SERVICES    **PeiServices
    252   )
    253 {
    254   EFI_STATUS            Status;
    255   EFI_PHYSICAL_ADDRESS  Address;
    256   PEI_FAT_PRIVATE_DATA  *PrivateData;
    257 
    258   Status = PeiServicesRegisterForShadow (FileHandle);
    259   if (!EFI_ERROR (Status)) {
    260     return Status;
    261   }
    262 
    263   Status = PeiServicesAllocatePages (
    264             EfiBootServicesCode,
    265             (sizeof (PEI_FAT_PRIVATE_DATA) - 1) / PEI_FAT_MEMMORY_PAGE_SIZE + 1,
    266             &Address
    267             );
    268   if (EFI_ERROR (Status)) {
    269     return EFI_OUT_OF_RESOURCES;
    270   }
    271 
    272   PrivateData = (PEI_FAT_PRIVATE_DATA *) (UINTN) Address;
    273 
    274   //
    275   // Initialize Private Data (to zero, as is required by subsequent operations)
    276   //
    277   ZeroMem ((UINT8 *) PrivateData, sizeof (PEI_FAT_PRIVATE_DATA));
    278 
    279   PrivateData->Signature = PEI_FAT_PRIVATE_DATA_SIGNATURE;
    280 
    281   //
    282   // Installs Ppi
    283   //
    284   PrivateData->DeviceRecoveryPpi.GetNumberRecoveryCapsules  = GetNumberRecoveryCapsules;
    285   PrivateData->DeviceRecoveryPpi.GetRecoveryCapsuleInfo     = GetRecoveryCapsuleInfo;
    286   PrivateData->DeviceRecoveryPpi.LoadRecoveryCapsule        = LoadRecoveryCapsule;
    287 
    288   PrivateData->PpiDescriptor.Flags                          = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
    289   PrivateData->PpiDescriptor.Guid = &gEfiPeiDeviceRecoveryModulePpiGuid;
    290   PrivateData->PpiDescriptor.Ppi  = &PrivateData->DeviceRecoveryPpi;
    291 
    292   Status = PeiServicesInstallPpi (&PrivateData->PpiDescriptor);
    293   if (EFI_ERROR (Status)) {
    294     return EFI_OUT_OF_RESOURCES;
    295   }
    296   //
    297   // Other initializations
    298   //
    299   PrivateData->BlockDeviceCount = 0;
    300 
    301   UpdateBlocksAndVolumes (PrivateData, TRUE);
    302   UpdateBlocksAndVolumes (PrivateData, FALSE);
    303 
    304   //
    305   // PrivateData is allocated now, set it to the module variable
    306   //
    307   mPrivateData = PrivateData;
    308 
    309   //
    310   // Installs Block Io Ppi notification function
    311   //
    312   PrivateData->NotifyDescriptor[0].Flags =
    313     (
    314       EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
    315     );
    316   PrivateData->NotifyDescriptor[0].Guid    = &gEfiPeiVirtualBlockIoPpiGuid;
    317   PrivateData->NotifyDescriptor[0].Notify  = BlockIoNotifyEntry;
    318   PrivateData->NotifyDescriptor[1].Flags  =
    319     (
    320       EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK |
    321       EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
    322     );
    323   PrivateData->NotifyDescriptor[1].Guid    = &gEfiPeiVirtualBlockIo2PpiGuid;
    324   PrivateData->NotifyDescriptor[1].Notify  = BlockIoNotifyEntry;
    325   return PeiServicesNotifyPpi (&PrivateData->NotifyDescriptor[0]);
    326 }
    327 
    328 
    329 /**
    330   Returns the number of DXE capsules residing on the device.
    331 
    332   This function searches for DXE capsules from the associated device and returns
    333   the number and maximum size in bytes of the capsules discovered. Entry 1 is
    334   assumed to be the highest load priority and entry N is assumed to be the lowest
    335   priority.
    336 
    337   @param[in]  PeiServices              General-purpose services that are available
    338                                        to every PEIM
    339   @param[in]  This                     Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
    340                                        instance.
    341   @param[out] NumberRecoveryCapsules   Pointer to a caller-allocated UINTN. On
    342                                        output, *NumberRecoveryCapsules contains
    343                                        the number of recovery capsule images
    344                                        available for retrieval from this PEIM
    345                                        instance.
    346 
    347   @retval EFI_SUCCESS        One or more capsules were discovered.
    348   @retval EFI_DEVICE_ERROR   A device error occurred.
    349   @retval EFI_NOT_FOUND      A recovery DXE capsule cannot be found.
    350 
    351 **/
    352 EFI_STATUS
    353 EFIAPI
    354 GetNumberRecoveryCapsules (
    355   IN EFI_PEI_SERVICES                               **PeiServices,
    356   IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI             *This,
    357   OUT UINTN                                         *NumberRecoveryCapsules
    358   )
    359 {
    360   EFI_STATUS            Status;
    361   PEI_FAT_PRIVATE_DATA  *PrivateData;
    362   UINTN                 Index;
    363   UINTN                 RecoveryCapsuleCount;
    364   PEI_FILE_HANDLE       Handle;
    365 
    366   PrivateData = PEI_FAT_PRIVATE_DATA_FROM_THIS (This);
    367 
    368   //
    369   // Search each volume in the root directory for the Recovery capsule
    370   //
    371   RecoveryCapsuleCount = 0;
    372   for (Index = 0; Index < PrivateData->VolumeCount; Index++) {
    373     Status = FindRecoveryFile (PrivateData, Index, (CHAR16 *)PcdGetPtr(PcdRecoveryFileName), &Handle);
    374     if (EFI_ERROR (Status)) {
    375       continue;
    376     }
    377 
    378     RecoveryCapsuleCount++;
    379   }
    380 
    381   *NumberRecoveryCapsules = RecoveryCapsuleCount;
    382 
    383   if (*NumberRecoveryCapsules == 0) {
    384     return EFI_NOT_FOUND;
    385   }
    386 
    387   return EFI_SUCCESS;
    388 }
    389 
    390 
    391 /**
    392   Returns the size and type of the requested recovery capsule.
    393 
    394   This function gets the size and type of the capsule specified by CapsuleInstance.
    395 
    396   @param[in]  PeiServices       General-purpose services that are available to every PEIM
    397   @param[in]  This              Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
    398                                 instance.
    399   @param[in]  CapsuleInstance   Specifies for which capsule instance to retrieve
    400                                 the information.  This parameter must be between
    401                                 one and the value returned by GetNumberRecoveryCapsules()
    402                                 in NumberRecoveryCapsules.
    403   @param[out] Size              A pointer to a caller-allocated UINTN in which
    404                                 the size of the requested recovery module is
    405                                 returned.
    406   @param[out] CapsuleType       A pointer to a caller-allocated EFI_GUID in which
    407                                 the type of the requested recovery capsule is
    408                                 returned.  The semantic meaning of the value
    409                                 returned is defined by the implementation.
    410 
    411   @retval EFI_SUCCESS        One or more capsules were discovered.
    412   @retval EFI_DEVICE_ERROR   A device error occurred.
    413   @retval EFI_NOT_FOUND      A recovery DXE capsule cannot be found.
    414 
    415 **/
    416 EFI_STATUS
    417 EFIAPI
    418 GetRecoveryCapsuleInfo (
    419   IN  EFI_PEI_SERVICES                              **PeiServices,
    420   IN  EFI_PEI_DEVICE_RECOVERY_MODULE_PPI            *This,
    421   IN  UINTN                                         CapsuleInstance,
    422   OUT UINTN                                         *Size,
    423   OUT EFI_GUID                                      *CapsuleType
    424   )
    425 {
    426   EFI_STATUS            Status;
    427   PEI_FAT_PRIVATE_DATA  *PrivateData;
    428   UINTN                 Index;
    429   UINTN                 BlockDeviceNo;
    430   UINTN                 RecoveryCapsuleCount;
    431   PEI_FILE_HANDLE       Handle;
    432   UINTN                 NumberRecoveryCapsules;
    433 
    434   Status = GetNumberRecoveryCapsules (PeiServices, This, &NumberRecoveryCapsules);
    435 
    436   if (EFI_ERROR (Status)) {
    437     return Status;
    438   }
    439 
    440   if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {
    441     CapsuleInstance = CapsuleInstance + 1;
    442   }
    443 
    444   if ((CapsuleInstance == 0) || (CapsuleInstance > NumberRecoveryCapsules)) {
    445     return EFI_NOT_FOUND;
    446   }
    447 
    448   PrivateData = PEI_FAT_PRIVATE_DATA_FROM_THIS (This);
    449 
    450   //
    451   // Search each volume in the root directory for the Recovery capsule
    452   //
    453   RecoveryCapsuleCount = 0;
    454   for (Index = 0; Index < PrivateData->VolumeCount; Index++) {
    455     Status = FindRecoveryFile (PrivateData, Index, (CHAR16 *)PcdGetPtr(PcdRecoveryFileName), &Handle);
    456 
    457     if (EFI_ERROR (Status)) {
    458       continue;
    459     }
    460 
    461     if (CapsuleInstance - 1 == RecoveryCapsuleCount) {
    462       //
    463       // Get file size
    464       //
    465       *Size = (UINTN) (((PEI_FAT_FILE *) Handle)->FileSize);
    466 
    467       //
    468       // Find corresponding physical block device
    469       //
    470       BlockDeviceNo = PrivateData->Volume[Index].BlockDeviceNo;
    471       while (PrivateData->BlockDevice[BlockDeviceNo].Logical && BlockDeviceNo < PrivateData->BlockDeviceCount) {
    472         BlockDeviceNo = PrivateData->BlockDevice[BlockDeviceNo].ParentDevNo;
    473       }
    474       //
    475       // Fill in the Capsule Type GUID according to the block device type
    476       //
    477       if (BlockDeviceNo < PrivateData->BlockDeviceCount) {
    478         if (PrivateData->BlockDevice[BlockDeviceNo].BlockIo2 != NULL) {
    479           switch (PrivateData->BlockDevice[BlockDeviceNo].InterfaceType) {
    480           case MSG_ATAPI_DP:
    481             CopyGuid (CapsuleType, &gRecoveryOnFatIdeDiskGuid);
    482             break;
    483 
    484           case MSG_USB_DP:
    485             CopyGuid (CapsuleType, &gRecoveryOnFatUsbDiskGuid);
    486             break;
    487 
    488           default:
    489             break;
    490           }
    491         }
    492         if (PrivateData->BlockDevice[BlockDeviceNo].BlockIo != NULL) {
    493           switch (PrivateData->BlockDevice[BlockDeviceNo].DevType) {
    494           case LegacyFloppy:
    495             CopyGuid (CapsuleType, &gRecoveryOnFatFloppyDiskGuid);
    496             break;
    497 
    498           case IdeCDROM:
    499           case IdeLS120:
    500             CopyGuid (CapsuleType, &gRecoveryOnFatIdeDiskGuid);
    501             break;
    502 
    503           case UsbMassStorage:
    504             CopyGuid (CapsuleType, &gRecoveryOnFatUsbDiskGuid);
    505             break;
    506 
    507           default:
    508             break;
    509           }
    510         }
    511       }
    512 
    513       return EFI_SUCCESS;
    514     }
    515 
    516     RecoveryCapsuleCount++;
    517   }
    518 
    519   return EFI_NOT_FOUND;
    520 }
    521 
    522 
    523 /**
    524   Loads a DXE capsule from some media into memory.
    525 
    526   This function, by whatever mechanism, retrieves a DXE capsule from some device
    527   and loads it into memory. Note that the published interface is device neutral.
    528 
    529   @param[in]     PeiServices       General-purpose services that are available
    530                                    to every PEIM
    531   @param[in]     This              Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
    532                                    instance.
    533   @param[in]     CapsuleInstance   Specifies which capsule instance to retrieve.
    534   @param[out]    Buffer            Specifies a caller-allocated buffer in which
    535                                    the requested recovery capsule will be returned.
    536 
    537   @retval EFI_SUCCESS        The capsule was loaded correctly.
    538   @retval EFI_DEVICE_ERROR   A device error occurred.
    539   @retval EFI_NOT_FOUND      A requested recovery DXE capsule cannot be found.
    540 
    541 **/
    542 EFI_STATUS
    543 EFIAPI
    544 LoadRecoveryCapsule (
    545   IN EFI_PEI_SERVICES                             **PeiServices,
    546   IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI           *This,
    547   IN UINTN                                        CapsuleInstance,
    548   OUT VOID                                        *Buffer
    549   )
    550 {
    551   EFI_STATUS            Status;
    552   PEI_FAT_PRIVATE_DATA  *PrivateData;
    553   UINTN                 Index;
    554   UINTN                 RecoveryCapsuleCount;
    555   PEI_FILE_HANDLE       Handle;
    556   UINTN                 NumberRecoveryCapsules;
    557 
    558   Status = GetNumberRecoveryCapsules (PeiServices, This, &NumberRecoveryCapsules);
    559 
    560   if (EFI_ERROR (Status)) {
    561     return Status;
    562   }
    563 
    564   if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {
    565     CapsuleInstance = CapsuleInstance + 1;
    566   }
    567 
    568   if ((CapsuleInstance == 0) || (CapsuleInstance > NumberRecoveryCapsules)) {
    569     return EFI_NOT_FOUND;
    570   }
    571 
    572   PrivateData = PEI_FAT_PRIVATE_DATA_FROM_THIS (This);
    573 
    574   //
    575   // Search each volume in the root directory for the Recovery capsule
    576   //
    577   RecoveryCapsuleCount = 0;
    578   for (Index = 0; Index < PrivateData->VolumeCount; Index++) {
    579     Status = FindRecoveryFile (PrivateData, Index, (CHAR16 *)PcdGetPtr(PcdRecoveryFileName), &Handle);
    580     if (EFI_ERROR (Status)) {
    581       continue;
    582     }
    583 
    584     if (CapsuleInstance - 1 == RecoveryCapsuleCount) {
    585 
    586       Status = FatReadFile (
    587                 PrivateData,
    588                 Handle,
    589                 (UINTN) (((PEI_FAT_FILE *) Handle)->FileSize),
    590                 Buffer
    591                 );
    592       return Status;
    593     }
    594 
    595     RecoveryCapsuleCount++;
    596   }
    597 
    598   return EFI_NOT_FOUND;
    599 }
    600 
    601 
    602 /**
    603   Finds the recovery file on a FAT volume.
    604   This function finds the the recovery file named FileName on a specified FAT volume and returns
    605   its FileHandle pointer.
    606 
    607   @param  PrivateData             Global memory map for accessing global
    608                                   variables.
    609   @param  VolumeIndex             The index of the volume.
    610   @param  FileName                The recovery file name to find.
    611   @param  Handle                  The output file handle.
    612 
    613   @retval EFI_DEVICE_ERROR        Some error occured when operating the FAT
    614                                   volume.
    615   @retval EFI_NOT_FOUND           The recovery file was not found.
    616   @retval EFI_SUCCESS             The recovery file was successfully found on the
    617                                   FAT volume.
    618 
    619 **/
    620 EFI_STATUS
    621 FindRecoveryFile (
    622   IN  PEI_FAT_PRIVATE_DATA  *PrivateData,
    623   IN  UINTN                 VolumeIndex,
    624   IN  CHAR16                *FileName,
    625   OUT PEI_FILE_HANDLE       *Handle
    626   )
    627 {
    628   EFI_STATUS    Status;
    629   PEI_FAT_FILE  Parent;
    630   PEI_FAT_FILE  *File;
    631 
    632   File = &PrivateData->File;
    633 
    634   //
    635   // VolumeIndex must be less than PEI_FAT_MAX_VOLUME because PrivateData->VolumeCount
    636   // cannot be larger than PEI_FAT_MAX_VOLUME when detecting recovery volume.
    637   //
    638   ASSERT (VolumeIndex < PEI_FAT_MAX_VOLUME);
    639 
    640   //
    641   // Construct root directory file
    642   //
    643   ZeroMem (&Parent, sizeof (PEI_FAT_FILE));
    644   Parent.IsFixedRootDir   = (BOOLEAN) ((PrivateData->Volume[VolumeIndex].FatType == Fat32) ? FALSE : TRUE);
    645   Parent.Attributes       = FAT_ATTR_DIRECTORY;
    646   Parent.CurrentPos       = 0;
    647   Parent.CurrentCluster   = Parent.IsFixedRootDir ? 0 : PrivateData->Volume[VolumeIndex].RootDirCluster;
    648   Parent.StartingCluster  = Parent.CurrentCluster;
    649   Parent.Volume           = &PrivateData->Volume[VolumeIndex];
    650 
    651   Status                  = FatSetFilePos (PrivateData, &Parent, 0);
    652   if (EFI_ERROR (Status)) {
    653     return EFI_DEVICE_ERROR;
    654   }
    655   //
    656   // Search for recovery capsule in root directory
    657   //
    658   Status = FatReadNextDirectoryEntry (PrivateData, &Parent, File);
    659   while (Status == EFI_SUCCESS) {
    660     //
    661     // Compare whether the file name is recovery file name.
    662     //
    663     if (EngStriColl (PrivateData, FileName, File->FileName)) {
    664       break;
    665     }
    666 
    667     Status = FatReadNextDirectoryEntry (PrivateData, &Parent, File);
    668   }
    669 
    670   if (EFI_ERROR (Status)) {
    671     return EFI_NOT_FOUND;
    672   }
    673 
    674   //
    675   // Get the recovery file, set its file position to 0.
    676   //
    677   if (File->StartingCluster != 0) {
    678     Status = FatSetFilePos (PrivateData, File, 0);
    679   }
    680 
    681   *Handle = File;
    682 
    683   return EFI_SUCCESS;
    684 
    685 }
    686