mirror of https://github.com/acidanthera/audk.git
496 lines
14 KiB
C
496 lines
14 KiB
C
/** @file
|
|
Install Platform EFI_PEI_RECOVERY_MODULE_PPI and Implementation of
|
|
EFI_PEI_LOAD_RECOVERY_CAPSULE service.
|
|
|
|
Copyright (c) 2013-2016 Intel Corporation.
|
|
|
|
This program and the accompanying materials
|
|
are licensed and made available under the terms and conditions of the BSD License
|
|
which accompanies this distribution. The full text of the license may be found at
|
|
http://opensource.org/licenses/bsd-license.php
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
|
**/
|
|
|
|
#include "CommonHeader.h"
|
|
#include "PlatformEarlyInit.h"
|
|
|
|
#include <Ppi/BlockIo.h>
|
|
|
|
//
|
|
// Capsule Types supported in this platform module
|
|
//
|
|
#include <Guid/CapsuleOnFatFloppyDisk.h>
|
|
#include <Guid/CapsuleOnFatIdeDisk.h>
|
|
#include <Guid/CapsuleOnFatUsbDisk.h>
|
|
#include <Guid/CapsuleOnDataCD.h>
|
|
#include <Guid/QuarkCapsuleGuid.h>
|
|
|
|
#include <Ppi/RecoveryModule.h>
|
|
#include <Ppi/DeviceRecoveryModule.h>
|
|
|
|
#include <Library/PeiServicesLib.h>
|
|
|
|
//
|
|
// Required Service
|
|
//
|
|
EFI_STATUS
|
|
EFIAPI
|
|
PlatformRecoveryModule (
|
|
IN EFI_PEI_SERVICES **PeiServices,
|
|
IN EFI_PEI_RECOVERY_MODULE_PPI *This
|
|
);
|
|
|
|
VOID
|
|
AssertNoCapsulesError (
|
|
IN EFI_PEI_SERVICES **PeiServices
|
|
);
|
|
|
|
VOID
|
|
AssertMediaDeviceError (
|
|
IN EFI_PEI_SERVICES **PeiServices
|
|
);
|
|
|
|
VOID
|
|
ReportLoadCapsuleSuccess (
|
|
IN EFI_PEI_SERVICES **PeiServices
|
|
);
|
|
|
|
VOID
|
|
CheckIfMediaPresentOnBlockIoDevice (
|
|
IN EFI_PEI_SERVICES **PeiServices,
|
|
IN OUT BOOLEAN *MediaDeviceError,
|
|
IN OUT BOOLEAN *MediaPresent
|
|
);
|
|
|
|
//
|
|
// Module globals
|
|
//
|
|
EFI_PEI_RECOVERY_MODULE_PPI mRecoveryPpi = { PlatformRecoveryModule };
|
|
|
|
EFI_PEI_PPI_DESCRIPTOR mRecoveryPpiList = {
|
|
(EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
|
|
&gEfiPeiRecoveryModulePpiGuid,
|
|
&mRecoveryPpi
|
|
};
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
PeimInitializeRecovery (
|
|
IN EFI_PEI_SERVICES **PeiServices
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Provide the functionality of the Recovery Module.
|
|
|
|
Arguments:
|
|
|
|
PeiServices - General purpose services available to every PEIM.
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS - If the interface could be successfully
|
|
installed.
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
Status = PeiServicesInstallPpi (&mRecoveryPpiList);
|
|
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
PlatformRecoveryModule (
|
|
IN EFI_PEI_SERVICES **PeiServices,
|
|
IN EFI_PEI_RECOVERY_MODULE_PPI *This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Provide the functionality of the Platform Recovery Module.
|
|
|
|
Arguments:
|
|
|
|
PeiServices - General purpose services available to every PEIM.
|
|
This - Pointer to EFI_PEI_RECOVERY_MODULE_PPI.
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS - If the interface could be successfully
|
|
installed.
|
|
EFI_UNSUPPORTED - Not supported.
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *DeviceRecoveryModule;
|
|
UINTN NumberOfImageProviders;
|
|
BOOLEAN ProviderAvailable;
|
|
UINTN NumberRecoveryCapsules;
|
|
UINTN RecoveryCapsuleSize;
|
|
EFI_GUID DeviceId;
|
|
EFI_PHYSICAL_ADDRESS Address;
|
|
VOID *Buffer;
|
|
EFI_CAPSULE_HEADER *CapsuleHeader;
|
|
EFI_PEI_HOB_POINTERS Hob;
|
|
BOOLEAN HobUpdate;
|
|
EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
|
|
UINTN Index;
|
|
EFI_GUID mEfiCapsuleHeaderGuid = QUARK_CAPSULE_GUID;
|
|
|
|
Index = 0;
|
|
|
|
Status = EFI_SUCCESS;
|
|
HobUpdate = FALSE;
|
|
|
|
ProviderAvailable = TRUE;
|
|
NumberOfImageProviders = 0;
|
|
|
|
DeviceRecoveryModule = NULL;
|
|
|
|
DEBUG ((EFI_D_INFO | 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) {
|
|
|
|
Status = PeiServicesLocatePpi (
|
|
&gEfiPeiDeviceRecoveryModulePpiGuid,
|
|
Index,
|
|
NULL,
|
|
(VOID **)&DeviceRecoveryModule
|
|
);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Device Recovery PPI located\n"));
|
|
NumberOfImageProviders++;
|
|
|
|
Status = DeviceRecoveryModule->GetNumberRecoveryCapsules (
|
|
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;
|
|
}
|
|
}
|
|
//
|
|
// The number of recovery capsules is 0.
|
|
//
|
|
if (!ProviderAvailable) {
|
|
AssertNoCapsulesError (PeiServices);
|
|
}
|
|
//
|
|
// If there is an image provider, get the capsule ID
|
|
//
|
|
if (ProviderAvailable) {
|
|
RecoveryCapsuleSize = 0;
|
|
if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {
|
|
Status = DeviceRecoveryModule->GetRecoveryCapsuleInfo (
|
|
PeiServices,
|
|
DeviceRecoveryModule,
|
|
0,
|
|
&RecoveryCapsuleSize,
|
|
&DeviceId
|
|
);
|
|
} else {
|
|
Status = DeviceRecoveryModule->GetRecoveryCapsuleInfo (
|
|
PeiServices,
|
|
DeviceRecoveryModule,
|
|
1,
|
|
&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, &gPeiCapsuleOnFatIdeDiskGuid)) &&
|
|
(!CompareGuid (&DeviceId, &gPeiCapsuleOnDataCDGuid)) &&
|
|
(!CompareGuid (&DeviceId, &gPeiCapsuleOnFatUsbDiskGuid))
|
|
) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
Buffer = NULL;
|
|
Address = (UINTN) AllocatePages ((RecoveryCapsuleSize - 1) / 0x1000 + 1);
|
|
ASSERT (Address);
|
|
|
|
Buffer = (UINT8 *) (UINTN) Address;
|
|
if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {
|
|
Status = DeviceRecoveryModule->LoadRecoveryCapsule (
|
|
PeiServices,
|
|
DeviceRecoveryModule,
|
|
0,
|
|
Buffer
|
|
);
|
|
} else {
|
|
Status = DeviceRecoveryModule->LoadRecoveryCapsule (
|
|
PeiServices,
|
|
DeviceRecoveryModule,
|
|
1,
|
|
Buffer
|
|
);
|
|
|
|
}
|
|
|
|
DEBUG ((EFI_D_INFO | EFI_D_LOAD, "LoadRecoveryCapsule Returns: %r\n", Status));
|
|
|
|
if (Status == EFI_DEVICE_ERROR) {
|
|
AssertMediaDeviceError (PeiServices);
|
|
}
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
} else {
|
|
ReportLoadCapsuleSuccess (PeiServices);
|
|
}
|
|
|
|
//
|
|
// Update FV Hob if found
|
|
//
|
|
Buffer = (VOID *)((UINT8 *) Buffer);
|
|
Status = PeiServicesGetHobList ((VOID **)&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));
|
|
|
|
if (Hob.FirmwareVolume->BaseAddress == (UINTN) PcdGet32 (PcdFlashFvMainBase)) {
|
|
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);
|
|
}
|
|
//
|
|
// Check if the top of the file is a firmware volume header
|
|
//
|
|
FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) Buffer;
|
|
CapsuleHeader = (EFI_CAPSULE_HEADER *) Buffer;
|
|
if (FvHeader->Signature == EFI_FVH_SIGNATURE) {
|
|
//
|
|
// 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) Buffer,
|
|
FvHeader->FvLength
|
|
);
|
|
|
|
DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Install FV Info PPI..\n"));
|
|
|
|
PeiServicesInstallFvInfoPpi (
|
|
NULL,
|
|
Buffer,
|
|
(UINT32) FvHeader->FvLength,
|
|
NULL,
|
|
NULL
|
|
);
|
|
}
|
|
//
|
|
// Point to the location immediately after the FV.
|
|
//
|
|
CapsuleHeader = (EFI_CAPSULE_HEADER *) ((UINT8 *) Buffer + FvHeader->FvLength);
|
|
}
|
|
|
|
//
|
|
// Check if pointer is still within the buffer
|
|
//
|
|
if ((UINTN) CapsuleHeader < (UINTN) ((UINT8 *) Buffer + RecoveryCapsuleSize)) {
|
|
|
|
//
|
|
// Check if it is a capsule
|
|
//
|
|
if (CompareGuid ((EFI_GUID *) CapsuleHeader, &mEfiCapsuleHeaderGuid)) {
|
|
|
|
//
|
|
// Set bootmode to capsule update so the capsule hob gets the right bootmode in the hob header.
|
|
//
|
|
Status = PeiServicesSetBootMode (BOOT_ON_FLASH_UPDATE);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Build capsule hob
|
|
//
|
|
BuildCvHob ((EFI_PHYSICAL_ADDRESS)(UINTN)CapsuleHeader, (UINT64)CapsuleHeader->CapsuleImageSize);
|
|
}
|
|
}
|
|
}
|
|
|
|
DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Recovery Module Returning: %r\n", Status));
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
AssertNoCapsulesError:
|
|
There were no recovery capsules found.
|
|
Case 1: Report the error that no recovery block io device/media is readable and assert.
|
|
Case 2: Report the error that there is no media present on any recovery block io device and assert.
|
|
Case 3: There is media present on some recovery block io device,
|
|
but there is no recovery capsule on it. Report the error and assert.
|
|
*/
|
|
VOID
|
|
AssertNoCapsulesError (
|
|
IN EFI_PEI_SERVICES **PeiServices
|
|
)
|
|
{
|
|
BOOLEAN MediaDeviceError;
|
|
BOOLEAN MediaPresent;
|
|
|
|
MediaDeviceError = TRUE;
|
|
MediaPresent = FALSE;
|
|
|
|
CheckIfMediaPresentOnBlockIoDevice (PeiServices, &MediaDeviceError, &MediaPresent);
|
|
/* if (MediaDeviceError) {
|
|
ReportStatusCode (
|
|
(EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED),
|
|
(EFI_PERIPHERAL_RECOVERY_MEDIA | EFI_P_EC_MEDIA_DEVICE_ERROR)
|
|
);
|
|
|
|
} else if (!MediaPresent) {
|
|
ReportStatusCode (
|
|
(EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED),
|
|
(EFI_PERIPHERAL_RECOVERY_MEDIA | EFI_P_EC_MEDIA_NOT_PRESENT)
|
|
);
|
|
|
|
} else {
|
|
ReportStatusCode (
|
|
(EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED),
|
|
(EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEIM_EC_NO_RECOVERY_CAPSULE)
|
|
);
|
|
}*/
|
|
//
|
|
// Hang.
|
|
//
|
|
CpuDeadLoop();
|
|
}
|
|
|
|
#define MAX_BLOCK_IO_PPI 32
|
|
|
|
/*
|
|
CheckIfMediaPresentOnBlockIoDevice:
|
|
Checks to see whether there was a media device error or to see if there is media present.
|
|
*/
|
|
VOID
|
|
CheckIfMediaPresentOnBlockIoDevice (
|
|
IN EFI_PEI_SERVICES **PeiServices,
|
|
IN OUT BOOLEAN *MediaDeviceError,
|
|
IN OUT BOOLEAN *MediaPresent
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN BlockIoPpiInstance;
|
|
EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi;
|
|
UINTN NumberBlockDevices;
|
|
EFI_PEI_BLOCK_IO_MEDIA Media;
|
|
|
|
*MediaDeviceError = TRUE;
|
|
*MediaPresent = FALSE;
|
|
|
|
for (BlockIoPpiInstance = 0; BlockIoPpiInstance < MAX_BLOCK_IO_PPI; BlockIoPpiInstance++) {
|
|
Status = PeiServicesLocatePpi (
|
|
&gEfiPeiVirtualBlockIoPpiGuid,
|
|
BlockIoPpiInstance,
|
|
NULL,
|
|
(VOID **)&BlockIoPpi
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
//
|
|
// Done with all Block Io Ppis
|
|
//
|
|
break;
|
|
}
|
|
|
|
Status = BlockIoPpi->GetNumberOfBlockDevices (
|
|
PeiServices,
|
|
BlockIoPpi,
|
|
&NumberBlockDevices
|
|
);
|
|
if (EFI_ERROR (Status) || (NumberBlockDevices == 0)) {
|
|
continue;
|
|
}
|
|
//
|
|
// Just retrieve the first block
|
|
//
|
|
Status = BlockIoPpi->GetBlockDeviceMediaInfo (
|
|
PeiServices,
|
|
BlockIoPpi,
|
|
0,
|
|
&Media
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
*MediaDeviceError = FALSE;
|
|
if (Media.MediaPresent) {
|
|
*MediaPresent = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID
|
|
AssertMediaDeviceError (
|
|
IN EFI_PEI_SERVICES **PeiServices
|
|
)
|
|
{
|
|
/* ReportStatusCode (
|
|
(EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED),
|
|
(EFI_PERIPHERAL_RECOVERY_MEDIA | EFI_P_EC_MEDIA_DEVICE_ERROR)
|
|
);
|
|
*/
|
|
CpuDeadLoop ();
|
|
}
|
|
|
|
VOID
|
|
ReportLoadCapsuleSuccess (
|
|
IN EFI_PEI_SERVICES **PeiServices
|
|
)
|
|
{
|
|
//
|
|
// EFI_SW_PEI_PC_CAPSULE_START: (from the status code spec):
|
|
// Loaded the recovery capsule. About to hand off control to the capsule.
|
|
//
|
|
/* ReportStatusCode (
|
|
EFI_PROGRESS_CODE,
|
|
(EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEIM_PC_CAPSULE_LOAD_SUCCESS)
|
|
);*/
|
|
}
|
|
|