]> git.proxmox.com Git - mirror_edk2.git/blob - FatPkg/FatPei/FatLiteApi.c
b71eaaab2a60051632a6429c8d6a15f8ba07a71a
[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 - 2018, 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 case MSG_NVME_NAMESPACE_DP:
489 CopyGuid (CapsuleType, &gRecoveryOnFatNvmeDiskGuid);
490 break;
491
492 default:
493 break;
494 }
495 }
496 if (PrivateData->BlockDevice[BlockDeviceNo].BlockIo != NULL) {
497 switch (PrivateData->BlockDevice[BlockDeviceNo].DevType) {
498 case LegacyFloppy:
499 CopyGuid (CapsuleType, &gRecoveryOnFatFloppyDiskGuid);
500 break;
501
502 case IdeCDROM:
503 case IdeLS120:
504 CopyGuid (CapsuleType, &gRecoveryOnFatIdeDiskGuid);
505 break;
506
507 case UsbMassStorage:
508 CopyGuid (CapsuleType, &gRecoveryOnFatUsbDiskGuid);
509 break;
510
511 default:
512 break;
513 }
514 }
515 }
516
517 return EFI_SUCCESS;
518 }
519
520 RecoveryCapsuleCount++;
521 }
522
523 return EFI_NOT_FOUND;
524 }
525
526
527 /**
528 Loads a DXE capsule from some media into memory.
529
530 This function, by whatever mechanism, retrieves a DXE capsule from some device
531 and loads it into memory. Note that the published interface is device neutral.
532
533 @param[in] PeiServices General-purpose services that are available
534 to every PEIM
535 @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
536 instance.
537 @param[in] CapsuleInstance Specifies which capsule instance to retrieve.
538 @param[out] Buffer Specifies a caller-allocated buffer in which
539 the requested recovery capsule will be returned.
540
541 @retval EFI_SUCCESS The capsule was loaded correctly.
542 @retval EFI_DEVICE_ERROR A device error occurred.
543 @retval EFI_NOT_FOUND A requested recovery DXE capsule cannot be found.
544
545 **/
546 EFI_STATUS
547 EFIAPI
548 LoadRecoveryCapsule (
549 IN EFI_PEI_SERVICES **PeiServices,
550 IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,
551 IN UINTN CapsuleInstance,
552 OUT VOID *Buffer
553 )
554 {
555 EFI_STATUS Status;
556 PEI_FAT_PRIVATE_DATA *PrivateData;
557 UINTN Index;
558 UINTN RecoveryCapsuleCount;
559 PEI_FILE_HANDLE Handle;
560 UINTN NumberRecoveryCapsules;
561
562 Status = GetNumberRecoveryCapsules (PeiServices, This, &NumberRecoveryCapsules);
563
564 if (EFI_ERROR (Status)) {
565 return Status;
566 }
567
568 if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {
569 CapsuleInstance = CapsuleInstance + 1;
570 }
571
572 if ((CapsuleInstance == 0) || (CapsuleInstance > NumberRecoveryCapsules)) {
573 return EFI_NOT_FOUND;
574 }
575
576 PrivateData = PEI_FAT_PRIVATE_DATA_FROM_THIS (This);
577
578 //
579 // Search each volume in the root directory for the Recovery capsule
580 //
581 RecoveryCapsuleCount = 0;
582 for (Index = 0; Index < PrivateData->VolumeCount; Index++) {
583 Status = FindRecoveryFile (PrivateData, Index, (CHAR16 *)PcdGetPtr(PcdRecoveryFileName), &Handle);
584 if (EFI_ERROR (Status)) {
585 continue;
586 }
587
588 if (CapsuleInstance - 1 == RecoveryCapsuleCount) {
589
590 Status = FatReadFile (
591 PrivateData,
592 Handle,
593 (UINTN) (((PEI_FAT_FILE *) Handle)->FileSize),
594 Buffer
595 );
596 return Status;
597 }
598
599 RecoveryCapsuleCount++;
600 }
601
602 return EFI_NOT_FOUND;
603 }
604
605
606 /**
607 Finds the recovery file on a FAT volume.
608 This function finds the the recovery file named FileName on a specified FAT volume and returns
609 its FileHandle pointer.
610
611 @param PrivateData Global memory map for accessing global
612 variables.
613 @param VolumeIndex The index of the volume.
614 @param FileName The recovery file name to find.
615 @param Handle The output file handle.
616
617 @retval EFI_DEVICE_ERROR Some error occured when operating the FAT
618 volume.
619 @retval EFI_NOT_FOUND The recovery file was not found.
620 @retval EFI_SUCCESS The recovery file was successfully found on the
621 FAT volume.
622
623 **/
624 EFI_STATUS
625 FindRecoveryFile (
626 IN PEI_FAT_PRIVATE_DATA *PrivateData,
627 IN UINTN VolumeIndex,
628 IN CHAR16 *FileName,
629 OUT PEI_FILE_HANDLE *Handle
630 )
631 {
632 EFI_STATUS Status;
633 PEI_FAT_FILE Parent;
634 PEI_FAT_FILE *File;
635
636 File = &PrivateData->File;
637
638 //
639 // VolumeIndex must be less than PEI_FAT_MAX_VOLUME because PrivateData->VolumeCount
640 // cannot be larger than PEI_FAT_MAX_VOLUME when detecting recovery volume.
641 //
642 ASSERT (VolumeIndex < PEI_FAT_MAX_VOLUME);
643
644 //
645 // Construct root directory file
646 //
647 ZeroMem (&Parent, sizeof (PEI_FAT_FILE));
648 Parent.IsFixedRootDir = (BOOLEAN) ((PrivateData->Volume[VolumeIndex].FatType == Fat32) ? FALSE : TRUE);
649 Parent.Attributes = FAT_ATTR_DIRECTORY;
650 Parent.CurrentPos = 0;
651 Parent.CurrentCluster = Parent.IsFixedRootDir ? 0 : PrivateData->Volume[VolumeIndex].RootDirCluster;
652 Parent.StartingCluster = Parent.CurrentCluster;
653 Parent.Volume = &PrivateData->Volume[VolumeIndex];
654
655 Status = FatSetFilePos (PrivateData, &Parent, 0);
656 if (EFI_ERROR (Status)) {
657 return EFI_DEVICE_ERROR;
658 }
659 //
660 // Search for recovery capsule in root directory
661 //
662 Status = FatReadNextDirectoryEntry (PrivateData, &Parent, File);
663 while (Status == EFI_SUCCESS) {
664 //
665 // Compare whether the file name is recovery file name.
666 //
667 if (EngStriColl (PrivateData, FileName, File->FileName)) {
668 break;
669 }
670
671 Status = FatReadNextDirectoryEntry (PrivateData, &Parent, File);
672 }
673
674 if (EFI_ERROR (Status)) {
675 return EFI_NOT_FOUND;
676 }
677
678 //
679 // Get the recovery file, set its file position to 0.
680 //
681 if (File->StartingCluster != 0) {
682 Status = FatSetFilePos (PrivateData, File, 0);
683 }
684
685 *Handle = File;
686
687 return EFI_SUCCESS;
688
689 }