| /** @file | |
| PCCT table parser | |
| Copyright (c) 2021 - 2024, Arm Limited. All rights reserved. | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| @par Reference(s): | |
| - ACPI 6.4 Specification - January 2021 | |
| **/ | |
| #include <Library/BaseMemoryLib.h> | |
| #include <Library/PrintLib.h> | |
| #include <Library/UefiLib.h> | |
| #include "AcpiParser.h" | |
| #include "AcpiView.h" | |
| #include "AcpiViewConfig.h" | |
| #include "PcctParser.h" | |
| // Local variables | |
| STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo; | |
| STATIC UINT32 *PccGlobalFlags; | |
| STATIC UINT8 *PccSubspaceLength; | |
| STATIC UINT8 *PccSubspaceType; | |
| STATIC UINT8 *ExtendedPccSubspaceInterruptFlags; | |
| /** | |
| This function validates the length coded on 4 bytes of a shared memory range | |
| @param [in] Ptr Pointer to the start of the field data. | |
| @param [in] Length Length of the field. | |
| @param [in] Context Pointer to context specific information e.g. this | |
| could be a pointer to the ACPI table header. | |
| **/ | |
| STATIC | |
| VOID | |
| EFIAPI | |
| ValidateRangeLength4 ( | |
| IN UINT8 *Ptr, | |
| IN UINT32 Length, | |
| IN VOID *Context | |
| ) | |
| { | |
| if (*(UINT32 *)Ptr < MIN_EXT_PCC_SUBSPACE_MEM_RANGE_LEN) { | |
| IncrementErrorCount (); | |
| Print ( | |
| L"\nError: Shared memory range length is too short.\n" | |
| L"Length is %u when it should be greater than or equal to %u", | |
| *(UINT32 *)Ptr, | |
| MIN_EXT_PCC_SUBSPACE_MEM_RANGE_LEN | |
| ); | |
| } | |
| } | |
| /** | |
| This function validates the length coded on 8 bytes of a shared memory range | |
| @param [in] Ptr Pointer to the start of the field data. | |
| @param [in] Length Length of the field. | |
| @param [in] Context Pointer to context specific information e.g. this | |
| could be a pointer to the ACPI table header. | |
| **/ | |
| STATIC | |
| VOID | |
| EFIAPI | |
| ValidateRangeLength8 ( | |
| IN UINT8 *Ptr, | |
| IN UINT32 Length, | |
| IN VOID *Context | |
| ) | |
| { | |
| if (*(UINT64 *)Ptr <= MIN_MEMORY_RANGE_LENGTH) { | |
| IncrementErrorCount (); | |
| Print ( | |
| L"\nError: Shared memory range length is too short.\n" | |
| L"Length is %u when it should be greater than %u", | |
| *(UINT64 *)Ptr, | |
| MIN_MEMORY_RANGE_LENGTH | |
| ); | |
| } | |
| } | |
| /** | |
| This function validates address space for Memory/IO GAS. | |
| @param [in] Ptr Pointer to the start of the field data. | |
| @param [in] Length Length of the field. | |
| @param [in] Context Pointer to context specific information e.g. this | |
| could be a pointer to the ACPI table header. | |
| **/ | |
| STATIC | |
| VOID | |
| EFIAPI | |
| ValidatePccMemoryIoGas ( | |
| IN UINT8 *Ptr, | |
| IN UINT32 Length, | |
| IN VOID *Context | |
| ) | |
| { | |
| switch (*(UINT8 *)Ptr) { | |
| #if !(defined (MDE_CPU_AARCH64)) | |
| case EFI_ACPI_6_4_SYSTEM_IO: | |
| #endif //if not (defined (MDE_CPU_AARCH64)) | |
| case EFI_ACPI_6_4_SYSTEM_MEMORY: | |
| return; | |
| default: | |
| IncrementErrorCount (); | |
| Print (L"\nError: Invalid address space"); | |
| } | |
| } | |
| /** | |
| This function validates address space for structures of types other than 0. | |
| @param [in] Ptr Pointer to the start of the field data. | |
| @param [in] Length Length of the field. | |
| @param [in] Context Pointer to context specific information e.g. this | |
| could be a pointer to the ACPI table header. | |
| **/ | |
| STATIC | |
| VOID | |
| EFIAPI | |
| ValidatePccGas ( | |
| IN UINT8 *Ptr, | |
| IN UINT32 Length, | |
| IN VOID *Context | |
| ) | |
| { | |
| switch (*(UINT8 *)Ptr) { | |
| #if !(defined (MDE_CPU_AARCH64)) | |
| case EFI_ACPI_6_4_SYSTEM_IO: | |
| #endif //if not (defined (MDE_CPU_AARCH64)) | |
| case EFI_ACPI_6_4_FUNCTIONAL_FIXED_HARDWARE: | |
| case EFI_ACPI_6_4_SYSTEM_MEMORY: | |
| return; | |
| default: | |
| IncrementErrorCount (); | |
| Print (L"\nError: Invalid address space"); | |
| } | |
| } | |
| /** | |
| This function validates doorbell address space for type 4 structure. | |
| @param [in] Ptr Pointer to the start of the field data. | |
| @param [in] Length Length of the field. | |
| @param [in] Context Pointer to context specific information e.g. this | |
| could be a pointer to the ACPI table header. | |
| **/ | |
| STATIC | |
| VOID | |
| EFIAPI | |
| ValidatePccDoorbellGas ( | |
| IN UINT8 *Ptr, | |
| IN UINT32 Length, | |
| IN VOID *Context | |
| ) | |
| { | |
| // For responder subspaces this field is optional, if not present the field | |
| // should just contain zeros. | |
| if (*PccSubspaceType == EFI_ACPI_6_4_PCCT_SUBSPACE_TYPE_4_EXTENDED_PCC) { | |
| if (IsZeroBuffer ( | |
| Ptr, | |
| sizeof (EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE) | |
| )) | |
| { | |
| return; | |
| } | |
| } | |
| ValidatePccGas (Ptr, Length, Context); | |
| } | |
| /** | |
| This function validates interrupt acknowledge address space for | |
| type 4 structure. | |
| @param [in] Ptr Pointer to the start of the field data. | |
| @param [in] Length Length of the field. | |
| @param [in] Context Pointer to context specific information e.g. this | |
| could be a pointer to the ACPI table header. | |
| **/ | |
| STATIC | |
| VOID | |
| EFIAPI | |
| ValidatePccIntAckGas ( | |
| IN UINT8 *Ptr, | |
| IN UINT32 Length, | |
| IN VOID *Context | |
| ) | |
| { | |
| // If the subspace does not support interrupts or the interrupt is | |
| // edge driven the register may be omitted. A value of 0x0 on all | |
| // 12 bytes of the GAS structure indicates the register is not | |
| // present. | |
| if (((*PccGlobalFlags & EFI_ACPI_6_4_PCCT_FLAGS_PLATFORM_INTERRUPT) != | |
| EFI_ACPI_6_4_PCCT_FLAGS_PLATFORM_INTERRUPT) || | |
| ((*ExtendedPccSubspaceInterruptFlags & | |
| EFI_ACPI_6_4_PCCT_SUBSPACE_PLATFORM_INTERRUPT_FLAGS_MODE) == | |
| EFI_ACPI_6_4_PCCT_SUBSPACE_PLATFORM_INTERRUPT_FLAGS_MODE)) | |
| { | |
| if (IsZeroBuffer ( | |
| Ptr, | |
| sizeof (EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE) | |
| )) | |
| { | |
| return; | |
| } | |
| } | |
| ValidatePccGas (Ptr, Length, Context); | |
| } | |
| /** | |
| This function validates error status address space for type 4 structure. | |
| @param [in] Ptr Pointer to the start of the field data. | |
| @param [in] Length Length of the field. | |
| @param [in] Context Pointer to context specific information e.g. this | |
| could be a pointer to the ACPI table header. | |
| **/ | |
| STATIC | |
| VOID | |
| EFIAPI | |
| ValidatePccErrStatusGas ( | |
| IN UINT8 *Ptr, | |
| IN UINT32 Length, | |
| IN VOID *Context | |
| ) | |
| { | |
| // This field is ignored by the OSPM on responder channels. | |
| if (*PccSubspaceType == EFI_ACPI_6_4_PCCT_SUBSPACE_TYPE_4_EXTENDED_PCC) { | |
| return; | |
| } | |
| ValidatePccGas (Ptr, Length, Context); | |
| } | |
| /** | |
| This function validates platform interrupt flags for type 4 structure. | |
| @param [in] Ptr Pointer to the start of the field data. | |
| @param [in] Length Length of the field. | |
| @param [in] Context Pointer to context specific information e.g. this | |
| could be a pointer to the ACPI table header. | |
| **/ | |
| STATIC | |
| VOID | |
| EFIAPI | |
| ValidatePlatInterrupt ( | |
| IN UINT8 *Ptr, | |
| IN UINT32 Length, | |
| IN VOID *Context | |
| ) | |
| { | |
| // If a responder subspace is present in the PCCT, then the global Platform | |
| // Interrupt flag must be set to 1. | |
| if ((*PccSubspaceType == EFI_ACPI_6_4_PCCT_SUBSPACE_TYPE_4_EXTENDED_PCC) && | |
| ((*PccGlobalFlags & EFI_ACPI_6_4_PCCT_FLAGS_PLATFORM_INTERRUPT) != | |
| EFI_ACPI_6_4_PCCT_FLAGS_PLATFORM_INTERRUPT)) | |
| { | |
| IncrementErrorCount (); | |
| Print ( | |
| L"\nError: Global Platform interrupt flag must be set to 1" \ | |
| L" if a PCC type 4 structure is present in PCCT." | |
| ); | |
| } | |
| } | |
| /** | |
| An ACPI_PARSER array describing the ACPI PCCT Table. | |
| */ | |
| STATIC CONST ACPI_PARSER PcctParser[] = { | |
| PARSE_ACPI_HEADER (&AcpiHdrInfo), | |
| { L"Flags", 4, 36, NULL, NULL, (VOID **)&PccGlobalFlags, NULL, NULL }, | |
| { L"Reserved", 8, 40, NULL, NULL, NULL, NULL, NULL } | |
| }; | |
| /** | |
| An ACPI_PARSER array describing the platform communications channel subspace | |
| structure header. | |
| */ | |
| STATIC CONST ACPI_PARSER PccSubspaceHeaderParser[] = { | |
| PCC_SUBSPACE_HEADER () | |
| // ... Type Specific Fields ... | |
| }; | |
| /** | |
| An ACPI_PARSER array describing the Generic Communications Subspace - Type 0 | |
| */ | |
| STATIC CONST ACPI_PARSER PccSubspaceType0Parser[] = { | |
| PCC_SUBSPACE_HEADER (), | |
| { L"Reserved", 6, 2, L"%x %x %x %x %x %x", Dump6Chars, NULL, NULL, NULL }, | |
| { L"Base Address", 8, 8, L"0x%lx", NULL, NULL, NULL, NULL }, | |
| { L"Memory Range Length",8, 16, L"0x%lx", NULL, NULL, ValidateRangeLength8, | |
| NULL }, | |
| { L"Doorbell Register",12, 24, NULL, DumpGas, NULL, ValidatePccMemoryIoGas, | |
| NULL }, | |
| { L"Doorbell Preserve",8, 36, L"0x%lx", NULL, NULL, NULL, NULL }, | |
| { L"Doorbell Write", 8, 44, L"0x%lx", NULL, NULL, NULL, NULL }, | |
| { L"Nominal Latency", 4, 52, L"%u", NULL, NULL, NULL, NULL }, | |
| { L"Maximum Periodic Access Rate",4, 56, L"%u", NULL, NULL, NULL, NULL }, | |
| { L"Minimum Request Turnaround Time",2, 60, L"%u", NULL, NULL, NULL, NULL } | |
| }; | |
| /** | |
| An ACPI_PARSER array describing the HW-Reduced Communications Subspace | |
| - Type 1 | |
| */ | |
| STATIC CONST ACPI_PARSER PccSubspaceType1Parser[] = { | |
| PCC_SUBSPACE_HEADER (), | |
| { L"Platform Interrupt",4, 2, L"0x%x", NULL, NULL, NULL, NULL }, | |
| { L"Platform Interrupt Flags",1, 6, L"0x%x", NULL, NULL, NULL, NULL }, | |
| { L"Reserved", 1, 7, L"0x%x", NULL, NULL, NULL, NULL }, | |
| { L"Base Address", 8, 8, L"0x%lx", NULL, NULL, NULL, NULL }, | |
| { L"Memory Range Length",8, 16, L"0x%lx", NULL, NULL, ValidateRangeLength8, | |
| NULL }, | |
| { L"Doorbell Register",12, 24, NULL, DumpGas, NULL, | |
| ValidatePccGas, NULL }, | |
| { L"Doorbell Preserve",8, 36, L"0x%lx", NULL, NULL, NULL, NULL }, | |
| { L"Doorbell Write", 8, 44, L"0x%lx", NULL, NULL, NULL, NULL }, | |
| { L"Nominal Latency", 4, 52, L"%u", NULL, NULL, NULL, NULL }, | |
| { L"Maximum Periodic Access Rate",4, 56, L"%u", NULL, NULL, NULL, NULL }, | |
| { L"Minimum Request Turnaround Time",2, 60, L"%u", NULL, NULL, NULL, NULL } | |
| }; | |
| /** | |
| An ACPI_PARSER array describing the HW-Reduced Communications Subspace | |
| - Type 2 | |
| */ | |
| STATIC CONST ACPI_PARSER PccSubspaceType2Parser[] = { | |
| PCC_SUBSPACE_HEADER (), | |
| { L"Platform Interrupt",4, 2, L"0x%x", NULL, NULL, NULL, NULL }, | |
| { L"Platform Interrupt Flags",1, 6, L"0x%x", NULL, NULL, NULL, NULL }, | |
| { L"Reserved", 1, 7, L"0x%x", NULL, NULL, NULL, NULL }, | |
| { L"Base Address", 8, 8, L"0x%lx", NULL, NULL, NULL, NULL }, | |
| { L"Memory Range Length",8, 16, L"0x%lx", NULL, NULL, ValidateRangeLength8, | |
| NULL }, | |
| { L"Doorbell Register",12, 24, NULL, DumpGas, NULL, | |
| ValidatePccGas, NULL }, | |
| { L"Doorbell Preserve",8, 36, L"0x%lx", NULL, NULL, NULL, NULL }, | |
| { L"Doorbell Write", 8, 44, L"0x%lx", NULL, NULL, NULL, NULL }, | |
| { L"Nominal Latency", 4, 52, L"%u", NULL, NULL, NULL, NULL }, | |
| { L"Maximum Periodic Access Rate",4, 56, L"%u", NULL, NULL, NULL, NULL }, | |
| { L"Minimum Request Turnaround Time",2, 60, L"%u", NULL, NULL, NULL, NULL }, | |
| { L"Platform Interrupt Ack Register",12, 62, NULL, DumpGas, NULL, | |
| ValidatePccGas, NULL }, | |
| { L"Platform Interrupt Ack Preserve",8, 74, L"0x%lx", NULL, NULL, NULL, NULL }, | |
| { L"Platform Interrupt Ack Write",8, 82, L"0x%lx", NULL, NULL, | |
| NULL, NULL }, | |
| }; | |
| /** | |
| An ACPI_PARSER array describing the Extended PCC Subspaces - Type 3/4 | |
| */ | |
| STATIC CONST ACPI_PARSER PccSubspaceType3Parser[] = { | |
| PCC_SUBSPACE_HEADER (), | |
| { L"Platform Interrupt", 4, 2, L"0x%x", NULL, NULL, | |
| ValidatePlatInterrupt, NULL }, | |
| { L"Platform Interrupt Flags", 1, 6, L"0x%x", NULL, | |
| (VOID **)&ExtendedPccSubspaceInterruptFlags,NULL, NULL }, | |
| { L"Reserved", 1, 7, L"0x%x", NULL, NULL,NULL, NULL }, | |
| { L"Base Address", 8, 8, L"0x%lx", NULL, NULL,NULL, NULL }, | |
| { L"Memory Range Length", 4, 16, L"0x%x", NULL, NULL,ValidateRangeLength4, | |
| NULL }, | |
| { L"Doorbell Register", 12, 20, NULL, DumpGas, NULL, | |
| ValidatePccDoorbellGas, NULL }, | |
| { L"Doorbell Preserve", 8, 32, L"0x%lx", NULL, NULL,NULL, NULL }, | |
| { L"Doorbell Write", 8, 40, L"0x%lx", NULL, NULL,NULL, NULL }, | |
| { L"Nominal Latency", 4, 48, L"%u", NULL, NULL,NULL, NULL }, | |
| { L"Maximum Periodic Access Rate", 4, 52, L"%u", NULL, NULL,NULL, NULL }, | |
| { L"Minimum Request Turnaround Time", 4, 56, L"%u", NULL, NULL,NULL, NULL }, | |
| { L"Platform Interrupt Ack Register", 12, 60, NULL, DumpGas, NULL, | |
| ValidatePccIntAckGas, NULL }, | |
| { L"Platform Interrupt Ack Preserve", 8, 72, L"0x%lx", NULL, NULL,NULL, NULL }, | |
| { L"Platform Interrupt Ack Set", 8, 80, L"0x%lx", NULL, NULL,NULL, NULL }, | |
| { L"Reserved", 8, 88, L"0x%lx", NULL, NULL,NULL, NULL }, | |
| { L"Cmd Complete Check Reg Addr", 12, 96, NULL, DumpGas, NULL, | |
| ValidatePccGas, NULL }, | |
| { L"Cmd Complete Check Mask", 8, 108, L"0x%lx", NULL, NULL,NULL, NULL }, | |
| { L"Cmd Update Reg Addr", 12, 116, NULL, DumpGas, NULL, | |
| ValidatePccGas, NULL }, | |
| { L"Cmd Update Preserve mask", 8, 128, L"0x%lx", NULL, NULL,NULL, NULL }, | |
| { L"Cmd Update Set mask", 8, 136, L"0x%lx", NULL, NULL,NULL, NULL }, | |
| { L"Error Status Register", 12, 144, NULL, DumpGas, NULL, | |
| ValidatePccErrStatusGas, NULL }, | |
| { L"Error Status Mask", 8, 156, L"0x%lx", NULL, NULL,NULL, NULL }, | |
| }; | |
| /** | |
| An ACPI_PARSER array describing the HW Registers based Communications | |
| Subspace Structure - Type 5 | |
| */ | |
| STATIC CONST ACPI_PARSER PccSubspaceType5Parser[] = { | |
| PCC_SUBSPACE_HEADER (), | |
| { L"Version", 2, 2, L"0x%x", NULL, NULL, NULL, NULL }, | |
| { L"Base Address", 8, 4, L"0x%lx", NULL, NULL, NULL, NULL }, | |
| { L"Shared Memory Range Length",8, 12, L"0x%lx", NULL, NULL, NULL, NULL }, | |
| { L"Doorbell Register", 12, 20, NULL, DumpGas, NULL, | |
| ValidatePccMemoryIoGas,NULL }, | |
| { L"Doorbell Preserve", 8, 32, L"0x%lx", NULL, NULL, NULL, NULL }, | |
| { L"Doorbell Write", 8, 40, L"0x%lx", NULL, NULL, NULL, NULL }, | |
| { L"Command Complete Check Register",12, 48, NULL, DumpGas, NULL, | |
| ValidatePccMemoryIoGas,NULL }, | |
| { L"Command Complete Check Mask",8, 60, L"0x%lx", NULL, NULL, NULL, NULL }, | |
| { L"Error Status Register",12, 68, NULL, DumpGas, NULL, | |
| ValidatePccMemoryIoGas,NULL }, | |
| { L"Error Status Mask", 8, 80, L"0x%lx", NULL, NULL, NULL, NULL }, | |
| { L"Nominal Latency", 4, 88, L"0x%x", NULL, NULL, NULL, NULL }, | |
| { L"Minimum Request Turnaround Time",4, 92, L"0x%x", NULL, NULL, NULL, NULL } | |
| }; | |
| /** | |
| This function parses the PCC Subspace type 0. | |
| @param [in] Ptr Pointer to the start of Subspace Structure. | |
| @param [in] Length Length of the Subspace Structure. | |
| **/ | |
| STATIC | |
| VOID | |
| DumpPccSubspaceType0 ( | |
| IN UINT8 *Ptr, | |
| IN UINT8 Length | |
| ) | |
| { | |
| ParseAcpi ( | |
| TRUE, | |
| 2, | |
| "Subspace Type 0", | |
| Ptr, | |
| Length, | |
| PARSER_PARAMS (PccSubspaceType0Parser) | |
| ); | |
| } | |
| /** | |
| This function parses the PCC Subspace type 1. | |
| @param [in] Ptr Pointer to the start of the Subspace Structure. | |
| @param [in] Length Length of the Subspace Structure. | |
| **/ | |
| STATIC | |
| VOID | |
| DumpPccSubspaceType1 ( | |
| IN UINT8 *Ptr, | |
| IN UINT8 Length | |
| ) | |
| { | |
| ParseAcpi ( | |
| TRUE, | |
| 2, | |
| "Subspace Type 1", | |
| Ptr, | |
| Length, | |
| PARSER_PARAMS (PccSubspaceType1Parser) | |
| ); | |
| } | |
| /** | |
| This function parses the PCC Subspace type 2. | |
| @param [in] Ptr Pointer to the start of the Subspace Structure. | |
| @param [in] Length Length of the Subspace Structure. | |
| **/ | |
| STATIC | |
| VOID | |
| DumpPccSubspaceType2 ( | |
| IN UINT8 *Ptr, | |
| IN UINT8 Length | |
| ) | |
| { | |
| ParseAcpi ( | |
| TRUE, | |
| 2, | |
| "Subspace Type 2", | |
| Ptr, | |
| Length, | |
| PARSER_PARAMS (PccSubspaceType2Parser) | |
| ); | |
| } | |
| /** | |
| This function parses the PCC Subspace type 3. | |
| @param [in] Ptr Pointer to the start of the Subspace Structure. | |
| @param [in] Length Length of the Subspace Structure. | |
| **/ | |
| STATIC | |
| VOID | |
| DumpPccSubspaceType3 ( | |
| IN UINT8 *Ptr, | |
| IN UINT8 Length | |
| ) | |
| { | |
| ParseAcpi ( | |
| TRUE, | |
| 2, | |
| "Subspace Type 3", | |
| Ptr, | |
| Length, | |
| PARSER_PARAMS (PccSubspaceType3Parser) | |
| ); | |
| } | |
| /** | |
| This function parses the PCC Subspace type 4. | |
| @param [in] Ptr Pointer to the start of the Subspace Structure. | |
| @param [in] Length Length of the Subspace Structure. | |
| **/ | |
| STATIC | |
| VOID | |
| DumpPccSubspaceType4 ( | |
| IN UINT8 *Ptr, | |
| IN UINT8 Length | |
| ) | |
| { | |
| ParseAcpi ( | |
| TRUE, | |
| 2, | |
| "Subspace Type 4", | |
| Ptr, | |
| Length, | |
| PARSER_PARAMS (PccSubspaceType3Parser) | |
| ); | |
| } | |
| /** | |
| This function parses the PCC Subspace type 5. | |
| @param [in] Ptr Pointer to the start of the Subspace Structure. | |
| @param [in] Length Length of the Subspace Structure. | |
| **/ | |
| STATIC | |
| VOID | |
| DumpPccSubspaceType5 ( | |
| IN UINT8 *Ptr, | |
| IN UINT8 Length | |
| ) | |
| { | |
| ParseAcpi ( | |
| TRUE, | |
| 2, | |
| "Subspace Type 5", | |
| Ptr, | |
| Length, | |
| PARSER_PARAMS (PccSubspaceType5Parser) | |
| ); | |
| } | |
| /** | |
| This function parses the ACPI PCCT table including its sub-structures | |
| of type 0 through 4. | |
| When trace is enabled this function parses the PCCT table and | |
| 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 | |
| ParseAcpiPcct ( | |
| IN BOOLEAN Trace, | |
| IN UINT8 *Ptr, | |
| IN UINT32 AcpiTableLength, | |
| IN UINT8 AcpiTableRevision | |
| ) | |
| { | |
| UINT32 Offset; | |
| UINT8 *PccSubspacePtr; | |
| UINTN SubspaceCount; | |
| if (!Trace) { | |
| return; | |
| } | |
| Offset = ParseAcpi ( | |
| TRUE, | |
| 0, | |
| "PCCT", | |
| Ptr, | |
| AcpiTableLength, | |
| PARSER_PARAMS (PcctParser) | |
| ); | |
| PccSubspacePtr = Ptr + Offset; | |
| SubspaceCount = 0; | |
| while (Offset < AcpiTableLength) { | |
| // Parse common structure header to obtain Type and Length. | |
| ParseAcpi ( | |
| FALSE, | |
| 0, | |
| NULL, | |
| PccSubspacePtr, | |
| AcpiTableLength - Offset, | |
| PARSER_PARAMS (PccSubspaceHeaderParser) | |
| ); | |
| // Check if the values used to control the parsing logic have been | |
| // successfully read. | |
| if ((PccSubspaceType == NULL) || | |
| (PccSubspaceLength == NULL)) | |
| { | |
| IncrementErrorCount (); | |
| Print ( | |
| L"ERROR: Insufficient remaining table buffer length to read the " \ | |
| L"structure header. Length = %u.\n", | |
| AcpiTableLength - Offset | |
| ); | |
| return; | |
| } | |
| // Validate Structure length | |
| if ((*PccSubspaceLength == 0) || | |
| ((Offset + (*PccSubspaceLength)) > AcpiTableLength)) | |
| { | |
| IncrementErrorCount (); | |
| Print ( | |
| L"ERROR: Invalid Structure length. " \ | |
| L"Length = %u. Offset = %u. AcpiTableLength = %u.\n", | |
| *PccSubspaceLength, | |
| Offset, | |
| AcpiTableLength | |
| ); | |
| return; | |
| } | |
| switch (*PccSubspaceType) { | |
| case EFI_ACPI_6_4_PCCT_SUBSPACE_TYPE_GENERIC: | |
| DumpPccSubspaceType0 ( | |
| PccSubspacePtr, | |
| *PccSubspaceLength | |
| ); | |
| break; | |
| case EFI_ACPI_6_4_PCCT_SUBSPACE_TYPE_1_HW_REDUCED_COMMUNICATIONS: | |
| DumpPccSubspaceType1 ( | |
| PccSubspacePtr, | |
| *PccSubspaceLength | |
| ); | |
| break; | |
| case EFI_ACPI_6_4_PCCT_SUBSPACE_TYPE_2_HW_REDUCED_COMMUNICATIONS: | |
| DumpPccSubspaceType2 ( | |
| PccSubspacePtr, | |
| *PccSubspaceLength | |
| ); | |
| break; | |
| case EFI_ACPI_6_4_PCCT_SUBSPACE_TYPE_3_EXTENDED_PCC: | |
| DumpPccSubspaceType3 ( | |
| PccSubspacePtr, | |
| *PccSubspaceLength | |
| ); | |
| break; | |
| case EFI_ACPI_6_4_PCCT_SUBSPACE_TYPE_4_EXTENDED_PCC: | |
| DumpPccSubspaceType4 ( | |
| PccSubspacePtr, | |
| *PccSubspaceLength | |
| ); | |
| break; | |
| case EFI_ACPI_6_4_PCCT_SUBSPACE_TYPE_5_HW_REGISTERS_COMMUNICATIONS: | |
| DumpPccSubspaceType5 ( | |
| PccSubspacePtr, | |
| *PccSubspaceLength | |
| ); | |
| break; | |
| default: | |
| IncrementErrorCount (); | |
| Print ( | |
| L"ERROR: Unknown PCC subspace structure:" | |
| L" Type = %u, Length = %u\n", | |
| PccSubspaceType, | |
| *PccSubspaceLength | |
| ); | |
| } | |
| PccSubspacePtr += *PccSubspaceLength; | |
| Offset += *PccSubspaceLength; | |
| SubspaceCount++; | |
| } // while | |
| if (SubspaceCount > MAX_PCC_SUBSPACES) { | |
| IncrementErrorCount (); | |
| Print (L"ERROR: Too many PCC subspaces."); | |
| } | |
| } |