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 ();
77 for (Index
= 0; Index
< PEI_FAT_CACHE_SIZE
; Index
++) {
78 PrivateData
->CacheBuffer
[Index
].Valid
= FALSE
;
81 PrivateData
->BlockDeviceCount
= 0;
84 // Find out all Block Io Ppi instances within the system
85 // Assuming all device Block Io Peims are dispatched already
87 for (BlockIoPpiInstance
= 0; BlockIoPpiInstance
< PEI_FAT_MAX_BLOCK_IO_PPI
; BlockIoPpiInstance
++) {
89 Status
= PeiServicesLocatePpi (
90 &gEfiPeiVirtualBlockIo2PpiGuid
,
93 (VOID
**) &BlockIo2Ppi
96 Status
= PeiServicesLocatePpi (
97 &gEfiPeiVirtualBlockIoPpiGuid
,
100 (VOID
**) &BlockIoPpi
103 if (EFI_ERROR (Status
)) {
105 // Done with all Block Io Ppis
111 Status
= BlockIo2Ppi
->GetNumberOfBlockDevices (
117 Status
= BlockIoPpi
->GetNumberOfBlockDevices (
123 if (EFI_ERROR (Status
)) {
127 for (Index
= 1; Index
<= NumberBlockDevices
&& PrivateData
->BlockDeviceCount
< PEI_FAT_MAX_BLOCK_DEVICE
; Index
++) {
130 Status
= BlockIo2Ppi
->GetBlockDeviceMediaInfo (
136 if (EFI_ERROR (Status
) || !Media2
.MediaPresent
) {
139 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].BlockIo2
= BlockIo2Ppi
;
140 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].InterfaceType
= Media2
.InterfaceType
;
141 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].LastBlock
= Media2
.LastBlock
;
142 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].BlockSize
= Media2
.BlockSize
;
144 Status
= BlockIoPpi
->GetBlockDeviceMediaInfo (
150 if (EFI_ERROR (Status
) || !Media
.MediaPresent
) {
153 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].BlockIo
= BlockIoPpi
;
154 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].DevType
= Media
.DeviceType
;
155 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].LastBlock
= Media
.LastBlock
;
156 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].BlockSize
= (UINT32
) Media
.BlockSize
;
159 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].IoAlign
= 0;
163 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].Logical
= FALSE
;
164 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].PartitionChecked
= FALSE
;
166 PrivateData
->BlockDevice
[PrivateData
->BlockDeviceCount
].PhysicalDevNo
= (UINT8
) Index
;
167 PrivateData
->BlockDeviceCount
++;
171 // Find out all logical devices
173 FatFindPartitions (PrivateData
);
176 // Build up file system volume array
178 PrivateData
->VolumeCount
= 0;
179 for (Index
= 0; Index
< PrivateData
->BlockDeviceCount
; Index
++) {
180 Volume
.BlockDeviceNo
= Index
;
181 Status
= FatGetBpbInfo (PrivateData
, &Volume
);
182 if (Status
== EFI_SUCCESS
) {
184 // Add the detected volume to the volume array
187 (UINT8
*) &(PrivateData
->Volume
[PrivateData
->VolumeCount
]),
189 sizeof (PEI_FAT_VOLUME
)
191 PrivateData
->VolumeCount
+= 1;
192 if (PrivateData
->VolumeCount
>= PEI_FAT_MAX_VOLUME
) {
203 BlockIo installation notification function. Find out all the current BlockIO
204 PPIs in the system and add them into private data. Assume there is
206 @param PeiServices General purpose services available to every
208 @param NotifyDescriptor The typedef structure of the notification
209 descriptor. Not used in this function.
210 @param Ppi The typedef structure of the PPI descriptor.
211 Not used in this function.
213 @retval EFI_SUCCESS The function completed successfully.
219 IN EFI_PEI_SERVICES
**PeiServices
,
220 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDescriptor
,
224 if (CompareGuid (NotifyDescriptor
->Guid
, &gEfiPeiVirtualBlockIo2PpiGuid
)) {
225 UpdateBlocksAndVolumes (mPrivateData
, TRUE
);
227 UpdateBlocksAndVolumes (mPrivateData
, FALSE
);
234 Installs the Device Recovery Module PPI, Initialize BlockIo Ppi
235 installation notification
237 @param FileHandle Handle of the file being invoked. Type
238 EFI_PEI_FILE_HANDLE is defined in
240 @param PeiServices Describes the list of possible PEI Services.
242 @retval EFI_SUCCESS The entry point was executed successfully.
243 @retval EFI_OUT_OF_RESOURCES There is no enough memory to complete the
250 IN EFI_PEI_FILE_HANDLE FileHandle
,
251 IN CONST EFI_PEI_SERVICES
**PeiServices
255 EFI_PHYSICAL_ADDRESS Address
;
256 PEI_FAT_PRIVATE_DATA
*PrivateData
;
258 Status
= PeiServicesRegisterForShadow (FileHandle
);
259 if (!EFI_ERROR (Status
)) {
263 Status
= PeiServicesAllocatePages (
265 (sizeof (PEI_FAT_PRIVATE_DATA
) - 1) / PEI_FAT_MEMMORY_PAGE_SIZE
+ 1,
268 if (EFI_ERROR (Status
)) {
269 return EFI_OUT_OF_RESOURCES
;
272 PrivateData
= (PEI_FAT_PRIVATE_DATA
*) (UINTN
) Address
;
275 // Initialize Private Data (to zero, as is required by subsequent operations)
277 ZeroMem ((UINT8
*) PrivateData
, sizeof (PEI_FAT_PRIVATE_DATA
));
279 PrivateData
->Signature
= PEI_FAT_PRIVATE_DATA_SIGNATURE
;
284 PrivateData
->DeviceRecoveryPpi
.GetNumberRecoveryCapsules
= GetNumberRecoveryCapsules
;
285 PrivateData
->DeviceRecoveryPpi
.GetRecoveryCapsuleInfo
= GetRecoveryCapsuleInfo
;
286 PrivateData
->DeviceRecoveryPpi
.LoadRecoveryCapsule
= LoadRecoveryCapsule
;
288 PrivateData
->PpiDescriptor
.Flags
= (EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
);
289 PrivateData
->PpiDescriptor
.Guid
= &gEfiPeiDeviceRecoveryModulePpiGuid
;
290 PrivateData
->PpiDescriptor
.Ppi
= &PrivateData
->DeviceRecoveryPpi
;
292 Status
= PeiServicesInstallPpi (&PrivateData
->PpiDescriptor
);
293 if (EFI_ERROR (Status
)) {
294 return EFI_OUT_OF_RESOURCES
;
297 // Other initializations
299 PrivateData
->BlockDeviceCount
= 0;
301 UpdateBlocksAndVolumes (PrivateData
, TRUE
);
302 UpdateBlocksAndVolumes (PrivateData
, FALSE
);
305 // PrivateData is allocated now, set it to the module variable
307 mPrivateData
= PrivateData
;
310 // Installs Block Io Ppi notification function
312 PrivateData
->NotifyDescriptor
[0].Flags
=
314 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
316 PrivateData
->NotifyDescriptor
[0].Guid
= &gEfiPeiVirtualBlockIoPpiGuid
;
317 PrivateData
->NotifyDescriptor
[0].Notify
= BlockIoNotifyEntry
;
318 PrivateData
->NotifyDescriptor
[1].Flags
=
320 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
|
321 EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
323 PrivateData
->NotifyDescriptor
[1].Guid
= &gEfiPeiVirtualBlockIo2PpiGuid
;
324 PrivateData
->NotifyDescriptor
[1].Notify
= BlockIoNotifyEntry
;
325 return PeiServicesNotifyPpi (&PrivateData
->NotifyDescriptor
[0]);
330 Returns the number of DXE capsules residing on the device.
332 This function searches for DXE capsules from the associated device and returns
333 the number and maximum size in bytes of the capsules discovered. Entry 1 is
334 assumed to be the highest load priority and entry N is assumed to be the lowest
337 @param[in] PeiServices General-purpose services that are available
339 @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
341 @param[out] NumberRecoveryCapsules Pointer to a caller-allocated UINTN. On
342 output, *NumberRecoveryCapsules contains
343 the number of recovery capsule images
344 available for retrieval from this PEIM
347 @retval EFI_SUCCESS One or more capsules were discovered.
348 @retval EFI_DEVICE_ERROR A device error occurred.
349 @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
354 GetNumberRecoveryCapsules (
355 IN EFI_PEI_SERVICES
**PeiServices
,
356 IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
*This
,
357 OUT UINTN
*NumberRecoveryCapsules
361 PEI_FAT_PRIVATE_DATA
*PrivateData
;
363 UINTN RecoveryCapsuleCount
;
364 PEI_FILE_HANDLE Handle
;
366 PrivateData
= PEI_FAT_PRIVATE_DATA_FROM_THIS (This
);
369 // Search each volume in the root directory for the Recovery capsule
371 RecoveryCapsuleCount
= 0;
372 for (Index
= 0; Index
< PrivateData
->VolumeCount
; Index
++) {
373 Status
= FindRecoveryFile (PrivateData
, Index
, PEI_FAT_RECOVERY_CAPSULE_WITHOUT_NT_EMULATOR
, &Handle
);
374 if (EFI_ERROR (Status
)) {
378 RecoveryCapsuleCount
++;
381 *NumberRecoveryCapsules
= RecoveryCapsuleCount
;
383 if (*NumberRecoveryCapsules
== 0) {
384 return EFI_NOT_FOUND
;
392 Returns the size and type of the requested recovery capsule.
394 This function gets the size and type of the capsule specified by CapsuleInstance.
396 @param[in] PeiServices General-purpose services that are available to every PEIM
397 @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
399 @param[in] CapsuleInstance Specifies for which capsule instance to retrieve
400 the information. This parameter must be between
401 one and the value returned by GetNumberRecoveryCapsules()
402 in NumberRecoveryCapsules.
403 @param[out] Size A pointer to a caller-allocated UINTN in which
404 the size of the requested recovery module is
406 @param[out] CapsuleType A pointer to a caller-allocated EFI_GUID in which
407 the type of the requested recovery capsule is
408 returned. The semantic meaning of the value
409 returned is defined by the implementation.
411 @retval EFI_SUCCESS One or more capsules were discovered.
412 @retval EFI_DEVICE_ERROR A device error occurred.
413 @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
418 GetRecoveryCapsuleInfo (
419 IN EFI_PEI_SERVICES
**PeiServices
,
420 IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
*This
,
421 IN UINTN CapsuleInstance
,
423 OUT EFI_GUID
*CapsuleType
427 PEI_FAT_PRIVATE_DATA
*PrivateData
;
430 UINTN RecoveryCapsuleCount
;
431 PEI_FILE_HANDLE Handle
;
432 UINTN NumberRecoveryCapsules
;
434 Status
= GetNumberRecoveryCapsules (PeiServices
, This
, &NumberRecoveryCapsules
);
436 if (EFI_ERROR (Status
)) {
440 if (FeaturePcdGet (PcdFrameworkCompatibilitySupport
)) {
441 CapsuleInstance
= CapsuleInstance
+ 1;
444 if ((CapsuleInstance
== 0) || (CapsuleInstance
> NumberRecoveryCapsules
)) {
445 return EFI_NOT_FOUND
;
448 PrivateData
= PEI_FAT_PRIVATE_DATA_FROM_THIS (This
);
451 // Search each volume in the root directory for the Recovery capsule
453 RecoveryCapsuleCount
= 0;
454 for (Index
= 0; Index
< PrivateData
->VolumeCount
; Index
++) {
455 Status
= FindRecoveryFile (PrivateData
, Index
, PEI_FAT_RECOVERY_CAPSULE_WITHOUT_NT_EMULATOR
, &Handle
);
457 if (EFI_ERROR (Status
)) {
461 if (CapsuleInstance
- 1 == RecoveryCapsuleCount
) {
465 *Size
= (UINTN
) (((PEI_FAT_FILE
*) Handle
)->FileSize
);
468 // Find corresponding physical block device
470 BlockDeviceNo
= PrivateData
->Volume
[Index
].BlockDeviceNo
;
471 while (PrivateData
->BlockDevice
[BlockDeviceNo
].Logical
&& BlockDeviceNo
< PrivateData
->BlockDeviceCount
) {
472 BlockDeviceNo
= PrivateData
->BlockDevice
[BlockDeviceNo
].ParentDevNo
;
475 // Fill in the Capsule Type GUID according to the block device type
477 if (BlockDeviceNo
< PrivateData
->BlockDeviceCount
) {
478 if (PrivateData
->BlockDevice
[BlockDeviceNo
].BlockIo2
!= NULL
) {
479 switch (PrivateData
->BlockDevice
[BlockDeviceNo
].InterfaceType
) {
481 CopyGuid (CapsuleType
, &gRecoveryOnFatIdeDiskGuid
);
485 CopyGuid (CapsuleType
, &gRecoveryOnFatUsbDiskGuid
);
492 if (PrivateData
->BlockDevice
[BlockDeviceNo
].BlockIo
!= NULL
) {
493 switch (PrivateData
->BlockDevice
[BlockDeviceNo
].DevType
) {
495 CopyGuid (CapsuleType
, &gRecoveryOnFatFloppyDiskGuid
);
500 CopyGuid (CapsuleType
, &gRecoveryOnFatIdeDiskGuid
);
504 CopyGuid (CapsuleType
, &gRecoveryOnFatUsbDiskGuid
);
516 RecoveryCapsuleCount
++;
519 return EFI_NOT_FOUND
;
524 Loads a DXE capsule from some media into memory.
526 This function, by whatever mechanism, retrieves a DXE capsule from some device
527 and loads it into memory. Note that the published interface is device neutral.
529 @param[in] PeiServices General-purpose services that are available
531 @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
533 @param[in] CapsuleInstance Specifies which capsule instance to retrieve.
534 @param[out] Buffer Specifies a caller-allocated buffer in which
535 the requested recovery capsule will be returned.
537 @retval EFI_SUCCESS The capsule was loaded correctly.
538 @retval EFI_DEVICE_ERROR A device error occurred.
539 @retval EFI_NOT_FOUND A requested recovery DXE capsule cannot be found.
544 LoadRecoveryCapsule (
545 IN EFI_PEI_SERVICES
**PeiServices
,
546 IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
*This
,
547 IN UINTN CapsuleInstance
,
552 PEI_FAT_PRIVATE_DATA
*PrivateData
;
554 UINTN RecoveryCapsuleCount
;
555 PEI_FILE_HANDLE Handle
;
556 UINTN NumberRecoveryCapsules
;
558 Status
= GetNumberRecoveryCapsules (PeiServices
, This
, &NumberRecoveryCapsules
);
560 if (EFI_ERROR (Status
)) {
564 if (FeaturePcdGet (PcdFrameworkCompatibilitySupport
)) {
565 CapsuleInstance
= CapsuleInstance
+ 1;
568 if ((CapsuleInstance
== 0) || (CapsuleInstance
> NumberRecoveryCapsules
)) {
569 return EFI_NOT_FOUND
;
572 PrivateData
= PEI_FAT_PRIVATE_DATA_FROM_THIS (This
);
575 // Search each volume in the root directory for the Recovery capsule
577 RecoveryCapsuleCount
= 0;
578 for (Index
= 0; Index
< PrivateData
->VolumeCount
; Index
++) {
579 Status
= FindRecoveryFile (PrivateData
, Index
, PEI_FAT_RECOVERY_CAPSULE_WITHOUT_NT_EMULATOR
, &Handle
);
580 if (EFI_ERROR (Status
)) {
584 if (CapsuleInstance
- 1 == RecoveryCapsuleCount
) {
586 Status
= FatReadFile (
589 (UINTN
) (((PEI_FAT_FILE
*) Handle
)->FileSize
),
595 RecoveryCapsuleCount
++;
598 return EFI_NOT_FOUND
;
603 Finds the recovery file on a FAT volume.
604 This function finds the the recovery file named FileName on a specified FAT volume and returns
605 its FileHandle pointer.
607 @param PrivateData Global memory map for accessing global
609 @param VolumeIndex The index of the volume.
610 @param FileName The recovery file name to find.
611 @param Handle The output file handle.
613 @retval EFI_DEVICE_ERROR Some error occured when operating the FAT
615 @retval EFI_NOT_FOUND The recovery file was not found.
616 @retval EFI_SUCCESS The recovery file was successfully found on the
622 IN PEI_FAT_PRIVATE_DATA
*PrivateData
,
623 IN UINTN VolumeIndex
,
625 OUT PEI_FILE_HANDLE
*Handle
632 File
= &PrivateData
->File
;
635 // VolumeIndex must be less than PEI_FAT_MAX_VOLUME because PrivateData->VolumeCount
636 // cannot be larger than PEI_FAT_MAX_VOLUME when detecting recovery volume.
638 ASSERT (VolumeIndex
< PEI_FAT_MAX_VOLUME
);
641 // Construct root directory file
643 ZeroMem (&Parent
, sizeof (PEI_FAT_FILE
));
644 Parent
.IsFixedRootDir
= (BOOLEAN
) ((PrivateData
->Volume
[VolumeIndex
].FatType
== Fat32
) ? FALSE
: TRUE
);
645 Parent
.Attributes
= FAT_ATTR_DIRECTORY
;
646 Parent
.CurrentPos
= 0;
647 Parent
.CurrentCluster
= Parent
.IsFixedRootDir
? 0 : PrivateData
->Volume
[VolumeIndex
].RootDirCluster
;
648 Parent
.StartingCluster
= Parent
.CurrentCluster
;
649 Parent
.Volume
= &PrivateData
->Volume
[VolumeIndex
];
651 Status
= FatSetFilePos (PrivateData
, &Parent
, 0);
652 if (EFI_ERROR (Status
)) {
653 return EFI_DEVICE_ERROR
;
656 // Search for recovery capsule in root directory
658 Status
= FatReadNextDirectoryEntry (PrivateData
, &Parent
, File
);
659 while (Status
== EFI_SUCCESS
) {
661 // Compare whether the file name is recovery file name.
663 if (EngStriColl (PrivateData
, FileName
, File
->FileName
)) {
667 Status
= FatReadNextDirectoryEntry (PrivateData
, &Parent
, File
);
670 if (EFI_ERROR (Status
)) {
671 return EFI_NOT_FOUND
;
675 // Get the recovery file, set its file position to 0.
677 if (File
->StartingCluster
!= 0) {
678 Status
= FatSetFilePos (PrivateData
, File
, 0);