mirror of https://github.com/acidanthera/audk.git
362 lines
11 KiB
C
362 lines
11 KiB
C
/** @file
|
|
|
|
Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>
|
|
|
|
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
|
|
|
|
|
|
|
Module Name:
|
|
|
|
|
|
Recovery.c
|
|
|
|
Abstract:
|
|
|
|
Tiano PEIM to provide the platform recovery functionality.
|
|
|
|
--*/
|
|
|
|
#include "PlatformEarlyInit.h"
|
|
|
|
#define PEI_FVMAIN_COMPACT_GUID \
|
|
{0x4A538818, 0x5AE0, 0x4eb2, 0xB2, 0xEB, 0x48, 0x8b, 0x23, 0x65, 0x70, 0x22};
|
|
|
|
EFI_GUID FvMainCompactFileGuid = PEI_FVMAIN_COMPACT_GUID;
|
|
|
|
//
|
|
// Required Service
|
|
//
|
|
EFI_STATUS
|
|
EFIAPI
|
|
PlatformRecoveryModule (
|
|
IN CONST EFI_PEI_SERVICES **PeiServices,
|
|
IN EFI_PEI_RECOVERY_MODULE_PPI *This
|
|
);
|
|
|
|
//
|
|
// Module globals
|
|
//
|
|
|
|
typedef struct {
|
|
EFI_GUID CapsuleGuid;
|
|
UINT32 HeaderSize;
|
|
UINT32 Flags;
|
|
UINT32 CapsuleImageSize;
|
|
UINT32 SequenceNumber;
|
|
EFI_GUID InstanceId;
|
|
UINT32 OffsetToSplitInformation;
|
|
UINT32 OffsetToCapsuleBody;
|
|
UINT32 OffsetToOemDefinedHeader;
|
|
UINT32 OffsetToAuthorInformation;
|
|
UINT32 OffsetToRevisionInformation;
|
|
UINT32 OffsetToShortDescription;
|
|
UINT32 OffsetToLongDescription;
|
|
UINT32 OffsetToApplicableDevices;
|
|
} OLD_EFI_CAPSULE_HEADER;
|
|
|
|
|
|
static EFI_PEI_RECOVERY_MODULE_PPI mRecoveryPpi = {
|
|
PlatformRecoveryModule
|
|
};
|
|
|
|
static EFI_PEI_PPI_DESCRIPTOR mRecoveryPpiList = {
|
|
(EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
|
|
&gEfiPeiRecoveryModulePpiGuid,
|
|
&mRecoveryPpi
|
|
};
|
|
|
|
/**
|
|
Provide the functionality of the Recovery Module.
|
|
|
|
@param PeiServices General purpose services available to every PEIM.
|
|
|
|
@retval Status EFI_SUCCESS if the interface could be successfully
|
|
installed
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
PeimInitializeRecovery (
|
|
IN CONST EFI_PEI_SERVICES **PeiServices
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
Status = (*PeiServices)->InstallPpi (
|
|
PeiServices,
|
|
&mRecoveryPpiList
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Provide the functionality of the Ea Recovery Module.
|
|
|
|
@param PeiServices General purpose services available to every PEIM.
|
|
@param This Pointer to PEI_RECOVERY_MODULE_INTERFACE.
|
|
|
|
@retval EFI_SUCCESS If the interface could be successfully
|
|
installed.
|
|
@retval EFI_UNSUPPORTED Not supported.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
PlatformRecoveryModule (
|
|
IN CONST EFI_PEI_SERVICES **PeiServices,
|
|
IN EFI_PEI_RECOVERY_MODULE_PPI *This
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *DeviceRecoveryModule;
|
|
UINTN NumberOfImageProviders;
|
|
BOOLEAN ProviderAvailable;
|
|
UINTN NumberRecoveryCapsules;
|
|
UINTN RecoveryCapsuleSize;
|
|
EFI_GUID DeviceId;
|
|
BOOLEAN ImageFound;
|
|
EFI_PHYSICAL_ADDRESS Address;
|
|
VOID *Buffer;
|
|
OLD_EFI_CAPSULE_HEADER *CapsuleHeader;
|
|
EFI_PEI_HOB_POINTERS Hob;
|
|
EFI_PEI_HOB_POINTERS HobOld;
|
|
EFI_HOB_CAPSULE_VOLUME *CapsuleHob;
|
|
BOOLEAN HobUpdate;
|
|
EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
|
|
UINTN Index;
|
|
BOOLEAN FoundFvMain;
|
|
BOOLEAN FoundCapsule;
|
|
static EFI_GUID mEfiCapsuleHeaderGuid = EFI_CAPSULE_GUID;
|
|
EFI_PEI_STALL_PPI *StallPpi;
|
|
|
|
(*PeiServices)->ReportStatusCode (
|
|
PeiServices,
|
|
EFI_PROGRESS_CODE,
|
|
EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEIM_PC_RECOVERY_BEGIN,
|
|
0,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
Status = (**PeiServices).LocatePpi (
|
|
PeiServices,
|
|
&gEfiPeiStallPpiGuid,
|
|
0,
|
|
NULL,
|
|
&StallPpi
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
StallPpi->Stall(
|
|
PeiServices,
|
|
StallPpi,
|
|
5000000
|
|
);
|
|
|
|
|
|
Index = 0;
|
|
|
|
Status = EFI_SUCCESS;
|
|
HobUpdate = FALSE;
|
|
|
|
ProviderAvailable = TRUE;
|
|
ImageFound = FALSE;
|
|
NumberOfImageProviders = 0;
|
|
|
|
DeviceRecoveryModule = NULL;
|
|
|
|
FoundCapsule = FALSE;
|
|
FoundFvMain = FALSE;
|
|
|
|
DEBUG ((EFI_D_ERROR | EFI_D_LOAD, "Recovery Entry\n"));
|
|
|
|
//
|
|
// Search the platform for some recovery capsule if the DXE IPL
|
|
// discovered a recovery condition and has requested a load.
|
|
//
|
|
while (ProviderAvailable == TRUE) {
|
|
|
|
Status = (*PeiServices)->LocatePpi (
|
|
PeiServices,
|
|
&gEfiPeiDeviceRecoveryModulePpiGuid,
|
|
Index,
|
|
NULL,
|
|
&DeviceRecoveryModule
|
|
);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Device Recovery PPI located\n"));
|
|
NumberOfImageProviders++;
|
|
|
|
Status = DeviceRecoveryModule->GetNumberRecoveryCapsules (
|
|
(EFI_PEI_SERVICES**)PeiServices,
|
|
DeviceRecoveryModule,
|
|
&NumberRecoveryCapsules
|
|
);
|
|
|
|
DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Number Of Recovery Capsules: %d\n", NumberRecoveryCapsules));
|
|
|
|
if (NumberRecoveryCapsules == 0) {
|
|
Index++;
|
|
} else {
|
|
break;
|
|
}
|
|
} else {
|
|
ProviderAvailable = FALSE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If there is an image provider, get the capsule ID
|
|
//
|
|
if (ProviderAvailable) {
|
|
RecoveryCapsuleSize = 0;
|
|
|
|
Status = DeviceRecoveryModule->GetRecoveryCapsuleInfo (
|
|
(EFI_PEI_SERVICES**)PeiServices,
|
|
DeviceRecoveryModule,
|
|
0,
|
|
&RecoveryCapsuleSize,
|
|
&DeviceId
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Recovery Capsule Size: %d\n", RecoveryCapsuleSize));
|
|
|
|
//
|
|
// Only support the 2 capsule types known
|
|
// Future enhancement is to rank-order the selection
|
|
//
|
|
if ((!CompareGuid (&DeviceId, &gRecoveryOnFatIdeDiskGuid)) &&
|
|
(!CompareGuid (&DeviceId, &gRecoveryOnFatFloppyDiskGuid)) &&
|
|
(!CompareGuid (&DeviceId, &gRecoveryOnDataCdGuid)) &&
|
|
(!CompareGuid (&DeviceId, &gRecoveryOnFatUsbDiskGuid))
|
|
) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
Buffer = NULL;
|
|
Status = (*PeiServices)->AllocatePages (
|
|
PeiServices,
|
|
EfiBootServicesCode,
|
|
(RecoveryCapsuleSize - 1) / 0x1000 + 1,
|
|
&Address
|
|
);
|
|
|
|
DEBUG ((EFI_D_INFO | EFI_D_LOAD, "AllocatePage Returns: %r\n", Status));
|
|
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Buffer = (UINT8 *) (UINTN) Address;
|
|
|
|
(*PeiServices)->ReportStatusCode (
|
|
PeiServices,
|
|
EFI_PROGRESS_CODE,
|
|
EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEIM_PC_CAPSULE_LOAD,
|
|
0,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
Status = DeviceRecoveryModule->LoadRecoveryCapsule (
|
|
(EFI_PEI_SERVICES**)PeiServices,
|
|
DeviceRecoveryModule,
|
|
0,
|
|
Buffer
|
|
);
|
|
|
|
DEBUG ((EFI_D_INFO | EFI_D_LOAD, "LoadRecoveryCapsule Returns: %r\n", Status));
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Update FV Hob if found
|
|
//
|
|
Status = (*PeiServices)->GetHobList (PeiServices, &Hob.Raw);
|
|
HobOld.Raw = Hob.Raw;
|
|
while (!END_OF_HOB_LIST (Hob)) {
|
|
if (Hob.Header->HobType == EFI_HOB_TYPE_FV) {
|
|
DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Hob FV Length: %x\n", Hob.FirmwareVolume->Length));
|
|
//
|
|
// BUGBUG Why is it a FV hob if it is greater than 0x50000?
|
|
//
|
|
if (Hob.FirmwareVolume->Length > 0x50000) {
|
|
HobUpdate = TRUE;
|
|
//
|
|
// This looks like the Hob we are interested in
|
|
//
|
|
DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Hob Updated\n"));
|
|
Hob.FirmwareVolume->BaseAddress = (UINTN) Buffer;
|
|
Hob.FirmwareVolume->Length = RecoveryCapsuleSize;
|
|
}
|
|
}
|
|
Hob.Raw = GET_NEXT_HOB (Hob);
|
|
}
|
|
|
|
FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)Buffer;
|
|
CapsuleHeader = (OLD_EFI_CAPSULE_HEADER *)Buffer;
|
|
|
|
//
|
|
// Check if top of file is a capsule
|
|
//
|
|
if (CompareGuid ((EFI_GUID *)CapsuleHeader, &mEfiCapsuleHeaderGuid)) {
|
|
FoundCapsule = TRUE;
|
|
} else if (FvHeader->Signature == EFI_FVH_SIGNATURE) {
|
|
//
|
|
// Assume the Firmware volume is a "FVMAIN" image
|
|
//
|
|
FoundFvMain = TRUE;
|
|
}
|
|
|
|
if (FoundFvMain) {
|
|
//
|
|
// build FV Hob if it is not built before
|
|
//
|
|
if (!HobUpdate) {
|
|
DEBUG ((EFI_D_INFO | EFI_D_LOAD, "FV Hob is not found, Build FV Hob then..\n"));
|
|
|
|
BuildFvHob (
|
|
(UINTN)FvHeader,
|
|
FvHeader->FvLength
|
|
);
|
|
}
|
|
}
|
|
|
|
if (FoundCapsule) {
|
|
//
|
|
// Build capsule hob
|
|
//
|
|
Status = (*PeiServices)->CreateHob (
|
|
PeiServices,
|
|
EFI_HOB_TYPE_CV,
|
|
sizeof (EFI_HOB_CAPSULE_VOLUME),
|
|
&CapsuleHob
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
CapsuleHob->BaseAddress = (UINT64)((UINTN)CapsuleHeader + (UINTN)CapsuleHeader->OffsetToCapsuleBody);
|
|
CapsuleHob->Length = (UINT64)((UINTN)CapsuleHeader->CapsuleImageSize -(UINTN)CapsuleHeader->OffsetToCapsuleBody);
|
|
(*PeiServices)->ReportStatusCode (
|
|
PeiServices,
|
|
EFI_PROGRESS_CODE,
|
|
EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEIM_PC_CAPSULE_START,
|
|
0,
|
|
NULL,
|
|
NULL
|
|
);
|
|
}
|
|
}
|
|
DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Recovery Module Returning: %r\n", Status));
|
|
return Status;
|
|
}
|