/** @file
|
*
|
* Copyright (c) 2018, Hisilicon Limited. All rights reserved.
|
* Copyright (c) 2018, Linaro Limited. All rights reserved.
|
*
|
* SPDX-License-Identifier: BSD-2-Clause-Patent
|
*
|
**/
|
|
#include <Guid/Cper.h>
|
#include "Ghes.h"
|
#include <Library/DebugLib.h>
|
#include <Library/UefiBootServicesTableLib.h>
|
|
#define READ_ACK_PRESERVE 0xFFFFFFFE
|
#define READ_ACK_WRITE 0x1
|
|
EFI_ACPI_6_1_GENERIC_ERROR_STATUS_STRUCTURE*
|
ErrorBlockInitial (
|
VOID *Block,
|
UINT32 Severity
|
)
|
{
|
EFI_ACPI_6_1_GENERIC_ERROR_STATUS_STRUCTURE* BlockHeader = Block;
|
BlockHeader->BlockStatus = (EFI_ACPI_6_1_ERROR_BLOCK_STATUS) {0, 0, 0, 0, 0};
|
BlockHeader->RawDataOffset = 0;
|
BlockHeader->RawDataLength = 0;
|
BlockHeader->DataLength = 0;
|
BlockHeader->ErrorSeverity = Severity;
|
return BlockHeader;
|
}
|
|
|
BOOLEAN
|
ErrorBlockUpdateStatusStructure (
|
VOID *ErrorBlock
|
)
|
{
|
if (ErrorBlock == NULL) {
|
return FALSE;
|
}
|
IN EFI_ACPI_6_1_GENERIC_ERROR_STATUS_STRUCTURE *BlockHeader = ErrorBlock;
|
VOID *EntriesBegin = ErrorBlock + sizeof (EFI_ACPI_6_1_GENERIC_ERROR_STATUS_STRUCTURE);
|
if (BlockHeader->BlockStatus.ErrorDataEntryCount == 0) {
|
gBS->SetMem (EntriesBegin, BlockHeader->DataLength, 0);
|
BlockHeader->RawDataLength = 0;
|
BlockHeader->RawDataOffset = 0;
|
BlockHeader->DataLength = 0;
|
}
|
return TRUE;
|
}
|
|
|
BOOLEAN
|
ErrorBlockAddErrorData (
|
IN VOID *ErrorBlock,
|
IN UINT32 MaxBlockLength,
|
IN EFI_CPER_SECTION_TYPE TypeOfErrorData,
|
IN VOID *GenericErrorData,
|
IN UINT32 SizeOfGenericErrorData,
|
IN ERROR_SEVERITY ErrorSeverity,
|
IN BOOLEAN Correctable
|
)
|
{
|
if (ErrorBlock == NULL || GenericErrorData == NULL) {
|
DEBUG ((DEBUG_ERROR, "[%a]:[%dL]Invalid Param \n", __FUNCTION__, __LINE__));
|
return FALSE;
|
}
|
EFI_ACPI_6_1_GENERIC_ERROR_DATA_ENTRY_STRUCTURE* Entry;
|
EFI_ACPI_6_1_GENERIC_ERROR_STATUS_STRUCTURE* BlockHeader = ErrorBlock;
|
EFI_ACPI_6_1_ERROR_BLOCK_STATUS* BlockStatus = &BlockHeader->BlockStatus;
|
(VOID)ErrorBlockUpdateStatusStructure (ErrorBlock);
|
UINT32 ExpectedNewDataLength = BlockHeader->DataLength +
|
sizeof (EFI_ACPI_6_1_GENERIC_ERROR_DATA_ENTRY_STRUCTURE) +
|
SizeOfGenericErrorData;
|
if (sizeof (EFI_ACPI_6_1_GENERIC_ERROR_STATUS_STRUCTURE) + ExpectedNewDataLength >
|
MaxBlockLength) {
|
DEBUG ((DEBUG_ERROR, "[%a]:[%dL]Out of BlockSize \n", __FUNCTION__, __LINE__));
|
return FALSE;
|
}
|
// guid
|
EFI_GUID Guid;
|
switch (TypeOfErrorData) {
|
case PROCESSOR_GENERIC:
|
Guid = (EFI_GUID)EFI_ERROR_SECTION_PROCESSOR_GENERIC_GUID;
|
break;
|
case PROCESSOR_ARM:
|
Guid = (EFI_GUID)EFI_ERROR_SECTION_PROCESSOR_SPECIFIC_ARM_GUID;
|
break;
|
case PLATFORM_MEMORY:
|
Guid = (EFI_GUID)EFI_ERROR_SECTION_PLATFORM_MEMORY_GUID;
|
break;
|
case PLATFORM_MEMORY2:
|
Guid = (EFI_GUID)EFI_ERROR_SECTION_PLATFORM_MEMORY2_GUID;
|
break;
|
case PCIE_EXPRESS:
|
Guid = (EFI_GUID)EFI_ERROR_SECTION_PCIE_GUID;
|
break;
|
case FIRMWARE_ERROR:
|
Guid = (EFI_GUID)EFI_ERROR_SECTION_FW_ERROR_RECORD_GUID;
|
break;
|
case PCI_BUS:
|
Guid = (EFI_GUID)EFI_ERROR_SECTION_PCI_PCIX_BUS_GUID;
|
break;
|
case PCI_COMPONENT:
|
Guid = (EFI_GUID)EFI_ERROR_SECTION_PCI_DEVICE_GUID;
|
break;
|
default:
|
return FALSE;
|
}
|
//Block Status
|
if (Correctable == TRUE) {
|
if (BlockStatus->CorrectableErrorValid == 0) {
|
BlockStatus->CorrectableErrorValid = 1;
|
} else {
|
BlockStatus->MultipleCorrectableErrors = 1;
|
}
|
} else {
|
if (BlockStatus->UncorrectableErrorValid == 0) {
|
BlockStatus->UncorrectableErrorValid = 1;
|
} else {
|
BlockStatus->MultipleUncorrectableErrors = 1;
|
}
|
}
|
BlockStatus->ErrorDataEntryCount++;
|
// Entry
|
Entry = (EFI_ACPI_6_1_GENERIC_ERROR_DATA_ENTRY_STRUCTURE*)(ErrorBlock +
|
sizeof (EFI_ACPI_6_1_GENERIC_ERROR_STATUS_STRUCTURE) +
|
BlockHeader->DataLength);
|
gBS->SetMem (Entry, sizeof (EFI_ACPI_6_1_GENERIC_ERROR_DATA_ENTRY_STRUCTURE), 0);
|
gBS->CopyMem (&Entry->SectionType, &Guid, sizeof (EFI_GUID));
|
Entry->ErrorSeverity = ErrorSeverity;
|
Entry->Revision = EFI_ACPI_6_1_GENERIC_ERROR_DATA_ENTRY_REVISION;
|
Entry->ErrorDataLength = SizeOfGenericErrorData;
|
VOID* GenericErrorDataFollowEntry = (VOID*)Entry +
|
sizeof (EFI_ACPI_6_1_GENERIC_ERROR_DATA_ENTRY_STRUCTURE);
|
gBS->CopyMem (
|
GenericErrorDataFollowEntry,
|
GenericErrorData,
|
SizeOfGenericErrorData);
|
// BlockHeader
|
BlockHeader->RawDataOffset = 0;
|
BlockHeader->RawDataLength = 0;
|
BlockHeader->DataLength = ExpectedNewDataLength;
|
return TRUE;
|
}
|
|
VOID
|
GhesV2Initial (
|
EFI_ACPI_6_1_GENERIC_HARDWARE_ERROR_SOURCE_VERSION_2_STRUCTURE *GhesV2,
|
UINT32 BlockLength
|
)
|
{
|
if (GhesV2 == NULL) {
|
return;
|
}
|
*GhesV2 = (EFI_ACPI_6_1_GENERIC_HARDWARE_ERROR_SOURCE_VERSION_2_STRUCTURE) {
|
.Type = EFI_ACPI_6_1_GENERIC_HARDWARE_ERROR_VERSION_2,
|
.SourceId = 0,
|
.RelatedSourceId = 0xFFFF,
|
.Flags = 0,
|
.Enabled = 1,
|
.NumberOfRecordsToPreAllocate = 1,//ERROR BLOCK
|
.MaxSectionsPerRecord = 1,// Num Entries(section)
|
.MaxRawDataLength = BlockLength, // Max Size Of a Raw Data
|
.ErrorStatusAddress = {
|
.AddressSpaceId = EFI_ACPI_6_1_SYSTEM_MEMORY,
|
.RegisterBitWidth = 64,
|
.RegisterBitOffset = 0,
|
.AccessSize = EFI_ACPI_6_1_QWORD,
|
.Address = 0
|
},
|
.NotificationStructure = {
|
.Type = EFI_ACPI_6_1_HARDWARE_ERROR_NOTIFICATION_GSIV,
|
.Length = sizeof (EFI_ACPI_6_1_GENERIC_HARDWARE_ERROR_SOURCE_VERSION_2_STRUCTURE),
|
.ConfigurationWriteEnable = {0, 0, 0, 0, 0, 0, 0} ,
|
.PollInterval = 0,
|
.Vector = 0,
|
.SwitchToPollingThresholdValue = 0,
|
.SwitchToPollingThresholdWindow = 0,
|
.ErrorThresholdValue = 0,
|
.ErrorThresholdWindow = 0
|
},
|
.ErrorStatusBlockLength = BlockLength,
|
.ReadAckRegister = {
|
.AddressSpaceId = EFI_ACPI_6_1_SYSTEM_MEMORY,
|
.RegisterBitWidth = 64,
|
.RegisterBitOffset = 0,
|
.AccessSize = EFI_ACPI_6_1_QWORD,
|
.Address = 0
|
},
|
.ReadAckPreserve = READ_ACK_PRESERVE,
|
.ReadAckWrite = READ_ACK_WRITE
|
};
|
return;
|
}
|
|
VOID
|
GhesV2AddNotification (
|
EFI_ACPI_6_1_GENERIC_HARDWARE_ERROR_SOURCE_VERSION_2_STRUCTURE *This,
|
UINT8 Type
|
)
|
{
|
This->NotificationStructure = (EFI_ACPI_6_1_HARDWARE_ERROR_NOTIFICATION_STRUCTURE) {
|
.Type = Type,
|
.Length = sizeof (EFI_ACPI_6_1_GENERIC_HARDWARE_ERROR_SOURCE_VERSION_2_STRUCTURE),
|
.ConfigurationWriteEnable = {
|
.Type = 0,
|
.PollInterval = 1,
|
.SwitchToPollingThresholdValue = 1,
|
.SwitchToPollingThresholdWindow = 1,
|
.ErrorThresholdValue = 1,
|
.ErrorThresholdWindow = 1
|
},
|
.PollInterval = 20,
|
.Vector = 0,
|
.SwitchToPollingThresholdValue = 0,
|
.SwitchToPollingThresholdWindow = 0,
|
.ErrorThresholdValue = 0,
|
.ErrorThresholdWindow = 0
|
};
|
return;
|
}
|
|
EFI_STATUS
|
GhesV2LinkErrorBlock (
|
EFI_ACPI_6_1_GENERIC_HARDWARE_ERROR_SOURCE_VERSION_2_STRUCTURE *GhesV2,
|
GHES_REGISTER *Register,
|
VOID *ErrorBlock
|
)
|
{
|
if (ErrorBlock == NULL || Register == NULL || GhesV2 == NULL) {
|
return EFI_INVALID_PARAMETER;
|
}
|
|
Register->ErrorStatusBlockAddress = (UINTN)ErrorBlock;
|
GhesV2->ErrorStatusAddress.Address = (UINTN)&(Register->ErrorStatusBlockAddress);
|
Register->AckRegister = READ_ACK_WRITE;
|
GhesV2->ReadAckRegister.Address = (UINT64)&(Register->AckRegister);
|
return EFI_SUCCESS;
|
}
|
|
|
VOID GhesV1Initial (
|
EFI_ACPI_6_1_GENERIC_HARDWARE_ERROR_SOURCE_STRUCTURE *GhesV1,
|
UINT32 BlockLength
|
)
|
{
|
if (GhesV1 == NULL) {
|
return;
|
}
|
*GhesV1 = (EFI_ACPI_6_1_GENERIC_HARDWARE_ERROR_SOURCE_STRUCTURE) {
|
.Type = EFI_ACPI_6_1_GENERIC_HARDWARE_ERROR,
|
.SourceId = 0,
|
.RelatedSourceId = 0xFFFF,
|
.Flags = 0,
|
.Enabled = 1,
|
.NumberOfRecordsToPreAllocate = 1,//ERROR BLOCK
|
.MaxSectionsPerRecord = 1,// Num Entries(section)
|
.MaxRawDataLength = BlockLength, // Max Size Of a Raw Data
|
.ErrorStatusAddress = {
|
.AddressSpaceId = EFI_ACPI_6_1_SYSTEM_MEMORY,
|
.RegisterBitWidth = 64,
|
.RegisterBitOffset = 0,
|
.AccessSize = EFI_ACPI_6_1_QWORD,
|
.Address = 0
|
},
|
.NotificationStructure = {
|
.Type = EFI_ACPI_6_1_HARDWARE_ERROR_NOTIFICATION_GSIV,
|
.Length = sizeof (EFI_ACPI_6_1_GENERIC_HARDWARE_ERROR_SOURCE_STRUCTURE),
|
.ConfigurationWriteEnable = {0, 0, 0, 0, 0, 0, 0},
|
.PollInterval = 0,
|
.Vector = 0,
|
.SwitchToPollingThresholdValue = 0,
|
.SwitchToPollingThresholdWindow = 0,
|
.ErrorThresholdValue = 0,
|
.ErrorThresholdWindow = 0
|
},
|
.ErrorStatusBlockLength = BlockLength,
|
};
|
return;
|
}
|
|
VOID
|
GhesV1AddNotification (
|
EFI_ACPI_6_1_GENERIC_HARDWARE_ERROR_SOURCE_STRUCTURE *This,
|
UINT8 Type
|
)
|
{
|
This->NotificationStructure = (EFI_ACPI_6_1_HARDWARE_ERROR_NOTIFICATION_STRUCTURE) {
|
.Type = Type,
|
.Length = sizeof (EFI_ACPI_6_1_GENERIC_HARDWARE_ERROR_SOURCE_STRUCTURE),
|
.ConfigurationWriteEnable = {
|
.Type = 0,
|
.PollInterval = 1,
|
.SwitchToPollingThresholdValue = 1,
|
.SwitchToPollingThresholdWindow = 1,
|
.ErrorThresholdValue = 1,
|
.ErrorThresholdWindow = 1
|
},
|
.PollInterval = 20,
|
.Vector = 0,
|
.SwitchToPollingThresholdValue = 0,
|
.SwitchToPollingThresholdWindow = 0,
|
.ErrorThresholdValue = 0,
|
.ErrorThresholdWindow = 0
|
};
|
return;
|
}
|
|
EFI_STATUS GhesV1LinkErrorBlock (
|
EFI_ACPI_6_1_GENERIC_HARDWARE_ERROR_SOURCE_STRUCTURE *This,
|
UINT64 *ptrBlockAddress,
|
VOID *ErrorBlock
|
)
|
{
|
if (ErrorBlock == NULL || ptrBlockAddress == NULL || This == NULL) {
|
return EFI_INVALID_PARAMETER;
|
}
|
*ptrBlockAddress = (UINTN)ErrorBlock;
|
This->ErrorStatusAddress.Address = (UINTN) ptrBlockAddress;
|
return EFI_SUCCESS;
|
}
|
|