1684 lines
57 KiB
C
1684 lines
57 KiB
C
/** @file
|
|
This file implements firmware version information.
|
|
|
|
Copyright (c) 2018 - 2021, Intel Corporation. All rights reserved.<BR>
|
|
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 "DxeTelemetryAcpiLib.h"
|
|
#include "DxeTelemetryHwErrRec.h"
|
|
|
|
BOOLEAN mPhatInstalled = FALSE;
|
|
UINTN mTableKey;
|
|
|
|
GLOBAL_REMOVE_IF_UNREFERENCED EFI_ACPI_TABLE_PROTOCOL *mAcpiTableProtocol = NULL;
|
|
EFI_RSC_HANDLER_PROTOCOL *mRscHandlerProtocol = NULL;
|
|
|
|
UINT8 AcpiComPonentHeadSize = OFFSET_OF (EFI_COMPONENT_VERSION_DATA, Records);
|
|
UINT16 AcpiFviRecordSize = sizeof (TELEMETRY_DATA_RECORD);
|
|
|
|
GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID *mDriverHealthSupportList[] = {
|
|
&gAdapterInfoMotherBoardHealthGuid,
|
|
&gAdapterInfoCsmeGuid,
|
|
&gAdapterInfoMrcGuid,
|
|
&gAdapterInfoNvmeHealthGuid,
|
|
NULL
|
|
};
|
|
|
|
/**
|
|
This function calculates and updates an UINT8 checksum.
|
|
|
|
@param Buffer Pointer to buffer to checksum
|
|
@param Size Number of bytes to checksum
|
|
|
|
**/
|
|
VOID
|
|
AcpiPlatformChecksum (
|
|
IN UINT8 *Buffer,
|
|
IN UINTN Size
|
|
)
|
|
{
|
|
UINTN ChecksumOffset;
|
|
|
|
ChecksumOffset = OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER, Checksum);
|
|
|
|
//
|
|
// Set checksum to 0 first
|
|
//
|
|
Buffer[ChecksumOffset] = 0;
|
|
|
|
//
|
|
// Update checksum value
|
|
//
|
|
Buffer[ChecksumOffset] = CalculateCheckSum8(Buffer, Size);
|
|
}
|
|
|
|
/**
|
|
Collect driver health information by CommponentID(Guid).
|
|
|
|
@param[in] ComponentID The unique GUID associated with this device.
|
|
@param[out] AcpiDataBlock Point to the buffer of driver health Acpi record
|
|
@param[out] AcpiDataSize length of driver health Acpi record
|
|
|
|
@retval EFI_SUCCESS All driver health info was collected successfully
|
|
@retval EFI_NOT_FOUND No handles match the search or no record was found.
|
|
@retval EFI_OUT_OF_RESOURCES There is not enough memory resource.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
DriverHealthAipDataCollection (
|
|
IN EFI_GUID *ComponentID,
|
|
OUT UINT8 **AcpiDataBlock,
|
|
OUT UINTN *AcpiDataSize
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_ADAPTER_INFORMATION_PROTOCOL *Aip;
|
|
UINTN HandleCount;
|
|
EFI_HANDLE *HandleBuffer;
|
|
EFI_GUID *InfoTypesBuffer;
|
|
UINTN InfoTypeBufferCount;
|
|
UINTN Index;
|
|
UINTN TypeIndex;
|
|
BOOLEAN Supported;
|
|
UINT8 *DataBlock;
|
|
UINTN BlockSize;
|
|
EFI_AIP_HEALTH_HEADER *AipPtr;
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
UINTN SizeOfDevicePath;
|
|
UINTN DevSpecificDataOffset;
|
|
EFI_ACPI_TELEMETRY_HEALTH_DATA_RECORD_STRUCTURE *AcpiDataBlockHeader;
|
|
UINTN AcpiDataSizeTemp;
|
|
CHAR16 *DevicePathText;
|
|
UINT8 *AcpiDataBlockHead;
|
|
|
|
InfoTypesBuffer = NULL;
|
|
Status = EFI_SUCCESS;
|
|
AipPtr = NULL;
|
|
DataBlock = NULL;
|
|
BlockSize = 0;
|
|
DevSpecificDataOffset = 0;
|
|
DevicePathText = NULL;
|
|
SizeOfDevicePath = 0;
|
|
*AcpiDataBlock = NULL;
|
|
*AcpiDataSize = 0;
|
|
AcpiDataSizeTemp = 0;
|
|
AcpiDataBlockHead = NULL;
|
|
|
|
Status = gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiAdapterInformationProtocolGuid,
|
|
NULL,
|
|
&HandleCount,
|
|
&HandleBuffer
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
//
|
|
// gEfiAdapterInformationProtocolGuid protocol not installed yet!
|
|
//
|
|
DEBUG ((EFI_D_ERROR, "gEfiAdapterInformationProtocolGuid locate failed, status = [%x] \n", Status));
|
|
return Status;
|
|
}
|
|
if (HandleBuffer == NULL) {
|
|
DEBUG ((EFI_D_ERROR, " HandleBuffer is null \n"));
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
for (Index = 0; Index < HandleCount ; Index++) {
|
|
Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiAdapterInformationProtocolGuid, (VOID **) &Aip);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((EFI_D_ERROR, "HandleProtocol gEfiAdapterInformationProtocolGuid failed. \n"));
|
|
return Status;
|
|
} else {
|
|
InfoTypeBufferCount = 0;
|
|
Status = Aip->GetSupportedTypes (Aip, &InfoTypesBuffer, &InfoTypeBufferCount);
|
|
if (EFI_ERROR (Status) || InfoTypesBuffer == NULL) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Check whether the AIP instance has FVI information block.
|
|
//
|
|
Supported = FALSE;
|
|
for (TypeIndex = 0; TypeIndex < InfoTypeBufferCount; TypeIndex++) {
|
|
if (CompareGuid (&InfoTypesBuffer[TypeIndex], ComponentID)) {
|
|
Supported = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!Supported) {
|
|
continue;
|
|
}
|
|
|
|
Status = Aip->GetInformation (Aip, ComponentID, (VOID **) &DataBlock, &BlockSize);
|
|
DEBUG ((EFI_D_ERROR, "Aip->GetInformation, Status=[%x], data length=[%x]. \n", Status, BlockSize));
|
|
if (EFI_ERROR (Status) || DataBlock == NULL || BlockSize == 0
|
|
|| BlockSize < sizeof (EFI_AIP_HEALTH_HEADER)) {
|
|
DEBUG ((EFI_D_ERROR, "It is failed to built driver Health. \n"));
|
|
continue;
|
|
}
|
|
|
|
AipPtr = (EFI_AIP_HEALTH_HEADER *) DataBlock;
|
|
|
|
//
|
|
// To handle driver health device path
|
|
//
|
|
Status = gBS->HandleProtocol (
|
|
HandleBuffer[Index],
|
|
&gEfiDevicePathProtocolGuid,
|
|
(VOID **) &DevicePath
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((EFI_D_ERROR, "Can't get DevicePath, Status = [%x]. \n", Status));
|
|
break;
|
|
} else {
|
|
DevicePathText = ConvertDeviceNodeToText (DevicePath, FALSE, FALSE);
|
|
if (DevicePathText == NULL) {
|
|
DEBUG ((EFI_D_ERROR, "Invalid DevicePath node.\n"));
|
|
break;
|
|
}
|
|
}
|
|
SizeOfDevicePath = StrSize (DevicePathText);
|
|
DevSpecificDataOffset = sizeof (EFI_ACPI_TELEMETRY_HEALTH_DATA_RECORD_STRUCTURE) + SizeOfDevicePath;
|
|
|
|
//
|
|
// To save the previous total size
|
|
//
|
|
AcpiDataSizeTemp = *AcpiDataSize;
|
|
//
|
|
// Get the total length (just include one default capsule instance for Mother board health)
|
|
//
|
|
if ((MAX_UINTN - DevSpecificDataOffset) < BlockSize - sizeof (EFI_AIP_HEALTH_HEADER)) {
|
|
DEBUG ((EFI_D_ERROR, "Warning: found integer overflow.\n"));
|
|
continue;
|
|
}
|
|
*AcpiDataSize += DevSpecificDataOffset + (BlockSize - sizeof (EFI_AIP_HEALTH_HEADER));
|
|
|
|
if (*AcpiDataBlock == NULL) {
|
|
//
|
|
// Try to find the 1th health record
|
|
//
|
|
*AcpiDataBlock = AllocateZeroPool (*AcpiDataSize);
|
|
} else {
|
|
*AcpiDataBlock = ReallocatePool (AcpiDataSizeTemp, *AcpiDataSize, *AcpiDataBlock);
|
|
}
|
|
|
|
if (*AcpiDataBlock == NULL) {
|
|
if (InfoTypesBuffer != NULL) {
|
|
FreePool (InfoTypesBuffer);
|
|
}
|
|
|
|
if (HandleBuffer != NULL) {
|
|
FreePool (HandleBuffer);
|
|
}
|
|
|
|
if (DataBlock != NULL) {
|
|
FreePool (DataBlock);
|
|
}
|
|
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
AcpiDataBlockHead = *AcpiDataBlock;
|
|
*AcpiDataBlock += AcpiDataSizeTemp;
|
|
AcpiDataBlockHeader = (EFI_ACPI_TELEMETRY_HEALTH_DATA_RECORD_STRUCTURE *) (*AcpiDataBlock);
|
|
|
|
AcpiDataBlockHeader->Header.RecordType = FirmwareHealthDataRecord;
|
|
AcpiDataBlockHeader->Header.RecordLength = (UINT16) (*AcpiDataSize - AcpiDataSizeTemp);
|
|
AcpiDataBlockHeader->Header.Revision = TELEMETRY_ACPI_HEADER_REVISION;
|
|
AcpiDataBlockHeader->Reserved = 0;
|
|
AcpiDataBlockHeader->AmHealthy = AipPtr->Healthy;
|
|
CopyGuid (&AcpiDataBlockHeader->DeviceSignature, &AipPtr->Signature);
|
|
AcpiDataBlockHeader->DeviceSpecificDataOffset = (UINT32) DevSpecificDataOffset;
|
|
|
|
if (SizeOfDevicePath > 0) {
|
|
//
|
|
// Add device path data to ACPI table
|
|
//
|
|
CopyMem (
|
|
*AcpiDataBlock + sizeof (EFI_ACPI_TELEMETRY_HEALTH_DATA_RECORD_STRUCTURE),
|
|
DevicePathText,
|
|
SizeOfDevicePath
|
|
);
|
|
}
|
|
|
|
//
|
|
// Attach driver health special data
|
|
//
|
|
CopyMem (
|
|
*AcpiDataBlock + DevSpecificDataOffset,
|
|
DataBlock + sizeof (EFI_AIP_HEALTH_HEADER),
|
|
BlockSize - sizeof (EFI_AIP_HEALTH_HEADER)
|
|
);
|
|
|
|
*AcpiDataBlock = AcpiDataBlockHead;
|
|
|
|
if (InfoTypesBuffer != NULL) {
|
|
FreePool (InfoTypesBuffer);
|
|
}
|
|
|
|
if (DataBlock != NULL) {
|
|
FreePool (DataBlock);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (HandleBuffer != NULL) {
|
|
FreePool (HandleBuffer);
|
|
}
|
|
|
|
if ((*AcpiDataBlock == NULL) || (*AcpiDataSize == 0)) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Retrieve all available Image info by Fmp protocol, and attach them
|
|
to the tail of Mother board health record.
|
|
|
|
@param[out] MotherBoardData Point to the buffer of EFI_LAST_UPDATE_DATA
|
|
in mother board health record
|
|
@param[out] MotherBoardSize totoal length of all EFI_LAST_UPDATE_DATA data
|
|
|
|
@retval EFI_SUCCESS Fmp info was collected successfully
|
|
@retval EFI_OUT_OF_RESOURCES There is not enough memory resource.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
AttachAllFmpInfoToEnd (
|
|
OUT UINT8 **MotherBoardData,
|
|
OUT UINTN *MotherBoardSize
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;
|
|
EFI_HANDLE *HandleBuffer;
|
|
UINTN NumberOfHandles;
|
|
UINTN Index;
|
|
UINT8 Index2;
|
|
EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf;
|
|
UINTN ImageInfoSize;
|
|
UINT32 FmpImageInfoDescriptorVer;
|
|
UINT8 FmpImageInfoCount;
|
|
UINTN DescriptorSize;
|
|
UINT32 PackageVersion;
|
|
CHAR16 *PackageVersionName;
|
|
UINTN RecordCount;
|
|
UINT8 *ImageInfoHead;
|
|
UINT64 *LastUpdateTimeValue;
|
|
UINT8 *CapsuleUpdateValue;
|
|
UINT16 *CapsuleUpdateLastValue;
|
|
EFI_TIME CapsuleLastUdpateTime;
|
|
EFI_GUID CapsuleUpdateGuid;
|
|
UINTN NumOfCapsuleUpdate;
|
|
CHAR16 CapsuleUpdate[16];
|
|
EFI_STATUS CapsuleStatus;
|
|
|
|
RecordCount = 0;
|
|
ImageInfoHead = NULL;
|
|
FmpImageInfoBuf = NULL;
|
|
LastUpdateTimeValue = NULL;
|
|
CapsuleUpdateLastValue = NULL;
|
|
CapsuleUpdateValue = NULL;
|
|
CapsuleStatus = EFI_SUCCESS;
|
|
|
|
Status = gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiFirmwareManagementProtocolGuid,
|
|
NULL,
|
|
&NumberOfHandles,
|
|
&HandleBuffer
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((EFI_D_ERROR, "FMP protocol is EFI_NOT_FOUND\n"));
|
|
return Status;
|
|
}
|
|
|
|
*MotherBoardData = AllocateZeroPool (sizeof (EFI_LAST_UPDATE_DATA) * NumberOfHandles);
|
|
if (*MotherBoardData == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto EXIT;
|
|
}
|
|
ImageInfoHead = *MotherBoardData;
|
|
|
|
for (Index = 0; Index < NumberOfHandles; Index++) {
|
|
Status = gBS->HandleProtocol (
|
|
HandleBuffer[Index],
|
|
&gEfiFirmwareManagementProtocolGuid,
|
|
(VOID **) &Fmp
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
continue;
|
|
}
|
|
|
|
ImageInfoSize = 0;
|
|
Status = Fmp->GetImageInfo (
|
|
Fmp,
|
|
&ImageInfoSize,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
if (Status != EFI_BUFFER_TOO_SMALL) {
|
|
continue;
|
|
}
|
|
|
|
FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);
|
|
if (FmpImageInfoBuf == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto EXIT;
|
|
}
|
|
|
|
PackageVersionName = NULL;
|
|
Status = Fmp->GetImageInfo (
|
|
Fmp,
|
|
&ImageInfoSize, // ImageInfoSize
|
|
FmpImageInfoBuf, // ImageInfo
|
|
&FmpImageInfoDescriptorVer, // DescriptorVersion
|
|
&FmpImageInfoCount, // DescriptorCount
|
|
&DescriptorSize, // DescriptorSize
|
|
&PackageVersion, // PackageVersion
|
|
&PackageVersionName // PackageVersionName
|
|
);
|
|
|
|
//
|
|
// If FMP GetInformation interface failed, skip this resource
|
|
//
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((EFI_D_ERROR, "FMP (%d) ImageInfo - %r\n", Index, Status));
|
|
FreePool (FmpImageInfoBuf);
|
|
continue;
|
|
}
|
|
|
|
//
|
|
//Check CapsuleLast
|
|
//
|
|
Status = GetVariable2 (CAPSULELAST, &gEfiCapsuleReportGuid, (VOID **) &CapsuleUpdateLastValue, NULL);
|
|
if (!EFI_ERROR (Status)) {
|
|
NumOfCapsuleUpdate = (UINT16) StrHexToUintn (&CapsuleUpdateLastValue[sizeof ("Capsule") - 1]);
|
|
for (Index2 = 0; Index2 <= NumOfCapsuleUpdate; Index2++) {
|
|
UnicodeSPrint (CapsuleUpdate, sizeof (CapsuleUpdate), L"%s%04X", CAPSULE_VAR_NAME, Index2);
|
|
Status = GetVariable2 (CapsuleUpdate, &gEfiCapsuleReportGuid, (VOID **) &CapsuleUpdateValue, NULL);
|
|
if (!EFI_ERROR (Status)) {
|
|
CopyMem (&CapsuleStatus, CapsuleUpdateValue + OFFSET_OF (EFI_CAPSULE_RESULT_VARIABLE_HEADER,
|
|
CapsuleStatus), sizeof (EFI_STATUS));
|
|
if (EFI_ERROR (CapsuleStatus)) {
|
|
continue;
|
|
}
|
|
CopyGuid (&CapsuleUpdateGuid,
|
|
(EFI_GUID *) (CapsuleUpdateValue +
|
|
sizeof (EFI_CAPSULE_RESULT_VARIABLE_HEADER) +
|
|
OFFSET_OF (EFI_CAPSULE_RESULT_VARIABLE_FMP, UpdateImageTypeId)));
|
|
if (CompareGuid (&FmpImageInfoBuf->ImageTypeId, &CapsuleUpdateGuid)) {
|
|
CopyMem (&CapsuleLastUdpateTime,
|
|
CapsuleUpdateValue +
|
|
OFFSET_OF (EFI_CAPSULE_RESULT_VARIABLE_HEADER, CapsuleProcessed), sizeof (EFI_TIME));
|
|
Status = gRT->SetVariable (
|
|
VARNAME_LASTUPDATETIME,
|
|
&FmpImageInfoBuf->ImageTypeId,
|
|
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
|
|
sizeof (EFI_TIME),
|
|
&CapsuleLastUdpateTime
|
|
);
|
|
}
|
|
if (CapsuleUpdateValue != NULL) {
|
|
FreePool (CapsuleUpdateValue);
|
|
}
|
|
} else {
|
|
Status = EFI_SUCCESS;
|
|
continue;
|
|
}
|
|
}
|
|
if (CapsuleUpdateLastValue != NULL) {
|
|
FreePool (CapsuleUpdateLastValue);
|
|
}
|
|
} else {
|
|
Status = EFI_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// combine all LastUdpateTime and EsrtID here
|
|
//
|
|
Status = GetVariable2 (VARNAME_LASTUPDATETIME, &FmpImageInfoBuf->ImageTypeId, (VOID **) &LastUpdateTimeValue, NULL);
|
|
if (!EFI_ERROR (Status) && (LastUpdateTimeValue != NULL)) {
|
|
CopyMem (ImageInfoHead, LastUpdateTimeValue, sizeof (EFI_TIME));
|
|
} else {
|
|
ZeroMem (ImageInfoHead, sizeof (EFI_TIME));
|
|
Status = EFI_SUCCESS;
|
|
}
|
|
ImageInfoHead = ImageInfoHead + sizeof (EFI_TIME);
|
|
|
|
CopyMem (ImageInfoHead, &FmpImageInfoBuf->ImageTypeId, sizeof (EFI_GUID));
|
|
ImageInfoHead = ImageInfoHead + sizeof (EFI_GUID);
|
|
|
|
RecordCount++;
|
|
if (PackageVersionName != NULL) {
|
|
FreePool (PackageVersionName);
|
|
}
|
|
|
|
if (LastUpdateTimeValue != NULL) {
|
|
FreePool (LastUpdateTimeValue);
|
|
}
|
|
|
|
FreePool (FmpImageInfoBuf);
|
|
}
|
|
|
|
*MotherBoardSize = sizeof (EFI_LAST_UPDATE_DATA) * RecordCount;
|
|
|
|
EXIT:
|
|
if (HandleBuffer != NULL) {
|
|
FreePool (HandleBuffer);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
|
|
This function scan ACPI table entry point.
|
|
|
|
@return ACPI table entry pointer
|
|
|
|
**/
|
|
VOID *
|
|
SearchAcpiTablePointer (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp;
|
|
EFI_ACPI_DESCRIPTION_HEADER *Entry;
|
|
EFI_STATUS Status;
|
|
|
|
Entry = NULL;
|
|
|
|
Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &mAcpiTableProtocol);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((EFI_D_INFO, "locate gEfiAcpiTableProtocolGuid failed, status[%x].\n", Status));
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Find ACPI table RSD_PTR from the system table.
|
|
//
|
|
Status = EfiGetSystemConfigurationTable (&gEfiAcpiTableGuid, (VOID **) &Rsdp);
|
|
if (EFI_ERROR (Status)) {
|
|
Status = EfiGetSystemConfigurationTable (&gEfiAcpi10TableGuid, (VOID **) &Rsdp);
|
|
}
|
|
|
|
if (EFI_ERROR (Status) || (Rsdp == NULL)) {
|
|
DEBUG ((EFI_D_INFO, "Can't find RSD_PTR from system table! \n"));
|
|
return NULL;
|
|
} else if (Rsdp->Revision >= EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION && Rsdp->XsdtAddress != 0) {
|
|
Entry = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN) Rsdp->XsdtAddress;
|
|
} else if (Rsdp->RsdtAddress != 0) {
|
|
Entry = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN) Rsdp->RsdtAddress;
|
|
}
|
|
|
|
if (Entry == NULL) {
|
|
DEBUG ((EFI_D_INFO, "Both XsdtAddress and RsdtAddress are NULL! \n"));
|
|
return NULL;
|
|
}
|
|
|
|
return Entry;
|
|
}
|
|
|
|
/**
|
|
|
|
This function scan ACPI table entry point by its signature.
|
|
|
|
@param Xsdt XSDT table entry point.
|
|
@param Signature ACPI table signature.
|
|
|
|
@return ACPI table entry point.
|
|
|
|
**/
|
|
VOID *
|
|
ScanTableInXSDT (
|
|
IN EFI_ACPI_DESCRIPTION_HEADER *Xsdt,
|
|
IN UINT32 Signature
|
|
)
|
|
{
|
|
UINTN Index;
|
|
UINT32 EntryCount;
|
|
UINT64 EntryPtr;
|
|
UINTN BasePtr;
|
|
EFI_ACPI_DESCRIPTION_HEADER *Table;
|
|
|
|
if (Xsdt == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
EntryCount = (Xsdt->Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof (UINT64);
|
|
|
|
BasePtr = (UINTN)(Xsdt + 1);
|
|
for (Index = 0; Index < EntryCount; Index ++) {
|
|
CopyMem (&EntryPtr, (VOID *) (BasePtr + Index * sizeof (UINT64)), sizeof (UINT64));
|
|
Table = (EFI_ACPI_DESCRIPTION_HEADER *) ((UINTN) (EntryPtr));
|
|
if (Table->Signature == Signature) {
|
|
return Table;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
|
|
This function scan PHAT table which was created in READY_TO_BOOT, and update it when EXIT_BOOT_SERVICES
|
|
Even is triggered.
|
|
|
|
@param[in] AcpiPhatTablePointer A pointer to the EFI_ACPI_DESCRIPTION_HEADER instance.
|
|
@param[in] AcpiBasicBootPerformancePointer A pointer to the BOOT_PERFORMANCE_TABLE instance.
|
|
@param[in] TelemetryVariable A pointer to the PLATFORM_TELEMETRY_VARIABLE instance.
|
|
**/
|
|
VOID
|
|
SearchAndUpdatePhatTable (
|
|
IN EFI_ACPI_DESCRIPTION_HEADER *AcpiPhatTablePointer,
|
|
IN BOOT_PERFORMANCE_TABLE *AcpiBasicBootPerformancePointer,
|
|
IN MOTHER_BOARD_HEALTH_VARIABLE *TelemetryVariable
|
|
)
|
|
{
|
|
UINT8 *PhatPointer;
|
|
EFI_ACPI_PLATFORM_TELEMETRY_RECORD_HEADER *TelemetryRecordHeader;
|
|
UINT8 *HealthRecord;
|
|
UINTN TotalRecordLength;
|
|
UINTN TelemetryDataLength;
|
|
EFI_ACPI_TELEMETRY_HEALTH_DATA_RECORD_STRUCTURE *MBRecordHead;
|
|
EFI_ACPI_MOTHERBOARD_HEALTH_DATA *MBRecordData;
|
|
|
|
TotalRecordLength = 0;
|
|
HealthRecord = NULL;
|
|
MBRecordHead = NULL;
|
|
MBRecordData = NULL;
|
|
if (AcpiPhatTablePointer->Length > sizeof (EFI_ACPI_DESCRIPTION_HEADER)) {
|
|
TelemetryDataLength = AcpiPhatTablePointer->Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER);
|
|
} else {
|
|
DEBUG ((EFI_D_ERROR, "PHAT table is not existed or corrupted \n"));
|
|
return;
|
|
}
|
|
//
|
|
// PHAT entry.
|
|
//
|
|
PhatPointer = (UINT8 *) AcpiPhatTablePointer + sizeof (EFI_ACPI_DESCRIPTION_HEADER);
|
|
for (TotalRecordLength = 0; TotalRecordLength < TelemetryDataLength - sizeof (EFI_ACPI_PLATFORM_TELEMETRY_RECORD_HEADER); ) {
|
|
TelemetryRecordHeader = (EFI_ACPI_PLATFORM_TELEMETRY_RECORD_HEADER *) PhatPointer;
|
|
if (TelemetryRecordHeader->RecordType == FirmwareHealthDataRecord
|
|
&& (TelemetryRecordHeader->RecordLength > sizeof (EFI_ACPI_PLATFORM_TELEMETRY_RECORD_HEADER))) {
|
|
//
|
|
// found driver health records
|
|
//
|
|
HealthRecord = (UINT8 *) TelemetryRecordHeader;
|
|
MBRecordHead = (EFI_ACPI_TELEMETRY_HEALTH_DATA_RECORD_STRUCTURE *) HealthRecord;
|
|
if (CompareGuid (&MBRecordHead->DeviceSignature, &gAdapterInfoMotherBoardHealthGuid)) {
|
|
MBRecordData = (EFI_ACPI_MOTHERBOARD_HEALTH_DATA *)(HealthRecord + MBRecordHead->DeviceSpecificDataOffset);
|
|
MBRecordData->MeanBootTime = TelemetryVariable->MeanBootTime;
|
|
MBRecordData->CurrentBootTime = AcpiBasicBootPerformancePointer->BasicBoot.OsLoaderStartImageStart;
|
|
MBRecordData->NumberOfBootsSinceUpdate = TelemetryVariable->NumberOfBootsSinceUpdate;
|
|
//
|
|
// Current Boot time over 50%(default) means NotHealth
|
|
//
|
|
if (PcdGet8 (PcdBootTimeOverPercentage) != 0) {
|
|
if ((DivU64x32 (MAX_UINT64, (UINT32) PcdGet8 (PcdBootTimeOverPercentage)) < TelemetryVariable->MeanBootTime)) {
|
|
DEBUG((EFI_D_ERROR, "MeanBootTime Overflow, Return Unhealthy.\n"));
|
|
((EFI_ACPI_TELEMETRY_HEALTH_DATA_RECORD_STRUCTURE *) TelemetryRecordHeader)->AmHealthy = TelemetryUnhealthy;
|
|
} else if (AcpiBasicBootPerformancePointer->BasicBoot.OsLoaderStartImageStart >
|
|
(TelemetryVariable->MeanBootTime + DivU64x32 (MultU64x32 (TelemetryVariable->MeanBootTime, (UINT32) PcdGet8 (PcdBootTimeOverPercentage)), 100))) {
|
|
((EFI_ACPI_TELEMETRY_HEALTH_DATA_RECORD_STRUCTURE *) TelemetryRecordHeader)->AmHealthy = TelemetryUnhealthy;
|
|
}
|
|
} else {
|
|
if (AcpiBasicBootPerformancePointer->BasicBoot.OsLoaderStartImageStart > TelemetryVariable->MeanBootTime) {
|
|
((EFI_ACPI_TELEMETRY_HEALTH_DATA_RECORD_STRUCTURE *) TelemetryRecordHeader)->AmHealthy = TelemetryUnhealthy;
|
|
}
|
|
}
|
|
|
|
AcpiPlatformChecksum (
|
|
(UINT8 *) AcpiPhatTablePointer,
|
|
AcpiPhatTablePointer->Length
|
|
);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (TelemetryRecordHeader->RecordLength > sizeof (EFI_ACPI_PLATFORM_TELEMETRY_RECORD_HEADER)) {
|
|
PhatPointer += TelemetryRecordHeader->RecordLength;
|
|
//
|
|
// check record border.
|
|
//
|
|
TotalRecordLength += TelemetryRecordHeader->RecordLength;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
Update the final record to Mother board variable.
|
|
|
|
@attention This function may receive untrusted input.
|
|
Data and AcpiBasicBootPerformancePointer is external input, so this function will validate its data structure within this buffer before use.
|
|
|
|
@param[in] Data The contents for the variable.
|
|
@param[in] AcpiBasicBootPerformancePointer This structure contains BasicBoot performance record.
|
|
|
|
@retval EFI_SUCCESS The firmware has successfully stored the variable and its data as
|
|
defined by the Attributes.
|
|
@retval EFI_INVALID_PARAMETER The input was NULL or calculating the result overflow of MeanBootTime.
|
|
**/
|
|
EFI_STATUS
|
|
SetMotherBoardVariable (
|
|
IN VOID *Data,
|
|
IN BOOT_PERFORMANCE_TABLE *AcpiBasicBootPerformancePointer
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
MOTHER_BOARD_HEALTH_VARIABLE *TelemetryVariable;
|
|
|
|
if ((Data == NULL) || (AcpiBasicBootPerformancePointer == NULL)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
TelemetryVariable = (MOTHER_BOARD_HEALTH_VARIABLE *) Data;
|
|
if (TelemetryVariable->NumberOfBootsSinceUpdate != 0) {
|
|
//
|
|
// Multiplication overflow check.
|
|
//
|
|
if (DivU64x32 (MAX_UINT64,(UINT32) TelemetryVariable->NumberOfBootsSinceUpdate) > TelemetryVariable->MeanBootTime ) {
|
|
//
|
|
// Addition overflow check.
|
|
//
|
|
if ((MAX_UINT64 - AcpiBasicBootPerformancePointer->BasicBoot.OsLoaderStartImageStart) <
|
|
(TelemetryVariable->MeanBootTime * TelemetryVariable->NumberOfBootsSinceUpdate)) {
|
|
DEBUG((EFI_D_ERROR, "Addition MeanBootTime Overflow.\n"));
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
} else {
|
|
DEBUG((EFI_D_ERROR, "Multiplication MeanBootTime Overflow.\n"));
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
//
|
|
// Search driver health from Acpi table and update them.
|
|
//
|
|
TelemetryVariable->MeanBootTime = DivU64x32 (TelemetryVariable->MeanBootTime * TelemetryVariable->NumberOfBootsSinceUpdate
|
|
+ AcpiBasicBootPerformancePointer->BasicBoot.OsLoaderStartImageStart,
|
|
(UINT32)(TelemetryVariable->NumberOfBootsSinceUpdate + 1));
|
|
TelemetryVariable->NumberOfBootsSinceUpdate += 1;
|
|
|
|
Status = gRT->SetVariable (
|
|
MOTHERBOARD_HEALTH_DATA_NAME,
|
|
&gMotherBoardHealthVariableGuid,
|
|
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
|
|
sizeof (MOTHER_BOARD_HEALTH_VARIABLE),
|
|
TelemetryVariable
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((EFI_D_ERROR, "Failed to set the MOTHERBOARD_HEALTH_DATA_NAME record into a variable. Status = %r\n", Status));
|
|
return Status;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
/**
|
|
Report status code listener of PHAT. This is used to collect performance data
|
|
for OsLoaderStartImageStart in PHAT.
|
|
|
|
@param[in] CodeType Indicates the type of status code being reported.
|
|
@param[in] Value Describes the current status of a hardware or software entity.
|
|
This included information about the class and subclass that is used to
|
|
classify the entity as well as an operation.
|
|
@param[in] Instance The enumeration of a hardware or software entity within
|
|
the system. Valid instance numbers start with 1.
|
|
@param[in] CallerId This optional parameter may be used to identify the caller.
|
|
This parameter allows the status code driver to apply different rules to
|
|
different callers.
|
|
@param[in] Data This optional parameter may be used to pass additional data.
|
|
|
|
@retval EFI_SUCCESS Status code is what we expected.
|
|
@retval EFI_UNSUPPORTED Status code not supported.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
PhatStatusCodeListenerDxe (
|
|
IN EFI_STATUS_CODE_TYPE CodeType,
|
|
IN EFI_STATUS_CODE_VALUE Value,
|
|
IN UINT32 Instance,
|
|
IN EFI_GUID *CallerId,
|
|
IN EFI_STATUS_CODE_DATA *Data
|
|
)
|
|
{
|
|
EFI_ACPI_DESCRIPTION_HEADER *AcpiEntry;
|
|
EFI_ACPI_DESCRIPTION_HEADER *AcpiPhatTablePointer;
|
|
FIRMWARE_PERFORMANCE_TABLE *AcpiFpdtTablePointer;
|
|
BOOT_PERFORMANCE_TABLE *AcpiBasicBootPerformancePointer;
|
|
EFI_STATUS Status;
|
|
MOTHER_BOARD_HEALTH_VARIABLE TelemetryVariable;
|
|
UINTN TelemetryBufferSize;
|
|
|
|
AcpiEntry = NULL;
|
|
AcpiPhatTablePointer = NULL;
|
|
AcpiFpdtTablePointer = NULL;
|
|
AcpiBasicBootPerformancePointer = NULL;
|
|
TelemetryBufferSize = 0;
|
|
|
|
//
|
|
// Check whether status code is what we are interested in.
|
|
//
|
|
if ((CodeType & EFI_STATUS_CODE_TYPE_MASK) != EFI_PROGRESS_CODE) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
ZeroMem (&TelemetryVariable, sizeof (MOTHER_BOARD_HEALTH_VARIABLE));
|
|
Status = EFI_SUCCESS;
|
|
if (Value == PcdGet32 (PcdProgressCodeOsLoaderLoad)) {
|
|
//
|
|
// Progress code for OS Loader LoadImage.
|
|
//
|
|
if (AcpiPhatTablePointer == NULL) {
|
|
return Status;
|
|
}
|
|
|
|
} else if (Value == (EFI_SOFTWARE_EFI_BOOT_SERVICE | EFI_SW_BS_PC_EXIT_BOOT_SERVICES)) {
|
|
AcpiEntry = SearchAcpiTablePointer ();
|
|
AcpiPhatTablePointer = ScanTableInXSDT (AcpiEntry, EFI_ACPI_PLATFORM_HEALTH_ASSESSMENT_TABLE_SIGNATURE);
|
|
if (AcpiPhatTablePointer == NULL) {
|
|
goto Done;
|
|
}
|
|
//
|
|
// Update OS Loader StartImage Start for UEFI boot.
|
|
//
|
|
AcpiFpdtTablePointer = ScanTableInXSDT (AcpiEntry, EFI_ACPI_6_1_FIRMWARE_PERFORMANCE_DATA_TABLE_SIGNATURE);
|
|
if (AcpiFpdtTablePointer == NULL) {
|
|
goto Done;
|
|
}
|
|
AcpiBasicBootPerformancePointer = (BOOT_PERFORMANCE_TABLE *) (UINTN)AcpiFpdtTablePointer->BootPointerRecord.BootPerformanceTablePointer;
|
|
|
|
TelemetryBufferSize = sizeof (MOTHER_BOARD_HEALTH_VARIABLE);
|
|
Status = gRT->GetVariable (
|
|
MOTHERBOARD_HEALTH_DATA_NAME,
|
|
&gMotherBoardHealthVariableGuid,
|
|
NULL,
|
|
&TelemetryBufferSize,
|
|
&TelemetryVariable
|
|
);
|
|
if (Status != EFI_SUCCESS) {
|
|
DEBUG ((EFI_D_ERROR, "Failed to get the MotherBoardHealth variable Status = %r\n", Status));
|
|
goto Done;
|
|
}
|
|
//
|
|
// Update the final record to Mother board variable.
|
|
//
|
|
Status = SetMotherBoardVariable (&TelemetryVariable, AcpiBasicBootPerformancePointer);
|
|
if (Status != EFI_SUCCESS) {
|
|
DEBUG ((EFI_D_ERROR, "Failed to set the MotherBoardHealth record into a variable. Status = %r\n", Status));
|
|
goto Done;
|
|
}
|
|
//
|
|
// Update the final record to PHAT table
|
|
//
|
|
SearchAndUpdatePhatTable (AcpiPhatTablePointer, AcpiBasicBootPerformancePointer, &TelemetryVariable);
|
|
Done:
|
|
//
|
|
// Set HwErrRec variable.
|
|
//
|
|
Status = SetDriverHealthHwErrRecVariable (AcpiPhatTablePointer);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((EFI_D_ERROR, "Failed to set the Health record into a HwErrRec#### variable. Status = %r\n", Status));
|
|
}
|
|
|
|
//
|
|
// Unregister boot time report status code listener.
|
|
//
|
|
mRscHandlerProtocol->Unregister (PhatStatusCodeListenerDxe);
|
|
|
|
} else {
|
|
//
|
|
// Ignore else progress code.
|
|
//
|
|
Status = EFI_UNSUPPORTED;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Convert Telemetry Aip data to Telemetry ACPI data.
|
|
|
|
@param[in] AipRecord A pointer to the FVI record buffer,does not contain header information.
|
|
May be NULL in order to determine the size buffer needed.
|
|
@param[out] AcpiAipRecord A pointer to the FVI record buffer.
|
|
@param[in] LengthOfFVI A pointer to the Length of FVI record.
|
|
|
|
@retval EFI_SUCCESS The function completed successfully.
|
|
@retval EFI_INVALID_PARAMETER LengthOfFVI is NULL.
|
|
@retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the results.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
ConvertFVIDataFromAipToAcpi (
|
|
IN UINT8 *AipRecord,
|
|
OUT UINT8 **AcpiAipRecord,
|
|
IN UINT16 *LengthOfFVI
|
|
)
|
|
{
|
|
if ((LengthOfFVI == NULL) || (AcpiAipRecord == NULL)) {
|
|
DEBUG ((EFI_D_ERROR, "ConvertFVIDataFromAipToAcpi : Invalid Parameter.\n"));
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
*AcpiAipRecord = NULL;
|
|
|
|
if (AipRecord == NULL) {
|
|
DEBUG ((EFI_D_INFO, "Get length of FVI successfully and then return.\n"));
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
*AcpiAipRecord = AllocateZeroPool (*LengthOfFVI);
|
|
if (*AcpiAipRecord == NULL) {
|
|
DEBUG ((EFI_D_ERROR, "EFI_OUT_OF_RESOURCES : AcpiAipBuffHead allocate failed.\n"));
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
CopyMem (*AcpiAipRecord, AipRecord, *LengthOfFVI);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Get Aip data from Hobs, these records won't be updated in DXE phase.
|
|
|
|
@param[in, out] InformationBlock A pointer to the InformationBlock structure which contains details.
|
|
May be NULL in order to determine the size buffer needed.
|
|
@param[out] InformationBlockSize The size of the InformationBlock in bytes.
|
|
**/
|
|
VOID
|
|
GetAipHobRecords (
|
|
IN OUT UINT8 **InformationBlock,
|
|
OUT UINT16 *InformationBlockSize
|
|
)
|
|
{
|
|
EFI_PEI_HOB_POINTERS Hob;
|
|
UINT8 *RecordPtr;
|
|
UINT8 *FviRecord;
|
|
UINT8 *AcpiAipRecord;
|
|
UINT16 RecordSize;
|
|
UINT8 HobHeadLength;
|
|
UINT8 *HobBuffTemp;
|
|
TELEMETRY_FIRMWARE_VERSION_INFO2_HOB *FviHob;
|
|
EFI_STATUS Status;
|
|
|
|
FviHob = NULL;
|
|
HobBuffTemp = NULL;
|
|
AcpiAipRecord = NULL;
|
|
HobHeadLength = OFFSET_OF (TELEMETRY_FIRMWARE_VERSION_INFO2_HOB, Records);
|
|
|
|
if (InformationBlockSize == NULL) {
|
|
DEBUG ((EFI_D_ERROR, "GetAipHobRecords : Invalid Parameter.\n"));
|
|
return;
|
|
}
|
|
*InformationBlockSize = 0;
|
|
if (InformationBlock != NULL){
|
|
HobBuffTemp = *InformationBlock;
|
|
}
|
|
|
|
//
|
|
// Get FVI HOB
|
|
//
|
|
for (Hob.Raw = GetHobList (); !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
|
|
if ((GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_GUID_EXTENSION) && (CompareGuid (&Hob.Guid->Name, &gTelemetryVersionHobGuid))) {
|
|
FviHob = (TELEMETRY_FIRMWARE_VERSION_INFO2_HOB *) GET_GUID_HOB_DATA (Hob.Raw);
|
|
|
|
RecordPtr = (UINT8 *) FviHob->Records;
|
|
if (FviHob->Header.HobLength > HobHeadLength) {
|
|
RecordSize = FviHob->Header.HobLength - HobHeadLength;
|
|
//
|
|
// Convert Telemetry Aip data to Telemetry ACPI data or get Length of FVI.
|
|
//
|
|
if (InformationBlock != NULL) {
|
|
//
|
|
// Record need 16-bit alignment in ConvertFVIDataFromAipToAcpi process.
|
|
//
|
|
FviRecord = AllocatePool (RecordSize * sizeof(UINT8));
|
|
if (FviRecord == NULL) {
|
|
DEBUG ((EFI_D_ERROR, "EFI_OUT_OF_RESOURCES : AcpiAipBuffHead allocate failed.\n"));
|
|
*InformationBlockSize = 0;
|
|
return;
|
|
}
|
|
CopyMem (FviRecord, RecordPtr, RecordSize);
|
|
|
|
Status = ConvertFVIDataFromAipToAcpi (FviRecord, &AcpiAipRecord, &RecordSize);
|
|
if (Status == EFI_OUT_OF_RESOURCES) {
|
|
DEBUG ((EFI_D_ERROR, "Failed to process ConvertFVIDataFromAipToAcpi due to lack of resources!\n"));
|
|
FreePool (FviRecord);
|
|
*InformationBlockSize = 0;
|
|
return;
|
|
}
|
|
FreePool (FviRecord);
|
|
}
|
|
} else {
|
|
continue;
|
|
}
|
|
if (InformationBlock != NULL) {
|
|
CopyMem (HobBuffTemp, AcpiAipRecord, RecordSize);
|
|
HobBuffTemp += RecordSize;
|
|
FreePool (AcpiAipRecord);
|
|
}
|
|
|
|
*InformationBlockSize += (UINT16) RecordSize;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
Get FVI Aip data from Protocols.
|
|
|
|
@param[in, out] TempAipBuffHeader A pointer to the buffer which follows up with hob record.
|
|
May be NULL in order to determine the size buffer needed.
|
|
@param[in, out] TotalLength The size of telemetry Aip data in bytes.
|
|
|
|
@retval EFI_SUCCESS The function completed successfully.
|
|
@retval EFI_INVALID_PARAMETER HandleBuffer is NULL.
|
|
@retval EFI_INVALID_PARAMETER Aip is NULL.
|
|
@retval EFI_UNSUPPORTED The InformationType is not known.
|
|
@retval EFI_DEVICE_ERROR The device reported an error.
|
|
@retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the results.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
CollectAipInfoFromProtocol (
|
|
IN OUT UINT8 **TempAipBuffHeader,
|
|
IN OUT UINT16 *TotalLength
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_ADAPTER_INFORMATION_PROTOCOL *Aip;
|
|
UINTN HandleCount;
|
|
EFI_HANDLE *HandleBuffer;
|
|
EFI_GUID *InfoTypesBuffer;
|
|
UINTN InfoTypeBufferCount;
|
|
UINTN TypeIndex;
|
|
BOOLEAN Supported;
|
|
VOID *DataBlock;
|
|
UINTN BufferSize;
|
|
UINT8 *FviRecordHeader;
|
|
UINTN Index;
|
|
UINT8 *AcpiAipRecord;
|
|
UINT16 AcpiFviSize;
|
|
|
|
FviRecordHeader = NULL;
|
|
DataBlock = NULL;
|
|
AcpiAipRecord = NULL;
|
|
BufferSize = 0;
|
|
AcpiFviSize = 0;
|
|
if (TotalLength == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
*TotalLength = 0;
|
|
|
|
Status = gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiAdapterInformationProtocolGuid,
|
|
NULL,
|
|
&HandleCount,
|
|
&HandleBuffer
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((EFI_D_ERROR, "gEfiAdapterInformationProtocolGuid locate failed, status = [%x] \n", Status));
|
|
//
|
|
// gEfiAdapterInformationProtocolGuid protocol not installed yet.
|
|
//
|
|
return Status;
|
|
}
|
|
|
|
for (Index = 0; Index < HandleCount ; Index++) {
|
|
Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiAdapterInformationProtocolGuid, (VOID **) &Aip);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((EFI_D_ERROR, "HandleProtocol gEfiAdapterInformationProtocolGuid failed. \n"));
|
|
} else {
|
|
InfoTypesBuffer = NULL;
|
|
InfoTypeBufferCount = 0;
|
|
//
|
|
// Check AIP
|
|
//
|
|
Status = Aip->GetSupportedTypes (Aip, &InfoTypesBuffer, &InfoTypeBufferCount);
|
|
if (EFI_ERROR (Status) || InfoTypesBuffer == NULL) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Check whether the AIP instance has FVI information block.
|
|
//
|
|
Supported = FALSE;
|
|
for (TypeIndex = 0; TypeIndex < InfoTypeBufferCount; TypeIndex++) {
|
|
if (CompareGuid (&InfoTypesBuffer[TypeIndex], &gTelemetryVersionRecord2Guid)) {
|
|
Supported = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
FreePool (InfoTypesBuffer);
|
|
if (!Supported) {
|
|
continue;
|
|
}
|
|
|
|
Status = Aip->GetInformation (Aip, &gTelemetryVersionRecord2Guid, &DataBlock, &BufferSize);
|
|
if (EFI_ERROR (Status) || DataBlock == NULL || BufferSize == 0) {
|
|
continue;
|
|
} else {
|
|
//
|
|
// skip Revision & RecordCount in EFI_AIP_TELEMETRY_VERSION_RECORD, find the valid
|
|
//
|
|
FviRecordHeader = (UINT8 *) ((EFI_AIP_TELEMETRY_VERSION_RECORD *) DataBlock)->Record;
|
|
}
|
|
//
|
|
// kick Revision & RecordCount out.
|
|
//
|
|
if (BufferSize > OFFSET_OF (EFI_AIP_TELEMETRY_VERSION_RECORD, Record)) {
|
|
AcpiFviSize = AcpiFviRecordSize * (UINT16 ) (((EFI_AIP_TELEMETRY_VERSION_RECORD *) DataBlock)->RecordCount);
|
|
DEBUG ((EFI_D_INFO, "AcpiFviSize = %d\n", AcpiFviSize));
|
|
if (TempAipBuffHeader != NULL) {
|
|
//
|
|
// Convert Telemetry Aip data to Telemetry ACPI data.
|
|
//
|
|
Status = ConvertFVIDataFromAipToAcpi (FviRecordHeader, &AcpiAipRecord, &AcpiFviSize);
|
|
if (Status == EFI_OUT_OF_RESOURCES) {
|
|
DEBUG ((EFI_D_ERROR, "Failed to process ConvertFVIDataFromAipToAcpi due to lack of resources!\n"));
|
|
FreePool (DataBlock);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
}
|
|
if ((MAX_UINT16 - *TotalLength) < AcpiFviSize) {
|
|
DEBUG ((EFI_D_ERROR, "TotalLength is Greater than 4G,abandon this FVI record.\n"));
|
|
FreePool (DataBlock);
|
|
if (AcpiAipRecord != NULL) {
|
|
FreePool (AcpiAipRecord);
|
|
}
|
|
continue;
|
|
}
|
|
if (TempAipBuffHeader != NULL) {
|
|
CopyMem (*TempAipBuffHeader, AcpiAipRecord, AcpiFviSize);
|
|
*TempAipBuffHeader += AcpiFviSize;
|
|
FreePool (AcpiAipRecord);
|
|
}
|
|
*TotalLength += (UINT16) AcpiFviSize;
|
|
}
|
|
FreePool (DataBlock);
|
|
}
|
|
}
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Get Aip data from Health drivers listed in mDriverHealthSupportList.
|
|
|
|
@param[out] AcpiAipBuffHead A pointer to the buffer which follows up with FVI record.
|
|
May be NULL in order to determine the size buffer needed.
|
|
@param[out] LengthOfDriverHealth The size of telemetry Aip driver health
|
|
data in bytes.
|
|
|
|
**/
|
|
VOID
|
|
CollectAipInfoFromHealthDriver (
|
|
IN OUT UINT8 **AcpiAipBuffHead,
|
|
OUT UINT32 *LengthOfDriverHealth
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN Index;
|
|
UINT8 *DriverHealthData;
|
|
UINTN DriverHealthSize;
|
|
UINT8 *MotherBoardTemp;
|
|
UINTN MotherBoardTempSize;
|
|
UINT8 *MotherBoardFinal;
|
|
UINTN MotherBoardFinalSize;
|
|
|
|
DriverHealthData = NULL;
|
|
DriverHealthSize = 0;
|
|
MotherBoardTemp = NULL;
|
|
MotherBoardTempSize = 0;
|
|
MotherBoardFinal = NULL;
|
|
MotherBoardFinalSize = 0;
|
|
|
|
if (LengthOfDriverHealth == NULL) {
|
|
DEBUG ((EFI_D_ERROR, "CollectAipInfoFromHealthDriver : Invalid Parameter.\n"));
|
|
return;
|
|
}
|
|
*LengthOfDriverHealth = 0;
|
|
|
|
for (Index = 0; mDriverHealthSupportList[Index] != NULL; Index++ ) {
|
|
Status = DriverHealthAipDataCollection (mDriverHealthSupportList[Index], &DriverHealthData, &DriverHealthSize);
|
|
//
|
|
// Integrate all driver health records
|
|
//
|
|
if (!EFI_ERROR (Status) && (DriverHealthSize > sizeof (EFI_ACPI_TELEMETRY_HEALTH_DATA_RECORD_STRUCTURE))) {
|
|
|
|
if (CompareGuid (mDriverHealthSupportList[Index], &gAdapterInfoMotherBoardHealthGuid)) {
|
|
DEBUG ((EFI_D_INFO, "One Mother Board record is matched! \n"));
|
|
Status = AttachAllFmpInfoToEnd (&MotherBoardTemp, &MotherBoardTempSize);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((EFI_D_INFO, "Get Mother Board Health special Info failed .....! \n", Status));
|
|
} else {
|
|
//
|
|
// combine MotherBoardTemp(with 1 instance by default) and More (from Fmp protocol).
|
|
//
|
|
MotherBoardFinalSize = DriverHealthSize + MotherBoardTempSize - sizeof (EFI_LAST_UPDATE_DATA);
|
|
((EFI_ACPI_PLATFORM_TELEMETRY_RECORD_HEADER *) DriverHealthData)->RecordLength = (UINT16) MotherBoardFinalSize;
|
|
if ((DriverHealthSize > sizeof (EFI_LAST_UPDATE_DATA)) && (MotherBoardTempSize > 0)) {
|
|
|
|
MotherBoardFinal = AllocateZeroPool (MotherBoardFinalSize);
|
|
if (MotherBoardFinal == NULL) {
|
|
DEBUG ((EFI_D_ERROR, "MotherBoardFinal allocate failed, LastUpdateTime can't be updated! \n"));
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Override the default LastUpdateTime and EsrtID
|
|
//
|
|
CopyMem (MotherBoardFinal, DriverHealthData, DriverHealthSize);
|
|
|
|
CopyMem (MotherBoardFinal + DriverHealthSize - sizeof (EFI_LAST_UPDATE_DATA), MotherBoardTemp, MotherBoardTempSize);
|
|
if (AcpiAipBuffHead != NULL) {
|
|
//
|
|
// To attach integrated mother board info to the end of record.
|
|
//
|
|
CopyMem (*AcpiAipBuffHead, MotherBoardFinal, MotherBoardFinalSize);
|
|
}
|
|
DriverHealthSize = MotherBoardFinalSize;
|
|
} else {
|
|
DEBUG ((EFI_D_INFO, "Mother Board Health record is corrupted or its length is 0, drop it!! \n"));
|
|
}
|
|
|
|
}
|
|
|
|
if (MotherBoardTemp != NULL) {
|
|
FreePool (MotherBoardTemp);
|
|
}
|
|
|
|
if (MotherBoardFinal != NULL) {
|
|
FreePool (MotherBoardFinal);
|
|
}
|
|
|
|
} else {
|
|
if ((MAX_UINT32 - *LengthOfDriverHealth) < DriverHealthSize) {
|
|
DEBUG ((EFI_D_ERROR, "LengthOfDriverHealth is Greater than 4G,abandon this driverHealth record.\n"));
|
|
if (DriverHealthData != NULL) {
|
|
FreePool (DriverHealthData);
|
|
}
|
|
continue;
|
|
}
|
|
if (AcpiAipBuffHead != NULL) {
|
|
//
|
|
// To handle other driver health record
|
|
//
|
|
CopyMem (*AcpiAipBuffHead, DriverHealthData, DriverHealthSize);
|
|
}
|
|
}
|
|
if (AcpiAipBuffHead != NULL) {
|
|
*AcpiAipBuffHead = *AcpiAipBuffHead + DriverHealthSize;
|
|
}
|
|
*LengthOfDriverHealth = *LengthOfDriverHealth + (UINT32) DriverHealthSize;
|
|
DEBUG ((EFI_D_INFO, "Driver Health -- [%g] has been converted successfully \n", *mDriverHealthSupportList[Index]));
|
|
}
|
|
if (DriverHealthData != NULL) {
|
|
FreePool (DriverHealthData);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
Initialize the header of the Platform Health Assessment Table.
|
|
|
|
@param[out] Header The header of the ACPI Table.
|
|
@param[in] OemId The OEM ID.
|
|
@param[in] OemTableId The OEM table ID for the Phat.
|
|
**/
|
|
VOID
|
|
InitPhatAcpiTableHeader (
|
|
OUT EFI_ACPI_DESCRIPTION_HEADER *Header,
|
|
IN UINT8 *OemId,
|
|
IN UINT64 *OemTableId
|
|
)
|
|
{
|
|
ZeroMem (Header, sizeof (EFI_ACPI_DESCRIPTION_HEADER));
|
|
|
|
Header->Signature = EFI_ACPI_PLATFORM_HEALTH_ASSESSMENT_TABLE_SIGNATURE;
|
|
//
|
|
// tatal length (FVI, Driver Health).
|
|
//
|
|
Header->Length = 0;
|
|
|
|
Header->Revision = EFI_ACPI_PLATFORM_HEALTH_ASSESSMENT_TABLE_VERSION;
|
|
Header->Checksum = 0;
|
|
CopyMem (Header->OemId, OemId, sizeof (Header->OemId));
|
|
CopyMem (&Header->OemTableId, OemTableId, sizeof (UINT64));
|
|
Header->OemRevision = EFI_ACPI_OEM_REVISION;
|
|
Header->CreatorId = EFI_ACPI_CREATOR_ID;
|
|
Header->CreatorRevision = EFI_ACPI_CREATOR_REVISION;
|
|
}
|
|
|
|
/**
|
|
Initialize the Platform Health Assessment Table.
|
|
Convert AIP data block to telementry ACPI style, and publish it.
|
|
|
|
@param[in] InfoBlock Point to AIP data block.
|
|
@param[in] InfoBlockSize The size of AIP data.
|
|
|
|
@retval EFI_SUCCESS Success
|
|
@retval EFI_OUT_OF_RESOURCES Status code not supported.
|
|
@retval EFI_INVALID_PARAMETER Either AcpiTableBuffer is NULL,
|
|
TableKey is NULL, or
|
|
AcpiTableBufferSize and the size
|
|
field embedded in the ACPI table
|
|
pointed to by AcpiTableBuffer
|
|
are not in sync.
|
|
@retval EFI_ACCESS_DENIED The table signature matches a table already
|
|
present in the system and platform policy
|
|
does not allow duplicate tables of this type.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
InstallAcpiTelemetryTable (
|
|
VOID *InfoBlock,
|
|
UINTN InfoBlockSize
|
|
)
|
|
{
|
|
EFI_ACPI_DESCRIPTION_HEADER *AcpiEntry;
|
|
UINT8 *Table;
|
|
EFI_ACPI_DESCRIPTION_HEADER AcpiHead;
|
|
EFI_STATUS Status;
|
|
|
|
if (mPhatInstalled) {
|
|
Status = mAcpiTableProtocol->UninstallAcpiTable (
|
|
mAcpiTableProtocol,
|
|
mTableKey
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
mPhatInstalled = FALSE;
|
|
}
|
|
|
|
AcpiEntry = SearchAcpiTablePointer ();
|
|
ZeroMem (&AcpiHead, sizeof (EFI_ACPI_DESCRIPTION_HEADER));
|
|
//
|
|
// Initialize the header of the Platform Health Assessment Table.
|
|
//
|
|
InitPhatAcpiTableHeader (&AcpiHead, AcpiEntry->OemId, &AcpiEntry->OemTableId);
|
|
|
|
//
|
|
// Allocate resource to hold the ACPI table.
|
|
//
|
|
Table = AllocateZeroPool (InfoBlockSize + sizeof (EFI_ACPI_DESCRIPTION_HEADER));
|
|
if (Table == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
AcpiHead.Length = sizeof (EFI_ACPI_DESCRIPTION_HEADER) + (UINT32)InfoBlockSize;
|
|
CopyMem (Table, &AcpiHead, sizeof (EFI_ACPI_DESCRIPTION_HEADER));
|
|
//
|
|
// Connect a telemetry data to ACPI table header.
|
|
//
|
|
CopyMem (Table + sizeof (EFI_ACPI_DESCRIPTION_HEADER), InfoBlock, InfoBlockSize);
|
|
|
|
AcpiPlatformChecksum (
|
|
(UINT8 *) Table,
|
|
((EFI_ACPI_DESCRIPTION_HEADER *)Table)->Length
|
|
);
|
|
//
|
|
// Install or update the Phat table.
|
|
//
|
|
Status = mAcpiTableProtocol->InstallAcpiTable (
|
|
mAcpiTableProtocol,
|
|
Table,
|
|
AcpiHead.Length,
|
|
&mTableKey
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((EFI_D_INFO, "Install Phat AcpiTable failed, Status = [%x]. \n", Status));
|
|
} else {
|
|
DEBUG ((EFI_D_INFO, "Install Phat AcpiTable successfull. \n"));
|
|
mPhatInstalled = TRUE;
|
|
}
|
|
|
|
if (Table != NULL) {
|
|
FreePool (Table);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Get length of telemetry from hob and aip.
|
|
|
|
@param LengthOfFVI Pointer to the length of FVI.
|
|
@param LengthOfDriverHealth Pointer to total length of telemetry Driver Health data.
|
|
|
|
@retval EFI_SUCCESS Get total length successful.
|
|
@retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the results.
|
|
@retval EFI_INVALID_PARAMETER LengthOfFVI and LengthOfDriverHealth is NULL.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
GetLengthOfTelemetryData (
|
|
IN OUT UINT16 *LengthOfFVI,
|
|
IN OUT UINT32 *LengthOfDriverHealth
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT16 HobLength;
|
|
|
|
HobLength = 0;
|
|
Status = EFI_SUCCESS;
|
|
|
|
if ((LengthOfFVI == NULL) && (LengthOfDriverHealth == NULL)) {
|
|
DEBUG ((EFI_D_ERROR, "GetLengthOfTelemetryData : Invalid Parameter.\n"));
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (LengthOfFVI != NULL) {
|
|
*LengthOfFVI = 0;
|
|
//
|
|
// Get FVI length from Aip Hob.
|
|
//
|
|
GetAipHobRecords (NULL, &HobLength);
|
|
//
|
|
// Get FVI length from Aip Protocol.
|
|
//
|
|
Status = CollectAipInfoFromProtocol (NULL, LengthOfFVI);
|
|
if (Status == EFI_OUT_OF_RESOURCES) {
|
|
DEBUG ((EFI_D_ERROR, "Failed to process CollectAipInfoFromProtocol due to lack of resources!\n"));
|
|
return Status;
|
|
}
|
|
if ((MAX_UINT16 - *LengthOfFVI) < (HobLength + AcpiComPonentHeadSize)) {
|
|
DEBUG ((EFI_D_ERROR, "LengthOfFVI is Greater than 4G,set the value of LengthOfFVI to zero.\n"));
|
|
*LengthOfFVI = AcpiComPonentHeadSize;
|
|
} else {
|
|
*LengthOfFVI += HobLength;
|
|
*LengthOfFVI += AcpiComPonentHeadSize;
|
|
}
|
|
}
|
|
|
|
if (LengthOfDriverHealth != NULL) {
|
|
*LengthOfDriverHealth = 0;
|
|
//
|
|
// Get Driver health length form aip protocol.
|
|
//
|
|
CollectAipInfoFromHealthDriver (NULL, LengthOfDriverHealth);
|
|
|
|
if (LengthOfFVI != NULL) {
|
|
if ((MAX_UINT32 - *LengthOfFVI) < *LengthOfDriverHealth) {
|
|
DEBUG ((EFI_D_ERROR, "TotalLength is Greater than UINT16,set the value of LengthOfDriverHealth to zero.\n"));
|
|
LengthOfDriverHealth = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Collect AIP data including FVI and driver health, then convert them to Acpi format.
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
BuildPhatAcpiTable (VOID)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT16 LengthOfFVI;
|
|
UINT32 LengthOfDriverHealth;
|
|
UINT32 TotalLength;
|
|
UINT8 *TempAipBuffHeader;
|
|
UINT8 *AcpiAipBuff;
|
|
UINT8 *AcpiAipBuffHead;
|
|
UINT16 HobLength;
|
|
EFI_ACPI_DESCRIPTION_HEADER *AcpiEntry;
|
|
EFI_ACPI_DESCRIPTION_HEADER *AcpiPhatTablePointer;
|
|
|
|
LengthOfFVI = 0;
|
|
LengthOfDriverHealth = 0;
|
|
TotalLength = 0;
|
|
HobLength = 0;
|
|
TempAipBuffHeader = NULL;
|
|
AcpiAipBuff = NULL;
|
|
AcpiAipBuffHead = NULL;
|
|
AcpiEntry = NULL;
|
|
AcpiPhatTablePointer = NULL;
|
|
|
|
//
|
|
// Get LengthOfFVI and LengthOfDriverHealth.
|
|
//
|
|
Status = GetLengthOfTelemetryData (&LengthOfFVI, &LengthOfDriverHealth);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((EFI_D_ERROR, "Failed to Get length of telemetry data. Status = %r\n", Status));
|
|
return;
|
|
}
|
|
DEBUG ((EFI_D_INFO, "Searching FVI is done: LengthOfFVI ==[%d], LengthOfDriverHealth == [%d] \n", LengthOfFVI, LengthOfDriverHealth));
|
|
|
|
TotalLength = LengthOfFVI + LengthOfDriverHealth;
|
|
AcpiAipBuff = AllocateZeroPool (TotalLength);
|
|
AcpiAipBuffHead = AcpiAipBuff;
|
|
if (AcpiAipBuff == NULL) {
|
|
DEBUG ((EFI_D_ERROR, "EFI_OUT_OF_RESOURCES : AcpiAipBuff allocate failed.\n"));
|
|
return;
|
|
}
|
|
|
|
((EFI_COMPONENT_VERSION_DATA *) AcpiAipBuffHead)->Revision = TELEMETRY_FVI_DATA_RECORD_REVISION;
|
|
((EFI_COMPONENT_VERSION_DATA *) AcpiAipBuffHead)->RecordLength = LengthOfFVI;
|
|
((EFI_COMPONENT_VERSION_DATA *) AcpiAipBuffHead)->RecordCount = (LengthOfFVI - AcpiComPonentHeadSize) / AcpiFviRecordSize;
|
|
AcpiAipBuffHead = AcpiAipBuff + AcpiComPonentHeadSize;
|
|
|
|
if (LengthOfFVI != AcpiComPonentHeadSize) {
|
|
|
|
//
|
|
// Get Aip data from Hobs.
|
|
//
|
|
GetAipHobRecords (&AcpiAipBuffHead, &HobLength);
|
|
TempAipBuffHeader = AcpiAipBuffHead + HobLength;
|
|
//
|
|
// Get Aip data from Protocol.
|
|
//
|
|
Status = CollectAipInfoFromProtocol (&TempAipBuffHeader, &LengthOfFVI);
|
|
if (Status == EFI_OUT_OF_RESOURCES) {
|
|
DEBUG ((EFI_D_ERROR, "Failed to process CollectAipInfoFromProtocol due to lack of resources!\n"));
|
|
if (AcpiAipBuff != NULL) {
|
|
FreePool (AcpiAipBuff);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Ready to add driver health record if they can be found
|
|
//
|
|
if (LengthOfDriverHealth != 0) {
|
|
CollectAipInfoFromHealthDriver (&TempAipBuffHeader, &LengthOfDriverHealth);
|
|
}
|
|
if (TempAipBuffHeader == NULL || LengthOfDriverHealth == 0) {
|
|
DEBUG ((EFI_D_ERROR, "No Driver health record was found. \n"));
|
|
}
|
|
|
|
//
|
|
// Initialize the Platform Health Assessment Table.
|
|
//
|
|
Status = InstallAcpiTelemetryTable (AcpiAipBuff, TotalLength);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((EFI_D_ERROR, "Install Telemetry ACPI table failed, Status = [%x] \n", Status));
|
|
}
|
|
|
|
//
|
|
// Clear all Telemetry HwErrRec variable.
|
|
//
|
|
Status = ClearAllTelemetryHwErrRec ();
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((EFI_D_ERROR, "Failed to ClearAll HwErrRec#### variable. Status = %r\n", Status));
|
|
}
|
|
|
|
AcpiEntry = SearchAcpiTablePointer();
|
|
if (AcpiEntry == NULL) {
|
|
DEBUG((EFI_D_ERROR, "EFI_NOT_FUND : AcpiEntry is NULL.\n"));
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Set HwErrRec variable.
|
|
//
|
|
AcpiPhatTablePointer = ScanTableInXSDT (AcpiEntry, EFI_ACPI_PLATFORM_HEALTH_ASSESSMENT_TABLE_SIGNATURE);
|
|
if (AcpiPhatTablePointer == NULL) {
|
|
DEBUG ((EFI_D_ERROR, "EFI_NOT_FUND : AcpiPhatTablePointer is NULL.\n"));
|
|
}
|
|
Status = SetDriverHealthHwErrRecVariable (AcpiPhatTablePointer);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((EFI_D_ERROR, "Failed to set the Health record into a HwErrRec#### variable. Status = %r\n", Status));
|
|
}
|
|
|
|
if (AcpiAipBuff != NULL) {
|
|
FreePool (AcpiAipBuff);
|
|
}
|
|
}
|
|
|
|
/**
|
|
Update PHAT callback function.
|
|
|
|
@param Event Pointer to this event
|
|
@param Context Event handler private data.
|
|
|
|
**/
|
|
|
|
VOID
|
|
EFIAPI
|
|
UpdatePhatAcpiTableCallback (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
BuildPhatAcpiTable();
|
|
}
|
|
|
|
/**
|
|
ReadytoBootEvent build PHAT.
|
|
|
|
@param Event Pointer to this event
|
|
@param Context Event handler private data.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
InstallPhatAcpiTableCallback (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
EFI_EVENT AcpiEvent;
|
|
EFI_STATUS Status;
|
|
|
|
if (Event != NULL) {
|
|
gBS->CloseEvent (Event);
|
|
}
|
|
|
|
BuildPhatAcpiTable();
|
|
|
|
//
|
|
// Register rebuild PHAT table event
|
|
//
|
|
Status = gBS->CreateEventEx (
|
|
EVT_NOTIFY_SIGNAL,
|
|
TPL_CALLBACK,
|
|
UpdatePhatAcpiTableCallback,
|
|
NULL,
|
|
&gPlatformAcpiUpdateEventGuid,
|
|
&AcpiEvent
|
|
);
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
return;
|
|
}
|
|
|
|
/**
|
|
Fixup internal data pointers so that the services can be called in virtual mode.
|
|
|
|
@param[in] Event The event registered.
|
|
@param[in] Context Event context. Not used in this event handler.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
TelemetryDriverHealthVirtualAddressChangeEvent (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
gRT->ConvertPointer (0, (VOID *) &mMotherBoardHealthRecBuffer);
|
|
}
|
|
|
|
/**
|
|
This is driver entry point to register the notification event.
|
|
|
|
@param[in] ImageHandle A handle for the image that is initializing this driver
|
|
@param[in] SystemTable A pointer to the EFI system table
|
|
|
|
@retval EFI_SUCCESS The initialization finished successfully.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DxeTelemetryAcpiLibConstructor (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
EFI_EVENT Event;
|
|
EFI_STATUS Status;
|
|
|
|
//
|
|
// Create Address Change event
|
|
//
|
|
Status = gBS->CreateEventEx (
|
|
EVT_NOTIFY_SIGNAL,
|
|
TPL_NOTIFY,
|
|
TelemetryDriverHealthVirtualAddressChangeEvent,
|
|
NULL,
|
|
&gEfiEventVirtualAddressChangeGuid,
|
|
&Event
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
//
|
|
// Get Report Status Code Handler Protocol.
|
|
//
|
|
Status = gBS->LocateProtocol (&gEfiRscHandlerProtocolGuid, NULL, (VOID **) &mRscHandlerProtocol);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
//
|
|
// Register report status code listener for OS Loader load and start.
|
|
//
|
|
Status = mRscHandlerProtocol->Register (PhatStatusCodeListenerDxe, TPL_HIGH_LEVEL);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
Status = EfiCreateEventReadyToBootEx (
|
|
TPL_CALLBACK,
|
|
InstallPhatAcpiTableCallback,
|
|
NULL,
|
|
&Event
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|