/** @file | |
FAT recovery PEIM entry point, Ppi Functions and FAT Api functions. | |
Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include "FatLitePeim.h" | |
PEI_FAT_PRIVATE_DATA *mPrivateData = NULL; | |
/** | |
BlockIo installation notification function. Find out all the current BlockIO | |
PPIs in the system and add them into private data. Assume there is | |
@param PeiServices General purpose services available to every | |
PEIM. | |
@param NotifyDescriptor The typedef structure of the notification | |
descriptor. Not used in this function. | |
@param Ppi The typedef structure of the PPI descriptor. | |
Not used in this function. | |
@retval EFI_SUCCESS The function completed successfully. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
BlockIoNotifyEntry ( | |
IN EFI_PEI_SERVICES **PeiServices, | |
IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, | |
IN VOID *Ppi | |
); | |
/** | |
Discover all the block I/O devices to find the FAT volume. | |
@param PrivateData Global memory map for accessing global | |
variables. | |
@param BlockIo2 Boolean to show whether using BlockIo2 or BlockIo | |
@retval EFI_SUCCESS The function completed successfully. | |
**/ | |
EFI_STATUS | |
UpdateBlocksAndVolumes ( | |
IN OUT PEI_FAT_PRIVATE_DATA *PrivateData, | |
IN BOOLEAN BlockIo2 | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_PEI_PPI_DESCRIPTOR *TempPpiDescriptor; | |
UINTN BlockIoPpiInstance; | |
EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi; | |
EFI_PEI_RECOVERY_BLOCK_IO2_PPI *BlockIo2Ppi; | |
UINTN NumberBlockDevices; | |
UINTN Index; | |
EFI_PEI_BLOCK_IO_MEDIA Media; | |
EFI_PEI_BLOCK_IO2_MEDIA Media2; | |
PEI_FAT_VOLUME Volume; | |
EFI_PEI_SERVICES **PeiServices; | |
PeiServices = (EFI_PEI_SERVICES **)GetPeiServicesTablePointer (); | |
BlockIo2Ppi = NULL; | |
BlockIoPpi = NULL; | |
// | |
// Clean up caches | |
// | |
for (Index = 0; Index < PEI_FAT_CACHE_SIZE; Index++) { | |
PrivateData->CacheBuffer[Index].Valid = FALSE; | |
} | |
PrivateData->BlockDeviceCount = 0; | |
// | |
// Find out all Block Io Ppi instances within the system | |
// Assuming all device Block Io Peims are dispatched already | |
// | |
for (BlockIoPpiInstance = 0; BlockIoPpiInstance < PEI_FAT_MAX_BLOCK_IO_PPI; BlockIoPpiInstance++) { | |
if (BlockIo2) { | |
Status = PeiServicesLocatePpi ( | |
&gEfiPeiVirtualBlockIo2PpiGuid, | |
BlockIoPpiInstance, | |
&TempPpiDescriptor, | |
(VOID **)&BlockIo2Ppi | |
); | |
} else { | |
Status = PeiServicesLocatePpi ( | |
&gEfiPeiVirtualBlockIoPpiGuid, | |
BlockIoPpiInstance, | |
&TempPpiDescriptor, | |
(VOID **)&BlockIoPpi | |
); | |
} | |
if (EFI_ERROR (Status)) { | |
// | |
// Done with all Block Io Ppis | |
// | |
break; | |
} | |
if (BlockIo2) { | |
Status = BlockIo2Ppi->GetNumberOfBlockDevices ( | |
PeiServices, | |
BlockIo2Ppi, | |
&NumberBlockDevices | |
); | |
} else { | |
Status = BlockIoPpi->GetNumberOfBlockDevices ( | |
PeiServices, | |
BlockIoPpi, | |
&NumberBlockDevices | |
); | |
} | |
if (EFI_ERROR (Status)) { | |
continue; | |
} | |
for (Index = 1; Index <= NumberBlockDevices && PrivateData->BlockDeviceCount < PEI_FAT_MAX_BLOCK_DEVICE; Index++) { | |
if (BlockIo2) { | |
Status = BlockIo2Ppi->GetBlockDeviceMediaInfo ( | |
PeiServices, | |
BlockIo2Ppi, | |
Index, | |
&Media2 | |
); | |
if (EFI_ERROR (Status) || !Media2.MediaPresent) { | |
continue; | |
} | |
PrivateData->BlockDevice[PrivateData->BlockDeviceCount].BlockIo2 = BlockIo2Ppi; | |
PrivateData->BlockDevice[PrivateData->BlockDeviceCount].InterfaceType = Media2.InterfaceType; | |
PrivateData->BlockDevice[PrivateData->BlockDeviceCount].LastBlock = Media2.LastBlock; | |
PrivateData->BlockDevice[PrivateData->BlockDeviceCount].BlockSize = Media2.BlockSize; | |
} else { | |
Status = BlockIoPpi->GetBlockDeviceMediaInfo ( | |
PeiServices, | |
BlockIoPpi, | |
Index, | |
&Media | |
); | |
if (EFI_ERROR (Status) || !Media.MediaPresent) { | |
continue; | |
} | |
PrivateData->BlockDevice[PrivateData->BlockDeviceCount].BlockIo = BlockIoPpi; | |
PrivateData->BlockDevice[PrivateData->BlockDeviceCount].DevType = Media.DeviceType; | |
PrivateData->BlockDevice[PrivateData->BlockDeviceCount].LastBlock = Media.LastBlock; | |
PrivateData->BlockDevice[PrivateData->BlockDeviceCount].BlockSize = (UINT32)Media.BlockSize; | |
} | |
PrivateData->BlockDevice[PrivateData->BlockDeviceCount].IoAlign = 0; | |
// | |
// Not used here | |
// | |
PrivateData->BlockDevice[PrivateData->BlockDeviceCount].Logical = FALSE; | |
PrivateData->BlockDevice[PrivateData->BlockDeviceCount].PartitionChecked = FALSE; | |
PrivateData->BlockDevice[PrivateData->BlockDeviceCount].PhysicalDevNo = (UINT8)Index; | |
PrivateData->BlockDeviceCount++; | |
} | |
} | |
// | |
// Find out all logical devices | |
// | |
FatFindPartitions (PrivateData); | |
// | |
// Build up file system volume array | |
// | |
PrivateData->VolumeCount = 0; | |
for (Index = 0; Index < PrivateData->BlockDeviceCount; Index++) { | |
Volume.BlockDeviceNo = Index; | |
Status = FatGetBpbInfo (PrivateData, &Volume); | |
if (Status == EFI_SUCCESS) { | |
// | |
// Add the detected volume to the volume array | |
// | |
CopyMem ( | |
(UINT8 *)&(PrivateData->Volume[PrivateData->VolumeCount]), | |
(UINT8 *)&Volume, | |
sizeof (PEI_FAT_VOLUME) | |
); | |
PrivateData->VolumeCount += 1; | |
if (PrivateData->VolumeCount >= PEI_FAT_MAX_VOLUME) { | |
break; | |
} | |
} | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
BlockIo installation notification function. Find out all the current BlockIO | |
PPIs in the system and add them into private data. Assume there is | |
@param PeiServices General purpose services available to every | |
PEIM. | |
@param NotifyDescriptor The typedef structure of the notification | |
descriptor. Not used in this function. | |
@param Ppi The typedef structure of the PPI descriptor. | |
Not used in this function. | |
@retval EFI_SUCCESS The function completed successfully. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
BlockIoNotifyEntry ( | |
IN EFI_PEI_SERVICES **PeiServices, | |
IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, | |
IN VOID *Ppi | |
) | |
{ | |
if (CompareGuid (NotifyDescriptor->Guid, &gEfiPeiVirtualBlockIo2PpiGuid)) { | |
UpdateBlocksAndVolumes (mPrivateData, TRUE); | |
} else { | |
UpdateBlocksAndVolumes (mPrivateData, FALSE); | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
Installs the Device Recovery Module PPI, Initialize BlockIo Ppi | |
installation notification | |
@param FileHandle Handle of the file being invoked. Type | |
EFI_PEI_FILE_HANDLE is defined in | |
FfsFindNextFile(). | |
@param PeiServices Describes the list of possible PEI Services. | |
@retval EFI_SUCCESS The entry point was executed successfully. | |
@retval EFI_OUT_OF_RESOURCES There is no enough memory to complete the | |
operations. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FatPeimEntry ( | |
IN EFI_PEI_FILE_HANDLE FileHandle, | |
IN CONST EFI_PEI_SERVICES **PeiServices | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_PHYSICAL_ADDRESS Address; | |
PEI_FAT_PRIVATE_DATA *PrivateData; | |
Status = PeiServicesRegisterForShadow (FileHandle); | |
if (!EFI_ERROR (Status)) { | |
return Status; | |
} | |
Status = PeiServicesAllocatePages ( | |
EfiBootServicesCode, | |
(sizeof (PEI_FAT_PRIVATE_DATA) - 1) / PEI_FAT_MEMORY_PAGE_SIZE + 1, | |
&Address | |
); | |
if (EFI_ERROR (Status)) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
PrivateData = (PEI_FAT_PRIVATE_DATA *)(UINTN)Address; | |
// | |
// Initialize Private Data (to zero, as is required by subsequent operations) | |
// | |
ZeroMem ((UINT8 *)PrivateData, sizeof (PEI_FAT_PRIVATE_DATA)); | |
PrivateData->Signature = PEI_FAT_PRIVATE_DATA_SIGNATURE; | |
// | |
// Installs Ppi | |
// | |
PrivateData->DeviceRecoveryPpi.GetNumberRecoveryCapsules = GetNumberRecoveryCapsules; | |
PrivateData->DeviceRecoveryPpi.GetRecoveryCapsuleInfo = GetRecoveryCapsuleInfo; | |
PrivateData->DeviceRecoveryPpi.LoadRecoveryCapsule = LoadRecoveryCapsule; | |
PrivateData->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST); | |
PrivateData->PpiDescriptor.Guid = &gEfiPeiDeviceRecoveryModulePpiGuid; | |
PrivateData->PpiDescriptor.Ppi = &PrivateData->DeviceRecoveryPpi; | |
Status = PeiServicesInstallPpi (&PrivateData->PpiDescriptor); | |
if (EFI_ERROR (Status)) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
// | |
// Other initializations | |
// | |
PrivateData->BlockDeviceCount = 0; | |
UpdateBlocksAndVolumes (PrivateData, TRUE); | |
UpdateBlocksAndVolumes (PrivateData, FALSE); | |
// | |
// PrivateData is allocated now, set it to the module variable | |
// | |
mPrivateData = PrivateData; | |
// | |
// Installs Block Io Ppi notification function | |
// | |
PrivateData->NotifyDescriptor[0].Flags = | |
( | |
EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | |
); | |
PrivateData->NotifyDescriptor[0].Guid = &gEfiPeiVirtualBlockIoPpiGuid; | |
PrivateData->NotifyDescriptor[0].Notify = BlockIoNotifyEntry; | |
PrivateData->NotifyDescriptor[1].Flags = | |
( | |
EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | | |
EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST | |
); | |
PrivateData->NotifyDescriptor[1].Guid = &gEfiPeiVirtualBlockIo2PpiGuid; | |
PrivateData->NotifyDescriptor[1].Notify = BlockIoNotifyEntry; | |
return PeiServicesNotifyPpi (&PrivateData->NotifyDescriptor[0]); | |
} | |
/** | |
Returns the number of DXE capsules residing on the device. | |
This function searches for DXE capsules from the associated device and returns | |
the number and maximum size in bytes of the capsules discovered. Entry 1 is | |
assumed to be the highest load priority and entry N is assumed to be the lowest | |
priority. | |
@param[in] PeiServices General-purpose services that are available | |
to every PEIM | |
@param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI | |
instance. | |
@param[out] NumberRecoveryCapsules Pointer to a caller-allocated UINTN. On | |
output, *NumberRecoveryCapsules contains | |
the number of recovery capsule images | |
available for retrieval from this PEIM | |
instance. | |
@retval EFI_SUCCESS One or more capsules were discovered. | |
@retval EFI_DEVICE_ERROR A device error occurred. | |
@retval EFI_NOT_FOUND A recovery DXE capsule cannot be found. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
GetNumberRecoveryCapsules ( | |
IN EFI_PEI_SERVICES **PeiServices, | |
IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This, | |
OUT UINTN *NumberRecoveryCapsules | |
) | |
{ | |
EFI_STATUS Status; | |
PEI_FAT_PRIVATE_DATA *PrivateData; | |
UINTN Index; | |
UINTN RecoveryCapsuleCount; | |
PEI_FILE_HANDLE Handle; | |
PrivateData = PEI_FAT_PRIVATE_DATA_FROM_THIS (This); | |
// | |
// Search each volume in the root directory for the Recovery capsule | |
// | |
RecoveryCapsuleCount = 0; | |
for (Index = 0; Index < PrivateData->VolumeCount; Index++) { | |
Status = FindRecoveryFile (PrivateData, Index, (CHAR16 *)PcdGetPtr (PcdRecoveryFileName), &Handle); | |
if (EFI_ERROR (Status)) { | |
continue; | |
} | |
RecoveryCapsuleCount++; | |
} | |
*NumberRecoveryCapsules = RecoveryCapsuleCount; | |
if (*NumberRecoveryCapsules == 0) { | |
return EFI_NOT_FOUND; | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
Returns the size and type of the requested recovery capsule. | |
This function gets the size and type of the capsule specified by CapsuleInstance. | |
@param[in] PeiServices General-purpose services that are available to every PEIM | |
@param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI | |
instance. | |
@param[in] CapsuleInstance Specifies for which capsule instance to retrieve | |
the information. This parameter must be between | |
one and the value returned by GetNumberRecoveryCapsules() | |
in NumberRecoveryCapsules. | |
@param[out] Size A pointer to a caller-allocated UINTN in which | |
the size of the requested recovery module is | |
returned. | |
@param[out] CapsuleType A pointer to a caller-allocated EFI_GUID in which | |
the type of the requested recovery capsule is | |
returned. The semantic meaning of the value | |
returned is defined by the implementation. | |
@retval EFI_SUCCESS One or more capsules were discovered. | |
@retval EFI_DEVICE_ERROR A device error occurred. | |
@retval EFI_NOT_FOUND A recovery DXE capsule cannot be found. | |
**/ | |
EFI_STATUS | |
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 | |
) | |
{ | |
EFI_STATUS Status; | |
PEI_FAT_PRIVATE_DATA *PrivateData; | |
UINTN Index; | |
UINTN BlockDeviceNo; | |
UINTN RecoveryCapsuleCount; | |
PEI_FILE_HANDLE Handle; | |
UINTN NumberRecoveryCapsules; | |
Status = GetNumberRecoveryCapsules (PeiServices, This, &NumberRecoveryCapsules); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
if ((CapsuleInstance == 0) || (CapsuleInstance > NumberRecoveryCapsules)) { | |
return EFI_NOT_FOUND; | |
} | |
PrivateData = PEI_FAT_PRIVATE_DATA_FROM_THIS (This); | |
// | |
// Search each volume in the root directory for the Recovery capsule | |
// | |
RecoveryCapsuleCount = 0; | |
for (Index = 0; Index < PrivateData->VolumeCount; Index++) { | |
Status = FindRecoveryFile (PrivateData, Index, (CHAR16 *)PcdGetPtr (PcdRecoveryFileName), &Handle); | |
if (EFI_ERROR (Status)) { | |
continue; | |
} | |
if (CapsuleInstance - 1 == RecoveryCapsuleCount) { | |
// | |
// Get file size | |
// | |
*Size = (UINTN)(((PEI_FAT_FILE *)Handle)->FileSize); | |
// | |
// Find corresponding physical block device | |
// | |
BlockDeviceNo = PrivateData->Volume[Index].BlockDeviceNo; | |
while (BlockDeviceNo < PrivateData->BlockDeviceCount && PrivateData->BlockDevice[BlockDeviceNo].Logical) { | |
BlockDeviceNo = PrivateData->BlockDevice[BlockDeviceNo].ParentDevNo; | |
} | |
// | |
// Fill in the Capsule Type GUID according to the block device type | |
// | |
if (BlockDeviceNo < PrivateData->BlockDeviceCount) { | |
if (PrivateData->BlockDevice[BlockDeviceNo].BlockIo2 != NULL) { | |
switch (PrivateData->BlockDevice[BlockDeviceNo].InterfaceType) { | |
case MSG_ATAPI_DP: | |
CopyGuid (CapsuleType, &gRecoveryOnFatIdeDiskGuid); | |
break; | |
case MSG_USB_DP: | |
CopyGuid (CapsuleType, &gRecoveryOnFatUsbDiskGuid); | |
break; | |
case MSG_NVME_NAMESPACE_DP: | |
CopyGuid (CapsuleType, &gRecoveryOnFatNvmeDiskGuid); | |
break; | |
default: | |
break; | |
} | |
} | |
if (PrivateData->BlockDevice[BlockDeviceNo].BlockIo != NULL) { | |
switch (PrivateData->BlockDevice[BlockDeviceNo].DevType) { | |
case LegacyFloppy: | |
CopyGuid (CapsuleType, &gRecoveryOnFatFloppyDiskGuid); | |
break; | |
case IdeCDROM: | |
case IdeLS120: | |
CopyGuid (CapsuleType, &gRecoveryOnFatIdeDiskGuid); | |
break; | |
case UsbMassStorage: | |
CopyGuid (CapsuleType, &gRecoveryOnFatUsbDiskGuid); | |
break; | |
default: | |
break; | |
} | |
} | |
} | |
return EFI_SUCCESS; | |
} | |
RecoveryCapsuleCount++; | |
} | |
return EFI_NOT_FOUND; | |
} | |
/** | |
Loads a DXE capsule from some media into memory. | |
This function, by whatever mechanism, retrieves a DXE capsule from some device | |
and loads it into memory. Note that the published interface is device neutral. | |
@param[in] PeiServices General-purpose services that are available | |
to every PEIM | |
@param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI | |
instance. | |
@param[in] CapsuleInstance Specifies which capsule instance to retrieve. | |
@param[out] Buffer Specifies a caller-allocated buffer in which | |
the requested recovery capsule will be returned. | |
@retval EFI_SUCCESS The capsule was loaded correctly. | |
@retval EFI_DEVICE_ERROR A device error occurred. | |
@retval EFI_NOT_FOUND A requested recovery DXE capsule cannot be found. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
LoadRecoveryCapsule ( | |
IN EFI_PEI_SERVICES **PeiServices, | |
IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This, | |
IN UINTN CapsuleInstance, | |
OUT VOID *Buffer | |
) | |
{ | |
EFI_STATUS Status; | |
PEI_FAT_PRIVATE_DATA *PrivateData; | |
UINTN Index; | |
UINTN RecoveryCapsuleCount; | |
PEI_FILE_HANDLE Handle; | |
UINTN NumberRecoveryCapsules; | |
Status = GetNumberRecoveryCapsules (PeiServices, This, &NumberRecoveryCapsules); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
if ((CapsuleInstance == 0) || (CapsuleInstance > NumberRecoveryCapsules)) { | |
return EFI_NOT_FOUND; | |
} | |
PrivateData = PEI_FAT_PRIVATE_DATA_FROM_THIS (This); | |
// | |
// Search each volume in the root directory for the Recovery capsule | |
// | |
RecoveryCapsuleCount = 0; | |
for (Index = 0; Index < PrivateData->VolumeCount; Index++) { | |
Status = FindRecoveryFile (PrivateData, Index, (CHAR16 *)PcdGetPtr (PcdRecoveryFileName), &Handle); | |
if (EFI_ERROR (Status)) { | |
continue; | |
} | |
if (CapsuleInstance - 1 == RecoveryCapsuleCount) { | |
Status = FatReadFile ( | |
PrivateData, | |
Handle, | |
(UINTN)(((PEI_FAT_FILE *)Handle)->FileSize), | |
Buffer | |
); | |
return Status; | |
} | |
RecoveryCapsuleCount++; | |
} | |
return EFI_NOT_FOUND; | |
} | |
/** | |
Finds the recovery file on a FAT volume. | |
This function finds the recovery file named FileName on a specified FAT volume and returns | |
its FileHandle pointer. | |
@param PrivateData Global memory map for accessing global | |
variables. | |
@param VolumeIndex The index of the volume. | |
@param FileName The recovery file name to find. | |
@param Handle The output file handle. | |
@retval EFI_DEVICE_ERROR Some error occurred when operating the FAT | |
volume. | |
@retval EFI_NOT_FOUND The recovery file was not found. | |
@retval EFI_SUCCESS The recovery file was successfully found on the | |
FAT volume. | |
**/ | |
EFI_STATUS | |
FindRecoveryFile ( | |
IN PEI_FAT_PRIVATE_DATA *PrivateData, | |
IN UINTN VolumeIndex, | |
IN CHAR16 *FileName, | |
OUT PEI_FILE_HANDLE *Handle | |
) | |
{ | |
EFI_STATUS Status; | |
PEI_FAT_FILE Parent; | |
PEI_FAT_FILE *File; | |
File = &PrivateData->File; | |
// | |
// VolumeIndex must be less than PEI_FAT_MAX_VOLUME because PrivateData->VolumeCount | |
// cannot be larger than PEI_FAT_MAX_VOLUME when detecting recovery volume. | |
// | |
ASSERT (VolumeIndex < PEI_FAT_MAX_VOLUME); | |
// | |
// Construct root directory file | |
// | |
ZeroMem (&Parent, sizeof (PEI_FAT_FILE)); | |
Parent.IsFixedRootDir = (BOOLEAN)((PrivateData->Volume[VolumeIndex].FatType == Fat32) ? FALSE : TRUE); | |
Parent.Attributes = FAT_ATTR_DIRECTORY; | |
Parent.CurrentPos = 0; | |
Parent.CurrentCluster = Parent.IsFixedRootDir ? 0 : PrivateData->Volume[VolumeIndex].RootDirCluster; | |
Parent.StartingCluster = Parent.CurrentCluster; | |
Parent.Volume = &PrivateData->Volume[VolumeIndex]; | |
Status = FatSetFilePos (PrivateData, &Parent, 0); | |
if (EFI_ERROR (Status)) { | |
return EFI_DEVICE_ERROR; | |
} | |
// | |
// Search for recovery capsule in root directory | |
// | |
Status = FatReadNextDirectoryEntry (PrivateData, &Parent, File); | |
while (Status == EFI_SUCCESS) { | |
// | |
// Compare whether the file name is recovery file name. | |
// | |
if (EngStriColl (PrivateData, FileName, File->FileName)) { | |
break; | |
} | |
Status = FatReadNextDirectoryEntry (PrivateData, &Parent, File); | |
} | |
if (EFI_ERROR (Status)) { | |
return EFI_NOT_FOUND; | |
} | |
// | |
// Get the recovery file, set its file position to 0. | |
// | |
if (File->StartingCluster != 0) { | |
Status = FatSetFilePos (PrivateData, File, 0); | |
} | |
*Handle = File; | |
return EFI_SUCCESS; | |
} |