2 FAT recovery PEIM entry point, Ppi Functions and FAT Api functions.
4 Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include "FatLitePeim.h"
12 PEI_FAT_PRIVATE_DATA
*mPrivateData
= NULL
;
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
18 @param PeiServices General purpose services available to every
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.
25 @retval EFI_SUCCESS The function completed successfully.
31 IN EFI_PEI_SERVICES
**PeiServices
,
32 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDescriptor
,
37 Discover all the block I/O devices to find the FAT volume.
39 @param PrivateData Global memory map for accessing global
41 @param BlockIo2 Boolean to show whether using BlockIo2 or BlockIo
43 @retval EFI_SUCCESS The function completed successfully.
47 UpdateBlocksAndVolumes (
48 IN OUT PEI_FAT_PRIVATE_DATA
*PrivateData
,
53 EFI_PEI_PPI_DESCRIPTOR
*TempPpiDescriptor
;
54 UINTN BlockIoPpiInstance
;
55 EFI_PEI_RECOVERY_BLOCK_IO_PPI
*BlockIoPpi
;
56 EFI_PEI_RECOVERY_BLOCK_IO2_PPI
*BlockIo2Ppi
;
57 UINTN NumberBlockDevices
;
59 EFI_PEI_BLOCK_IO_MEDIA Media
;
60 EFI_PEI_BLOCK_IO2_MEDIA Media2
;
61 PEI_FAT_VOLUME Volume
;
62 EFI_PEI_SERVICES
**PeiServices
;
64 PeiServices
= (EFI_PEI_SERVICES
**)GetPeiServicesTablePointer ();
70 for (Index
= 0; Index
< PEI_FAT_CACHE_SIZE
; Index
++) {
71 PrivateData
->CacheBuffer
[Index
].Valid
= FALSE
;
74 PrivateData
->BlockDeviceCount
= 0;
77 // Find out all Block Io Ppi instances within the system
78 // Assuming all device Block Io Peims are dispatched already
80 for (BlockIoPpiInstance
= 0; BlockIoPpiInstance
< PEI_FAT_MAX_BLOCK_IO_PPI
; BlockIoPpiInstance
++) {
82 Status
= PeiServicesLocatePpi (
83 &gEfiPeiVirtualBlockIo2PpiGuid
,
89 Status
= PeiServicesLocatePpi (
90 &gEfiPeiVirtualBlockIoPpiGuid
,
97 if (EFI_ERROR (Status
)) {
99 // Done with all Block Io Ppis
105 Status
= BlockIo2Ppi
->GetNumberOfBlockDevices (
111 Status
= BlockIoPpi
->GetNumberOfBlockDevices (
118 if (EFI_ERROR (Status
)) {
122 for (Index
= 1; Index
<= NumberBlockDevices
&& PrivateData
->BlockDeviceCount
< PEI_FAT_MAX_BLOCK_DEVICE
; Index
++) {
124 Status
= BlockIo2Ppi
->GetBlockDeviceMediaInfo (
130 if (EFI_ERROR (Status
) || !Media2
.MediaPresent
) {
134 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].BlockIo2
= BlockIo2Ppi
;
135 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].InterfaceType
= Media2
.InterfaceType
;
136 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].LastBlock
= Media2
.LastBlock
;
137 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].BlockSize
= Media2
.BlockSize
;
139 Status
= BlockIoPpi
->GetBlockDeviceMediaInfo (
145 if (EFI_ERROR (Status
) || !Media
.MediaPresent
) {
149 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].BlockIo
= BlockIoPpi
;
150 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].DevType
= Media
.DeviceType
;
151 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].LastBlock
= Media
.LastBlock
;
152 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].BlockSize
= (UINT32
)Media
.BlockSize
;
155 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].IoAlign
= 0;
159 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].Logical
= FALSE
;
160 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].PartitionChecked
= FALSE
;
162 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].PhysicalDevNo
= (UINT8
)Index
;
163 PrivateData
->BlockDeviceCount
++;
168 // Find out all logical devices
170 FatFindPartitions (PrivateData
);
173 // Build up file system volume array
175 PrivateData
->VolumeCount
= 0;
176 for (Index
= 0; Index
< PrivateData
->BlockDeviceCount
; Index
++) {
177 Volume
.BlockDeviceNo
= Index
;
178 Status
= FatGetBpbInfo (PrivateData
, &Volume
);
179 if (Status
== EFI_SUCCESS
) {
181 // Add the detected volume to the volume array
184 (UINT8
*)&(PrivateData
->Volume
[PrivateData
->VolumeCount
]),
186 sizeof (PEI_FAT_VOLUME
)
188 PrivateData
->VolumeCount
+= 1;
189 if (PrivateData
->VolumeCount
>= PEI_FAT_MAX_VOLUME
) {
199 BlockIo installation notification function. Find out all the current BlockIO
200 PPIs in the system and add them into private data. Assume there is
202 @param PeiServices General purpose services available to every
204 @param NotifyDescriptor The typedef structure of the notification
205 descriptor. Not used in this function.
206 @param Ppi The typedef structure of the PPI descriptor.
207 Not used in this function.
209 @retval EFI_SUCCESS The function completed successfully.
215 IN EFI_PEI_SERVICES
**PeiServices
,
216 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDescriptor
,
220 if (CompareGuid (NotifyDescriptor
->Guid
, &gEfiPeiVirtualBlockIo2PpiGuid
)) {
221 UpdateBlocksAndVolumes (mPrivateData
, TRUE
);
223 UpdateBlocksAndVolumes (mPrivateData
, FALSE
);
230 Installs the Device Recovery Module PPI, Initialize BlockIo Ppi
231 installation notification
233 @param FileHandle Handle of the file being invoked. Type
234 EFI_PEI_FILE_HANDLE is defined in
236 @param PeiServices Describes the list of possible PEI Services.
238 @retval EFI_SUCCESS The entry point was executed successfully.
239 @retval EFI_OUT_OF_RESOURCES There is no enough memory to complete the
246 IN EFI_PEI_FILE_HANDLE FileHandle
,
247 IN CONST EFI_PEI_SERVICES
**PeiServices
251 EFI_PHYSICAL_ADDRESS Address
;
252 PEI_FAT_PRIVATE_DATA
*PrivateData
;
254 Status
= PeiServicesRegisterForShadow (FileHandle
);
255 if (!EFI_ERROR (Status
)) {
259 Status
= PeiServicesAllocatePages (
261 (sizeof (PEI_FAT_PRIVATE_DATA
) - 1) / PEI_FAT_MEMORY_PAGE_SIZE
+ 1,
264 if (EFI_ERROR (Status
)) {
265 return EFI_OUT_OF_RESOURCES
;
268 PrivateData
= (PEI_FAT_PRIVATE_DATA
*)(UINTN
)Address
;
271 // Initialize Private Data (to zero, as is required by subsequent operations)
273 ZeroMem ((UINT8
*)PrivateData
, sizeof (PEI_FAT_PRIVATE_DATA
));
275 PrivateData
->Signature
= PEI_FAT_PRIVATE_DATA_SIGNATURE
;
280 PrivateData
->DeviceRecoveryPpi
.GetNumberRecoveryCapsules
= GetNumberRecoveryCapsules
;
281 PrivateData
->DeviceRecoveryPpi
.GetRecoveryCapsuleInfo
= GetRecoveryCapsuleInfo
;
282 PrivateData
->DeviceRecoveryPpi
.LoadRecoveryCapsule
= LoadRecoveryCapsule
;
284 PrivateData
->PpiDescriptor
.Flags
= (EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
);
285 PrivateData
->PpiDescriptor
.Guid
= &gEfiPeiDeviceRecoveryModulePpiGuid
;
286 PrivateData
->PpiDescriptor
.Ppi
= &PrivateData
->DeviceRecoveryPpi
;
288 Status
= PeiServicesInstallPpi (&PrivateData
->PpiDescriptor
);
289 if (EFI_ERROR (Status
)) {
290 return EFI_OUT_OF_RESOURCES
;
294 // Other initializations
296 PrivateData
->BlockDeviceCount
= 0;
298 UpdateBlocksAndVolumes (PrivateData
, TRUE
);
299 UpdateBlocksAndVolumes (PrivateData
, FALSE
);
302 // PrivateData is allocated now, set it to the module variable
304 mPrivateData
= PrivateData
;
307 // Installs Block Io Ppi notification function
309 PrivateData
->NotifyDescriptor
[0].Flags
=
311 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
313 PrivateData
->NotifyDescriptor
[0].Guid
= &gEfiPeiVirtualBlockIoPpiGuid
;
314 PrivateData
->NotifyDescriptor
[0].Notify
= BlockIoNotifyEntry
;
315 PrivateData
->NotifyDescriptor
[1].Flags
=
317 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
|
318 EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
320 PrivateData
->NotifyDescriptor
[1].Guid
= &gEfiPeiVirtualBlockIo2PpiGuid
;
321 PrivateData
->NotifyDescriptor
[1].Notify
= BlockIoNotifyEntry
;
322 return PeiServicesNotifyPpi (&PrivateData
->NotifyDescriptor
[0]);
326 Returns the number of DXE capsules residing on the device.
328 This function searches for DXE capsules from the associated device and returns
329 the number and maximum size in bytes of the capsules discovered. Entry 1 is
330 assumed to be the highest load priority and entry N is assumed to be the lowest
333 @param[in] PeiServices General-purpose services that are available
335 @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
337 @param[out] NumberRecoveryCapsules Pointer to a caller-allocated UINTN. On
338 output, *NumberRecoveryCapsules contains
339 the number of recovery capsule images
340 available for retrieval from this PEIM
343 @retval EFI_SUCCESS One or more capsules were discovered.
344 @retval EFI_DEVICE_ERROR A device error occurred.
345 @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
350 GetNumberRecoveryCapsules (
351 IN EFI_PEI_SERVICES
**PeiServices
,
352 IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
*This
,
353 OUT UINTN
*NumberRecoveryCapsules
357 PEI_FAT_PRIVATE_DATA
*PrivateData
;
359 UINTN RecoveryCapsuleCount
;
360 PEI_FILE_HANDLE Handle
;
362 PrivateData
= PEI_FAT_PRIVATE_DATA_FROM_THIS (This
);
365 // Search each volume in the root directory for the Recovery capsule
367 RecoveryCapsuleCount
= 0;
368 for (Index
= 0; Index
< PrivateData
->VolumeCount
; Index
++) {
369 Status
= FindRecoveryFile (PrivateData
, Index
, (CHAR16
*)PcdGetPtr (PcdRecoveryFileName
), &Handle
);
370 if (EFI_ERROR (Status
)) {
374 RecoveryCapsuleCount
++;
377 *NumberRecoveryCapsules
= RecoveryCapsuleCount
;
379 if (*NumberRecoveryCapsules
== 0) {
380 return EFI_NOT_FOUND
;
387 Returns the size and type of the requested recovery capsule.
389 This function gets the size and type of the capsule specified by CapsuleInstance.
391 @param[in] PeiServices General-purpose services that are available to every PEIM
392 @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
394 @param[in] CapsuleInstance Specifies for which capsule instance to retrieve
395 the information. This parameter must be between
396 one and the value returned by GetNumberRecoveryCapsules()
397 in NumberRecoveryCapsules.
398 @param[out] Size A pointer to a caller-allocated UINTN in which
399 the size of the requested recovery module is
401 @param[out] CapsuleType A pointer to a caller-allocated EFI_GUID in which
402 the type of the requested recovery capsule is
403 returned. The semantic meaning of the value
404 returned is defined by the implementation.
406 @retval EFI_SUCCESS One or more capsules were discovered.
407 @retval EFI_DEVICE_ERROR A device error occurred.
408 @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
413 GetRecoveryCapsuleInfo (
414 IN EFI_PEI_SERVICES
**PeiServices
,
415 IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
*This
,
416 IN UINTN CapsuleInstance
,
418 OUT EFI_GUID
*CapsuleType
422 PEI_FAT_PRIVATE_DATA
*PrivateData
;
425 UINTN RecoveryCapsuleCount
;
426 PEI_FILE_HANDLE Handle
;
427 UINTN NumberRecoveryCapsules
;
429 Status
= GetNumberRecoveryCapsules (PeiServices
, This
, &NumberRecoveryCapsules
);
431 if (EFI_ERROR (Status
)) {
435 if ((CapsuleInstance
== 0) || (CapsuleInstance
> NumberRecoveryCapsules
)) {
436 return EFI_NOT_FOUND
;
439 PrivateData
= PEI_FAT_PRIVATE_DATA_FROM_THIS (This
);
442 // Search each volume in the root directory for the Recovery capsule
444 RecoveryCapsuleCount
= 0;
445 for (Index
= 0; Index
< PrivateData
->VolumeCount
; Index
++) {
446 Status
= FindRecoveryFile (PrivateData
, Index
, (CHAR16
*)PcdGetPtr (PcdRecoveryFileName
), &Handle
);
448 if (EFI_ERROR (Status
)) {
452 if (CapsuleInstance
- 1 == RecoveryCapsuleCount
) {
456 *Size
= (UINTN
)(((PEI_FAT_FILE
*)Handle
)->FileSize
);
459 // Find corresponding physical block device
461 BlockDeviceNo
= PrivateData
->Volume
[Index
].BlockDeviceNo
;
462 while (PrivateData
->BlockDevice
[BlockDeviceNo
].Logical
&& BlockDeviceNo
< PrivateData
->BlockDeviceCount
) {
463 BlockDeviceNo
= PrivateData
->BlockDevice
[BlockDeviceNo
].ParentDevNo
;
467 // Fill in the Capsule Type GUID according to the block device type
469 if (BlockDeviceNo
< PrivateData
->BlockDeviceCount
) {
470 if (PrivateData
->BlockDevice
[BlockDeviceNo
].BlockIo2
!= NULL
) {
471 switch (PrivateData
->BlockDevice
[BlockDeviceNo
].InterfaceType
) {
473 CopyGuid (CapsuleType
, &gRecoveryOnFatIdeDiskGuid
);
477 CopyGuid (CapsuleType
, &gRecoveryOnFatUsbDiskGuid
);
480 case MSG_NVME_NAMESPACE_DP
:
481 CopyGuid (CapsuleType
, &gRecoveryOnFatNvmeDiskGuid
);
489 if (PrivateData
->BlockDevice
[BlockDeviceNo
].BlockIo
!= NULL
) {
490 switch (PrivateData
->BlockDevice
[BlockDeviceNo
].DevType
) {
492 CopyGuid (CapsuleType
, &gRecoveryOnFatFloppyDiskGuid
);
497 CopyGuid (CapsuleType
, &gRecoveryOnFatIdeDiskGuid
);
501 CopyGuid (CapsuleType
, &gRecoveryOnFatUsbDiskGuid
);
513 RecoveryCapsuleCount
++;
516 return EFI_NOT_FOUND
;
520 Loads a DXE capsule from some media into memory.
522 This function, by whatever mechanism, retrieves a DXE capsule from some device
523 and loads it into memory. Note that the published interface is device neutral.
525 @param[in] PeiServices General-purpose services that are available
527 @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
529 @param[in] CapsuleInstance Specifies which capsule instance to retrieve.
530 @param[out] Buffer Specifies a caller-allocated buffer in which
531 the requested recovery capsule will be returned.
533 @retval EFI_SUCCESS The capsule was loaded correctly.
534 @retval EFI_DEVICE_ERROR A device error occurred.
535 @retval EFI_NOT_FOUND A requested recovery DXE capsule cannot be found.
540 LoadRecoveryCapsule (
541 IN EFI_PEI_SERVICES
**PeiServices
,
542 IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
*This
,
543 IN UINTN CapsuleInstance
,
548 PEI_FAT_PRIVATE_DATA
*PrivateData
;
550 UINTN RecoveryCapsuleCount
;
551 PEI_FILE_HANDLE Handle
;
552 UINTN NumberRecoveryCapsules
;
554 Status
= GetNumberRecoveryCapsules (PeiServices
, This
, &NumberRecoveryCapsules
);
556 if (EFI_ERROR (Status
)) {
560 if ((CapsuleInstance
== 0) || (CapsuleInstance
> NumberRecoveryCapsules
)) {
561 return EFI_NOT_FOUND
;
564 PrivateData
= PEI_FAT_PRIVATE_DATA_FROM_THIS (This
);
567 // Search each volume in the root directory for the Recovery capsule
569 RecoveryCapsuleCount
= 0;
570 for (Index
= 0; Index
< PrivateData
->VolumeCount
; Index
++) {
571 Status
= FindRecoveryFile (PrivateData
, Index
, (CHAR16
*)PcdGetPtr (PcdRecoveryFileName
), &Handle
);
572 if (EFI_ERROR (Status
)) {
576 if (CapsuleInstance
- 1 == RecoveryCapsuleCount
) {
577 Status
= FatReadFile (
580 (UINTN
)(((PEI_FAT_FILE
*)Handle
)->FileSize
),
586 RecoveryCapsuleCount
++;
589 return EFI_NOT_FOUND
;
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.
597 @param PrivateData Global memory map for accessing global
599 @param VolumeIndex The index of the volume.
600 @param FileName The recovery file name to find.
601 @param Handle The output file handle.
603 @retval EFI_DEVICE_ERROR Some error occurred when operating the FAT
605 @retval EFI_NOT_FOUND The recovery file was not found.
606 @retval EFI_SUCCESS The recovery file was successfully found on the
612 IN PEI_FAT_PRIVATE_DATA
*PrivateData
,
613 IN UINTN VolumeIndex
,
615 OUT PEI_FILE_HANDLE
*Handle
622 File
= &PrivateData
->File
;
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.
628 ASSERT (VolumeIndex
< PEI_FAT_MAX_VOLUME
);
631 // Construct root directory file
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
];
641 Status
= FatSetFilePos (PrivateData
, &Parent
, 0);
642 if (EFI_ERROR (Status
)) {
643 return EFI_DEVICE_ERROR
;
647 // Search for recovery capsule in root directory
649 Status
= FatReadNextDirectoryEntry (PrivateData
, &Parent
, File
);
650 while (Status
== EFI_SUCCESS
) {
652 // Compare whether the file name is recovery file name.
654 if (EngStriColl (PrivateData
, FileName
, File
->FileName
)) {
658 Status
= FatReadNextDirectoryEntry (PrivateData
, &Parent
, File
);
661 if (EFI_ERROR (Status
)) {
662 return EFI_NOT_FOUND
;
666 // Get the recovery file, set its file position to 0.
668 if (File
->StartingCluster
!= 0) {
669 Status
= FatSetFilePos (PrivateData
, File
, 0);