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
,
38 Discover all the block I/O devices to find the FAT volume.
40 @param PrivateData Global memory map for accessing global
42 @param BlockIo2 Boolean to show whether using BlockIo2 or BlockIo
44 @retval EFI_SUCCESS The function completed successfully.
48 UpdateBlocksAndVolumes (
49 IN OUT PEI_FAT_PRIVATE_DATA
*PrivateData
,
54 EFI_PEI_PPI_DESCRIPTOR
*TempPpiDescriptor
;
55 UINTN BlockIoPpiInstance
;
56 EFI_PEI_RECOVERY_BLOCK_IO_PPI
*BlockIoPpi
;
57 EFI_PEI_RECOVERY_BLOCK_IO2_PPI
*BlockIo2Ppi
;
58 UINTN NumberBlockDevices
;
60 EFI_PEI_BLOCK_IO_MEDIA Media
;
61 EFI_PEI_BLOCK_IO2_MEDIA Media2
;
62 PEI_FAT_VOLUME Volume
;
63 EFI_PEI_SERVICES
**PeiServices
;
65 PeiServices
= (EFI_PEI_SERVICES
**) GetPeiServicesTablePointer ();
71 for (Index
= 0; Index
< PEI_FAT_CACHE_SIZE
; Index
++) {
72 PrivateData
->CacheBuffer
[Index
].Valid
= FALSE
;
75 PrivateData
->BlockDeviceCount
= 0;
78 // Find out all Block Io Ppi instances within the system
79 // Assuming all device Block Io Peims are dispatched already
81 for (BlockIoPpiInstance
= 0; BlockIoPpiInstance
< PEI_FAT_MAX_BLOCK_IO_PPI
; BlockIoPpiInstance
++) {
83 Status
= PeiServicesLocatePpi (
84 &gEfiPeiVirtualBlockIo2PpiGuid
,
87 (VOID
**) &BlockIo2Ppi
90 Status
= PeiServicesLocatePpi (
91 &gEfiPeiVirtualBlockIoPpiGuid
,
97 if (EFI_ERROR (Status
)) {
99 // Done with all Block Io Ppis
105 Status
= BlockIo2Ppi
->GetNumberOfBlockDevices (
111 Status
= BlockIoPpi
->GetNumberOfBlockDevices (
117 if (EFI_ERROR (Status
)) {
121 for (Index
= 1; Index
<= NumberBlockDevices
&& PrivateData
->BlockDeviceCount
< PEI_FAT_MAX_BLOCK_DEVICE
; Index
++) {
124 Status
= BlockIo2Ppi
->GetBlockDeviceMediaInfo (
130 if (EFI_ERROR (Status
) || !Media2
.MediaPresent
) {
133 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].BlockIo2
= BlockIo2Ppi
;
134 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].InterfaceType
= Media2
.InterfaceType
;
135 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].LastBlock
= Media2
.LastBlock
;
136 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].BlockSize
= Media2
.BlockSize
;
138 Status
= BlockIoPpi
->GetBlockDeviceMediaInfo (
144 if (EFI_ERROR (Status
) || !Media
.MediaPresent
) {
147 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].BlockIo
= BlockIoPpi
;
148 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].DevType
= Media
.DeviceType
;
149 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].LastBlock
= Media
.LastBlock
;
150 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].BlockSize
= (UINT32
) Media
.BlockSize
;
153 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].IoAlign
= 0;
157 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].Logical
= FALSE
;
158 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].PartitionChecked
= FALSE
;
160 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].PhysicalDevNo
= (UINT8
) Index
;
161 PrivateData
->BlockDeviceCount
++;
165 // Find out all logical devices
167 FatFindPartitions (PrivateData
);
170 // Build up file system volume array
172 PrivateData
->VolumeCount
= 0;
173 for (Index
= 0; Index
< PrivateData
->BlockDeviceCount
; Index
++) {
174 Volume
.BlockDeviceNo
= Index
;
175 Status
= FatGetBpbInfo (PrivateData
, &Volume
);
176 if (Status
== EFI_SUCCESS
) {
178 // Add the detected volume to the volume array
181 (UINT8
*) &(PrivateData
->Volume
[PrivateData
->VolumeCount
]),
183 sizeof (PEI_FAT_VOLUME
)
185 PrivateData
->VolumeCount
+= 1;
186 if (PrivateData
->VolumeCount
>= PEI_FAT_MAX_VOLUME
) {
197 BlockIo installation notification function. Find out all the current BlockIO
198 PPIs in the system and add them into private data. Assume there is
200 @param PeiServices General purpose services available to every
202 @param NotifyDescriptor The typedef structure of the notification
203 descriptor. Not used in this function.
204 @param Ppi The typedef structure of the PPI descriptor.
205 Not used in this function.
207 @retval EFI_SUCCESS The function completed successfully.
213 IN EFI_PEI_SERVICES
**PeiServices
,
214 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDescriptor
,
218 if (CompareGuid (NotifyDescriptor
->Guid
, &gEfiPeiVirtualBlockIo2PpiGuid
)) {
219 UpdateBlocksAndVolumes (mPrivateData
, TRUE
);
221 UpdateBlocksAndVolumes (mPrivateData
, FALSE
);
228 Installs the Device Recovery Module PPI, Initialize BlockIo Ppi
229 installation notification
231 @param FileHandle Handle of the file being invoked. Type
232 EFI_PEI_FILE_HANDLE is defined in
234 @param PeiServices Describes the list of possible PEI Services.
236 @retval EFI_SUCCESS The entry point was executed successfully.
237 @retval EFI_OUT_OF_RESOURCES There is no enough memory to complete the
244 IN EFI_PEI_FILE_HANDLE FileHandle
,
245 IN CONST EFI_PEI_SERVICES
**PeiServices
249 EFI_PHYSICAL_ADDRESS Address
;
250 PEI_FAT_PRIVATE_DATA
*PrivateData
;
252 Status
= PeiServicesRegisterForShadow (FileHandle
);
253 if (!EFI_ERROR (Status
)) {
257 Status
= PeiServicesAllocatePages (
259 (sizeof (PEI_FAT_PRIVATE_DATA
) - 1) / PEI_FAT_MEMORY_PAGE_SIZE
+ 1,
262 if (EFI_ERROR (Status
)) {
263 return EFI_OUT_OF_RESOURCES
;
266 PrivateData
= (PEI_FAT_PRIVATE_DATA
*) (UINTN
) Address
;
269 // Initialize Private Data (to zero, as is required by subsequent operations)
271 ZeroMem ((UINT8
*) PrivateData
, sizeof (PEI_FAT_PRIVATE_DATA
));
273 PrivateData
->Signature
= PEI_FAT_PRIVATE_DATA_SIGNATURE
;
278 PrivateData
->DeviceRecoveryPpi
.GetNumberRecoveryCapsules
= GetNumberRecoveryCapsules
;
279 PrivateData
->DeviceRecoveryPpi
.GetRecoveryCapsuleInfo
= GetRecoveryCapsuleInfo
;
280 PrivateData
->DeviceRecoveryPpi
.LoadRecoveryCapsule
= LoadRecoveryCapsule
;
282 PrivateData
->PpiDescriptor
.Flags
= (EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
);
283 PrivateData
->PpiDescriptor
.Guid
= &gEfiPeiDeviceRecoveryModulePpiGuid
;
284 PrivateData
->PpiDescriptor
.Ppi
= &PrivateData
->DeviceRecoveryPpi
;
286 Status
= PeiServicesInstallPpi (&PrivateData
->PpiDescriptor
);
287 if (EFI_ERROR (Status
)) {
288 return EFI_OUT_OF_RESOURCES
;
291 // Other initializations
293 PrivateData
->BlockDeviceCount
= 0;
295 UpdateBlocksAndVolumes (PrivateData
, TRUE
);
296 UpdateBlocksAndVolumes (PrivateData
, FALSE
);
299 // PrivateData is allocated now, set it to the module variable
301 mPrivateData
= PrivateData
;
304 // Installs Block Io Ppi notification function
306 PrivateData
->NotifyDescriptor
[0].Flags
=
308 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
310 PrivateData
->NotifyDescriptor
[0].Guid
= &gEfiPeiVirtualBlockIoPpiGuid
;
311 PrivateData
->NotifyDescriptor
[0].Notify
= BlockIoNotifyEntry
;
312 PrivateData
->NotifyDescriptor
[1].Flags
=
314 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
|
315 EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
317 PrivateData
->NotifyDescriptor
[1].Guid
= &gEfiPeiVirtualBlockIo2PpiGuid
;
318 PrivateData
->NotifyDescriptor
[1].Notify
= BlockIoNotifyEntry
;
319 return PeiServicesNotifyPpi (&PrivateData
->NotifyDescriptor
[0]);
324 Returns the number of DXE capsules residing on the device.
326 This function searches for DXE capsules from the associated device and returns
327 the number and maximum size in bytes of the capsules discovered. Entry 1 is
328 assumed to be the highest load priority and entry N is assumed to be the lowest
331 @param[in] PeiServices General-purpose services that are available
333 @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
335 @param[out] NumberRecoveryCapsules Pointer to a caller-allocated UINTN. On
336 output, *NumberRecoveryCapsules contains
337 the number of recovery capsule images
338 available for retrieval from this PEIM
341 @retval EFI_SUCCESS One or more capsules were discovered.
342 @retval EFI_DEVICE_ERROR A device error occurred.
343 @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
348 GetNumberRecoveryCapsules (
349 IN EFI_PEI_SERVICES
**PeiServices
,
350 IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
*This
,
351 OUT UINTN
*NumberRecoveryCapsules
355 PEI_FAT_PRIVATE_DATA
*PrivateData
;
357 UINTN RecoveryCapsuleCount
;
358 PEI_FILE_HANDLE Handle
;
360 PrivateData
= PEI_FAT_PRIVATE_DATA_FROM_THIS (This
);
363 // Search each volume in the root directory for the Recovery capsule
365 RecoveryCapsuleCount
= 0;
366 for (Index
= 0; Index
< PrivateData
->VolumeCount
; Index
++) {
367 Status
= FindRecoveryFile (PrivateData
, Index
, (CHAR16
*)PcdGetPtr(PcdRecoveryFileName
), &Handle
);
368 if (EFI_ERROR (Status
)) {
372 RecoveryCapsuleCount
++;
375 *NumberRecoveryCapsules
= RecoveryCapsuleCount
;
377 if (*NumberRecoveryCapsules
== 0) {
378 return EFI_NOT_FOUND
;
386 Returns the size and type of the requested recovery capsule.
388 This function gets the size and type of the capsule specified by CapsuleInstance.
390 @param[in] PeiServices General-purpose services that are available to every PEIM
391 @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
393 @param[in] CapsuleInstance Specifies for which capsule instance to retrieve
394 the information. This parameter must be between
395 one and the value returned by GetNumberRecoveryCapsules()
396 in NumberRecoveryCapsules.
397 @param[out] Size A pointer to a caller-allocated UINTN in which
398 the size of the requested recovery module is
400 @param[out] CapsuleType A pointer to a caller-allocated EFI_GUID in which
401 the type of the requested recovery capsule is
402 returned. The semantic meaning of the value
403 returned is defined by the implementation.
405 @retval EFI_SUCCESS One or more capsules were discovered.
406 @retval EFI_DEVICE_ERROR A device error occurred.
407 @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
412 GetRecoveryCapsuleInfo (
413 IN EFI_PEI_SERVICES
**PeiServices
,
414 IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
*This
,
415 IN UINTN CapsuleInstance
,
417 OUT EFI_GUID
*CapsuleType
421 PEI_FAT_PRIVATE_DATA
*PrivateData
;
424 UINTN RecoveryCapsuleCount
;
425 PEI_FILE_HANDLE Handle
;
426 UINTN NumberRecoveryCapsules
;
428 Status
= GetNumberRecoveryCapsules (PeiServices
, This
, &NumberRecoveryCapsules
);
430 if (EFI_ERROR (Status
)) {
434 if ((CapsuleInstance
== 0) || (CapsuleInstance
> NumberRecoveryCapsules
)) {
435 return EFI_NOT_FOUND
;
438 PrivateData
= PEI_FAT_PRIVATE_DATA_FROM_THIS (This
);
441 // Search each volume in the root directory for the Recovery capsule
443 RecoveryCapsuleCount
= 0;
444 for (Index
= 0; Index
< PrivateData
->VolumeCount
; Index
++) {
445 Status
= FindRecoveryFile (PrivateData
, Index
, (CHAR16
*)PcdGetPtr(PcdRecoveryFileName
), &Handle
);
447 if (EFI_ERROR (Status
)) {
451 if (CapsuleInstance
- 1 == RecoveryCapsuleCount
) {
455 *Size
= (UINTN
) (((PEI_FAT_FILE
*) Handle
)->FileSize
);
458 // Find corresponding physical block device
460 BlockDeviceNo
= PrivateData
->Volume
[Index
].BlockDeviceNo
;
461 while (PrivateData
->BlockDevice
[BlockDeviceNo
].Logical
&& BlockDeviceNo
< PrivateData
->BlockDeviceCount
) {
462 BlockDeviceNo
= PrivateData
->BlockDevice
[BlockDeviceNo
].ParentDevNo
;
465 // Fill in the Capsule Type GUID according to the block device type
467 if (BlockDeviceNo
< PrivateData
->BlockDeviceCount
) {
468 if (PrivateData
->BlockDevice
[BlockDeviceNo
].BlockIo2
!= NULL
) {
469 switch (PrivateData
->BlockDevice
[BlockDeviceNo
].InterfaceType
) {
471 CopyGuid (CapsuleType
, &gRecoveryOnFatIdeDiskGuid
);
475 CopyGuid (CapsuleType
, &gRecoveryOnFatUsbDiskGuid
);
478 case MSG_NVME_NAMESPACE_DP
:
479 CopyGuid (CapsuleType
, &gRecoveryOnFatNvmeDiskGuid
);
486 if (PrivateData
->BlockDevice
[BlockDeviceNo
].BlockIo
!= NULL
) {
487 switch (PrivateData
->BlockDevice
[BlockDeviceNo
].DevType
) {
489 CopyGuid (CapsuleType
, &gRecoveryOnFatFloppyDiskGuid
);
494 CopyGuid (CapsuleType
, &gRecoveryOnFatIdeDiskGuid
);
498 CopyGuid (CapsuleType
, &gRecoveryOnFatUsbDiskGuid
);
510 RecoveryCapsuleCount
++;
513 return EFI_NOT_FOUND
;
518 Loads a DXE capsule from some media into memory.
520 This function, by whatever mechanism, retrieves a DXE capsule from some device
521 and loads it into memory. Note that the published interface is device neutral.
523 @param[in] PeiServices General-purpose services that are available
525 @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
527 @param[in] CapsuleInstance Specifies which capsule instance to retrieve.
528 @param[out] Buffer Specifies a caller-allocated buffer in which
529 the requested recovery capsule will be returned.
531 @retval EFI_SUCCESS The capsule was loaded correctly.
532 @retval EFI_DEVICE_ERROR A device error occurred.
533 @retval EFI_NOT_FOUND A requested recovery DXE capsule cannot be found.
538 LoadRecoveryCapsule (
539 IN EFI_PEI_SERVICES
**PeiServices
,
540 IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
*This
,
541 IN UINTN CapsuleInstance
,
546 PEI_FAT_PRIVATE_DATA
*PrivateData
;
548 UINTN RecoveryCapsuleCount
;
549 PEI_FILE_HANDLE Handle
;
550 UINTN NumberRecoveryCapsules
;
552 Status
= GetNumberRecoveryCapsules (PeiServices
, This
, &NumberRecoveryCapsules
);
554 if (EFI_ERROR (Status
)) {
558 if ((CapsuleInstance
== 0) || (CapsuleInstance
> NumberRecoveryCapsules
)) {
559 return EFI_NOT_FOUND
;
562 PrivateData
= PEI_FAT_PRIVATE_DATA_FROM_THIS (This
);
565 // Search each volume in the root directory for the Recovery capsule
567 RecoveryCapsuleCount
= 0;
568 for (Index
= 0; Index
< PrivateData
->VolumeCount
; Index
++) {
569 Status
= FindRecoveryFile (PrivateData
, Index
, (CHAR16
*)PcdGetPtr(PcdRecoveryFileName
), &Handle
);
570 if (EFI_ERROR (Status
)) {
574 if (CapsuleInstance
- 1 == RecoveryCapsuleCount
) {
576 Status
= FatReadFile (
579 (UINTN
) (((PEI_FAT_FILE
*) Handle
)->FileSize
),
585 RecoveryCapsuleCount
++;
588 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
;
646 // Search for recovery capsule in root directory
648 Status
= FatReadNextDirectoryEntry (PrivateData
, &Parent
, File
);
649 while (Status
== EFI_SUCCESS
) {
651 // Compare whether the file name is recovery file name.
653 if (EngStriColl (PrivateData
, FileName
, File
->FileName
)) {
657 Status
= FatReadNextDirectoryEntry (PrivateData
, &Parent
, File
);
660 if (EFI_ERROR (Status
)) {
661 return EFI_NOT_FOUND
;
665 // Get the recovery file, set its file position to 0.
667 if (File
->StartingCluster
!= 0) {
668 Status
= FatSetFilePos (PrivateData
, File
, 0);