|
@@ -0,0 +1,330 @@
|
|
|
+/** @file
|
|
|
+*
|
|
|
+* Copyright (c) 2018, Hisilicon Limited. All rights reserved.
|
|
|
+* Copyright (c) 2018, Linaro Limited. All rights reserved.
|
|
|
+*
|
|
|
+* This program and the accompanying materials
|
|
|
+* are licensed and made available under the terms and conditions of the BSD License
|
|
|
+* which accompanies this distribution. The full text of the license may be found at
|
|
|
+* http://opensource.org/licenses/bsd-license.php
|
|
|
+*
|
|
|
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
|
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
+*
|
|
|
+**/
|
|
|
+
|
|
|
+#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;
|
|
|
+}
|
|
|
+
|