2 Source file for CD recovery PEIM
4 Copyright (c) 2006 - 2014, 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
);
68 PrivateData
->DeviceRecoveryPpi
.GetNumberRecoveryCapsules
= GetNumberRecoveryCapsules
;
69 PrivateData
->DeviceRecoveryPpi
.GetRecoveryCapsuleInfo
= GetRecoveryCapsuleInfo
;
70 PrivateData
->DeviceRecoveryPpi
.LoadRecoveryCapsule
= LoadRecoveryCapsule
;
72 PrivateData
->PpiDescriptor
.Flags
= (EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
);
73 PrivateData
->PpiDescriptor
.Guid
= &gEfiPeiDeviceRecoveryModulePpiGuid
;
74 PrivateData
->PpiDescriptor
.Ppi
= &PrivateData
->DeviceRecoveryPpi
;
76 Status
= PeiServicesInstallPpi (&PrivateData
->PpiDescriptor
);
77 if (EFI_ERROR (Status
)) {
78 return EFI_OUT_OF_RESOURCES
;
81 // PrivateData is allocated now, set it to the module variable
83 mPrivateData
= PrivateData
;
86 // Installs Block Io Ppi notification function
88 PrivateData
->NotifyDescriptor
.Flags
=
90 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
|
91 EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
93 PrivateData
->NotifyDescriptor
.Guid
= &gEfiPeiVirtualBlockIoPpiGuid
;
94 PrivateData
->NotifyDescriptor
.Notify
= BlockIoNotifyEntry
;
95 return PeiServicesNotifyPpi (&PrivateData
->NotifyDescriptor
);
100 BlockIo installation notification function.
102 This function finds out all the current Block IO PPIs in the system and add them
105 @param PeiServices Indirect reference to the PEI Services Table.
106 @param NotifyDescriptor Address of the notification descriptor data structure.
107 @param Ppi Address of the PPI that was installed.
109 @retval EFI_SUCCESS The function completes successfully.
115 IN EFI_PEI_SERVICES
**PeiServices
,
116 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDescriptor
,
120 UpdateBlocksAndVolumes (mPrivateData
);
126 Finds out all the current Block IO PPIs in the system and add them into private data.
128 @param PrivateData The private data structure that contains recovery module information.
130 @retval EFI_SUCCESS The blocks and volumes are updated successfully.
134 UpdateBlocksAndVolumes (
135 IN OUT PEI_CD_EXPRESS_PRIVATE_DATA
*PrivateData
139 EFI_PEI_PPI_DESCRIPTOR
*TempPpiDescriptor
;
140 UINTN BlockIoPpiInstance
;
141 EFI_PEI_RECOVERY_BLOCK_IO_PPI
*BlockIoPpi
;
142 UINTN NumberBlockDevices
;
143 UINTN IndexBlockDevice
;
144 EFI_PEI_BLOCK_IO_MEDIA Media
;
145 EFI_PEI_SERVICES
**PeiServices
;
147 IndexBlockDevice
= 0;
149 // Find out all Block Io Ppi instances within the system
150 // Assuming all device Block Io Peims are dispatched already
152 for (BlockIoPpiInstance
= 0; BlockIoPpiInstance
< PEI_CD_EXPRESS_MAX_BLOCK_IO_PPI
; BlockIoPpiInstance
++) {
153 Status
= PeiServicesLocatePpi (
154 &gEfiPeiVirtualBlockIoPpiGuid
,
157 (VOID
**) &BlockIoPpi
159 if (EFI_ERROR (Status
)) {
161 // Done with all Block Io Ppis
166 PeiServices
= (EFI_PEI_SERVICES
**) GetPeiServicesTablePointer ();
167 Status
= BlockIoPpi
->GetNumberOfBlockDevices (
172 if (EFI_ERROR (Status
) || (NumberBlockDevices
== 0)) {
176 // Just retrieve the first block, should emulate all blocks.
178 for (IndexBlockDevice
= 1; IndexBlockDevice
<= NumberBlockDevices
&& PrivateData
->CapsuleCount
< PEI_CD_EXPRESS_MAX_CAPSULE_NUMBER
; IndexBlockDevice
++) {
179 Status
= BlockIoPpi
->GetBlockDeviceMediaInfo (
185 if (EFI_ERROR (Status
) ||
186 !Media
.MediaPresent
||
187 ((Media
.DeviceType
!= IdeCDROM
) && (Media
.DeviceType
!= UsbMassStorage
)) ||
188 (Media
.BlockSize
!= PEI_CD_BLOCK_SIZE
)
193 DEBUG ((EFI_D_INFO
, "PeiCdExpress DeviceType is %d\n", Media
.DeviceType
));
194 DEBUG ((EFI_D_INFO
, "PeiCdExpress MediaPresent is %d\n", Media
.MediaPresent
));
195 DEBUG ((EFI_D_INFO
, "PeiCdExpress BlockSize is 0x%x\n", Media
.BlockSize
));
196 DEBUG ((EFI_D_INFO
, "PeiCdExpress Status is %d\n", Status
));
198 DEBUG ((EFI_D_INFO
, "IndexBlockDevice is %d\n", IndexBlockDevice
));
199 PrivateData
->CapsuleData
[PrivateData
->CapsuleCount
].IndexBlock
= IndexBlockDevice
;
200 PrivateData
->CapsuleData
[PrivateData
->CapsuleCount
].BlockIo
= BlockIoPpi
;
201 Status
= FindRecoveryCapsules (PrivateData
);
202 DEBUG ((EFI_D_INFO
, "Status is %d\n", Status
));
204 if (EFI_ERROR (Status
)) {
208 PrivateData
->CapsuleCount
++;
217 Finds out the recovery capsule in the current volume.
219 @param PrivateData The private data structure that contains recovery module information.
221 @retval EFI_SUCCESS The recovery capsule is successfully found in the volume.
222 @retval EFI_NOT_FOUND The recovery capsule is not found in the volume.
227 FindRecoveryCapsules (
228 IN OUT PEI_CD_EXPRESS_PRIVATE_DATA
*PrivateData
233 EFI_PEI_RECOVERY_BLOCK_IO_PPI
*BlockIoPpi
;
239 PEI_CD_EXPRESS_DIR_FILE_RECORD
*RoorDirRecord
;
240 UINTN VolumeSpaceSize
;
241 BOOLEAN StartOfVolume
;
243 UINTN IndexBlockDevice
;
245 Buffer
= PrivateData
->BlockBuffer
;
246 BufferSize
= PEI_CD_BLOCK_SIZE
;
250 // The volume descriptor starts on Lba 16
252 IndexBlockDevice
= PrivateData
->CapsuleData
[PrivateData
->CapsuleCount
].IndexBlock
;
253 BlockIoPpi
= PrivateData
->CapsuleData
[PrivateData
->CapsuleCount
].BlockIo
;
256 StartOfVolume
= TRUE
;
260 SetMem (Buffer
, BufferSize
, 0);
261 Status
= BlockIoPpi
->ReadBlocks (
262 (EFI_PEI_SERVICES
**) GetPeiServicesTablePointer (),
269 if (EFI_ERROR (Status
)) {
273 StandardID
= (UINT8
*) (Buffer
+ PEI_CD_EXPRESS_STANDARD_ID_OFFSET
);
274 if (!StringCmp (StandardID
, (UINT8
*) PEI_CD_STANDARD_ID
, PEI_CD_EXPRESS_STANDARD_ID_SIZE
, TRUE
)) {
280 StartOfVolume
= FALSE
;
283 Type
= *(UINT8
*) (Buffer
+ PEI_CD_EXPRESS_VOLUME_TYPE_OFFSET
);
284 if (Type
== PEI_CD_EXPRESS_VOLUME_TYPE_TERMINATOR
) {
285 if (VolumeSpaceSize
== 0) {
288 Lba
= (OriginalLBA
+ VolumeSpaceSize
);
290 StartOfVolume
= TRUE
;
295 if (Type
!= PEI_CD_EXPRESS_VOLUME_TYPE_PRIMARY
) {
300 VolumeSpaceSize
= *(UINT32
*) (Buffer
+ PEI_CD_EXPRESS_VOLUME_SPACE_OFFSET
);
302 RoorDirRecord
= (PEI_CD_EXPRESS_DIR_FILE_RECORD
*) (Buffer
+ PEI_CD_EXPRESS_ROOT_DIR_RECORD_OFFSET
);
303 RootDirLBA
= RoorDirRecord
->LocationOfExtent
[0];
305 Status
= RetrieveCapsuleFileFromRoot (PrivateData
, BlockIoPpi
, IndexBlockDevice
, RootDirLBA
);
306 if (!EFI_ERROR (Status
)) {
308 // Just look for the first primary descriptor
316 return EFI_NOT_FOUND
;
320 Retrieves the recovery capsule in root directory of the current volume.
322 @param PrivateData The private data structure that contains recovery module information.
323 @param BlockIoPpi The Block IO PPI used to access the volume.
324 @param IndexBlockDevice The index of current block device.
325 @param Lba The starting logic block address to retrieve capsule.
327 @retval EFI_SUCCESS The recovery capsule is successfully found in the volume.
328 @retval EFI_NOT_FOUND The recovery capsule is not found in the volume.
334 RetrieveCapsuleFileFromRoot (
335 IN OUT PEI_CD_EXPRESS_PRIVATE_DATA
*PrivateData
,
336 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI
*BlockIoPpi
,
337 IN UINTN IndexBlockDevice
,
344 PEI_CD_EXPRESS_DIR_FILE_RECORD
*FileRecord
;
347 Buffer
= PrivateData
->BlockBuffer
;
348 BufferSize
= PEI_CD_BLOCK_SIZE
;
350 SetMem (Buffer
, BufferSize
, 0);
352 Status
= BlockIoPpi
->ReadBlocks (
353 (EFI_PEI_SERVICES
**) GetPeiServicesTablePointer (),
360 if (EFI_ERROR (Status
)) {
365 FileRecord
= (PEI_CD_EXPRESS_DIR_FILE_RECORD
*) Buffer
;
367 if (FileRecord
->Length
== 0) {
371 // Not intend to check other flag now
373 if ((FileRecord
->Flag
& PEI_CD_EXPRESS_DIR_FILE_REC_FLAG_ISDIR
) != 0) {
374 Buffer
+= FileRecord
->Length
;
378 for (Index
= 0; Index
< FileRecord
->FileIDLength
; Index
++) {
379 if (FileRecord
->FileID
[Index
] == ';') {
384 if (Index
!= (sizeof (PEI_RECOVERY_FILE_NAME
) - 1)) {
385 Buffer
+= FileRecord
->Length
;
389 if (!StringCmp (FileRecord
->FileID
, (UINT8
*) PEI_RECOVERY_FILE_NAME
, sizeof (PEI_RECOVERY_FILE_NAME
) - 1, FALSE
)) {
390 Buffer
+= FileRecord
->Length
;
394 PrivateData
->CapsuleData
[PrivateData
->CapsuleCount
].CapsuleStartLBA
= FileRecord
->LocationOfExtent
[0];
395 PrivateData
->CapsuleData
[PrivateData
->CapsuleCount
].CapsuleSize
=
397 FileRecord
->DataLength
[0] /
406 return EFI_NOT_FOUND
;
410 Returns the number of DXE capsules residing on the device.
412 This function searches for DXE capsules from the associated device and returns
413 the number and maximum size in bytes of the capsules discovered. Entry 1 is
414 assumed to be the highest load priority and entry N is assumed to be the lowest
417 @param[in] PeiServices General-purpose services that are available
419 @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
421 @param[out] NumberRecoveryCapsules Pointer to a caller-allocated UINTN. On
422 output, *NumberRecoveryCapsules contains
423 the number of recovery capsule images
424 available for retrieval from this PEIM
427 @retval EFI_SUCCESS One or more capsules were discovered.
428 @retval EFI_DEVICE_ERROR A device error occurred.
429 @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
434 GetNumberRecoveryCapsules (
435 IN EFI_PEI_SERVICES
**PeiServices
,
436 IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
*This
,
437 OUT UINTN
*NumberRecoveryCapsules
440 PEI_CD_EXPRESS_PRIVATE_DATA
*PrivateData
;
442 PrivateData
= PEI_CD_EXPRESS_PRIVATE_DATA_FROM_THIS (This
);
443 UpdateBlocksAndVolumes (PrivateData
);
444 *NumberRecoveryCapsules
= PrivateData
->CapsuleCount
;
446 if (*NumberRecoveryCapsules
== 0) {
447 return EFI_NOT_FOUND
;
454 Returns the size and type of the requested recovery capsule.
456 This function gets the size and type of the capsule specified by CapsuleInstance.
458 @param[in] PeiServices General-purpose services that are available to every PEIM
459 @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
461 @param[in] CapsuleInstance Specifies for which capsule instance to retrieve
462 the information. This parameter must be between
463 one and the value returned by GetNumberRecoveryCapsules()
464 in NumberRecoveryCapsules.
465 @param[out] Size A pointer to a caller-allocated UINTN in which
466 the size of the requested recovery module is
468 @param[out] CapsuleType A pointer to a caller-allocated EFI_GUID in which
469 the type of the requested recovery capsule is
470 returned. The semantic meaning of the value
471 returned is defined by the implementation.
473 @retval EFI_SUCCESS One or more capsules were discovered.
474 @retval EFI_DEVICE_ERROR A device error occurred.
475 @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
480 GetRecoveryCapsuleInfo (
481 IN EFI_PEI_SERVICES
**PeiServices
,
482 IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
*This
,
483 IN UINTN CapsuleInstance
,
485 OUT EFI_GUID
*CapsuleType
488 PEI_CD_EXPRESS_PRIVATE_DATA
*PrivateData
;
489 UINTN NumberRecoveryCapsules
;
492 Status
= GetNumberRecoveryCapsules (PeiServices
, This
, &NumberRecoveryCapsules
);
494 if (EFI_ERROR (Status
)) {
498 if (FeaturePcdGet (PcdFrameworkCompatibilitySupport
)) {
499 CapsuleInstance
= CapsuleInstance
+ 1;
502 if ((CapsuleInstance
== 0) || (CapsuleInstance
> NumberRecoveryCapsules
)) {
503 return EFI_NOT_FOUND
;
506 PrivateData
= PEI_CD_EXPRESS_PRIVATE_DATA_FROM_THIS (This
);
508 *Size
= PrivateData
->CapsuleData
[CapsuleInstance
- 1].CapsuleSize
;
511 &gRecoveryOnDataCdGuid
,
519 Loads a DXE capsule from some media into memory.
521 This function, by whatever mechanism, retrieves a DXE capsule from some device
522 and loads it into memory. Note that the published interface is device neutral.
524 @param[in] PeiServices General-purpose services that are available
526 @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
528 @param[in] CapsuleInstance Specifies which capsule instance to retrieve.
529 @param[out] Buffer Specifies a caller-allocated buffer in which
530 the requested recovery capsule will be returned.
532 @retval EFI_SUCCESS The capsule was loaded correctly.
533 @retval EFI_DEVICE_ERROR A device error occurred.
534 @retval EFI_NOT_FOUND A requested recovery DXE capsule cannot be found.
539 LoadRecoveryCapsule (
540 IN EFI_PEI_SERVICES
**PeiServices
,
541 IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
*This
,
542 IN UINTN CapsuleInstance
,
547 PEI_CD_EXPRESS_PRIVATE_DATA
*PrivateData
;
548 EFI_PEI_RECOVERY_BLOCK_IO_PPI
*BlockIoPpi
;
549 UINTN NumberRecoveryCapsules
;
551 Status
= GetNumberRecoveryCapsules (PeiServices
, This
, &NumberRecoveryCapsules
);
553 if (EFI_ERROR (Status
)) {
557 if (FeaturePcdGet (PcdFrameworkCompatibilitySupport
)) {
558 CapsuleInstance
= CapsuleInstance
+ 1;
561 if ((CapsuleInstance
== 0) || (CapsuleInstance
> NumberRecoveryCapsules
)) {
562 return EFI_NOT_FOUND
;
565 PrivateData
= PEI_CD_EXPRESS_PRIVATE_DATA_FROM_THIS (This
);
566 BlockIoPpi
= PrivateData
->CapsuleData
[CapsuleInstance
- 1].BlockIo
;
568 Status
= BlockIoPpi
->ReadBlocks (
571 PrivateData
->CapsuleData
[CapsuleInstance
- 1].IndexBlock
,
572 PrivateData
->CapsuleData
[CapsuleInstance
- 1].CapsuleStartLBA
,
573 PrivateData
->CapsuleData
[CapsuleInstance
- 1].CapsuleSize
,
580 This function compares two ASCII strings in case sensitive/insensitive way.
582 @param Source1 The first string.
583 @param Source2 The second string.
584 @param Size The maximum comparison length.
585 @param CaseSensitive Flag to indicate whether the comparison is case sensitive.
587 @retval TRUE The two strings are the same.
588 @retval FALSE The two string are not the same.
596 IN BOOLEAN CaseSensitive
602 for (Index
= 0; Index
< Size
; Index
++) {
603 if (Source1
[Index
] == Source2
[Index
]) {
607 if (!CaseSensitive
) {
608 Dif
= (UINT8
) ((Source1
[Index
] > Source2
[Index
]) ? (Source1
[Index
] - Source2
[Index
]) : (Source2
[Index
] - Source1
[Index
]));
609 if (Dif
== ('a' - 'A')) {