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;
168 // Find out all Block Io Ppi instances within the system
169 // Assuming all device Block Io Peims are dispatched already
171 for (BlockIoPpiInstance
= 0; BlockIoPpiInstance
< PEI_CD_EXPRESS_MAX_BLOCK_IO_PPI
; BlockIoPpiInstance
++) {
173 Status
= PeiServicesLocatePpi (
174 &gEfiPeiVirtualBlockIo2PpiGuid
,
177 (VOID
**) &BlockIo2Ppi
180 Status
= PeiServicesLocatePpi (
181 &gEfiPeiVirtualBlockIoPpiGuid
,
184 (VOID
**) &BlockIoPpi
187 if (EFI_ERROR (Status
)) {
189 // Done with all Block Io Ppis
194 PeiServices
= (EFI_PEI_SERVICES
**) GetPeiServicesTablePointer ();
196 Status
= BlockIo2Ppi
->GetNumberOfBlockDevices (
202 Status
= BlockIoPpi
->GetNumberOfBlockDevices (
208 if (EFI_ERROR (Status
) || (NumberBlockDevices
== 0)) {
212 // Just retrieve the first block, should emulate all blocks.
214 for (IndexBlockDevice
= 1; IndexBlockDevice
<= NumberBlockDevices
&& PrivateData
->CapsuleCount
< PEI_CD_EXPRESS_MAX_CAPSULE_NUMBER
; IndexBlockDevice
++) {
216 Status
= BlockIo2Ppi
->GetBlockDeviceMediaInfo (
222 if (EFI_ERROR (Status
) ||
223 !Media2
.MediaPresent
||
224 ((Media2
.InterfaceType
!= MSG_ATAPI_DP
) && (Media2
.InterfaceType
!= MSG_USB_DP
)) ||
225 (Media2
.BlockSize
!= PEI_CD_BLOCK_SIZE
)
229 DEBUG ((EFI_D_INFO
, "PeiCdExpress InterfaceType is %d\n", Media2
.InterfaceType
));
230 DEBUG ((EFI_D_INFO
, "PeiCdExpress MediaPresent is %d\n", Media2
.MediaPresent
));
231 DEBUG ((EFI_D_INFO
, "PeiCdExpress BlockSize is 0x%x\n", Media2
.BlockSize
));
233 Status
= BlockIoPpi
->GetBlockDeviceMediaInfo (
239 if (EFI_ERROR (Status
) ||
240 !Media
.MediaPresent
||
241 ((Media
.DeviceType
!= IdeCDROM
) && (Media
.DeviceType
!= UsbMassStorage
)) ||
242 (Media
.BlockSize
!= PEI_CD_BLOCK_SIZE
)
246 DEBUG ((EFI_D_INFO
, "PeiCdExpress DeviceType is %d\n", Media
.DeviceType
));
247 DEBUG ((EFI_D_INFO
, "PeiCdExpress MediaPresent is %d\n", Media
.MediaPresent
));
248 DEBUG ((EFI_D_INFO
, "PeiCdExpress BlockSize is 0x%x\n", Media
.BlockSize
));
251 DEBUG ((EFI_D_INFO
, "PeiCdExpress Status is %d\n", Status
));
253 DEBUG ((EFI_D_INFO
, "IndexBlockDevice is %d\n", IndexBlockDevice
));
254 PrivateData
->CapsuleData
[PrivateData
->CapsuleCount
].IndexBlock
= IndexBlockDevice
;
256 PrivateData
->CapsuleData
[PrivateData
->CapsuleCount
].BlockIo2
= BlockIo2Ppi
;
258 PrivateData
->CapsuleData
[PrivateData
->CapsuleCount
].BlockIo
= BlockIoPpi
;
260 Status
= FindRecoveryCapsules (PrivateData
);
261 DEBUG ((EFI_D_INFO
, "Status is %d\n", Status
));
263 if (EFI_ERROR (Status
)) {
267 PrivateData
->CapsuleCount
++;
276 Finds out the recovery capsule in the current volume.
278 @param PrivateData The private data structure that contains recovery module information.
280 @retval EFI_SUCCESS The recovery capsule is successfully found in the volume.
281 @retval EFI_NOT_FOUND The recovery capsule is not found in the volume.
286 FindRecoveryCapsules (
287 IN OUT PEI_CD_EXPRESS_PRIVATE_DATA
*PrivateData
292 EFI_PEI_RECOVERY_BLOCK_IO_PPI
*BlockIoPpi
;
293 EFI_PEI_RECOVERY_BLOCK_IO2_PPI
*BlockIo2Ppi
;
299 PEI_CD_EXPRESS_DIR_FILE_RECORD
*RoorDirRecord
;
300 UINTN VolumeSpaceSize
;
301 BOOLEAN StartOfVolume
;
303 UINTN IndexBlockDevice
;
305 Buffer
= PrivateData
->BlockBuffer
;
306 BufferSize
= PEI_CD_BLOCK_SIZE
;
310 // The volume descriptor starts on Lba 16
312 IndexBlockDevice
= PrivateData
->CapsuleData
[PrivateData
->CapsuleCount
].IndexBlock
;
313 BlockIoPpi
= PrivateData
->CapsuleData
[PrivateData
->CapsuleCount
].BlockIo
;
314 BlockIo2Ppi
= PrivateData
->CapsuleData
[PrivateData
->CapsuleCount
].BlockIo2
;
317 StartOfVolume
= TRUE
;
321 SetMem (Buffer
, BufferSize
, 0);
322 if (BlockIo2Ppi
!= NULL
) {
323 Status
= BlockIo2Ppi
->ReadBlocks (
324 (EFI_PEI_SERVICES
**) GetPeiServicesTablePointer (),
332 Status
= BlockIoPpi
->ReadBlocks (
333 (EFI_PEI_SERVICES
**) GetPeiServicesTablePointer (),
341 if (EFI_ERROR (Status
)) {
345 StandardID
= (UINT8
*) (Buffer
+ PEI_CD_EXPRESS_STANDARD_ID_OFFSET
);
346 if (!StringCmp (StandardID
, (UINT8
*) PEI_CD_STANDARD_ID
, PEI_CD_EXPRESS_STANDARD_ID_SIZE
, TRUE
)) {
352 StartOfVolume
= FALSE
;
355 Type
= *(UINT8
*) (Buffer
+ PEI_CD_EXPRESS_VOLUME_TYPE_OFFSET
);
356 if (Type
== PEI_CD_EXPRESS_VOLUME_TYPE_TERMINATOR
) {
357 if (VolumeSpaceSize
== 0) {
360 Lba
= (OriginalLBA
+ VolumeSpaceSize
);
362 StartOfVolume
= TRUE
;
367 if (Type
!= PEI_CD_EXPRESS_VOLUME_TYPE_PRIMARY
) {
372 VolumeSpaceSize
= *(UINT32
*) (Buffer
+ PEI_CD_EXPRESS_VOLUME_SPACE_OFFSET
);
374 RoorDirRecord
= (PEI_CD_EXPRESS_DIR_FILE_RECORD
*) (Buffer
+ PEI_CD_EXPRESS_ROOT_DIR_RECORD_OFFSET
);
375 RootDirLBA
= RoorDirRecord
->LocationOfExtent
[0];
377 Status
= RetrieveCapsuleFileFromRoot (PrivateData
, BlockIoPpi
, BlockIo2Ppi
, IndexBlockDevice
, RootDirLBA
);
378 if (!EFI_ERROR (Status
)) {
380 // Just look for the first primary descriptor
388 return EFI_NOT_FOUND
;
392 Retrieves the recovery capsule in root directory of the current volume.
394 @param PrivateData The private data structure that contains recovery module information.
395 @param BlockIoPpi The Block IO PPI used to access the volume.
396 @param BlockIo2Ppi The Block IO 2 PPI used to access the volume.
397 @param IndexBlockDevice The index of current block device.
398 @param Lba The starting logic block address to retrieve capsule.
400 @retval EFI_SUCCESS The recovery capsule is successfully found in the volume.
401 @retval EFI_NOT_FOUND The recovery capsule is not found in the volume.
407 RetrieveCapsuleFileFromRoot (
408 IN OUT PEI_CD_EXPRESS_PRIVATE_DATA
*PrivateData
,
409 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI
*BlockIoPpi
,
410 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI
*BlockIo2Ppi
,
411 IN UINTN IndexBlockDevice
,
418 PEI_CD_EXPRESS_DIR_FILE_RECORD
*FileRecord
;
421 Buffer
= PrivateData
->BlockBuffer
;
422 BufferSize
= PEI_CD_BLOCK_SIZE
;
424 SetMem (Buffer
, BufferSize
, 0);
426 if (BlockIo2Ppi
!= NULL
) {
427 Status
= BlockIo2Ppi
->ReadBlocks (
428 (EFI_PEI_SERVICES
**) GetPeiServicesTablePointer (),
436 Status
= BlockIoPpi
->ReadBlocks (
437 (EFI_PEI_SERVICES
**) GetPeiServicesTablePointer (),
445 if (EFI_ERROR (Status
)) {
450 FileRecord
= (PEI_CD_EXPRESS_DIR_FILE_RECORD
*) Buffer
;
452 if (FileRecord
->Length
== 0) {
456 // Not intend to check other flag now
458 if ((FileRecord
->Flag
& PEI_CD_EXPRESS_DIR_FILE_REC_FLAG_ISDIR
) != 0) {
459 Buffer
+= FileRecord
->Length
;
463 for (Index
= 0; Index
< FileRecord
->FileIDLength
; Index
++) {
464 if (FileRecord
->FileID
[Index
] == ';') {
469 if (Index
!= (sizeof (PEI_RECOVERY_FILE_NAME
) - 1)) {
470 Buffer
+= FileRecord
->Length
;
474 if (!StringCmp (FileRecord
->FileID
, (UINT8
*) PEI_RECOVERY_FILE_NAME
, sizeof (PEI_RECOVERY_FILE_NAME
) - 1, FALSE
)) {
475 Buffer
+= FileRecord
->Length
;
479 PrivateData
->CapsuleData
[PrivateData
->CapsuleCount
].CapsuleStartLBA
= FileRecord
->LocationOfExtent
[0];
480 PrivateData
->CapsuleData
[PrivateData
->CapsuleCount
].CapsuleSize
=
482 FileRecord
->DataLength
[0] /
491 return EFI_NOT_FOUND
;
495 Returns the number of DXE capsules residing on the device.
497 This function searches for DXE capsules from the associated device and returns
498 the number and maximum size in bytes of the capsules discovered. Entry 1 is
499 assumed to be the highest load priority and entry N is assumed to be the lowest
502 @param[in] PeiServices General-purpose services that are available
504 @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
506 @param[out] NumberRecoveryCapsules Pointer to a caller-allocated UINTN. On
507 output, *NumberRecoveryCapsules contains
508 the number of recovery capsule images
509 available for retrieval from this PEIM
512 @retval EFI_SUCCESS One or more capsules were discovered.
513 @retval EFI_DEVICE_ERROR A device error occurred.
514 @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
519 GetNumberRecoveryCapsules (
520 IN EFI_PEI_SERVICES
**PeiServices
,
521 IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
*This
,
522 OUT UINTN
*NumberRecoveryCapsules
525 PEI_CD_EXPRESS_PRIVATE_DATA
*PrivateData
;
527 PrivateData
= PEI_CD_EXPRESS_PRIVATE_DATA_FROM_THIS (This
);
528 UpdateBlocksAndVolumes (PrivateData
, TRUE
);
529 UpdateBlocksAndVolumes (PrivateData
, FALSE
);
530 *NumberRecoveryCapsules
= PrivateData
->CapsuleCount
;
532 if (*NumberRecoveryCapsules
== 0) {
533 return EFI_NOT_FOUND
;
540 Returns the size and type of the requested recovery capsule.
542 This function gets the size and type of the capsule specified by CapsuleInstance.
544 @param[in] PeiServices General-purpose services that are available to every PEIM
545 @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
547 @param[in] CapsuleInstance Specifies for which capsule instance to retrieve
548 the information. This parameter must be between
549 one and the value returned by GetNumberRecoveryCapsules()
550 in NumberRecoveryCapsules.
551 @param[out] Size A pointer to a caller-allocated UINTN in which
552 the size of the requested recovery module is
554 @param[out] CapsuleType A pointer to a caller-allocated EFI_GUID in which
555 the type of the requested recovery capsule is
556 returned. The semantic meaning of the value
557 returned is defined by the implementation.
559 @retval EFI_SUCCESS One or more capsules were discovered.
560 @retval EFI_DEVICE_ERROR A device error occurred.
561 @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
566 GetRecoveryCapsuleInfo (
567 IN EFI_PEI_SERVICES
**PeiServices
,
568 IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
*This
,
569 IN UINTN CapsuleInstance
,
571 OUT EFI_GUID
*CapsuleType
574 PEI_CD_EXPRESS_PRIVATE_DATA
*PrivateData
;
575 UINTN NumberRecoveryCapsules
;
578 Status
= GetNumberRecoveryCapsules (PeiServices
, This
, &NumberRecoveryCapsules
);
580 if (EFI_ERROR (Status
)) {
584 if (FeaturePcdGet (PcdFrameworkCompatibilitySupport
)) {
585 CapsuleInstance
= CapsuleInstance
+ 1;
588 if ((CapsuleInstance
== 0) || (CapsuleInstance
> NumberRecoveryCapsules
)) {
589 return EFI_NOT_FOUND
;
592 PrivateData
= PEI_CD_EXPRESS_PRIVATE_DATA_FROM_THIS (This
);
594 *Size
= PrivateData
->CapsuleData
[CapsuleInstance
- 1].CapsuleSize
;
597 &gRecoveryOnDataCdGuid
,
605 Loads a DXE capsule from some media into memory.
607 This function, by whatever mechanism, retrieves a DXE capsule from some device
608 and loads it into memory. Note that the published interface is device neutral.
610 @param[in] PeiServices General-purpose services that are available
612 @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
614 @param[in] CapsuleInstance Specifies which capsule instance to retrieve.
615 @param[out] Buffer Specifies a caller-allocated buffer in which
616 the requested recovery capsule will be returned.
618 @retval EFI_SUCCESS The capsule was loaded correctly.
619 @retval EFI_DEVICE_ERROR A device error occurred.
620 @retval EFI_NOT_FOUND A requested recovery DXE capsule cannot be found.
625 LoadRecoveryCapsule (
626 IN EFI_PEI_SERVICES
**PeiServices
,
627 IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
*This
,
628 IN UINTN CapsuleInstance
,
633 PEI_CD_EXPRESS_PRIVATE_DATA
*PrivateData
;
634 EFI_PEI_RECOVERY_BLOCK_IO_PPI
*BlockIoPpi
;
635 EFI_PEI_RECOVERY_BLOCK_IO2_PPI
*BlockIo2Ppi
;
636 UINTN NumberRecoveryCapsules
;
638 Status
= GetNumberRecoveryCapsules (PeiServices
, This
, &NumberRecoveryCapsules
);
640 if (EFI_ERROR (Status
)) {
644 if (FeaturePcdGet (PcdFrameworkCompatibilitySupport
)) {
645 CapsuleInstance
= CapsuleInstance
+ 1;
648 if ((CapsuleInstance
== 0) || (CapsuleInstance
> NumberRecoveryCapsules
)) {
649 return EFI_NOT_FOUND
;
652 PrivateData
= PEI_CD_EXPRESS_PRIVATE_DATA_FROM_THIS (This
);
653 BlockIoPpi
= PrivateData
->CapsuleData
[CapsuleInstance
- 1].BlockIo
;
654 BlockIo2Ppi
= PrivateData
->CapsuleData
[CapsuleInstance
- 1].BlockIo2
;
656 if (BlockIo2Ppi
!= NULL
) {
657 Status
= BlockIo2Ppi
->ReadBlocks (
660 PrivateData
->CapsuleData
[CapsuleInstance
- 1].IndexBlock
,
661 PrivateData
->CapsuleData
[CapsuleInstance
- 1].CapsuleStartLBA
,
662 PrivateData
->CapsuleData
[CapsuleInstance
- 1].CapsuleSize
,
666 Status
= BlockIoPpi
->ReadBlocks (
669 PrivateData
->CapsuleData
[CapsuleInstance
- 1].IndexBlock
,
670 PrivateData
->CapsuleData
[CapsuleInstance
- 1].CapsuleStartLBA
,
671 PrivateData
->CapsuleData
[CapsuleInstance
- 1].CapsuleSize
,
679 This function compares two ASCII strings in case sensitive/insensitive way.
681 @param Source1 The first string.
682 @param Source2 The second string.
683 @param Size The maximum comparison length.
684 @param CaseSensitive Flag to indicate whether the comparison is case sensitive.
686 @retval TRUE The two strings are the same.
687 @retval FALSE The two string are not the same.
695 IN BOOLEAN CaseSensitive
701 for (Index
= 0; Index
< Size
; Index
++) {
702 if (Source1
[Index
] == Source2
[Index
]) {
706 if (!CaseSensitive
) {
707 Dif
= (UINT8
) ((Source1
[Index
] > Source2
[Index
]) ? (Source1
[Index
] - Source2
[Index
]) : (Source2
[Index
] - Source1
[Index
]));
708 if (Dif
== ('a' - 'A')) {