alder_lake_bios/Intel/AlderLake/AlderLakeChipsetPkg/Library/PeiSeamlessRecoveryLibSysFw/SeamlessRecoveryLib.c

647 lines
15 KiB
C

/** @file
Lite version of SeamlessRecoveryLib for PEIMs before memory initialization
;******************************************************************************
;* Copyright (c) 2020 - 2021, Insyde Software Corp. All Rights Reserved.
;*
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
;* transmit, broadcast, present, recite, release, license or otherwise exploit
;* any part of this publication in any form, by any means, without the prior
;* written permission of Insyde Software Corporation.
;*
;******************************************************************************
*/
#include <Uefi.h>
#include <Library/PcdLib.h>
#include <Library/DebugLib.h>
#include <Library/PeiServicesLib.h>
#include <Library/HobLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/FlashRegionLib.h>
#include <Library/VariableLib.h>
#include <Library/SeamlessRecoveryLib.h>
#include <Library/SpiAccessLib.h>
#include <Guid/SysFwUpdateProgress.h>
#include <Library/PciSegmentLib.h>
#include <Library/PchPciBdfLib.h>
#include <Register/SpiRegs.h>
/**
Check whether it is in firmware failure recovery mode
@param None
@retval TRUE The system is in firmware failure recovery mode
FALSE The system is not in firmware failure recovery mode
**/
BOOLEAN
EFIAPI
IsFirmwareFailureRecovery (
VOID
)
{
EFI_GUID *RecoverySig;
RecoverySig = (EFI_GUID *)(UINTN) FdmGetNAtAddr (&gH2OFlashMapRegionFtwBackupGuid ,1);
if (RecoverySig != NULL && CompareGuid( PcdGetPtr(PcdSeamlessRecoverySignature), RecoverySig) ) {
return TRUE;
}
return FALSE;
}
/**
Set firmware updating in process signature, not supported if PEI memory is not initialized
@param None
@returns None
**/
VOID
EFIAPI
SetFirmwareUpdatingFlag (
BOOLEAN FirmwareUpdatingFlag
)
{
//
// not supported
//
return;
}
/**
Set firmware updating progress.
@param[in] Progress Update progress
@retval EFI_SUCCESS Operation completed successfully.
@retval Others Operation was unsuccessful.
**/
EFI_STATUS
EFIAPI
SetFirmwareUpdateProgress (
IN UINT32 Progress
)
{
//
// not supported
//
return EFI_UNSUPPORTED;
}
/**
Get firmware updating progress.
@param[out] Progress Update progress
@retval EFI_SUCCESS Operation completed successfully.
@retval Others Operation was unsuccessful.
**/
EFI_STATUS
EFIAPI
GetFirmwareUpdateProgress (
OUT UINT32 *Progress
)
{
EFI_HOB_GUID_TYPE *GuidHob;
GuidHob = GetFirstGuidHob (&gH2OSeamlessRecoveryGuid);
if (GuidHob == NULL) {
return EFI_NOT_FOUND;
}
*Progress = *(UINT32 *)GET_GUID_HOB_DATA (GuidHob);
return EFI_SUCCESS;
}
/**
Check whether there was a firmware update interrupted.
@retval TRUE Fimware update was interrupted.
FALSE No fimware update was interrupted.
**/
BOOLEAN
EFIAPI
IsFirmwareUpdateInterrupted (
VOID
)
{
EFI_STATUS Status;
UINT32 Data32;
Status = GetFirmwareUpdateProgress (&Data32);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "Failed to get Progress hob -%r\n"));
return FALSE;
}
return (Data32 > FlashStart) && (Data32 < FlashResiliency);
}
/**
Clear firmware updating progress.
@retval EFI_SUCCESS Operation completed successfully.
@retval Others Operation was unsuccessful.
**/
EFI_STATUS
EFIAPI
ClearFirmwareUpdateProgress (
VOID
)
{
//
// not supported
//
return EFI_UNSUPPORTED;
}
/**
Check whether firmware update resiliency is supported.
@retval TRUE Firmware update resiliecny is supported.
FALSE Firmware update resiliecny is not supported.
**/
BOOLEAN
EFIAPI
IsFirmwareUpdateResiliencySupported (
VOID
)
{
return FeaturePcdGet (PcdH2OBiosUpdateFaultToleranceResiliencyEnabled);
}
BOOLEAN
PeiIsTopSwapEnabled (
VOID
)
{
return !!(PciSegmentRead32 (SpiPciCfgBase () + R_SPI_CFG_BC) & B_SPI_CFG_BC_TSS);
}
/**
Check whether firmware update resiliency is enabled.
@retval TRUE Firmware update resiliency is enabled.
FALSE Firmware update resiliency is not enabled.
**/
BOOLEAN
EFIAPI
IsFirmwareUpdateResiliencyEnabled (
VOID
)
{
EFI_STATUS Status;
UINT32 Data32;
EFI_HOB_GUID_TYPE *GuidHob;
BOOLEAN TopSwapStatus;
TopSwapStatus = FALSE;
if (!IsFirmwareUpdateResiliencySupported ()) {
return FALSE;
}
GuidHob = GetFirstGuidHob (&gChasmfallsTopSwapStatusGuid);
if (GuidHob != NULL) {
TopSwapStatus = *((BOOLEAN *) GET_GUID_HOB_DATA (GuidHob));
}
Status = GetFirmwareUpdateProgress (&Data32);
if (EFI_ERROR (Status)) {
if (PeiIsTopSwapEnabled()){
return TRUE;
} else if (TopSwapStatus) {
return TRUE;
}
return FALSE;
}
return (Data32 == FlashResiliency);
}
/**
Create hobs for H2O progress.
@retval EFI_SUCCESS Operation completed successfully.
@retval Others Operation was unsuccessful.
**/
STATIC
EFI_STATUS
CreateH2OSeamlessRecoveryHob (
VOID
)
{
EFI_STATUS Status;
UINT32 Data32;
UINTN DataSize;
EFI_HOB_GUID_TYPE *GuidHob;
Status = EFI_SUCCESS;
GuidHob = GetFirstGuidHob (&gH2OSeamlessRecoveryGuid);
if (GuidHob == NULL) {
DataSize = sizeof (UINT32);
Status = CommonGetVariable (
UPDATE_PROGRESS_NAME,
&gH2OSeamlessRecoveryGuid,
&DataSize,
&Data32
);
if (!EFI_ERROR (Status)) {
BuildGuidDataHob (&gH2OSeamlessRecoveryGuid, &Data32, sizeof (UINT32));
}
}
return Status;
}
/**
Create hobs for digest.
@retval EFI_SUCCESS Operation completed successfully.
@retval Others Operation was unsuccessful.
**/
STATIC
EFI_STATUS
CreateH2OSeamlessRecoveryDigestHob (
VOID
)
{
EFI_STATUS Status;
EFI_HOB_GUID_TYPE *GuidHob;
VOID *Sha256DigestInFv;
EFI_PEI_FILE_HANDLE DigestFileHandle;
Sha256DigestInFv = NULL;
DigestFileHandle = NULL;
GuidHob = GetFirstGuidHob (&gH2OSeamlessRecoveryDigestGuid);
if (GuidHob == NULL) {
Status = PeiServicesFfsFindFileByName (&gSbbDigestGuid, (EFI_PEI_FV_HANDLE) FixedPcdGet32 (PcdFlashFvRecoveryBase), &DigestFileHandle);
if (!EFI_ERROR (Status)) {
//
// Search RAW section.
//
Status = PeiServicesFfsFindSectionData (EFI_SECTION_RAW, DigestFileHandle, &Sha256DigestInFv);
if (!EFI_ERROR (Status)) {
DEBUG ((DEBUG_INFO, "Find Obb digest on ROM:\n"));
BuildGuidDataHob (&gH2OSeamlessRecoveryDigestGuid, Sha256DigestInFv, SHA256_DIGEST_SIZE);
}
}
}
return EFI_SUCCESS;
}
/**
Get SysFw update progress.
@retval EFI_SUCCESS Operation completed successfully.
@retval Others Operation was unsuccessful.
**/
STATIC
EFI_STATUS
GetSysFwUpdateProgress (
OUT SYSTEM_FIRMWARE_UPDATE_PROGRESS *UpdatePorgress
)
{
EFI_STATUS Status;
UINTN DataSize;
SYSTEM_FIRMWARE_UPDATE_PROGRESS TempUpdatePorgress;
//
// Only flash interrupted case will exist progress variable.
//
DataSize = sizeof (SYSTEM_FIRMWARE_UPDATE_PROGRESS);
Status = CommonGetVariable (
SYSFW_UPDATE_PROGRESS_VARIABLE_NAME,
&gSysFwUpdateProgressGuid,
&DataSize,
&TempUpdatePorgress
);
if (EFI_ERROR (Status)) {
return Status;
}
CopyMem (UpdatePorgress, &TempUpdatePorgress, sizeof (SYSTEM_FIRMWARE_UPDATE_PROGRESS));
return EFI_SUCCESS;
}
/**
Get sysfw update digest.
@retval EFI_SUCCESS Operation completed successfully.
@retval Others Operation was unsuccessful.
**/
STATIC
EFI_STATUS
CreateSysFwUpdateDigestHob (
VOID
)
{
EFI_STATUS Status;
UINTN DataSize;
UINT8 Sha256Variable[SHA256_DIGEST_SIZE];
EFI_HOB_GUID_TYPE *GuidHob;
GuidHob = GetFirstGuidHob (&gSysFwUpdateDigiestGuid);
if (GuidHob != NULL) {
//
// Already exists
//
return EFI_SUCCESS;
}
DataSize = SHA256_DIGEST_SIZE;
ZeroMem (Sha256Variable, SHA256_DIGEST_SIZE);
Status = CommonGetVariable (
SYSBIOS_NEW_CAPSULE_DIGEST_VARIABLE_NAMEN,
&gSysFwUpdateDigiestGuid,
&DataSize,
&Sha256Variable
);
if (EFI_ERROR (Status)) {
return Status;
}
BuildGuidDataHob (&gSysFwUpdateDigiestGuid, Sha256Variable, DataSize);
return EFI_SUCCESS;
}
/**
Trunk SysFwUpdate & H2O progress.
@retval EFI_SUCCESS Operation completed successfully.
@retval Others Operation was unsuccessful.
**/
STATIC
EFI_STATUS
SysFwUpdateProgressHobThunk (
VOID
)
{
EFI_STATUS Status;
SYSTEM_FIRMWARE_UPDATE_PROGRESS UpdatePorgress;
UINT32 H2OProgress;
EFI_HOB_GUID_TYPE *GuidHob;
Status = GetSysFwUpdateProgress (&UpdatePorgress);
if (EFI_ERROR (Status)) {
return Status;
}
GuidHob = GetFirstGuidHob (&gSysFwUpdateProgressGuid);
if (GuidHob == NULL) {
BuildGuidDataHob (&gSysFwUpdateProgressGuid, &UpdatePorgress, sizeof (SYSTEM_FIRMWARE_UPDATE_PROGRESS));
}
if ((UpdatePorgress.Component != UpdatingBios) &&
(UpdatePorgress.Component != UpdatingResiliency) &&
(UpdatePorgress.Component != UpdatinguCode) &&
(UpdatePorgress.Component != UpdatingBtGAcm)) {
return EFI_UNSUPPORTED;
}
if (UpdatePorgress.Component == UpdatingBios) {
if (IsFirmwareUpdateResiliencySupported ()) {
switch (UpdatePorgress.Progress) {
case BiosIbbR:
H2OProgress = FlashPbb;
break;
case BiosIbb:
H2OProgress = FlashSbb;
break;
default:
H2OProgress = FlashMax;
break;
}
} else {
switch (UpdatePorgress.Progress) {
case BiosIbbR:
H2OProgress = FlashPbbR;
break;
case BiosIbb:
H2OProgress = FlashPbb;
break;
case BiosObb:
H2OProgress = FlashSbb;
break;
default:
H2OProgress = FlashMax;
break;
}
}
} else if (UpdatePorgress.Component == UpdatingResiliency) {
H2OProgress = FlashResiliency;
} else if (UpdatePorgress.Component == UpdatinguCode) {
H2OProgress = FlashPbb;
} else if (UpdatePorgress.Component == UpdatingBtGAcm) {
switch (UpdatePorgress.Progress) {
case BiosIbbR:
H2OProgress = FlashPbb;
break;
default:
H2OProgress = FlashMax;
break;
}
}
GuidHob = GetFirstGuidHob (&gH2OSeamlessRecoveryGuid);
if (GuidHob == NULL) {
BuildGuidDataHob (&gH2OSeamlessRecoveryGuid, &H2OProgress, sizeof (UINT32));
}
CreateSysFwUpdateDigestHob ();
return EFI_SUCCESS;
}
/**
Trunk SysFwUpdate & H2O progress.
@retval EFI_SUCCESS Operation completed successfully.
@retval Others Operation was unsuccessful.
**/
STATIC
EFI_STATUS
FmpCapsuleInfoThunk (
VOID
)
{
EFI_STATUS Status;
EFI_HOB_GUID_TYPE *GuidHob;
UINT32 H2OProgress;
UINTN DataSize;
SYSTEM_FIRMWARE_COMPONENT Component;
UINT64 OsIndications;
SYSTEM_FIRMWARE_UPDATE_PROGRESS UpdatePorgress;
UINT32 Data32;
if (PcdGet8(PcdChasmFallsSupport) == 1){
GuidHob = GetFirstGuidHob (&gChasmfallsCrisisRecoveryGuid);
if (GuidHob != NULL) {
H2OProgress = FlashStart;
UpdatePorgress.Component = UpdatingBios;
UpdatePorgress.Progress = 0;
goto BuildHob;
}
}
//
// Capsule put in HDD.
// Insyde capsule will set progress variable to FlashStart in DxeCapsuleLib.
//
DataSize = sizeof (SYSTEM_FIRMWARE_COMPONENT);
Status = CommonGetVariable (
L"FmpCapsuleInfo",
&gFmpCapsuleInfoGuid,
&DataSize,
&Component
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// If it is capsule update?
//
DataSize = sizeof (UINT64);
Status = CommonGetVariable (
L"OsIndications",
&gEfiGlobalVariableGuid,
&DataSize,
&OsIndications
);
if (EFI_ERROR (Status)) {
return Status;
}
if ((OsIndications & EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED) == 0) {
return EFI_UNSUPPORTED;
}
if (Component == UpdatingBios) {
H2OProgress = FlashStart;
UpdatePorgress.Component = UpdatingBios;
UpdatePorgress.Progress = 0;
} else if (Component == UpdatinguCode) {
H2OProgress = FlashStart;
UpdatePorgress.Component = UpdatinguCode;
UpdatePorgress.Progress = 0;
} else if (Component == UpdatingBtGAcm) {
H2OProgress = FlashStart;
UpdatePorgress.Component = UpdatingBtGAcm;
UpdatePorgress.Progress = 0;
} else if (Component == UpdatingTypeMax){
// Monolithic update. Sync bios's progress.
DataSize = sizeof (UINT32);
Status = CommonGetVariable (
UPDATE_PROGRESS_NAME,
&gH2OSeamlessRecoveryGuid,
&DataSize,
&Data32
);
if (!EFI_ERROR (Status)) {
BuildGuidDataHob (&gH2OSeamlessRecoveryGuid, &Data32, sizeof (UINT32));
return EFI_SUCCESS;
} else {
// First time do capsule update.
H2OProgress = FlashStart;
UpdatePorgress.Component = UpdatingBios;
UpdatePorgress.Progress = 0;
}
} else {
//
// Not support device firmware case.
//
return EFI_UNSUPPORTED;
}
BuildHob:
//
// Create insyde progress hob to disable bioslock.
//
GuidHob = GetFirstGuidHob (&gH2OSeamlessRecoveryGuid);
if (GuidHob == NULL) {
BuildGuidDataHob (&gH2OSeamlessRecoveryGuid, &H2OProgress, sizeof (UINT32));
}
return EFI_SUCCESS;
}
/**
The constructor function of PeiSeamlessRecoveryLib.
@param FileHandle The handle of FFS header the loaded driver.
@param PeiServices The pointer to the PEI services.
@retval EFI_SUCCESS The constructor executes successfully.
@retval EFI_OUT_OF_RESOURCES There is no enough resource for the constructor.
**/
EFI_STATUS
EFIAPI
SeamlessRecoveryLibConstructor (
IN EFI_PEI_FILE_HANDLE FileHandle,
IN CONST EFI_PEI_SERVICES **PeiServices
)
{
EFI_STATUS Status;
//
// First sync intel progress variable to insyde progress variable.
// There are two case.
//
//
// (2) Flash interrupted case,
// Sync progress varialbe for recovery to load old/new dxe and disable bios lock.
//
Status = SysFwUpdateProgressHobThunk ();
if (EFI_ERROR (Status)) {
//
// (1) First time to do capsule update.
// Build progress hob to disable bios lock.
//
Status = FmpCapsuleInfoThunk ();
}
//
// No intel capsule.
// Only build insyde progress hob to disable bioslock or recovery to load old dxe or new dxe.
//
if (EFI_ERROR (Status)) {
CreateH2OSeamlessRecoveryHob ();
}
//
// Create sbb digest hob for case(2) to load old obb.
// Both Intel and Insyde used.
//
CreateH2OSeamlessRecoveryDigestHob ();
return EFI_SUCCESS;
}