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
UpdateBlocksAndVolumes(IN OUT PEI_FAT_PRIVATE_DATA * PrivateData,IN BOOLEAN BlockIo2)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
BlockIoNotifyEntry(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_NOTIFY_DESCRIPTOR * NotifyDescriptor,IN VOID * Ppi)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
FatPeimEntry(IN EFI_PEI_FILE_HANDLE FileHandle,IN CONST EFI_PEI_SERVICES ** PeiServices)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
GetNumberRecoveryCapsules(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI * This,OUT UINTN * NumberRecoveryCapsules)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
GetRecoveryCapsuleInfo(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI * This,IN UINTN CapsuleInstance,OUT UINTN * Size,OUT EFI_GUID * CapsuleType)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
LoadRecoveryCapsule(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI * This,IN UINTN CapsuleInstance,OUT VOID * Buffer)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
FindRecoveryFile(IN PEI_FAT_PRIVATE_DATA * PrivateData,IN UINTN VolumeIndex,IN CHAR16 * FileName,OUT PEI_FILE_HANDLE * Handle)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