4 Copyright (c) 2021, Arm Limited.
5 SPDX-License-Identifier: BSD-2-Clause-Patent
8 - ACPI 6.4 Specification - January 2021
11 #include <Library/BaseMemoryLib.h>
12 #include <Library/PrintLib.h>
13 #include <Library/UefiLib.h>
14 #include "AcpiParser.h"
16 #include "AcpiViewConfig.h"
17 #include "PcctParser.h"
20 STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo
;
22 STATIC UINT32
*PccGlobalFlags
;
23 STATIC UINT8
*PccSubspaceLength
;
24 STATIC UINT8
*PccSubspaceType
;
25 STATIC UINT8
*ExtendedPccSubspaceInterruptFlags
;
28 This function validates the length coded on 4 bytes of a shared memory range
30 @param [in] Ptr Pointer to the start of the field data.
31 @param [in] Context Pointer to context specific information e.g. this
32 could be a pointer to the ACPI table header.
37 ValidateRangeLength4 (
42 if (*(UINT32
*)Ptr
< MIN_EXT_PCC_SUBSPACE_MEM_RANGE_LEN
) {
43 IncrementErrorCount ();
45 L
"\nError: Shared memory range length is too short.\n"
46 L
"Length is %u when it should be greater than or equal to %u",
48 MIN_EXT_PCC_SUBSPACE_MEM_RANGE_LEN
54 This function validates the length coded on 8 bytes of a shared memory range
56 @param [in] Ptr Pointer to the start of the field data.
57 @param [in] Context Pointer to context specific information e.g. this
58 could be a pointer to the ACPI table header.
63 ValidateRangeLength8 (
68 if (*(UINT64
*)Ptr
<= MIN_MEMORY_RANGE_LENGTH
) {
69 IncrementErrorCount ();
71 L
"\nError: Shared memory range length is too short.\n"
72 L
"Length is %u when it should be greater than %u",
74 MIN_MEMORY_RANGE_LENGTH
80 This function validates address space for Memory/IO GAS.
82 @param [in] Ptr Pointer to the start of the field data.
83 @param [in] Context Pointer to context specific information e.g. this
84 could be a pointer to the ACPI table header.
89 ValidatePccMemoryIoGas (
94 switch (*(UINT8
*)Ptr
) {
95 #if !(defined (MDE_CPU_ARM) || defined (MDE_CPU_AARCH64))
96 case EFI_ACPI_6_4_SYSTEM_IO
:
97 #endif //if not (defined (MDE_CPU_ARM) || defined (MDE_CPU_AARCH64))
98 case EFI_ACPI_6_4_SYSTEM_MEMORY
:
101 IncrementErrorCount ();
102 Print (L
"\nError: Invalid address space");
107 This function validates address space for structures of types other than 0.
109 @param [in] Ptr Pointer to the start of the field data.
110 @param [in] Context Pointer to context specific information e.g. this
111 could be a pointer to the ACPI table header.
121 switch (*(UINT8
*)Ptr
) {
122 #if !(defined (MDE_CPU_ARM) || defined (MDE_CPU_AARCH64))
123 case EFI_ACPI_6_4_SYSTEM_IO
:
124 #endif //if not (defined (MDE_CPU_ARM) || defined (MDE_CPU_AARCH64))
125 case EFI_ACPI_6_4_FUNCTIONAL_FIXED_HARDWARE
:
126 case EFI_ACPI_6_4_SYSTEM_MEMORY
:
129 IncrementErrorCount ();
130 Print (L
"\nError: Invalid address space");
135 This function validates doorbell address space for type 4 structure.
137 @param [in] Ptr Pointer to the start of the field data.
138 @param [in] Context Pointer to context specific information e.g. this
139 could be a pointer to the ACPI table header.
144 ValidatePccDoorbellGas (
149 // For slave subspaces this field is optional, if not present the field
150 // should just contain zeros.
151 if (*PccSubspaceType
== EFI_ACPI_6_4_PCCT_SUBSPACE_TYPE_4_EXTENDED_PCC
) {
154 sizeof (EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE
)
161 ValidatePccGas (Ptr
, Context
);
165 This function validates interrupt acknowledge address space for
168 @param [in] Ptr Pointer to the start of the field data.
169 @param [in] Context Pointer to context specific information e.g. this
170 could be a pointer to the ACPI table header.
175 ValidatePccIntAckGas (
180 // If the subspace does not support interrupts or the interrupt is
181 // edge driven the register may be omitted. A value of 0x0 on all
182 // 12 bytes of the GAS structure indicates the register is not
184 if (((*PccGlobalFlags
& EFI_ACPI_6_4_PCCT_FLAGS_PLATFORM_INTERRUPT
) !=
185 EFI_ACPI_6_4_PCCT_FLAGS_PLATFORM_INTERRUPT
) ||
186 ((*ExtendedPccSubspaceInterruptFlags
&
187 EFI_ACPI_6_4_PCCT_SUBSPACE_PLATFORM_INTERRUPT_FLAGS_MODE
) ==
188 EFI_ACPI_6_4_PCCT_SUBSPACE_PLATFORM_INTERRUPT_FLAGS_MODE
))
192 sizeof (EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE
)
199 ValidatePccGas (Ptr
, Context
);
203 This function validates error status address space for type 4 structure.
205 @param [in] Ptr Pointer to the start of the field data.
206 @param [in] Context Pointer to context specific information e.g. this
207 could be a pointer to the ACPI table header.
212 ValidatePccErrStatusGas (
217 // This field is ignored by the OSPM on slave channels.
218 if (*PccSubspaceType
== EFI_ACPI_6_4_PCCT_SUBSPACE_TYPE_4_EXTENDED_PCC
) {
222 ValidatePccGas (Ptr
, Context
);
226 This function validates platform interrupt flags for type 4 structure.
228 @param [in] Ptr Pointer to the start of the field data.
229 @param [in] Context Pointer to context specific information e.g. this
230 could be a pointer to the ACPI table header.
235 ValidatePlatInterrupt (
240 // If a slave subspace is present in the PCCT, then the global Platform
241 // Interrupt flag must be set to 1.
242 if ((*PccSubspaceType
== EFI_ACPI_6_4_PCCT_SUBSPACE_TYPE_4_EXTENDED_PCC
) &&
243 ((*PccGlobalFlags
& EFI_ACPI_6_4_PCCT_FLAGS_PLATFORM_INTERRUPT
) !=
244 EFI_ACPI_6_4_PCCT_FLAGS_PLATFORM_INTERRUPT
))
246 IncrementErrorCount ();
248 L
"\nError: Global Platform interrupt flag must be set to 1" \
249 L
" if a PCC type 4 structure is present in PCCT."
255 An ACPI_PARSER array describing the ACPI PCCT Table.
257 STATIC CONST ACPI_PARSER PcctParser
[] = {
258 PARSE_ACPI_HEADER (&AcpiHdrInfo
),
259 { L
"Flags", 4, 36, NULL
, NULL
, (VOID
**)&PccGlobalFlags
, NULL
, NULL
},
260 { L
"Reserved", 8, 40, NULL
, NULL
, NULL
, NULL
, NULL
}
264 An ACPI_PARSER array describing the platform communications channel subspace
267 STATIC CONST ACPI_PARSER PccSubspaceHeaderParser
[] = {
268 PCC_SUBSPACE_HEADER ()
269 // ... Type Specific Fields ...
273 An ACPI_PARSER array describing the Generic Communications Subspace - Type 0
275 STATIC CONST ACPI_PARSER PccSubspaceType0Parser
[] = {
276 PCC_SUBSPACE_HEADER (),
277 { L
"Reserved", 6, 2, L
"%x %x %x %x %x %x", Dump6Chars
, NULL
, NULL
, NULL
},
278 { L
"Base Address", 8, 8, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
279 { L
"Memory Range Length",8, 16, L
"0x%lx", NULL
, NULL
, ValidateRangeLength8
,
281 { L
"Doorbell Register",12, 24, NULL
, DumpGas
, NULL
, ValidatePccMemoryIoGas
,
283 { L
"Doorbell Preserve",8, 36, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
284 { L
"Doorbell Write", 8, 44, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
285 { L
"Nominal Latency", 4, 52, L
"%u", NULL
, NULL
, NULL
, NULL
},
286 { L
"Maximum Periodic Access Rate",4, 56, L
"%u", NULL
, NULL
, NULL
, NULL
},
287 { L
"Minimum Request Turnaround Time",2, 60, L
"%u", NULL
, NULL
, NULL
, NULL
}
291 An ACPI_PARSER array describing the HW-Reduced Communications Subspace
294 STATIC CONST ACPI_PARSER PccSubspaceType1Parser
[] = {
295 PCC_SUBSPACE_HEADER (),
296 { L
"Platform Interrupt",4, 2, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
297 { L
"Platform Interrupt Flags",1, 6, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
298 { L
"Reserved", 1, 7, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
299 { L
"Base Address", 8, 8, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
300 { L
"Memory Range Length",8, 16, L
"0x%lx", NULL
, NULL
, ValidateRangeLength8
,
302 { L
"Doorbell Register",12, 24, NULL
, DumpGas
, NULL
,
303 ValidatePccGas
, NULL
},
304 { L
"Doorbell Preserve",8, 36, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
305 { L
"Doorbell Write", 8, 44, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
306 { L
"Nominal Latency", 4, 52, L
"%u", NULL
, NULL
, NULL
, NULL
},
307 { L
"Maximum Periodic Access Rate",4, 56, L
"%u", NULL
, NULL
, NULL
, NULL
},
308 { L
"Minimum Request Turnaround Time",2, 60, L
"%u", NULL
, NULL
, NULL
, NULL
}
312 An ACPI_PARSER array describing the HW-Reduced Communications Subspace
315 STATIC CONST ACPI_PARSER PccSubspaceType2Parser
[] = {
316 PCC_SUBSPACE_HEADER (),
317 { L
"Platform Interrupt",4, 2, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
318 { L
"Platform Interrupt Flags",1, 6, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
319 { L
"Reserved", 1, 7, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
320 { L
"Base Address", 8, 8, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
321 { L
"Memory Range Length",8, 16, L
"0x%lx", NULL
, NULL
, ValidateRangeLength8
,
323 { L
"Doorbell Register",12, 24, NULL
, DumpGas
, NULL
,
324 ValidatePccGas
, NULL
},
325 { L
"Doorbell Preserve",8, 36, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
326 { L
"Doorbell Write", 8, 44, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
327 { L
"Nominal Latency", 4, 52, L
"%u", NULL
, NULL
, NULL
, NULL
},
328 { L
"Maximum Periodic Access Rate",4, 56, L
"%u", NULL
, NULL
, NULL
, NULL
},
329 { L
"Minimum Request Turnaround Time",2, 60, L
"%u", NULL
, NULL
, NULL
, NULL
},
330 { L
"Platform Interrupt Ack Register",12, 62, NULL
, DumpGas
, NULL
,
331 ValidatePccGas
, NULL
},
332 { L
"Platform Interrupt Ack Preserve",8, 74, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
333 { L
"Platform Interrupt Ack Write",8, 82, L
"0x%lx", NULL
, NULL
,
338 An ACPI_PARSER array describing the Extended PCC Subspaces - Type 3/4
340 STATIC CONST ACPI_PARSER PccSubspaceType3Parser
[] = {
341 PCC_SUBSPACE_HEADER (),
342 { L
"Platform Interrupt", 4, 2, L
"0x%x", NULL
, NULL
,
343 ValidatePlatInterrupt
, NULL
},
344 { L
"Platform Interrupt Flags", 1, 6, L
"0x%x", NULL
,
345 (VOID
**)&ExtendedPccSubspaceInterruptFlags
,NULL
, NULL
},
346 { L
"Reserved", 1, 7, L
"0x%x", NULL
, NULL
,NULL
, NULL
},
347 { L
"Base Address", 8, 8, L
"0x%lx", NULL
, NULL
,NULL
, NULL
},
348 { L
"Memory Range Length", 4, 16, L
"0x%x", NULL
, NULL
,ValidateRangeLength4
,
350 { L
"Doorbell Register", 12, 20, NULL
, DumpGas
, NULL
,
351 ValidatePccDoorbellGas
, NULL
},
352 { L
"Doorbell Preserve", 8, 32, L
"0x%lx", NULL
, NULL
,NULL
, NULL
},
353 { L
"Doorbell Write", 8, 40, L
"0x%lx", NULL
, NULL
,NULL
, NULL
},
354 { L
"Nominal Latency", 4, 48, L
"%u", NULL
, NULL
,NULL
, NULL
},
355 { L
"Maximum Periodic Access Rate", 4, 52, L
"%u", NULL
, NULL
,NULL
, NULL
},
356 { L
"Minimum Request Turnaround Time", 4, 56, L
"%u", NULL
, NULL
,NULL
, NULL
},
357 { L
"Platform Interrupt Ack Register", 12, 60, NULL
, DumpGas
, NULL
,
358 ValidatePccIntAckGas
, NULL
},
359 { L
"Platform Interrupt Ack Preserve", 8, 72, L
"0x%lx", NULL
, NULL
,NULL
, NULL
},
360 { L
"Platform Interrupt Ack Set", 8, 80, L
"0x%lx", NULL
, NULL
,NULL
, NULL
},
361 { L
"Reserved", 8, 88, L
"0x%lx", NULL
, NULL
,NULL
, NULL
},
362 { L
"Cmd Complete Check Reg Addr", 12, 96, NULL
, DumpGas
, NULL
,
363 ValidatePccGas
, NULL
},
364 { L
"Cmd Complete Check Mask", 8, 108, L
"0x%lx", NULL
, NULL
,NULL
, NULL
},
365 { L
"Cmd Update Reg Addr", 12, 116, NULL
, DumpGas
, NULL
,
366 ValidatePccGas
, NULL
},
367 { L
"Cmd Update Preserve mask", 8, 128, L
"0x%lx", NULL
, NULL
,NULL
, NULL
},
368 { L
"Cmd Update Set mask", 8, 136, L
"0x%lx", NULL
, NULL
,NULL
, NULL
},
369 { L
"Error Status Register", 12, 144, NULL
, DumpGas
, NULL
,
370 ValidatePccErrStatusGas
, NULL
},
371 { L
"Error Status Mask", 8, 156, L
"0x%lx", NULL
, NULL
,NULL
, NULL
},
375 An ACPI_PARSER array describing the HW Registers based Communications
376 Subspace Structure - Type 5
378 STATIC CONST ACPI_PARSER PccSubspaceType5Parser
[] = {
379 PCC_SUBSPACE_HEADER (),
380 { L
"Version", 2, 2, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
381 { L
"Base Address", 8, 4, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
382 { L
"Shared Memory Range Length",8, 12, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
383 { L
"Doorbell Register", 12, 20, NULL
, DumpGas
, NULL
,
384 ValidatePccMemoryIoGas
,NULL
},
385 { L
"Doorbell Preserve", 8, 32, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
386 { L
"Doorbell Write", 8, 40, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
387 { L
"Command Complete Check Register",12, 48, NULL
, DumpGas
, NULL
,
388 ValidatePccMemoryIoGas
,NULL
},
389 { L
"Command Complete Check Mask",8, 60, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
390 { L
"Error Status Register",12, 68, NULL
, DumpGas
, NULL
,
391 ValidatePccMemoryIoGas
,NULL
},
392 { L
"Error Status Mask", 8, 80, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
393 { L
"Nominal Latency", 4, 88, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
394 { L
"Minimum Request Turnaround Time",4, 92, L
"0x%x", NULL
, NULL
, NULL
, NULL
}
398 This function parses the PCC Subspace type 0.
400 @param [in] Ptr Pointer to the start of Subspace Structure.
401 @param [in] Length Length of the Subspace Structure.
405 DumpPccSubspaceType0 (
416 PARSER_PARAMS (PccSubspaceType0Parser
)
421 This function parses the PCC Subspace type 1.
423 @param [in] Ptr Pointer to the start of the Subspace Structure.
424 @param [in] Length Length of the Subspace Structure.
428 DumpPccSubspaceType1 (
439 PARSER_PARAMS (PccSubspaceType1Parser
)
444 This function parses the PCC Subspace type 2.
446 @param [in] Ptr Pointer to the start of the Subspace Structure.
447 @param [in] Length Length of the Subspace Structure.
451 DumpPccSubspaceType2 (
462 PARSER_PARAMS (PccSubspaceType2Parser
)
467 This function parses the PCC Subspace type 3.
469 @param [in] Ptr Pointer to the start of the Subspace Structure.
470 @param [in] Length Length of the Subspace Structure.
474 DumpPccSubspaceType3 (
485 PARSER_PARAMS (PccSubspaceType3Parser
)
490 This function parses the PCC Subspace type 4.
492 @param [in] Ptr Pointer to the start of the Subspace Structure.
493 @param [in] Length Length of the Subspace Structure.
497 DumpPccSubspaceType4 (
508 PARSER_PARAMS (PccSubspaceType3Parser
)
513 This function parses the PCC Subspace type 5.
515 @param [in] Ptr Pointer to the start of the Subspace Structure.
516 @param [in] Length Length of the Subspace Structure.
520 DumpPccSubspaceType5 (
531 PARSER_PARAMS (PccSubspaceType5Parser
)
536 This function parses the ACPI PCCT table including its sub-structures
538 When trace is enabled this function parses the PCCT table and
539 traces the ACPI table fields.
541 This function also performs validation of the ACPI table fields.
543 @param [in] Trace If TRUE, trace the ACPI fields.
544 @param [in] Ptr Pointer to the start of the buffer.
545 @param [in] AcpiTableLength Length of the ACPI table.
546 @param [in] AcpiTableRevision Revision of the ACPI table.
553 IN UINT32 AcpiTableLength
,
554 IN UINT8 AcpiTableRevision
558 UINT8
*PccSubspacePtr
;
571 PARSER_PARAMS (PcctParser
)
574 PccSubspacePtr
= Ptr
+ Offset
;
577 while (Offset
< AcpiTableLength
) {
578 // Parse common structure header to obtain Type and Length.
584 AcpiTableLength
- Offset
,
585 PARSER_PARAMS (PccSubspaceHeaderParser
)
588 // Check if the values used to control the parsing logic have been
589 // successfully read.
590 if ((PccSubspaceType
== NULL
) ||
591 (PccSubspaceLength
== NULL
))
593 IncrementErrorCount ();
595 L
"ERROR: Insufficient remaining table buffer length to read the " \
596 L
"structure header. Length = %u.\n",
597 AcpiTableLength
- Offset
602 // Validate Structure length
603 if ((*PccSubspaceLength
== 0) ||
604 ((Offset
+ (*PccSubspaceLength
)) > AcpiTableLength
))
606 IncrementErrorCount ();
608 L
"ERROR: Invalid Structure length. " \
609 L
"Length = %u. Offset = %u. AcpiTableLength = %u.\n",
617 switch (*PccSubspaceType
) {
618 case EFI_ACPI_6_4_PCCT_SUBSPACE_TYPE_GENERIC
:
619 DumpPccSubspaceType0 (
624 case EFI_ACPI_6_4_PCCT_SUBSPACE_TYPE_1_HW_REDUCED_COMMUNICATIONS
:
625 DumpPccSubspaceType1 (
630 case EFI_ACPI_6_4_PCCT_SUBSPACE_TYPE_2_HW_REDUCED_COMMUNICATIONS
:
631 DumpPccSubspaceType2 (
636 case EFI_ACPI_6_4_PCCT_SUBSPACE_TYPE_3_EXTENDED_PCC
:
637 DumpPccSubspaceType3 (
642 case EFI_ACPI_6_4_PCCT_SUBSPACE_TYPE_4_EXTENDED_PCC
:
643 DumpPccSubspaceType4 (
648 case EFI_ACPI_6_4_PCCT_SUBSPACE_TYPE_5_HW_REGISTERS_COMMUNICATIONS
:
649 DumpPccSubspaceType5 (
655 IncrementErrorCount ();
657 L
"ERROR: Unknown PCC subspace structure:"
658 L
" Type = %u, Length = %u\n",
664 PccSubspacePtr
+= *PccSubspaceLength
;
665 Offset
+= *PccSubspaceLength
;
669 if (SubspaceCount
> MAX_PCC_SUBSPACES
) {
670 IncrementErrorCount ();
671 Print (L
"ERROR: Too many PCC subspaces.");