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