alder_lake_bios/Intel/AlderLake/AlderLakePlatSamplePkg/Features/CrashLogDxe/CrashLogDxe.c

702 lines
25 KiB
C

/** @file
This DXE driver supports the CrashLog Feature.
@copyright
INTEL CONFIDENTIAL
Copyright 2016 - 2021 Intel Corporation.
The source code contained or described herein and all documents related to the
source code ("Material") are owned by Intel Corporation or its suppliers or
licensors. Title to the Material remains with Intel Corporation or its suppliers
and licensors. The Material may contain trade secrets and proprietary and
confidential information of Intel Corporation and its suppliers and licensors,
and is protected by worldwide copyright and trade secret laws and treaty
provisions. No part of the Material may be used, copied, reproduced, modified,
published, uploaded, posted, transmitted, distributed, or disclosed in any way
without Intel's prior express written permission.
No license under any patent, copyright, trade secret or other intellectual
property right is granted to or conferred upon you by disclosure or delivery
of the Materials, either expressly, by implication, inducement, estoppel or
otherwise. Any license under such intellectual property rights must be
express and approved by Intel in writing.
Unless otherwise agreed by Intel in writing, you may not remove or alter
this notice or any other notice embedded in Materials by Intel or
Intel's suppliers or licensors in any way.
This file contains a 'Sample Driver' and is licensed as such under the terms
of your license agreement with Intel or your vendor. This file may be modified
by the user, subject to the additional terms of the license agreement.
@par Specification Reference:
**/
#include "CrashLogDxe.h"
///
/// Boot Error Record Table (BERT) instance
///
STATIC EFI_ACPI_6_1_BOOT_ERROR_RECORD_TABLE_HEADER *mBert;
STATIC EFI_ACPI_TABLE_PROTOCOL *mAcpiTbl = NULL;
STATIC BOOLEAN mPmcCrashLogSupport = FALSE;
STATIC BOOLEAN mPmcCrashLogPresent = FALSE;
STATIC BOOLEAN mCpuCrashLogSupport = FALSE;
STATIC BOOLEAN mCpuCrashLogPresent = FALSE;
STATIC UINT32 mMainLogDataBuffer = 0;
STATIC UINT32 mTelemetryDataBuffer = 0;
STATIC UINT32 mTraceDataBuffer = 0;
STATIC UINT32 mPmcCrashLogSize = 0;
STATIC UINT32 mCpuCrashLogSize = 0;
STATIC UINT32 mMainLogSize = 0;
STATIC UINT32 mTelemetrySize = 0;
STATIC UINT32 mTraceSize = 0;
EFI_GUID gCrashLog_RecordId_Guid = CRASHLOG_RECORDID_GUID;
EFI_GUID gTelemetry_RecordId_Guid = TELEMETRY_RECORDID_GUID;
EFI_GUID gTrace_RecordId_Guid = TRACE_RECORDID_GUID;
/**
Update Platform & OEM ID's in Whea ACPI tables
@param[in] TableHeader BERT Table Header Pointer
**/
VOID
UpdateAcpiTableIds (
EFI_ACPI_DESCRIPTION_HEADER *TableHeader
)
{
//
// Update the OEMID, OEM revision, OEM TABLE ID, Creator ID and Creator revision
//
*(UINT32 *)(TableHeader->OemId) = 'I' + ('N' << 8) + ('T' << 16) + ('E' << 24);
*(UINT16 *)(TableHeader->OemId + 4) = 'L' + (' ' << 8);
TableHeader->OemTableId = EFI_ACPI_OEM_TABLE_ID;
TableHeader->OemRevision = EFI_WHEA_OEM_REVISION;
TableHeader->CreatorId = EFI_ACPI_CREATOR_ID;
TableHeader->CreatorRevision = EFI_ACPI_CREATOR_REVISION;
}
/**
Get PMC Crash log
@param[in] Destination Memory address of GEBE entry
@param[in] PmcCrashLogHob Crash log data HOB
@retval EFI_SUCCESS The function completes successfully
**/
EFI_STATUS
GetPmcCrashLog (
IN UINT32 *Destination,
IN CRASHLOG_HOB *PmcCrashLogHob
)
{
UINT32 *PmcCrashLogAddr;
UINT32 PmcCrashLogSize = 0;
DEBUG ((DEBUG_INFO, "BERT Pmc CrashLog Destination = 0x%x \n", Destination));
DEBUG ((DEBUG_INFO, "Value at PmcCrashLogAddress 0x%x = 0x%x \n", PmcCrashLogHob->AllocateAddress, MmioRead32 (PmcCrashLogHob->AllocateAddress)));
DEBUG ((DEBUG_INFO, "Pmc Crash Data Collection\n"));
PmcCrashLogAddr = (UINT32 *) PmcCrashLogHob->AllocateAddress;
while (PmcCrashLogSize < (PmcCrashLogHob->Size)) {
*Destination = *PmcCrashLogAddr;
if (PmcCrashLogSize < CRASHLOG_SIZE_DEBUG_PURPOSE) { // Dumping only few bytes to help debug
DEBUG ((DEBUG_INFO, "PmcCrashData = 0x%x\n", *Destination));
}
Destination++;
PmcCrashLogAddr++;
PmcCrashLogSize += 4;
}
DEBUG ((DEBUG_INFO, "Copied Pmc CrasLog Size = 0x%x\n", PmcCrashLogSize));
return EFI_SUCCESS;
}
/**
Get Cpu Crash log
@retval EFI_SUCCESS The function completes successfully
**/
EFI_STATUS
GetCpuCrashLog (
IN UINT32 *MainLogDestination,
IN UINT32 *TelemetryDestination,
IN UINT32 *TraceDestination
)
{
UINT32 *CrashLogAddr = NULL;
UINT32 CrashLogSize = 0;
if (mCpuCrashLogSize > 0) {
DEBUG ((DEBUG_INFO, "Cpu CrashLog is present.\n"));
} else {
return EFI_NOT_FOUND;
}
if ((MainLogDestination == NULL) || (TelemetryDestination == NULL) || (TraceDestination == NULL)) {
return EFI_INVALID_PARAMETER;
}
DEBUG ((DEBUG_INFO, "Cpu Crash Data Collection\n"));
CrashLogAddr = (UINT32 *) (UINTN) mMainLogDataBuffer;
DEBUG ((DEBUG_INFO, "Value at MainCrashLogAddress 0x%x = 0x%x \n ", (UINTN)CrashLogAddr, (UINT32) *CrashLogAddr));
while (CrashLogSize < (mMainLogSize)) {
*MainLogDestination = *CrashLogAddr;
if (CrashLogSize < CRASHLOG_SIZE_DEBUG_PURPOSE) { // Dumping only few bytes to help debug
DEBUG ((DEBUG_INFO, "Main CrashData = 0x%x\n", *MainLogDestination));
}
MainLogDestination++;
CrashLogAddr++;
CrashLogSize+=4;
}
DEBUG ((DEBUG_INFO, "Copied Main CrasLog Size = 0x%x\n", CrashLogSize));
CrashLogSize = 0;
CrashLogAddr = (UINT32 *) (UINTN) mTelemetryDataBuffer;
DEBUG ((DEBUG_INFO, "Value at TelemetryCrashLogAddress 0x%x = 0x%x \n ", (UINTN)CrashLogAddr, (UINT32) *CrashLogAddr));
while (CrashLogSize < (mTelemetrySize)) {
*TelemetryDestination = *CrashLogAddr;
if (CrashLogSize < CRASHLOG_SIZE_DEBUG_PURPOSE) { // Dumping only few bytes to help debug
DEBUG ((DEBUG_INFO, "Telemetry CrashData = 0x%x\n", *TelemetryDestination));
}
TelemetryDestination++;
CrashLogAddr++;
CrashLogSize+=4;
}
DEBUG ((DEBUG_INFO, "Copied Telemetry CrasLog Size = 0x%x\n", CrashLogSize));
CrashLogSize = 0;
CrashLogAddr = (UINT32 *) (UINTN) mTraceDataBuffer;
DEBUG ((DEBUG_INFO, "Value at TraceCrashLogAddress 0x%x = 0x%x \n ", (UINTN)CrashLogAddr, (UINT32) *CrashLogAddr));
while (CrashLogSize < (mTraceSize)) {
*TraceDestination = *CrashLogAddr;
if (CrashLogSize < CRASHLOG_SIZE_DEBUG_PURPOSE) { // Dumping only few bytes to help debug
DEBUG ((DEBUG_INFO, "Trace CrashData = 0x%x\n", *TraceDestination));
}
TraceDestination++;
CrashLogAddr++;
CrashLogSize+=4;
}
DEBUG ((DEBUG_INFO, "Copied Trace CrasLog Size = 0x%x\n", CrashLogSize));
return EFI_SUCCESS;
}
/**
Add a new Firmware CrashLog Entry to existing Error Status Block.
@param[in] ErrStsBlk BERT GENERIC_ERROR_STATUS instance.
@param[in out] FirmwareGenericErrorAddr Pointer to this FirmwareGenericError entry address, updated on return.
@param[in out] FirmwareCrashLogPayloadAddr Pointer to Firmware CrashLog Entry payload address, updated on return.
@param[in] EntrySize Firmware CrashLog Entry payload size.
@param[in] EntrySource Firmware CrashLog Entry source.
@param[in] EntryVersion Firmware CrashLog Entry version.
**/
VOID
AddFirmwareCrashLogEntry (
IN EFI_ACPI_6_1_GENERIC_ERROR_STATUS_STRUCTURE *ErrStsBlk,
IN OUT FIRMWARE_GENERIC_ERROR **FirmwareGenericErrorAddr,
IN OUT UINT8 **FirmwareCrashLogPayloadAddr,
IN UINT32 EntrySize,
IN EFI_GUID RecordIdGuid
)
{
FIRMWARE_GENERIC_ERROR *FirmwareGenericError = NULL;
FirmwareGenericError = (FIRMWARE_GENERIC_ERROR*)((UINT8*)(void*)ErrStsBlk + ErrStsBlk->DataLength + sizeof (EFI_ACPI_6_1_GENERIC_ERROR_STATUS_STRUCTURE));
ZeroMem (FirmwareGenericError, sizeof (FIRMWARE_GENERIC_ERROR));
CopyMem (&FirmwareGenericError->GenericErrorDataEntry.SectionType, &gEfiFirmwareErrorSectionGuid, sizeof (EFI_GUID));
FirmwareGenericError->GenericErrorDataEntry.ErrorSeverity = EFI_ACPI_6_1_ERROR_SEVERITY_FATAL;
FirmwareGenericError->GenericErrorDataEntry.Revision = EFI_ACPI_6_1_GENERIC_ERROR_DATA_ENTRY_REVISION;
FirmwareGenericError->GenericErrorDataEntry.ValidationBits = 0;
FirmwareGenericError->GenericErrorDataEntry.ErrorDataLength = EntrySize + sizeof (EFI_FIRMWARE_ERROR_DATA);
FirmwareGenericError->EfiFirmwareErrorData.ErrorType = 2; //FW CrashLog Error Record
FirmwareGenericError->EfiFirmwareErrorData.Revision = EFI_2_7_FIRMWARE_ERROR_RECORD_REVISION;
FirmwareGenericError->EfiFirmwareErrorData.RecordIdGuid = RecordIdGuid;
ErrStsBlk->DataLength += FirmwareGenericError->GenericErrorDataEntry.ErrorDataLength + sizeof (EFI_ACPI_6_1_GENERIC_ERROR_DATA_ENTRY_STRUCTURE);
ErrStsBlk->BlockStatus.ErrorDataEntryCount++;
*FirmwareGenericErrorAddr = FirmwareGenericError;
*FirmwareCrashLogPayloadAddr = (UINT8*)(void*) FirmwareGenericError + sizeof (FIRMWARE_GENERIC_ERROR);
}
/**
Get PMC, PUNIT, CPU Crash Log, and initialize the APEI BERT GENERIC_ERROR_STATUS structure
@param[in] ErrStsBlk BERT GENERIC_ERROR_STATUS instance.
@retval EFI_SUCCESS The function completes successfully
**/
EFI_STATUS
GenFwBootErrorlog (
IN EFI_ACPI_6_1_GENERIC_ERROR_STATUS_STRUCTURE *ErrStsBlk
)
{
EFI_STATUS Status = EFI_SUCCESS;
FIRMWARE_GENERIC_ERROR *MainFirmwareGenericError = NULL;
FIRMWARE_GENERIC_ERROR *TelemetryFirmwareGenericError = NULL;
FIRMWARE_GENERIC_ERROR *TraceFirmwareGenericError = NULL;
FIRMWARE_GENERIC_ERROR *PmcFirmwareGenericError = NULL;
UINT8 *PmcDest;
UINT8 *MainDest = NULL;
UINT8 *TelemetryDest = NULL;
UINT8 *TraceDest = NULL;
EFI_HOB_GUID_TYPE *CrashLogDataBufferHob;
CRASHLOG_HOB *PmcCrashLogHob;
UINT32 HobDataSize;
UINT32 Index;
if (ErrStsBlk == NULL) {
return EFI_NOT_FOUND;
}
ErrStsBlk->RawDataOffset = 0;
ErrStsBlk->RawDataLength = 0;
ErrStsBlk->ErrorSeverity = EFI_ACPI_6_1_ERROR_SEVERITY_FATAL;
ErrStsBlk->BlockStatus.ErrorDataEntryCount = 0;
ErrStsBlk->DataLength = 0;
//
// Getting Cpu Crashlog and adding entry
//
if (mCpuCrashLogSupport && mCpuCrashLogPresent) {
//
// MainLog crashlog data is presented then create GEBE for MainLog , Telemetry and Trace
//
if (mMainLogSize) {
AddFirmwareCrashLogEntry (ErrStsBlk, &MainFirmwareGenericError, &MainDest, mMainLogSize, gCrashLog_RecordId_Guid);
DEBUG ((DEBUG_INFO, "ErrStsBlk = 0x%x, MainFirmwareGenericError = 0x%x, MainDest = 0x%x, mMainLogSize = 0x%x\n", ErrStsBlk, MainFirmwareGenericError, MainDest, mMainLogSize));
if (mTelemetrySize) {
AddFirmwareCrashLogEntry (ErrStsBlk, &TelemetryFirmwareGenericError, &TelemetryDest, mTelemetrySize, gTelemetry_RecordId_Guid);
DEBUG ((DEBUG_INFO, "ErrStsBlk = 0x%x, TelemetryFirmwareGenericError = 0x%x, TelemetryDest = 0x%x, mTelemetrySize = 0x%x\n", ErrStsBlk, TelemetryFirmwareGenericError, TelemetryDest, mTelemetrySize));
}
if (mTraceSize) {
AddFirmwareCrashLogEntry (ErrStsBlk, &TraceFirmwareGenericError, &TraceDest, mTraceSize, gTrace_RecordId_Guid);
DEBUG ((DEBUG_INFO, "ErrStsBlk = 0x%x, TraceFirmwareGenericError = 0x%x, TraceDest = 0x%x, mTraceSize = 0x%x\n", ErrStsBlk, TraceFirmwareGenericError, TraceDest, mTraceSize));
}
}
Status = GetCpuCrashLog ((void*) MainDest, (void*) TelemetryDest, (void*) TraceDest);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "CPU CrashLog data are not collected\n"));
}
}
//
// Getting Pmc Crashlog and adding entry
//
if (mPmcCrashLogSupport && mPmcCrashLogPresent ) {
CrashLogDataBufferHob = GetFirstGuidHob (&gPmcCrashLogDataBufferHobGuid);
PmcCrashLogHob = (CRASHLOG_HOB *) GET_GUID_HOB_DATA (CrashLogDataBufferHob);
HobDataSize = GET_GUID_HOB_DATA_SIZE (CrashLogDataBufferHob) / sizeof (CRASHLOG_HOB);
for (Index = 0; Index < HobDataSize; Index++) {
//
// Pmc crashlog data is presented then create GEBE for PmcCrashLog
//
AddFirmwareCrashLogEntry (ErrStsBlk, &PmcFirmwareGenericError, &PmcDest, PmcCrashLogHob[Index].Size, gCrashLog_RecordId_Guid);
DEBUG ((DEBUG_INFO, "ErrStsBlk = 0x%x, PmcFirmwareGenericError = 0x%x, PmcDest = 0x%x, PmcCrashLogHob[%d].Size = 0x%x\n", ErrStsBlk, PmcFirmwareGenericError, PmcDest, Index, PmcCrashLogHob[Index].Size));
Status = GetPmcCrashLog ((void*) PmcDest, &(PmcCrashLogHob[Index]));
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "PMC CrashLog data are not collected\n"));
}
}
}
if (mPmcCrashLogSupport == FALSE && mCpuCrashLogSupport == FALSE) {
return EFI_NOT_FOUND;
}
ErrStsBlk->BlockStatus.MultipleUncorrectableErrors = 1;
ErrStsBlk->BlockStatus.UncorrectableErrorValid = 1;
mBert->BootErrorRegionLength = ErrStsBlk->DataLength + sizeof (EFI_ACPI_6_1_GENERIC_ERROR_STATUS_STRUCTURE);
DEBUG ((DEBUG_INFO, " ErrStsBlk->DataLength = 0x%x\n", ErrStsBlk->DataLength));
DEBUG ((DEBUG_INFO, " ErrorStatusBlock Size = 0x%x\n", mBert->BootErrorRegionLength));
if (PmcFirmwareGenericError != NULL) {
DEBUG((DEBUG_INFO, " PmcFirmwareGenericError->GenericErrorDataEntry.ErrorDataLength = 0x%x\n", PmcFirmwareGenericError->GenericErrorDataEntry.ErrorDataLength));
}
DEBUG ((DEBUG_INFO, " PmcCrashLogSize = 0x%x\n", mPmcCrashLogSize));
DEBUG ((DEBUG_INFO, " CpuCrashLogSize = 0x%x\n", mCpuCrashLogSize));
return EFI_SUCCESS;
}
/**
Log firmware boot error log in APEI BERT.
@param[in] BootErrorTable APEI BERT address.
@retval EFI_SUCCESS The function completes successfully
**/
EFI_STATUS
LogFwBootErrorlog (
IN EFI_ACPI_6_1_BOOT_ERROR_RECORD_TABLE_HEADER *BootErrorTable
)
{
EFI_ACPI_6_1_GENERIC_ERROR_STATUS_STRUCTURE *ErrStsBlk;
if (BootErrorTable == NULL) {
return EFI_NOT_FOUND;
}
ErrStsBlk = (EFI_ACPI_6_1_GENERIC_ERROR_STATUS_STRUCTURE *) (UINTN) BootErrorTable->BootErrorRegion;
if (ErrStsBlk->DataLength >= BootErrorTable->BootErrorRegionLength) {
return EFI_OUT_OF_RESOURCES;
}
return GenFwBootErrorlog (ErrStsBlk);
}
/**
Install ACPI table for APEI BERT
@param[in] Bert APEI BERT Instance.
@retval EFI_SUCCESS The function completes successfully
**/
STATIC
EFI_STATUS
InstallApeiBertTables (
EFI_ACPI_6_1_BOOT_ERROR_RECORD_TABLE_HEADER *Bert
)
{
EFI_STATUS Status;
UINTN TableKey;
Status = EFI_SUCCESS;
if (Bert == NULL) {
return EFI_INVALID_PARAMETER;
}
if (mAcpiTbl) {
DEBUG ((DEBUG_INFO, "APEI Support. Install BERT Table \n"));
TableKey = 0;
Status = mAcpiTbl->InstallAcpiTable (
mAcpiTbl,
Bert,
Bert->Header.Length,
&TableKey
);
}
return Status;
}
/**
Get Crash Log size.
@param[in] CrashLogDataBufferHob Crash log data HOB
@retval PmcCrashLogSize Total size of all crash log data.
**/
UINT32
GetPmcCrashLogSize (
IN EFI_HOB_GUID_TYPE *CrashLogDataBufferHob
)
{
UINT32 Index;
UINT32 HobDataSize;
UINT32 PmcCrashLogSize;
CRASHLOG_HOB *PmcCrashLogHob;
PmcCrashLogSize = 0;
while (CrashLogDataBufferHob != NULL) {
PmcCrashLogHob = (CRASHLOG_HOB *) GET_GUID_HOB_DATA (CrashLogDataBufferHob);
HobDataSize = GET_GUID_HOB_DATA_SIZE (CrashLogDataBufferHob) / sizeof (CRASHLOG_HOB);
for (Index = 0; Index < HobDataSize; Index++) {
PmcCrashLogSize += PmcCrashLogHob[Index].Size;
}
CrashLogDataBufferHob = GET_NEXT_HOB (CrashLogDataBufferHob);
CrashLogDataBufferHob = GetNextGuidHob (&gPmcCrashLogDataBufferHobGuid, CrashLogDataBufferHob);
}
return PmcCrashLogSize;
}
/**
Determine Crash Log support or not.
@param[in] DiscoveryBuffer Discovery buffer read from PMC
**/
BOOLEAN
GetPmcCrashLogSupport (
IN PMC_IPC_DISCOVERY_BUF *DiscoveryBuffer
)
{
if (DiscoveryBuffer->Bits.Avail != 1) {
return FALSE;
}
switch (DiscoveryBuffer->Bits64.Mech) {
case CRASHLOG_MECH_LEGACY:
if (DiscoveryBuffer->Bits.Dis == 1) {
return FALSE;
}
break;
case CRASHLOG_MECH_DESCRIPTOR_TABLE:
if (DiscoveryBuffer->Bits64.CrashDisSts) {
return FALSE;
}
break;
default:
return FALSE;
}
return TRUE;
}
/**
Discover CrashLog
@retval TRUE if CPU or PMC crash log is discovered.
@retval FALSE if none of CPU and PMC crash logs are discovered.
**/
BOOLEAN
DiscoverCrashLog (
VOID
)
{
EFI_STATUS Status;
PMC_IPC_DISCOVERY_BUF DiscoveryBuffer;
TEL_CRASHLOG_DEVSC_CAP CrashLogDevscCap;
BOOLEAN CrashLogSupport;
Status = EFI_SUCCESS;
CrashLogSupport = FALSE;
ZeroMem (&DiscoveryBuffer, sizeof (PMC_IPC_DISCOVERY_BUF));
//
// PCH CrashLog Discovery
//
Status = PmcCrashLogDiscovery (&DiscoveryBuffer);
if (EFI_ERROR (Status) || (GetPmcCrashLogSupport (&DiscoveryBuffer) == FALSE)) {
DEBUG ((DEBUG_INFO, "PCH CrashLog feature not supported\n"));
} else {
mPmcCrashLogSupport = TRUE;
CrashLogSupport = TRUE;
}
//
// CPU CrashLog Discovery
//
Status = GetCpuCrashLogCapability (&CrashLogDevscCap);
if (EFI_ERROR (Status) ) {
DEBUG ((DEBUG_INFO, "CPU CrashLog feature not supported\n"));
} else {
mCpuCrashLogSupport = TRUE;
CrashLogSupport = TRUE;
}
return CrashLogSupport;
}
/**
Entry point of the CrashLog support driver.
@param[in] ImageHandle EFI_HANDLE: A handle for the image that is initializing this driver
@param[in] SystemTable EFI_SYSTEM_TABLE: A pointer to the EFI system table
@retval EFI_SUCCESS: Driver initialized successfully
EFI_LOAD_ERROR: Failed to Initialize or to Load the driver
EFI_OUT_OF_RESOURCES: Could not allocate needed resources
**/
EFI_STATUS
EFIAPI
InstallCrashLogSupport (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
SETUP_DATA SetupData;
UINTN VariableSize;
UINT32 VariableAttributes;
BOOLEAN CreateBertTableOrNot;
EFI_HOB_GUID_TYPE *CrashLogDataBufferHob;
UINT32 BootErrorRegionSize;
CRASHLOG_HOB *PmcCrashLogHob;
CPU_CRASHLOG_HOB *CpuCrashLogHob;
UINT32 CrashLogCount = 0;
CreateBertTableOrNot = FALSE;
VariableSize = sizeof (SETUP_DATA);
DEBUG ((DEBUG_INFO, "CrashLog Entry Point\n"));
Status = gRT->GetVariable (
L"Setup",
&gSetupVariableGuid,
&VariableAttributes,
&VariableSize,
&SetupData
);
if (EFI_ERROR (Status)) {
return Status;
}
if (!SetupData.EnableCrashLog) {
//
// The PCH CrashLog Disable.
//
DEBUG ((DEBUG_INFO, "Disable PCH CrashLog Feature\n"));
Status = PmcCrashLogDisable ();
return Status;
}
//
// Check for the CrashLog feature, if it is available or not.
//
CreateBertTableOrNot = DiscoverCrashLog ();
if (!CreateBertTableOrNot) {
DEBUG ((DEBUG_ERROR, "DiscoverCrashLog: CrashLog is not supported \n"));
return EFI_UNSUPPORTED;
}
if (mPmcCrashLogSupport) {
if (SetupData.CrashLogOnAllReset) {
DEBUG ((DEBUG_INFO, "Crash Log on All Reset \n"));
//
// Collect crash data on every boot
//
Status = PmcCrashLogOnAllReset ();
DEBUG ((DEBUG_INFO, "PMC IPC to collect Crash Log on every reset successful\n"));
}
}
DEBUG ((DEBUG_INFO, "BERT Init\n"));
CrashLogDataBufferHob = GetFirstGuidHob (&gPmcCrashLogDataBufferHobGuid);
if (CrashLogDataBufferHob != NULL) {
PmcCrashLogHob = (CRASHLOG_HOB *) GET_GUID_HOB_DATA (CrashLogDataBufferHob);
mPmcCrashLogSize = GetPmcCrashLogSize (CrashLogDataBufferHob);
if ((PmcCrashLogHob != NULL) && (mPmcCrashLogSize > 0)){
DEBUG ((DEBUG_ERROR, "PMC CrashLog data is present\n"));
DEBUG ((DEBUG_INFO, "PmcCrashLogDataBuffer = 0x%x\n", PmcCrashLogHob));
DEBUG ((DEBUG_INFO, "PMC CrashLog Size = 0x%x\n", mPmcCrashLogSize));
mPmcCrashLogPresent = TRUE;
CrashLogCount += GET_GUID_HOB_DATA_SIZE (CrashLogDataBufferHob) / sizeof (CRASHLOG_HOB);
}
} else {
DEBUG ((DEBUG_ERROR, "PMC CrashLog data is not present \n"));
mPmcCrashLogPresent = FALSE;
}
CrashLogDataBufferHob = GetFirstGuidHob (&gCpuCrashLogDataBufferHobGuid);
if (CrashLogDataBufferHob != NULL) {
CpuCrashLogHob = (CPU_CRASHLOG_HOB *) GET_GUID_HOB_DATA (CrashLogDataBufferHob);
mMainLogDataBuffer = (UINT32) (CpuCrashLogHob->Main.AllocateAddress);
mTelemetryDataBuffer = (UINT32) (CpuCrashLogHob->Telemetry.AllocateAddress);
mTraceDataBuffer = (UINT32) (CpuCrashLogHob->Trace.AllocateAddress);
mMainLogSize = CpuCrashLogHob->Main.Size;
mTelemetrySize = CpuCrashLogHob->Telemetry.Size;
mTraceSize = CpuCrashLogHob->Trace.Size;
mCpuCrashLogSize = mMainLogSize + mTelemetrySize + mTraceSize;
DEBUG ((DEBUG_INFO, "MainLogDataBuffer = 0x%x\n", mMainLogDataBuffer));
DEBUG ((DEBUG_INFO, "MainLogSize = 0x%x\n", mMainLogSize));
DEBUG ((DEBUG_INFO, "TelemetryDataBuffer = 0x%x\n", mTelemetryDataBuffer));
DEBUG ((DEBUG_INFO, "TelemetrySize = 0x%x\n", mTelemetrySize));
DEBUG ((DEBUG_INFO, "TraceDataBuffer = 0x%x\n", mTraceDataBuffer));
DEBUG ((DEBUG_INFO, "TraceSize = 0x%x\n", mTraceSize));
DEBUG ((DEBUG_INFO, "CpuCrashLogSize = 0x%x\n", mCpuCrashLogSize));
}
if (mMainLogSize) {
DEBUG ((DEBUG_ERROR, "Cpu CrashLog data is present\n"));
mCpuCrashLogPresent = TRUE;
CrashLogCount++;
if (mTelemetrySize) {
CrashLogCount++;
}
if (mTraceSize) {
CrashLogCount++;
}
} else {
DEBUG ((DEBUG_ERROR, "Cpu CrashLog data is not present\n"));
mCpuCrashLogPresent = FALSE;
}
if ((mCpuCrashLogPresent == FALSE) && (mPmcCrashLogPresent == FALSE)) {
DEBUG ((DEBUG_ERROR, "CrashLog is not present. Skip BERT creation \n"));
return EFI_NOT_READY;
}
//
// Allocate memory for BERT table
//
mBert = (EFI_ACPI_6_1_BOOT_ERROR_RECORD_TABLE_HEADER *) AllocateZeroPool (sizeof (EFI_ACPI_6_1_BOOT_ERROR_RECORD_TABLE_HEADER));
if (mBert == NULL) {
DEBUG ((DEBUG_ERROR, "Unable to Allocate Memory for BERT Record Creation\n"));
return EFI_OUT_OF_RESOURCES;
}
//
// Fill EFI_ACPI_DESCRIPTION_HEADER structure
//
mBert->Header.Signature = EFI_ACPI_6_1_BOOT_ERROR_RECORD_TABLE_SIGNATURE;
mBert->Header.Length = sizeof (EFI_ACPI_6_1_BOOT_ERROR_RECORD_TABLE_HEADER);
mBert->Header.Revision = EFI_ACPI_6_1_BOOT_ERROR_RECORD_TABLE_REVISION;
mBert->Header.Checksum = 0;
UpdateAcpiTableIds (&mBert->Header);
//
// Allocate memory space Error status blocks
// Allocate memort space for Errorlog Address range, Fill EFI_ACPI_6_1_BOOT_ERROR_RECORD_TABLE_HEADER(mBert) structure
//
BootErrorRegionSize = sizeof (EFI_ACPI_6_1_GENERIC_ERROR_STATUS_STRUCTURE) + sizeof (FIRMWARE_GENERIC_ERROR) * CrashLogCount + mPmcCrashLogSize + mCpuCrashLogSize;
mBert->BootErrorRegion = (UINT64) AllocateReservedZeroPool ((UINTN) BootErrorRegionSize);
DEBUG ((DEBUG_INFO, "mBert->BootErrorRegion = %x\n", (UINTN)mBert->BootErrorRegion));
DEBUG ((DEBUG_INFO, "mBert->BootErrorRegionSize = %x\n", BootErrorRegionSize));
if (mBert->BootErrorRegion == 0) {
DEBUG ((DEBUG_ERROR, "Unable to Allocate Memory for Boot Error Record Data\n"));
return EFI_OUT_OF_RESOURCES;
}
mBert->BootErrorRegionLength = BootErrorRegionSize;
Status = LogFwBootErrorlog (mBert);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_INFO, "No Pmc or Punit or Cpu error log found\n"));
return EFI_NOT_FOUND;
}
mAcpiTbl = NULL;
Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &mAcpiTbl);
ASSERT_EFI_ERROR (Status);
Status = InstallApeiBertTables (mBert);
if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
DEBUG ((DEBUG_ERROR, "Not able to install ACPI table for APEI BERT \n"));
}
if (mBert != NULL) {
FreePool (mBert);
}
DEBUG ((DEBUG_INFO, "CrashLog Exit \n"));
return Status;
}