mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-12-04 13:23:26 +01:00
716 lines
25 KiB
C
716 lines
25 KiB
C
|
/** @file
|
||
|
Source file for CD recovery PEIM
|
||
|
|
||
|
Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
|
||
|
|
||
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||
|
|
||
|
**/
|
||
|
|
||
|
#include "PeiCdExpress.h"
|
||
|
|
||
|
PEI_CD_EXPRESS_PRIVATE_DATA *mPrivateData = NULL;
|
||
|
CHAR8 *mRecoveryFileName;
|
||
|
UINTN mRecoveryFileNameSize;
|
||
|
|
||
|
/**
|
||
|
Installs the Device Recovery Module PPI, Initialize BlockIo Ppi
|
||
|
installation notification
|
||
|
|
||
|
@param FileHandle The file handle of the image.
|
||
|
@param PeiServices General purpose services available to every PEIM.
|
||
|
|
||
|
@retval EFI_SUCCESS The function completed successfully.
|
||
|
@retval EFI_OUT_OF_RESOURCES There is not enough system memory.
|
||
|
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
EFIAPI
|
||
|
CdExpressPeimEntry (
|
||
|
IN EFI_PEI_FILE_HANDLE FileHandle,
|
||
|
IN CONST EFI_PEI_SERVICES **PeiServices
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData;
|
||
|
|
||
|
if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
PrivateData = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (*PrivateData)));
|
||
|
if (PrivateData == NULL) {
|
||
|
return EFI_OUT_OF_RESOURCES;
|
||
|
}
|
||
|
|
||
|
mRecoveryFileNameSize = PcdGetSize(PcdRecoveryFileName) / sizeof(CHAR16);
|
||
|
mRecoveryFileName = AllocatePool(mRecoveryFileNameSize);
|
||
|
if (mRecoveryFileName == NULL) {
|
||
|
return EFI_OUT_OF_RESOURCES;
|
||
|
}
|
||
|
Status = UnicodeStrToAsciiStrS(PcdGetPtr(PcdRecoveryFileName), mRecoveryFileName, mRecoveryFileNameSize);
|
||
|
if (EFI_ERROR(Status)) {
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Initialize Private Data (to zero, as is required by subsequent operations)
|
||
|
//
|
||
|
ZeroMem (PrivateData, sizeof (*PrivateData));
|
||
|
PrivateData->Signature = PEI_CD_EXPRESS_PRIVATE_DATA_SIGNATURE;
|
||
|
|
||
|
PrivateData->BlockBuffer = AllocatePages (EFI_SIZE_TO_PAGES (PEI_CD_BLOCK_SIZE));
|
||
|
if (PrivateData->BlockBuffer == NULL) {
|
||
|
return EFI_OUT_OF_RESOURCES;
|
||
|
}
|
||
|
|
||
|
PrivateData->CapsuleCount = 0;
|
||
|
Status = UpdateBlocksAndVolumes (PrivateData, TRUE);
|
||
|
Status = UpdateBlocksAndVolumes (PrivateData, FALSE);
|
||
|
|
||
|
//
|
||
|
// Installs Ppi
|
||
|
//
|
||
|
PrivateData->DeviceRecoveryPpi.GetNumberRecoveryCapsules = GetNumberRecoveryCapsules;
|
||
|
PrivateData->DeviceRecoveryPpi.GetRecoveryCapsuleInfo = GetRecoveryCapsuleInfo;
|
||
|
PrivateData->DeviceRecoveryPpi.LoadRecoveryCapsule = LoadRecoveryCapsule;
|
||
|
|
||
|
PrivateData->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
|
||
|
PrivateData->PpiDescriptor.Guid = &gEfiPeiDeviceRecoveryModulePpiGuid;
|
||
|
PrivateData->PpiDescriptor.Ppi = &PrivateData->DeviceRecoveryPpi;
|
||
|
|
||
|
Status = PeiServicesInstallPpi (&PrivateData->PpiDescriptor);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
return EFI_OUT_OF_RESOURCES;
|
||
|
}
|
||
|
//
|
||
|
// PrivateData is allocated now, set it to the module variable
|
||
|
//
|
||
|
mPrivateData = PrivateData;
|
||
|
|
||
|
//
|
||
|
// Installs Block Io Ppi notification function
|
||
|
//
|
||
|
PrivateData->NotifyDescriptor.Flags =
|
||
|
(
|
||
|
EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
|
||
|
);
|
||
|
PrivateData->NotifyDescriptor.Guid = &gEfiPeiVirtualBlockIoPpiGuid;
|
||
|
PrivateData->NotifyDescriptor.Notify = BlockIoNotifyEntry;
|
||
|
|
||
|
PrivateData->NotifyDescriptor2.Flags =
|
||
|
(
|
||
|
EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK |
|
||
|
EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
|
||
|
);
|
||
|
PrivateData->NotifyDescriptor2.Guid = &gEfiPeiVirtualBlockIo2PpiGuid;
|
||
|
PrivateData->NotifyDescriptor2.Notify = BlockIoNotifyEntry;
|
||
|
|
||
|
return PeiServicesNotifyPpi (&PrivateData->NotifyDescriptor);
|
||
|
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
BlockIo installation notification function.
|
||
|
|
||
|
This function finds out all the current Block IO PPIs in the system and add them
|
||
|
into private data.
|
||
|
|
||
|
@param PeiServices Indirect reference to the PEI Services Table.
|
||
|
@param NotifyDescriptor Address of the notification descriptor data structure.
|
||
|
@param Ppi Address of the PPI that was installed.
|
||
|
|
||
|
@retval EFI_SUCCESS The function completes successfully.
|
||
|
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
EFIAPI
|
||
|
BlockIoNotifyEntry (
|
||
|
IN EFI_PEI_SERVICES **PeiServices,
|
||
|
IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
|
||
|
IN VOID *Ppi
|
||
|
)
|
||
|
{
|
||
|
if (CompareGuid (NotifyDescriptor->Guid, &gEfiPeiVirtualBlockIo2PpiGuid)) {
|
||
|
UpdateBlocksAndVolumes (mPrivateData, TRUE);
|
||
|
} else {
|
||
|
UpdateBlocksAndVolumes (mPrivateData, FALSE);
|
||
|
}
|
||
|
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Finds out all the current Block IO PPIs in the system and add them into private data.
|
||
|
|
||
|
@param PrivateData The private data structure that contains recovery module information.
|
||
|
@param BlockIo2 Boolean to show whether using BlockIo2 or BlockIo.
|
||
|
|
||
|
@retval EFI_SUCCESS The blocks and volumes are updated successfully.
|
||
|
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
UpdateBlocksAndVolumes (
|
||
|
IN OUT PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData,
|
||
|
IN BOOLEAN BlockIo2
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
EFI_PEI_PPI_DESCRIPTOR *TempPpiDescriptor;
|
||
|
UINTN BlockIoPpiInstance;
|
||
|
EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi;
|
||
|
EFI_PEI_RECOVERY_BLOCK_IO2_PPI *BlockIo2Ppi;
|
||
|
UINTN NumberBlockDevices;
|
||
|
UINTN IndexBlockDevice;
|
||
|
EFI_PEI_BLOCK_IO_MEDIA Media;
|
||
|
EFI_PEI_BLOCK_IO2_MEDIA Media2;
|
||
|
EFI_PEI_SERVICES **PeiServices;
|
||
|
|
||
|
IndexBlockDevice = 0;
|
||
|
BlockIo2Ppi = NULL;
|
||
|
BlockIoPpi = NULL;
|
||
|
//
|
||
|
// Find out all Block Io Ppi instances within the system
|
||
|
// Assuming all device Block Io Peims are dispatched already
|
||
|
//
|
||
|
for (BlockIoPpiInstance = 0; BlockIoPpiInstance < PEI_CD_EXPRESS_MAX_BLOCK_IO_PPI; BlockIoPpiInstance++) {
|
||
|
if (BlockIo2) {
|
||
|
Status = PeiServicesLocatePpi (
|
||
|
&gEfiPeiVirtualBlockIo2PpiGuid,
|
||
|
BlockIoPpiInstance,
|
||
|
&TempPpiDescriptor,
|
||
|
(VOID **) &BlockIo2Ppi
|
||
|
);
|
||
|
} else {
|
||
|
Status = PeiServicesLocatePpi (
|
||
|
&gEfiPeiVirtualBlockIoPpiGuid,
|
||
|
BlockIoPpiInstance,
|
||
|
&TempPpiDescriptor,
|
||
|
(VOID **) &BlockIoPpi
|
||
|
);
|
||
|
}
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
//
|
||
|
// Done with all Block Io Ppis
|
||
|
//
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
PeiServices = (EFI_PEI_SERVICES **) GetPeiServicesTablePointer ();
|
||
|
if (BlockIo2) {
|
||
|
Status = BlockIo2Ppi->GetNumberOfBlockDevices (
|
||
|
PeiServices,
|
||
|
BlockIo2Ppi,
|
||
|
&NumberBlockDevices
|
||
|
);
|
||
|
} else {
|
||
|
Status = BlockIoPpi->GetNumberOfBlockDevices (
|
||
|
PeiServices,
|
||
|
BlockIoPpi,
|
||
|
&NumberBlockDevices
|
||
|
);
|
||
|
}
|
||
|
if (EFI_ERROR (Status) || (NumberBlockDevices == 0)) {
|
||
|
continue;
|
||
|
}
|
||
|
//
|
||
|
// Just retrieve the first block, should emulate all blocks.
|
||
|
//
|
||
|
for (IndexBlockDevice = 1; IndexBlockDevice <= NumberBlockDevices && PrivateData->CapsuleCount < PEI_CD_EXPRESS_MAX_CAPSULE_NUMBER; IndexBlockDevice ++) {
|
||
|
if (BlockIo2) {
|
||
|
Status = BlockIo2Ppi->GetBlockDeviceMediaInfo (
|
||
|
PeiServices,
|
||
|
BlockIo2Ppi,
|
||
|
IndexBlockDevice,
|
||
|
&Media2
|
||
|
);
|
||
|
if (EFI_ERROR (Status) ||
|
||
|
!Media2.MediaPresent ||
|
||
|
((Media2.InterfaceType != MSG_ATAPI_DP) && (Media2.InterfaceType != MSG_USB_DP)) ||
|
||
|
(Media2.BlockSize != PEI_CD_BLOCK_SIZE)
|
||
|
) {
|
||
|
continue;
|
||
|
}
|
||
|
DEBUG ((EFI_D_INFO, "PeiCdExpress InterfaceType is %d\n", Media2.InterfaceType));
|
||
|
DEBUG ((EFI_D_INFO, "PeiCdExpress MediaPresent is %d\n", Media2.MediaPresent));
|
||
|
DEBUG ((EFI_D_INFO, "PeiCdExpress BlockSize is 0x%x\n", Media2.BlockSize));
|
||
|
} else {
|
||
|
Status = BlockIoPpi->GetBlockDeviceMediaInfo (
|
||
|
PeiServices,
|
||
|
BlockIoPpi,
|
||
|
IndexBlockDevice,
|
||
|
&Media
|
||
|
);
|
||
|
if (EFI_ERROR (Status) ||
|
||
|
!Media.MediaPresent ||
|
||
|
((Media.DeviceType != IdeCDROM) && (Media.DeviceType != UsbMassStorage)) ||
|
||
|
(Media.BlockSize != PEI_CD_BLOCK_SIZE)
|
||
|
) {
|
||
|
continue;
|
||
|
}
|
||
|
DEBUG ((EFI_D_INFO, "PeiCdExpress DeviceType is %d\n", Media.DeviceType));
|
||
|
DEBUG ((EFI_D_INFO, "PeiCdExpress MediaPresent is %d\n", Media.MediaPresent));
|
||
|
DEBUG ((EFI_D_INFO, "PeiCdExpress BlockSize is 0x%x\n", Media.BlockSize));
|
||
|
}
|
||
|
|
||
|
DEBUG ((EFI_D_INFO, "PeiCdExpress Status is %d\n", Status));
|
||
|
|
||
|
DEBUG ((EFI_D_INFO, "IndexBlockDevice is %d\n", IndexBlockDevice));
|
||
|
PrivateData->CapsuleData[PrivateData->CapsuleCount].IndexBlock = IndexBlockDevice;
|
||
|
if (BlockIo2) {
|
||
|
PrivateData->CapsuleData[PrivateData->CapsuleCount].BlockIo2 = BlockIo2Ppi;
|
||
|
} else {
|
||
|
PrivateData->CapsuleData[PrivateData->CapsuleCount].BlockIo = BlockIoPpi;
|
||
|
}
|
||
|
Status = FindRecoveryCapsules (PrivateData);
|
||
|
DEBUG ((EFI_D_INFO, "Status is %d\n", Status));
|
||
|
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
PrivateData->CapsuleCount++;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Finds out the recovery capsule in the current volume.
|
||
|
|
||
|
@param PrivateData The private data structure that contains recovery module information.
|
||
|
|
||
|
@retval EFI_SUCCESS The recovery capsule is successfully found in the volume.
|
||
|
@retval EFI_NOT_FOUND The recovery capsule is not found in the volume.
|
||
|
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
EFIAPI
|
||
|
FindRecoveryCapsules (
|
||
|
IN OUT PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
UINTN Lba;
|
||
|
EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi;
|
||
|
EFI_PEI_RECOVERY_BLOCK_IO2_PPI *BlockIo2Ppi;
|
||
|
UINTN BufferSize;
|
||
|
UINT8 *Buffer;
|
||
|
UINT8 Type;
|
||
|
UINT8 *StandardID;
|
||
|
UINT32 RootDirLBA;
|
||
|
PEI_CD_EXPRESS_DIR_FILE_RECORD *RoorDirRecord;
|
||
|
UINTN VolumeSpaceSize;
|
||
|
BOOLEAN StartOfVolume;
|
||
|
UINTN OriginalLBA;
|
||
|
UINTN IndexBlockDevice;
|
||
|
|
||
|
Buffer = PrivateData->BlockBuffer;
|
||
|
BufferSize = PEI_CD_BLOCK_SIZE;
|
||
|
|
||
|
Lba = 16;
|
||
|
//
|
||
|
// The volume descriptor starts on Lba 16
|
||
|
//
|
||
|
IndexBlockDevice = PrivateData->CapsuleData[PrivateData->CapsuleCount].IndexBlock;
|
||
|
BlockIoPpi = PrivateData->CapsuleData[PrivateData->CapsuleCount].BlockIo;
|
||
|
BlockIo2Ppi = PrivateData->CapsuleData[PrivateData->CapsuleCount].BlockIo2;
|
||
|
|
||
|
VolumeSpaceSize = 0;
|
||
|
StartOfVolume = TRUE;
|
||
|
OriginalLBA = 16;
|
||
|
|
||
|
while (TRUE) {
|
||
|
SetMem (Buffer, BufferSize, 0);
|
||
|
if (BlockIo2Ppi != NULL) {
|
||
|
Status = BlockIo2Ppi->ReadBlocks (
|
||
|
(EFI_PEI_SERVICES **) GetPeiServicesTablePointer (),
|
||
|
BlockIo2Ppi,
|
||
|
IndexBlockDevice,
|
||
|
Lba,
|
||
|
BufferSize,
|
||
|
Buffer
|
||
|
);
|
||
|
} else {
|
||
|
Status = BlockIoPpi->ReadBlocks (
|
||
|
(EFI_PEI_SERVICES **) GetPeiServicesTablePointer (),
|
||
|
BlockIoPpi,
|
||
|
IndexBlockDevice,
|
||
|
Lba,
|
||
|
BufferSize,
|
||
|
Buffer
|
||
|
);
|
||
|
}
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
StandardID = (UINT8 *) (Buffer + PEI_CD_EXPRESS_STANDARD_ID_OFFSET);
|
||
|
if (!StringCmp (StandardID, (UINT8 *) PEI_CD_STANDARD_ID, PEI_CD_EXPRESS_STANDARD_ID_SIZE, TRUE)) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (StartOfVolume) {
|
||
|
OriginalLBA = Lba;
|
||
|
StartOfVolume = FALSE;
|
||
|
}
|
||
|
|
||
|
Type = *(UINT8 *) (Buffer + PEI_CD_EXPRESS_VOLUME_TYPE_OFFSET);
|
||
|
if (Type == PEI_CD_EXPRESS_VOLUME_TYPE_TERMINATOR) {
|
||
|
if (VolumeSpaceSize == 0) {
|
||
|
break;
|
||
|
} else {
|
||
|
Lba = (OriginalLBA + VolumeSpaceSize);
|
||
|
VolumeSpaceSize = 0;
|
||
|
StartOfVolume = TRUE;
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (Type != PEI_CD_EXPRESS_VOLUME_TYPE_PRIMARY) {
|
||
|
Lba++;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
VolumeSpaceSize = *(UINT32 *) (Buffer + PEI_CD_EXPRESS_VOLUME_SPACE_OFFSET);
|
||
|
|
||
|
RoorDirRecord = (PEI_CD_EXPRESS_DIR_FILE_RECORD *) (Buffer + PEI_CD_EXPRESS_ROOT_DIR_RECORD_OFFSET);
|
||
|
RootDirLBA = RoorDirRecord->LocationOfExtent[0];
|
||
|
|
||
|
Status = RetrieveCapsuleFileFromRoot (PrivateData, BlockIoPpi, BlockIo2Ppi, IndexBlockDevice, RootDirLBA);
|
||
|
if (!EFI_ERROR (Status)) {
|
||
|
//
|
||
|
// Just look for the first primary descriptor
|
||
|
//
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
Lba++;
|
||
|
}
|
||
|
|
||
|
return EFI_NOT_FOUND;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Retrieves the recovery capsule in root directory of the current volume.
|
||
|
|
||
|
@param PrivateData The private data structure that contains recovery module information.
|
||
|
@param BlockIoPpi The Block IO PPI used to access the volume.
|
||
|
@param BlockIo2Ppi The Block IO 2 PPI used to access the volume.
|
||
|
@param IndexBlockDevice The index of current block device.
|
||
|
@param Lba The starting logic block address to retrieve capsule.
|
||
|
|
||
|
@retval EFI_SUCCESS The recovery capsule is successfully found in the volume.
|
||
|
@retval EFI_NOT_FOUND The recovery capsule is not found in the volume.
|
||
|
@retval Others
|
||
|
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
EFIAPI
|
||
|
RetrieveCapsuleFileFromRoot (
|
||
|
IN OUT PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData,
|
||
|
IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi,
|
||
|
IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *BlockIo2Ppi,
|
||
|
IN UINTN IndexBlockDevice,
|
||
|
IN UINT32 Lba
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
UINTN BufferSize;
|
||
|
UINT8 *Buffer;
|
||
|
PEI_CD_EXPRESS_DIR_FILE_RECORD *FileRecord;
|
||
|
UINTN Index;
|
||
|
|
||
|
Buffer = PrivateData->BlockBuffer;
|
||
|
BufferSize = PEI_CD_BLOCK_SIZE;
|
||
|
|
||
|
SetMem (Buffer, BufferSize, 0);
|
||
|
|
||
|
if (BlockIo2Ppi != NULL) {
|
||
|
Status = BlockIo2Ppi->ReadBlocks (
|
||
|
(EFI_PEI_SERVICES **) GetPeiServicesTablePointer (),
|
||
|
BlockIo2Ppi,
|
||
|
IndexBlockDevice,
|
||
|
Lba,
|
||
|
BufferSize,
|
||
|
Buffer
|
||
|
);
|
||
|
} else {
|
||
|
Status = BlockIoPpi->ReadBlocks (
|
||
|
(EFI_PEI_SERVICES **) GetPeiServicesTablePointer (),
|
||
|
BlockIoPpi,
|
||
|
IndexBlockDevice,
|
||
|
Lba,
|
||
|
BufferSize,
|
||
|
Buffer
|
||
|
);
|
||
|
}
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
while (1) {
|
||
|
FileRecord = (PEI_CD_EXPRESS_DIR_FILE_RECORD *) Buffer;
|
||
|
|
||
|
if (FileRecord->Length == 0) {
|
||
|
break;
|
||
|
}
|
||
|
//
|
||
|
// Not intend to check other flag now
|
||
|
//
|
||
|
if ((FileRecord->Flag & PEI_CD_EXPRESS_DIR_FILE_REC_FLAG_ISDIR) != 0) {
|
||
|
Buffer += FileRecord->Length;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
for (Index = 0; Index < FileRecord->FileIDLength; Index++) {
|
||
|
if (FileRecord->FileID[Index] == ';') {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (Index != mRecoveryFileNameSize - 1) {
|
||
|
Buffer += FileRecord->Length;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (!StringCmp (FileRecord->FileID, (UINT8 *)mRecoveryFileName, mRecoveryFileNameSize - 1, FALSE)) {
|
||
|
Buffer += FileRecord->Length;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
PrivateData->CapsuleData[PrivateData->CapsuleCount].CapsuleStartLBA = FileRecord->LocationOfExtent[0];
|
||
|
PrivateData->CapsuleData[PrivateData->CapsuleCount].CapsuleBlockAlignedSize =
|
||
|
(
|
||
|
FileRecord->DataLength[0] /
|
||
|
PEI_CD_BLOCK_SIZE +
|
||
|
1
|
||
|
) *
|
||
|
PEI_CD_BLOCK_SIZE;
|
||
|
PrivateData->CapsuleData[PrivateData->CapsuleCount].CapsuleSize = FileRecord->DataLength[0];
|
||
|
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
return EFI_NOT_FOUND;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Returns the number of DXE capsules residing on the device.
|
||
|
|
||
|
This function searches for DXE capsules from the associated device and returns
|
||
|
the number and maximum size in bytes of the capsules discovered. Entry 1 is
|
||
|
assumed to be the highest load priority and entry N is assumed to be the lowest
|
||
|
priority.
|
||
|
|
||
|
@param[in] PeiServices General-purpose services that are available
|
||
|
to every PEIM
|
||
|
@param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
|
||
|
instance.
|
||
|
@param[out] NumberRecoveryCapsules Pointer to a caller-allocated UINTN. On
|
||
|
output, *NumberRecoveryCapsules contains
|
||
|
the number of recovery capsule images
|
||
|
available for retrieval from this PEIM
|
||
|
instance.
|
||
|
|
||
|
@retval EFI_SUCCESS One or more capsules were discovered.
|
||
|
@retval EFI_DEVICE_ERROR A device error occurred.
|
||
|
@retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
|
||
|
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
EFIAPI
|
||
|
GetNumberRecoveryCapsules (
|
||
|
IN EFI_PEI_SERVICES **PeiServices,
|
||
|
IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,
|
||
|
OUT UINTN *NumberRecoveryCapsules
|
||
|
)
|
||
|
{
|
||
|
PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData;
|
||
|
|
||
|
PrivateData = PEI_CD_EXPRESS_PRIVATE_DATA_FROM_THIS (This);
|
||
|
UpdateBlocksAndVolumes (PrivateData, TRUE);
|
||
|
UpdateBlocksAndVolumes (PrivateData, FALSE);
|
||
|
*NumberRecoveryCapsules = PrivateData->CapsuleCount;
|
||
|
|
||
|
if (*NumberRecoveryCapsules == 0) {
|
||
|
return EFI_NOT_FOUND;
|
||
|
}
|
||
|
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Returns the size and type of the requested recovery capsule.
|
||
|
|
||
|
This function gets the size and type of the capsule specified by CapsuleInstance.
|
||
|
|
||
|
@param[in] PeiServices General-purpose services that are available to every PEIM
|
||
|
@param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
|
||
|
instance.
|
||
|
@param[in] CapsuleInstance Specifies for which capsule instance to retrieve
|
||
|
the information. This parameter must be between
|
||
|
one and the value returned by GetNumberRecoveryCapsules()
|
||
|
in NumberRecoveryCapsules.
|
||
|
@param[out] Size A pointer to a caller-allocated UINTN in which
|
||
|
the size of the requested recovery module is
|
||
|
returned.
|
||
|
@param[out] CapsuleType A pointer to a caller-allocated EFI_GUID in which
|
||
|
the type of the requested recovery capsule is
|
||
|
returned. The semantic meaning of the value
|
||
|
returned is defined by the implementation.
|
||
|
|
||
|
@retval EFI_SUCCESS One or more capsules were discovered.
|
||
|
@retval EFI_DEVICE_ERROR A device error occurred.
|
||
|
@retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
|
||
|
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
EFIAPI
|
||
|
GetRecoveryCapsuleInfo (
|
||
|
IN EFI_PEI_SERVICES **PeiServices,
|
||
|
IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,
|
||
|
IN UINTN CapsuleInstance,
|
||
|
OUT UINTN *Size,
|
||
|
OUT EFI_GUID *CapsuleType
|
||
|
)
|
||
|
{
|
||
|
PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData;
|
||
|
UINTN NumberRecoveryCapsules;
|
||
|
EFI_STATUS Status;
|
||
|
|
||
|
Status = GetNumberRecoveryCapsules (PeiServices, This, &NumberRecoveryCapsules);
|
||
|
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
if ((CapsuleInstance == 0) || (CapsuleInstance > NumberRecoveryCapsules)) {
|
||
|
return EFI_NOT_FOUND;
|
||
|
}
|
||
|
|
||
|
PrivateData = PEI_CD_EXPRESS_PRIVATE_DATA_FROM_THIS (This);
|
||
|
|
||
|
*Size = PrivateData->CapsuleData[CapsuleInstance - 1].CapsuleSize;
|
||
|
CopyMem (
|
||
|
CapsuleType,
|
||
|
&gRecoveryOnDataCdGuid,
|
||
|
sizeof (EFI_GUID)
|
||
|
);
|
||
|
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Loads a DXE capsule from some media into memory.
|
||
|
|
||
|
This function, by whatever mechanism, retrieves a DXE capsule from some device
|
||
|
and loads it into memory. Note that the published interface is device neutral.
|
||
|
|
||
|
@param[in] PeiServices General-purpose services that are available
|
||
|
to every PEIM
|
||
|
@param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
|
||
|
instance.
|
||
|
@param[in] CapsuleInstance Specifies which capsule instance to retrieve.
|
||
|
@param[out] Buffer Specifies a caller-allocated buffer in which
|
||
|
the requested recovery capsule will be returned.
|
||
|
|
||
|
@retval EFI_SUCCESS The capsule was loaded correctly.
|
||
|
@retval EFI_DEVICE_ERROR A device error occurred.
|
||
|
@retval EFI_NOT_FOUND A requested recovery DXE capsule cannot be found.
|
||
|
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
EFIAPI
|
||
|
LoadRecoveryCapsule (
|
||
|
IN EFI_PEI_SERVICES **PeiServices,
|
||
|
IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,
|
||
|
IN UINTN CapsuleInstance,
|
||
|
OUT VOID *Buffer
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData;
|
||
|
EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi;
|
||
|
EFI_PEI_RECOVERY_BLOCK_IO2_PPI *BlockIo2Ppi;
|
||
|
UINTN NumberRecoveryCapsules;
|
||
|
|
||
|
Status = GetNumberRecoveryCapsules (PeiServices, This, &NumberRecoveryCapsules);
|
||
|
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
if ((CapsuleInstance == 0) || (CapsuleInstance > NumberRecoveryCapsules)) {
|
||
|
return EFI_NOT_FOUND;
|
||
|
}
|
||
|
|
||
|
PrivateData = PEI_CD_EXPRESS_PRIVATE_DATA_FROM_THIS (This);
|
||
|
BlockIoPpi = PrivateData->CapsuleData[CapsuleInstance - 1].BlockIo;
|
||
|
BlockIo2Ppi = PrivateData->CapsuleData[CapsuleInstance - 1].BlockIo2;
|
||
|
|
||
|
if (BlockIo2Ppi != NULL) {
|
||
|
Status = BlockIo2Ppi->ReadBlocks (
|
||
|
PeiServices,
|
||
|
BlockIo2Ppi,
|
||
|
PrivateData->CapsuleData[CapsuleInstance - 1].IndexBlock,
|
||
|
PrivateData->CapsuleData[CapsuleInstance - 1].CapsuleStartLBA,
|
||
|
PrivateData->CapsuleData[CapsuleInstance - 1].CapsuleBlockAlignedSize,
|
||
|
Buffer
|
||
|
);
|
||
|
} else {
|
||
|
Status = BlockIoPpi->ReadBlocks (
|
||
|
PeiServices,
|
||
|
BlockIoPpi,
|
||
|
PrivateData->CapsuleData[CapsuleInstance - 1].IndexBlock,
|
||
|
PrivateData->CapsuleData[CapsuleInstance - 1].CapsuleStartLBA,
|
||
|
PrivateData->CapsuleData[CapsuleInstance - 1].CapsuleBlockAlignedSize,
|
||
|
Buffer
|
||
|
);
|
||
|
}
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
This function compares two ASCII strings in case sensitive/insensitive way.
|
||
|
|
||
|
@param Source1 The first string.
|
||
|
@param Source2 The second string.
|
||
|
@param Size The maximum comparison length.
|
||
|
@param CaseSensitive Flag to indicate whether the comparison is case sensitive.
|
||
|
|
||
|
@retval TRUE The two strings are the same.
|
||
|
@retval FALSE The two string are not the same.
|
||
|
|
||
|
**/
|
||
|
BOOLEAN
|
||
|
StringCmp (
|
||
|
IN UINT8 *Source1,
|
||
|
IN UINT8 *Source2,
|
||
|
IN UINTN Size,
|
||
|
IN BOOLEAN CaseSensitive
|
||
|
)
|
||
|
{
|
||
|
UINTN Index;
|
||
|
UINT8 Dif;
|
||
|
|
||
|
for (Index = 0; Index < Size; Index++) {
|
||
|
if (Source1[Index] == Source2[Index]) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (!CaseSensitive) {
|
||
|
Dif = (UINT8) ((Source1[Index] > Source2[Index]) ? (Source1[Index] - Source2[Index]) : (Source2[Index] - Source1[Index]));
|
||
|
if (Dif == ('a' - 'A')) {
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|