2 Source file for CD recovery PEIM
4 Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include "PeiCdExpress.h"
12 PEI_CD_EXPRESS_PRIVATE_DATA
*mPrivateData
= NULL
;
13 CHAR8
*mRecoveryFileName
;
14 UINTN mRecoveryFileNameSize
;
17 Installs the Device Recovery Module PPI, Initialize BlockIo Ppi
18 installation notification
20 @param FileHandle The file handle of the image.
21 @param PeiServices General purpose services available to every PEIM.
23 @retval EFI_SUCCESS The function completed successfully.
24 @retval EFI_OUT_OF_RESOURCES There is not enough system memory.
30 IN EFI_PEI_FILE_HANDLE FileHandle
,
31 IN CONST EFI_PEI_SERVICES
**PeiServices
35 PEI_CD_EXPRESS_PRIVATE_DATA
*PrivateData
;
37 if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle
))) {
41 PrivateData
= AllocatePages (EFI_SIZE_TO_PAGES (sizeof (*PrivateData
)));
42 if (PrivateData
== NULL
) {
43 return EFI_OUT_OF_RESOURCES
;
46 mRecoveryFileNameSize
= PcdGetSize(PcdRecoveryFileName
) / sizeof(CHAR16
);
47 mRecoveryFileName
= AllocatePool(mRecoveryFileNameSize
);
48 if (mRecoveryFileName
== NULL
) {
49 return EFI_OUT_OF_RESOURCES
;
51 Status
= UnicodeStrToAsciiStrS(PcdGetPtr(PcdRecoveryFileName
), mRecoveryFileName
, mRecoveryFileNameSize
);
52 if (EFI_ERROR(Status
)) {
57 // Initialize Private Data (to zero, as is required by subsequent operations)
59 ZeroMem (PrivateData
, sizeof (*PrivateData
));
60 PrivateData
->Signature
= PEI_CD_EXPRESS_PRIVATE_DATA_SIGNATURE
;
62 PrivateData
->BlockBuffer
= AllocatePages (EFI_SIZE_TO_PAGES (PEI_CD_BLOCK_SIZE
));
63 if (PrivateData
->BlockBuffer
== NULL
) {
64 return EFI_OUT_OF_RESOURCES
;
67 PrivateData
->CapsuleCount
= 0;
68 Status
= UpdateBlocksAndVolumes (PrivateData
, TRUE
);
69 Status
= UpdateBlocksAndVolumes (PrivateData
, FALSE
);
74 PrivateData
->DeviceRecoveryPpi
.GetNumberRecoveryCapsules
= GetNumberRecoveryCapsules
;
75 PrivateData
->DeviceRecoveryPpi
.GetRecoveryCapsuleInfo
= GetRecoveryCapsuleInfo
;
76 PrivateData
->DeviceRecoveryPpi
.LoadRecoveryCapsule
= LoadRecoveryCapsule
;
78 PrivateData
->PpiDescriptor
.Flags
= (EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
);
79 PrivateData
->PpiDescriptor
.Guid
= &gEfiPeiDeviceRecoveryModulePpiGuid
;
80 PrivateData
->PpiDescriptor
.Ppi
= &PrivateData
->DeviceRecoveryPpi
;
82 Status
= PeiServicesInstallPpi (&PrivateData
->PpiDescriptor
);
83 if (EFI_ERROR (Status
)) {
84 return EFI_OUT_OF_RESOURCES
;
87 // PrivateData is allocated now, set it to the module variable
89 mPrivateData
= PrivateData
;
92 // Installs Block Io Ppi notification function
94 PrivateData
->NotifyDescriptor
.Flags
=
96 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
98 PrivateData
->NotifyDescriptor
.Guid
= &gEfiPeiVirtualBlockIoPpiGuid
;
99 PrivateData
->NotifyDescriptor
.Notify
= BlockIoNotifyEntry
;
101 PrivateData
->NotifyDescriptor2
.Flags
=
103 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
|
104 EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
106 PrivateData
->NotifyDescriptor2
.Guid
= &gEfiPeiVirtualBlockIo2PpiGuid
;
107 PrivateData
->NotifyDescriptor2
.Notify
= BlockIoNotifyEntry
;
109 return PeiServicesNotifyPpi (&PrivateData
->NotifyDescriptor
);
114 BlockIo installation notification function.
116 This function finds out all the current Block IO PPIs in the system and add them
119 @param PeiServices Indirect reference to the PEI Services Table.
120 @param NotifyDescriptor Address of the notification descriptor data structure.
121 @param Ppi Address of the PPI that was installed.
123 @retval EFI_SUCCESS The function completes successfully.
129 IN EFI_PEI_SERVICES
**PeiServices
,
130 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDescriptor
,
134 if (CompareGuid (NotifyDescriptor
->Guid
, &gEfiPeiVirtualBlockIo2PpiGuid
)) {
135 UpdateBlocksAndVolumes (mPrivateData
, TRUE
);
137 UpdateBlocksAndVolumes (mPrivateData
, FALSE
);
144 Finds out all the current Block IO PPIs in the system and add them into private data.
146 @param PrivateData The private data structure that contains recovery module information.
147 @param BlockIo2 Boolean to show whether using BlockIo2 or BlockIo.
149 @retval EFI_SUCCESS The blocks and volumes are updated successfully.
153 UpdateBlocksAndVolumes (
154 IN OUT PEI_CD_EXPRESS_PRIVATE_DATA
*PrivateData
,
159 EFI_PEI_PPI_DESCRIPTOR
*TempPpiDescriptor
;
160 UINTN BlockIoPpiInstance
;
161 EFI_PEI_RECOVERY_BLOCK_IO_PPI
*BlockIoPpi
;
162 EFI_PEI_RECOVERY_BLOCK_IO2_PPI
*BlockIo2Ppi
;
163 UINTN NumberBlockDevices
;
164 UINTN IndexBlockDevice
;
165 EFI_PEI_BLOCK_IO_MEDIA Media
;
166 EFI_PEI_BLOCK_IO2_MEDIA Media2
;
167 EFI_PEI_SERVICES
**PeiServices
;
169 IndexBlockDevice
= 0;
173 // Find out all Block Io Ppi instances within the system
174 // Assuming all device Block Io Peims are dispatched already
176 for (BlockIoPpiInstance
= 0; BlockIoPpiInstance
< PEI_CD_EXPRESS_MAX_BLOCK_IO_PPI
; BlockIoPpiInstance
++) {
178 Status
= PeiServicesLocatePpi (
179 &gEfiPeiVirtualBlockIo2PpiGuid
,
182 (VOID
**) &BlockIo2Ppi
185 Status
= PeiServicesLocatePpi (
186 &gEfiPeiVirtualBlockIoPpiGuid
,
189 (VOID
**) &BlockIoPpi
192 if (EFI_ERROR (Status
)) {
194 // Done with all Block Io Ppis
199 PeiServices
= (EFI_PEI_SERVICES
**) GetPeiServicesTablePointer ();
201 Status
= BlockIo2Ppi
->GetNumberOfBlockDevices (
207 Status
= BlockIoPpi
->GetNumberOfBlockDevices (
213 if (EFI_ERROR (Status
) || (NumberBlockDevices
== 0)) {
217 // Just retrieve the first block, should emulate all blocks.
219 for (IndexBlockDevice
= 1; IndexBlockDevice
<= NumberBlockDevices
&& PrivateData
->CapsuleCount
< PEI_CD_EXPRESS_MAX_CAPSULE_NUMBER
; IndexBlockDevice
++) {
221 Status
= BlockIo2Ppi
->GetBlockDeviceMediaInfo (
227 if (EFI_ERROR (Status
) ||
228 !Media2
.MediaPresent
||
229 ((Media2
.InterfaceType
!= MSG_ATAPI_DP
) && (Media2
.InterfaceType
!= MSG_USB_DP
)) ||
230 (Media2
.BlockSize
!= PEI_CD_BLOCK_SIZE
)
234 DEBUG ((DEBUG_INFO
, "PeiCdExpress InterfaceType is %d\n", Media2
.InterfaceType
));
235 DEBUG ((DEBUG_INFO
, "PeiCdExpress MediaPresent is %d\n", Media2
.MediaPresent
));
236 DEBUG ((DEBUG_INFO
, "PeiCdExpress BlockSize is 0x%x\n", Media2
.BlockSize
));
238 Status
= BlockIoPpi
->GetBlockDeviceMediaInfo (
244 if (EFI_ERROR (Status
) ||
245 !Media
.MediaPresent
||
246 ((Media
.DeviceType
!= IdeCDROM
) && (Media
.DeviceType
!= UsbMassStorage
)) ||
247 (Media
.BlockSize
!= PEI_CD_BLOCK_SIZE
)
251 DEBUG ((DEBUG_INFO
, "PeiCdExpress DeviceType is %d\n", Media
.DeviceType
));
252 DEBUG ((DEBUG_INFO
, "PeiCdExpress MediaPresent is %d\n", Media
.MediaPresent
));
253 DEBUG ((DEBUG_INFO
, "PeiCdExpress BlockSize is 0x%x\n", Media
.BlockSize
));
256 DEBUG ((DEBUG_INFO
, "PeiCdExpress Status is %d\n", Status
));
258 DEBUG ((DEBUG_INFO
, "IndexBlockDevice is %d\n", IndexBlockDevice
));
259 PrivateData
->CapsuleData
[PrivateData
->CapsuleCount
].IndexBlock
= IndexBlockDevice
;
261 PrivateData
->CapsuleData
[PrivateData
->CapsuleCount
].BlockIo2
= BlockIo2Ppi
;
263 PrivateData
->CapsuleData
[PrivateData
->CapsuleCount
].BlockIo
= BlockIoPpi
;
265 Status
= FindRecoveryCapsules (PrivateData
);
266 DEBUG ((DEBUG_INFO
, "Status is %d\n", Status
));
268 if (EFI_ERROR (Status
)) {
272 PrivateData
->CapsuleCount
++;
281 Finds out the recovery capsule in the current volume.
283 @param PrivateData The private data structure that contains recovery module information.
285 @retval EFI_SUCCESS The recovery capsule is successfully found in the volume.
286 @retval EFI_NOT_FOUND The recovery capsule is not found in the volume.
291 FindRecoveryCapsules (
292 IN OUT PEI_CD_EXPRESS_PRIVATE_DATA
*PrivateData
297 EFI_PEI_RECOVERY_BLOCK_IO_PPI
*BlockIoPpi
;
298 EFI_PEI_RECOVERY_BLOCK_IO2_PPI
*BlockIo2Ppi
;
304 PEI_CD_EXPRESS_DIR_FILE_RECORD
*RoorDirRecord
;
305 UINTN VolumeSpaceSize
;
306 BOOLEAN StartOfVolume
;
308 UINTN IndexBlockDevice
;
310 Buffer
= PrivateData
->BlockBuffer
;
311 BufferSize
= PEI_CD_BLOCK_SIZE
;
315 // The volume descriptor starts on Lba 16
317 IndexBlockDevice
= PrivateData
->CapsuleData
[PrivateData
->CapsuleCount
].IndexBlock
;
318 BlockIoPpi
= PrivateData
->CapsuleData
[PrivateData
->CapsuleCount
].BlockIo
;
319 BlockIo2Ppi
= PrivateData
->CapsuleData
[PrivateData
->CapsuleCount
].BlockIo2
;
322 StartOfVolume
= TRUE
;
326 SetMem (Buffer
, BufferSize
, 0);
327 if (BlockIo2Ppi
!= NULL
) {
328 Status
= BlockIo2Ppi
->ReadBlocks (
329 (EFI_PEI_SERVICES
**) GetPeiServicesTablePointer (),
337 Status
= BlockIoPpi
->ReadBlocks (
338 (EFI_PEI_SERVICES
**) GetPeiServicesTablePointer (),
346 if (EFI_ERROR (Status
)) {
350 StandardID
= (UINT8
*) (Buffer
+ PEI_CD_EXPRESS_STANDARD_ID_OFFSET
);
351 if (!StringCmp (StandardID
, (UINT8
*) PEI_CD_STANDARD_ID
, PEI_CD_EXPRESS_STANDARD_ID_SIZE
, TRUE
)) {
357 StartOfVolume
= FALSE
;
360 Type
= *(UINT8
*) (Buffer
+ PEI_CD_EXPRESS_VOLUME_TYPE_OFFSET
);
361 if (Type
== PEI_CD_EXPRESS_VOLUME_TYPE_TERMINATOR
) {
362 if (VolumeSpaceSize
== 0) {
365 Lba
= (OriginalLBA
+ VolumeSpaceSize
);
367 StartOfVolume
= TRUE
;
372 if (Type
!= PEI_CD_EXPRESS_VOLUME_TYPE_PRIMARY
) {
377 VolumeSpaceSize
= *(UINT32
*) (Buffer
+ PEI_CD_EXPRESS_VOLUME_SPACE_OFFSET
);
379 RoorDirRecord
= (PEI_CD_EXPRESS_DIR_FILE_RECORD
*) (Buffer
+ PEI_CD_EXPRESS_ROOT_DIR_RECORD_OFFSET
);
380 RootDirLBA
= RoorDirRecord
->LocationOfExtent
[0];
382 Status
= RetrieveCapsuleFileFromRoot (PrivateData
, BlockIoPpi
, BlockIo2Ppi
, IndexBlockDevice
, RootDirLBA
);
383 if (!EFI_ERROR (Status
)) {
385 // Just look for the first primary descriptor
393 return EFI_NOT_FOUND
;
397 Retrieves the recovery capsule in root directory of the current volume.
399 @param PrivateData The private data structure that contains recovery module information.
400 @param BlockIoPpi The Block IO PPI used to access the volume.
401 @param BlockIo2Ppi The Block IO 2 PPI used to access the volume.
402 @param IndexBlockDevice The index of current block device.
403 @param Lba The starting logic block address to retrieve capsule.
405 @retval EFI_SUCCESS The recovery capsule is successfully found in the volume.
406 @retval EFI_NOT_FOUND The recovery capsule is not found in the volume.
412 RetrieveCapsuleFileFromRoot (
413 IN OUT PEI_CD_EXPRESS_PRIVATE_DATA
*PrivateData
,
414 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI
*BlockIoPpi
,
415 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI
*BlockIo2Ppi
,
416 IN UINTN IndexBlockDevice
,
423 PEI_CD_EXPRESS_DIR_FILE_RECORD
*FileRecord
;
426 Buffer
= PrivateData
->BlockBuffer
;
427 BufferSize
= PEI_CD_BLOCK_SIZE
;
429 SetMem (Buffer
, BufferSize
, 0);
431 if (BlockIo2Ppi
!= NULL
) {
432 Status
= BlockIo2Ppi
->ReadBlocks (
433 (EFI_PEI_SERVICES
**) GetPeiServicesTablePointer (),
441 Status
= BlockIoPpi
->ReadBlocks (
442 (EFI_PEI_SERVICES
**) GetPeiServicesTablePointer (),
450 if (EFI_ERROR (Status
)) {
455 FileRecord
= (PEI_CD_EXPRESS_DIR_FILE_RECORD
*) Buffer
;
457 if (FileRecord
->Length
== 0) {
461 // Not intend to check other flag now
463 if ((FileRecord
->Flag
& PEI_CD_EXPRESS_DIR_FILE_REC_FLAG_ISDIR
) != 0) {
464 Buffer
+= FileRecord
->Length
;
468 for (Index
= 0; Index
< FileRecord
->FileIDLength
; Index
++) {
469 if (FileRecord
->FileID
[Index
] == ';') {
474 if (Index
!= mRecoveryFileNameSize
- 1) {
475 Buffer
+= FileRecord
->Length
;
479 if (!StringCmp (FileRecord
->FileID
, (UINT8
*)mRecoveryFileName
, mRecoveryFileNameSize
- 1, FALSE
)) {
480 Buffer
+= FileRecord
->Length
;
484 PrivateData
->CapsuleData
[PrivateData
->CapsuleCount
].CapsuleStartLBA
= FileRecord
->LocationOfExtent
[0];
485 PrivateData
->CapsuleData
[PrivateData
->CapsuleCount
].CapsuleBlockAlignedSize
=
487 FileRecord
->DataLength
[0] /
492 PrivateData
->CapsuleData
[PrivateData
->CapsuleCount
].CapsuleSize
= FileRecord
->DataLength
[0];
497 return EFI_NOT_FOUND
;
501 Returns the number of DXE capsules residing on the device.
503 This function searches for DXE capsules from the associated device and returns
504 the number and maximum size in bytes of the capsules discovered. Entry 1 is
505 assumed to be the highest load priority and entry N is assumed to be the lowest
508 @param[in] PeiServices General-purpose services that are available
510 @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
512 @param[out] NumberRecoveryCapsules Pointer to a caller-allocated UINTN. On
513 output, *NumberRecoveryCapsules contains
514 the number of recovery capsule images
515 available for retrieval from this PEIM
518 @retval EFI_SUCCESS One or more capsules were discovered.
519 @retval EFI_DEVICE_ERROR A device error occurred.
520 @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
525 GetNumberRecoveryCapsules (
526 IN EFI_PEI_SERVICES
**PeiServices
,
527 IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
*This
,
528 OUT UINTN
*NumberRecoveryCapsules
531 PEI_CD_EXPRESS_PRIVATE_DATA
*PrivateData
;
533 PrivateData
= PEI_CD_EXPRESS_PRIVATE_DATA_FROM_THIS (This
);
534 UpdateBlocksAndVolumes (PrivateData
, TRUE
);
535 UpdateBlocksAndVolumes (PrivateData
, FALSE
);
536 *NumberRecoveryCapsules
= PrivateData
->CapsuleCount
;
538 if (*NumberRecoveryCapsules
== 0) {
539 return EFI_NOT_FOUND
;
546 Returns the size and type of the requested recovery capsule.
548 This function gets the size and type of the capsule specified by CapsuleInstance.
550 @param[in] PeiServices General-purpose services that are available to every PEIM
551 @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
553 @param[in] CapsuleInstance Specifies for which capsule instance to retrieve
554 the information. This parameter must be between
555 one and the value returned by GetNumberRecoveryCapsules()
556 in NumberRecoveryCapsules.
557 @param[out] Size A pointer to a caller-allocated UINTN in which
558 the size of the requested recovery module is
560 @param[out] CapsuleType A pointer to a caller-allocated EFI_GUID in which
561 the type of the requested recovery capsule is
562 returned. The semantic meaning of the value
563 returned is defined by the implementation.
565 @retval EFI_SUCCESS One or more capsules were discovered.
566 @retval EFI_DEVICE_ERROR A device error occurred.
567 @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
572 GetRecoveryCapsuleInfo (
573 IN EFI_PEI_SERVICES
**PeiServices
,
574 IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
*This
,
575 IN UINTN CapsuleInstance
,
577 OUT EFI_GUID
*CapsuleType
580 PEI_CD_EXPRESS_PRIVATE_DATA
*PrivateData
;
581 UINTN NumberRecoveryCapsules
;
584 Status
= GetNumberRecoveryCapsules (PeiServices
, This
, &NumberRecoveryCapsules
);
586 if (EFI_ERROR (Status
)) {
590 if ((CapsuleInstance
== 0) || (CapsuleInstance
> NumberRecoveryCapsules
)) {
591 return EFI_NOT_FOUND
;
594 PrivateData
= PEI_CD_EXPRESS_PRIVATE_DATA_FROM_THIS (This
);
596 *Size
= PrivateData
->CapsuleData
[CapsuleInstance
- 1].CapsuleSize
;
599 &gRecoveryOnDataCdGuid
,
607 Loads a DXE capsule from some media into memory.
609 This function, by whatever mechanism, retrieves a DXE capsule from some device
610 and loads it into memory. Note that the published interface is device neutral.
612 @param[in] PeiServices General-purpose services that are available
614 @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
616 @param[in] CapsuleInstance Specifies which capsule instance to retrieve.
617 @param[out] Buffer Specifies a caller-allocated buffer in which
618 the requested recovery capsule will be returned.
620 @retval EFI_SUCCESS The capsule was loaded correctly.
621 @retval EFI_DEVICE_ERROR A device error occurred.
622 @retval EFI_NOT_FOUND A requested recovery DXE capsule cannot be found.
627 LoadRecoveryCapsule (
628 IN EFI_PEI_SERVICES
**PeiServices
,
629 IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
*This
,
630 IN UINTN CapsuleInstance
,
635 PEI_CD_EXPRESS_PRIVATE_DATA
*PrivateData
;
636 EFI_PEI_RECOVERY_BLOCK_IO_PPI
*BlockIoPpi
;
637 EFI_PEI_RECOVERY_BLOCK_IO2_PPI
*BlockIo2Ppi
;
638 UINTN NumberRecoveryCapsules
;
640 Status
= GetNumberRecoveryCapsules (PeiServices
, This
, &NumberRecoveryCapsules
);
642 if (EFI_ERROR (Status
)) {
646 if ((CapsuleInstance
== 0) || (CapsuleInstance
> NumberRecoveryCapsules
)) {
647 return EFI_NOT_FOUND
;
650 PrivateData
= PEI_CD_EXPRESS_PRIVATE_DATA_FROM_THIS (This
);
651 BlockIoPpi
= PrivateData
->CapsuleData
[CapsuleInstance
- 1].BlockIo
;
652 BlockIo2Ppi
= PrivateData
->CapsuleData
[CapsuleInstance
- 1].BlockIo2
;
654 if (BlockIo2Ppi
!= NULL
) {
655 Status
= BlockIo2Ppi
->ReadBlocks (
658 PrivateData
->CapsuleData
[CapsuleInstance
- 1].IndexBlock
,
659 PrivateData
->CapsuleData
[CapsuleInstance
- 1].CapsuleStartLBA
,
660 PrivateData
->CapsuleData
[CapsuleInstance
- 1].CapsuleBlockAlignedSize
,
664 Status
= BlockIoPpi
->ReadBlocks (
667 PrivateData
->CapsuleData
[CapsuleInstance
- 1].IndexBlock
,
668 PrivateData
->CapsuleData
[CapsuleInstance
- 1].CapsuleStartLBA
,
669 PrivateData
->CapsuleData
[CapsuleInstance
- 1].CapsuleBlockAlignedSize
,
677 This function compares two ASCII strings in case sensitive/insensitive way.
679 @param Source1 The first string.
680 @param Source2 The second string.
681 @param Size The maximum comparison length.
682 @param CaseSensitive Flag to indicate whether the comparison is case sensitive.
684 @retval TRUE The two strings are the same.
685 @retval FALSE The two string are not the same.
693 IN BOOLEAN CaseSensitive
699 for (Index
= 0; Index
< Size
; Index
++) {
700 if (Source1
[Index
] == Source2
[Index
]) {
704 if (!CaseSensitive
) {
705 Dif
= (UINT8
) ((Source1
[Index
] > Source2
[Index
]) ? (Source1
[Index
] - Source2
[Index
]) : (Source2
[Index
] - Source1
[Index
]));
706 if (Dif
== ('a' - 'A')) {