alder_lake_bios/Intel/AlderLake/AlderLakePlatSamplePkg/Telemetry/CsmeHealthDxe/CsmeHealthDxe.c

331 lines
14 KiB
C

/** @file
CSME FW Health Data Initialization for Telemetry.
@copyright
INTEL CONFIDENTIAL
Copyright 2019 - 2020 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 an 'Intel Peripheral Driver' and is uniquely identified as
"Intel Reference Module" and is licensed for Intel CPUs and chipsets under
the terms of your license agreement with Intel or your vendor. This file may
be modified by the user, subject to additional terms of the license agreement.
@par Specification Reference:
**/
#include "CsmeHealthDxe.h"
typedef struct {
EFI_HANDLE Handle;
EFI_ADAPTER_INFORMATION_PROTOCOL AdapterInfo;
EFI_DEVICE_PATH_PROTOCOL *CsmeDevicePath;
} CSME_HEALTH_DEV;
/**
This function gets the CSME health data.
@param[in] This A pointer to the EFI_ADAPTER_INFORMATION_PROTOCOL instance.
@param[in] InformationType A pointer to gAdapterInfoCsmeGuid that defines the contents of InformationBlock.
The caller must use the InformationType to specify the infromation it needs to retrieve
from this service and to determine how to parse the InformationBlock.
The driver should not attempt to free InformationType.
@param[out] InformationBlock A pointer to the number of GUIDs present in InfoTypesBuffer.
@param[out] InformationBlockSize The driver return the size of the InformationBlock.
@retval EFI_INVALID_PARAMETER
@retval EFI_OUT_OF_RESOURCES
@retval EFI_UNSUPPORTED
@retval EFI_SUCCESS
**/
EFI_STATUS
EFIAPI
CsmeHealthDataAipGetInfo (
IN EFI_ADAPTER_INFORMATION_PROTOCOL *This,
IN EFI_GUID *InformationType,
OUT VOID **InformationBlock,
OUT UINTN *InformationBlockSize
)
{
UINT8 IsHealthy;
EFI_AIP_CSME_HEALTH_STATE *HealthDataBlockPtr;
UINT64 DevicePciCfgBase;
ME_FW_HOB *MeFwHob;
HECI_FWS_REGISTER FwSts1;
HECI_GS_SHDW_REGISTER FwSts2;
HECI_FW_STS6_REGISTER FwSts6;
UINTN BlockSize;
if ((This == NULL) || (InformationBlock == NULL) || (InformationBlockSize == NULL)) {
return EFI_INVALID_PARAMETER;
}
if (!CompareGuid (InformationType, &gAdapterInfoCsmeGuid)) {
return EFI_UNSUPPORTED;
}
DEBUG ((DEBUG_INFO, "CsmeHealthDataAipGetInfo : Getting CSME Health Data ...\n"));
*InformationBlockSize = 0;
*InformationBlock = NULL;
IsHealthy = 0;
BlockSize = sizeof(EFI_AIP_CSME_HEALTH_STATE);
HealthDataBlockPtr = (EFI_AIP_CSME_HEALTH_STATE *) AllocateZeroPool (BlockSize);
if (HealthDataBlockPtr == NULL) {
DEBUG ((DEBUG_ERROR, "CsmeHealthDataAipGetInfo : Out of resource to allocate for EFI_AIP_CSME_HEALTH_STATE.\n"));
return EFI_OUT_OF_RESOURCES;
}
//
// If HECI device is available, read current FWSTS1 and FWSTS2 from config space first.
// If HECI device is not available, get info from ME_FW_HOB.
//
DevicePciCfgBase = PCI_SEGMENT_LIB_ADDRESS (ME_SEGMENT, ME_BUS, ME_DEVICE_NUMBER, HECI_FUNCTION_NUMBER, 0);
if (PciSegmentRead16 (DevicePciCfgBase + PCI_DEVICE_ID_OFFSET) != 0xFFFF) {
DEBUG ((DEBUG_INFO, "CsmeHealthDataAipGetInfo : Reading FWSTS from registers ... \n"));
FwSts1.ul = PciSegmentRead32 (PCI_SEGMENT_LIB_ADDRESS (ME_SEGMENT, ME_BUS, ME_DEVICE_NUMBER, HECI_FUNCTION_NUMBER, R_ME_HFS));
FwSts2.ul = PciSegmentRead32 (PCI_SEGMENT_LIB_ADDRESS (ME_SEGMENT, ME_BUS, ME_DEVICE_NUMBER, HECI_FUNCTION_NUMBER, R_ME_HFS_2));
FwSts6.ul = PciSegmentRead32 (PCI_SEGMENT_LIB_ADDRESS (ME_SEGMENT, ME_BUS, ME_DEVICE_NUMBER, HECI_FUNCTION_NUMBER, R_ME_HFS_6));
DEBUG ((DEBUG_INFO, "CsmeHealthDataAipGetInfo : FwSts1 = 0x%08x, FwSts2 = 0x%08x \n", FwSts1.ul, FwSts2.ul));
DEBUG ((DEBUG_INFO, " : FwSts6 = 0x%08x \n", FwSts6.ul));
} else {
DEBUG ((DEBUG_INFO, "CsmeHealthDataAipGetInfo : HECI device is not availbale so reading FWSTS from HOB ... \n"));
MeFwHob = GetFirstGuidHob (&gMeFwHobGuid);
if (MeFwHob != NULL) {
FwSts1.ul = MeFwHob->Group[0].Reg[0];
FwSts2.ul = MeFwHob->Group[0].Reg[1];
FwSts6.ul = MeFwHob->Group[0].Reg[5];
DEBUG ((DEBUG_INFO, "CsmeHealthDataAipGetInfo : FwSts1 = 0x%08x, FwSts2 = 0x%08x \n", FwSts1, FwSts2));
DEBUG ((DEBUG_INFO, " : FwSts6 = 0x%08x \n", FwSts6));
} else {
DEBUG ((DEBUG_ERROR, "CsmeHealthDataAipGetInfo : ME FW Hob is not available \n"));
FreePool (HealthDataBlockPtr);
return EFI_DEVICE_ERROR;
}
}
//
// Store CSME Health Data
//
HealthDataBlockPtr->Revision = CSME_AIP_DATA_REVISION;
HealthDataBlockPtr->CurrentState = (UINT8)FwSts1.r.CurrentState;
HealthDataBlockPtr->FwInitComplete = (UINT8)FwSts1.r.FwInitComplete;
HealthDataBlockPtr->MfsFailure = (UINT8)FwSts2.r.MfsFailure;
HealthDataBlockPtr->MeOperationMode = (UINT8)FwSts1.r.MeOperationMode;
HealthDataBlockPtr->ErrorCode = (UINT8)FwSts1.r.ErrorCode;
//
// ManufacturingMode is not available on the Alder Lake platform
//
HealthDataBlockPtr->ManufacturingMode = 0;
HealthDataBlockPtr->FpfSocConfigLock = (UINT8)FwSts6.r.FpfSocConfigLock;
HealthDataBlockPtr->FwUpdateInprogress = (UINT8)FwSts1.r.FwUpdateInprogress;
//
// Evaluate if it is healthy
//
IsHealthy = TelemetryUnhealthy;
if ((HealthDataBlockPtr->CurrentState == ME_STATE_NORMAL) && // ME is in normal working state
(HealthDataBlockPtr->MfsFailure == 0x0) && // No MFS failure detected
(HealthDataBlockPtr->MeOperationMode == 0x0) && // Normal operation mode
(HealthDataBlockPtr->ErrorCode == 0x0)) { // No error
IsHealthy = TelemetryHealthy; // 1: healthy
}
//
// Create the data header
//
HealthDataBlockPtr->Header.Length = sizeof(EFI_AIP_CSME_HEALTH_STATE);
HealthDataBlockPtr->Header.Revision = CSME_AIP_HEADER_REVISION;
HealthDataBlockPtr->Header.Healthy = IsHealthy;
CopyGuid (&HealthDataBlockPtr->Header.Signature, &gAdapterInfoCsmeGuid);
//
// Print CSME health data block
//
DEBUG ((DEBUG_INFO, "=== EFI_AIP_CSME_HEALTH_STATE ==\n"));
DEBUG ((DEBUG_INFO, " EFI_AIP_HEALTH_HEADER \n"));
DEBUG ((DEBUG_INFO, " Length = 0x%04x \n", HealthDataBlockPtr->Header.Length));
DEBUG ((DEBUG_INFO, " Revision = 0x%02x \n", HealthDataBlockPtr->Header.Revision));
DEBUG ((DEBUG_INFO, " Healthy = 0x%02x \n", HealthDataBlockPtr->Header.Healthy));
DEBUG ((DEBUG_INFO, " Signature = %g \n", HealthDataBlockPtr->Header.Signature));
DEBUG ((DEBUG_INFO, " Revision = 0x%02x \n", HealthDataBlockPtr->Revision));
DEBUG ((DEBUG_INFO, " FwInitComplete = 0x%02x \n", HealthDataBlockPtr->FwInitComplete));
DEBUG ((DEBUG_INFO, " CurrentState = 0x%02x \n", HealthDataBlockPtr->CurrentState));
DEBUG ((DEBUG_INFO, " MfsFailure = 0x%02x \n", HealthDataBlockPtr->MfsFailure));
DEBUG ((DEBUG_INFO, " MeOperationMode = 0x%02x \n", HealthDataBlockPtr->MeOperationMode));
DEBUG ((DEBUG_INFO, " ErrorCode = 0x%02x \n", HealthDataBlockPtr->ErrorCode));
DEBUG ((DEBUG_INFO, " FpfSocConfigLock = 0x%02x \n", HealthDataBlockPtr->FpfSocConfigLock));
DEBUG ((DEBUG_INFO, " FwUpdateInprogress = 0x%02x \n", HealthDataBlockPtr->FwUpdateInprogress));
DEBUG ((DEBUG_INFO, "==================================\n"));
*InformationBlock = HealthDataBlockPtr;
*InformationBlockSize = sizeof (EFI_AIP_CSME_HEALTH_STATE);
return EFI_SUCCESS;
}
/**
This function sets the CSME health data.
@param[in] *This A pointer to the EFI_ADAPTER_INFORMATION_PROTOCOL instance.
@param[in] EFI_GUID *InformationType A pointer to gAdapterInfoCsmeGuid that defines the contents of InformationBlock.
The caller must use the InformationType to specify the infromation it needs to retrieve
from this service and to determine how to parse the InformationBlock.
The driver should not attempt to free InformationType.
@param[in] VOID **InformationBlock A poointer to the number of GUIDs present in InfoTypesBuffer.
@retval EFI_WRITE_PROTECTED
**/
EFI_STATUS
EFIAPI
CsmeHealthDataAipSetInfo (
IN EFI_ADAPTER_INFORMATION_PROTOCOL *This,
IN EFI_GUID *InformationType,
IN VOID *InformationBlock,
IN UINTN InformationBlockSize
)
{
if ((This == NULL) || (InformationBlock == NULL)) {
return EFI_INVALID_PARAMETER;
}
if (!CompareGuid (InformationType, &gAdapterInfoCsmeGuid)) {
return EFI_UNSUPPORTED;
}
return EFI_WRITE_PROTECTED;
}
/**
This function gets a list of Information types for this instance of the protocol.
@param[in] *This A pointer to the EFI_ADAPTER_INFORMATION_PROTOCOL instance.
@param[out] **InfoTypesBuffer A pointer to the array of InformationType GUID is supported by This.
This buffer is allocated by this service, and it is the responsibility
of the caller to free it after using it.
@param[out] *InfoTypesBufferCount A pointer to the number of GUIDs present in InfoTypesBuffer.
@retval EFI_INVALID_PARAMETER
@retval EFI_OUT_OF_RESOURCES
@retval EFI_SUCCESS
**/
EFI_STATUS
EFIAPI
CsmeHealthDataGetSupportedTypes (
IN EFI_ADAPTER_INFORMATION_PROTOCOL *This,
OUT EFI_GUID **InfoTypesBuffer,
OUT UINTN *InfoTypesBufferCount
)
{
if ((This == NULL) || (InfoTypesBuffer == NULL) || (InfoTypesBufferCount == NULL)) {
return EFI_INVALID_PARAMETER;
}
*InfoTypesBuffer = AllocateCopyPool (sizeof(gAdapterInfoCsmeGuid), &gAdapterInfoCsmeGuid);
if (*InfoTypesBuffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
*InfoTypesBufferCount = 1;
return EFI_SUCCESS;
}
/**
This function installs EFI_ADAPTER_INFORMATION_PROTOCOL for CSME Health Data.
The data is consumed by Telemetry data collector.
@param[in] ImageHandle The firmware allocated handle for the EFI image.
@param[in] SystemTable A pointer to the EFI System Table.
@retval EFI_SUCCESS The CSME Health data is successfully published in AIP protocol.
@retval EFI_OUT_OF_RESOURCES Out of resources to allocate EFI_ADAPTER_INFORMATION_PROTOCOL.
**/
EFI_STATUS
EFIAPI
CsmeHealthDataDxeEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
CSME_HEALTH_DEV *CsmeHealthPrivate;
VENDOR_DEVICE_PATH VendorDeviceNode;
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
Status = EFI_SUCCESS;
DevicePath = NULL;
DEBUG ((DEBUG_INFO, "InitializeCsmeHealthData Begins\n"));
CsmeHealthPrivate = (CSME_HEALTH_DEV *) AllocateZeroPool (sizeof (CSME_HEALTH_DEV));
if (CsmeHealthPrivate == NULL) {
DEBUG ((EFI_D_ERROR, "EFI_OUT_OF_RESOURCES to Allocate EFI_ADAPTER_INFORMATION_PROTOCOL.\n"));
return EFI_OUT_OF_RESOURCES;
}
CsmeHealthPrivate->Handle = NULL;
CsmeHealthPrivate->AdapterInfo.GetInformation = CsmeHealthDataAipGetInfo;
CsmeHealthPrivate->AdapterInfo.SetInformation = CsmeHealthDataAipSetInfo;
CsmeHealthPrivate->AdapterInfo.GetSupportedTypes = CsmeHealthDataGetSupportedTypes;
ZeroMem (&VendorDeviceNode, sizeof (VENDOR_DEVICE_PATH));
VendorDeviceNode.Header.Type = HARDWARE_DEVICE_PATH;
VendorDeviceNode.Header.SubType = HW_VENDOR_DP;
CopyGuid (&VendorDeviceNode.Guid, &gAdapterInfoCsmeGuid);
SetDevicePathNodeLength (&VendorDeviceNode.Header, sizeof (VENDOR_DEVICE_PATH));
DevicePath = AppendDevicePathNode (NULL, (EFI_DEVICE_PATH_PROTOCOL*)&VendorDeviceNode);
if (DevicePath == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto ERROR;
}
CsmeHealthPrivate->CsmeDevicePath = DevicePath;
Status = gBS->InstallMultipleProtocolInterfaces (
&CsmeHealthPrivate->Handle,
&gEfiAdapterInformationProtocolGuid,
&CsmeHealthPrivate->AdapterInfo,
&gEfiDevicePathProtocolGuid,
CsmeHealthPrivate->CsmeDevicePath,
NULL
);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "InitializeCsmeHealthData: faild to install AIP protocol, %r.\n", Status));
goto ERROR;
}
DEBUG ((DEBUG_INFO, "InitializeCsmeHealthData Ends\n"));
return Status;
ERROR:
//
// On error, clean the Aip service context data, and free the memory allocated.
//
FreePool (CsmeHealthPrivate);
if (DevicePath != NULL) {
FreePool (DevicePath);
}
return Status;
}