|
| 1 | +/** @file |
| 2 | + Firmware Performance Data Table (FPDT) table parser |
| 3 | +
|
| 4 | + Copyright (c) 2025, AMD Incorporated. All rights reserved. |
| 5 | + SPDX-License-Identifier: BSD-2-Clause-Patent |
| 6 | +
|
| 7 | + @par Reference(s): |
| 8 | + - ACPI 6.5 Specification - August 2022 |
| 9 | +**/ |
| 10 | + |
| 11 | +#include <IndustryStandard/Acpi.h> |
| 12 | +#include <Library/UefiLib.h> |
| 13 | +#include <Library/DebugLib.h> |
| 14 | +#include "AcpiParser.h" |
| 15 | +#include "AcpiTableParser.h" |
| 16 | +#include "AcpiViewConfig.h" |
| 17 | + |
| 18 | +// Local Variables |
| 19 | +STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo; |
| 20 | + |
| 21 | +/** |
| 22 | + An ACPI_PARSER array describing the ACPI FPDT performance record header. |
| 23 | +**/ |
| 24 | +STATIC CONST ACPI_PARSER FpdtPerfRecordParser[] = { |
| 25 | + { L"Type", 2, 0, L"0x%x", NULL, NULL, NULL, NULL }, |
| 26 | + { L"Length", 1, 2, L"0x%x", NULL, NULL, NULL, NULL }, |
| 27 | + { L"Revision", 1, 3, L"0x%x", NULL, NULL, NULL, NULL } |
| 28 | +}; |
| 29 | + |
| 30 | +/** |
| 31 | + An ACPI_PARSER array describing the ACPI FPDT boot performance pointer record. |
| 32 | +**/ |
| 33 | +STATIC CONST ACPI_PARSER FpdtBootPerfPointerParser[] = { |
| 34 | + { L"Type", 2, 0, L"0x%x", NULL, NULL, NULL, NULL }, |
| 35 | + { L"Length", 1, 2, L"0x%x", NULL, NULL, NULL, NULL }, |
| 36 | + { L"Revision", 1, 3, L"0x%x", NULL, NULL, NULL, NULL }, |
| 37 | + { L"Reserved", 4, 4, L"0x%x", NULL, NULL, NULL, NULL }, |
| 38 | + { L"BootPerformanceTablePointer", 8, 8, L"0x%lx", NULL, NULL, NULL, NULL } |
| 39 | +}; |
| 40 | + |
| 41 | +/** |
| 42 | + An ACPI_PARSER array describing the ACPI FPDT S3 performance pointer record. |
| 43 | +**/ |
| 44 | +STATIC CONST ACPI_PARSER FpdtS3PerfPointerParser[] = { |
| 45 | + { L"Type", 2, 0, L"0x%x", NULL, NULL, NULL, NULL }, |
| 46 | + { L"Length", 1, 2, L"0x%x", NULL, NULL, NULL, NULL }, |
| 47 | + { L"Revision", 1, 3, L"0x%x", NULL, NULL, NULL, NULL }, |
| 48 | + { L"Reserved", 4, 4, L"0x%x", NULL, NULL, NULL, NULL }, |
| 49 | + { L"S3PerformanceTablePointer", 8, 8, L"0x%lx", NULL, NULL, NULL, NULL } |
| 50 | +}; |
| 51 | + |
| 52 | +/** |
| 53 | + An ACPI_PARSER array describing the ACPI FPDT firmware table header. |
| 54 | +**/ |
| 55 | +STATIC CONST ACPI_PARSER AcpiFpdtHdrParser[] = { |
| 56 | + { L"Signature", 4, 0, NULL, Dump4Chars, NULL, NULL, NULL }, |
| 57 | + { L"Length", 4, 4, L"0x%x", NULL, NULL, NULL, NULL } |
| 58 | +}; |
| 59 | + |
| 60 | +/** |
| 61 | + An ACPI_PARSER array describing the ACPI FPDT firmware basic boot record. |
| 62 | +**/ |
| 63 | +STATIC CONST ACPI_PARSER FpdtBasicBootRecordParser[] = { |
| 64 | + { L"Type", 2, 0, L"0x%x", NULL, NULL, NULL, NULL }, |
| 65 | + { L"Length", 1, 2, L"0x%x", NULL, NULL, NULL, NULL }, |
| 66 | + { L"Revision", 1, 3, L"0x%x", NULL, NULL, NULL, NULL }, |
| 67 | + { L"Reserved", 4, 4, L"0x%x", NULL, NULL, NULL, NULL }, |
| 68 | + { L"ResetEnd", 8, 8, L"0x%lx", NULL, NULL, NULL, NULL }, |
| 69 | + { L"OsLoaderLoadImageStart", 8, 16, L"0x%lx", NULL, NULL, NULL, NULL }, |
| 70 | + { L"OsLoaderStartImageStart", 8, 24, L"0x%lx", NULL, NULL, NULL, NULL }, |
| 71 | + { L"ExitBootServicesEntry", 8, 32, L"0x%lx", NULL, NULL, NULL, NULL }, |
| 72 | + { L"ExitBootServicesExit", 8, 40, L"0x%lx", NULL, NULL, NULL, NULL } |
| 73 | +}; |
| 74 | + |
| 75 | +/** |
| 76 | + An ACPI_PARSER array describing the ACPI FPDT S3 resume record. |
| 77 | +**/ |
| 78 | +STATIC CONST ACPI_PARSER FpdtS3ResumeRecordParser[] = { |
| 79 | + { L"Type", 2, 0, L"0x%x", NULL, NULL, NULL, NULL }, |
| 80 | + { L"Length", 1, 2, L"0x%x", NULL, NULL, NULL, NULL }, |
| 81 | + { L"Revision", 1, 3, L"0x%x", NULL, NULL, NULL, NULL }, |
| 82 | + { L"ResumeCount", 4, 4, L"0x%x", NULL, NULL, NULL, NULL }, |
| 83 | + { L"FullResume", 8, 8, L"0x%lx", NULL, NULL, NULL, NULL }, |
| 84 | + { L"AverageResume", 8, 16, L"0x%lx", NULL, NULL, NULL, NULL } |
| 85 | +}; |
| 86 | + |
| 87 | +/** |
| 88 | + An ACPI_PARSER array describing the ACPI FPDT S3 suspend record. |
| 89 | +**/ |
| 90 | +STATIC CONST ACPI_PARSER FpdtS3SuspendRecordParser[] = { |
| 91 | + { L"Type", 2, 0, L"0x%x", NULL, NULL, NULL, NULL }, |
| 92 | + { L"Length", 1, 2, L"0x%x", NULL, NULL, NULL, NULL }, |
| 93 | + { L"Revision", 1, 3, L"0x%x", NULL, NULL, NULL, NULL }, |
| 94 | + { L"SuspendStart", 4, 4, L"0x%x", NULL, NULL, NULL, NULL }, |
| 95 | + { L"SuspendEnd", 8, 12, L"0x%lx", NULL, NULL, NULL, NULL } |
| 96 | +}; |
| 97 | + |
| 98 | +/** |
| 99 | + An ACPI_PARSER array describing the ACPI FPDT Table. |
| 100 | +**/ |
| 101 | +STATIC CONST ACPI_PARSER FpdtParser[] = { |
| 102 | + PARSE_ACPI_HEADER (&AcpiHdrInfo) |
| 103 | +}; |
| 104 | + |
| 105 | +/** |
| 106 | + This function parses the ACPI FPDT table. |
| 107 | + This function parses the FPDT table and optionally traces the ACPI |
| 108 | + table fields. |
| 109 | +
|
| 110 | + This function also performs validation of the ACPI table fields. |
| 111 | +
|
| 112 | + @param [in] Trace If TRUE, trace the ACPI fields. |
| 113 | + @param [in] Ptr Pointer to the start of the buffer. |
| 114 | + @param [in] AcpiTableLength Length of the ACPI table. |
| 115 | + @param [in] AcpiTableRevision Revision of the ACPI table. |
| 116 | +**/ |
| 117 | +VOID |
| 118 | +EFIAPI |
| 119 | +ParseAcpiFpdt ( |
| 120 | + IN BOOLEAN Trace, |
| 121 | + IN UINT8 *Ptr, |
| 122 | + IN UINT32 AcpiTableLength, |
| 123 | + IN UINT8 AcpiTableRevision |
| 124 | + ) |
| 125 | +{ |
| 126 | + EFI_ACPI_6_5_FPDT_BOOT_PERFORMANCE_TABLE_POINTER_RECORD *FpdtBasicBootPtr; |
| 127 | + EFI_ACPI_6_5_FPDT_FIRMWARE_BASIC_BOOT_RECORD *FpdtBasicBootRec; |
| 128 | + EFI_ACPI_6_5_FPDT_PERFORMANCE_RECORD_HEADER *FpdtRecHdr; |
| 129 | + EFI_ACPI_6_5_FPDT_PERFORMANCE_RECORD_HEADER *RecordHeader; |
| 130 | + EFI_ACPI_6_5_FPDT_PERFORMANCE_TABLE_HEADER *FpdtHdr; |
| 131 | + EFI_ACPI_6_5_FPDT_S3_PERFORMANCE_TABLE_POINTER_RECORD *FpdtS3Ptr; |
| 132 | + EFI_ACPI_6_5_FPDT_S3_RESUME_RECORD *FpdtS3ResumeRec; |
| 133 | + EFI_ACPI_6_5_FPDT_S3_SUSPEND_RECORD *FpdtS3SuspendRec; |
| 134 | + UINT32 Offset; |
| 135 | + UINT32 RecOffset; |
| 136 | + UINT8 *RecordPtr; |
| 137 | + |
| 138 | + if (!Trace) { |
| 139 | + return; |
| 140 | + } |
| 141 | + |
| 142 | + Offset = ParseAcpi ( |
| 143 | + TRUE, |
| 144 | + 0, |
| 145 | + "FPDT", |
| 146 | + Ptr, |
| 147 | + AcpiTableLength, |
| 148 | + PARSER_PARAMS (FpdtParser) |
| 149 | + ); |
| 150 | + |
| 151 | + RecordPtr = Ptr + Offset; |
| 152 | + |
| 153 | + while (Offset < AcpiTableLength) { |
| 154 | + RecordHeader = (EFI_ACPI_6_5_FPDT_PERFORMANCE_RECORD_HEADER *)RecordPtr; |
| 155 | + |
| 156 | + if (RecordHeader->Type == EFI_ACPI_6_5_FPDT_RECORD_TYPE_FIRMWARE_BASIC_BOOT_POINTER) { |
| 157 | + FpdtBasicBootPtr = (EFI_ACPI_6_5_FPDT_BOOT_PERFORMANCE_TABLE_POINTER_RECORD *)RecordPtr; |
| 158 | + ParseAcpi ( |
| 159 | + TRUE, |
| 160 | + 2, |
| 161 | + "FPDT Boot Performance Pointer Record", |
| 162 | + RecordPtr, |
| 163 | + FpdtBasicBootPtr->Header.Length, |
| 164 | + PARSER_PARAMS (FpdtBootPerfPointerParser) |
| 165 | + ); |
| 166 | + // Parse the header AcpiFpdtHdrParser |
| 167 | + ParseAcpi ( |
| 168 | + TRUE, |
| 169 | + 4, |
| 170 | + "Firmware Basic Boot Performance Table", |
| 171 | + (UINT8 *)(UINTN)(FpdtBasicBootPtr->BootPerformanceTablePointer), |
| 172 | + sizeof (EFI_ACPI_6_5_FPDT_PERFORMANCE_TABLE_HEADER), |
| 173 | + PARSER_PARAMS (AcpiFpdtHdrParser) |
| 174 | + ); |
| 175 | + FpdtHdr = (EFI_ACPI_6_5_FPDT_PERFORMANCE_TABLE_HEADER *)(UINTN)(FpdtBasicBootPtr->BootPerformanceTablePointer); |
| 176 | + RecOffset = sizeof (EFI_ACPI_6_5_FPDT_PERFORMANCE_TABLE_HEADER); |
| 177 | + while (RecOffset < FpdtHdr->Length) { |
| 178 | + FpdtBasicBootRec = (EFI_ACPI_6_5_FPDT_FIRMWARE_BASIC_BOOT_RECORD *)((UINT8 *)(UINTN)(FpdtBasicBootPtr->BootPerformanceTablePointer) + RecOffset); |
| 179 | + if (FpdtBasicBootRec->Header.Type != EFI_ACPI_6_5_FPDT_RUNTIME_RECORD_TYPE_FIRMWARE_BASIC_BOOT) { |
| 180 | + /// break the inner-loop if no more basic boot records |
| 181 | + break; |
| 182 | + } |
| 183 | + |
| 184 | + /// Parse the records inside the Boot Performance Table |
| 185 | + ParseAcpi ( |
| 186 | + TRUE, |
| 187 | + 4, |
| 188 | + "FPDT Boot Performance Table", |
| 189 | + (UINT8 *)(UINTN)(FpdtBasicBootPtr->BootPerformanceTablePointer) + RecOffset, |
| 190 | + FpdtBasicBootRec->Header.Length, |
| 191 | + PARSER_PARAMS (FpdtBasicBootRecordParser) |
| 192 | + ); |
| 193 | + RecOffset += FpdtBasicBootRec->Header.Length; |
| 194 | + } |
| 195 | + } else if (RecordHeader->Type == EFI_ACPI_6_5_FPDT_RECORD_TYPE_S3_PERFORMANCE_TABLE_POINTER) { |
| 196 | + FpdtS3Ptr = (EFI_ACPI_6_5_FPDT_S3_PERFORMANCE_TABLE_POINTER_RECORD *)RecordPtr; |
| 197 | + ParseAcpi ( |
| 198 | + TRUE, |
| 199 | + 2, |
| 200 | + "FPDT S3 Performance Pointer Record", |
| 201 | + RecordPtr, |
| 202 | + FpdtS3Ptr->Header.Length, |
| 203 | + PARSER_PARAMS (FpdtS3PerfPointerParser) |
| 204 | + ); |
| 205 | + |
| 206 | + ParseAcpi ( |
| 207 | + TRUE, |
| 208 | + 4, |
| 209 | + "S3 Performance Table Pointer Record", |
| 210 | + (UINT8 *)(UINTN)(FpdtS3Ptr->S3PerformanceTablePointer), |
| 211 | + sizeof (EFI_ACPI_6_5_FPDT_PERFORMANCE_TABLE_HEADER), |
| 212 | + PARSER_PARAMS (AcpiFpdtHdrParser) |
| 213 | + ); |
| 214 | + FpdtHdr = (EFI_ACPI_6_5_FPDT_PERFORMANCE_TABLE_HEADER *)(UINTN)(FpdtS3Ptr->S3PerformanceTablePointer); |
| 215 | + RecOffset = sizeof (EFI_ACPI_6_5_FPDT_PERFORMANCE_TABLE_HEADER); |
| 216 | + while (RecOffset < FpdtHdr->Length) { |
| 217 | + FpdtRecHdr = (EFI_ACPI_6_5_FPDT_PERFORMANCE_RECORD_HEADER *)((UINT8 *)(UINTN)(FpdtS3Ptr->S3PerformanceTablePointer) + RecOffset); |
| 218 | + if (FpdtRecHdr->Type == EFI_ACPI_6_5_FPDT_RUNTIME_RECORD_TYPE_S3_RESUME) { |
| 219 | + FpdtS3ResumeRec = (EFI_ACPI_6_5_FPDT_S3_RESUME_RECORD *)((UINT8 *)(UINTN)(FpdtS3Ptr->S3PerformanceTablePointer) + RecOffset); |
| 220 | + /// Parse the S3 Resume Record |
| 221 | + ParseAcpi ( |
| 222 | + TRUE, |
| 223 | + 4, |
| 224 | + "FPDT S3 Resume Record", |
| 225 | + (UINT8 *)(UINTN)(FpdtS3Ptr->S3PerformanceTablePointer) + RecOffset, |
| 226 | + FpdtS3ResumeRec->Header.Length, |
| 227 | + PARSER_PARAMS (FpdtS3ResumeRecordParser) |
| 228 | + ); |
| 229 | + } else if (FpdtRecHdr->Type == EFI_ACPI_6_5_FPDT_RUNTIME_RECORD_TYPE_S3_SUSPEND) { |
| 230 | + FpdtS3SuspendRec = (EFI_ACPI_6_5_FPDT_S3_SUSPEND_RECORD *)((UINT8 *)(UINTN)(FpdtS3Ptr->S3PerformanceTablePointer) + RecOffset); |
| 231 | + /// Parse the S3 Suspend Record |
| 232 | + ParseAcpi ( |
| 233 | + TRUE, |
| 234 | + 4, |
| 235 | + "FPDT S3 Suspend Record", |
| 236 | + (UINT8 *)(UINTN)(FpdtS3Ptr->S3PerformanceTablePointer) + RecOffset, |
| 237 | + FpdtS3SuspendRec->Header.Length, |
| 238 | + PARSER_PARAMS (FpdtS3SuspendRecordParser) |
| 239 | + ); |
| 240 | + } else { |
| 241 | + /// break the inner-loop if no more S3 records |
| 242 | + break; |
| 243 | + } |
| 244 | + |
| 245 | + RecOffset += FpdtRecHdr->Length; |
| 246 | + } |
| 247 | + } else { |
| 248 | + /// Parse the reserved record types |
| 249 | + ParseAcpi ( |
| 250 | + TRUE, |
| 251 | + 2, |
| 252 | + "FPDT Performance Record", |
| 253 | + RecordPtr, |
| 254 | + RecordHeader->Length, |
| 255 | + PARSER_PARAMS (FpdtPerfRecordParser) |
| 256 | + ); |
| 257 | + } |
| 258 | + |
| 259 | + Offset += RecordHeader->Length; |
| 260 | + RecordPtr += RecordHeader->Length; |
| 261 | + } |
| 262 | +} |
0 commit comments