2 FAT recovery PEIM entry point, Ppi Functions and FAT Api functions.
4 Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
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
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.
16 #include "FatLitePeim.h"
18 PEI_FAT_PRIVATE_DATA
*mPrivateData
= NULL
;
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
24 @param PeiServices General purpose services available to every
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.
31 @retval EFI_SUCCESS The function completed successfully.
37 IN EFI_PEI_SERVICES
**PeiServices
,
38 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDescriptor
,
44 Discover all the block I/O devices to find the FAT volume.
46 @param PrivateData Global memory map for accessing global
48 @param BlockIo2 Boolean to show whether using BlockIo2 or BlockIo
50 @retval EFI_SUCCESS The function completed successfully.
54 UpdateBlocksAndVolumes (
55 IN OUT PEI_FAT_PRIVATE_DATA
*PrivateData
,
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
;
66 EFI_PEI_BLOCK_IO_MEDIA Media
;
67 EFI_PEI_BLOCK_IO2_MEDIA Media2
;
68 PEI_FAT_VOLUME Volume
;
69 EFI_PEI_SERVICES
**PeiServices
;
71 PeiServices
= (EFI_PEI_SERVICES
**) GetPeiServicesTablePointer ();
76 for (Index
= 0; Index
< PEI_FAT_CACHE_SIZE
; Index
++) {
77 PrivateData
->CacheBuffer
[Index
].Valid
= FALSE
;
80 PrivateData
->BlockDeviceCount
= 0;
83 // Find out all Block Io Ppi instances within the system
84 // Assuming all device Block Io Peims are dispatched already
86 for (BlockIoPpiInstance
= 0; BlockIoPpiInstance
< PEI_FAT_MAX_BLOCK_IO_PPI
; BlockIoPpiInstance
++) {
88 Status
= PeiServicesLocatePpi (
89 &gEfiPeiVirtualBlockIo2PpiGuid
,
92 (VOID
**) &BlockIo2Ppi
95 Status
= PeiServicesLocatePpi (
96 &gEfiPeiVirtualBlockIoPpiGuid
,
102 if (EFI_ERROR (Status
)) {
104 // Done with all Block Io Ppis
110 Status
= BlockIo2Ppi
->GetNumberOfBlockDevices (
116 Status
= BlockIoPpi
->GetNumberOfBlockDevices (
122 if (EFI_ERROR (Status
)) {
126 for (Index
= 1; Index
<= NumberBlockDevices
&& PrivateData
->BlockDeviceCount
< PEI_FAT_MAX_BLOCK_DEVICE
; Index
++) {
129 Status
= BlockIo2Ppi
->GetBlockDeviceMediaInfo (
135 if (EFI_ERROR (Status
) || !Media2
.MediaPresent
) {
139 Status
= BlockIoPpi
->GetBlockDeviceMediaInfo (
145 if (EFI_ERROR (Status
) || !Media
.MediaPresent
) {
150 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].IoAlign
= 0;
154 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].Logical
= FALSE
;
155 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].PartitionChecked
= FALSE
;
157 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].PhysicalDevNo
= (UINT8
) Index
;
159 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].BlockIo2
= BlockIo2Ppi
;
160 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].InterfaceType
= Media2
.InterfaceType
;
161 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].LastBlock
= Media2
.LastBlock
;
162 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].BlockSize
= Media2
.BlockSize
;
164 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].BlockIo
= BlockIoPpi
;
165 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].DevType
= Media
.DeviceType
;
166 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].LastBlock
= Media
.LastBlock
;
167 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].BlockSize
= (UINT32
) Media
.BlockSize
;
169 PrivateData
->BlockDeviceCount
++;
173 // Find out all logical devices
175 FatFindPartitions (PrivateData
);
178 // Build up file system volume array
180 PrivateData
->VolumeCount
= 0;
181 for (Index
= 0; Index
< PrivateData
->BlockDeviceCount
; Index
++) {
182 Volume
.BlockDeviceNo
= Index
;
183 Status
= FatGetBpbInfo (PrivateData
, &Volume
);
184 if (Status
== EFI_SUCCESS
) {
186 // Add the detected volume to the volume array
189 (UINT8
*) &(PrivateData
->Volume
[PrivateData
->VolumeCount
]),
191 sizeof (PEI_FAT_VOLUME
)
193 PrivateData
->VolumeCount
+= 1;
194 if (PrivateData
->VolumeCount
>= PEI_FAT_MAX_VOLUME
) {
205 BlockIo installation notification function. Find out all the current BlockIO
206 PPIs in the system and add them into private data. Assume there is
208 @param PeiServices General purpose services available to every
210 @param NotifyDescriptor The typedef structure of the notification
211 descriptor. Not used in this function.
212 @param Ppi The typedef structure of the PPI descriptor.
213 Not used in this function.
215 @retval EFI_SUCCESS The function completed successfully.
221 IN EFI_PEI_SERVICES
**PeiServices
,
222 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDescriptor
,
226 if (CompareGuid (NotifyDescriptor
->Guid
, &gEfiPeiVirtualBlockIo2PpiGuid
)) {
227 UpdateBlocksAndVolumes (mPrivateData
, TRUE
);
229 UpdateBlocksAndVolumes (mPrivateData
, FALSE
);
236 Installs the Device Recovery Module PPI, Initialize BlockIo Ppi
237 installation notification
239 @param FileHandle Handle of the file being invoked. Type
240 EFI_PEI_FILE_HANDLE is defined in
242 @param PeiServices Describes the list of possible PEI Services.
244 @retval EFI_SUCCESS The entry point was executed successfully.
245 @retval EFI_OUT_OF_RESOURCES There is no enough memory to complete the
252 IN EFI_PEI_FILE_HANDLE FileHandle
,
253 IN CONST EFI_PEI_SERVICES
**PeiServices
257 EFI_PHYSICAL_ADDRESS Address
;
258 PEI_FAT_PRIVATE_DATA
*PrivateData
;
260 Status
= PeiServicesRegisterForShadow (FileHandle
);
261 if (!EFI_ERROR (Status
)) {
265 Status
= PeiServicesAllocatePages (
267 (sizeof (PEI_FAT_PRIVATE_DATA
) - 1) / PEI_FAT_MEMMORY_PAGE_SIZE
+ 1,
270 if (EFI_ERROR (Status
)) {
271 return EFI_OUT_OF_RESOURCES
;
274 PrivateData
= (PEI_FAT_PRIVATE_DATA
*) (UINTN
) Address
;
277 // Initialize Private Data (to zero, as is required by subsequent operations)
279 ZeroMem ((UINT8
*) PrivateData
, sizeof (PEI_FAT_PRIVATE_DATA
));
281 PrivateData
->Signature
= PEI_FAT_PRIVATE_DATA_SIGNATURE
;
286 PrivateData
->DeviceRecoveryPpi
.GetNumberRecoveryCapsules
= GetNumberRecoveryCapsules
;
287 PrivateData
->DeviceRecoveryPpi
.GetRecoveryCapsuleInfo
= GetRecoveryCapsuleInfo
;
288 PrivateData
->DeviceRecoveryPpi
.LoadRecoveryCapsule
= LoadRecoveryCapsule
;
290 PrivateData
->PpiDescriptor
.Flags
= (EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
);
291 PrivateData
->PpiDescriptor
.Guid
= &gEfiPeiDeviceRecoveryModulePpiGuid
;
292 PrivateData
->PpiDescriptor
.Ppi
= &PrivateData
->DeviceRecoveryPpi
;
294 Status
= PeiServicesInstallPpi (&PrivateData
->PpiDescriptor
);
295 if (EFI_ERROR (Status
)) {
296 return EFI_OUT_OF_RESOURCES
;
299 // Other initializations
301 PrivateData
->BlockDeviceCount
= 0;
303 UpdateBlocksAndVolumes (PrivateData
, TRUE
);
304 UpdateBlocksAndVolumes (PrivateData
, FALSE
);
307 // PrivateData is allocated now, set it to the module variable
309 mPrivateData
= PrivateData
;
312 // Installs Block Io Ppi notification function
314 PrivateData
->NotifyDescriptor
[0].Flags
=
316 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
318 PrivateData
->NotifyDescriptor
[0].Guid
= &gEfiPeiVirtualBlockIoPpiGuid
;
319 PrivateData
->NotifyDescriptor
[0].Notify
= BlockIoNotifyEntry
;
320 PrivateData
->NotifyDescriptor
[1].Flags
=
322 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
|
323 EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
325 PrivateData
->NotifyDescriptor
[1].Guid
= &gEfiPeiVirtualBlockIo2PpiGuid
;
326 PrivateData
->NotifyDescriptor
[1].Notify
= BlockIoNotifyEntry
;
327 return PeiServicesNotifyPpi (&PrivateData
->NotifyDescriptor
[0]);
332 Returns the number of DXE capsules residing on the device.
334 This function searches for DXE capsules from the associated device and returns
335 the number and maximum size in bytes of the capsules discovered. Entry 1 is
336 assumed to be the highest load priority and entry N is assumed to be the lowest
339 @param[in] PeiServices General-purpose services that are available
341 @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
343 @param[out] NumberRecoveryCapsules Pointer to a caller-allocated UINTN. On
344 output, *NumberRecoveryCapsules contains
345 the number of recovery capsule images
346 available for retrieval from this PEIM
349 @retval EFI_SUCCESS One or more capsules were discovered.
350 @retval EFI_DEVICE_ERROR A device error occurred.
351 @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
356 GetNumberRecoveryCapsules (
357 IN EFI_PEI_SERVICES
**PeiServices
,
358 IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
*This
,
359 OUT UINTN
*NumberRecoveryCapsules
363 PEI_FAT_PRIVATE_DATA
*PrivateData
;
365 UINTN RecoveryCapsuleCount
;
366 PEI_FILE_HANDLE Handle
;
368 PrivateData
= PEI_FAT_PRIVATE_DATA_FROM_THIS (This
);
371 // Search each volume in the root directory for the Recovery capsule
373 RecoveryCapsuleCount
= 0;
374 for (Index
= 0; Index
< PrivateData
->VolumeCount
; Index
++) {
375 Status
= FindRecoveryFile (PrivateData
, Index
, PEI_FAT_RECOVERY_CAPSULE_WITHOUT_NT_EMULATOR
, &Handle
);
376 if (EFI_ERROR (Status
)) {
380 RecoveryCapsuleCount
++;
383 *NumberRecoveryCapsules
= RecoveryCapsuleCount
;
385 if (*NumberRecoveryCapsules
== 0) {
386 return EFI_NOT_FOUND
;
394 Returns the size and type of the requested recovery capsule.
396 This function gets the size and type of the capsule specified by CapsuleInstance.
398 @param[in] PeiServices General-purpose services that are available to every PEIM
399 @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
401 @param[in] CapsuleInstance Specifies for which capsule instance to retrieve
402 the information. This parameter must be between
403 one and the value returned by GetNumberRecoveryCapsules()
404 in NumberRecoveryCapsules.
405 @param[out] Size A pointer to a caller-allocated UINTN in which
406 the size of the requested recovery module is
408 @param[out] CapsuleType A pointer to a caller-allocated EFI_GUID in which
409 the type of the requested recovery capsule is
410 returned. The semantic meaning of the value
411 returned is defined by the implementation.
413 @retval EFI_SUCCESS One or more capsules were discovered.
414 @retval EFI_DEVICE_ERROR A device error occurred.
415 @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
420 GetRecoveryCapsuleInfo (
421 IN EFI_PEI_SERVICES
**PeiServices
,
422 IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
*This
,
423 IN UINTN CapsuleInstance
,
425 OUT EFI_GUID
*CapsuleType
429 PEI_FAT_PRIVATE_DATA
*PrivateData
;
432 UINTN RecoveryCapsuleCount
;
433 PEI_FILE_HANDLE Handle
;
434 UINTN NumberRecoveryCapsules
;
436 Status
= GetNumberRecoveryCapsules (PeiServices
, This
, &NumberRecoveryCapsules
);
438 if (EFI_ERROR (Status
)) {
442 if (FeaturePcdGet (PcdFrameworkCompatibilitySupport
)) {
443 CapsuleInstance
= CapsuleInstance
+ 1;
446 if ((CapsuleInstance
== 0) || (CapsuleInstance
> NumberRecoveryCapsules
)) {
447 return EFI_NOT_FOUND
;
450 PrivateData
= PEI_FAT_PRIVATE_DATA_FROM_THIS (This
);
453 // Search each volume in the root directory for the Recovery capsule
455 RecoveryCapsuleCount
= 0;
456 for (Index
= 0; Index
< PrivateData
->VolumeCount
; Index
++) {
457 Status
= FindRecoveryFile (PrivateData
, Index
, PEI_FAT_RECOVERY_CAPSULE_WITHOUT_NT_EMULATOR
, &Handle
);
459 if (EFI_ERROR (Status
)) {
463 if (CapsuleInstance
- 1 == RecoveryCapsuleCount
) {
467 *Size
= (UINTN
) (((PEI_FAT_FILE
*) Handle
)->FileSize
);
470 // Find corresponding physical block device
472 BlockDeviceNo
= PrivateData
->Volume
[Index
].BlockDeviceNo
;
473 while (PrivateData
->BlockDevice
[BlockDeviceNo
].Logical
&& BlockDeviceNo
< PrivateData
->BlockDeviceCount
) {
474 BlockDeviceNo
= PrivateData
->BlockDevice
[BlockDeviceNo
].ParentDevNo
;
477 // Fill in the Capsule Type GUID according to the block device type
479 if (BlockDeviceNo
< PrivateData
->BlockDeviceCount
) {
480 if (PrivateData
->BlockDevice
[BlockDeviceNo
].BlockIo2
!= NULL
) {
481 switch (PrivateData
->BlockDevice
[BlockDeviceNo
].InterfaceType
) {
483 CopyGuid (CapsuleType
, &gRecoveryOnFatIdeDiskGuid
);
487 CopyGuid (CapsuleType
, &gRecoveryOnFatUsbDiskGuid
);
494 if (PrivateData
->BlockDevice
[BlockDeviceNo
].BlockIo
!= NULL
) {
495 switch (PrivateData
->BlockDevice
[BlockDeviceNo
].DevType
) {
497 CopyGuid (CapsuleType
, &gRecoveryOnFatFloppyDiskGuid
);
502 CopyGuid (CapsuleType
, &gRecoveryOnFatIdeDiskGuid
);
506 CopyGuid (CapsuleType
, &gRecoveryOnFatUsbDiskGuid
);
518 RecoveryCapsuleCount
++;
521 return EFI_NOT_FOUND
;
526 Loads a DXE capsule from some media into memory.
528 This function, by whatever mechanism, retrieves a DXE capsule from some device
529 and loads it into memory. Note that the published interface is device neutral.
531 @param[in] PeiServices General-purpose services that are available
533 @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
535 @param[in] CapsuleInstance Specifies which capsule instance to retrieve.
536 @param[out] Buffer Specifies a caller-allocated buffer in which
537 the requested recovery capsule will be returned.
539 @retval EFI_SUCCESS The capsule was loaded correctly.
540 @retval EFI_DEVICE_ERROR A device error occurred.
541 @retval EFI_NOT_FOUND A requested recovery DXE capsule cannot be found.
546 LoadRecoveryCapsule (
547 IN EFI_PEI_SERVICES
**PeiServices
,
548 IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
*This
,
549 IN UINTN CapsuleInstance
,
554 PEI_FAT_PRIVATE_DATA
*PrivateData
;
556 UINTN RecoveryCapsuleCount
;
557 PEI_FILE_HANDLE Handle
;
558 UINTN NumberRecoveryCapsules
;
560 Status
= GetNumberRecoveryCapsules (PeiServices
, This
, &NumberRecoveryCapsules
);
562 if (EFI_ERROR (Status
)) {
566 if (FeaturePcdGet (PcdFrameworkCompatibilitySupport
)) {
567 CapsuleInstance
= CapsuleInstance
+ 1;
570 if ((CapsuleInstance
== 0) || (CapsuleInstance
> NumberRecoveryCapsules
)) {
571 return EFI_NOT_FOUND
;
574 PrivateData
= PEI_FAT_PRIVATE_DATA_FROM_THIS (This
);
577 // Search each volume in the root directory for the Recovery capsule
579 RecoveryCapsuleCount
= 0;
580 for (Index
= 0; Index
< PrivateData
->VolumeCount
; Index
++) {
581 Status
= FindRecoveryFile (PrivateData
, Index
, PEI_FAT_RECOVERY_CAPSULE_WITHOUT_NT_EMULATOR
, &Handle
);
582 if (EFI_ERROR (Status
)) {
586 if (CapsuleInstance
- 1 == RecoveryCapsuleCount
) {
588 Status
= FatReadFile (
591 (UINTN
) (((PEI_FAT_FILE
*) Handle
)->FileSize
),
597 RecoveryCapsuleCount
++;
600 return EFI_NOT_FOUND
;
605 Finds the recovery file on a FAT volume.
606 This function finds the the recovery file named FileName on a specified FAT volume and returns
607 its FileHandle pointer.
609 @param PrivateData Global memory map for accessing global
611 @param VolumeIndex The index of the volume.
612 @param FileName The recovery file name to find.
613 @param Handle The output file handle.
615 @retval EFI_DEVICE_ERROR Some error occured when operating the FAT
617 @retval EFI_NOT_FOUND The recovery file was not found.
618 @retval EFI_SUCCESS The recovery file was successfully found on the
624 IN PEI_FAT_PRIVATE_DATA
*PrivateData
,
625 IN UINTN VolumeIndex
,
627 OUT PEI_FILE_HANDLE
*Handle
634 File
= &PrivateData
->File
;
637 // VolumeIndex must be less than PEI_FAT_MAX_VOLUME because PrivateData->VolumeCount
638 // cannot be larger than PEI_FAT_MAX_VOLUME when detecting recovery volume.
640 ASSERT (VolumeIndex
< PEI_FAT_MAX_VOLUME
);
643 // Construct root directory file
645 ZeroMem (&Parent
, sizeof (PEI_FAT_FILE
));
646 Parent
.IsFixedRootDir
= (BOOLEAN
) ((PrivateData
->Volume
[VolumeIndex
].FatType
== Fat32
) ? FALSE
: TRUE
);
647 Parent
.Attributes
= FAT_ATTR_DIRECTORY
;
648 Parent
.CurrentPos
= 0;
649 Parent
.CurrentCluster
= Parent
.IsFixedRootDir
? 0 : PrivateData
->Volume
[VolumeIndex
].RootDirCluster
;
650 Parent
.StartingCluster
= Parent
.CurrentCluster
;
651 Parent
.Volume
= &PrivateData
->Volume
[VolumeIndex
];
653 Status
= FatSetFilePos (PrivateData
, &Parent
, 0);
654 if (EFI_ERROR (Status
)) {
655 return EFI_DEVICE_ERROR
;
658 // Search for recovery capsule in root directory
660 Status
= FatReadNextDirectoryEntry (PrivateData
, &Parent
, File
);
661 while (Status
== EFI_SUCCESS
) {
663 // Compare whether the file name is recovery file name.
665 if (EngStriColl (PrivateData
, FileName
, File
->FileName
)) {
669 Status
= FatReadNextDirectoryEntry (PrivateData
, &Parent
, File
);
672 if (EFI_ERROR (Status
)) {
673 return EFI_NOT_FOUND
;
677 // Get the recovery file, set its file position to 0.
679 if (File
->StartingCluster
!= 0) {
680 Status
= FatSetFilePos (PrivateData
, File
, 0);