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