alder_lake_bios/Lcfc/LfcPkg/HangCheckSmm/Intel/HangCheck.c

252 lines
7.2 KiB
C

//*****************************************************************************
// //
// Copyright (c) 2012 - 2017, Hefei LCFC Information Technology Co.Ltd.
// And/or its affiliates. All rights reserved.
// Hefei LCFC Information Technology Co.Ltd. PROPRIETARY/CONFIDENTIAL.
// Use is subject to license terms.
//
//******************************************************************************
/*++
Abstract:
This driver is used BIOS Hang Check feature. It will beep twice and blink power LED, when novo button
is pressed for longer than 4s, while the unit is software hang.
History:
Date Name Version Description
2017.06.06 Mandy Xiao/Annie Wei v1.00 Initial release
2018.09.14 Storm Yin/Rita Zhang v1.01 Add dump pci configuration registers function sample code
2018.09.18 Storm Yin v1.02 optimize for dumping pci configuration registers function sample code
Module Name:
HangCheck.c
--*/
#include <Uefi.h>
#include <Library/LfcLib.h>
#include <Library/LfcEcLib.h>
#include <Library/GpioLib.h>
#include <Library/DebugLib.h>
#include <Protocol/SmmGpiDispatch2.h>
#include <Library/SmmServicesTableLib.h>
#include <Library/FdSupportLib.h>
#include <Library/TimerLib.h>
#include <Guid/LfcVariableGuid.h>
#include <Library/IoLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Library/OemSvcLfcGetEcSmiGpioPad.h>
UINT32 mGpioSmiPad = 0;
// for easy to handle NB BDF, assuem max PCI bus # is 8: PCI_MAX_BUS_NUM
#define PCI_STORE_MAX_DEV 50
#define PCI_MAX_BUS_NUM 8
#define PCI_MAX_DEV 31
#define PCI_MAX_FUN 7
#define PcieBsaeAddress 0xE0000000
#define PciExpressConfigAddress(Bus,Device,Function,Offset) \
(((Offset) & 0xfff) | (((Function) & 0x07) << 12) | (((Device) & 0x1f) << 15) | (((Bus) & 0xff) << 20) + PcieBsaeAddress)
// LCFCTODO need change according your Resize Region map
#define DUMP_LOG_SPI_OFFSET 0xff630000
EFI_STATUS
DumpLogToVariable (
)
{
UINT8 Bus;
UINT8 Dev;
UINT8 Fun;
UINT8 WriteLog[PCI_STORE_MAX_DEV][256]={0};
UINT32 SrcAddress32;
EFI_STATUS Status;
UINTN Num1;
UINTN Num2;
Num1 = 0;
//
// Dump all PCI configuration registers to structure.
//
for ( Bus=0; Bus < PCI_MAX_BUS_NUM; Bus++) {
for ( Dev=0; Dev < PCI_MAX_DEV; Dev++ ) {
for ( Fun=0; Fun < PCI_MAX_FUN; Fun++) {
SrcAddress32 = PciExpressConfigAddress(Bus,Dev,Fun,0);
if (0xFFFF != *(UINT16 *)((UINTN) SrcAddress32)) {
if (Num1++ > PCI_STORE_MAX_DEV) {
break;
}
for (Num2 = 0; Num2 < 256; Num2++) {
WriteLog[Num1][Num2] = MmioRead8 (SrcAddress32 + Num2);
}
}
else {
continue;
}
}
}
}
//
// Save structure to UEFI variable.
//
Status = gRT->SetVariable (
L"HangCheckPciLog",
&gLfcVariableGuid,
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
sizeof(WriteLog),
&WriteLog
);
if (EFI_ERROR (Status)) {
ASSERT_EFI_ERROR (Status);
return Status;
}
return EFI_SUCCESS;
}
EFI_STATUS
DumpLogToBiosSpi (
)
{
UINT8 Bus;
UINT8 Dev;
UINT8 Fun;
EFI_STATUS Status;
UINT32 WriteAddress;
UINT32 WriteSize;
UINT32 SrcAddress32;
//
// Warning!!! BIOS SPI rom address need re-porting when used.
//
WriteAddress = DUMP_LOG_SPI_OFFSET;
for ( Bus=0; Bus < PCI_MAX_BUS_NUM; Bus++) {
for ( Dev=0; Dev < PCI_MAX_DEV; Dev++ ) {
for ( Fun=0; Fun < PCI_MAX_FUN; Fun++) {
SrcAddress32 = PciExpressConfigAddress(Bus,Dev,Fun,0);
if (0xFFFF != *(UINT16 *)((UINTN) SrcAddress32)) {
WriteSize = 0x100;
Status = FlashProgram (
(VOID *)((UINTN) WriteAddress),
(VOID *)((UINTN) SrcAddress32),
(UINTN *)&WriteSize,
(WriteAddress & ~(0xFFFF))
);
MicroSecondDelay (50);
WriteAddress += WriteSize;
}
else {
continue;
}
}
}
}
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
HangCheckHandler (
IN EFI_HANDLE DispatchHandle,
IN CONST EFI_SMM_GPI_REGISTER_CONTEXT *GpiRegisterContext
)
{
UINTN Num;
UINT8 Data;
//
// Clear ALT_GPI_SMI_STS register for GPIO (EC SMI#)
//
GpioClearGpiSmiSts (mGpioSmiPad);
//Send command to EC for starting to light shine
LfcEcLibStartLight();
//Beep
for (Num = 0; Num < 2; Num++) {
Data = IoRead8 ( 0x61 );
Data |= 0x03;
IoWrite8 ( 0x61, Data );
LfcProjectLibStall (200000);
Data = IoRead8 ( 0x61 );
Data = Data & 0xFC;
IoWrite8 ( 0x61, Data );
LfcProjectLibStall (200000);
}
//
// Note!!!
// Following is store dump log sample code, please enable it by needed.
//
// Store log in UEFI variable.
//DumpLogToVariable ();
// Backup store log way, store log in BIOS SPI. If use this way dump log, please re-porting SPI address.
DumpLogToBiosSpi ();
//Beep again to note store log.
for (Num = 0; Num < 2; Num++) {
Data = IoRead8 ( 0x61 );
Data |= 0x03;
IoWrite8 ( 0x61, Data );
LfcProjectLibStall (200000);
Data = IoRead8 ( 0x61 );
Data = Data & 0xFC;
IoWrite8 ( 0x61, Data );
LfcProjectLibStall (200000);
}
//Send command to EC for stopping to light shine
LfcEcLibStopLight();
return EFI_SUCCESS;
}
EFI_STATUS
HangCheckEntry(
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
EFI_SMM_GPI_DISPATCH2_PROTOCOL *mSmmGpiDispatch;
EFI_SMM_GPI_REGISTER_CONTEXT GpiRegisterContext;
EFI_HANDLE GpiHandle;
UINT32 LfcEcSmiGpioPad;
// Get GpioPad value for EC SMI#
OemSvcLfcGetEcSmiGpioPad(&LfcEcSmiGpioPad);
mGpioSmiPad = LfcEcSmiGpioPad;
//
// Get GpiNum according to GPIO Group+Pad
//
GpioGetGpiSmiNum (mGpioSmiPad, &GpiRegisterContext.GpiNum);
//
// Register SMI handler EC SMI usage during Connected Standby
//
Status = gSmst->SmmLocateProtocol (&gEfiSmmGpiDispatch2ProtocolGuid, NULL, &mSmmGpiDispatch);
if (EFI_ERROR (Status)) {
ASSERT_EFI_ERROR (Status);
return Status;
}
DEBUG ((DEBUG_ERROR, "Installing HangCheckHandler Handler \n"));
Status = mSmmGpiDispatch->Register (
mSmmGpiDispatch,
(EFI_SMM_HANDLER_ENTRY_POINT2)HangCheckHandler,
&GpiRegisterContext,
&GpiHandle
);
DEBUG ((DEBUG_ERROR, "HangCheckHandler Install Status: %x\n", Status));
return Status;
}