blob: 5179bf8268339e4bffb0ac899d6339876a354350 [file] [log] [blame]
/** @file
Firmware Performance Data Table (FPDT) table parser
Copyright (C) 2026 Advanced Micro Devices, Inc. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
@par Reference(s):
- ACPI 6.5 Specification - August 2022
**/
#include <IndustryStandard/Acpi.h>
#include <Library/UefiLib.h>
#include <Library/DebugLib.h>
#include "AcpiParser.h"
#include "AcpiTableParser.h"
#include "AcpiViewConfig.h"
/**
Parse the Firmware basic boot performance record.
EFI_ACPI_6_5_FPDT_PERFORMANCE_TABLE_HEADER
**/
VOID
EFIAPI
DumpFbbp (
IN CONST CHAR16 *Format OPTIONAL,
IN UINT8 *Ptr,
IN UINT32 Length
);
/**
Parse the S3 performance table record.
EFI_ACPI_6_5_FPDT_RECORD_TYPE_S3_PERFORMANCE_TABLE_POINTER
@param [in] Format Format string.
@param [in] Ptr Pointer to the start of the record.
@param [in] Length Length of the field.
**/
VOID
EFIAPI
DumpS3Ptp (
IN CONST CHAR16 *Format OPTIONAL,
IN UINT8 *Ptr,
IN UINT32 Length
);
// Local Variables
STATIC ACPI_DESCRIPTION_HEADER_INFO mAcpiHdrInfo;
/**
An ACPI_PARSER array describing the ACPI FPDT performance record header.
**/
STATIC CONST ACPI_PARSER mFpdtPerfRecordParser[] = {
{ L"Type", 2, 0, L"0x%x", NULL, NULL, NULL, NULL },
{ L"Length", 1, 2, L"0x%x", NULL, NULL, NULL, NULL },
{ L"Revision", 1, 3, L"0x%x", NULL, NULL, NULL, NULL }
};
/**
An ACPI_PARSER array describing the ACPI FPDT boot performance pointer record.
**/
STATIC CONST ACPI_PARSER mFpdtBootPerfPointerParser[] = {
{ L"Type", 2, 0, L"0x%x", NULL, NULL, NULL, NULL },
{ L"Length", 1, 2, L"0x%x", NULL, NULL, NULL, NULL },
{ L"Revision", 1, 3, L"0x%x", NULL, NULL, NULL, NULL },
{ L"Reserved", 4, 4, L"0x%x", NULL, NULL, NULL, NULL },
{ L"BootPerformanceTablePointer", 8, 8, NULL, DumpFbbp, NULL, NULL, NULL }
};
/**
An ACPI_PARSER array describing the ACPI FPDT S3 performance pointer record.
**/
STATIC CONST ACPI_PARSER mFpdtS3PerfPointerParser[] = {
{ L"Type", 2, 0, L"0x%x", NULL, NULL, NULL, NULL },
{ L"Length", 1, 2, L"0x%x", NULL, NULL, NULL, NULL },
{ L"Revision", 1, 3, L"0x%x", NULL, NULL, NULL, NULL },
{ L"Reserved", 4, 4, L"0x%x", NULL, NULL, NULL, NULL },
{ L"S3PerformanceTablePointer", 8, 8, NULL, DumpS3Ptp, NULL, NULL, NULL }
};
/**
An ACPI_PARSER array describing the ACPI FPDT firmware table header.
**/
STATIC CONST ACPI_PARSER mAcpiFpdtHdrParser[] = {
{ L"Signature", 4, 0, NULL, Dump4Chars, NULL, NULL, NULL },
{ L"Length", 4, 4, L"0x%x", NULL, NULL, NULL, NULL }
};
/**
An ACPI_PARSER array describing the ACPI FPDT firmware basic boot record.
**/
STATIC CONST ACPI_PARSER mFpdtBasicBootRecordParser[] = {
{ L"Type", 2, 0, L"0x%x", NULL, NULL, NULL, NULL },
{ L"Length", 1, 2, L"0x%x", NULL, NULL, NULL, NULL },
{ L"Revision", 1, 3, L"0x%x", NULL, NULL, NULL, NULL },
{ L"Reserved", 4, 4, L"0x%x", NULL, NULL, NULL, NULL },
{ L"ResetEnd", 8, 8, L"0x%lx", NULL, NULL, NULL, NULL },
{ L"OsLoaderLoadImageStart", 8, 16, L"0x%lx", NULL, NULL, NULL, NULL },
{ L"OsLoaderStartImageStart", 8, 24, L"0x%lx", NULL, NULL, NULL, NULL },
{ L"ExitBootServicesEntry", 8, 32, L"0x%lx", NULL, NULL, NULL, NULL },
{ L"ExitBootServicesExit", 8, 40, L"0x%lx", NULL, NULL, NULL, NULL }
};
/**
An ACPI_PARSER array describing the ACPI FPDT S3 resume record.
**/
STATIC CONST ACPI_PARSER mFpdtS3ResumeRecordParser[] = {
{ L"Type", 2, 0, L"0x%x", NULL, NULL, NULL, NULL },
{ L"Length", 1, 2, L"0x%x", NULL, NULL, NULL, NULL },
{ L"Revision", 1, 3, L"0x%x", NULL, NULL, NULL, NULL },
{ L"ResumeCount", 4, 4, L"0x%x", NULL, NULL, NULL, NULL },
{ L"FullResume", 8, 8, L"0x%lx", NULL, NULL, NULL, NULL },
{ L"AverageResume", 8, 16, L"0x%lx", NULL, NULL, NULL, NULL }
};
/**
An ACPI_PARSER array describing the ACPI FPDT S3 suspend record.
**/
STATIC CONST ACPI_PARSER mFpdtS3SuspendRecordParser[] = {
{ L"Type", 2, 0, L"0x%x", NULL, NULL, NULL, NULL },
{ L"Length", 1, 2, L"0x%x", NULL, NULL, NULL, NULL },
{ L"Revision", 1, 3, L"0x%x", NULL, NULL, NULL, NULL },
{ L"SuspendStart", 4, 4, L"0x%x", NULL, NULL, NULL, NULL },
{ L"SuspendEnd", 8, 12, L"0x%lx", NULL, NULL, NULL, NULL }
};
/**
An ACPI_PARSER array describing the ACPI FPDT Table.
**/
STATIC CONST ACPI_PARSER mFpdtParser[] = {
PARSE_ACPI_HEADER (&mAcpiHdrInfo)
};
/**
Parse the S3 performance table record.
EFI_ACPI_6_5_FPDT_RECORD_TYPE_S3_PERFORMANCE_TABLE_POINTER
@param [in] Format Format string.
@param [in] Ptr Pointer to the start of the record.
@param [in] Length Length of the field.
**/
VOID
EFIAPI
DumpS3Ptp (
IN CONST CHAR16 *Format OPTIONAL,
IN UINT8 *Ptr,
IN UINT32 Length
)
{
EFI_ACPI_6_5_FPDT_PERFORMANCE_TABLE_HEADER *FpdtHdr;
EFI_ACPI_6_5_FPDT_S3_RESUME_RECORD *FpdtS3ResumeRec;
EFI_ACPI_6_5_FPDT_S3_SUSPEND_RECORD *FpdtS3SuspendRec;
UINT32 RecOffset;
UINT8 *RecPtr;
EFI_ACPI_6_5_FPDT_PERFORMANCE_RECORD_HEADER *FpdtRecHdr;
BOOLEAN InvalidRecord;
InvalidRecord = FALSE;
RecPtr = (UINT8 *)(UINTN)(*(UINT64 *)Ptr);
Print (
(Format != NULL) ? Format : L"0x%lx\n",
RecPtr
);
ParseAcpi (
TRUE,
4,
"S3 Performance Table Pointer Record",
RecPtr,
sizeof (EFI_ACPI_6_5_FPDT_PERFORMANCE_TABLE_HEADER),
PARSER_PARAMS (mAcpiFpdtHdrParser)
);
RecOffset = sizeof (EFI_ACPI_6_5_FPDT_PERFORMANCE_TABLE_HEADER);
FpdtHdr = (EFI_ACPI_6_5_FPDT_PERFORMANCE_TABLE_HEADER *)(RecPtr);
while (!InvalidRecord && (RecOffset < FpdtHdr->Length)) {
FpdtRecHdr = (EFI_ACPI_6_5_FPDT_PERFORMANCE_RECORD_HEADER *)(RecPtr + RecOffset);
switch (FpdtRecHdr->Type) {
case EFI_ACPI_6_5_FPDT_RUNTIME_RECORD_TYPE_S3_RESUME:
FpdtS3ResumeRec = (EFI_ACPI_6_5_FPDT_S3_RESUME_RECORD *)(RecPtr + RecOffset);
ParseAcpi (
TRUE,
4,
"FPDT S3 Resume Record",
RecPtr + RecOffset,
FpdtS3ResumeRec->Header.Length,
PARSER_PARAMS (mFpdtS3ResumeRecordParser)
);
break;
case EFI_ACPI_6_5_FPDT_RUNTIME_RECORD_TYPE_S3_SUSPEND:
FpdtS3SuspendRec = (EFI_ACPI_6_5_FPDT_S3_SUSPEND_RECORD *)(RecPtr + RecOffset);
ParseAcpi (
TRUE,
4,
"FPDT S3 Suspend Record",
RecPtr + RecOffset,
FpdtS3SuspendRec->Header.Length,
PARSER_PARAMS (mFpdtS3SuspendRecordParser)
);
break;
default:
IncrementErrorCount ();
Print (
L"\nError: Unknown FPDT S3 Performance Record Type: 0x%x\n",
FpdtRecHdr->Type
);
InvalidRecord = TRUE;
break;
}
RecOffset += FpdtRecHdr->Length;
}
}
/**
Parse the Firmware basic boot performance record.
EFI_ACPI_6_5_FPDT_PERFORMANCE_TABLE_HEADER
@param [in] Format Format string.
@param [in] Ptr Pointer to the start of the record.
@param [in] Length Length of the field.
**/
VOID
EFIAPI
DumpFbbp (
IN CONST CHAR16 *Format OPTIONAL,
IN UINT8 *Ptr,
IN UINT32 Length
)
{
EFI_ACPI_6_5_FPDT_FIRMWARE_BASIC_BOOT_RECORD *FpdtBasicBootRec;
EFI_ACPI_6_5_FPDT_PERFORMANCE_TABLE_HEADER *FpdtHdr;
UINT32 RecOffset;
UINT8 *RecPtr;
RecPtr = (UINT8 *)(UINTN)(*(UINT64 *)Ptr);
Print (
(Format != NULL) ? Format : L"0x%lx\n",
RecPtr
);
ParseAcpi (
TRUE,
4,
"Firmware Basic Boot Performance Table",
RecPtr,
sizeof (EFI_ACPI_6_5_FPDT_PERFORMANCE_TABLE_HEADER),
PARSER_PARAMS (mAcpiFpdtHdrParser)
);
RecOffset = sizeof (EFI_ACPI_6_5_FPDT_PERFORMANCE_TABLE_HEADER);
FpdtHdr = (EFI_ACPI_6_5_FPDT_PERFORMANCE_TABLE_HEADER *)RecPtr;
while (RecOffset < FpdtHdr->Length) {
FpdtBasicBootRec = (EFI_ACPI_6_5_FPDT_FIRMWARE_BASIC_BOOT_RECORD *)(RecPtr + RecOffset);
if (FpdtBasicBootRec->Header.Type != EFI_ACPI_6_5_FPDT_RUNTIME_RECORD_TYPE_FIRMWARE_BASIC_BOOT) {
IncrementErrorCount ();
Print (
L"\nError: Unexpected FPDT Boot Performance Record Type: 0x%x\n",
FpdtBasicBootRec->Header.Type
);
break;
}
ParseAcpi (
TRUE,
4,
"FPDT Boot Performance Table",
RecPtr + RecOffset,
FpdtBasicBootRec->Header.Length,
PARSER_PARAMS (mFpdtBasicBootRecordParser)
);
RecOffset += FpdtBasicBootRec->Header.Length;
}
}
/**
This function parses the ACPI FPDT table.
This function parses the FPDT table and optionally traces the ACPI
table fields.
This function also performs validation of the ACPI table fields.
@param [in] Trace If TRUE, trace the ACPI fields.
@param [in] Ptr Pointer to the start of the buffer.
@param [in] AcpiTableLength Length of the ACPI table.
@param [in] AcpiTableRevision Revision of the ACPI table.
**/
VOID
EFIAPI
ParseAcpiFpdt (
IN BOOLEAN Trace,
IN UINT8 *Ptr,
IN UINT32 AcpiTableLength,
IN UINT8 AcpiTableRevision
)
{
EFI_ACPI_6_5_FPDT_PERFORMANCE_RECORD_HEADER *RecordHeader;
UINT32 Offset;
UINT8 *RecordPtr;
if (!Trace) {
return;
}
Offset = ParseAcpi (
TRUE,
0,
"FPDT",
Ptr,
AcpiTableLength,
PARSER_PARAMS (mFpdtParser)
);
RecordPtr = Ptr + Offset;
while (Offset < AcpiTableLength) {
RecordHeader = (EFI_ACPI_6_5_FPDT_PERFORMANCE_RECORD_HEADER *)RecordPtr;
switch (RecordHeader->Type) {
case EFI_ACPI_6_5_FPDT_RECORD_TYPE_FIRMWARE_BASIC_BOOT_POINTER:
ParseAcpi (
TRUE,
2,
"FPDT Boot Performance Pointer Record",
RecordPtr,
RecordHeader->Length,
PARSER_PARAMS (mFpdtBootPerfPointerParser)
);
break;
case EFI_ACPI_6_5_FPDT_RECORD_TYPE_S3_PERFORMANCE_TABLE_POINTER:
ParseAcpi (
TRUE,
2,
"FPDT S3 Performance Table Pointer Record",
RecordPtr,
RecordHeader->Length,
PARSER_PARAMS (mFpdtS3PerfPointerParser)
);
break;
default:
/// Parse the reserved record types
ParseAcpi (
TRUE,
2,
"FPDT Performance Record",
RecordPtr,
RecordHeader->Length,
PARSER_PARAMS (mFpdtPerfRecordParser)
);
break;
}
Offset += RecordHeader->Length;
RecordPtr += RecordHeader->Length;
}
}