| /** @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; | |
| } |