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