| /** @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; | |
| } | |
| } |