2 Source file for CD recovery PEIM
4 Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions
8 of the BSD License which accompanies this distribution. The
9 full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 #include "PeiCdExpress.h"
19 PEI_CD_EXPRESS_PRIVATE_DATA
*mPrivateData
= NULL
;
22 Installs the Device Recovery Module PPI, Initialize BlockIo Ppi
23 installation notification
25 @param FileHandle The file handle of the image.
26 @param PeiServices General purpose services available to every PEIM.
28 @retval EFI_SUCCESS The function completed successfully.
29 @retval EFI_OUT_OF_RESOURCES There is not enough system memory.
35 IN EFI_PEI_FILE_HANDLE FileHandle
,
36 IN CONST EFI_PEI_SERVICES
**PeiServices
40 PEI_CD_EXPRESS_PRIVATE_DATA
*PrivateData
;
42 if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle
))) {
46 PrivateData
= AllocatePages (EFI_SIZE_TO_PAGES (sizeof (*PrivateData
)));
47 if (PrivateData
== NULL
) {
48 return EFI_OUT_OF_RESOURCES
;
52 // Initialize Private Data (to zero, as is required by subsequent operations)
54 ZeroMem (PrivateData
, sizeof (*PrivateData
));
55 PrivateData
->Signature
= PEI_CD_EXPRESS_PRIVATE_DATA_SIGNATURE
;
57 PrivateData
->BlockBuffer
= AllocatePages (EFI_SIZE_TO_PAGES (PEI_CD_BLOCK_SIZE
));
58 if (PrivateData
->BlockBuffer
== NULL
) {
59 return EFI_OUT_OF_RESOURCES
;
62 PrivateData
->CapsuleCount
= 0;
63 Status
= UpdateBlocksAndVolumes (PrivateData
, TRUE
);
64 Status
= UpdateBlocksAndVolumes (PrivateData
, FALSE
);
69 PrivateData
->DeviceRecoveryPpi
.GetNumberRecoveryCapsules
= GetNumberRecoveryCapsules
;
70 PrivateData
->DeviceRecoveryPpi
.GetRecoveryCapsuleInfo
= GetRecoveryCapsuleInfo
;
71 PrivateData
->DeviceRecoveryPpi
.LoadRecoveryCapsule
= LoadRecoveryCapsule
;
73 PrivateData
->PpiDescriptor
.Flags
= (EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
);
74 PrivateData
->PpiDescriptor
.Guid
= &gEfiPeiDeviceRecoveryModulePpiGuid
;
75 PrivateData
->PpiDescriptor
.Ppi
= &PrivateData
->DeviceRecoveryPpi
;
77 Status
= PeiServicesInstallPpi (&PrivateData
->PpiDescriptor
);
78 if (EFI_ERROR (Status
)) {
79 return EFI_OUT_OF_RESOURCES
;
82 // PrivateData is allocated now, set it to the module variable
84 mPrivateData
= PrivateData
;
87 // Installs Block Io Ppi notification function
89 PrivateData
->NotifyDescriptor
.Flags
=
91 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
93 PrivateData
->NotifyDescriptor
.Guid
= &gEfiPeiVirtualBlockIoPpiGuid
;
94 PrivateData
->NotifyDescriptor
.Notify
= BlockIoNotifyEntry
;
96 PrivateData
->NotifyDescriptor2
.Flags
=
98 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
|
99 EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
101 PrivateData
->NotifyDescriptor2
.Guid
= &gEfiPeiVirtualBlockIo2PpiGuid
;
102 PrivateData
->NotifyDescriptor2
.Notify
= BlockIoNotifyEntry
;
104 return PeiServicesNotifyPpi (&PrivateData
->NotifyDescriptor
);
109 BlockIo installation notification function.
111 This function finds out all the current Block IO PPIs in the system and add them
114 @param PeiServices Indirect reference to the PEI Services Table.
115 @param NotifyDescriptor Address of the notification descriptor data structure.
116 @param Ppi Address of the PPI that was installed.
118 @retval EFI_SUCCESS The function completes successfully.
124 IN EFI_PEI_SERVICES
**PeiServices
,
125 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDescriptor
,
129 if (CompareGuid (NotifyDescriptor
->Guid
, &gEfiPeiVirtualBlockIo2PpiGuid
)) {
130 UpdateBlocksAndVolumes (mPrivateData
, TRUE
);
132 UpdateBlocksAndVolumes (mPrivateData
, FALSE
);
139 Finds out all the current Block IO PPIs in the system and add them into private data.
141 @param PrivateData The private data structure that contains recovery module information.
142 @param BlockIo2 Boolean to show whether using BlockIo2 or BlockIo.
144 @retval EFI_SUCCESS The blocks and volumes are updated successfully.
148 UpdateBlocksAndVolumes (
149 IN OUT PEI_CD_EXPRESS_PRIVATE_DATA
*PrivateData
,
154 EFI_PEI_PPI_DESCRIPTOR
*TempPpiDescriptor
;
155 UINTN BlockIoPpiInstance
;
156 EFI_PEI_RECOVERY_BLOCK_IO_PPI
*BlockIoPpi
;
157 EFI_PEI_RECOVERY_BLOCK_IO2_PPI
*BlockIo2Ppi
;
158 UINTN NumberBlockDevices
;
159 UINTN IndexBlockDevice
;
160 EFI_PEI_BLOCK_IO_MEDIA Media
;
161 EFI_PEI_BLOCK_IO2_MEDIA Media2
;
162 EFI_PEI_SERVICES
**PeiServices
;
164 IndexBlockDevice
= 0;
166 // Find out all Block Io Ppi instances within the system
167 // Assuming all device Block Io Peims are dispatched already
169 for (BlockIoPpiInstance
= 0; BlockIoPpiInstance
< PEI_CD_EXPRESS_MAX_BLOCK_IO_PPI
; BlockIoPpiInstance
++) {
171 Status
= PeiServicesLocatePpi (
172 &gEfiPeiVirtualBlockIo2PpiGuid
,
175 (VOID
**) &BlockIo2Ppi
178 Status
= PeiServicesLocatePpi (
179 &gEfiPeiVirtualBlockIoPpiGuid
,
182 (VOID
**) &BlockIoPpi
185 if (EFI_ERROR (Status
)) {
187 // Done with all Block Io Ppis
192 PeiServices
= (EFI_PEI_SERVICES
**) GetPeiServicesTablePointer ();
194 Status
= BlockIo2Ppi
->GetNumberOfBlockDevices (
200 Status
= BlockIoPpi
->GetNumberOfBlockDevices (
206 if (EFI_ERROR (Status
) || (NumberBlockDevices
== 0)) {
210 // Just retrieve the first block, should emulate all blocks.
212 for (IndexBlockDevice
= 1; IndexBlockDevice
<= NumberBlockDevices
&& PrivateData
->CapsuleCount
< PEI_CD_EXPRESS_MAX_CAPSULE_NUMBER
; IndexBlockDevice
++) {
214 Status
= BlockIo2Ppi
->GetBlockDeviceMediaInfo (
220 if (EFI_ERROR (Status
) ||
221 !Media2
.MediaPresent
||
222 ((Media2
.InterfaceType
!= MSG_ATAPI_DP
) && (Media2
.InterfaceType
!= MSG_USB_DP
)) ||
223 (Media2
.BlockSize
!= PEI_CD_BLOCK_SIZE
)
227 DEBUG ((EFI_D_INFO
, "PeiCdExpress InterfaceType is %d\n", Media2
.InterfaceType
));
228 DEBUG ((EFI_D_INFO
, "PeiCdExpress MediaPresent is %d\n", Media2
.MediaPresent
));
229 DEBUG ((EFI_D_INFO
, "PeiCdExpress BlockSize is 0x%x\n", Media2
.BlockSize
));
231 Status
= BlockIoPpi
->GetBlockDeviceMediaInfo (
237 if (EFI_ERROR (Status
) ||
238 !Media
.MediaPresent
||
239 ((Media
.DeviceType
!= IdeCDROM
) && (Media
.DeviceType
!= UsbMassStorage
)) ||
240 (Media
.BlockSize
!= PEI_CD_BLOCK_SIZE
)
244 DEBUG ((EFI_D_INFO
, "PeiCdExpress DeviceType is %d\n", Media
.DeviceType
));
245 DEBUG ((EFI_D_INFO
, "PeiCdExpress MediaPresent is %d\n", Media
.MediaPresent
));
246 DEBUG ((EFI_D_INFO
, "PeiCdExpress BlockSize is 0x%x\n", Media
.BlockSize
));
249 DEBUG ((EFI_D_INFO
, "PeiCdExpress Status is %d\n", Status
));
251 DEBUG ((EFI_D_INFO
, "IndexBlockDevice is %d\n", IndexBlockDevice
));
252 PrivateData
->CapsuleData
[PrivateData
->CapsuleCount
].IndexBlock
= IndexBlockDevice
;
254 PrivateData
->CapsuleData
[PrivateData
->CapsuleCount
].BlockIo2
= BlockIo2Ppi
;
256 PrivateData
->CapsuleData
[PrivateData
->CapsuleCount
].BlockIo
= BlockIoPpi
;
258 Status
= FindRecoveryCapsules (PrivateData
);
259 DEBUG ((EFI_D_INFO
, "Status is %d\n", Status
));
261 if (EFI_ERROR (Status
)) {
265 PrivateData
->CapsuleCount
++;
274 Finds out the recovery capsule in the current volume.
276 @param PrivateData The private data structure that contains recovery module information.
278 @retval EFI_SUCCESS The recovery capsule is successfully found in the volume.
279 @retval EFI_NOT_FOUND The recovery capsule is not found in the volume.
284 FindRecoveryCapsules (
285 IN OUT PEI_CD_EXPRESS_PRIVATE_DATA
*PrivateData
290 EFI_PEI_RECOVERY_BLOCK_IO_PPI
*BlockIoPpi
;
291 EFI_PEI_RECOVERY_BLOCK_IO2_PPI
*BlockIo2Ppi
;
297 PEI_CD_EXPRESS_DIR_FILE_RECORD
*RoorDirRecord
;
298 UINTN VolumeSpaceSize
;
299 BOOLEAN StartOfVolume
;
301 UINTN IndexBlockDevice
;
303 Buffer
= PrivateData
->BlockBuffer
;
304 BufferSize
= PEI_CD_BLOCK_SIZE
;
308 // The volume descriptor starts on Lba 16
310 IndexBlockDevice
= PrivateData
->CapsuleData
[PrivateData
->CapsuleCount
].IndexBlock
;
311 BlockIoPpi
= PrivateData
->CapsuleData
[PrivateData
->CapsuleCount
].BlockIo
;
312 BlockIo2Ppi
= PrivateData
->CapsuleData
[PrivateData
->CapsuleCount
].BlockIo2
;
315 StartOfVolume
= TRUE
;
319 SetMem (Buffer
, BufferSize
, 0);
320 if (BlockIo2Ppi
!= NULL
) {
321 Status
= BlockIo2Ppi
->ReadBlocks (
322 (EFI_PEI_SERVICES
**) GetPeiServicesTablePointer (),
330 Status
= BlockIoPpi
->ReadBlocks (
331 (EFI_PEI_SERVICES
**) GetPeiServicesTablePointer (),
339 if (EFI_ERROR (Status
)) {
343 StandardID
= (UINT8
*) (Buffer
+ PEI_CD_EXPRESS_STANDARD_ID_OFFSET
);
344 if (!StringCmp (StandardID
, (UINT8
*) PEI_CD_STANDARD_ID
, PEI_CD_EXPRESS_STANDARD_ID_SIZE
, TRUE
)) {
350 StartOfVolume
= FALSE
;
353 Type
= *(UINT8
*) (Buffer
+ PEI_CD_EXPRESS_VOLUME_TYPE_OFFSET
);
354 if (Type
== PEI_CD_EXPRESS_VOLUME_TYPE_TERMINATOR
) {
355 if (VolumeSpaceSize
== 0) {
358 Lba
= (OriginalLBA
+ VolumeSpaceSize
);
360 StartOfVolume
= TRUE
;
365 if (Type
!= PEI_CD_EXPRESS_VOLUME_TYPE_PRIMARY
) {
370 VolumeSpaceSize
= *(UINT32
*) (Buffer
+ PEI_CD_EXPRESS_VOLUME_SPACE_OFFSET
);
372 RoorDirRecord
= (PEI_CD_EXPRESS_DIR_FILE_RECORD
*) (Buffer
+ PEI_CD_EXPRESS_ROOT_DIR_RECORD_OFFSET
);
373 RootDirLBA
= RoorDirRecord
->LocationOfExtent
[0];
375 Status
= RetrieveCapsuleFileFromRoot (PrivateData
, BlockIoPpi
, BlockIo2Ppi
, IndexBlockDevice
, RootDirLBA
);
376 if (!EFI_ERROR (Status
)) {
378 // Just look for the first primary descriptor
386 return EFI_NOT_FOUND
;
390 Retrieves the recovery capsule in root directory of the current volume.
392 @param PrivateData The private data structure that contains recovery module information.
393 @param BlockIoPpi The Block IO PPI used to access the volume.
394 @param BlockIo2Ppi The Block IO 2 PPI used to access the volume.
395 @param IndexBlockDevice The index of current block device.
396 @param Lba The starting logic block address to retrieve capsule.
398 @retval EFI_SUCCESS The recovery capsule is successfully found in the volume.
399 @retval EFI_NOT_FOUND The recovery capsule is not found in the volume.
405 RetrieveCapsuleFileFromRoot (
406 IN OUT PEI_CD_EXPRESS_PRIVATE_DATA
*PrivateData
,
407 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI
*BlockIoPpi
,
408 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI
*BlockIo2Ppi
,
409 IN UINTN IndexBlockDevice
,
416 PEI_CD_EXPRESS_DIR_FILE_RECORD
*FileRecord
;
419 Buffer
= PrivateData
->BlockBuffer
;
420 BufferSize
= PEI_CD_BLOCK_SIZE
;
422 SetMem (Buffer
, BufferSize
, 0);
424 if (BlockIo2Ppi
!= NULL
) {
425 Status
= BlockIo2Ppi
->ReadBlocks (
426 (EFI_PEI_SERVICES
**) GetPeiServicesTablePointer (),
434 Status
= BlockIoPpi
->ReadBlocks (
435 (EFI_PEI_SERVICES
**) GetPeiServicesTablePointer (),
443 if (EFI_ERROR (Status
)) {
448 FileRecord
= (PEI_CD_EXPRESS_DIR_FILE_RECORD
*) Buffer
;
450 if (FileRecord
->Length
== 0) {
454 // Not intend to check other flag now
456 if ((FileRecord
->Flag
& PEI_CD_EXPRESS_DIR_FILE_REC_FLAG_ISDIR
) != 0) {
457 Buffer
+= FileRecord
->Length
;
461 for (Index
= 0; Index
< FileRecord
->FileIDLength
; Index
++) {
462 if (FileRecord
->FileID
[Index
] == ';') {
467 if (Index
!= (sizeof (PEI_RECOVERY_FILE_NAME
) - 1)) {
468 Buffer
+= FileRecord
->Length
;
472 if (!StringCmp (FileRecord
->FileID
, (UINT8
*) PEI_RECOVERY_FILE_NAME
, sizeof (PEI_RECOVERY_FILE_NAME
) - 1, FALSE
)) {
473 Buffer
+= FileRecord
->Length
;
477 PrivateData
->CapsuleData
[PrivateData
->CapsuleCount
].CapsuleStartLBA
= FileRecord
->LocationOfExtent
[0];
478 PrivateData
->CapsuleData
[PrivateData
->CapsuleCount
].CapsuleSize
=
480 FileRecord
->DataLength
[0] /
489 return EFI_NOT_FOUND
;
493 Returns the number of DXE capsules residing on the device.
495 This function searches for DXE capsules from the associated device and returns
496 the number and maximum size in bytes of the capsules discovered. Entry 1 is
497 assumed to be the highest load priority and entry N is assumed to be the lowest
500 @param[in] PeiServices General-purpose services that are available
502 @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
504 @param[out] NumberRecoveryCapsules Pointer to a caller-allocated UINTN. On
505 output, *NumberRecoveryCapsules contains
506 the number of recovery capsule images
507 available for retrieval from this PEIM
510 @retval EFI_SUCCESS One or more capsules were discovered.
511 @retval EFI_DEVICE_ERROR A device error occurred.
512 @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
517 GetNumberRecoveryCapsules (
518 IN EFI_PEI_SERVICES
**PeiServices
,
519 IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
*This
,
520 OUT UINTN
*NumberRecoveryCapsules
523 PEI_CD_EXPRESS_PRIVATE_DATA
*PrivateData
;
525 PrivateData
= PEI_CD_EXPRESS_PRIVATE_DATA_FROM_THIS (This
);
526 UpdateBlocksAndVolumes (PrivateData
, TRUE
);
527 UpdateBlocksAndVolumes (PrivateData
, FALSE
);
528 *NumberRecoveryCapsules
= PrivateData
->CapsuleCount
;
530 if (*NumberRecoveryCapsules
== 0) {
531 return EFI_NOT_FOUND
;
538 Returns the size and type of the requested recovery capsule.
540 This function gets the size and type of the capsule specified by CapsuleInstance.
542 @param[in] PeiServices General-purpose services that are available to every PEIM
543 @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
545 @param[in] CapsuleInstance Specifies for which capsule instance to retrieve
546 the information. This parameter must be between
547 one and the value returned by GetNumberRecoveryCapsules()
548 in NumberRecoveryCapsules.
549 @param[out] Size A pointer to a caller-allocated UINTN in which
550 the size of the requested recovery module is
552 @param[out] CapsuleType A pointer to a caller-allocated EFI_GUID in which
553 the type of the requested recovery capsule is
554 returned. The semantic meaning of the value
555 returned is defined by the implementation.
557 @retval EFI_SUCCESS One or more capsules were discovered.
558 @retval EFI_DEVICE_ERROR A device error occurred.
559 @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
564 GetRecoveryCapsuleInfo (
565 IN EFI_PEI_SERVICES
**PeiServices
,
566 IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
*This
,
567 IN UINTN CapsuleInstance
,
569 OUT EFI_GUID
*CapsuleType
572 PEI_CD_EXPRESS_PRIVATE_DATA
*PrivateData
;
573 UINTN NumberRecoveryCapsules
;
576 Status
= GetNumberRecoveryCapsules (PeiServices
, This
, &NumberRecoveryCapsules
);
578 if (EFI_ERROR (Status
)) {
582 if (FeaturePcdGet (PcdFrameworkCompatibilitySupport
)) {
583 CapsuleInstance
= CapsuleInstance
+ 1;
586 if ((CapsuleInstance
== 0) || (CapsuleInstance
> NumberRecoveryCapsules
)) {
587 return EFI_NOT_FOUND
;
590 PrivateData
= PEI_CD_EXPRESS_PRIVATE_DATA_FROM_THIS (This
);
592 *Size
= PrivateData
->CapsuleData
[CapsuleInstance
- 1].CapsuleSize
;
595 &gRecoveryOnDataCdGuid
,
603 Loads a DXE capsule from some media into memory.
605 This function, by whatever mechanism, retrieves a DXE capsule from some device
606 and loads it into memory. Note that the published interface is device neutral.
608 @param[in] PeiServices General-purpose services that are available
610 @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
612 @param[in] CapsuleInstance Specifies which capsule instance to retrieve.
613 @param[out] Buffer Specifies a caller-allocated buffer in which
614 the requested recovery capsule will be returned.
616 @retval EFI_SUCCESS The capsule was loaded correctly.
617 @retval EFI_DEVICE_ERROR A device error occurred.
618 @retval EFI_NOT_FOUND A requested recovery DXE capsule cannot be found.
623 LoadRecoveryCapsule (
624 IN EFI_PEI_SERVICES
**PeiServices
,
625 IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
*This
,
626 IN UINTN CapsuleInstance
,
631 PEI_CD_EXPRESS_PRIVATE_DATA
*PrivateData
;
632 EFI_PEI_RECOVERY_BLOCK_IO_PPI
*BlockIoPpi
;
633 EFI_PEI_RECOVERY_BLOCK_IO2_PPI
*BlockIo2Ppi
;
634 UINTN NumberRecoveryCapsules
;
636 Status
= GetNumberRecoveryCapsules (PeiServices
, This
, &NumberRecoveryCapsules
);
638 if (EFI_ERROR (Status
)) {
642 if (FeaturePcdGet (PcdFrameworkCompatibilitySupport
)) {
643 CapsuleInstance
= CapsuleInstance
+ 1;
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].CapsuleSize
,
664 Status
= BlockIoPpi
->ReadBlocks (
667 PrivateData
->CapsuleData
[CapsuleInstance
- 1].IndexBlock
,
668 PrivateData
->CapsuleData
[CapsuleInstance
- 1].CapsuleStartLBA
,
669 PrivateData
->CapsuleData
[CapsuleInstance
- 1].CapsuleSize
,
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')) {