alder_lake_bios/Board/Oem/L05AlderLakeSMultiBoardPkg/Library/PeiOemSvcKernelLib/OemSvcDetectRecoveryRequest.c

222 lines
6.8 KiB
C

/** @file
This OemService provides OEM to decide the method of recovery request.
When DXE loader found that the DXE-core of firmware volume is corrupt, it will force system to restart.
This service will be called to set the recovery requests before system restart.
To design the recovery requests according to OEM specification.
;******************************************************************************
;* Copyright (c) 2012 - 2021, Insyde Software Corporation. 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 <Library/PeiOemSvcKernelLib.h>
#include <Library/CmosLib.h>
#include <Library/HobLib.h>
#include <ChipsetCmos.h>
#ifdef L05_CRISIS_ENABLE
#include <L05Config.h>
#include <Library/PeiServicesLib.h>
#include <Library/CmosLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/FeatureLib/OemSvcBIOSCrisis.h>
#include <OemCmos.h>
#endif
#ifdef L05_BIOS_SELF_HEALING_SUPPORT
#include <Library/FeatureLib/OemSvcNotifyEcToStopWdt.h>
#endif
#ifdef L05_CRISIS_ENABLE
/**
Update L05 Crisis BIOS Name.
[Lenovo China Minimum BIOS Spec V1.40]
3.5.1 Crisis Recovery
4. the Crisis BIOS must be name as: xxCN.bin, xx is BIOS build ID.
@param None
@retval EFI_SUCCESS The operation completed successfully.
@retval Others An unexpected error occurred.
**/
EFI_STATUS
UpdateL05CrisisBiosName (
VOID
)
{
CHAR16 CrisisBiosName[10];
UINTN BufferSize;
CHAR16 *FirmwareVersionString;
FirmwareVersionString = NULL;
BufferSize = sizeof (CrisisBiosName);
ZeroMem (CrisisBiosName, BufferSize);
StrCpyS (CrisisBiosName, BufferSize / sizeof (CHAR16), L05_CRISIS_BIOS_NAME);
FirmwareVersionString = (CHAR16 *) PcdGetPtr (PcdFirmwareVersionString);
CrisisBiosName[0] = FirmwareVersionString[0];
CrisisBiosName[1] = FirmwareVersionString[1];
PcdSetPtrS (PcdPeiRecoveryFile, &BufferSize, CrisisBiosName);
return EFI_SUCCESS;
}
/**
Check BIOS recovery hotkey status.
@param None
@retval EFI_UNSUPPORTED To do default.
@retval EFI_MEDIA_CHANGED Hotkey detected. Change current boot mode to recovery mode.
**/
EFI_STATUS
CheckL05RecoveryHotkey (
VOID
)
{
//
// Todo:
// Add project specific code in here.
//
return EFI_UNSUPPORTED;
}
#endif
/**
This OemService provides OEM to detect the recovery mode.
OEM designs the rule to detect that boot mode is recovery mode or not,
The rule bases on the recovery request which defined in OemService "OemSetRecoveryRequest".
@param[in, out] *IsRecovery If service detects that the current system is recovery mode.
This parameter will return TRUE, else return FALSE.
@retval EFI_UNSUPPORTED Returns unsupported by default.
@retval EFI_SUCCESS The service is customized in the project.
@retval EFI_MEDIA_CHANGED The value of IN OUT parameter is changed.
@retval Others Depends on customization.
**/
EFI_STATUS
OemSvcDetectRecoveryRequest (
IN OUT BOOLEAN *IsRecovery
)
{
#ifdef L05_CRISIS_ENABLE
EFI_STATUS Status;
EFI_BOOT_MODE BootMode;
#endif
#ifdef L05_CRISIS_ENABLE
//
// [Lenovo China Minimum BIOS Spec V1.40]
// 3.5.1 Crisis Recovery
// 4. the Crisis BIOS must be name as: xxCN.bin, xx is BIOS build ID.
//
Status = UpdateL05CrisisBiosName ();
Status = PeiServicesGetBootMode (&BootMode);
if (!EFI_ERROR (Status) && (BootMode == BOOT_ON_S3_RESUME)) {
*IsRecovery = FALSE;
return EFI_SUCCESS;
}
#endif
if (RECOVERY_VALUE == ReadExtCmos8 ( R_XCMOS_INDEX, R_XCMOS_DATA, ChipsetRecoveryFlag)) {
*IsRecovery = TRUE;
#ifndef L05_CRISIS_ENABLE
if (PcdGet8(PcdChasmFallsSupport) == 1) {
BuildGuidDataHob (&gChasmfallsCrisisRecoveryGuid, IsRecovery, sizeof(BOOLEAN));
}
#endif
} else {
*IsRecovery = FALSE;
}
#ifdef L05_CRISIS_ENABLE
//
// BUG!! BUG!! BUG!!
// This is for Lenovo INTERNAL NovoButton and CrisisRecovery test.
// Project need to remove this code.
// 0x01 = Crisis Recovery.
// 0x02 = Novo button pressed.
//
if (ReadCmos8 (EFI_L05_NOVO_BUTTON_CRISIS_TEST) == (UINT8)0x01) {
*IsRecovery = TRUE;
PcdSetBoolS (PcdL05BiosRecoveryHotkeyFlag, TRUE);
if (PcdGet8 (PcdChasmFallsSupport) == 2) {
WriteCmos8 (EFI_L05_NOVO_BUTTON_CRISIS_TEST, (UINT8)0x00);
}
}
//
// [Lenovo China Minimum BIOS Spec V1.39]
// 3.5.1 Crisis Recovery
// Lenovo require the BIOS support user can press "Fn + R" hot key and power on system
// to crisis recovery corrupted BIOS.
//
Status = CheckL05RecoveryHotkey ();
if (Status == EFI_MEDIA_CHANGED) {
*IsRecovery = TRUE;
PcdSetBoolS (PcdL05BiosRecoveryHotkeyFlag, TRUE);
}
#ifdef L05_BIOS_SELF_HEALING_SUPPORT
if (ReadCmos8 (EfiL05BiosSelfHealingModeSwitch) == V_EFI_L05_BIOS_SELF_HEALING_MODE_CRISIS_RECOVERY) {
PcdSetBoolS (PcdL05BiosRecoveryHotkeyFlag, TRUE);
WriteCmos8 (EfiL05BiosSelfHealingModeSwitch, V_EFI_L05_BIOS_SELF_HEALING_MODE_NORMAL);
}
#endif
//
// [Lenovo China Minimum BIOS Spec V1.39]
// 3.5.1 Crisis Recovery
// Systems must be enabled the Battery LED in the whole recovery process.
//
#ifdef L05_BIOS_SELF_HEALING_SUPPORT
if (*IsRecovery && PcdGetBool (PcdL05BiosRecoveryHotkeyFlag)) {
#else
if (*IsRecovery) {
#endif
OemSvcSetCrisisLedState ();
}
if (*IsRecovery) {
if (PcdGet8(PcdChasmFallsSupport) == 1) {
BuildGuidDataHob (&gChasmfallsCrisisRecoveryGuid, IsRecovery, sizeof(BOOLEAN));
}
}
#ifdef L05_BIOS_SELF_HEALING_SUPPORT
//
// [Lenovo BIOS Self-Healing Design Guidance Specification V1.9]
// 2.1 Overview
// The EC boot flow and BIOS top swap self-healing flow :
// BIOS should check Top Swap pin status.
// If Top Swap bit is enabled then enter recovery mode and notify EC to stop WDT.
//
if (PcdGetBool (PcdL05TopSwapEnable)) {
OemSvcNotifyEcToStopWdt ();
}
//
// Set flag to indicate that crisis recovery will continue on the next boot
//
if (PcdGetBool (PcdL05BiosRecoveryHotkeyFlag) &&
(ReadCmos8 (EfiL05BiosSelfHealingModeSwitch) != V_EFI_L05_BIOS_SELF_HEALING_MODE_CRISIS_RECOVERY)) {
WriteCmos8 (EfiL05BiosSelfHealingModeSwitch, V_EFI_L05_BIOS_SELF_HEALING_MODE_CRISIS_RECOVERY);
}
#endif
#endif
return EFI_MEDIA_CHANGED;
}