Date   

[PATCH v1 10/14] DynamicTablesPkg: FdtHwInfoParser: Add ITS parser

PierreGondois
 

From: Pierre Gondois <Pierre.Gondois@...>

Arm GIC v3/v4 optionally includes support for GIC Interrupt
Translation Service (ITS). The GIC ITS Structure is part of
the Multiple APIC Description Table (MADT) that describes
the GIC Interrupt Translation service to the OS.

The GIC Interrupt Translation Service information is described
in the platform Device Tree, the bindings for which can be
found at:
- linux/Documentation/devicetree/bindings/interrupt-controller/
arm,gic-v3.yaml

The FdtHwInfoParser implements a GIC ITS Parser that parses the
platform Device Tree to create CM_ARM_GIC_ITS_INFO objects which
are encapsulated in a Configuration Manager descriptor object and
added to the platform information repository.

The platform Configuration Manager can then utilise this information
when generating the MADT table.

Signed-off-by: Pierre Gondois <Pierre.Gondois@...>
Signed-off-by: Sami Mujawar <sami.mujawar@...>
---
.../FdtHwInfoParserLib/Gic/ArmGicItsParser.c | 215 ++++++++++++++++++
.../FdtHwInfoParserLib/Gic/ArmGicItsParser.h | 48 ++++
2 files changed, 263 insertions(+)
create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicItsParser.c
create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicItsParser.h

diff --git a/DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicItsParser.c b/DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicItsParser.c
new file mode 100644
index 000000000000..faaa0df1d9be
--- /dev/null
+++ b/DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicItsParser.c
@@ -0,0 +1,215 @@
+/** @file
+ Arm Gic Interrupt Translation Service Parser.
+
+ Copyright (c) 2021, ARM Limited. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - linux/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml
+**/
+
+#include "CmObjectDescUtility.h"
+#include "FdtHwInfoParser.h"
+#include "Gic/ArmGicDispatcher.h"
+#include "Gic/ArmGicItsParser.h"
+
+/** Parse a Gic compatible interrupt-controller node,
+ extracting GicIts information.
+
+ This parser is valid for Gic v3 and higher.
+
+ @param [in] Fdt Pointer to a Flattened Device Tree (Fdt).
+ @param [in] GicIntcNode Offset of a Gic compatible
+ interrupt-controller node.
+ @param [in] GicItsId Id for the Gic ITS node.
+ @param [in] GicItsInfo The CM_ARM_GIC_ITS_INFO to populate.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GicItsIntcNodeParser (
+ IN CONST VOID * Fdt,
+ IN INT32 GicIntcNode,
+ IN UINT32 GicItsId,
+ IN CM_ARM_GIC_ITS_INFO * GicItsInfo
+ )
+{
+ EFI_STATUS Status;
+ INT32 AddressCells;
+ CONST UINT8 * Data;
+ INT32 DataSize;
+
+ if ((Fdt == NULL) ||
+ (GicItsInfo == NULL)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = FdtGetParentAddressInfo (Fdt, GicIntcNode, &AddressCells, NULL);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Don't support more than 64 bits and less than 32 bits addresses.
+ if ((AddressCells < 1) ||
+ (AddressCells > 2)) {
+ ASSERT (0);
+ return EFI_ABORTED;
+ }
+
+ Data = fdt_getprop (Fdt, GicIntcNode, "reg", &DataSize);
+ if ((Data == NULL) || (DataSize < (INT32)(AddressCells * sizeof (UINT32)))) {
+ // If error or not enough space.
+ ASSERT (0);
+ return EFI_ABORTED;
+ }
+
+ if (AddressCells == 2) {
+ GicItsInfo->PhysicalBaseAddress = fdt64_to_cpu (*(UINT64*)Data);
+ } else {
+ GicItsInfo->PhysicalBaseAddress = fdt32_to_cpu (*(UINT32*)Data);
+ }
+
+ // Gic Its Id
+ GicItsInfo->GicItsId = GicItsId;
+
+ // {default = 0}
+ GicItsInfo->ProximityDomain = 0;
+ return Status;
+}
+
+/** CM_ARM_GIC_ITS_INFO parser function.
+
+ This parser expects FdtBranch to be a Gic interrupt-controller node.
+ Gic version must be v3 or higher.
+ typedef struct CmArmGicItsInfo {
+ UINT32 GicItsId; // {Populated}
+ UINT64 PhysicalBaseAddress; // {Populated}
+ UINT32 ProximityDomain; // {default = 0}
+ } CM_ARM_GIC_ITS_INFO;
+
+ A parser parses a Device Tree to populate a specific CmObj type. None,
+ one or many CmObj can be created by the parser.
+ The created CmObj are then handed to the parser's caller through the
+ HW_INFO_ADD_OBJECT interface.
+ This can also be a dispatcher. I.e. a function that not parsing a
+ Device Tree but calling other parsers.
+
+ @param [in] FdtParserHandle A handle to the parser instance.
+ @param [in] FdtBranch When searching for DT node name, restrict
+ the search to this Device Tree branch.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND Not found.
+ @retval EFI_UNSUPPORTED Unsupported.
+**/
+EFI_STATUS
+EFIAPI
+ArmGicItsInfoParser (
+ IN CONST FDT_HW_INFO_PARSER_HANDLE FdtParserHandle,
+ IN INT32 FdtBranch
+ )
+{
+ EFI_STATUS Status;
+ UINT32 GicVersion;
+ CM_ARM_GIC_ITS_INFO GicItsInfo;
+ UINT32 Index;
+ INT32 GicItsNode;
+ UINT32 GicItsNodeCount;
+ VOID * Fdt;
+
+ if (FdtParserHandle == NULL) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Fdt = FdtParserHandle->Fdt;
+
+ if (!FdtNodeHasProperty (Fdt, FdtBranch, "interrupt-controller")) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Get the Gic version of the interrupt-controller.
+ Status = GetGicVersion (Fdt, FdtBranch, &GicVersion);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ if (GicVersion < 3) {
+ ASSERT (0);
+ return EFI_UNSUPPORTED;
+ }
+
+ // Count the nodes with the "msi-controller" property.
+ // The interrupt-controller itself can have this property,
+ // but the first node is skipped in the search.
+ Status = FdtCountPropNodeInBranch (
+ Fdt,
+ FdtBranch,
+ "msi-controller",
+ &GicItsNodeCount
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ if (GicItsNodeCount == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ GicItsNode = FdtBranch;
+ for (Index = 0; Index < GicItsNodeCount; Index++) {
+ ZeroMem (&GicItsInfo, sizeof (CM_ARM_GIC_ITS_INFO));
+
+ Status = FdtGetNextPropNodeInBranch (
+ Fdt,
+ FdtBranch,
+ "msi-controller",
+ &GicItsNode
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ if (Status == EFI_NOT_FOUND) {
+ // Should have found the node.
+ Status = EFI_ABORTED;
+ }
+ return Status;
+ }
+
+ Status = GicItsIntcNodeParser (
+ Fdt,
+ GicItsNode,
+ Index,
+ &GicItsInfo
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Add the CmObj to the Configuration Manager.
+ Status = AddSingleCmObj (
+ FdtParserHandle,
+ CREATE_CM_ARM_OBJECT_ID (EArmObjGicItsInfo),
+ &GicItsInfo,
+ sizeof (CM_ARM_GIC_ITS_INFO),
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+ } // for
+
+ return Status;
+}
diff --git a/DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicItsParser.h b/DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicItsParser.h
new file mode 100644
index 000000000000..6ea498ff71c9
--- /dev/null
+++ b/DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicItsParser.h
@@ -0,0 +1,48 @@
+/** @file
+ Arm Gic Interrupt Translation Service Parser.
+
+ Copyright (c) 2021, ARM Limited. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - linux/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml
+**/
+
+#ifndef ARM_GIC_ITS_PARSER_H_
+#define ARM_GIC_ITS_PARSER_H_
+
+/** CM_ARM_GIC_ITS_INFO parser function.
+
+ This parser expects FdtBranch to be a Gic interrupt-controller node.
+ Gic version must be v3 or higher.
+ typedef struct CmArmGicItsInfo {
+ UINT32 GicItsId; // {Populated}
+ UINT64 PhysicalBaseAddress; // {Populated}
+ UINT32 ProximityDomain; // {default = 0}
+ } CM_ARM_GIC_ITS_INFO;
+
+ A parser parses a Device Tree to populate a specific CmObj type. None,
+ one or many CmObj can be created by the parser.
+ The created CmObj are then handed to the parser's caller through the
+ HW_INFO_ADD_OBJECT interface.
+ This can also be a dispatcher. I.e. a function that not parsing a
+ Device Tree but calling other parsers.
+
+ @param [in] FdtParserHandle A handle to the parser instance.
+ @param [in] FdtBranch When searching for DT node name, restrict
+ the search to this Device Tree branch.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND Not found.
+ @retval EFI_UNSUPPORTED Unsupported.
+**/
+EFI_STATUS
+EFIAPI
+ArmGicItsInfoParser (
+ IN CONST FDT_HW_INFO_PARSER_HANDLE FdtParserHandle,
+ IN INT32 FdtBranch
+ );
+
+#endif // ARM_GIC_ITS_PARSER_H_
--
2.17.1


[PATCH v1 09/14] DynamicTablesPkg: FdtHwInfoParser: Add MSI Frame parser

PierreGondois
 

From: Pierre Gondois <Pierre.Gondois@...>

Arm GIC version 2 systems that support Message Signalled Interrupts
implement GICv2m MSI frame(s). Each GICv2m MSI frame consists of a
4k page which includes registers to generate message signalled
interrupts to an associated GIC distributor. The frame also includes
registers to discover the set of distributor lines which may be
signalled by MSIs from that frame. A system may have multiple MSI
frames, and separate frames may be defined for secure and non-secure
access.

A MSI Frame structure is part of the Multiple APIC Description Table
(MADT) and must only be used to describe non-secure MSI frames.

The MSI Frame information is described in the platform Device Tree,
the bindings for which can be found at:
- linux/Documentation/devicetree/bindings/interrupt-controller/
arm,gic.yaml
- linux/Documentation/devicetree/bindings/interrupt-controller/
arm,gic-v3.yaml

The FdtHwInfoParser implements a MSI Frame Parser that parses
the platform Device Tree to create CM_ARM_GIC_MSI_FRAME_INFO
objects which are encapsulated in a Configuration Manager
descriptor object and added to the platform information
repository.

The platform Configuration Manager can then utilise this
information when generating the MADT table.

Signed-off-by: Pierre Gondois <Pierre.Gondois@...>
Signed-off-by: Sami Mujawar <sami.mujawar@...>
---
.../Gic/ArmGicMsiFrameParser.c | 214 ++++++++++++++++++
.../Gic/ArmGicMsiFrameParser.h | 50 ++++
2 files changed, 264 insertions(+)
create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicMsiFrameParser.c
create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicMsiFrameParser.h

diff --git a/DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicMsiFrameParser.c b/DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicMsiFrameParser.c
new file mode 100644
index 000000000000..9e6715f69ce7
--- /dev/null
+++ b/DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicMsiFrameParser.c
@@ -0,0 +1,214 @@
+/** @file
+ Arm Gic Msi frame Parser.
+
+ Copyright (c) 2021, ARM Limited. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - linux/Documentation/devicetree/bindings/interrupt-controller/arm,gic.yaml
+ - linux/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml
+**/
+
+#include "CmObjectDescUtility.h"
+#include "FdtHwInfoParser.h"
+#include "Gic/ArmGicDispatcher.h"
+#include "Gic/ArmGicMsiFrameParser.h"
+
+/** List of "compatible" property values for Msi-frame nodes.
+
+ Any other "compatible" value is not supported by this module.
+*/
+STATIC CONST COMPATIBILITY_STR MsiFrameCompatibleStr[] = {
+ {"arm,gic-v2m-frame"}
+};
+
+/** COMPATIBILITY_INFO structure for the MSI frame.
+*/
+STATIC CONST COMPATIBILITY_INFO MsiFrameCompatibleInfo = {
+ ARRAY_SIZE (MsiFrameCompatibleStr),
+ MsiFrameCompatibleStr
+};
+
+/** Parse a Msi frame node.
+
+ @param [in] Fdt Pointer to a Flattened Device Tree (Fdt).
+ @param [in] MsiFrameNode Offset of a Msi frame node.
+ @param [in] MsiFrameId Frame ID.
+ @param [out] MsiFrameInfo The CM_ARM_GIC_MSI_FRAME_INFO to populate.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+MsiFrameNodeParser (
+ IN CONST VOID * Fdt,
+ IN INT32 MsiFrameNode,
+ IN UINT32 MsiFrameId,
+ OUT CM_ARM_GIC_MSI_FRAME_INFO * MsiFrameInfo
+ )
+{
+ EFI_STATUS Status;
+ INT32 AddressCells;
+ CONST UINT8 * Data;
+ INT32 DataSize;
+
+ if ((Fdt == NULL) ||
+ (MsiFrameInfo == NULL)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = FdtGetParentAddressInfo (Fdt, MsiFrameNode, &AddressCells, NULL);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Don't support more than 64 bits and less than 32 bits addresses.
+ if ((AddressCells < 1) ||
+ (AddressCells > 2)) {
+ ASSERT (0);
+ return EFI_ABORTED;
+ }
+
+ Data = fdt_getprop (Fdt, MsiFrameNode, "reg", &DataSize);
+ if ((Data == NULL) || (DataSize < (INT32)(AddressCells * sizeof (UINT32)))) {
+ // If error or not enough space.
+ ASSERT (0);
+ return EFI_ABORTED;
+ }
+
+ if (AddressCells == 2) {
+ MsiFrameInfo->PhysicalBaseAddress = fdt64_to_cpu (*(UINT64*)Data);
+ } else {
+ MsiFrameInfo->PhysicalBaseAddress = fdt32_to_cpu (*(UINT32*)Data);
+ }
+
+ MsiFrameInfo->GicMsiFrameId = MsiFrameId;
+
+ return EFI_SUCCESS;
+}
+
+/** CM_ARM_GIC_MSI_FRAME_INFO parser function.
+
+ The following structure is populated:
+ typedef struct CmArmGicMsiFrameInfo {
+ UINT32 GicMsiFrameId; // {Populated}
+ UINT64 PhysicalBaseAddress; // {Populated}
+ UINT32 Flags; // {default = 0}
+ UINT16 SPICount;
+ UINT16 SPIBase;
+ } CM_ARM_GIC_MSI_FRAME_INFO;
+
+ A parser parses a Device Tree to populate a specific CmObj type. None,
+ one or many CmObj can be created by the parser.
+ The created CmObj are then handed to the parser's caller through the
+ HW_INFO_ADD_OBJECT interface.
+ This can also be a dispatcher. I.e. a function that not parsing a
+ Device Tree but calling other parsers.
+
+ @param [in] FdtParserHandle A handle to the parser instance.
+ @param [in] FdtBranch When searching for DT node name, restrict
+ the search to this Device Tree branch.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND Not found.
+ @retval EFI_UNSUPPORTED Unsupported.
+**/
+EFI_STATUS
+EFIAPI
+ArmGicMsiFrameInfoParser (
+ IN CONST FDT_HW_INFO_PARSER_HANDLE FdtParserHandle,
+ IN INT32 FdtBranch
+ )
+{
+ EFI_STATUS Status;
+ INT32 MsiFrameNode;
+ UINT32 MsiFrameNodeCount;
+
+ UINT32 Index;
+ CM_ARM_GIC_MSI_FRAME_INFO MsiFrameInfo;
+ VOID * Fdt;
+
+ if (FdtParserHandle == NULL) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Fdt = FdtParserHandle->Fdt;
+
+ // Count the number of nodes having the "interrupt-controller" property.
+ Status = FdtCountPropNodeInBranch (
+ Fdt,
+ FdtBranch,
+ "msi-controller",
+ &MsiFrameNodeCount
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ if (MsiFrameNodeCount == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ // Parse each node having the "msi-controller" property.
+ MsiFrameNode = FdtBranch;
+ for (Index = 0; Index < MsiFrameNodeCount; Index++) {
+ ZeroMem (&MsiFrameInfo, sizeof (CM_ARM_GIC_MSI_FRAME_INFO));
+
+ Status = FdtGetNextPropNodeInBranch (
+ Fdt,
+ FdtBranch,
+ "msi-controller",
+ &MsiFrameNode
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ if (Status == EFI_NOT_FOUND) {
+ // Should have found the node.
+ Status = EFI_ABORTED;
+ }
+ return Status;
+ }
+
+ if (!FdtNodeIsCompatible (Fdt, MsiFrameNode, &MsiFrameCompatibleInfo)) {
+ ASSERT (0);
+ Status = EFI_UNSUPPORTED;
+ return Status;
+ }
+
+ // Parse the Msi information.
+ Status = MsiFrameNodeParser (
+ Fdt,
+ MsiFrameNode,
+ Index,
+ &MsiFrameInfo
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Add the CmObj to the Configuration Manager.
+ Status = AddSingleCmObj (
+ FdtParserHandle,
+ CREATE_CM_ARM_OBJECT_ID (EArmObjGicMsiFrameInfo),
+ &MsiFrameInfo,
+ sizeof (CM_ARM_GIC_MSI_FRAME_INFO),
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+ } // for
+
+ return Status;
+}
diff --git a/DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicMsiFrameParser.h b/DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicMsiFrameParser.h
new file mode 100644
index 000000000000..40f83010a686
--- /dev/null
+++ b/DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicMsiFrameParser.h
@@ -0,0 +1,50 @@
+/** @file
+ Arm Gic Msi frame Parser.
+
+ Copyright (c) 2021, ARM Limited. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - linux/Documentation/devicetree/bindings/interrupt-controller/arm,gic.yaml
+ - linux/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml
+**/
+
+#ifndef ARM_GIC_MSI_FRAME_PARSER_H_
+#define ARM_GIC_MSI_FRAME_PARSER_H_
+
+/** CM_ARM_GIC_MSI_FRAME_INFO parser function.
+
+ The following structure is populated:
+ typedef struct CmArmGicMsiFrameInfo {
+ UINT32 GicMsiFrameId; // {Populated}
+ UINT64 PhysicalBaseAddress; // {Populated}
+ UINT32 Flags; // {default = 0}
+ UINT16 SPICount;
+ UINT16 SPIBase;
+ } CM_ARM_GIC_MSI_FRAME_INFO;
+
+ A parser parses a Device Tree to populate a specific CmObj type. None,
+ one or many CmObj can be created by the parser.
+ The created CmObj are then handed to the parser's caller through the
+ HW_INFO_ADD_OBJECT interface.
+ This can also be a dispatcher. I.e. a function that not parsing a
+ Device Tree but calling other parsers.
+
+ @param [in] FdtParserHandle A handle to the parser instance.
+ @param [in] FdtBranch When searching for DT node name, restrict
+ the search to this Device Tree branch.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND Not found.
+ @retval EFI_UNSUPPORTED Unsupported.
+**/
+EFI_STATUS
+EFIAPI
+ArmGicMsiFrameInfoParser (
+ IN CONST FDT_HW_INFO_PARSER_HANDLE FdtParserHandle,
+ IN INT32 FdtBranch
+ );
+
+#endif // ARM_GIC_MSI_FRAME_PARSER_H_
--
2.17.1


[PATCH v1 08/14] DynamicTablesPkg: FdtHwInfoParser: Add GICD parser

PierreGondois
 

From: Pierre Gondois <Pierre.Gondois@...>

On ARM-based systems the Generic Interrupt Controller (GIC)
manages interrupts on the system. Each interrupt is identified
in the GIC by an interrupt identifier (INTID). ACPI GSIVs map
one to one to GIC INTIDs for peripheral interrupts, whether
shared (SPI) or private (PPI). The GIC distributor provides
the routing configuration for the interrupts.

The GIC Distributor (GICD) structure is part of the Multiple
APIC Description Table (MADT) that describes the GIC
distributor to the OS. The MADT table is a mandatory table
required for booting a standards-based operating system.

The GIC Distributor information is described in the platform
Device Tree, the bindings for which can be found at:
- linux/Documentation/devicetree/bindings/interrupt-controller/
arm,gic.yaml
- linux/Documentation/devicetree/bindings/interrupt-controller/
arm,gic-v3.yaml

The FdtHwInfoParser implements a GIC Distributor Parser that
parses the platform Device Tree to create CM_ARM_GICD_INFO
object which is encapsulated in a Configuration Manager
descriptor object and added to the platform information
repository.

The platform Configuration Manager can then utilise this
information when generating the MADT table.

Signed-off-by: Pierre Gondois <Pierre.Gondois@...>
Signed-off-by: Sami Mujawar <sami.mujawar@...>
---
.../FdtHwInfoParserLib/Gic/ArmGicDParser.c | 171 ++++++++++++++++++
.../FdtHwInfoParserLib/Gic/ArmGicDParser.h | 50 +++++
2 files changed, 221 insertions(+)
create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicDParser.c
create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicDParser.h

diff --git a/DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicDParser.c b/DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicDParser.c
new file mode 100644
index 000000000000..10207a667336
--- /dev/null
+++ b/DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicDParser.c
@@ -0,0 +1,171 @@
+/** @file
+ Arm Gic Distributor Parser.
+
+ Copyright (c) 2021, ARM Limited. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - linux/Documentation/devicetree/bindings/interrupt-controller/arm,gic.yaml
+ - linux/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml
+**/
+
+#include "CmObjectDescUtility.h"
+#include "FdtHwInfoParser.h"
+#include "Gic/ArmGicDispatcher.h"
+#include "Gic/ArmGicDParser.h"
+
+/** Parse a Gic compatible interrupt-controller node,
+ extracting GicD information.
+
+ This parser is valid for Gic v2 and v3.
+
+ @param [in] Fdt Pointer to a Flattened Device Tree (Fdt).
+ @param [in] GicIntcNode Offset of a Gic compatible
+ interrupt-controller node.
+ @param [in] GicDInfo The CM_ARM_GICD_INFO to populate.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GicDIntcNodeParser (
+ IN CONST VOID * Fdt,
+ IN INT32 GicIntcNode,
+ IN CM_ARM_GICD_INFO * GicDInfo
+ )
+{
+ EFI_STATUS Status;
+ INT32 AddressCells;
+ CONST UINT8 * Data;
+ INT32 DataSize;
+
+ if ((Fdt == NULL) ||
+ (GicDInfo == NULL)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = FdtGetParentAddressInfo (Fdt, GicIntcNode, &AddressCells, NULL);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Don't support more than 64 bits and less than 32 bits addresses.
+ if ((AddressCells < 1) ||
+ (AddressCells > 2)) {
+ ASSERT (0);
+ return EFI_ABORTED;
+ }
+
+ Data = fdt_getprop (Fdt, GicIntcNode, "reg", &DataSize);
+ if ((Data == NULL) || (DataSize < (INT32)(AddressCells * sizeof (UINT32)))) {
+ // If error or not enough space.
+ ASSERT (0);
+ return EFI_ABORTED;
+ }
+
+ if (AddressCells == 2) {
+ GicDInfo->PhysicalBaseAddress = fdt64_to_cpu (*(UINT64*)Data);
+ } else {
+ GicDInfo->PhysicalBaseAddress = fdt32_to_cpu (*(UINT32*)Data);
+ }
+
+ return Status;
+}
+
+/** CM_ARM_GICD_INFO parser function.
+
+ This parser expects FdtBranch to be a Gic interrupt-controller node.
+ At most one CmObj is created.
+ The following structure is populated:
+ typedef struct CmArmGicDInfo {
+ UINT64 PhysicalBaseAddress; // {Populated}
+ UINT32 SystemVectorBase;
+ UINT8 GicVersion; // {Populated}
+ } CM_ARM_GICD_INFO;
+
+ A parser parses a Device Tree to populate a specific CmObj type. None,
+ one or many CmObj can be created by the parser.
+ The created CmObj are then handed to the parser's caller through the
+ HW_INFO_ADD_OBJECT interface.
+ This can also be a dispatcher. I.e. a function that not parsing a
+ Device Tree but calling other parsers.
+
+ @param [in] FdtParserHandle A handle to the parser instance.
+ @param [in] FdtBranch When searching for DT node name, restrict
+ the search to this Device Tree branch.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND Not found.
+ @retval EFI_UNSUPPORTED Unsupported.
+**/
+EFI_STATUS
+EFIAPI
+ArmGicDInfoParser (
+ IN CONST FDT_HW_INFO_PARSER_HANDLE FdtParserHandle,
+ IN INT32 FdtBranch
+ )
+{
+ EFI_STATUS Status;
+ UINT32 GicVersion;
+ CM_ARM_GICD_INFO GicDInfo;
+ VOID * Fdt;
+
+ if (FdtParserHandle == NULL) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Fdt = FdtParserHandle->Fdt;
+
+ if (!FdtNodeHasProperty (Fdt, FdtBranch, "interrupt-controller")) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Get the Gic version of the interrupt-controller.
+ Status = GetGicVersion (Fdt, FdtBranch, &GicVersion);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ ZeroMem (&GicDInfo, sizeof (GicDInfo));
+ GicDInfo.GicVersion = GicVersion;
+
+ // Parse the interrupt-controller depending on its Gic version.
+ switch (GicVersion) {
+ case 2:
+ case 3:
+ {
+ // Set the Gic version, then parse the GicD information.
+ Status = GicDIntcNodeParser (Fdt, FdtBranch, &GicDInfo);
+ break;
+ }
+ default:
+ {
+ // Unsupported Gic version.
+ ASSERT (0);
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ // Add the CmObj to the Configuration Manager.
+ Status = AddSingleCmObj (
+ FdtParserHandle,
+ CREATE_CM_ARM_OBJECT_ID (EArmObjGicDInfo),
+ &GicDInfo,
+ sizeof (CM_ARM_GICD_INFO),
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ }
+ return Status;
+}
diff --git a/DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicDParser.h b/DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicDParser.h
new file mode 100644
index 000000000000..a274a4b43070
--- /dev/null
+++ b/DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicDParser.h
@@ -0,0 +1,50 @@
+/** @file
+ Arm Gic Distributor Parser.
+
+ Copyright (c) 2021, ARM Limited. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - linux/Documentation/devicetree/bindings/interrupt-controller/arm,gic.yaml
+ - linux/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml
+**/
+
+#ifndef ARM_GICD_PARSER_H_
+#define ARM_GICD_PARSER_H_
+
+/** CM_ARM_GICD_INFO parser function.
+
+ This parser expects FdtBranch to be a Gic interrupt-controller node.
+ At most one CmObj is created.
+ The following structure is populated:
+ typedef struct CmArmGicDInfo {
+ UINT64 PhysicalBaseAddress; // {Populated}
+ UINT32 SystemVectorBase;
+ UINT8 GicVersion; // {Populated}
+ } CM_ARM_GICD_INFO;
+
+ A parser parses a Device Tree to populate a specific CmObj type. None,
+ one or many CmObj can be created by the parser.
+ The created CmObj are then handed to the parser's caller through the
+ HW_INFO_ADD_OBJECT interface.
+ This can also be a dispatcher. I.e. a function that not parsing a
+ Device Tree but calling other parsers.
+
+ @param [in] FdtParserHandle A handle to the parser instance.
+ @param [in] FdtBranch When searching for DT node name, restrict
+ the search to this Device Tree branch.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND Not found.
+ @retval EFI_UNSUPPORTED Unsupported.
+**/
+EFI_STATUS
+EFIAPI
+ArmGicDInfoParser (
+ IN CONST FDT_HW_INFO_PARSER_HANDLE FdtParserHandle,
+ IN INT32 FdtBranch
+ );
+
+#endif // ARM_GICD_PARSER_H_
--
2.17.1


[PATCH v1 07/14] DynamicTablesPkg: FdtHwInfoParser: Add GICC parser

PierreGondois
 

From: Pierre Gondois <Pierre.Gondois@...>

The GIC CPU Interface (GICC) structure is part of the Multiple
APIC Description Table (MADT) that describes the interrupt model
for the platform. The MADT table is a mandatory table required
for booting a standards-based operating system.

Arm requires the GIC interrupt model, in which the logical
processors are required to have a Processor Device object in
the DSDT, and must convey each processor’s GIC information to
the OS using the GICC structure.

The CPU and GIC information is described in the platform Device
Tree, the bindings for which can be found at:
- linux/Documentation/devicetree/bindings/arm/cpus.yaml
- linux/Documentation/devicetree/bindings/interrupt-controller/
arm,gic.yaml
- linux/Documentation/devicetree/bindings/interrupt-controller/
arm,gic-v3.yaml

The FdtHwInfoParser implements a GIC CPU Interface Parser that
parses the platform Device Tree to create CM_ARM_GICC_INFO
objects which are encapsulated in a Configuration Manager
descriptor object and added to the platform information
repository.

The platform Configuration Manager can then utilise this
information when generating the MADT and the SSDT CPU
information tables.

Signed-off-by: Pierre Gondois <Pierre.Gondois@...>
Signed-off-by: Sami Mujawar <sami.mujawar@...>
---
.../FdtHwInfoParserLib/Gic/ArmGicCParser.c | 762 ++++++++++++++++++
.../FdtHwInfoParserLib/Gic/ArmGicCParser.h | 67 ++
2 files changed, 829 insertions(+)
create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicCParser.c
create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicCParser.h

diff --git a/DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicCParser.c b/DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicCParser.c
new file mode 100644
index 000000000000..2163888c870e
--- /dev/null
+++ b/DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicCParser.c
@@ -0,0 +1,762 @@
+/** @file
+ Arm Gic cpu parser.
+
+ Copyright (c) 2021, ARM Limited. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - linux/Documentation/devicetree/bindings/arm/cpus.yaml
+ - linux/Documentation/devicetree/bindings/interrupt-controller/arm,gic.yaml
+ - linux/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml
+**/
+
+#include "FdtHwInfoParser.h"
+#include "CmObjectDescUtility.h"
+#include "Gic/ArmGicCParser.h"
+#include "Gic/ArmGicDispatcher.h"
+
+/** List of "compatible" property values for CPU nodes.
+
+ Any other "compatible" value is not supported by this module.
+*/
+STATIC CONST COMPATIBILITY_STR CpuCompatibleStr[] = {
+ {"arm,arm-v7"},
+ {"arm,arm-v8"},
+ {"arm,cortex-a15"},
+ {"arm,cortex-a7"},
+ {"arm,cortex-a57"}
+};
+
+/** COMPATIBILITY_INFO structure for CPU nodes.
+*/
+STATIC CONST COMPATIBILITY_INFO CpuCompatibleInfo = {
+ ARRAY_SIZE (CpuCompatibleStr),
+ CpuCompatibleStr
+};
+
+/** Parse a "cpu" node.
+
+ @param [in] Fdt Pointer to a Flattened Device Tree (Fdt).
+ @param [in] CpuNode Offset of a cpu node.
+ @param [in] GicVersion Version of the GIC.
+ @param [in] AddressCells Number of address cells used for the reg
+ property.
+ @param [out] GicCInfo CM_ARM_GICC_INFO structure to populate.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_UNSUPPORTED Unsupported.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+CpuNodeParser (
+ IN CONST VOID * Fdt,
+ IN INT32 CpuNode,
+ IN UINT32 GicVersion,
+ IN UINT32 AddressCells,
+ OUT CM_ARM_GICC_INFO * GicCInfo
+)
+{
+ UINT32 CpuRegProp;
+ CONST VOID * Data;
+ INT32 DataSize;
+ UINT64 MpIdr;
+
+ if (GicCInfo == NULL) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Data = fdt_getprop (Fdt, CpuNode, "reg", &DataSize);
+ if ((Data == NULL) ||
+ ((DataSize != sizeof (UINT32)) &&
+ (DataSize != sizeof (UINT64)))) {
+ ASSERT (0);
+ return EFI_ABORTED;
+ }
+
+ if (AddressCells == 1) {
+ MpIdr = fdt32_to_cpu (*((UINT32*)Data));
+ } else if (AddressCells == 2) {
+ MpIdr = fdt64_to_cpu (*((UINT64*)Data));
+ } else {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Currently we only support 3 affinity levels.
+ if ((MpIdr & ~(ARM_CORE_AFF0 | ARM_CORE_AFF1 | ARM_CORE_AFF2)) != 0) {
+ ASSERT (0);
+ return EFI_UNSUPPORTED;
+ }
+
+ CpuRegProp = (MpIdr & (ARM_CORE_AFF0 | ARM_CORE_AFF1 | ARM_CORE_AFF2));
+
+ /* ACPI 6.3, s5.2.12.14 GIC CPU Interface (GICC) Structure:
+ GIC 's CPU Interface Number. In GICv1/v2 implementations,
+ this value matches the bit index of the associated processor
+ in the GIC distributor's GICD_ITARGETSR register. For
+ GICv3/4 implementations this field must be provided by the
+ platform, if compatibility mode is supported. If it is not supported
+ by the implementation, then this field must be zero.
+
+ Note: We do not support compatibility mode for GicV3
+ */
+ if (GicVersion == 2) {
+ GicCInfo->CPUInterfaceNumber = CpuRegProp;
+ } else {
+ GicCInfo->CPUInterfaceNumber = 0;
+ }
+
+ GicCInfo->AcpiProcessorUid = CpuRegProp;
+ GicCInfo->Flags = EFI_ACPI_6_3_GIC_ENABLED;
+ GicCInfo->MPIDR= MpIdr;
+
+ return EFI_SUCCESS;
+}
+
+/** Parse a "cpus" node and its children "cpu" nodes.
+
+ Create as many CM_ARM_GICC_INFO structures as "cpu" nodes.
+
+ @param [in] Fdt Pointer to a Flattened Device Tree (Fdt).
+ @param [in] CpusNode Offset of a cpus node.
+ @param [in] GicVersion Version of the GIC.
+ @param [out] NewGicCmObjDesc If success, CM_OBJ_DESCRIPTOR containing
+ all the created CM_ARM_GICC_INFO.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_UNSUPPORTED Unsupported.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+CpusNodeParser (
+ IN CONST VOID * Fdt,
+ IN INT32 CpusNode,
+ IN UINT32 GicVersion,
+ OUT CM_OBJ_DESCRIPTOR ** NewGicCmObjDesc
+ )
+{
+ EFI_STATUS Status;
+ INT32 CpuNode;
+ UINT32 CpuNodeCount;
+ INT32 AddressCells;
+
+ UINT32 Index;
+ CM_ARM_GICC_INFO * GicCInfoBuffer;
+ UINT32 GicCInfoBufferSize;
+
+ if (NewGicCmObjDesc == NULL) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AddressCells = fdt_address_cells (Fdt, CpusNode);
+ if (AddressCells < 0) {
+ ASSERT (0);
+ return EFI_ABORTED;
+ }
+
+ // Count the number of "cpu" nodes under the "cpus" node.
+ Status = FdtCountNamedNodeInBranch (Fdt, CpusNode, "cpu", &CpuNodeCount);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ if (CpuNodeCount == 0) {
+ ASSERT (0);
+ return EFI_NOT_FOUND;
+ }
+
+ // Allocate memory for CpuNodeCount CM_ARM_GICC_INFO structures.
+ GicCInfoBufferSize = CpuNodeCount * sizeof (CM_ARM_GICC_INFO);
+ GicCInfoBuffer = AllocateZeroPool (GicCInfoBufferSize);
+ if (GicCInfoBuffer == NULL) {
+ ASSERT (0);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CpuNode = CpusNode;
+ for (Index = 0; Index < CpuNodeCount; Index++) {
+ Status = FdtGetNextNamedNodeInBranch (Fdt, CpusNode, "cpu", &CpuNode);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ if (Status == EFI_NOT_FOUND) {
+ // Should have found the node.
+ Status = EFI_ABORTED;
+ }
+ goto exit_handler;
+ }
+
+ // Parse the "cpu" node.
+ if (!FdtNodeIsCompatible (Fdt, CpuNode, &CpuCompatibleInfo)) {
+ ASSERT (0);
+ Status = EFI_UNSUPPORTED;
+ goto exit_handler;
+ }
+
+ Status = CpuNodeParser (
+ Fdt,
+ CpuNode,
+ GicVersion,
+ AddressCells,
+ &GicCInfoBuffer[Index]
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ goto exit_handler;
+ }
+ } // for
+
+ Status = CreateCmObjDesc (
+ CREATE_CM_ARM_OBJECT_ID (EArmObjGicCInfo),
+ CpuNodeCount,
+ GicCInfoBuffer,
+ GicCInfoBufferSize,
+ NewGicCmObjDesc
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ }
+
+exit_handler:
+ FreePool (GicCInfoBuffer);
+ return Status;
+}
+
+/** Parse a Gic compatible interrupt-controller node,
+ extracting GicC information generic to Gic v2 and v3.
+
+ This function modifies a CM_OBJ_DESCRIPTOR object.
+ The following CM_ARM_GICC_INFO fields are patched:
+ - VGICMaintenanceInterrupt;
+ - Flags;
+
+ @param [in] Fdt Pointer to a Flattened Device Tree (Fdt).
+ @param [in] GicIntcNode Offset of a Gic compatible
+ interrupt-controller node.
+ @param [in, out] GicCCmObjDesc The CM_ARM_GICC_INFO to patch.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GicCIntcNodeParser (
+ IN CONST VOID * Fdt,
+ IN INT32 GicIntcNode,
+ IN OUT CM_OBJ_DESCRIPTOR * GicCCmObjDesc
+ )
+{
+ EFI_STATUS Status;
+ INT32 IntCells;
+ CM_ARM_GICC_INFO * GicCInfo;
+
+ CONST UINT8 * Data;
+ INT32 DataSize;
+
+ if (GicCCmObjDesc == NULL) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Get the number of cells used to encode an interrupt.
+ Status = FdtGetInterruptCellsInfo (Fdt, GicIntcNode, &IntCells);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Get the GSIV maintenance interrupt.
+ // According to the DT bindings, this could be the:
+ // "Interrupt source of the parent interrupt controller on secondary GICs"
+ // but it is assumed that only one Gic is available.
+ Data = fdt_getprop (Fdt, GicIntcNode, "interrupts", &DataSize);
+ if ((Data != NULL) && (DataSize == (IntCells * sizeof (UINT32)))) {
+ GicCInfo = (CM_ARM_GICC_INFO*)GicCCmObjDesc->Data;
+ GicCInfo->VGICMaintenanceInterrupt =
+ FdtGetInterruptId ((CONST UINT32*)Data);
+ GicCInfo->Flags = DT_IRQ_IS_EDGE_TRIGGERED (
+ fdt32_to_cpu (((UINT32*)Data)[IRQ_FLAGS_OFFSET])
+ ) ?
+ EFI_ACPI_6_3_VGIC_MAINTENANCE_INTERRUPT_MODE_FLAGS :
+ 0;
+ return Status;
+ } else if (DataSize < 0) {
+ // This property is optional and was not found. Just return.
+ return Status;
+ }
+ // The property exists and its size doesn't match for one interrupt.
+ ASSERT (0);
+ return EFI_ABORTED;
+}
+
+/** Parse a Gic compatible interrupt-controller node,
+ extracting GicCv2 information.
+
+ This function modifies a CM_OBJ_DESCRIPTOR object.
+ The following CM_ARM_GICC_INFO fields are patched:
+ - PhysicalAddress;
+ - GICH;
+ - GICV;
+
+ @param [in] Fdt Pointer to a Flattened Device Tree (Fdt).
+ @param [in] Gicv2IntcNode Offset of a Gicv2 compatible
+ interrupt-controller node.
+ @param [in, out] GicCCmObjDesc The CM_ARM_GICC_INFO to patch.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GicCv2IntcNodeParser (
+ IN CONST VOID * Fdt,
+ IN INT32 Gicv2IntcNode,
+ IN OUT CM_OBJ_DESCRIPTOR * GicCCmObjDesc
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Index;
+ CM_ARM_GICC_INFO * GicCInfo;
+ INT32 AddressCells;
+ INT32 SizeCells;
+
+ CONST UINT8 * GicCValue;
+ CONST UINT8 * GicVValue;
+ CONST UINT8 * GicHValue;
+
+ CONST UINT8 * Data;
+ INT32 DataSize;
+ UINT32 RegSize;
+ UINT32 RegCount;
+
+ if (GicCCmObjDesc == NULL) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ GicCInfo = (CM_ARM_GICC_INFO*)GicCCmObjDesc->Data;
+ GicVValue = NULL;
+ GicHValue = NULL;
+
+ // Get the #address-cells and #size-cells property values.
+ Status = FdtGetParentAddressInfo (
+ Fdt,
+ Gicv2IntcNode,
+ &AddressCells,
+ &SizeCells
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Don't support more than 64 bits and less than 32 bits addresses.
+ if ((AddressCells < 1) ||
+ (AddressCells > 2) ||
+ (SizeCells < 1) ||
+ (SizeCells > 2)) {
+ ASSERT (0);
+ return EFI_ABORTED;
+ }
+
+ RegSize = (AddressCells + SizeCells) * sizeof (UINT32);
+
+ Data = fdt_getprop (Fdt, Gicv2IntcNode, "reg", &DataSize);
+ if ((Data == NULL) ||
+ (DataSize < 0) ||
+ ((DataSize % RegSize) != 0)) {
+ // If error or wrong size.
+ ASSERT (0);
+ return EFI_ABORTED;
+ }
+
+ RegCount = DataSize/RegSize;
+
+ switch (RegCount) {
+ case 4:
+ {
+ // GicV is at index 3 in the reg property. GicV is optional.
+ GicVValue = Data + (sizeof (UINT32) *
+ GET_DT_REG_ADDRESS_OFFSET (3, AddressCells, SizeCells));
+ // fall-through.
+ }
+ case 3:
+ {
+ // GicH is at index 2 in the reg property. GicH is optional.
+ GicHValue = Data + (sizeof (UINT32) *
+ GET_DT_REG_ADDRESS_OFFSET (2, AddressCells, SizeCells));
+ // fall-through.
+ }
+ case 2:
+ {
+ // GicC is at index 1 in the reg property. GicC is mandatory.
+ GicCValue = Data + (sizeof (UINT32) *
+ GET_DT_REG_ADDRESS_OFFSET (1, AddressCells, SizeCells));
+ break;
+ }
+ default:
+ {
+ // Not enough or too much information.
+ ASSERT (0);
+ return EFI_ABORTED;
+ }
+ }
+
+ // Patch the relevant fields of the CM_ARM_GICC_INFO objects.
+ for (Index = 0; Index < GicCCmObjDesc->Count; Index++) {
+ if (AddressCells == 2) {
+ GicCInfo[Index].PhysicalBaseAddress = fdt64_to_cpu (*(UINT64*)GicCValue);
+ GicCInfo[Index].GICH = (GicHValue == NULL) ? 0 :
+ fdt64_to_cpu (*(UINT64*)GicHValue);
+ GicCInfo[Index].GICV = (GicVValue == NULL) ? 0 :
+ fdt64_to_cpu (*(UINT64*)GicVValue);
+ } else {
+ GicCInfo[Index].PhysicalBaseAddress = fdt32_to_cpu (*(UINT32*)GicCValue);
+ GicCInfo[Index].GICH = (GicHValue == NULL) ? 0 :
+ fdt32_to_cpu (*(UINT32*)GicHValue);
+ GicCInfo[Index].GICV = (GicVValue == NULL) ? 0 :
+ fdt32_to_cpu (*(UINT32*)GicVValue);
+ }
+ } // for
+
+ return EFI_SUCCESS;
+}
+
+/** Parse a Gic compatible interrupt-controller node,
+ extracting GicCv3 information.
+
+ This function modifies a CM_OBJ_DESCRIPTOR object.
+ The following CM_ARM_GICC_INFO fields are patched:
+ - PhysicalAddress;
+ - GICH;
+ - GICV;
+
+ @param [in] Fdt Pointer to a Flattened Device Tree (Fdt).
+ @param [in] Gicv3IntcNode Offset of a Gicv3 compatible
+ interrupt-controller node.
+ @param [in, out] GicCCmObjDesc The CM_ARM_GICC_INFO to patch.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GicCv3IntcNodeParser (
+ IN CONST VOID * Fdt,
+ IN INT32 Gicv3IntcNode,
+ IN OUT CM_OBJ_DESCRIPTOR * GicCCmObjDesc
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Index;
+ CM_ARM_GICC_INFO * GicCInfo;
+ INT32 AddressCells;
+ INT32 SizeCells;
+ UINT32 AdditionalRedistReg;
+
+ CONST UINT8 * GicCValue;
+ CONST UINT8 * GicVValue;
+ CONST UINT8 * GicHValue;
+
+ CONST UINT8 * Data;
+ INT32 DataSize;
+ UINT32 RegSize;
+ UINT32 RegCount;
+
+ if (GicCCmObjDesc == NULL) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ GicCInfo = (CM_ARM_GICC_INFO*)GicCCmObjDesc->Data;
+ GicCValue = NULL;
+ GicVValue = NULL;
+ GicHValue = NULL;
+
+ // Get the #address-cells and #size-cells property values.
+ Status = FdtGetParentAddressInfo (
+ Fdt,
+ Gicv3IntcNode,
+ &AddressCells,
+ &SizeCells
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Don't support more than 64 bits and less than 32 bits addresses.
+ if ((AddressCells < 1) ||
+ (AddressCells > 2) ||
+ (SizeCells < 1) ||
+ (SizeCells > 2)) {
+ ASSERT (0);
+ return EFI_ABORTED;
+ }
+
+ // The "#redistributor-regions" property is optional.
+ Data = fdt_getprop (Fdt, Gicv3IntcNode, "#redistributor-regions", &DataSize);
+ if ((Data != NULL) && (DataSize == sizeof (UINT32))) {
+ ASSERT (fdt32_to_cpu (*(UINT32*)Data) > 1);
+ AdditionalRedistReg = fdt32_to_cpu (*(UINT32*)Data) - 1;
+ } else {
+ AdditionalRedistReg = 0;
+ }
+
+ RegSize = (AddressCells + SizeCells) * sizeof (UINT32);
+
+ /*
+ Ref: linux/blob/master/Documentation/devicetree/bindings/
+ interrupt-controller/arm%2Cgic-v3.yaml
+
+ reg:
+ description: |
+ Specifies base physical address(s) and size of the GIC
+ registers, in the following order:
+ - GIC Distributor interface (GICD)
+ - GIC Redistributors (GICR), one range per redistributor region
+ - GIC CPU interface (GICC)
+ - GIC Hypervisor interface (GICH)
+ - GIC Virtual CPU interface (GICV)
+ GICC, GICH and GICV are optional.
+ minItems: 2
+ maxItems: 4096
+ */
+ Data = fdt_getprop (Fdt, Gicv3IntcNode, "reg", &DataSize);
+ if ((Data == NULL) ||
+ (DataSize < 0) ||
+ ((DataSize % RegSize) != 0)) {
+ // If error or wrong size.
+ ASSERT (0);
+ return EFI_ABORTED;
+ }
+
+ RegCount = (DataSize / RegSize) - AdditionalRedistReg;
+
+ // The GicD and GicR info is mandatory.
+ switch (RegCount) {
+ case 5:
+ {
+ // GicV is at index 4 in the reg property. GicV is optional.
+ GicVValue = Data + (sizeof (UINT32) *
+ GET_DT_REG_ADDRESS_OFFSET (
+ 4 + AdditionalRedistReg,
+ AddressCells,
+ SizeCells
+ ));
+ // fall-through.
+ }
+ case 4:
+ {
+ // GicH is at index 3 in the reg property. GicH is optional.
+ GicHValue = Data + (sizeof (UINT32) *
+ GET_DT_REG_ADDRESS_OFFSET (
+ 3 + AdditionalRedistReg,
+ AddressCells,
+ SizeCells
+ ));
+ // fall-through.
+ }
+ case 3:
+ {
+ // GicC is at index 2 in the reg property. GicC is optional.
+ // Even though GicC is optional, it is made mandatory in this parser.
+ GicCValue = Data + (sizeof (UINT32) *
+ GET_DT_REG_ADDRESS_OFFSET (
+ 2 + AdditionalRedistReg,
+ AddressCells,
+ SizeCells
+ ));
+ // fall-through
+ }
+ case 2:
+ {
+ // GicR is discribed by the CM_ARM_GIC_REDIST_INFO object.
+ // GicD is described by the CM_ARM_GICD_INFO object.
+ break;
+ }
+ default:
+ {
+ // Not enough or too much information.
+ ASSERT (0);
+ return EFI_ABORTED;
+ }
+ }
+
+ // Patch the relevant fields of the CM_ARM_GICC_INFO objects.
+ if (AddressCells == 2) {
+ for (Index = 0; Index < GicCCmObjDesc->Count; Index++) {
+ // GicR is discribed by the CM_ARM_GIC_REDIST_INFO object.
+ GicCInfo[Index].GICRBaseAddress = 0;
+ GicCInfo[Index].PhysicalBaseAddress = (GicCValue == NULL) ? 0 :
+ fdt64_to_cpu (*(UINT64*)GicCValue);
+ GicCInfo[Index].GICH = (GicHValue == NULL) ? 0 :
+ fdt64_to_cpu (*(UINT64*)GicHValue);
+ GicCInfo[Index].GICV = (GicVValue == NULL) ? 0 :
+ fdt64_to_cpu (*(UINT64*)GicVValue);
+ }
+ } else {
+ for (Index = 0; Index < GicCCmObjDesc->Count; Index++) {
+ // GicR is discribed by the CM_ARM_GIC_REDIST_INFO object.
+ GicCInfo[Index].GICRBaseAddress = 0;
+ GicCInfo[Index].PhysicalBaseAddress = (GicCValue == NULL) ? 0 :
+ fdt32_to_cpu (*(UINT32*)GicCValue);
+ GicCInfo[Index].GICH = (GicHValue == NULL) ? 0 :
+ fdt32_to_cpu (*(UINT32*)GicHValue);
+ GicCInfo[Index].GICV = (GicVValue == NULL) ? 0 :
+ fdt32_to_cpu (*(UINT32*)GicVValue);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/** CM_ARM_GICC_INFO parser function.
+
+ This parser expects FdtBranch to be the "\cpus" node node.
+ At most one CmObj is created.
+ The following structure is populated:
+ typedef struct CmArmGicCInfo {
+ UINT32 CPUInterfaceNumber; // {Populated}
+ UINT32 AcpiProcessorUid; // {Populated}
+ UINT32 Flags; // {Populated}
+ UINT32 ParkingProtocolVersion; // {default = 0}
+ UINT32 PerformanceInterruptGsiv; // {default = 0}
+ UINT64 ParkedAddress; // {default = 0}
+ UINT64 PhysicalBaseAddress; // {Populated}
+ UINT64 GICV; // {Populated}
+ UINT64 GICH; // {Populated}
+ UINT32 VGICMaintenanceInterrupt; // {Populated}
+ UINT64 GICRBaseAddress; // {default = 0}
+ UINT64 MPIDR; // {Populated}
+ UINT8 ProcessorPowerEfficiencyClass; // {default = 0}
+ UINT16 SpeOverflowInterrupt; // {default = 0}
+ UINT32 ProximityDomain; // {default = 0}
+ UINT32 ClockDomain; // {default = 0}
+ UINT32 AffinityFlags; // {default = 0}
+ } CM_ARM_GICC_INFO;
+
+ The pmu information can be found in the pmu node. There is no support
+ for now.
+
+ A parser parses a Device Tree to populate a specific CmObj type. None,
+ one or many CmObj can be created by the parser.
+ The created CmObj are then handed to the parser's caller through the
+ HW_INFO_ADD_OBJECT interface.
+ This can also be a dispatcher. I.e. a function that not parsing a
+ Device Tree but calling other parsers.
+
+ @param [in] FdtParserHandle A handle to the parser instance.
+ @param [in] FdtBranch When searching for DT node name, restrict
+ the search to this Device Tree branch.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND Not found.
+ @retval EFI_UNSUPPORTED Unsupported.
+**/
+EFI_STATUS
+EFIAPI
+ArmGicCInfoParser (
+ IN CONST FDT_HW_INFO_PARSER_HANDLE FdtParserHandle,
+ IN INT32 FdtBranch
+ )
+{
+ EFI_STATUS Status;
+ INT32 IntcNode;
+ UINT32 GicVersion;
+ CM_OBJ_DESCRIPTOR * NewCmObjDesc;
+ VOID * Fdt;
+
+ if (FdtParserHandle == NULL) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Fdt = FdtParserHandle->Fdt;
+ NewCmObjDesc = NULL;
+
+ // The FdtBranch points to the Cpus Node.
+ // Get the interrupt-controller node associated to the "cpus" node.
+ Status = FdtGetIntcParentNode (Fdt, FdtBranch, &IntcNode);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ if (Status == EFI_NOT_FOUND) {
+ // Should have found the node.
+ Status = EFI_ABORTED;
+ }
+ goto exit_handler;
+ }
+
+ Status = GetGicVersion (Fdt, IntcNode, &GicVersion);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ goto exit_handler;
+ }
+
+ // Parse the "cpus" nodes and its children "cpu" nodes,
+ // and create a CM_OBJ_DESCRIPTOR.
+ Status = CpusNodeParser (Fdt, FdtBranch, GicVersion, &NewCmObjDesc);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Parse the interrupt-controller node according to the Gic version.
+ switch (GicVersion) {
+ case 2:
+ {
+ Status = GicCv2IntcNodeParser (Fdt, IntcNode, NewCmObjDesc);
+ break;
+ }
+ case 3:
+ {
+ Status = GicCv3IntcNodeParser (Fdt, IntcNode, NewCmObjDesc);
+ break;
+ }
+ default:
+ {
+ // Unsupported Gic version.
+ ASSERT (0);
+ Status = EFI_UNSUPPORTED;
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ goto exit_handler;
+ }
+
+ // Parse the Gic information common to Gic v2 and v3.
+ Status = GicCIntcNodeParser (Fdt, IntcNode, NewCmObjDesc);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ goto exit_handler;
+ }
+
+ // Add all the CmObjs to the Configuration Manager.
+ Status = AddMultipleCmObj (FdtParserHandle, NewCmObjDesc, 0, NULL);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ goto exit_handler;
+ }
+
+exit_handler:
+ FreeCmObjDesc (NewCmObjDesc);
+ return Status;
+}
diff --git a/DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicCParser.h b/DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicCParser.h
new file mode 100644
index 000000000000..10e6b03c541f
--- /dev/null
+++ b/DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicCParser.h
@@ -0,0 +1,67 @@
+/** @file
+ Arm Gic cpu parser.
+
+ Copyright (c) 2021, ARM Limited. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - linux/Documentation/devicetree/bindings/interrupt-controller/arm,gic.yaml
+ - linux/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml
+**/
+
+#ifndef ARM_GICC_PARSER_H_
+#define ARM_GICC_PARSER_H_
+
+/** CM_ARM_GICC_INFO parser function.
+
+ This parser expects FdtBranch to be the "\cpus" node node.
+ At most one CmObj is created.
+ The following structure is populated:
+ typedef struct CmArmGicCInfo {
+ UINT32 CPUInterfaceNumber; // {Populated}
+ UINT32 AcpiProcessorUid; // {Populated}
+ UINT32 Flags; // {Populated}
+ UINT32 ParkingProtocolVersion; // {default = 0}
+ UINT32 PerformanceInterruptGsiv; // {default = 0}
+ UINT64 ParkedAddress; // {default = 0}
+ UINT64 PhysicalBaseAddress; // {Populated}
+ UINT64 GICV; // {Populated}
+ UINT64 GICH; // {Populated}
+ UINT32 VGICMaintenanceInterrupt; // {Populated}
+ UINT64 GICRBaseAddress; // {default = 0}
+ UINT64 MPIDR; // {Populated}
+ UINT8 ProcessorPowerEfficiencyClass; // {default = 0}
+ UINT16 SpeOverflowInterrupt; // {default = 0}
+ UINT32 ProximityDomain; // {default = 0}
+ UINT32 ClockDomain; // {default = 0}
+ UINT32 AffinityFlags; // {default = 0}
+ } CM_ARM_GICC_INFO;
+
+ The pmu information can be found in the pmu node. There is no support
+ for now.
+
+ A parser parses a Device Tree to populate a specific CmObj type. None,
+ one or many CmObj can be created by the parser.
+ The created CmObj are then handed to the parser's caller through the
+ HW_INFO_ADD_OBJECT interface.
+ This can also be a dispatcher. I.e. a function that not parsing a
+ Device Tree but calling other parsers.
+
+ @param [in] FdtParserHandle A handle to the parser instance.
+ @param [in] FdtBranch When searching for DT node name, restrict
+ the search to this Device Tree branch.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND Not found.
+ @retval EFI_UNSUPPORTED Unsupported.
+**/
+EFI_STATUS
+EFIAPI
+ArmGicCInfoParser (
+ IN CONST FDT_HW_INFO_PARSER_HANDLE FdtParserHandle,
+ IN INT32 FdtBranch
+ );
+
+#endif // ARM_GICC_PARSER_H_
--
2.17.1


[PATCH v1 06/14] DynamicTablesPkg: FdtHwInfoParser: Add Serial port parser

PierreGondois
 

From: Pierre Gondois <Pierre.Gondois@...>

The Microsoft Debug Port Table 2 (DBG2), the Serial Port Console
Redirector (SPCR) table are mandatory tables required for booting
a standards-based operating system. The DBG2 table is used by the
OS debugger while the SPCR table is used to configure the serial
terminal. Additionally, the serial ports available on a platform
for generic use also need to be described in DSDT/SSDT for an OS
to be able to use the serial ports.

The Arm Base System Architecture 1.0 specification a lists of
supported serial port hardware for Arm Platforms. This list
includes the following serial port UARTs:
- SBSA/Generic UART
- a fully 16550 compatible UART.
Along, with these the PL011 UART is the most commonly used serial
port hardware on Arm platforms.

The serial port hardware information is described in the platform
Device Tree, the bindings for which can be found at:
- linux/Documentation/devicetree/bindings/serial/serial.yaml
- linux/Documentation/devicetree/bindings/serial/8250.txt
- linux/Documentation/devicetree/bindings/serial/arm_sbsa_uart.txt
- linux/Documentation/devicetree/bindings/serial/pl011.yaml

The FdtHwInfoParser implements a Serial Port Parser that parses
the platform Device Tree to create CM_ARM_SERIAL_PORT_INFO objects
with the following IDs:
- EArmObjSerialConsolePortInfo (for use by SPCR)
- EArmObjSerialDebugPortInfo (for use by DBG2)
- EArmObjSerialPortInfo (for use as generic Serial Ports)

The Serial Port for use by SPCR is selected by parsing the Device
Tree for the '/chosen' node with the 'stdout-path' property. The
next Serial Port is selected for use as the Debug Serial Port and
the remaining serial ports are used as generic serial ports.

The CM_ARM_SERIAL_PORT_INFO objects are encapsulated in Configuration
Manager descriptor objects with the respective IDs and are added to
the platform information repository.

The platform Configuration Manager can then utilise this information
when generating the DBG2, SPCR and the SSDT serial port tables.

Signed-off-by: Pierre Gondois <Pierre.Gondois@...>
Signed-off-by: Sami Mujawar <sami.mujawar@...>
---
.../Serial/ArmSerialPortParser.c | 621 ++++++++++++++++++
.../Serial/ArmSerialPortParser.h | 47 ++
2 files changed, 668 insertions(+)
create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/Serial/ArmSerialPortParser.c
create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/Serial/ArmSerialPortParser.h

diff --git a/DynamicTablesPkg/Library/FdtHwInfoParserLib/Serial/ArmSerialPortParser.c b/DynamicTablesPkg/Library/FdtHwInfoParserLib/Serial/ArmSerialPortParser.c
new file mode 100644
index 000000000000..d5db206ae93c
--- /dev/null
+++ b/DynamicTablesPkg/Library/FdtHwInfoParserLib/Serial/ArmSerialPortParser.c
@@ -0,0 +1,621 @@
+/** @file
+ Arm Serial Port Parser.
+
+ Copyright (c) 2021, ARM Limited. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - linux/Documentation/devicetree/bindings/serial/serial.yaml
+ - linux/Documentation/devicetree/bindings/serial/8250.txt
+ - linux/Documentation/devicetree/bindings/serial/arm_sbsa_uart.txt
+ - linux/Documentation/devicetree/bindings/serial/pl011.yaml
+**/
+
+#include <IndustryStandard/DebugPort2Table.h>
+
+#include "CmObjectDescUtility.h"
+#include "FdtHwInfoParser.h"
+#include "Serial/ArmSerialPortParser.h"
+
+/** List of "compatible" property values for serial port nodes.
+
+ Any other "compatible" value is not supported by this module.
+*/
+STATIC CONST COMPATIBILITY_STR SerialCompatibleStr[] = {
+ {"ns16550a"},
+ {"arm,sbsa-uart"}
+};
+
+/** COMPATIBILITY_INFO structure for the SerialCompatible.
+*/
+CONST COMPATIBILITY_INFO SerialCompatibleInfo = {
+ ARRAY_SIZE (SerialCompatibleStr),
+ SerialCompatibleStr
+};
+
+/** 16550 UART compatible strings.
+
+ Any string of this list must be part of SerialCompatible.
+*/
+STATIC CONST COMPATIBILITY_STR Serial16550CompatibleStr[] = {
+ {"ns16550a"}
+};
+
+/** COMPATIBILITY_INFO structure for the Serial16550Compatible.
+*/
+CONST COMPATIBILITY_INFO Serial16550CompatibleInfo = {
+ ARRAY_SIZE (Serial16550CompatibleStr),
+ Serial16550CompatibleStr
+};
+
+/** SBSA UART compatible strings.
+
+ Any string of this list must be part of SerialCompatible.
+*/
+STATIC CONST COMPATIBILITY_STR SerialSbsaCompatibleStr[] = {
+ {"arm,sbsa-uart"}
+};
+
+/** COMPATIBILITY_INFO structure for the SerialSbsaCompatible.
+*/
+CONST COMPATIBILITY_INFO SerialSbsaCompatibleInfo = {
+ ARRAY_SIZE (SerialSbsaCompatibleStr),
+ SerialSbsaCompatibleStr
+};
+
+/** Parse a serial port node.
+
+ @param [in] Fdt Pointer to a Flattened Device Tree (Fdt).
+ @param [in] SerialPortNode Offset of a serial-port node.
+ @param [in] SerialPortInfo The CM_ARM_SERIAL_PORT_INFO to populate.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_UNSUPPORTED Unsupported.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+SerialPortNodeParser (
+ IN CONST VOID * Fdt,
+ IN INT32 SerialPortNode,
+ IN CM_ARM_SERIAL_PORT_INFO * SerialPortInfo
+ )
+{
+ EFI_STATUS Status;
+ INT32 IntcNode;
+ CONST UINT8 * SizeValue;
+
+ INT32 AddressCells;
+ INT32 SizeCells;
+ INT32 IntCells;
+
+ CONST UINT8 * Data;
+ INT32 DataSize;
+ UINT8 AccessSize;
+
+ if ((Fdt == NULL) ||
+ (SerialPortInfo == NULL)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = FdtGetParentAddressInfo (
+ Fdt,
+ SerialPortNode,
+ &AddressCells,
+ &SizeCells
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Don't support more than 64 bits and less than 32 bits addresses.
+ if ((AddressCells < 1) ||
+ (AddressCells > 2) ||
+ (SizeCells < 1) ||
+ (SizeCells > 2)) {
+ ASSERT (0);
+ return EFI_ABORTED;
+ }
+
+ Data = fdt_getprop (Fdt, SerialPortNode, "reg", &DataSize);
+ if ((Data == NULL) ||
+ (DataSize < (INT32)(sizeof (UINT32) *
+ GET_DT_REG_ADDRESS_OFFSET (1, AddressCells, SizeCells)) - 1)) {
+ // If error or not enough space.
+ ASSERT (0);
+ return EFI_ABORTED;
+ }
+
+ if (AddressCells == 2) {
+ SerialPortInfo->BaseAddress = fdt64_to_cpu (*(UINT64*)Data);
+ } else {
+ SerialPortInfo->BaseAddress = fdt32_to_cpu (*(UINT32*)Data);
+ }
+
+ SizeValue = Data + (sizeof (UINT32) *
+ GET_DT_REG_SIZE_OFFSET (0, AddressCells, SizeCells));
+ if (SizeCells == 2) {
+ SerialPortInfo->BaseAddressLength = fdt64_to_cpu (*(UINT64*)SizeValue);
+ } else {
+ SerialPortInfo->BaseAddressLength = fdt32_to_cpu (*(UINT32*)SizeValue);
+ }
+
+ // Get the associated interrupt-controller.
+ Status= FdtGetIntcParentNode (Fdt, SerialPortNode, &IntcNode);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ if (Status == EFI_NOT_FOUND) {
+ // Should have found the node.
+ Status = EFI_ABORTED;
+ }
+ return Status;
+ }
+
+ // Get the number of cells used to encode an interrupt.
+ Status = FdtGetInterruptCellsInfo (Fdt, IntcNode, &IntCells);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ Data = fdt_getprop (Fdt, SerialPortNode, "interrupts", &DataSize);
+ if ((Data == NULL) || (DataSize != (IntCells * sizeof (UINT32)))) {
+ // If error or not 1 interrupt.
+ ASSERT (0);
+ return EFI_ABORTED;
+ }
+
+ SerialPortInfo->Interrupt = FdtGetInterruptId ((CONST UINT32*)Data);
+
+ // Note: clock-frequency is optional for SBSA UART.
+ Data = fdt_getprop (Fdt, SerialPortNode, "clock-frequency", &DataSize);
+ if (Data != NULL) {
+ if (DataSize < sizeof (UINT32)) {
+ // If error or not enough space.
+ ASSERT (0);
+ return EFI_ABORTED;
+ } else if (fdt_node_offset_by_phandle (Fdt, fdt32_to_cpu (*Data)) >= 0) {
+ // "clock-frequency" can be a "clocks phandle to refer to the clk used".
+ // This is not supported.
+ ASSERT (0);
+ return EFI_UNSUPPORTED;
+ }
+ SerialPortInfo->Clock = fdt32_to_cpu (*(UINT32*)Data);
+ }
+
+ if (FdtNodeIsCompatible (Fdt, SerialPortNode, &Serial16550CompatibleInfo)) {
+ SerialPortInfo->PortSubtype = EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_FULL_16550;
+
+ /* reg-io-width:
+ description: |
+ The size (in bytes) of the IO accesses that should be performed on the
+ device. There are some systems that require 32-bit accesses to the
+ UART.
+ */
+ Data = fdt_getprop (Fdt, SerialPortNode, "reg-io-width", &DataSize);
+ if (Data != NULL) {
+ if (DataSize < sizeof (UINT32)) {
+ // If error or not enough space.
+ ASSERT (0);
+ return EFI_ABORTED;
+ }
+
+ AccessSize = fdt32_to_cpu (*(UINT32*)Data);
+ if (AccessSize > EFI_ACPI_6_3_QWORD) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+ SerialPortInfo->AccessSize = AccessSize;
+ } else {
+ // 8250/16550 defaults to byte access.
+ SerialPortInfo->AccessSize = EFI_ACPI_6_3_BYTE;
+ }
+ } else if (FdtNodeIsCompatible (
+ Fdt,
+ SerialPortNode,
+ &SerialSbsaCompatibleInfo
+ )) {
+ SerialPortInfo->PortSubtype =
+ EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_ARM_SBSA_GENERIC_UART;
+ } else {
+ ASSERT (0);
+ return EFI_UNSUPPORTED;
+ }
+
+ // Set Baudrate to 115200 by default
+ SerialPortInfo->BaudRate = 115200;
+ return EFI_SUCCESS;
+}
+
+/** Find the console serial-port node in the DT.
+
+ This function fetches the node referenced in the "stdout-path"
+ property of the "chosen" node.
+
+ @param [in] Fdt Pointer to a Flattened Device Tree (Fdt).
+ @param [out] SerialConsoleNode If success, contains the node offset
+ of the console serial-port node.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND Not found.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GetSerialConsoleNode (
+ IN CONST VOID * Fdt,
+ OUT INT32 * SerialConsoleNode
+ )
+{
+ CONST CHAR8 * Prop;
+ INT32 PropSize;
+ CONST CHAR8 * Path;
+ INT32 PathLen;
+ INT32 ChosenNode;
+
+ if ((Fdt == NULL) ||
+ (SerialConsoleNode == NULL)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // The "chosen" node resides at the the root of the DT. Fetch it.
+ ChosenNode = fdt_path_offset (Fdt, "/chosen");
+ if (ChosenNode < 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ Prop = fdt_getprop (Fdt, ChosenNode, "stdout-path", &PropSize);
+ if ((Prop == NULL) || (PropSize < 0)) {
+ return EFI_NOT_FOUND;
+ }
+
+ // Determine the actual path length, as a colon terminates the path.
+ Path = ScanMem8 (Prop, ':', PropSize);
+ if (Path == NULL) {
+ PathLen = (UINT32)AsciiStrLen (Prop);
+ } else {
+ PathLen = (INT32)(Path - Prop);
+ }
+
+ // Aliases cannot start with a '/', so it must be the actual path.
+ if (Prop[0] == '/') {
+ *SerialConsoleNode = fdt_path_offset_namelen (Fdt, Prop, PathLen);
+ return EFI_SUCCESS;
+ }
+
+ // Lookup the alias, as this contains the actual path.
+ Path = fdt_get_alias_namelen (Fdt, Prop, PathLen);
+ if (Path == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ *SerialConsoleNode = fdt_path_offset (Fdt, Path);
+ return EFI_SUCCESS;
+}
+
+/** CM_ARM_SERIAL_PORT_INFO dispatcher function (for a generic serial-port).
+
+ @param [in] FdtParserHandle A handle to the parser instance.
+ @param [in] GenericSerialInfo Pointer to a serial port info list.
+ @param [in] NodeCount Count of serial ports to dispatch.
+ @param [in] SerialObjectId Serial port object ID.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND Not found.
+ @retval EFI_UNSUPPORTED Unsupported.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+ArmSerialPortInfoDispatch (
+ IN CONST FDT_HW_INFO_PARSER_HANDLE FdtParserHandle,
+ IN CM_ARM_SERIAL_PORT_INFO * GenericSerialInfo,
+ IN INT32 NodeCount,
+ IN EARM_OBJECT_ID SerialObjectId
+)
+{
+ EFI_STATUS Status;
+ CM_OBJ_DESCRIPTOR * NewCmObjDesc;
+
+ if ((GenericSerialInfo == NULL) || (NodeCount == 0)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((SerialObjectId != EArmObjSerialPortInfo) &&
+ (SerialObjectId != EArmObjSerialDebugPortInfo) &&
+ (SerialObjectId != EArmObjSerialConsolePortInfo)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Dispatch the Generic Serial ports
+ Status = CreateCmObjDesc (
+ CREATE_CM_ARM_OBJECT_ID (SerialObjectId),
+ NodeCount,
+ GenericSerialInfo,
+ sizeof (CM_ARM_SERIAL_PORT_INFO) * NodeCount,
+ &NewCmObjDesc
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Add all the CmObjs to the Configuration Manager.
+ Status = AddMultipleCmObj (FdtParserHandle, NewCmObjDesc, 0, NULL);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ }
+
+ FreeCmObjDesc (NewCmObjDesc);
+ return Status;
+}
+
+/** CM_ARM_SERIAL_PORT_INFO parser function (for debug/console serial-port).
+
+ This parser expects FdtBranch to be the debug serial-port node.
+ At most one CmObj is created.
+ The following structure is populated:
+ typedef struct CmArmSerialPortInfo {
+ UINT64 BaseAddress; // {Populated}
+ UINT32 Interrupt; // {Populated}
+ UINT64 BaudRate; // {default}
+ UINT32 Clock; // {Populated}
+ UINT16 PortSubtype; // {Populated}
+ UINT64 BaseAddressLength // {Populated}
+ } CM_ARM_SERIAL_PORT_INFO;
+
+ A parser parses a Device Tree to populate a specific CmObj type. None,
+ one or many CmObj can be created by the parser.
+ The created CmObj are then handed to the parser's caller through the
+ HW_INFO_ADD_OBJECT interface.
+ This can also be a dispatcher. I.e. a function that not parsing a
+ Device Tree but calling other parsers.
+
+ @param [in] FdtParserHandle A handle to the parser instance.
+ @param [in] FdtBranch When searching for DT node name, restrict
+ the search to this Device Tree branch.
+ @param [in] SerialObjectId ArmNamespace Object ID for the serial port.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND Not found.
+ @retval EFI_UNSUPPORTED Unsupported.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+ArmSerialPortInfoParser (
+ IN CONST FDT_HW_INFO_PARSER_HANDLE FdtParserHandle,
+ IN INT32 FdtBranch,
+ IN EARM_OBJECT_ID SerialObjectId
+ )
+{
+ EFI_STATUS Status;
+ CM_ARM_SERIAL_PORT_INFO SerialInfo;
+
+ if ((SerialObjectId != EArmObjSerialDebugPortInfo) &&
+ (SerialObjectId != EArmObjSerialConsolePortInfo)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ZeroMem (&SerialInfo, sizeof (SerialInfo));
+
+ Status = SerialPortNodeParser (
+ FdtParserHandle->Fdt,
+ FdtBranch,
+ &SerialInfo
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ Status = ArmSerialPortInfoDispatch (
+ FdtParserHandle,
+ &SerialInfo,
+ 1,
+ SerialObjectId
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ }
+
+ return Status;
+}
+
+/** SerialPort dispatcher.
+
+ This disptacher populates the CM_ARM_SERIAL_PORT_INFO structure for
+ the following CM_OBJ_ID:
+ - EArmObjSerialConsolePortInfo
+ - EArmObjSerialDebugPortInfo
+ - EArmObjSerialPortInfo
+
+ A parser parses a Device Tree to populate a specific CmObj type. None,
+ one or many CmObj can be created by the parser.
+ The created CmObj are then handed to the parser's caller through the
+ HW_INFO_ADD_OBJECT interface.
+ This can also be a dispatcher. I.e. a function that not parsing a
+ Device Tree but calling other parsers.
+
+ @param [in] FdtParserHandle A handle to the parser instance.
+ @param [in] FdtBranch When searching for DT node name, restrict
+ the search to this Device Tree branch.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND Not found.
+ @retval EFI_UNSUPPORTED Unsupported.
+**/
+EFI_STATUS
+EFIAPI
+SerialPortDispatcher (
+ IN CONST FDT_HW_INFO_PARSER_HANDLE FdtParserHandle,
+ IN INT32 FdtBranch
+ )
+{
+ EFI_STATUS Status;
+ INT32 SerialConsoleNode;
+ INT32 SerialDebugNode;
+ INT32 SerialNode;
+ UINT32 Index;
+ UINT32 SerialNodeCount;
+ UINT32 SerialNodesRemaining;
+ CM_ARM_SERIAL_PORT_INFO * GenericSerialInfo;
+ UINT32 GenericSerialIndex;
+ VOID * Fdt;
+
+ if (FdtParserHandle == NULL) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Fdt = FdtParserHandle->Fdt;
+
+ // Count the number of serial-ports.
+ Status = FdtCountCompatNodeInBranch (
+ Fdt,
+ FdtBranch,
+ &SerialCompatibleInfo,
+ &SerialNodeCount
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ if (SerialNodeCount == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ // Track remaining nodes separately as SerialNodeCount
+ // is used in for loop below and reducing SerialNodeCount
+ // would result in the Generic Serial port nodes not
+ // being found if the serial console port node is among
+ // the first few serial nodes.
+ SerialNodesRemaining = SerialNodeCount;
+
+ // Identify the serial console port.
+ Status = GetSerialConsoleNode (Fdt, &SerialConsoleNode);
+ if (Status == EFI_NOT_FOUND) {
+ // No serial console.
+ SerialConsoleNode = -1;
+ } else if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ } else {
+ // Parse the console serial-port.
+ Status = ArmSerialPortInfoParser (
+ FdtParserHandle,
+ SerialConsoleNode,
+ EArmObjSerialConsolePortInfo
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+ SerialNodesRemaining--;
+ }
+
+ GenericSerialInfo = NULL;
+ if (SerialNodesRemaining > 1) {
+ // We have more than one serial port remaining.
+ // This means that the first serial port will
+ // be reserved as a debug port, and the remaining
+ // will be for general purpose use.
+ SerialNodesRemaining--;
+ GenericSerialInfo = AllocateZeroPool (
+ SerialNodesRemaining *
+ sizeof (CM_ARM_SERIAL_PORT_INFO)
+ );
+ if (GenericSerialInfo == NULL) {
+ ASSERT (0);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ SerialNode = FdtBranch;
+ SerialDebugNode = -1;
+ GenericSerialIndex = 0;
+ for (Index = 0; Index < SerialNodeCount; Index++) {
+ // Search the next serial-port node in the branch.
+ Status = FdtGetNextCompatNodeInBranch (
+ Fdt,
+ FdtBranch,
+ &SerialCompatibleInfo,
+ &SerialNode
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ if (Status == EFI_NOT_FOUND) {
+ // Should have found the node.
+ Status = EFI_ABORTED;
+ }
+ goto exit_handler;
+ }
+
+ // Ignore the serial console node.
+ if (SerialNode == SerialConsoleNode) {
+ continue;
+ } else if (SerialDebugNode == -1) {
+ // The first serial-port node, not being the console serial-port,
+ // will be the debug serial-port.
+ SerialDebugNode = SerialNode;
+ Status = ArmSerialPortInfoParser (
+ FdtParserHandle,
+ SerialDebugNode,
+ EArmObjSerialDebugPortInfo
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ goto exit_handler;
+ }
+ } else {
+ if (GenericSerialInfo == NULL) {
+ // Should not be possible.
+ ASSERT (0);
+ Status = EFI_ABORTED;
+ goto exit_handler;
+ }
+
+ Status = SerialPortNodeParser (
+ Fdt,
+ SerialNode,
+ &GenericSerialInfo[GenericSerialIndex++]
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ goto exit_handler;
+ }
+ }
+ } // for
+
+ if (GenericSerialIndex > 0) {
+ Status = ArmSerialPortInfoDispatch (
+ FdtParserHandle,
+ GenericSerialInfo,
+ GenericSerialIndex,
+ EArmObjSerialPortInfo
+ );
+ }
+
+exit_handler:
+ if (GenericSerialInfo != NULL) {
+ FreePool (GenericSerialInfo);
+ }
+ return Status;
+}
diff --git a/DynamicTablesPkg/Library/FdtHwInfoParserLib/Serial/ArmSerialPortParser.h b/DynamicTablesPkg/Library/FdtHwInfoParserLib/Serial/ArmSerialPortParser.h
new file mode 100644
index 000000000000..5e4707849e39
--- /dev/null
+++ b/DynamicTablesPkg/Library/FdtHwInfoParserLib/Serial/ArmSerialPortParser.h
@@ -0,0 +1,47 @@
+/** @file
+ Arm Serial Port Parser.
+
+ Copyright (c) 2021, ARM Limited. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - linux/Documentation/devicetree/bindings/serial/serial.yaml
+ - linux/Documentation/devicetree/bindings/serial/8250.txt
+**/
+
+#ifndef ARM_SERIAL_PORT_PARSER_H_
+#define ARM_SERIAL_PORT_PARSER_H_
+
+/** SerialPort dispatcher.
+
+ This disptacher populates the CM_ARM_SERIAL_PORT_INFO structure for
+ the following CM_OBJ_ID:
+ - EArmObjSerialConsolePortInfo
+ - EArmObjSerialDebugPortInfo
+ - EArmObjSerialPortInfo
+
+ A parser parses a Device Tree to populate a specific CmObj type. None,
+ one or many CmObj can be created by the parser.
+ The created CmObj are then handed to the parser's caller through the
+ HW_INFO_ADD_OBJECT interface.
+ This can also be a dispatcher. I.e. a function that not parsing a
+ Device Tree but calling other parsers.
+
+ @param [in] FdtParserHandle A handle to the parser instance.
+ @param [in] FdtBranch When searching for DT node name, restrict
+ the search to this Device Tree branch.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND Not found.
+ @retval EFI_UNSUPPORTED Unsupported.
+**/
+EFI_STATUS
+EFIAPI
+SerialPortDispatcher (
+ IN CONST FDT_HW_INFO_PARSER_HANDLE FdtParserHandle,
+ IN INT32 FdtBranch
+ );
+
+#endif // ARM_SERIAL_PORT_PARSER_H_
--
2.17.1


[PATCH v1 05/14] DynamicTablesPkg: FdtHwInfoParser: Generic Timer Parser

PierreGondois
 

From: Pierre Gondois <Pierre.Gondois@...>

The Generic Timer Description Table (GTDT) is a mandatory table
required for booting a standards-based operating system. It
provides an OSPM with information about a system’s Generic Timer
configuration. The Generic Timer (GT) is a standard timer interface
implemented on ARM processor-based systems. The GTDT provides OSPM
with information about a system’s GT interrupt configurations, for
both per-processor timers, and platform (memory-mapped) timers.

The Generic Timer information is described in the platform Device
Tree. The Device Tree bindings for the Generic timers can be found
at:
- linux/Documentation/devicetree/bindings/timer/arm,arch_timer.yaml

The FdtHwInfoParser implements a Generic Timer Parser that parses
the platform Device Tree to create a CM_ARM_GENERIC_TIMER_INFO
object. The CM_ARM_GENERIC_TIMER_INFO object is encapsulated in a
Configuration Manager descriptor object and added to the platform
information repository.

The platform Configuration Manager can then utilise this information
when generating the GTDT table.

Note: The Generic Timer Parser currently does not support parsing
of memory-mapped platform timers.

Signed-off-by: Pierre Gondois <Pierre.Gondois@...>
Signed-off-by: Sami Mujawar <sami.mujawar@...>
---
.../GenericTimer/ArmGenericTimerParser.c | 254 ++++++++++++++++++
.../GenericTimer/ArmGenericTimerParser.h | 66 +++++
2 files changed, 320 insertions(+)
create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/GenericTimer/ArmGenericTimerParser.c
create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/GenericTimer/ArmGenericTimerParser.h

diff --git a/DynamicTablesPkg/Library/FdtHwInfoParserLib/GenericTimer/ArmGenericTimerParser.c b/DynamicTablesPkg/Library/FdtHwInfoParserLib/GenericTimer/ArmGenericTimerParser.c
new file mode 100644
index 000000000000..e7095396a5a8
--- /dev/null
+++ b/DynamicTablesPkg/Library/FdtHwInfoParserLib/GenericTimer/ArmGenericTimerParser.c
@@ -0,0 +1,254 @@
+/** @file
+ Arm generic timer parser.
+
+ Copyright (c) 2021, ARM Limited. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - linux/Documentation/devicetree/bindings/timer/arm,arch_timer.yaml
+**/
+
+#include "FdtHwInfoParser.h"
+#include "CmObjectDescUtility.h"
+#include "GenericTimer/ArmGenericTimerParser.h"
+#include "Gic/ArmGicDispatcher.h"
+
+/** List of "compatible" property values for timer nodes.
+
+ Other "compatible" values are not supported by this module.
+*/
+STATIC CONST COMPATIBILITY_STR TimerCompatibleStr[] = {
+ {"arm,armv7-timer"},
+ {"arm,armv8-timer"}
+};
+
+/** Timer compatiblity information.
+*/
+STATIC CONST COMPATIBILITY_INFO TimerCompatibleInfo = {
+ ARRAY_SIZE (TimerCompatibleStr),
+ TimerCompatibleStr
+};
+
+/** Parse a timer node.
+
+ @param [in] Fdt Pointer to a Flattened Device Tree (Fdt).
+ @param [in] TimerNode Offset of a timer node.
+ @param [in] GenericTimerInfo The CM_ARM_BOOT_ARCH_INFO to populate.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+TimerNodeParser (
+ IN CONST VOID * Fdt,
+ IN INT32 TimerNode,
+ IN CM_ARM_GENERIC_TIMER_INFO * GenericTimerInfo
+ )
+{
+ EFI_STATUS Status;
+ CONST UINT32 * Data;
+ INT32 IntcNode;
+ UINT32 GicVersion;
+ INT32 DataSize;
+ INT32 IntCells;
+ BOOLEAN AlwaysOnTimer;
+
+ if ((Fdt == NULL) ||
+ (GenericTimerInfo == NULL)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Data = fdt_getprop (Fdt, TimerNode, "always-on", &DataSize);
+ if ((Data == NULL) || (DataSize < 0)) {
+ AlwaysOnTimer = FALSE;
+ } else {
+ AlwaysOnTimer = TRUE;
+ }
+
+ // Get the associated interrupt-controller.
+ Status = FdtGetIntcParentNode (Fdt, TimerNode, &IntcNode);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Check that the interrupt-controller node is a Gic.
+ Status = GetGicVersion (Fdt, IntcNode, &GicVersion);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Get the number of cells used to encode an interrupt.
+ Status = FdtGetInterruptCellsInfo (Fdt, IntcNode, &IntCells);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ if (Status == EFI_NOT_FOUND) {
+ // Should have found the node.
+ Status = EFI_ABORTED;
+ }
+ return Status;
+ }
+
+ Data = fdt_getprop (Fdt, TimerNode, "interrupts", &DataSize);
+ if ((Data == NULL) ||
+ (DataSize != (FdtMaxTimerItem * IntCells * sizeof (UINT32)))) {
+ // If error or not FdtMaxTimerItem interrupts.
+ ASSERT (0);
+ return EFI_ABORTED;
+ }
+
+ GenericTimerInfo->SecurePL1TimerGSIV =
+ FdtGetInterruptId (&Data[FdtSecureTimerIrq * IntCells]);
+ GenericTimerInfo->SecurePL1TimerFlags =
+ FdtGetInterruptFlags (&Data[FdtSecureTimerIrq * IntCells]);
+ GenericTimerInfo->NonSecurePL1TimerGSIV =
+ FdtGetInterruptId (&Data[FdtNonSecureTimerIrq * IntCells]);
+ GenericTimerInfo->NonSecurePL1TimerFlags =
+ FdtGetInterruptFlags (&Data[FdtNonSecureTimerIrq * IntCells]);
+ GenericTimerInfo->VirtualTimerGSIV =
+ FdtGetInterruptId (&Data[FdtVirtualTimerIrq * IntCells]);
+ GenericTimerInfo->VirtualTimerFlags =
+ FdtGetInterruptFlags (&Data[FdtVirtualTimerIrq * IntCells]);
+ GenericTimerInfo->NonSecurePL2TimerGSIV =
+ FdtGetInterruptId (&Data[FdtHypervisorTimerIrq * IntCells]);
+ GenericTimerInfo->NonSecurePL2TimerFlags =
+ FdtGetInterruptFlags (&Data[FdtHypervisorTimerIrq * IntCells]);
+
+ if (AlwaysOnTimer) {
+ GenericTimerInfo->SecurePL1TimerFlags |= BIT2;
+ GenericTimerInfo->NonSecurePL1TimerFlags |= BIT2;
+ GenericTimerInfo->VirtualTimerFlags |= BIT2;
+ GenericTimerInfo->NonSecurePL2TimerFlags |= BIT2;
+ }
+
+ // Setup default values
+ // The CntControlBase & CntReadBase Physical Address are optional if
+ // the system implements EL3 (Security Extensions). So, initialise
+ // these to their default value.
+ GenericTimerInfo->CounterControlBaseAddress = 0xFFFFFFFFFFFFFFFF;
+ GenericTimerInfo->CounterReadBaseAddress = 0xFFFFFFFFFFFFFFFF;
+
+ // For systems not implementing ARMv8.1 VHE, this field is 0.
+ GenericTimerInfo->VirtualPL2TimerGSIV = 0;
+ GenericTimerInfo->VirtualPL2TimerFlags = 0;
+
+ return EFI_SUCCESS;
+}
+
+/** CM_ARM_GENERIC_TIMER_INFO parser function.
+
+ The following structure is populated:
+ typedef struct CmArmGenericTimerInfo {
+ UINT64 CounterControlBaseAddress; // {default}
+ UINT64 CounterReadBaseAddress; // {default}
+ UINT32 SecurePL1TimerGSIV; // {Populated}
+ UINT32 SecurePL1TimerFlags; // {Populated}
+ UINT32 NonSecurePL1TimerGSIV; // {Populated}
+ UINT32 NonSecurePL1TimerFlags; // {Populated}
+ UINT32 VirtualTimerGSIV; // {Populated}
+ UINT32 VirtualTimerFlags; // {Populated}
+ UINT32 NonSecurePL2TimerGSIV; // {Populated}
+ UINT32 NonSecurePL2TimerFlags; // {Populated}
+ UINT32 VirtualPL2TimerGSIV; // {default}
+ UINT32 VirtualPL2TimerFlags; // {default}
+ } CM_ARM_GENERIC_TIMER_INFO;
+
+ A parser parses a Device Tree to populate a specific CmObj type. None,
+ one or many CmObj can be created by the parser.
+ The created CmObj are then handed to the parser's caller through the
+ HW_INFO_ADD_OBJECT interface.
+ This can also be a dispatcher. I.e. a function that not parsing a
+ Device Tree but calling other parsers.
+
+ @param [in] FdtParserHandle A handle to the parser instance.
+ @param [in] FdtBranch When searching for DT node name, restrict
+ the search to this Device Tree branch.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND Not found.
+ @retval EFI_UNSUPPORTED Unsupported.
+**/
+EFI_STATUS
+EFIAPI
+ArmGenericTimerInfoParser (
+ IN CONST FDT_HW_INFO_PARSER_HANDLE FdtParserHandle,
+ IN INT32 FdtBranch
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Index;
+ INT32 TimerNode;
+ UINT32 TimerNodeCount;
+ CM_ARM_GENERIC_TIMER_INFO GenericTimerInfo;
+ VOID * Fdt;
+
+ if (FdtParserHandle == NULL) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Fdt = FdtParserHandle->Fdt;
+ Status = FdtCountCompatNodeInBranch (
+ Fdt,
+ FdtBranch,
+ &TimerCompatibleInfo,
+ &TimerNodeCount
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ if (TimerNodeCount == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ // Parse each timer node in the branch.
+ TimerNode = FdtBranch;
+ for (Index = 0; Index < TimerNodeCount; Index++) {
+ ZeroMem (&GenericTimerInfo, sizeof (CM_ARM_GENERIC_TIMER_INFO));
+
+ Status = FdtGetNextCompatNodeInBranch (
+ Fdt,
+ FdtBranch,
+ &TimerCompatibleInfo,
+ &TimerNode
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ if (Status == EFI_NOT_FOUND) {
+ // Should have found the node.
+ Status = EFI_ABORTED;
+ }
+ return Status;
+ }
+
+ Status = TimerNodeParser (Fdt, TimerNode, &GenericTimerInfo);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Add the CmObj to the Configuration Manager.
+ Status = AddSingleCmObj (
+ FdtParserHandle,
+ CREATE_CM_ARM_OBJECT_ID (EArmObjGenericTimerInfo),
+ &GenericTimerInfo,
+ sizeof (CM_ARM_GENERIC_TIMER_INFO),
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+ } // for
+
+ return Status;
+}
diff --git a/DynamicTablesPkg/Library/FdtHwInfoParserLib/GenericTimer/ArmGenericTimerParser.h b/DynamicTablesPkg/Library/FdtHwInfoParserLib/GenericTimer/ArmGenericTimerParser.h
new file mode 100644
index 000000000000..e1d294b3eea9
--- /dev/null
+++ b/DynamicTablesPkg/Library/FdtHwInfoParserLib/GenericTimer/ArmGenericTimerParser.h
@@ -0,0 +1,66 @@
+/** @file
+ Arm generic timer parser.
+
+ Copyright (c) 2021, ARM Limited. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - linux/Documentation/devicetree/bindings/timer/arm,arch_timer.yaml
+**/
+
+#ifndef ARM_GENERIC_TIMER_PARSER_H_
+#define ARM_GENERIC_TIMER_PARSER_H_
+
+/** An enum listing the FDT interrupt items.
+*/
+typedef enum FdtTimerInterruptItems {
+ FdtSecureTimerIrq, ///< Secure timer IRQ
+ FdtNonSecureTimerIrq, ///< Non-secure timer IRQ
+ FdtVirtualTimerIrq, ///< Virtual timer IRQ
+ FdtHypervisorTimerIrq, ///< Hypervisor timer IRQ
+ FdtMaxTimerItem ///< Max timer item
+} FDT_TIMER_INTERRUPT_ITEMS;
+
+/** CM_ARM_BOOT_ARCH_INFO parser function.
+
+ The following structure is populated:
+ typedef struct CmArmGenericTimerInfo {
+ UINT64 CounterControlBaseAddress; // {default}
+ UINT64 CounterReadBaseAddress; // {default}
+ UINT32 SecurePL1TimerGSIV; // {Populated}
+ UINT32 SecurePL1TimerFlags; // {Populated}
+ UINT32 NonSecurePL1TimerGSIV; // {Populated}
+ UINT32 NonSecurePL1TimerFlags; // {Populated}
+ UINT32 VirtualTimerGSIV; // {Populated}
+ UINT32 VirtualTimerFlags; // {Populated}
+ UINT32 NonSecurePL2TimerGSIV; // {Populated}
+ UINT32 NonSecurePL2TimerFlags; // {Populated}
+ UINT32 VirtualPL2TimerGSIV; // {default}
+ UINT32 VirtualPL2TimerFlags; // {default}
+ } CM_ARM_GENERIC_TIMER_INFO;
+
+ A parser parses a Device Tree to populate a specific CmObj type. None,
+ one or many CmObj can be created by the parser.
+ The created CmObj are then handed to the parser's caller through the
+ HW_INFO_ADD_OBJECT interface.
+ This can also be a dispatcher. I.e. a function that not parsing a
+ Device Tree but calling other parsers.
+
+ @param [in] FdtParserHandle A handle to the parser instance.
+ @param [in] FdtBranch When searching for DT node name, restrict
+ the search to this Device Tree branch.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND Not found.
+ @retval EFI_UNSUPPORTED Unsupported.
+**/
+EFI_STATUS
+EFIAPI
+ArmGenericTimerInfoParser (
+ IN CONST FDT_HW_INFO_PARSER_HANDLE FdtParserHandle,
+ IN INT32 FdtBranch
+ );
+
+#endif // ARM_GENERIC_TIMER_PARSER_H_
--
2.17.1


[PATCH v1 04/14] DynamicTablesPkg: FdtHwInfoParser: Add Boot Arch parser

PierreGondois
 

From: Pierre Gondois <Pierre.Gondois@...>

The Fixed ACPI Description Table (FADT) is a mandatory table
required for booting a standards-based operating system. The
FADT table has an 'ARM Boot Architecture Flags' field that is
used by an OS at boot time to determine the code path during
boot. This field is used to specify if the platform complies
with the PSCI specification. It is also used to describe the
conduit (SMC/HVC) to be used for PSCI.

The PSCI compliance information for a platform is described
in the platform Device Tree, the bindings for which can be
found at:
- linux/Documentation/devicetree/bindings/arm/psci.yaml

The FdtHwInfoParser implements a Boot Arch Parser that parses
the platform Device Tree to create a CM_ARM_BOOT_ARCH_INFO
object. The CM_ARM_BOOT_ARCH_INFO object is encapsulated in
a Configuration Manager descriptor object and added to the
platform information repository.

The platform Configuration Manager can then utilise this
information when generating the FADT table.

Signed-off-by: Pierre Gondois <Pierre.Gondois@...>
Signed-off-by: Sami Mujawar <sami.mujawar@...>
---
.../BootArch/ArmBootArchParser.c | 161 ++++++++++++++++++
.../BootArch/ArmBootArchParser.h | 45 +++++
2 files changed, 206 insertions(+)
create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/BootArch/ArmBootArchParser.c
create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/BootArch/ArmBootArchParser.h

diff --git a/DynamicTablesPkg/Library/FdtHwInfoParserLib/BootArch/ArmBootArchParser.c b/DynamicTablesPkg/Library/FdtHwInfoParserLib/BootArch/ArmBootArchParser.c
new file mode 100644
index 000000000000..b18970f115f2
--- /dev/null
+++ b/DynamicTablesPkg/Library/FdtHwInfoParserLib/BootArch/ArmBootArchParser.c
@@ -0,0 +1,161 @@
+/** @file
+ Arm boot architecture parser.
+
+ Copyright (c) 2021, ARM Limited. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - linux/Documentation/devicetree/bindings/arm/psci.yaml
+**/
+
+#include "FdtHwInfoParser.h"
+#include "CmObjectDescUtility.h"
+#include "BootArch/ArmBootArchParser.h"
+
+/** List of "compatible" property values for Psci nodes.
+
+ Other "compatible" values are not supported by this module.
+*/
+STATIC CONST COMPATIBILITY_STR PsciCompatibleStr[] = {
+ {"arm,psci-0.2"},
+ {"arm,psci"}
+};
+
+/** COMPATIBILITY_INFO structure for the PsciCompatibleInfo.
+*/
+STATIC CONST COMPATIBILITY_INFO PsciCompatibleInfo = {
+ ARRAY_SIZE (PsciCompatibleStr),
+ PsciCompatibleStr
+};
+
+/** List of PSCI method strings.
+*/
+STATIC CONST CHAR8 *PsciMethod[] = {
+ "smc",
+ "hvc"
+};
+
+/** Parse a Psci node.
+
+ @param [in] Fdt Pointer to a Flattened Device Tree (Fdt).
+ @param [in] PsciNode Offset of a Psci node.
+ @param [in] BootArchInfo The CM_ARM_BOOT_ARCH_INFO to populate.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+PsciNodeParser (
+ IN CONST VOID * Fdt,
+ IN INT32 PsciNode,
+ IN CM_ARM_BOOT_ARCH_INFO * BootArchInfo
+ )
+{
+ CONST VOID * Data;
+ INT32 DataSize;
+
+ if ((Fdt == NULL) ||
+ (BootArchInfo == NULL)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Default to parking protocol
+ BootArchInfo->BootArchFlags = 0;
+
+ Data = fdt_getprop (Fdt, PsciNode, "method", &DataSize);
+ if ((Data == NULL) || (DataSize < 0)) {
+ ASSERT (0);
+ return EFI_ABORTED;
+ }
+
+ // Check PSCI conduit.
+ if (AsciiStrnCmp (Data, PsciMethod[0], DataSize) == 0) {
+ BootArchInfo->BootArchFlags = EFI_ACPI_6_3_ARM_PSCI_COMPLIANT;
+
+ } else if (AsciiStrnCmp (Data, PsciMethod[1], DataSize) == 0) {
+ BootArchInfo->BootArchFlags = (EFI_ACPI_6_3_ARM_PSCI_COMPLIANT |
+ EFI_ACPI_6_3_ARM_PSCI_USE_HVC);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/** CM_ARM_BOOT_ARCH_INFO parser function.
+
+ The following structure is populated:
+ typedef struct CmArmBootArchInfo {
+ UINT16 BootArchFlags; // {Populated}
+ } CM_ARM_BOOT_ARCH_INFO;
+
+ A parser parses a Device Tree to populate a specific CmObj type. None,
+ one or many CmObj can be created by the parser.
+ The created CmObj are then handed to the parser's caller through the
+ HW_INFO_ADD_OBJECT interface.
+ This can also be a dispatcher. I.e. a function that not parsing a
+ Device Tree but calling other parsers.
+
+ @param [in] FdtParserHandle A handle to the parser instance.
+ @param [in] FdtBranch When searching for DT node name, restrict
+ the search to this Device Tree branch.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND Not found.
+ @retval EFI_UNSUPPORTED Unsupported.
+**/
+EFI_STATUS
+EFIAPI
+ArmBootArchInfoParser (
+ IN CONST FDT_HW_INFO_PARSER_HANDLE FdtParserHandle,
+ IN INT32 FdtBranch
+ )
+{
+ EFI_STATUS Status;
+ INT32 PsciNode;
+ CM_ARM_BOOT_ARCH_INFO BootArchInfo;
+
+ if (FdtParserHandle == NULL) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ZeroMem (&BootArchInfo, sizeof (CM_ARM_BOOT_ARCH_INFO));
+
+ PsciNode = FdtBranch;
+ Status = FdtGetNextCompatNodeInBranch (
+ FdtParserHandle->Fdt,
+ FdtBranch,
+ &PsciCompatibleInfo,
+ &PsciNode
+ );
+ if (EFI_ERROR (Status)) {
+ // Error, or no node found.
+ ASSERT (Status == EFI_NOT_FOUND);
+ return Status;
+ }
+
+ // Parse the psci node.
+ Status = PsciNodeParser (FdtParserHandle->Fdt, PsciNode, &BootArchInfo);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Add the CmObj to the Configuration Manager.
+ Status = AddSingleCmObj (
+ FdtParserHandle,
+ CREATE_CM_ARM_OBJECT_ID (EArmObjBootArchInfo),
+ &BootArchInfo,
+ sizeof (CM_ARM_BOOT_ARCH_INFO),
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ }
+ return Status;
+}
diff --git a/DynamicTablesPkg/Library/FdtHwInfoParserLib/BootArch/ArmBootArchParser.h b/DynamicTablesPkg/Library/FdtHwInfoParserLib/BootArch/ArmBootArchParser.h
new file mode 100644
index 000000000000..959c65a53fb3
--- /dev/null
+++ b/DynamicTablesPkg/Library/FdtHwInfoParserLib/BootArch/ArmBootArchParser.h
@@ -0,0 +1,45 @@
+/** @file
+ Arm boot architecture parser.
+
+ Copyright (c) 2021, ARM Limited. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - linux/Documentation/devicetree/bindings/arm/psci.yaml
+**/
+
+#ifndef ARM_BOOT_ARCH_PARSER_H_
+#define ARM_BOOT_ARCH_PARSER_H_
+
+/** CM_ARM_BOOT_ARCH_INFO parser function.
+
+ The following structure is populated:
+ typedef struct CmArmBootArchInfo {
+ UINT16 BootArchFlags; // {Populated}
+ } CM_ARM_BOOT_ARCH_INFO;
+
+ A parser parses a Device Tree to populate a specific CmObj type. None,
+ one or many CmObj can be created by the parser.
+ The created CmObj are then handed to the parser's caller through the
+ HW_INFO_ADD_OBJECT interface.
+ This can also be a dispatcher. I.e. a function that not parsing a
+ Device Tree but calling other parsers.
+
+ @param [in] FdtParserHandle A handle to the parser instance.
+ @param [in] FdtBranch When searching for DT node name, restrict
+ the search to this Device Tree branch.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND Not found.
+ @retval EFI_UNSUPPORTED Unsupported.
+**/
+EFI_STATUS
+EFIAPI
+ArmBootArchInfoParser (
+ IN CONST FDT_HW_INFO_PARSER_HANDLE FdtParserHandle,
+ IN INT32 FdtBranch
+ );
+
+#endif // ARM_BOOT_ARCH_PARSER_H_
--
2.17.1


[PATCH v1 03/14] DynamicTablesPkg: FdtHwInfoParser: Add FDT utility functions

PierreGondois
 

From: Pierre Gondois <Pierre.Gondois@...>

The FdtHwInfoParser parses a platform Device Tree and populates
the Platform Information repository with Configuration Manager
objects.

Therefore, add a set of helper functions to simplify parsing of
the platform Device Tree.

Signed-off-by: Pierre Gondois <Pierre.Gondois@...>
Signed-off-by: Sami Mujawar <sami.mujawar@...>
---
.../Library/FdtHwInfoParserLib/FdtUtility.c | 909 ++++++++++++++++++
.../Library/FdtHwInfoParserLib/FdtUtility.h | 458 +++++++++
2 files changed, 1367 insertions(+)
create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/FdtUtility.c
create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/FdtUtility.h

diff --git a/DynamicTablesPkg/Library/FdtHwInfoParserLib/FdtUtility.c b/DynamicTablesPkg/Library/FdtHwInfoParserLib/FdtUtility.c
new file mode 100644
index 000000000000..0fca82aedf9e
--- /dev/null
+++ b/DynamicTablesPkg/Library/FdtHwInfoParserLib/FdtUtility.c
@@ -0,0 +1,909 @@
+/** @file
+ Flattened device tree utility.
+
+ Copyright (c) 2021, ARM Limited. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - Device tree Specification - Release v0.3
+ - linux/Documentation/devicetree/bindings/interrupt-controller/arm%2Cgic.yaml
+ - linux//Documentation/devicetree/bindings/interrupt-controller/arm%2Cgic.yaml
+**/
+
+#include <FdtHwInfoParserInclude.h>
+#include "FdtUtility.h"
+
+/** Get the interrupt Id of an interrupt described in a fdt.
+
+ Data must describe a GIC interrupt. A GIC interrupt is on at least
+ 3 UINT32 cells.
+ This function DOES NOT SUPPORT extended SPI range and extended PPI range.
+
+ @param [in] Data Pointer to the first cell of an "interrupts" property.
+
+ @retval The interrupt id.
+**/
+UINT32
+EFIAPI
+FdtGetInterruptId (
+ UINT32 CONST * Data
+ )
+{
+ UINT32 IrqType;
+ UINT32 IrqId;
+
+ ASSERT (Data != NULL);
+
+ IrqType = fdt32_to_cpu (Data[IRQ_TYPE_OFFSET]);
+ IrqId = fdt32_to_cpu (Data[IRQ_NUMBER_OFFSET]);
+
+ switch (IrqType) {
+ case DT_SPI_IRQ:
+ IrqId += SPI_OFFSET;
+ break;
+
+ case DT_PPI_IRQ:
+ IrqId += PPI_OFFSET;
+ break;
+
+ default:
+ ASSERT (0);
+ IrqId = 0;
+ }
+
+ return IrqId;
+}
+
+/** Get the ACPI interrupt flags of an interrupt described in a fdt.
+
+ Data must describe a GIC interrupt. A GIC interrupt is on at least
+ 3 UINT32 cells.
+
+ PPI interrupt cpu mask on bits [15:8] are ignored.
+
+ @param [in] Data Pointer to the first cell of an "interrupts" property.
+
+ @retval The interrupt flags (for ACPI).
+**/
+UINT32
+EFIAPI
+FdtGetInterruptFlags (
+ UINT32 CONST * Data
+ )
+{
+ UINT32 IrqFlags;
+ UINT32 AcpiIrqFlags;
+
+ ASSERT (Data != NULL);
+
+ IrqFlags = fdt32_to_cpu (Data[IRQ_FLAGS_OFFSET]);
+
+ AcpiIrqFlags = DT_IRQ_IS_EDGE_TRIGGERED (IrqFlags) ? BIT0 : 0;
+ AcpiIrqFlags |= DT_IRQ_IS_ACTIVE_LOW (IrqFlags) ? BIT1 : 0;
+
+ return AcpiIrqFlags;
+}
+
+/** Check whether a node has the input name.
+
+ @param [in] Fdt Pointer to a Flattened Device Tree.
+ @param [in] Node Offset of the node to check the name.
+ @param [in] SearchName Node name to search.
+ This is a NULL terminated string.
+
+ @retval True The node has the input name.
+ @retval FALSE Otherwise, or error.
+**/
+STATIC
+BOOLEAN
+EFIAPI
+FdtNodeHasName (
+ IN CONST VOID * Fdt,
+ IN INT32 Node,
+ IN CONST VOID * SearchName
+ )
+{
+ CONST CHAR8 * NodeName;
+ UINT32 Length;
+
+ if ((Fdt == NULL) ||
+ (SearchName == NULL)) {
+ ASSERT (0);
+ return FALSE;
+ }
+
+ // Always compare the whole string. Don't stop at the "@" char.
+ Length = (UINT32)AsciiStrLen (SearchName);
+
+ // Get the address of the node name.
+ NodeName = fdt_offset_ptr (Fdt, Node + FDT_TAGSIZE, Length + 1);
+ if (NodeName == NULL) {
+ return FALSE;
+ }
+
+ // SearchName must be longer than the node name.
+ if (Length > AsciiStrLen (NodeName)) {
+ return FALSE;
+ }
+
+ // Use CompareMem here instead of AsciiStrnCmp as the NodeName
+ // may contain the node name followed by '@'0x<addr>.
+ if (AsciiStrnCmp (NodeName, SearchName, Length) != 0) {
+ return FALSE;
+ }
+
+ // The name matches perfectly, or
+ // the node name is XXX@addr and the XXX matches.
+ if ((NodeName[Length] == '\0') ||
+ (NodeName[Length] == '@')) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/** Iterate through the list of strings in the Context,
+ and check whether at least one string is matching the
+ "compatible" property of the node.
+
+ @param [in] Fdt Pointer to a Flattened Device Tree.
+ @param [in] Node Offset of the node to operate the check on.
+ @param [in] CompatInfo COMPATIBILITY_INFO containing the list of compatible
+ strings to compare with the "compatible" property
+ of the node.
+
+ @retval TRUE At least one string matched, the node is compatible.
+ @retval FALSE Otherwise, or error.
+**/
+BOOLEAN
+EFIAPI
+FdtNodeIsCompatible (
+ IN CONST VOID * Fdt,
+ IN INT32 Node,
+ IN CONST VOID * CompatInfo
+ )
+{
+ UINT32 Index;
+ CONST COMPATIBILITY_STR * CompatibleTable;
+ UINT32 Count;
+ CONST VOID * Prop;
+ INT32 PropLen;
+
+ if ((Fdt == NULL) ||
+ (CompatInfo == NULL)) {
+ ASSERT (0);
+ return FALSE;
+ }
+
+ Count = ((COMPATIBILITY_INFO*)CompatInfo)->Count;
+ CompatibleTable = ((COMPATIBILITY_INFO*)CompatInfo)->CompatTable;
+
+ // Get the "compatible" property.
+ Prop = fdt_getprop (Fdt, Node, "compatible", &PropLen);
+ if ((Prop == NULL) || (PropLen < 0)) {
+ return FALSE;
+ }
+
+ for (Index = 0; Index < Count; Index++) {
+ if (fdt_stringlist_contains (
+ Prop,
+ PropLen,
+ CompatibleTable[Index].CompatStr
+ )) {
+ return TRUE;
+ }
+ } // for
+
+ return FALSE;
+}
+
+/** Check whether a node has a property.
+
+ @param [in] Fdt Pointer to a Flattened Device Tree.
+ @param [in] Node Offset of the node to operate the check on.
+ @param [in] PropertyName Name of the property to search.
+ This is a NULL terminated string.
+
+ @retval True The node has the property.
+ @retval FALSE Otherwise, or error.
+**/
+BOOLEAN
+EFIAPI
+FdtNodeHasProperty (
+ IN CONST VOID * Fdt,
+ IN INT32 Node,
+ IN CONST VOID * PropertyName
+ )
+{
+ INT32 Size;
+ CONST VOID * Prop;
+
+ if ((Fdt == NULL) ||
+ (PropertyName == NULL)) {
+ ASSERT (0);
+ return FALSE;
+ }
+
+ Prop = fdt_getprop (Fdt, Node, PropertyName, &Size);
+ if ((Prop == NULL) || (Size < 0)) {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/** Get the next node in the whole DT fulfilling a condition.
+
+ The condition to fulfill is checked by the NodeChecker function.
+ Context is passed to NodeChecker.
+
+ The Device tree is traversed in a depth-first search, starting from Node.
+ The input Node is skipped.
+
+ @param [in] Fdt Pointer to a Flattened Device Tree.
+ @param [in, out] Node At entry: Node offset to start the search.
+ This first node is skipped.
+ Write (-1) to search the whole tree.
+ At exit: If success, contains the offset of
+ the next node fulfilling the
+ condition.
+ @param [in, out] Depth Depth is incremented/decremented of the depth
+ difference between the input Node and the
+ output Node.
+ E.g.: If the output Node is a child node
+ of the input Node, contains (+1).
+ @param [in] NodeChecker Function called to check if the condition
+ is fulfilled.
+ @param [in] Context Context for the NodeChecker.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND No matching node found.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+FdtGetNextCondNode (
+ IN CONST VOID * Fdt,
+ IN OUT INT32 * Node,
+ IN OUT INT32 * Depth,
+ IN NODE_CHECKER_FUNC NodeChecker,
+ IN CONST VOID * Context
+ )
+{
+ INT32 CurrNode;
+
+ if ((Fdt == NULL) ||
+ (Node == NULL) ||
+ (Depth == NULL) ||
+ (NodeChecker == NULL)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CurrNode = *Node;
+ do {
+ CurrNode = fdt_next_node (Fdt, CurrNode, Depth);
+ if ((CurrNode == -FDT_ERR_NOTFOUND) ||
+ (*Depth < 0)) {
+ // End of the tree, no matching node found.
+ return EFI_NOT_FOUND;
+ } else if (CurrNode < 0) {
+ // An error occurred.
+ ASSERT (0);
+ return EFI_ABORTED;
+ }
+ } while (!NodeChecker (Fdt, CurrNode, Context));
+
+ // Matching node found.
+ *Node = CurrNode;
+ return EFI_SUCCESS;
+}
+
+/** Get the next node in a branch fulfilling a condition.
+
+ The condition to fulfill is checked by the NodeChecker function.
+ Context is passed to NodeChecker.
+
+ The Device tree is traversed in a depth-first search, starting from Node.
+ The input Node is skipped.
+
+ @param [in] Fdt Pointer to a Flattened Device Tree.
+ @param [in] FdtBranch Only search in the sub-nodes of this
+ branch.
+ Write (-1) to search the whole tree.
+ @param [in] NodeChecker Function called to check if the condition
+ is fulfilled.
+ @param [in] Context Context for the NodeChecker.
+ @param [in, out] Node At entry: Node offset to start the search.
+ This first node is skipped.
+ Write (-1) to search the whole tree.
+ At exit: If success, contains the offset
+ of the next node in the branch
+ fulfilling the condition.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND No matching node found.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+FdtGetNextCondNodeInBranch (
+ IN CONST VOID * Fdt,
+ IN INT32 FdtBranch,
+ IN NODE_CHECKER_FUNC NodeChecker,
+ IN CONST VOID * Context,
+ IN OUT INT32 * Node
+ )
+{
+ EFI_STATUS Status;
+ INT32 CurrNode;
+ INT32 Depth;
+
+ if ((Fdt == NULL) ||
+ (Node == NULL) ||
+ (NodeChecker == NULL)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CurrNode = FdtBranch;
+ Depth = 0;
+
+ // First, check the Node is in the sub-nodes of the branch.
+ // This allows to find the relative depth of Node in the branch.
+ if (CurrNode != *Node) {
+ for (CurrNode = fdt_next_node (Fdt, CurrNode, &Depth);
+ (CurrNode >= 0) && (Depth > 0);
+ CurrNode = fdt_next_node (Fdt, CurrNode, &Depth)) {
+ if (CurrNode == *Node) {
+ // Node found.
+ break;
+ }
+ } // for
+
+ if ((CurrNode < 0) || (Depth <= 0)) {
+ // Node is not a node in the branch, or an error occurred.
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ // Get the next node in the tree fulfilling the condition,
+ // in any branch.
+ Status = FdtGetNextCondNode (
+ Fdt,
+ Node,
+ &Depth,
+ NodeChecker,
+ Context
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (Status == EFI_NOT_FOUND);
+ return Status;
+ }
+
+ if (Depth <= 0) {
+ // The node found is not in the right branch.
+ return EFI_NOT_FOUND;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/** Get the next node in a branch having a matching name.
+
+ The Device tree is traversed in a depth-first search, starting from Node.
+ The input Node is skipped.
+
+ @param [in] Fdt Pointer to a Flattened Device Tree.
+ @param [in] FdtBranch Only search in the sub-nodes of this branch.
+ Write (-1) to search the whole tree.
+ @param [in] NodeName The node name to search.
+ This is a NULL terminated string.
+ @param [in, out] Node At entry: Node offset to start the search.
+ This first node is skipped.
+ Write (-1) to search the whole tree.
+ At exit: If success, contains the offset of
+ the next node in the branch
+ having a matching name.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND No matching node found.
+**/
+EFI_STATUS
+EFIAPI
+FdtGetNextNamedNodeInBranch (
+ IN CONST VOID * Fdt,
+ IN INT32 FdtBranch,
+ IN CONST CHAR8 * NodeName,
+ IN OUT INT32 * Node
+ )
+{
+ return FdtGetNextCondNodeInBranch (
+ Fdt,
+ FdtBranch,
+ FdtNodeHasName,
+ NodeName,
+ Node
+ );
+}
+
+/** Get the next node in a branch with at least one compatible property.
+
+ The Device tree is traversed in a depth-first search, starting from Node.
+ The input Node is skipped.
+
+ @param [in] Fdt Pointer to a Flattened Device Tree.
+ @param [in] FdtBranch Only search in the sub-nodes of this branch.
+ Write (-1) to search the whole tree.
+ @param [in] CompatNamesInfo Table of compatible strings to compare with
+ the compatible property of the node.
+ @param [in, out] Node At entry: Node offset to start the search.
+ This first node is skipped.
+ Write (-1) to search the whole tree.
+ At exit: If success, contains the offset of
+ the next node in the branch
+ being compatible.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND No matching node found.
+**/
+EFI_STATUS
+EFIAPI
+FdtGetNextCompatNodeInBranch (
+ IN CONST VOID * Fdt,
+ IN INT32 FdtBranch,
+ IN CONST COMPATIBILITY_INFO * CompatNamesInfo,
+ IN OUT INT32 * Node
+ )
+{
+ return FdtGetNextCondNodeInBranch (
+ Fdt,
+ FdtBranch,
+ FdtNodeIsCompatible,
+ (CONST VOID*)CompatNamesInfo,
+ Node
+ );
+}
+
+/** Get the next node in a branch having the PropName property.
+
+ The Device tree is traversed in a depth-first search, starting from Node.
+ The input Node is skipped.
+
+ @param [in] Fdt Pointer to a Flattened Device Tree.
+ @param [in] FdtBranch Only search in the sub-nodes of this branch.
+ Write (-1) to search the whole tree.
+ @param [in] PropName Name of the property to search.
+ This is a NULL terminated string.
+ @param [in, out] Node At entry: Node offset to start the search.
+ This first node is skipped.
+ Write (-1) to search the whole tree.
+ At exit: If success, contains the offset of
+ the next node in the branch
+ being compatible.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND No matching node found.
+**/
+EFI_STATUS
+EFIAPI
+FdtGetNextPropNodeInBranch (
+ IN CONST VOID * Fdt,
+ IN INT32 FdtBranch,
+ IN CONST CHAR8 * PropName,
+ IN OUT INT32 * Node
+ )
+{
+ return FdtGetNextCondNodeInBranch (
+ Fdt,
+ FdtBranch,
+ FdtNodeHasProperty,
+ (CONST VOID*)PropName,
+ Node
+ );
+}
+
+/** Count the number of Device Tree nodes fulfilling a condition
+ in a Device Tree branch.
+
+ The condition to fulfill is checked by the NodeChecker function.
+ Context is passed to NodeChecker.
+
+ @param [in] Fdt Pointer to a Flattened Device Tree.
+ @param [in] FdtBranch Only search in the sub-nodes of this branch.
+ Write (-1) to search the whole tree.
+ @param [in] NodeChecker Function called to check the condition is
+ fulfilled.
+ @param [in] Context Context for the NodeChecker.
+ @param [out] NodeCount If success, contains the count of nodes
+ fulfilling the condition.
+ Can be 0.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+FdtCountCondNodeInBranch (
+ IN CONST VOID * Fdt,
+ IN INT32 FdtBranch,
+ IN NODE_CHECKER_FUNC NodeChecker,
+ IN CONST VOID * Context,
+ OUT UINT32 * NodeCount
+ )
+{
+ EFI_STATUS Status;
+ INT32 CurrNode;
+
+ if ((Fdt == NULL) ||
+ (NodeChecker == NULL) ||
+ (NodeCount == NULL)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *NodeCount = 0;
+ CurrNode = FdtBranch;
+ while (TRUE) {
+ Status = FdtGetNextCondNodeInBranch (
+ Fdt,
+ FdtBranch,
+ NodeChecker,
+ Context,
+ &CurrNode
+ );
+ if (EFI_ERROR (Status) &&
+ (Status != EFI_NOT_FOUND)) {
+ ASSERT (0);
+ return Status;
+ } else if (Status == EFI_NOT_FOUND) {
+ break;
+ }
+ (*NodeCount)++;
+ }
+ return EFI_SUCCESS;
+}
+
+/** Count the number of nodes in a branch with the input name.
+
+ @param [in] Fdt Pointer to a Flattened Device Tree.
+ @param [in] FdtBranch Only search in the sub-nodes of this branch.
+ Write (-1) to search the whole tree.
+ @param [in] NodeName Node name to search.
+ This is a NULL terminated string.
+ @param [out] NodeCount If success, contains the count of nodes
+ fulfilling the condition.
+ Can be 0.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+EFI_STATUS
+EFIAPI
+FdtCountNamedNodeInBranch (
+ IN CONST VOID * Fdt,
+ IN INT32 FdtBranch,
+ IN CONST CHAR8 * NodeName,
+ OUT UINT32 * NodeCount
+ )
+{
+ return FdtCountCondNodeInBranch (
+ Fdt,
+ FdtBranch,
+ FdtNodeHasName,
+ NodeName,
+ NodeCount
+ );
+}
+
+/** Count the number of nodes in a branch with at least
+ one compatible property.
+
+ @param [in] Fdt Pointer to a Flattened Device Tree.
+ @param [in] FdtBranch Only search in the sub-nodes of this branch.
+ Write (-1) to search the whole tree.
+ @param [in] CompatNamesInfo Table of compatible strings to
+ compare with the compatible property
+ of the node.
+ @param [out] NodeCount If success, contains the count of nodes
+ fulfilling the condition.
+ Can be 0.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+EFI_STATUS
+EFIAPI
+FdtCountCompatNodeInBranch (
+ IN CONST VOID * Fdt,
+ IN INT32 FdtBranch,
+ IN CONST COMPATIBILITY_INFO * CompatNamesInfo,
+ OUT UINT32 * NodeCount
+ )
+{
+ return FdtCountCondNodeInBranch (
+ Fdt,
+ FdtBranch,
+ FdtNodeIsCompatible,
+ CompatNamesInfo,
+ NodeCount
+ );
+}
+
+/** Count the number of nodes in a branch having the PropName property.
+
+ @param [in] Fdt Pointer to a Flattened Device Tree.
+ @param [in] FdtBranch Only search in the sub-nodes of this branch.
+ Write (-1) to search the whole tree.
+ @param [in] PropName Name of the property to search.
+ This is a NULL terminated string.
+ @param [out] NodeCount If success, contains the count of nodes
+ fulfilling the condition.
+ Can be 0.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+EFI_STATUS
+EFIAPI
+FdtCountPropNodeInBranch (
+ IN CONST VOID * Fdt,
+ IN INT32 FdtBranch,
+ IN CONST CHAR8 * PropName,
+ OUT UINT32 * NodeCount
+ )
+{
+ return FdtCountCondNodeInBranch (
+ Fdt,
+ FdtBranch,
+ FdtNodeHasProperty,
+ PropName,
+ NodeCount
+ );
+}
+
+/** Get the interrupt-controller node handling the interrupts of
+ the input node.
+
+ To do this, recursively search a node with either the "interrupt-controller"
+ or the "interrupt-parent" property in the parents of Node.
+
+ Devicetree Specification, Release v0.3,
+ 2.4.1 "Properties for Interrupt Generating Devices":
+ Because the hierarchy of the nodes in the interrupt tree
+ might not match the devicetree, the interrupt-parent
+ property is available to make the definition of an
+ interrupt parent explicit. The value is the phandle to the
+ interrupt parent. If this property is missing from a
+ device, its interrupt parent is assumed to be its devicetree
+ parent.
+
+ @param [in] Fdt Pointer to a Flattened Device Tree.
+ @param [in] Node Offset of the node to start the search.
+ @param [out] IntcNode If success, contains the offset of the
+ interrupt-controller node.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_FOUND No interrupt-controller node found.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+EFI_STATUS
+EFIAPI
+FdtGetIntcParentNode (
+ IN CONST VOID * Fdt,
+ IN INT32 Node,
+ OUT INT32 * IntcNode
+ )
+{
+ CONST UINT32 * PHandle;
+ INT32 Size;
+ CONST VOID * Prop;
+
+ if ((Fdt == NULL) ||
+ (IntcNode == NULL)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ while (TRUE) {
+ // Check whether the node has the "interrupt-controller" property.
+ Prop = fdt_getprop (Fdt, Node, "interrupt-controller", &Size);
+ if ((Prop != NULL) && (Size >= 0)) {
+ // The interrupt-controller has been found.
+ *IntcNode = Node;
+ return EFI_SUCCESS;
+ } else {
+ // Check whether the node has the "interrupt-parent" property.
+ PHandle = fdt_getprop (Fdt, Node, "interrupt-parent", &Size);
+ if ((PHandle != NULL) && (Size == sizeof (UINT32))) {
+ // The phandle of the interrupt-controller has been found.
+ // Search the node having this phandle and return it.
+ Node = fdt_node_offset_by_phandle (Fdt, fdt32_to_cpu (*PHandle));
+ if (Node < 0) {
+ ASSERT (0);
+ return EFI_ABORTED;
+ }
+
+ *IntcNode = Node;
+ return EFI_SUCCESS;
+ } else if (Size != -FDT_ERR_NOTFOUND) {
+ ASSERT (0);
+ return EFI_ABORTED;
+ }
+ }
+
+ if (Node == 0) {
+ // We are at the root of the tree. Not parent available.
+ return EFI_NOT_FOUND;
+ }
+
+ // Get the parent of the node.
+ Node = fdt_parent_offset (Fdt, Node);
+ if (Node < 0) {
+ // An error occurred.
+ ASSERT (0);
+ return EFI_ABORTED;
+ }
+ } // while
+}
+
+/** Get the "interrupt-cells" property value of the node.
+
+ The "interrupts" property requires to know the number of cells used
+ to encode an interrupt. This information is stored in the
+ interrupt-controller of the input Node.
+
+ @param [in] Fdt Pointer to a Flattened Device Tree (Fdt).
+ @param [in] IntcNode Offset of an interrupt-controller node.
+ @param [out] IntCells If success, contains the "interrupt-cells"
+ property of the IntcNode.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_UNSUPPORTED Unsupported.
+**/
+EFI_STATUS
+EFIAPI
+FdtGetInterruptCellsInfo (
+ IN CONST VOID * Fdt,
+ IN INT32 IntcNode,
+ OUT INT32 * IntCells
+ )
+{
+ CONST UINT32 * Data;
+ INT32 Size;
+
+ if ((Fdt == NULL) ||
+ (IntCells == NULL)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Data = fdt_getprop (Fdt, IntcNode, "#interrupt-cells", &Size);
+ if ((Data == NULL) || (Size != sizeof (UINT32))) {
+ // If error or not on one UINT32 cell.
+ ASSERT (0);
+ return EFI_ABORTED;
+ }
+
+ *IntCells = fdt32_to_cpu (*Data);
+
+ return EFI_SUCCESS;
+}
+
+/** Get the "#address-cells" and/or "#size-cells" property of the node.
+
+ According to the Device Tree specification, s2.3.5 "#address-cells and
+ #size-cells":
+ "If missing, a client program should assume a default value of 2 for
+ #address-cells, and a value of 1 for #size-cells."
+
+ @param [in] Fdt Pointer to a Flattened Device Tree.
+ @param [in] Node Offset of the node having to get the
+ "#address-cells" and "#size-cells"
+ properties from.
+ @param [out] AddressCells If success, number of address-cells.
+ If the property is not available,
+ default value is 2.
+ @param [out] SizeCells If success, number of size-cells.
+ If the property is not available,
+ default value is 1.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+EFI_STATUS
+EFIAPI
+FdtGetAddressInfo (
+ IN CONST VOID * Fdt,
+ IN INT32 Node,
+ OUT INT32 * AddressCells, OPTIONAL
+ OUT INT32 * SizeCells OPTIONAL
+ )
+{
+ if (Fdt == NULL) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (AddressCells != NULL) {
+ *AddressCells = fdt_address_cells (Fdt, Node);
+ if (*AddressCells < 0) {
+ ASSERT (0);
+ return EFI_ABORTED;
+ }
+ }
+
+ if (SizeCells != NULL) {
+ *SizeCells = fdt_size_cells (Fdt, Node);
+ if (*SizeCells < 0) {
+ ASSERT (0);
+ return EFI_ABORTED;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/** Get the "#address-cells" and/or "#size-cells" property of the parent node.
+
+ According to the Device Tree specification, s2.3.5 "#address-cells and
+ #size-cells":
+ "If missing, a client program should assume a default value of 2 for
+ #address-cells, and a value of 1 for #size-cells."
+
+ @param [in] Fdt Pointer to a Flattened Device Tree.
+ @param [in] Node Offset of the node having to get the
+ "#address-cells" and "#size-cells"
+ properties from its parent.
+ @param [out] AddressCells If success, number of address-cells.
+ If the property is not available,
+ default value is 2.
+ @param [out] SizeCells If success, number of size-cells.
+ If the property is not available,
+ default value is 1.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+EFI_STATUS
+EFIAPI
+FdtGetParentAddressInfo (
+ IN CONST VOID * Fdt,
+ IN INT32 Node,
+ OUT INT32 * AddressCells, OPTIONAL
+ OUT INT32 * SizeCells OPTIONAL
+ )
+{
+ if (Fdt == NULL) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Node = fdt_parent_offset (Fdt, Node);
+ if (Node < 0) {
+ // End of the tree, or an error occurred.
+ ASSERT (0);
+ return EFI_ABORTED;
+ }
+
+ return FdtGetAddressInfo (Fdt, Node, AddressCells, SizeCells);
+}
diff --git a/DynamicTablesPkg/Library/FdtHwInfoParserLib/FdtUtility.h b/DynamicTablesPkg/Library/FdtHwInfoParserLib/FdtUtility.h
new file mode 100644
index 000000000000..0076c5066d4c
--- /dev/null
+++ b/DynamicTablesPkg/Library/FdtHwInfoParserLib/FdtUtility.h
@@ -0,0 +1,458 @@
+/** @file
+ Flattened device tree utility.
+
+ Copyright (c) 2021, ARM Limited. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - Device tree Specification - Release v0.3
+ - linux/Documentation/devicetree/bindings/interrupt-controller/arm%2Cgic.yaml
+ - linux//Documentation/devicetree/bindings/interrupt-controller/arm%2Cgic.yaml
+**/
+
+#ifndef FDT_UTILITY_H_
+#define FDT_UTILITY_H_
+
+/** Get the offset of an address in a "reg" Device Tree property.
+
+ In a Device Tree, the "reg" property stores address/size couples.
+ They are stored on N 32-bits cells.
+ Based on the value of the #address-cells, the #size-cells and the
+ index in the "reg" property, compute the number of 32-bits cells
+ to skip.
+
+ @param [in] Index Index in the reg property.
+ @param [in] AddrCells Number of cells used to store an address.
+ @param [in] SizeCells Number of cells used to store the size of
+ an address.
+
+ @retval Number of 32-bits cells to skip to access the address.
+*/
+#define GET_DT_REG_ADDRESS_OFFSET(Index, AddrCells, SizeCells) ( \
+ (Index) * ((AddrCells) + (SizeCells)) \
+ )
+
+/** Get the offset of an address size in a "reg" Device Tree property.
+
+ In a Device Tree, the "reg" property stores address/size couples.
+ They are stored on N 32-bits cells.
+ Based on the value of the #address-cells, the #size-cells and the
+ index in the "reg" property, compute the number of 32-bits cells
+ to skip.
+
+ @param [in] Index Index in the reg property.
+ @param [in] AddrCells Number of cells used to store an address.
+ @param [in] SizeCells Number of cells used to store the size of
+ an address.
+
+ @retval Number of 32-bits cells to skip to access the address size.
+*/
+#define GET_DT_REG_SIZE_OFFSET(Index, AddrCells, SizeCells) ( \
+ GET_DT_REG_ADDRESS_OFFSET ((Index), (AddrCells), (SizeCells)) + \
+ (SizeCells) \
+ )
+
+/// Maximum string length for compatible names.
+#define COMPATIBLE_STR_LEN (32U)
+
+/// Interrupt macros
+#define PPI_OFFSET (16U)
+#define SPI_OFFSET (32U)
+#define DT_PPI_IRQ (1U)
+#define DT_SPI_IRQ (0U)
+#define DT_IRQ_IS_EDGE_TRIGGERED(x) ((((x) & (BIT0 | BIT2)) != 0))
+#define DT_IRQ_IS_ACTIVE_LOW(x) ((((x) & (BIT1 | BIT3)) != 0))
+#define IRQ_TYPE_OFFSET (0U)
+#define IRQ_NUMBER_OFFSET (1U)
+#define IRQ_FLAGS_OFFSET (2U)
+
+/** Get the interrupt Id of an interrupt described in a fdt.
+
+ Data must describe a GIC interrupt. A GIC interrupt is on at least
+ 3 UINT32 cells.
+ This function DOES NOT SUPPORT extended SPI range and extended PPI range.
+
+ @param [in] Data Pointer to the first cell of an "interrupts" property.
+
+ @retval The interrupt id.
+**/
+UINT32
+EFIAPI
+FdtGetInterruptId (
+ UINT32 CONST * Data
+ );
+
+/** Get the ACPI interrupt flags of an interrupt described in a fdt.
+
+ Data must describe a GIC interrupt. A GIC interrupt is on at least
+ 3 UINT32 cells.
+
+ @param [in] Data Pointer to the first cell of an "interrupts" property.
+
+ @retval The interrupt flags (for ACPI).
+**/
+UINT32
+EFIAPI
+FdtGetInterruptFlags (
+ UINT32 CONST * Data
+ );
+
+/** A structure describing a compatibility string.
+*/
+typedef struct CompatStr {
+ CONST CHAR8 CompatStr[COMPATIBLE_STR_LEN];
+} COMPATIBILITY_STR;
+
+/** Structure containing a list of compatible names and their count.
+*/
+typedef struct CompatibilityInfo {
+ /// Count of entries in the NAME_TABLE.
+ UINT32 Count;
+
+ /// Pointer to a table storing the names.
+ CONST COMPATIBILITY_STR * CompatTable;
+} COMPATIBILITY_INFO;
+
+/** Operate a check on a Device Tree node.
+
+ @param [in] Fdt Pointer to a Flattened Device Tree.
+ @param [in] NodeOffset Offset of the node to compare input string.
+ @param [in] Context Context to operate the check on the node.
+
+ @retval True The check is correct.
+ @retval FALSE Otherwise, or error.
+**/
+typedef
+BOOLEAN
+(EFIAPI *NODE_CHECKER_FUNC) (
+ IN CONST VOID * Fdt,
+ IN INT32 NodeOffset,
+ IN CONST VOID * Context
+ );
+
+/** Iterate through the list of strings in the Context,
+ and check whether at least one string is matching the
+ "compatible" property of the node.
+
+ @param [in] Fdt Pointer to a Flattened Device Tree.
+ @param [in] Node Offset of the node to operate the check on.
+ @param [in] CompatInfo COMPATIBILITY_INFO containing the list of compatible
+ strings to compare with the "compatible" property
+ of the node.
+
+ @retval TRUE At least one string matched, the node is compatible.
+ @retval FALSE Otherwise, or error.
+**/
+BOOLEAN
+EFIAPI
+FdtNodeIsCompatible (
+ IN CONST VOID * Fdt,
+ IN INT32 Node,
+ IN CONST VOID * CompatInfo
+ );
+
+/** Check whether a node has a property.
+
+ @param [in] Fdt Pointer to a Flattened Device Tree.
+ @param [in] Node Offset of the node to operate the check on.
+ @param [in] PropertyName Name of the property to search.
+ This is a NULL terminated string.
+
+ @retval True The node has the property.
+ @retval FALSE Otherwise, or error.
+**/
+BOOLEAN
+EFIAPI
+FdtNodeHasProperty (
+ IN CONST VOID * Fdt,
+ IN INT32 Node,
+ IN CONST VOID * PropertyName
+ );
+
+/** Get the next node in a branch having a matching name.
+
+ The Device tree is traversed in a depth-first search, starting from Node.
+ The input Node is skipped.
+
+ @param [in] Fdt Pointer to a Flattened Device Tree.
+ @param [in] FdtBranch Only search in the sub-nodes of this branch.
+ Write (-1) to search the whole tree.
+ @param [in] NodeName The node name to search.
+ This is a NULL terminated string.
+ @param [in, out] Node At entry: Node offset to start the search.
+ This first node is skipped.
+ Write (-1) to search the whole tree.
+ At exit: If success, contains the offset of
+ the next node in the branch
+ having a matching name.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND No matching node found.
+**/
+EFI_STATUS
+EFIAPI
+FdtGetNextNamedNodeInBranch (
+ IN CONST VOID * Fdt,
+ IN INT32 FdtBranch,
+ IN CONST CHAR8 * NodeName,
+ IN OUT INT32 * Node
+ );
+
+/** Get the next node in a branch with at least one compatible property.
+
+ The Device tree is traversed in a depth-first search, starting from Node.
+ The input Node is skipped.
+
+ @param [in] Fdt Pointer to a Flattened Device Tree.
+ @param [in] FdtBranch Only search in the sub-nodes of this branch.
+ Write (-1) to search the whole tree.
+ @param [in] CompatNamesInfo Table of compatible strings to compare with
+ the compatible property of the node.
+ @param [in, out] Node At entry: Node offset to start the search.
+ This first node is skipped.
+ Write (-1) to search the whole tree.
+ At exit: If success, contains the offset of
+ the next node in the branch
+ being compatible.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND No matching node found.
+**/
+EFI_STATUS
+EFIAPI
+FdtGetNextCompatNodeInBranch (
+ IN CONST VOID * Fdt,
+ IN INT32 FdtBranch,
+ IN CONST COMPATIBILITY_INFO * CompatNamesInfo,
+ IN OUT INT32 * Node
+ );
+
+/** Get the next node in a branch having the PropName property.
+
+ The Device tree is traversed in a depth-first search, starting from Node.
+ The input Node is skipped.
+
+ @param [in] Fdt Pointer to a Flattened Device Tree.
+ @param [in] FdtBranch Only search in the sub-nodes of this branch.
+ Write (-1) to search the whole tree.
+ @param [in] PropName Name of the property to search.
+ This is a NULL terminated string.
+ @param [in, out] Node At entry: Node offset to start the search.
+ This first node is skipped.
+ Write (-1) to search the whole tree.
+ At exit: If success, contains the offset of
+ the next node in the branch
+ being compatible.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND No matching node found.
+**/
+EFI_STATUS
+EFIAPI
+FdtGetNextPropNodeInBranch (
+ IN CONST VOID * Fdt,
+ IN INT32 FdtBranch,
+ IN CONST CHAR8 * PropName,
+ IN OUT INT32 * Node
+ );
+
+/** Count the number of nodes in a branch with the input name.
+
+ @param [in] Fdt Pointer to a Flattened Device Tree.
+ @param [in] FdtBranch Only search in the sub-nodes of this branch.
+ Write (-1) to search the whole tree.
+ @param [in] NodeName Node name to search.
+ This is a NULL terminated string.
+ @param [out] NodeCount If success, contains the count of nodes
+ fulfilling the condition.
+ Can be 0.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+EFI_STATUS
+EFIAPI
+FdtCountNamedNodeInBranch (
+ IN CONST VOID * Fdt,
+ IN INT32 FdtBranch,
+ IN CONST CHAR8 * NodeName,
+ OUT UINT32 * NodeCount
+ );
+
+/** Count the number of nodes in a branch with at least
+ one compatible property.
+
+ @param [in] Fdt Pointer to a Flattened Device Tree.
+ @param [in] FdtBranch Only search in the sub-nodes of this branch.
+ Write (-1) to search the whole tree.
+ @param [in] CompatibleTable Table of compatible strings to
+ compare with the compatible property
+ of the node.
+ @param [out] NodeCount If success, contains the count of nodes
+ fulfilling the condition.
+ Can be 0.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+EFI_STATUS
+EFIAPI
+FdtCountCompatNodeInBranch (
+ IN CONST VOID * Fdt,
+ IN INT32 FdtBranch,
+ IN CONST COMPATIBILITY_INFO * CompatNamesInfo,
+ OUT UINT32 * NodeCount
+ );
+
+/** Count the number of nodes in a branch having the PropName property.
+
+ @param [in] Fdt Pointer to a Flattened Device Tree.
+ @param [in] FdtBranch Only search in the sub-nodes of this branch.
+ Write (-1) to search the whole tree.
+ @param [in] PropName Name of the property to search.
+ This is a NULL terminated string.
+ @param [out] NodeCount If success, contains the count of nodes
+ fulfilling the condition.
+ Can be 0.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+EFI_STATUS
+EFIAPI
+FdtCountPropNodeInBranch (
+ IN CONST VOID * Fdt,
+ IN INT32 FdtBranch,
+ IN CONST CHAR8 * PropName,
+ OUT UINT32 * NodeCount
+ );
+
+/** Get the interrupt-controller node handling the interrupts of
+ the input node.
+
+ To do this, recursively search a node with either the "interrupt-controller"
+ or the "interrupt-parent" property in the parents of Node.
+
+ Devicetree Specification, Release v0.3,
+ 2.4.1 "Properties for Interrupt Generating Devices":
+ Because the hierarchy of the nodes in the interrupt tree
+ might not match the devicetree, the interrupt-parent
+ property is available to make the definition of an
+ interrupt parent explicit. The value is the phandle to the
+ interrupt parent. If this property is missing from a
+ device, its interrupt parent is assumed to be its devicetree
+ parent.
+
+ @param [in] Fdt Pointer to a Flattened Device Tree.
+ @param [in] Node Offset of the node to start the search.
+ @param [out] IntcNode If success, contains the offset of the
+ interrupt-controller node.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_FOUND No interrupt-controller node found.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+EFI_STATUS
+EFIAPI
+FdtGetIntcParentNode (
+ IN CONST VOID * Fdt,
+ IN INT32 Node,
+ OUT INT32 * IntcNode
+ );
+
+/** Get the "interrupt-cells" property value of the node.
+
+ The "interrupts" property requires to know the number of cells used
+ to encode an interrupt. This information is stored in the
+ interrupt-controller of the input Node.
+
+ @param [in] Fdt Pointer to a Flattened Device Tree (Fdt).
+ @param [in] IntcNode Offset of an interrupt-controller node.
+ @param [out] IntCells If success, contains the "interrupt-cells"
+ property of the IntcNode.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_UNSUPPORTED Unsupported.
+**/
+EFI_STATUS
+EFIAPI
+FdtGetInterruptCellsInfo (
+ IN CONST VOID * Fdt,
+ IN INT32 IntcNode,
+ OUT INT32 * InterruptCells
+ );
+
+/** Get the "#address-cells" and/or "#size-cells" property of the node.
+
+ According to the Device Tree specification, s2.3.5 "#address-cells and
+ #size-cells":
+ "If missing, a client program should assume a default value of 2 for
+ #address-cells, and a value of 1 for #size-cells."
+
+ @param [in] Fdt Pointer to a Flattened Device Tree.
+ @param [in] Node Offset of the node having to get the
+ "#address-cells" and "#size-cells"
+ properties from.
+ @param [out] AddressCells If success, number of address-cells.
+ If the property is not available,
+ default value is 2.
+ @param [out] SizeCells If success, number of size-cells.
+ If the property is not available,
+ default value is 1.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+EFI_STATUS
+EFIAPI
+FdtGetAddressInfo (
+ IN CONST VOID * Fdt,
+ IN INT32 Node,
+ OUT INT32 * AddressCells, OPTIONAL
+ OUT INT32 * SizeCells OPTIONAL
+ );
+
+/** Get the "#address-cells" and/or "#size-cells" property of the parent node.
+
+ According to the Device Tree specification, s2.3.5 "#address-cells and
+ #size-cells":
+ "If missing, a client program should assume a default value of 2 for
+ #address-cells, and a value of 1 for #size-cells."
+
+ @param [in] Fdt Pointer to a Flattened Device Tree.
+ @param [in] Node Offset of the node having to get the
+ "#address-cells" and "#size-cells"
+ properties from its parent.
+ @param [out] AddressCells If success, number of address-cells.
+ If the property is not available,
+ default value is 2.
+ @param [out] SizeCells If success, number of size-cells.
+ If the property is not available,
+ default value is 1.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ABORTED An error occurred.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+EFI_STATUS
+EFIAPI
+FdtGetParentAddressInfo (
+ IN CONST VOID * Fdt,
+ IN INT32 Node,
+ OUT INT32 * AddressCells, OPTIONAL
+ OUT INT32 * SizeCells OPTIONAL
+ );
+
+#endif // FDT_UTILITY_H_
--
2.17.1


[PATCH v1 02/14] DynamicTablesPkg: FdtHwInfoParser: CM Object descriptor helper

PierreGondois
 

From: Pierre Gondois <Pierre.Gondois@...>

FdtHwInfoParserLib is an instance of the HwInfoParser. The
FdtHwInfoParser parses a platform Device Tree and populates
the Platform Information repository with Configuration
Manager objects that describe the platform hardware.
These Configuration Manager objects are encapsulated in
Configuration Manager Object Descriptors.

Therefore, add helper functions to create and free the
Configuration Manager Object descriptors.

Signed-off-by: Pierre Gondois <Pierre.Gondois@...>
Signed-off-by: Sami Mujawar <sami.mujawar@...>
---
.../FdtHwInfoParserLib/CmObjectDescUtility.c | 305 ++++++++++++++++++
.../FdtHwInfoParserLib/CmObjectDescUtility.h | 131 ++++++++
2 files changed, 436 insertions(+)
create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/CmObjectDescUtility.c
create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/CmObjectDescUtility.h

diff --git a/DynamicTablesPkg/Library/FdtHwInfoParserLib/CmObjectDescUtility.c b/DynamicTablesPkg/Library/FdtHwInfoParserLib/CmObjectDescUtility.c
new file mode 100644
index 000000000000..e471217504fe
--- /dev/null
+++ b/DynamicTablesPkg/Library/FdtHwInfoParserLib/CmObjectDescUtility.c
@@ -0,0 +1,305 @@
+/** @file
+ Configuration manager Object Descriptor Utility.
+
+ Copyright (c) 2021, ARM Limited. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <FdtHwInfoParserInclude.h>
+#include <ConfigurationManagerObject.h>
+
+#include "CmObjectDescUtility.h"
+
+/** Create a CM_OBJ_DESCRIPTOR.
+
+ @param [in] ObjectId CM_OBJECT_ID of the node.
+ @param [in] Count Number of CmObj stored in the
+ data field.
+ @param [in] Data Pointer to one or more CmObj objects.
+ The content of this Data buffer is copied.
+ @param [in] Size Size of the Data buffer.
+ @param [out] NewCmObjDesc The created CM_OBJ_DESCRIPTOR.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES An allocation has failed.
+**/
+EFI_STATUS
+EFIAPI
+CreateCmObjDesc (
+ IN CM_OBJECT_ID ObjectId,
+ IN UINT32 Count,
+ IN VOID * Data,
+ IN UINT32 Size,
+ OUT CM_OBJ_DESCRIPTOR ** NewCmObjDesc
+ )
+{
+ CM_OBJ_DESCRIPTOR * CmObjDesc;
+ VOID * DataBuffer;
+
+ if ((Count == 0) ||
+ (Data == NULL) ||
+ (Size == 0) ||
+ (NewCmObjDesc == NULL)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CmObjDesc = AllocateZeroPool (sizeof (CM_OBJ_DESCRIPTOR));
+ if (CmObjDesc == NULL) {
+ ASSERT (0);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ DataBuffer = AllocateCopyPool (Size, Data);
+ if (DataBuffer == NULL) {
+ ASSERT (0);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CmObjDesc->ObjectId = ObjectId;
+ CmObjDesc->Count = Count;
+ CmObjDesc->Data = DataBuffer;
+ CmObjDesc->Size = Size;
+
+ *NewCmObjDesc = CmObjDesc;
+
+ return EFI_SUCCESS;
+}
+
+/** Free resources allocated for the CM_OBJ_DESCRIPTOR.
+
+ @param [in] CmObjDesc Pointer to the CM_OBJ_DESCRIPTOR.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+EFI_STATUS
+EFIAPI
+FreeCmObjDesc (
+ IN CM_OBJ_DESCRIPTOR * CmObjDesc
+ )
+{
+ if (CmObjDesc == NULL) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (CmObjDesc->Data != NULL) {
+ FreePool (CmObjDesc->Data);
+ }
+
+ FreePool (CmObjDesc);
+ return EFI_SUCCESS;
+}
+
+/** Add a single CmObj to the Configuration Manager.
+
+ @param [in] FdtParserHandle A handle to the parser instance.
+ @param [in] ObjectId CmObj ObjectId.
+ @param [in] Data CmObj Data.
+ @param [in] Size CmObj Size.
+ @param [out] Token If provided and success,
+ token generated for this CmObj.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+EFI_STATUS
+EFIAPI
+AddSingleCmObj (
+ IN CONST FDT_HW_INFO_PARSER_HANDLE FdtParserHandle,
+ IN CM_OBJECT_ID ObjectId,
+ IN VOID *Data,
+ IN UINT32 Size,
+ OUT CM_OBJECT_TOKEN *Token OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ CM_OBJ_DESCRIPTOR CmObjDesc;
+
+ if ((FdtParserHandle == NULL) ||
+ (FdtParserHandle->HwInfoAdd == NULL) ||
+ (Data == NULL) ||
+ (Size == 0)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CmObjDesc.ObjectId = ObjectId;
+ CmObjDesc.Count = 1;
+ CmObjDesc.Data = Data;
+ CmObjDesc.Size = Size;
+
+ // Add the CmObj.
+ // Don't ask for a token.
+ Status = FdtParserHandle->HwInfoAdd (
+ FdtParserHandle,
+ FdtParserHandle->Context,
+ &CmObjDesc,
+ Token
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ }
+ return Status;
+}
+
+/** Add multiple CmObj to the Configuration Manager.
+
+ @param [in] FdtParserHandle A handle to the parser instance.
+ @param [in] CmObjDesc CmObjDesc containing multiple CmObj
+ to add.
+ @param [in] TokenCount If provided, count of entries in the
+ TokenTable.
+ @param [out] TokenTable If provided and success,
+ token generated for these CmObj.
+ Address of an array of CM_OBJECT_TOKEN
+ with the same number of elements as the
+ CmObjDesc.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+EFI_STATUS
+EFIAPI
+AddMultipleCmObj (
+ IN CONST FDT_HW_INFO_PARSER_HANDLE FdtParserHandle,
+ IN CONST CM_OBJ_DESCRIPTOR *CmObjDesc,
+ IN UINT32 TokenCount, OPTIONAL
+ OUT CM_OBJECT_TOKEN *TokenTable OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Index;
+ UINT32 Count;
+ VOID * Data;
+ UINT32 Size;
+ CM_OBJ_DESCRIPTOR SingleCmObjDesc;
+
+ if ((FdtParserHandle == NULL) ||
+ (FdtParserHandle->HwInfoAdd == NULL) ||
+ (CmObjDesc == NULL) ||
+ (CmObjDesc->Count == 0) ||
+ (CmObjDesc->Data == NULL) ||
+ (CmObjDesc->Size == 0)){
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Count = CmObjDesc->Count;
+ Data = CmObjDesc->Data;
+ Size = CmObjDesc->Size / Count;
+
+ SingleCmObjDesc.ObjectId = CmObjDesc->ObjectId;
+ SingleCmObjDesc.Count = 1;
+ SingleCmObjDesc.Size = Size;
+
+ for (Index = 0; Index < Count; Index++) {
+ SingleCmObjDesc.Data = Data + Index * Size;
+ // Add the CmObj.
+ Status = FdtParserHandle->HwInfoAdd (
+ FdtParserHandle,
+ FdtParserHandle->Context,
+ &SingleCmObjDesc,
+ (TokenTable != NULL) ?
+ &TokenTable[Index] :
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+ } // for
+
+ return Status;
+}
+
+/** Add multiple CmObj to the Configuration Manager.
+
+ Get one token referencing a EArmObjCmRef CmObj itself referencing
+ the input CmObj. In the table below, RefToken is returned.
+
+ Token referencing an Array of tokens Array of CmObj
+ array of EArmObjCmRef referencing each from the input:
+ CmObj: CmObj from the input:
+
+ RefToken ---> CmObjToken[0] ---> CmObj[0]
+ CmObjToken[1] ---> CmObj[1]
+ CmObjToken[2] ---> CmObj[2]
+
+ @param [in] FdtParserHandle A handle to the parser instance.
+ @param [in] CmObjDesc CmObjDesc containing multiple CmObj
+ to add.
+ @param [out] Token If success, token referencing an array
+ of EArmObjCmRef CmObj, themselves
+ referencing the input CmObjs.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES An allocation has failed.
+**/
+EFI_STATUS
+EFIAPI
+AddMultipleCmObjWithCmObjRef (
+ IN CONST FDT_HW_INFO_PARSER_HANDLE FdtParserHandle,
+ IN CM_OBJ_DESCRIPTOR * CmObjDesc,
+ OUT CM_OBJECT_TOKEN * Token
+ )
+{
+ EFI_STATUS Status;
+ CM_OBJ_DESCRIPTOR CmObjRef;
+ CM_OBJECT_TOKEN *TokenTable;
+ INT32 TokenTableSize;
+
+ if ((FdtParserHandle == NULL) ||
+ (FdtParserHandle->HwInfoAdd == NULL) ||
+ (CmObjDesc == NULL) ||
+ (CmObjDesc->Count == 0) ||
+ (CmObjDesc->Data == NULL) ||
+ (CmObjDesc->Size == 0) ||
+ (Token == NULL)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Allocate a buffer to store the tokens.
+ TokenTableSize = CmObjDesc->Count * sizeof (CM_OBJECT_TOKEN);
+ TokenTable = AllocateZeroPool (TokenTableSize);
+ if (TokenTable == NULL) {
+ ASSERT (0);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ // Add the input CmObjs.
+ Status = AddMultipleCmObj (
+ FdtParserHandle,
+ CmObjDesc,
+ CmObjDesc->Count,
+ TokenTable
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ goto exit_handler;
+ }
+
+ CmObjRef.ObjectId = CREATE_CM_ARM_OBJECT_ID (EArmObjCmRef);
+ CmObjRef.Data = TokenTable;
+ CmObjRef.Count = CmObjDesc->Count;
+ CmObjRef.Size = TokenTableSize;
+
+ // Add the array of EArmObjCmRef CmObjs.
+ Status = FdtParserHandle->HwInfoAdd (
+ FdtParserHandle,
+ FdtParserHandle->Context,
+ &CmObjRef,
+ Token
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ }
+
+exit_handler:
+ FreePool (TokenTable);
+ return Status;
+}
diff --git a/DynamicTablesPkg/Library/FdtHwInfoParserLib/CmObjectDescUtility.h b/DynamicTablesPkg/Library/FdtHwInfoParserLib/CmObjectDescUtility.h
new file mode 100644
index 000000000000..34439c716fb3
--- /dev/null
+++ b/DynamicTablesPkg/Library/FdtHwInfoParserLib/CmObjectDescUtility.h
@@ -0,0 +1,131 @@
+/** @file
+ Configuration manager Object Descriptor Utility.
+
+ Copyright (c) 2021, ARM Limited. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef CM_OBJECT_DESC_UTILITY_H_
+#define CM_OBJECT_DESC_UTILITY_H_
+
+#include <ConfigurationManagerObject.h>
+
+#include "FdtHwInfoParser.h"
+
+/** Create a CM_OBJ_DESCRIPTOR.
+
+ @param [in] ObjectId CM_OBJECT_ID of the node.
+ @param [in] Count Number of CmObj stored in the
+ data field.
+ @param [in] Data Pointer to one or more CmObj objects.
+ The content of this Data buffer is copied.
+ @param [in] Size Size of the Data buffer.
+ @param [out] NewCmObjDesc The created CM_OBJ_DESCRIPTOR.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES An allocation has failed.
+**/
+EFI_STATUS
+EFIAPI
+CreateCmObjDesc (
+ IN CM_OBJECT_ID ObjectId,
+ IN UINT32 Count,
+ IN VOID * Data,
+ IN UINT32 Size,
+ OUT CM_OBJ_DESCRIPTOR ** NewCmObjDesc
+ );
+
+/** Free resources allocated for the CM_OBJ_DESCRIPTOR.
+
+ @param [in] CmObjDesc Pointer to the CM_OBJ_DESCRIPTOR.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+EFI_STATUS
+EFIAPI
+FreeCmObjDesc (
+ IN CM_OBJ_DESCRIPTOR * CmObjDesc
+ );
+
+/** Add a single CmObj to the Configuration Manager.
+
+ @param [in] FdtParserHandle A handle to the parser instance.
+ @param [in] ObjectId CmObj ObjectId.
+ @param [in] Data CmObj Data.
+ @param [in] Size CmObj Size.
+ @param [out] Token If provided and success,
+ token generated for this CmObj.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+EFI_STATUS
+EFIAPI
+AddSingleCmObj (
+ IN CONST FDT_HW_INFO_PARSER_HANDLE FdtParserHandle,
+ IN CM_OBJECT_ID ObjectId,
+ IN VOID *Data,
+ IN UINT32 Size,
+ OUT CM_OBJECT_TOKEN *Token OPTIONAL
+ );
+
+/** Add multiple CmObj to the Configuration Manager.
+
+ @param [in] FdtParserHandle A handle to the parser instance.
+ @param [in] CmObjDesc CmObjDesc containing multiple CmObj
+ to add.
+ @param [in] TokenCount If provided, count of entries in the
+ TokenTable.
+ @param [out] TokenTable If provided and success,
+ token generated for these CmObj.
+ Address of an array of CM_OBJECT_TOKEN
+ with the same number of elements as the
+ CmObjDesc.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+EFI_STATUS
+EFIAPI
+AddMultipleCmObj (
+ IN CONST FDT_HW_INFO_PARSER_HANDLE FdtParserHandle,
+ IN CONST CM_OBJ_DESCRIPTOR *CmObjDesc,
+ IN UINT32 TokenCount, OPTIONAL
+ OUT CM_OBJECT_TOKEN *TokenTable OPTIONAL
+ );
+
+/** Add multiple CmObj to the Configuration Manager.
+
+ Get one token referencing a EArmObjCmRef CmObj itself referencing
+ the input CmObj. In the table below, RefToken is returned.
+
+ Token referencing an Array of tokens Array of CmObj
+ array of EArmObjCmRef referencing each from the input:
+ CmObj: CmObj from the input:
+
+ RefToken ---> CmObjToken[0] ---> CmObj[0]
+ CmObjToken[1] ---> CmObj[1]
+ CmObjToken[2] ---> CmObj[2]
+
+ @param [in] FdtParserHandle A handle to the parser instance.
+ @param [in] CmObjDesc CmObjDesc containing multiple CmObj
+ to add.
+ @param [out] Token If success, token referencing an array
+ of EArmObjCmRef CmObj, themselves
+ referencing the input CmObjs.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES An allocation has failed.
+**/
+EFI_STATUS
+EFIAPI
+AddMultipleCmObjWithCmObjRef (
+ IN CONST FDT_HW_INFO_PARSER_HANDLE FdtParserHandle,
+ IN CM_OBJ_DESCRIPTOR * CmObjDesc,
+ OUT CM_OBJECT_TOKEN * Token
+ );
+
+#endif // CM_OBJECT_DESC_UTILITY_H_
--
2.17.1


[PATCH v1 01/14] DynamicTablesPkg: Definition for HwInfoParser interface

PierreGondois
 

From: Pierre Gondois <Pierre.Gondois@...>

Hardware information parser is an optional module defined
by the Dynamic Tables Framework. It can either parse an
XML, a Device Tree or a Json file containing the platform
hardware information to populate the platform information
repository.

The Configuration Manager can then utilise this information
to generate ACPI tables for the platform.

Therefore, define an interface for the HwInfoParser library
class.

Signed-off-by: Pierre Gondois <Pierre.Gondois@...>
Signed-off-by: Sami Mujawar <sami.mujawar@...>
---
DynamicTablesPkg/DynamicTablesPkg.dec | 3 +
.../Include/Library/HwInfoParserLib.h | 99 +++++++++++++++++++
2 files changed, 102 insertions(+)
create mode 100644 DynamicTablesPkg/Include/Library/HwInfoParserLib.h

diff --git a/DynamicTablesPkg/DynamicTablesPkg.dec b/DynamicTablesPkg/DynamicTablesPkg.dec
index 9996bdf6f520..80a61dd2dbac 100644
--- a/DynamicTablesPkg/DynamicTablesPkg.dec
+++ b/DynamicTablesPkg/DynamicTablesPkg.dec
@@ -24,6 +24,9 @@ [LibraryClasses]
## @libraryclass Defines a set of APIs for Dynamic AML generation.
AmlLib|Include/Library/AmlLib/AmlLib.h

+ ## @libraryclass Defines a set of APIs to a hardware information parser.
+ HwInfoParserLib|Include/Library/HwInfoParserLib.h
+
## @libraryclass Defines a set of methods for fixing up a SSDT Serial Port.
SsdtSerialPortFixupLib|Include/Library/SsdtSerialPortFixupLib.h

diff --git a/DynamicTablesPkg/Include/Library/HwInfoParserLib.h b/DynamicTablesPkg/Include/Library/HwInfoParserLib.h
new file mode 100644
index 000000000000..472fbefcc6b5
--- /dev/null
+++ b/DynamicTablesPkg/Include/Library/HwInfoParserLib.h
@@ -0,0 +1,99 @@
+/** @file
+ Hardware information parser library.
+
+ Copyright (c) 2021, ARM Limited. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef HW_INFO_PARSER_LIB_H_
+#define HW_INFO_PARSER_LIB_H_
+
+#include <ConfigurationManagerObject.h>
+
+/** A handle to the HwInfoParser instance.
+*/
+typedef VOID * HW_INFO_PARSER_HANDLE;
+
+/** Function pointer called by the parser to add information.
+
+ Callback function that the parser can use to add new
+ CmObj. This function must copy the CmObj data and not rely on
+ the parser preserving the CmObj memory.
+ This function is responsible of the Token allocation.
+
+ @param [in] ParserHandle A handle to the parser instance.
+ @param [in] Context A pointer to the caller's context provided in
+ HwInfoParserInit ().
+ @param [in] CmObjDesc CM_OBJ_DESCRIPTOR containing the CmObj(s) to add.
+ @param [out] Token If provided and success, contain the token
+ generated for the CmObj.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+typedef
+EFI_STATUS
+(EFIAPI * HW_INFO_ADD_OBJECT) (
+ IN HW_INFO_PARSER_HANDLE ParserHandle,
+ IN VOID * Context,
+ IN CONST CM_OBJ_DESCRIPTOR * CmObjDesc,
+ OUT CM_OBJECT_TOKEN * Token OPTIONAL
+ );
+
+/** Initialise the HwInfoParser.
+
+ The HwInfoParser shall use the information provided by the HwDataSource
+ to initialise the internal state of the parser or to index the data. This
+ internal state shall be linked to the ParserHandle using an implementation
+ defined mechanism.
+
+ @param [in] HwDataSource Pointer to the blob containing the hardware
+ information. It can be a pointer to a Device
+ Tree, an XML file, etc. or any other data
+ structure defined by the HwInfoParser.
+ @param [in] Context A pointer to the caller's context.
+ @param [in] HwInfoAdd Function pointer called by the parser when
+ adding information.
+ @param [out] ParserHandle A handle to the parser instance.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+EFI_STATUS
+EFIAPI
+HwInfoParserInit (
+ IN VOID * HwDataSource,
+ IN VOID * Context,
+ IN HW_INFO_ADD_OBJECT HwInfoAdd,
+ OUT HW_INFO_PARSER_HANDLE * ParserHandle
+ );
+
+/** Parse the data provided by the HwDataSource.
+
+ @param [in] ParserHandle A handle to the parser instance.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES An allocation has failed.
+**/
+EFI_STATUS
+EFIAPI
+HwInfoParse (
+ IN HW_INFO_PARSER_HANDLE ParserHandle
+ );
+
+/** Cleanup any internal state and resources that were allocated
+ by the the HwInfoParser.
+
+ @param [in] ParserHandle A handle to the parser instance.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+EFI_STATUS
+EFIAPI
+HwInfoParserShutdown (
+ IN HW_INFO_PARSER_HANDLE ParserHandle
+ );
+
+#endif // HW_INFO_PARSER_LIB_H_
--
2.17.1


[PATCH v1 00/14] Implement a FdtHwInfoParserLib

PierreGondois
 

From: Pierre Gondois <Pierre.Gondois@...>

The generic HwInfoParserLib provides an interface to parse hardware
information stored in certain a data type (e.g.: xml, device tree,
...) and generate objects that can be used by the DynamicTablesPkg
framework to generate another hardware description (e.g.:
SMBIOS tables, ACPI tables, ...).

This patch-set also implements a FdtHwInfoParserLib, parsing
hardware information stored in a device tree. The objects
generated by the library have been used ACPI tables.

The changes can be seen at: https://github.com/PierreARM/edk2/tree/1787_Implement_FdtHwInfoParser
The results of the CI can be seen at: https://github.com/tianocore/edk2/pull/1749

This patch-set is dependent over the following patch-sets:
[PATCH v1 00/10] Various DynamicTablesPkg modifications
https://edk2.groups.io/g/devel/message/76929
and:
[PATCH v1 00/13] Create a SSDT CPU topology generator
https://edk2.groups.io/g/devel/message/76941
and:
[PATCH v1 0/7] Create a SSDT PCIe generator
https://edk2.groups.io/g/devel/message/76958

Pierre Gondois (14):
DynamicTablesPkg: Definition for HwInfoParser interface
DynamicTablesPkg: FdtHwInfoParser: CM Object descriptor helper
DynamicTablesPkg: FdtHwInfoParser: Add FDT utility functions
DynamicTablesPkg: FdtHwInfoParser: Add Boot Arch parser
DynamicTablesPkg: FdtHwInfoParser: Generic Timer Parser
DynamicTablesPkg: FdtHwInfoParser: Add Serial port parser
DynamicTablesPkg: FdtHwInfoParser: Add GICC parser
DynamicTablesPkg: FdtHwInfoParser: Add GICD parser
DynamicTablesPkg: FdtHwInfoParser: Add MSI Frame parser
DynamicTablesPkg: FdtHwInfoParser: Add ITS parser
DynamicTablesPkg: FdtHwInfoParser: Add GICR parser
DynamicTablesPkg: FdtHwInfoParser: Add GIC dispatcher
DynamicTablesPkg: FdtHwInfoParser: Add PCI config parser
DynamicTablesPkg: Add FdtHwInfoParser library

DynamicTablesPkg/DynamicTablesPkg.dec | 3 +
DynamicTablesPkg/DynamicTablesPkg.dsc | 3 +-
.../Include/Library/HwInfoParserLib.h | 99 ++
.../BootArch/ArmBootArchParser.c | 161 ++++
.../BootArch/ArmBootArchParser.h | 45 +
.../FdtHwInfoParserLib/CmObjectDescUtility.c | 305 ++++++
.../FdtHwInfoParserLib/CmObjectDescUtility.h | 131 +++
.../FdtHwInfoParserLib/FdtHwInfoParser.c | 193 ++++
.../FdtHwInfoParserLib/FdtHwInfoParser.h | 63 ++
.../FdtHwInfoParserInclude.h | 17 +
.../FdtHwInfoParserLib/FdtHwInfoParserLib.inf | 56 ++
.../Library/FdtHwInfoParserLib/FdtUtility.c | 909 ++++++++++++++++++
.../Library/FdtHwInfoParserLib/FdtUtility.h | 458 +++++++++
.../GenericTimer/ArmGenericTimerParser.c | 254 +++++
.../GenericTimer/ArmGenericTimerParser.h | 66 ++
.../FdtHwInfoParserLib/Gic/ArmGicCParser.c | 762 +++++++++++++++
.../FdtHwInfoParserLib/Gic/ArmGicCParser.h | 67 ++
.../FdtHwInfoParserLib/Gic/ArmGicDParser.c | 171 ++++
.../FdtHwInfoParserLib/Gic/ArmGicDParser.h | 50 +
.../FdtHwInfoParserLib/Gic/ArmGicDispatcher.c | 212 ++++
.../FdtHwInfoParserLib/Gic/ArmGicDispatcher.h | 72 ++
.../FdtHwInfoParserLib/Gic/ArmGicItsParser.c | 215 +++++
.../FdtHwInfoParserLib/Gic/ArmGicItsParser.h | 48 +
.../Gic/ArmGicMsiFrameParser.c | 214 +++++
.../Gic/ArmGicMsiFrameParser.h | 50 +
.../FdtHwInfoParserLib/Gic/ArmGicRParser.c | 237 +++++
.../FdtHwInfoParserLib/Gic/ArmGicRParser.h | 47 +
.../Pci/ArmPciConfigSpaceParser.c | 799 +++++++++++++++
.../Pci/ArmPciConfigSpaceParser.h | 142 +++
.../Serial/ArmSerialPortParser.c | 621 ++++++++++++
.../Serial/ArmSerialPortParser.h | 47 +
31 files changed, 6516 insertions(+), 1 deletion(-)
create mode 100644 DynamicTablesPkg/Include/Library/HwInfoParserLib.h
create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/BootArch/ArmBootArchParser.c
create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/BootArch/ArmBootArchParser.h
create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/CmObjectDescUtility.c
create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/CmObjectDescUtility.h
create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/FdtHwInfoParser.c
create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/FdtHwInfoParser.h
create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/FdtHwInfoParserInclude.h
create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/FdtHwInfoParserLib.inf
create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/FdtUtility.c
create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/FdtUtility.h
create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/GenericTimer/ArmGenericTimerParser.c
create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/GenericTimer/ArmGenericTimerParser.h
create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicCParser.c
create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicCParser.h
create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicDParser.c
create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicDParser.h
create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicDispatcher.c
create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicDispatcher.h
create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicItsParser.c
create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicItsParser.h
create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicMsiFrameParser.c
create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicMsiFrameParser.h
create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicRParser.c
create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/Gic/ArmGicRParser.h
create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/Pci/ArmPciConfigSpaceParser.c
create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/Pci/ArmPciConfigSpaceParser.h
create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/Serial/ArmSerialPortParser.c
create mode 100644 DynamicTablesPkg/Library/FdtHwInfoParserLib/Serial/ArmSerialPortParser.h

--
2.17.1


Re: [EXTERNAL] Re: [edk2-devel] [PATCH] NetworkPkg: Addressed static code analyzer issues

Sivaraman Nainar
 

Hi Lazlo:

case Dhcp4SendRequest:
if (Packet->Length > PXEBC_DHCP4_PACKET_MAX_SIZE) {
//
// If the to be sent packet exceeds the maximum length, abort the DHCP process.
//
Status = EFI_ABORTED;
break;
}
The same packet Length check already taken care on case Dhcp4SendDiscover: also.

So I prefer to remove the above set of lines.

Wil update the subject when sending V2 changes.

-Siva

-----Original Message-----
From: Laszlo Ersek <lersek@...>
Sent: Wednesday, June 23, 2021 3:45 PM
To: devel@edk2.groups.io; emergingsiva@...
Cc: Sivaraman Nainar <sivaramann@...>; Maciej Rabeda <maciej.rabeda@...>; Jiaxin Wu <jiaxin.wu@...>; Siyuan Fu <siyuan.fu@...>
Subject: [EXTERNAL] Re: [edk2-devel] [PATCH] NetworkPkg: Addressed static code analyzer issues


**CAUTION: The e-mail below is from an external source. Please exercise caution before opening attachments, clicking links, or following guidance.**

adding NetworkPkg maintainers, comments below

On 06/18/21 05:30, INDIA\sivaramann wrote:
Issue on the PxeBcDhcp4CallBack() functions of UEFIPXEBC Driver.
In this function allowed events are Dhcp4RcvdOffer, Dhcp4SelectOffer,
Dhcp4SendDiscover, Dhcp4RcvdAck. If any other event comes as input it
will exit in beginning itself.
Yes.


Later below switch case handling the default case which is not reachable.
I assume this code is a not reachable code and can be removed
(1) The edk2 coding style recommends adding "default" cases to switch statements, as far as I recall. I'd keep the default, but add

ASSERT (FALSE);

there.

(2) There is a more confusing style issue with the same switch statement. Namely, it has a case label for "Dhcp4SendRequest". Control will never jump to that label, due to the "if" at the top of the function that you highlight.

Importantly, the *code* starting at the "Dhcp4SendRequest" case label must not be removed, as the "Dhcp4SendDiscover" logic *falls through* to it. However, the "Dhcp4SendRequest" case label itself should be removed, and the comment just above it should be updated.

This dead label seems to originate from historical commit a3bcde70e6dc ("Add NetworkPkg (P.UDK2010.UP3.Network.P1)", 2010-11-01).

(3) The subject line is nearly useless, please name at least "NetworkPkg/UefiPxeBcDxe".

Thanks
Laszlo



Signed-off-by: Sivaraman <sivaramann@...>
---
NetworkPkg/UefiPxeBcDxe/PxeBcDhcp4.c | 2 --
1 file changed, 2 deletions(-)

diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp4.c
b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp4.c
index fb63cf61a9..c0d8211ea0 100644
--- a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp4.c
+++ b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp4.c
@@ -1331,8 +1331,6 @@ PxeBcDhcp4CallBack (
}
break;

- default:
- break;
}

return Status;
-The information contained in this message may be confidential and proprietary to American Megatrends (AMI). This communication is intended to be read only by the individual or entity to whom it is addressed or by their designee. If the reader of this message is not the intended recipient, you are on notice that any distribution of this message, in any form, is strictly prohibited. Please promptly notify the sender by reply e-mail or by telephone at 770-246-8600, and then delete or destroy all copies of the transmission.


[PATCH v1 7/7] DynamicTablesPkg: SSDT Pci express generator

PierreGondois
 

From: Pierre Gondois <Pierre.Gondois@...>

This generator allows to generate a SSDT table describing
a Pci express Bus. It uses the following CmObj:
- EArmObjCmRef
- EArmObjPciConfigSpaceInfo
- EArmObjPciAddressMapInfo
- EArmObjPciInterruptMapInfo

Signed-off-by: Pierre Gondois <Pierre.Gondois@...>
---
DynamicTablesPkg/DynamicTables.dsc.inc | 2 +
DynamicTablesPkg/Include/AcpiTableGenerator.h | 5 +
.../AcpiSsdtPcieLibArm/SsdtPcieGenerator.c | 1417 +++++++++++++++++
.../AcpiSsdtPcieLibArm/SsdtPcieGenerator.h | 134 ++
.../Arm/AcpiSsdtPcieLibArm/SsdtPcieLibArm.inf | 32 +
.../SsdtPcieOscTemplate.asl | 80 +
6 files changed, 1670 insertions(+)
create mode 100644 DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieGenerator.c
create mode 100644 DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieGenerator.h
create mode 100644 DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieLibArm.inf
create mode 100644 DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieOscTemplate.asl

diff --git a/DynamicTablesPkg/DynamicTables.dsc.inc b/DynamicTablesPkg/DynamicTables.dsc.inc
index 292215c39456..60bcf4b199e8 100644
--- a/DynamicTablesPkg/DynamicTables.dsc.inc
+++ b/DynamicTablesPkg/DynamicTables.dsc.inc
@@ -39,6 +39,7 @@ [Components.common]

# AML Codegen
DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCpuTopologyLibArm/SsdtCpuTopologyLibArm.inf
+ DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieLibArm.inf

#
# Dynamic Table Factory Dxe
@@ -62,6 +63,7 @@ [Components.common]

# AML Codegen
NULL|DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCpuTopologyLibArm/SsdtCpuTopologyLibArm.inf
+ NULL|DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieLibArm.inf
}

#
diff --git a/DynamicTablesPkg/Include/AcpiTableGenerator.h b/DynamicTablesPkg/Include/AcpiTableGenerator.h
index 45c808ba740d..58ec941f2a35 100644
--- a/DynamicTablesPkg/Include/AcpiTableGenerator.h
+++ b/DynamicTablesPkg/Include/AcpiTableGenerator.h
@@ -67,6 +67,10 @@ The Dynamic Tables Framework implements the following ACPI table generators:
The SSDT Cpu-Topology generator collates the cpu and LPI
information from the Configuration Manager and generates a
SSDT table describing the CPU hierarchy.
+ - SSDT Pci-Express:
+ The SSDT Pci Express generator collates the Pci Express
+ information from the Configuration Manager and generates a
+ SSDT table describing a Pci Express bus.
*/

/** The ACPI_TABLE_GENERATOR_ID type describes ACPI table generator ID.
@@ -93,6 +97,7 @@ typedef enum StdAcpiTableId {
EStdAcpiTableIdSsdtSerialPort, ///< SSDT Serial-Port Generator
EStdAcpiTableIdSsdtCmn600, ///< SSDT Cmn-600 Generator
EStdAcpiTableIdSsdtCpuTopology, ///< SSDT Cpu Topology
+ EStdAcpiTableIdSsdtPciExpress, ///< SSDT Pci Express Generator
EStdAcpiTableIdMax
} ESTD_ACPI_TABLE_ID;

diff --git a/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieGenerator.c b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieGenerator.c
new file mode 100644
index 000000000000..478bc60ef6f3
--- /dev/null
+++ b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieGenerator.c
@@ -0,0 +1,1417 @@
+/** @file
+ SSDT Pcie Table Generator.
+
+ Copyright (c) 2021, Arm Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - PCI Firmware Specification - Revision 3.0
+ - ACPI 6.4 specification:
+ - s6.2.13 "_PRT (PCI Routing Table)"
+ - s6.1.1 "_ADR (Address)"
+ - linux kernel code
+**/
+
+#include <Library/AcpiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Protocol/AcpiTable.h>
+
+// Module specific include files.
+#include <AcpiTableGenerator.h>
+#include <ConfigurationManagerObject.h>
+#include <ConfigurationManagerHelper.h>
+#include <Library/AcpiHelperLib.h>
+#include <Library/AmlLib/AmlLib.h>
+#include <Protocol/ConfigurationManagerProtocol.h>
+
+#include "SsdtPcieGenerator.h"
+
+/** ARM standard SSDT Pcie Table Generator.
+
+Requirements:
+ The following Configuration Manager Object(s) are required by
+ this Generator:
+ - EArmObjCmRef
+ - EArmObjPciConfigSpaceInfo
+ - EArmObjPciAddressMapInfo
+ - EArmObjPciInterruptMapInfo
+*/
+
+/** This macro expands to a function that retrieves the cross-CM-object-
+ reference information from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+ EObjNameSpaceArm,
+ EArmObjCmRef,
+ CM_ARM_OBJ_REF
+ );
+
+/** This macro expands to a function that retrieves the Pci
+ Configuration Space Information from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+ EObjNameSpaceArm,
+ EArmObjPciConfigSpaceInfo,
+ CM_ARM_PCI_CONFIG_SPACE_INFO
+ );
+
+/** This macro expands to a function that retrieves the Pci
+ Address Mapping Information from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+ EObjNameSpaceArm,
+ EArmObjPciAddressMapInfo,
+ CM_ARM_PCI_ADDRESS_MAP_INFO
+ );
+
+/** This macro expands to a function that retrieves the Pci
+ Interrupt Mapping Information from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+ EObjNameSpaceArm,
+ EArmObjPciInterruptMapInfo,
+ CM_ARM_PCI_INTERRUPT_MAP_INFO
+ );
+
+/** Initialize the MappingTable.
+
+ @param [in] MappingTable The mapping table structure.
+ @param [in] Count Number of entries to allocate in the
+ MappingTable.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+MappingTableInitialize (
+ IN MAPPING_TABLE * MappingTable,
+ IN UINT32 Count
+ )
+{
+ UINT32 * Table;
+
+ if ((MappingTable == NULL) ||
+ (Count == 0)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Table = AllocateZeroPool (sizeof (*Table) * Count);
+ if (Table == NULL) {
+ ASSERT (0);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ MappingTable->Table = Table;
+ MappingTable->LastIndex = 0;
+ MappingTable->MaxIndex = Count;
+
+ return EFI_SUCCESS;
+}
+
+/** Free the MappingTable.
+
+ @param [in, out] MappingTable The mapping table structure.
+**/
+STATIC
+VOID
+EFIAPI
+MappingTableFree (
+ IN OUT MAPPING_TABLE * MappingTable
+ )
+{
+ ASSERT (MappingTable != NULL);
+ ASSERT (MappingTable->Table != NULL);
+
+ if (MappingTable->Table != NULL) {
+ FreePool (MappingTable->Table);
+ }
+}
+
+/** Add a new entry to the MappingTable and return its index.
+
+ If an entry with [Integer] is already available in the table,
+ return its index without adding a new entry.
+
+ @param [in] MappingTable The mapping table structure.
+ @param [in] Integer New Integer entry to add.
+
+ @retval The index of the Integer entry in the MappingTable.
+**/
+STATIC
+UINT32
+EFIAPI
+MappingTableAdd (
+ IN MAPPING_TABLE * MappingTable,
+ IN UINT32 Integer
+ )
+{
+ UINT32 * Table;
+ UINT32 Index;
+ UINT32 LastIndex;
+
+ ASSERT (MappingTable != NULL);
+ ASSERT (MappingTable->Table != NULL);
+
+ Table = MappingTable->Table;
+ LastIndex = MappingTable->LastIndex;
+
+ // Search if there is already an entry with this Integer.
+ for (Index = 0; Index < LastIndex; Index++) {
+ if (Table[Index] == Integer) {
+ return Index;
+ }
+ }
+
+ ASSERT (LastIndex < MAX_PCI_LEGACY_INTERRUPT);
+ ASSERT (LastIndex < MappingTable->MaxIndex);
+
+ // If no, create a new entry.
+ Table[LastIndex] = Integer;
+
+ return MappingTable->LastIndex++;
+}
+
+/** Generate required Pci device information.
+
+ ASL code:
+ Name (_UID, [Uid]) // Uid of the Pci device
+ Name (_HID, EISAID ("PNP0A08")) // PCI Express Root Bridge
+ Name (_CID, EISAID ("PNP0A03")) // Compatible PCI Root Bridge
+ Name (_SEG, [Pci segment group]) // PCI Segment Group number
+ Name (_BBN, [Bus number]) // PCI Base Bus Number
+ Name (_CCA, 1) // Initially mark the PCI coherent
+
+ @param [in] PciInfo Pci device information.
+ @param [in] Uid Unique Id of the Pci device.
+ @param [in, out] PciNode Pci node to amend.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GeneratePciDeviceInfo (
+ IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO * PciInfo,
+ IN UINT32 Uid,
+ IN OUT AML_OBJECT_NODE_HANDLE PciNode
+ )
+{
+ EFI_STATUS Status;
+ UINT32 EisaId;
+
+ ASSERT (PciInfo != NULL);
+ ASSERT (PciNode != NULL);
+
+ // ASL: Name (_UID, [Uid])
+ Status = AmlCodeGenNameInteger ("_UID", Uid, PciNode, NULL);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // ASL: Name (_HID, EISAID ("PNP0A08"))
+ Status = AmlGetEisaIdFromString ("PNP0A08", &EisaId);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+ Status = AmlCodeGenNameInteger ("_HID", EisaId, PciNode, NULL);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // ASL: Name (_CID, EISAID ("PNP0A03"))
+ Status = AmlGetEisaIdFromString ("PNP0A03", &EisaId);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+ Status = AmlCodeGenNameInteger ("_CID", EisaId, PciNode, NULL);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // ASL: Name (_SEG, [Pci segment group])
+ Status = AmlCodeGenNameInteger (
+ "_SEG",
+ PciInfo->PciSegmentGroupNumber,
+ PciNode,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // ASL: Name (_BBN, [Bus number])
+ Status = AmlCodeGenNameInteger (
+ "_BBN",
+ PciInfo->StartBusNumber,
+ PciNode,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // ASL: Name (_CCA, 1)
+ // Must be aligned with the IORT CCA property in
+ // "Table 14 Memory access properties"
+ Status = AmlCodeGenNameInteger ("_CCA", 1, PciNode, NULL);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ }
+ return Status;
+}
+
+/** Generate a Link device.
+
+ The Link device is added at the beginning of the ASL Pci device definition.
+
+ Each Link device represents a Pci legacy interrupt (INTA-...-INTD).
+
+ ASL code:
+ Device ([Link Name]) {
+ Name (_UID, [Uid]])
+ Name (_HID, EISAID ("PNP0C0F"))
+ Name (_PRS, ResourceTemplate () {
+ Interrupt (ResourceProducer, Level, ActiveHigh, Exclusive) { [Irq]] }
+ })
+ Method (_CRS, 0) { Return (_PRS) }
+ Method (_SRS, 1) { }
+ Method (_DIS) { }
+ }
+
+ The list of objects to define is available at:
+ PCI Firmware Specification - Revision 3.3,
+ s3.5. "Device State at Firmware/Operating System Handoff"
+
+ @param [in] Irq Interrupt controller interrupt.
+ @param [in] IrqFlags Interrupt flags.
+ @param [in] LinkIndex Legacy Pci interrupt index.
+ Must be between 0-INTA and 3-INTD.
+ @param [in, out] PciNode Pci node to amend.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GenerateLinkDevice (
+ IN UINT32 Irq,
+ IN UINT32 IrqFlags,
+ IN UINT32 LinkIndex,
+ IN OUT AML_OBJECT_NODE_HANDLE PciNode
+ )
+{
+ EFI_STATUS Status;
+ CHAR8 AslName[AML_NAME_SEG_SIZE + 1];
+ AML_OBJECT_NODE_HANDLE LinkNode;
+ AML_OBJECT_NODE_HANDLE CrsNode;
+ UINT32 EisaId;
+
+ ASSERT (LinkIndex < 4);
+ ASSERT (PciNode != NULL);
+
+ CopyMem (AslName, "LNKx", AML_NAME_SEG_SIZE + 1);
+ AslName[AML_NAME_SEG_SIZE - 1] = 'A' + LinkIndex;
+
+ // ASL: Device (LNKx) {}
+ Status = AmlCodeGenDevice (AslName, NULL, &LinkNode);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // The LNKx devices must be defined before being referenced.
+ // Thus add it to the head of the Pci list of variable arguments.
+ Status = AmlAttachNode (PciNode, LinkNode);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ // Failed to add.
+ AmlDeleteTree ((AML_NODE_HANDLE)LinkNode);
+ return Status;
+ }
+
+ // ASL: Name (_UID, [Uid])
+ Status = AmlCodeGenNameInteger ("_UID", LinkIndex, LinkNode, NULL);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // ASL: Name (_HID, EISAID ("PNP0C0F"))
+ Status = AmlGetEisaIdFromString ("PNP0C0F", &EisaId);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+ Status = AmlCodeGenNameInteger ("_HID", EisaId, LinkNode, NULL);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // ASL:
+ // Name (_PRS, ResourceTemplate () {
+ // Interrupt (ResourceProducer, Level, ActiveHigh, Exclusive) { [Irq] }
+ // })
+ Status = AmlCodeGenNameResourceTemplate ("_PRS", LinkNode, &CrsNode);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+ Status = AmlCodeGenRdInterrupt (
+ FALSE,
+ (IrqFlags & BIT0) != 0,
+ (IrqFlags & BIT1) != 0,
+ FALSE,
+ &Irq,
+ 1,
+ CrsNode,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // ASL:
+ // Method (_CRS, 0) {
+ // Return (_PRS)
+ // }
+ Status = AmlCodeGenMethodRetNameString (
+ "_CRS",
+ "_PRS",
+ 0,
+ FALSE,
+ 0,
+ LinkNode,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // ASL: Method (_SRS, 1) {}
+ // Not possible to set interrupts.
+ Status = AmlCodeGenMethodRetNameString (
+ "_SRS",
+ NULL,
+ 1,
+ FALSE,
+ 0,
+ LinkNode,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // ASL:Method (_DIS, 1) {}
+ // Not possible to disable interrupts.
+ Status = AmlCodeGenMethodRetNameString (
+ "_DIS",
+ NULL,
+ 0,
+ FALSE,
+ 0,
+ LinkNode,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // _STA:
+ // ACPI 6.4, s6.3.7 "_STA (Device Status)":
+ // If a device object describes a device that is not on an enumerable bus
+ // and the device object does not have an _STA object, then OSPM assumes
+ // that the device is present, enabled, shown in the UI, and functioning.
+
+ // _MAT:
+ // Not supported. Mainly used for processors.
+
+ return Status;
+}
+
+/** Generate Pci slots devices.
+
+ PCI Firmware Specification - Revision 3.3,
+ s4.8 "Generic ACPI PCI Slot Description" requests to describe the PCI slot
+ used. It should be possible to enumerate them, but this is additional
+ information.
+
+ @param [in] MappingTable The mapping table structure.
+ @param [in, out] PciNode Pci node to amend.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GeneratePciSlots (
+ IN CONST MAPPING_TABLE * MappingTable,
+ IN OUT AML_OBJECT_NODE_HANDLE PciNode
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Index;
+ UINT32 LastIndex;
+ UINT32 DeviceId;
+ CHAR8 AslName[AML_NAME_SEG_SIZE + 1];
+ AML_OBJECT_NODE_HANDLE DeviceNode;
+
+ ASSERT (MappingTable != NULL);
+ ASSERT (PciNode != NULL);
+
+ // Generic device name is "Dxx".
+ CopyMem (AslName, "Dxx_", AML_NAME_SEG_SIZE + 1);
+
+ LastIndex = MappingTable->LastIndex;
+
+ // There are at most 32 devices on a Pci bus.
+ ASSERT (LastIndex < 32);
+
+ for (Index = 0; Index < LastIndex; Index++) {
+ DeviceId = MappingTable->Table[Index];
+ AslName[AML_NAME_SEG_SIZE - 3] = AsciiFromHex (DeviceId & 0xF);
+ AslName[AML_NAME_SEG_SIZE - 2] = AsciiFromHex ((DeviceId >> 4) & 0xF);
+
+ // ASL:
+ // Device (Dxx) {
+ // Name (_ADR, [address value])
+ // }
+ Status = AmlCodeGenDevice (AslName, PciNode, &DeviceNode);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ /* ACPI 6.4 specification, Table 6.2: "ADR Object Address Encodings"
+ High word-Device #, Low word-Function #. (for example, device 3,
+ function 2 is 0x00030002). To refer to all the functions on a device #,
+ use a function number of FFFF).
+ */
+ Status = AmlCodeGenNameInteger (
+ "_ADR",
+ (DeviceId << 16) | 0xFFFF,
+ DeviceNode,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // _SUN object is not generated as we don't know which slot will be used.
+ }
+
+ return Status;
+}
+
+/** Generate a _PRT object (Pci Routing Table) for the Pci device.
+
+ Cf. ACPI 6.4 specification, s6.2.13 "_PRT (PCI Routing Table)"
+
+ @param [in] Generator The SSDT Pci generator.
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager
+ Protocol interface.
+ @param [in] PciInfo Pci device information.
+ @param [in, out] PciNode Pci node to amend.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GeneratePrt (
+ IN ACPI_PCI_GENERATOR * Generator,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO * PciInfo,
+ IN OUT AML_OBJECT_NODE_HANDLE PciNode
+ )
+{
+ EFI_STATUS Status;
+ INT32 Index;
+ UINT32 IrqTableIndex;
+ AML_OBJECT_NODE_HANDLE PrtNode;
+ CHAR8 AslName[AML_NAME_SEG_SIZE + 1];
+ CM_ARM_OBJ_REF * RefInfo;
+ UINT32 RefCount;
+ CM_ARM_PCI_INTERRUPT_MAP_INFO * IrqMapInfo;
+ UINT32 IrqFlags;
+ UINT32 PrevIrqFlags;
+
+ ASSERT (Generator != NULL);
+ ASSERT (CfgMgrProtocol != NULL);
+ ASSERT (PciInfo != NULL);
+ ASSERT (PciNode != NULL);
+
+ // Get the array of CM_ARM_OBJ_REF referencing the
+ // CM_ARM_PCI_INTERRUPT_MAP_INFO objects.
+ Status = GetEArmObjCmRef (
+ CfgMgrProtocol,
+ PciInfo->InterruptMapToken,
+ &RefInfo,
+ &RefCount
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Initialized IrqTable.
+ Status = MappingTableInitialize (&Generator->IrqTable, RefCount);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Initialized DeviceTable.
+ Status = MappingTableInitialize (&Generator->DeviceTable, RefCount);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ goto exit_handler;
+ }
+
+ // ASL: Name (_PRT, Package () {})
+ Status = AmlCodeGenNamePackage ("_PRT", PciNode, &PrtNode);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ goto exit_handler;
+ }
+
+ CopyMem (AslName, "LNKx", AML_NAME_SEG_SIZE + 1);
+
+ for (Index = 0; Index < RefCount; Index++) {
+ // Get CM_ARM_PCI_INTERRUPT_MAP_INFO structures one by one.
+ Status = GetEArmObjPciInterruptMapInfo (
+ CfgMgrProtocol,
+ RefInfo[Index].ReferenceToken,
+ &IrqMapInfo,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ goto exit_handler;
+ }
+
+ // Add the interrupt in the IrqTable and get the link name.
+ IrqTableIndex = MappingTableAdd (
+ &Generator->IrqTable,
+ IrqMapInfo->IntcInterrupt.Interrupt
+ );
+ AslName[AML_NAME_SEG_SIZE - 1] = 'A' + IrqTableIndex;
+
+ // Check that the interrupts flags are identical for all interrupts.
+ PrevIrqFlags = IrqFlags;
+ IrqFlags = IrqMapInfo->IntcInterrupt.Flags;
+ if ((Index > 0) && (PrevIrqFlags != IrqFlags)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Add the device to the DeviceTable.
+ MappingTableAdd (&Generator->DeviceTable, IrqMapInfo->PciDevice);
+
+ /* Add a _PRT entry.
+ ASL
+ Name (_PRT, Package () {
+ [OldPrtEntries],
+ [NewPrtEntry]
+ })
+
+ Address is set as:
+ ACPI 6.4 specification, Table 6.2: "ADR Object Address Encodings"
+ High word-Device #, Low word-Function #. (for example, device 3,
+ function 2 is 0x00030002). To refer to all the functions on a device #,
+ use a function number of FFFF).
+ */
+ Status = AmlAddPrtEntry (
+ (IrqMapInfo->PciDevice << 16) | 0xFFFF,
+ IrqMapInfo->PciInterrupt,
+ AslName,
+ 0,
+ PrtNode
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ goto exit_handler;
+ }
+ } // for
+
+ // Generate the LNKx devices now that we know all the interrupts used.
+ // To look nicer, do it in reverse order since LNKx are added to the head.
+ for (Index = Generator->IrqTable.LastIndex - 1; Index >= 0; Index--) {
+ Status = GenerateLinkDevice (
+ Generator->IrqTable.Table[Index],
+ IrqFlags,
+ Index,
+ PciNode
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ goto exit_handler;
+ }
+ } // for
+
+ // Generate the Pci slots once all the device have been added.
+ Status = GeneratePciSlots (&Generator->DeviceTable, PciNode);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ goto exit_handler;
+ }
+
+exit_handler:
+ MappingTableFree (&Generator->IrqTable);
+ MappingTableFree (&Generator->DeviceTable);
+
+ return Status;
+}
+
+/** Generate a _CRS method for the Pci device.
+
+ @param [in] Generator The SSDT Pci generator.
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager
+ Protocol interface.
+ @param [in] PciInfo Pci device information.
+ @param [in, out] PciNode Pci node to amend.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GeneratePciCrs (
+ IN ACPI_PCI_GENERATOR * Generator,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO * PciInfo,
+ IN OUT AML_OBJECT_NODE_HANDLE PciNode
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN Translation;
+ UINT32 Index;
+ CM_ARM_OBJ_REF * RefInfo;
+ UINT32 RefCount;
+ CM_ARM_PCI_ADDRESS_MAP_INFO * AddrMapInfo;
+ AML_OBJECT_NODE_HANDLE CrsNode;
+
+ ASSERT (Generator != NULL);
+ ASSERT (CfgMgrProtocol != NULL);
+ ASSERT (PciInfo != NULL);
+ ASSERT (PciNode != NULL);
+
+ // ASL: Name (_CRS, ResourceTemplate () {})
+ Status = AmlCodeGenNameResourceTemplate ("_CRS", PciNode, &CrsNode);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // ASL:
+ // WordBusNumber ( // Bus numbers assigned to this root
+ // ResourceProducer, MinFixed, MaxFixed, PosDecode,
+ // 0, // AddressGranularity
+ // [Start], // AddressMinimum - Minimum Bus Number
+ // [End], // AddressMaximum - Maximum Bus Number
+ // 0, // AddressTranslation - Set to 0
+ // [End] - [Start] + 1 // RangeLength - Number of Busses
+ // )
+ Status = AmlCodeGenRdWordBusNumber (
+ FALSE, TRUE, TRUE, TRUE,
+ 0,
+ PciInfo->StartBusNumber,
+ PciInfo->EndBusNumber,
+ 0,
+ PciInfo->EndBusNumber - PciInfo->StartBusNumber + 1,
+ 0,
+ NULL,
+ CrsNode,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Get the array of CM_ARM_OBJ_REF referencing the
+ // CM_ARM_PCI_ADDRESS_MAP_INFO objects.
+ Status = GetEArmObjCmRef (
+ CfgMgrProtocol,
+ PciInfo->AddressMapToken,
+ &RefInfo,
+ &RefCount
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ for (Index = 0; Index < RefCount; Index++) {
+ // Get CM_ARM_PCI_ADDRESS_MAP_INFO structures one by one.
+ Status = GetEArmObjPciAddressMapInfo (
+ CfgMgrProtocol,
+ RefInfo[Index].ReferenceToken,
+ &AddrMapInfo,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ Translation = (AddrMapInfo->CpuAddress != AddrMapInfo->PciAddress);
+
+ switch (AddrMapInfo->SpaceCode) {
+ case PCI_SS_IO:
+ Status = AmlCodeGenRdDWordIo (
+ FALSE, TRUE, TRUE, TRUE, 3,
+ 0,
+ AddrMapInfo->PciAddress,
+ AddrMapInfo->PciAddress + AddrMapInfo->AddressSize - 1,
+ Translation ? AddrMapInfo->CpuAddress : 0,
+ AddrMapInfo->AddressSize,
+ 0, NULL,
+ TRUE,
+ FALSE,
+ CrsNode,
+ NULL
+ );
+ break;
+
+ case PCI_SS_M32:
+ Status = AmlCodeGenRdDWordMemory (
+ FALSE, TRUE, TRUE, TRUE, TRUE, TRUE,
+ 0,
+ AddrMapInfo->PciAddress,
+ AddrMapInfo->PciAddress + AddrMapInfo->AddressSize - 1,
+ Translation ? AddrMapInfo->CpuAddress : 0,
+ AddrMapInfo->AddressSize,
+ 0, NULL,
+ 0,
+ TRUE,
+ CrsNode,
+ NULL
+ );
+ break;
+
+ case PCI_SS_M64:
+ Status = AmlCodeGenRdQWordMemory (
+ FALSE, TRUE, TRUE, TRUE, TRUE, TRUE,
+ 0,
+ AddrMapInfo->PciAddress,
+ AddrMapInfo->PciAddress + AddrMapInfo->AddressSize - 1,
+ Translation ? AddrMapInfo->CpuAddress : 0,
+ AddrMapInfo->AddressSize,
+ 0, NULL,
+ 0,
+ TRUE,
+ CrsNode,
+ NULL
+ );
+ break;
+
+ default:
+ Status = EFI_INVALID_PARAMETER;
+ } // switch
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+ } // for
+ return Status;
+}
+
+/** Add an _OSC template method to the PciNode.
+
+ The _OSC method is provided as an AML blob. The blob is
+ parsed and attached at the end of the PciNode list of variable elements.
+
+ @param [in, out] PciNode Pci node to amend.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+AddOscMethod (
+ IN OUT AML_OBJECT_NODE_HANDLE PciNode
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS Status1;
+ EFI_ACPI_DESCRIPTION_HEADER * SsdtPcieOscTemplate;
+ AML_ROOT_NODE_HANDLE RootNode;
+ AML_OBJECT_NODE_HANDLE OscNode;
+
+ ASSERT (PciNode != NULL);
+
+ // Parse the Ssdt Pci Osc Template.
+ SsdtPcieOscTemplate = (EFI_ACPI_DESCRIPTION_HEADER*)
+ ssdtpcieosctemplate_aml_code;
+
+ RootNode = NULL;
+ Status = AmlParseDefinitionBlock (
+ SsdtPcieOscTemplate,
+ &RootNode
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-PCI-OSC: Failed to parse SSDT PCI OSC Template."
+ " Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+
+ Status = AmlFindNode (RootNode, "\\_OSC", &OscNode);
+ if (EFI_ERROR (Status)) {
+ goto error_handler;
+ }
+
+ Status = AmlDetachNode (OscNode);
+ if (EFI_ERROR (Status)) {
+ goto error_handler;
+ }
+
+ Status = AmlAttachNode (PciNode, OscNode);
+ if (EFI_ERROR (Status)) {
+ goto error_handler;
+ }
+
+error_handler:
+ // Cleanup
+ Status1 = AmlDeleteTree (RootNode);
+ if (EFI_ERROR (Status1)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-PCI-OSC: Failed to cleanup AML tree."
+ " Status = %r\n",
+ Status1
+ ));
+ // If Status was success but we failed to delete the AML Tree
+ // return Status1 else return the original error code, i.e. Status.
+ if (!EFI_ERROR (Status)) {
+ return Status1;
+ }
+ }
+
+ return Status;
+}
+
+/** Generate a Pci device.
+
+ @param [in] Generator The SSDT Pci generator.
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager
+ Protocol interface.
+ @param [in] PciInfo Pci device information.
+ @param [in] Uid Unique Id of the Pci device.
+ @param [in, out] RootNode RootNode of the AML tree to populate.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GeneratePciDevice (
+ IN ACPI_PCI_GENERATOR * Generator,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO * PciInfo,
+ IN UINT32 Uid,
+ IN OUT AML_ROOT_NODE_HANDLE * RootNode
+ )
+{
+ EFI_STATUS Status;
+
+ CHAR8 AslName[AML_NAME_SEG_SIZE + 1];
+ AML_OBJECT_NODE_HANDLE ScopeNode;
+ AML_OBJECT_NODE_HANDLE PciNode;
+
+ ASSERT (Generator != NULL);
+ ASSERT (CfgMgrProtocol != NULL);
+ ASSERT (PciInfo != NULL);
+ ASSERT (RootNode != NULL);
+
+ PciNode = NULL;
+
+ // ASL: Scope (\_SB) {}
+ Status = AmlCodeGenScope (SB_SCOPE, RootNode, &ScopeNode);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Write the name of the PCI device.
+ CopyMem (AslName, "PCIx", AML_NAME_SEG_SIZE + 1);
+ AslName[AML_NAME_SEG_SIZE - 1] = AsciiFromHex (Uid);
+
+ // ASL: Device (PCIx) {}
+ Status = AmlCodeGenDevice (AslName, ScopeNode, &PciNode);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Populate the PCIx node with some Id values.
+ Status = GeneratePciDeviceInfo (PciInfo, Uid, PciNode);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Generate the Pci Routing Table (_PRT).
+ if (PciInfo->InterruptMapToken != CM_NULL_TOKEN) {
+ Status = GeneratePrt (
+ Generator,
+ CfgMgrProtocol,
+ PciInfo,
+ PciNode
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+ }
+
+ // Generate the _CRS method.
+ Status = GeneratePciCrs (Generator, CfgMgrProtocol, PciInfo, PciNode);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Add the template _OSC method.
+ Status = AddOscMethod (PciNode);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ }
+
+ return Status;
+}
+
+/** Build an Ssdt table describing a Pci device.
+
+ @param [in] Generator The SSDT Pci generator.
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager
+ Protocol interface.
+ @param [in] PciInfo Pci device information.
+ @param [in] Uid Unique Id of the Pci device.
+ @param [out] Table If success, contains the created SSDT table.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+BuildSsdtPciTable (
+ IN ACPI_PCI_GENERATOR * Generator,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO * PciInfo,
+ IN UINT32 Uid,
+ OUT EFI_ACPI_DESCRIPTION_HEADER ** Table
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS Status1;
+ AML_ROOT_NODE_HANDLE RootNode;
+ CHAR8 OemTableId[9];
+
+ ASSERT (Generator != NULL);
+ ASSERT (CfgMgrProtocol != NULL);
+ ASSERT (PciInfo != NULL);
+ ASSERT (Table != NULL);
+
+ CopyMem (OemTableId, "SSDTPCIx", sizeof (OemTableId) + 1);
+ OemTableId[7] = AsciiFromHex(Uid);
+
+ // Create a new Ssdt table.
+ Status = AmlCodeGenDefinitionBlock (
+ "SSDT",
+ "ARMLTD",
+ OemTableId,
+ 1,
+ &RootNode
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ Status = GeneratePciDevice (
+ Generator,
+ CfgMgrProtocol,
+ PciInfo,
+ Uid,
+ RootNode
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ goto exit_handler;
+ }
+
+ // Serialize the tree.
+ Status = AmlSerializeDefinitionBlock (
+ RootNode,
+ Table
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-PCI: Failed to Serialize SSDT Table Data."
+ " Status = %r\n",
+ Status
+ ));
+ }
+
+exit_handler:
+ // Cleanup
+ Status1 = AmlDeleteTree (RootNode);
+ if (EFI_ERROR (Status1)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-PCI: Failed to cleanup AML tree."
+ " Status = %r\n",
+ Status1
+ ));
+ // If Status was success but we failed to delete the AML Tree
+ // return Status1 else return the original error code, i.e. Status.
+ if (!EFI_ERROR (Status)) {
+ return Status1;
+ }
+ }
+
+ return Status;
+}
+
+/** Construct SSDT tables describing Pci root complexes.
+
+ This function invokes the Configuration Manager protocol interface
+ to get the required hardware information for generating the ACPI
+ table.
+
+ If this function allocates any resources then they must be freed
+ in the FreeXXXXTableResourcesEx function.
+
+ @param [in] This Pointer to the ACPI table generator.
+ @param [in] AcpiTableInfo Pointer to the ACPI table information.
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager
+ Protocol interface.
+ @param [out] Table Pointer to a list of generated ACPI table(s).
+ @param [out] TableCount Number of generated ACPI table(s).
+
+ @retval EFI_SUCCESS Table generated successfully.
+ @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration
+ Manager is less than the Object size for
+ the requested object.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_NOT_FOUND Could not find information.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
+ @retval EFI_UNSUPPORTED Unsupported configuration.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+BuildSsdtPciTableEx (
+ IN CONST ACPI_TABLE_GENERATOR * This,
+ IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ OUT EFI_ACPI_DESCRIPTION_HEADER *** Table,
+ OUT UINTN * CONST TableCount
+ )
+{
+ EFI_STATUS Status;
+ CM_ARM_PCI_CONFIG_SPACE_INFO * PciInfo;
+ UINT32 PciCount;
+ UINTN Index;
+ EFI_ACPI_DESCRIPTION_HEADER ** TableList;
+ ACPI_PCI_GENERATOR * Generator;
+
+ ASSERT (This != NULL);
+ ASSERT (AcpiTableInfo != NULL);
+ ASSERT (CfgMgrProtocol != NULL);
+ ASSERT (Table != NULL);
+ ASSERT (TableCount != NULL);
+ ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
+ ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
+
+ *TableCount = 0;
+ Generator = (ACPI_PCI_GENERATOR*)This;
+
+ Status = GetEArmObjPciConfigSpaceInfo (
+ CfgMgrProtocol,
+ CM_NULL_TOKEN,
+ &PciInfo,
+ &PciCount
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ if (PciCount > MAX_PCI_ROOT_COMPLEXES_SUPPORTED) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-PCI: Too many Pci root complexes: %d."
+ " Maximum Pci root complexes supported = %d.\n",
+ PciCount,
+ MAX_PCI_ROOT_COMPLEXES_SUPPORTED
+ ));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Allocate a table to store pointers to the SSDT tables.
+ TableList = (EFI_ACPI_DESCRIPTION_HEADER**)
+ AllocateZeroPool (
+ (sizeof (EFI_ACPI_DESCRIPTION_HEADER*) * PciCount)
+ );
+ if (TableList == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-PCI: Failed to allocate memory for Table List."
+ " Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+
+ // Setup the table list early so that appropriate cleanup
+ // can be done in case of failure.
+ *Table = TableList;
+
+ for (Index = 0; Index < PciCount; Index++) {
+ // Build a SSDT table describing the Pci devices.
+ Status = BuildSsdtPciTable (
+ Generator,
+ CfgMgrProtocol,
+ &PciInfo[Index],
+ Index,
+ &TableList[Index]
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-PCI: Failed to build associated SSDT table."
+ " Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+
+ *TableCount += 1;
+ } // for
+
+error_handler:
+ // Note: Table list and Table count have been setup. The
+ // error handler does nothing here as the framework will invoke
+ // FreeSsdtPciTableEx () even on failure.
+ return Status;
+}
+
+/** Free any resources allocated for constructing the tables.
+
+ @param [in] This Pointer to the ACPI table generator.
+ @param [in] AcpiTableInfo Pointer to the ACPI Table Info.
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager
+ Protocol Interface.
+ @param [in, out] Table Pointer to an array of pointers
+ to ACPI Table(s).
+ @param [in] TableCount Number of ACPI table(s).
+
+ @retval EFI_SUCCESS The resources were freed successfully.
+ @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+FreeSsdtPciTableEx (
+ IN CONST ACPI_TABLE_GENERATOR * CONST This,
+ IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ IN OUT EFI_ACPI_DESCRIPTION_HEADER *** CONST Table,
+ IN CONST UINTN TableCount
+ )
+{
+ EFI_ACPI_DESCRIPTION_HEADER ** TableList;
+ UINTN Index;
+
+ ASSERT (This != NULL);
+ ASSERT (AcpiTableInfo != NULL);
+ ASSERT (CfgMgrProtocol != NULL);
+ ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
+ ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
+
+ if ((Table == NULL) ||
+ (*Table == NULL) ||
+ (TableCount == 0)) {
+ DEBUG ((DEBUG_ERROR, "ERROR: SSDT-PCI: Invalid Table Pointer\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ TableList = *Table;
+ for (Index = 0; Index < TableCount; Index++) {
+ if ((TableList[Index] != NULL) &&
+ (TableList[Index]->Signature ==
+ EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE)) {
+ FreePool (TableList[Index]);
+ } else {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-PCI: Could not free SSDT table at index %d.",
+ Index
+ ));
+ return EFI_INVALID_PARAMETER;
+ }
+ } //for
+
+ // Free the table list.
+ FreePool (*Table);
+
+ return EFI_SUCCESS;
+}
+
+/** This macro defines the SSDT Pci Table Generator revision.
+*/
+#define SSDT_PCI_GENERATOR_REVISION CREATE_REVISION (1, 0)
+
+/** The interface for the SSDT Pci Table Generator.
+*/
+STATIC
+ACPI_PCI_GENERATOR SsdtPcieGenerator = {
+ // ACPI table generator header
+ {
+ // Generator ID
+ CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdSsdtPciExpress),
+ // Generator Description
+ L"ACPI.STD.SSDT.PCI.GENERATOR",
+ // ACPI Table Signature
+ EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE,
+ // ACPI Table Revision - Unused
+ 0,
+ // Minimum ACPI Table Revision - Unused
+ 0,
+ // Creator ID
+ TABLE_GENERATOR_CREATOR_ID_ARM,
+ // Creator Revision
+ SSDT_PCI_GENERATOR_REVISION,
+ // Build table function. Use the extended version instead.
+ NULL,
+ // Free table function. Use the extended version instead.
+ NULL,
+ // Extended Build table function.
+ BuildSsdtPciTableEx,
+ // Extended free function.
+ FreeSsdtPciTableEx
+ },
+
+ // Private fields are defined from here.
+
+ // IrqTable
+ {
+ // Table
+ NULL,
+ // LastIndex
+ 0,
+ // MaxIndex
+ 0
+ },
+ // DeviceTable
+ {
+ // Table
+ NULL,
+ // LastIndex
+ 0,
+ // MaxIndex
+ 0
+ },
+};
+
+/** Register the Generator with the ACPI Table Factory.
+
+ @param [in] ImageHandle The handle to the image.
+ @param [in] SystemTable Pointer to the System Table.
+
+ @retval EFI_SUCCESS The Generator is registered.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_ALREADY_STARTED The Generator for the Table ID
+ is already registered.
+**/
+EFI_STATUS
+EFIAPI
+AcpiSsdtPcieLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE * SystemTable
+ )
+{
+ EFI_STATUS Status;
+ Status = RegisterAcpiTableGenerator (&SsdtPcieGenerator.Header);
+ DEBUG ((
+ DEBUG_INFO,
+ "SSDT-PCI: Register Generator. Status = %r\n",
+ Status
+ ));
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+/** Deregister the Generator from the ACPI Table Factory.
+
+ @param [in] ImageHandle The handle to the image.
+ @param [in] SystemTable Pointer to the System Table.
+
+ @retval EFI_SUCCESS The Generator is deregistered.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_NOT_FOUND The Generator is not registered.
+**/
+EFI_STATUS
+EFIAPI
+AcpiSsdtPcieLibDestructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE * SystemTable
+ )
+{
+ EFI_STATUS Status;
+ Status = DeregisterAcpiTableGenerator (&SsdtPcieGenerator.Header);
+ DEBUG ((
+ DEBUG_INFO,
+ "SSDT-PCI: Deregister Generator. Status = %r\n",
+ Status
+ ));
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
diff --git a/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieGenerator.h b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieGenerator.h
new file mode 100644
index 000000000000..2b7f40447d87
--- /dev/null
+++ b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieGenerator.h
@@ -0,0 +1,134 @@
+/** @file
+ SSDT Pcie Table Generator.
+
+ Copyright (c) 2021, Arm Limited. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - PCI Firmware Specification - Revision 3.0
+ - ACPI 6.4 specification:
+ - s6.2.13 "_PRT (PCI Routing Table)"
+ - s6.1.1 "_ADR (Address)"
+ - linux kernel code
+**/
+
+#ifndef SSDT_PCIE_GENERATOR_H_
+#define SSDT_PCIE_GENERATOR_H_
+
+/** Pci address attributes.
+*/
+#define PCI_SS_CONFIG 0
+#define PCI_SS_IO 1
+#define PCI_SS_M32 2
+#define PCI_SS_M64 3
+
+/** Maximum Pci root complexes supported by this generator.
+
+ Note: This is not a hard limitation and can be extended if needed.
+ Corresponding changes would be needed to support the Name and
+ UID fields describing the Pci root complexes.
+*/
+#define MAX_PCI_ROOT_COMPLEXES_SUPPORTED 16
+
+/** Maximum number of Pci legacy interrupts.
+
+ Currently 4 for INTA-INTB-INTC-INTD.
+*/
+#define MAX_PCI_LEGACY_INTERRUPT 4
+
+// _SB scope of the AML namespace.
+#define SB_SCOPE "\\_SB_"
+
+/** C array containing the compiled AML template.
+ This symbol is defined in the auto generated C file
+ containing the AML bytecode array.
+*/
+extern CHAR8 ssdtpcieosctemplate_aml_code[];
+
+#pragma pack(1)
+
+/** Structure used to map integer to an index.
+*/
+typedef struct MappingTable {
+ /// Mapping table.
+ /// Contains the Index <-> integer mapping
+ UINT32 * Table;
+
+ /// Last used index of the Table.
+ /// Bound by MaxIndex.
+ UINT32 LastIndex;
+
+ /// Number of entries in the Table.
+ UINT32 MaxIndex;
+} MAPPING_TABLE;
+
+/** A structure holding the Pcie generator and additional private data.
+*/
+typedef struct AcpiPcieGenerator {
+ /// ACPI Table generator header
+ ACPI_TABLE_GENERATOR Header;
+
+ // Private fields are defined from here.
+
+ /** A structure used to handle the Address and Interrupt Map referencing.
+
+ A CM_ARM_PCI_CONFIG_SPACE_INFO structure references two CM_ARM_OBJ_REF:
+ - one for the address mapping, referencing
+ CM_ARM_PCI_ADDRESS_MAP_INFO structures.
+ - one for the address mapping, referencing
+ CM_ARM_PCI_INTERRUPT_MAP_INFO structures.
+
+ Example (for the interrupt mapping):
+ (Pci0)
+ CM_ARM_PCI_CONFIG_SPACE_INFO
+ |
+ v
+ (List of references to address mappings)
+ CM_ARM_OBJ_REF
+ |
+ +----------------------------------------
+ | |
+ v v
+ (A first interrupt mapping) (A second interrupt mapping)
+ CM_ARM_PCI_INTERRUPT_MAP_INFO[0] CM_ARM_PCI_INTERRUPT_MAP_INFO[1]
+
+ The CM_ARM_PCI_INTERRUPT_MAP_INFO objects cannot be handled individually.
+ Device's Pci legacy interrupts that are mapped to the same CPU interrupt
+ are grouped under a Link device.
+ For instance, the following mapping:
+ - [INTA of device 0] mapped on [GIC irq 168]
+ - [INTB of device 1] mapped on [GIC irq 168]
+ will be represented in an SSDT table as:
+ - [INTA of device 0] mapped on [Link device A]
+ - [INTB of device 1] mapped on [Link device A]
+ - [Link device A] mapped on [GIC irq 168]
+
+ Counting the number of Cpu interrupts used and grouping them in Link
+ devices is done through this IRQ_TABLE.
+
+ ASL code:
+ Scope (_SB) {
+ Device (LNKA) {
+ [...]
+ Name (_PRS, ResourceTemplate () {
+ Interrupt (ResourceProducer, Level, ActiveHigh, Exclusive) { 168 }
+ })
+ }
+
+ Device (PCI0) {
+ Name (_PRT, Package () {
+ Package (0x0FFFF, 0, LNKA, 0) // INTA of device 0 <-> LNKA
+ Package (0x1FFFF, 1, LNKA, 0) // INTB of device 1 <-> LNKA
+ })
+ }
+ }
+ */
+ MAPPING_TABLE IrqTable;
+
+ /// Table to map: Index <-> Pci device
+ MAPPING_TABLE DeviceTable;
+} ACPI_PCI_GENERATOR;
+
+#pragma pack()
+
+#endif // SSDT_PCIE_GENERATOR_H_
diff --git a/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieLibArm.inf b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieLibArm.inf
new file mode 100644
index 000000000000..283b5648017c
--- /dev/null
+++ b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieLibArm.inf
@@ -0,0 +1,32 @@
+## @file
+# Ssdt Serial Port Table Generator
+#
+# Copyright (c) 2021, Arm Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ INF_VERSION = 0x0001001B
+ BASE_NAME = SsdtPcieLibArm
+ FILE_GUID = E431D7FD-26BF-4E3D-9064-5B13B0439057
+ VERSION_STRING = 1.0
+ MODULE_TYPE = DXE_DRIVER
+ LIBRARY_CLASS = NULL|DXE_DRIVER
+ CONSTRUCTOR = AcpiSsdtPcieLibConstructor
+ DESTRUCTOR = AcpiSsdtPcieLibDestructor
+
+[Sources]
+ SsdtPcieGenerator.c
+ SsdtPcieGenerator.h
+ SsdtPcieOscTemplate.asl
+
+[Packages]
+ DynamicTablesPkg/DynamicTablesPkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ AcpiHelperLib
+ AmlLib
+ BaseLib
diff --git a/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieOscTemplate.asl b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieOscTemplate.asl
new file mode 100644
index 000000000000..feaf56b53384
--- /dev/null
+++ b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieOscTemplate.asl
@@ -0,0 +1,80 @@
+/** @file
+ SSDT Pci Osc (Operating System Capabilities)
+
+ Copyright (c) 2021, Arm Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - PCI Firmware Specification - Revision 3.3
+ - ACPI 6.4 specification:
+ - s6.2.13 "_PRT (PCI Routing Table)"
+ - s6.1.1 "_ADR (Address)"
+ - linux kernel code
+**/
+
+DefinitionBlock ("SsdtPciOsc.aml", "SSDT", 2, "ARMLTD", "PCI-OSC", 1) {
+
+ // This table is just a template and is never installed as a table.
+ // Pci devices are dynamically created at runtime as:
+ // ASL:
+ // Device (PCIx) {
+ // ...
+ // }
+ // and the _OSC method available below is appended to the PCIx device as:
+ // ASL:
+ // Device (PCIx) {
+ // ...
+ // Method (_OSC, 4 {
+ // ...
+ // })
+ // }
+ Method (_OSC, 4) {
+ //
+ // OS Control Handoff
+ //
+ Name (SUPP, Zero) // PCI _OSC Support Field value
+ Name (CTRL, Zero) // PCI _OSC Control Field value
+
+ // Create DWord-addressable fields from the Capabilities Buffer
+ CreateDWordField (Arg3, 0, CDW1)
+ CreateDWordField (Arg3, 4, CDW2)
+ CreateDWordField (Arg3, 8, CDW3)
+
+ // Check for proper UUID
+ If (LEqual (Arg0,ToUUID ("33DB4D5B-1FF7-401C-9657-7441C03DD766"))) {
+
+ // Save Capabilities DWord2 & 3
+ Store (CDW2, SUPP)
+ Store (CDW3, CTRL)
+
+ // Only allow native hot plug control if OS supports:
+ // * ASPM
+ // * Clock PM
+ // * MSI/MSI-X
+ If (LNotEqual (And (SUPP, 0x16), 0x16)) {
+ And (CTRL, 0x1E, CTRL) // Mask bit 0 (and undefined bits)
+ }
+
+ // Always allow native PME, AER (no dependencies)
+
+ // Never allow SHPC (no SHPC controller in this system)
+ And (CTRL, 0x1D, CTRL)
+
+ If (LNotEqual (Arg1, One)) { // Unknown revision
+ Or (CDW1, 0x08, CDW1)
+ }
+
+ If (LNotEqual (CDW3, CTRL)) { // Capabilities bits were masked
+ Or (CDW1, 0x10, CDW1)
+ }
+
+ // Update DWORD3 in the buffer
+ Store (CTRL,CDW3)
+ Return (Arg3)
+ } Else {
+ Or (CDW1, 4, CDW1) // Unrecognized UUID
+ Return (Arg3)
+ } // If
+ } // _OSC
+}
--
2.17.1


[PATCH v1 6/7] DynamicTablesPkg: Add Pci related objects

PierreGondois
 

From: Pierre Gondois <Pierre.Gondois@...>

Introduce the following CmObj in the ArmNameSpaceObjects:
- CM_ARM_PCI_ADDRESS_MAP_INFO
- CM_ARM_PCI_INTERRUPT_MAP_INFO

These objects allow to describe address range mapping
of Pci busses and interrupt mapping of Pci devices.

Signed-off-by: Pierre Gondois <Pierre.Gondois@...>
---
.../Include/ArmNameSpaceObjects.h | 78 +++++++++++++++++++
.../ConfigurationManagerObjectParser.c | 28 ++++++-
2 files changed, 105 insertions(+), 1 deletion(-)

diff --git a/DynamicTablesPkg/Include/ArmNameSpaceObjects.h b/DynamicTablesPkg/Include/ArmNameSpaceObjects.h
index 9c49091def59..b3779f828c17 100644
--- a/DynamicTablesPkg/Include/ArmNameSpaceObjects.h
+++ b/DynamicTablesPkg/Include/ArmNameSpaceObjects.h
@@ -59,6 +59,8 @@ typedef enum ArmObjectID {
EArmObjSerialPortInfo, ///< 35 - Generic Serial Port Info
EArmObjCmn600Info, ///< 36 - CMN-600 Info
EArmObjLpiInfo, ///< 37 - Lpi Info
+ EArmObjPciAddressMapInfo, ///< 38 - Pci Address Map Info
+ EArmObjPciInterruptMapInfo, ///< 39 - Pci Interrupt Map Info
EArmObjMax
} EARM_OBJECT_ID;

@@ -433,6 +435,14 @@ typedef struct CmArmPciConfigSpaceInfo {

/// The end bus number
UINT8 EndBusNumber;
+
+ /// Optional field: Reference Token for address mapping.
+ /// Token identifying a CM_ARM_OBJ_REF structure.
+ CM_OBJECT_TOKEN AddressMapToken;
+
+ /// Optional field: Reference Token for interrupt mapping.
+ /// Token identifying a CM_ARM_OBJ_REF structure.
+ CM_OBJECT_TOKEN InterruptMapToken;
} CM_ARM_PCI_CONFIG_SPACE_INFO;

/** A structure that describes the
@@ -666,6 +676,10 @@ typedef struct CmArmGenericInterrupt {
UINT32 Interrupt;

/// Flags
+ /// BIT0: 0: Interrupt is Level triggered
+ /// 1: Interrupt is Edge triggered
+ /// BIT1: 0: Interrupt is Active high
+ /// 1: Interrupt is Active low
UINT32 Flags;
} CM_ARM_GENERIC_INTERRUPT;

@@ -946,6 +960,70 @@ typedef struct CmArmLpiInfo {
CHAR8 StateName[16];
} CM_ARM_LPI_INFO;

+/** A structure that describes a PCI Address Map.
+
+ The memory-ranges used by the PCI bus are described by this object.
+
+ ID: EArmObjPciAddressMapInfo
+*/
+typedef struct CmArmPciAddressMapInfo {
+ /** Pci address space code
+
+ Available values are:
+ - 0: Configuration Space
+ - 1: I/O Space
+ - 2: 32-bit-address Memory Space
+ - 3: 64-bit-address Memory Space
+ */
+ UINT8 SpaceCode;
+
+ /// PCI address
+ UINT64 PciAddress;
+
+ /// Cpu address
+ UINT64 CpuAddress;
+
+ /// Address size
+ UINT64 AddressSize;
+} CM_ARM_PCI_ADDRESS_MAP_INFO;
+
+/** A structure that describes a PCI Interrupt Map.
+
+ The legacy PCI interrupts used by PCI devices are described by this object.
+
+ Cf Devicetree Specification - Release v0.3
+ s2.4.3 "Interrupt Nexus Properties"
+
+ ID: EArmObjPciInterruptMapInfo
+*/
+typedef struct CmArmPciInterruptMapInfo {
+ /// Pci Bus.
+ /// Value on 8 bits (max 255).
+ UINT8 PciBus;
+
+ /// Pci Bus.
+ /// Value on 5 bits (max 31).
+ UINT8 PciDevice;
+
+ /** PCI interrupt
+
+ ACPI bindings are used:
+ Cf. ACPI 6.4, s6.2.13 _PRT (PCI Routing Table):
+ "0-INTA, 1-INTB, 2-INTC, 3-INTD"
+
+ Device-tree bindings are shifted by 1:
+ "INTA=1, INTB=2, INTC=3, INTD=4"
+ */
+ UINT8 PciInterrupt;
+
+ /** Interrupt controller interrupt.
+
+ Cf Devicetree Specification - Release v0.3
+ s2.4.3 "Interrupt Nexus Properties": "parent interrupt specifier"
+ */
+ CM_ARM_GENERIC_INTERRUPT IntcInterrupt;
+} CM_ARM_PCI_INTERRUPT_MAP_INFO;
+
#pragma pack()

#endif // ARM_NAMESPACE_OBJECTS_H_
diff --git a/DynamicTablesPkg/Library/Common/TableHelperLib/ConfigurationManagerObjectParser.c b/DynamicTablesPkg/Library/Common/TableHelperLib/ConfigurationManagerObjectParser.c
index da5f5846edd9..0ba4e6e5faff 100644
--- a/DynamicTablesPkg/Library/Common/TableHelperLib/ConfigurationManagerObjectParser.c
+++ b/DynamicTablesPkg/Library/Common/TableHelperLib/ConfigurationManagerObjectParser.c
@@ -152,7 +152,9 @@ STATIC CONST CM_OBJ_PARSER CmArmPciConfigSpaceInfoParser[] = {
{"BaseAddress", 8, "0x%llx", NULL},
{"PciSegmentGroupNumber", 2, "0x%x", NULL},
{"StartBusNumber", 1, "0x%x", NULL},
- {"EndBusNumber", 1, "0x%x", NULL}
+ {"EndBusNumber", 1, "0x%x", NULL},
+ {"AddressMapToken", sizeof (CM_OBJECT_TOKEN), "0x%p", NULL},
+ {"InterruptMapToken", sizeof (CM_OBJECT_TOKEN), "0x%p", NULL},
};

/** A parser for EArmObjHypervisorVendorIdentity.
@@ -401,6 +403,26 @@ STATIC CONST CM_OBJ_PARSER CmArmLpiInfoParser[] = {
{"StateName", 16, "0x%a", NULL},
};

+/** A parser for EArmObjPciAddressMapInfo.
+*/
+STATIC CONST CM_OBJ_PARSER CmArmPciAddressMapInfoParser[] = {
+ {"SpaceCode", 1, "%d", NULL},
+ {"PciAddress", 8, "0x%llx", NULL},
+ {"CpuAddress", 8, "0x%llx", NULL},
+ {"AddressSize", 8, "0x%llx", NULL},
+};
+
+/** A parser for EArmObjPciInterruptMapInfo.
+*/
+STATIC CONST CM_OBJ_PARSER CmPciInterruptMapInfoParser[] = {
+ {"PciBus", 1, "0x%x", NULL},
+ {"PciDevice", 1, "0x%x", NULL},
+ {"PciInterrupt", 1, "0x%x", NULL},
+ {"IntcInterrupt", sizeof (CM_ARM_GENERIC_INTERRUPT),
+ NULL, NULL, CmArmGenericInterruptParser,
+ ARRAY_SIZE (CmArmGenericInterruptParser)},
+};
+
/** A parser for Arm namespace objects.
*/
STATIC CONST CM_OBJ_PARSER_ARRAY ArmNamespaceObjectParser[] = {
@@ -475,6 +497,10 @@ STATIC CONST CM_OBJ_PARSER_ARRAY ArmNamespaceObjectParser[] = {
ARRAY_SIZE (CmArmCmn600InfoParser)},
{"EArmObjLpiInfo", CmArmLpiInfoParser,
ARRAY_SIZE (CmArmLpiInfoParser)},
+ {"EArmObjPciAddressMapInfo", CmArmPciAddressMapInfoParser,
+ ARRAY_SIZE (CmArmPciAddressMapInfoParser)},
+ {"EArmObjPciInterruptMapInfo", CmPciInterruptMapInfoParser,
+ ARRAY_SIZE (CmPciInterruptMapInfoParser)},
{"EArmObjMax", NULL, 0},
};

--
2.17.1


[PATCH v1 5/7] DynamicTablesPkg: Add AmlAttachNode()

PierreGondois
 

From: Pierre Gondois <Pierre.Gondois@...>

This function allows to add a node as the last node of a parent node
in an AML tree. For instance,
ASL code corresponding to NewNode:
Name (_UID, 0)

ASL code corresponding to ParentNode:
Device (PCI0) {
Name(_HID, EISAID("PNP0A08"))
}

"AmlAttachNode (ParentNode, NewNode)" will result in:
ASL code:
Device (PCI0) {
Name(_HID, EISAID("PNP0A08"))
Name (_UID, 0)
}

Signed-off-by: Pierre Gondois <Pierre.Gondois@...>
---
.../Include/Library/AmlLib/AmlLib.h | 33 +++++++++++++++++
.../Library/Common/AmlLib/Api/AmlApi.c | 36 +++++++++++++++++++
2 files changed, 69 insertions(+)

diff --git a/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h b/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h
index 4a10da8cd7bb..b4766726e84d 100644
--- a/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h
+++ b/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h
@@ -166,6 +166,39 @@ AmlDetachNode (
IN AML_NODE_HANDLE Node
);

+/** Attach a node in an AML tree.
+
+ The node will be added as the last statement of the ParentNode.
+ E.g.:
+ ASL code corresponding to NewNode:
+ Name (_UID, 0)
+
+ ASL code corresponding to ParentNode:
+ Device (PCI0) {
+ Name(_HID, EISAID("PNP0A08"))
+ }
+
+ "AmlAttachNode (ParentNode, NewNode)" will result in:
+ ASL code:
+ Device (PCI0) {
+ Name(_HID, EISAID("PNP0A08"))
+ Name (_UID, 0)
+ }
+
+ @param [in] ParentNode Pointer to the parent node.
+ Must be a root or an object node.
+ @param [in] NewNode Pointer to the node to add.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+EFI_STATUS
+EFIAPI
+AmlAttachNode (
+ IN AML_NODE_HANDLE ParentNode,
+ IN AML_NODE_HANDLE NewNode
+ );
+
/** Find a node in the AML namespace, given an ASL path and a reference Node.

- The AslPath can be an absolute path, or a relative path from the
diff --git a/DynamicTablesPkg/Library/Common/AmlLib/Api/AmlApi.c b/DynamicTablesPkg/Library/Common/AmlLib/Api/AmlApi.c
index 6f9e3f6f2805..def581299f5c 100644
--- a/DynamicTablesPkg/Library/Common/AmlLib/Api/AmlApi.c
+++ b/DynamicTablesPkg/Library/Common/AmlLib/Api/AmlApi.c
@@ -379,6 +379,42 @@ AmlNameOpGetNextRdNode (
return EFI_SUCCESS;
}

+/** Attach a node in an AML tree.
+
+ The node will be added as the last statement of the ParentNode.
+ E.g.:
+ ASL code corresponding to NewNode:
+ Name (_UID, 0)
+
+ ASL code corresponding to ParentNode:
+ Device (PCI0) {
+ Name(_HID, EISAID("PNP0A08"))
+ }
+
+ "AmlAttachNode (ParentNode, NewNode)" will result in:
+ ASL code:
+ Device (PCI0) {
+ Name(_HID, EISAID("PNP0A08"))
+ Name (_UID, 0)
+ }
+
+ @param [in] ParentNode Pointer to the parent node.
+ Must be a root or an object node.
+ @param [in] NewNode Pointer to the node to add.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+EFI_STATUS
+EFIAPI
+AmlAttachNode (
+ IN AML_NODE_HANDLE ParentNode,
+ IN AML_NODE_HANDLE NewNode
+ )
+{
+ return AmlVarListAddTail (ParentNode, NewNode);
+}
+
// DEPRECATED APIS
#ifndef DISABLE_NEW_DEPRECATED_INTERFACES

--
2.17.1


[PATCH v1 4/7] DynamicTablesPkg: AML Code generation to add _PRT entries

PierreGondois
 

From: Pierre Gondois <Pierre.Gondois@...>

_PRT entries can describe interrupt mapping for Pci devices. The
object is described in ACPI 6.4 s6.2.13 "_PRT (PCI Routing Table)".

Add AmlCodeGenPrtEntry() helper function to add _PRT entries
to an existing _PRT object.

Signed-off-by: Pierre Gondois <Pierre.Gondois@...>
---
.../Include/Library/AmlLib/AmlLib.h | 52 +++++
.../Common/AmlLib/CodeGen/AmlCodeGen.c | 210 ++++++++++++++++++
2 files changed, 262 insertions(+)

diff --git a/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h b/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h
index 544bc670c455..4a10da8cd7bb 100644
--- a/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h
+++ b/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h
@@ -908,6 +908,58 @@ AmlCodeGenNameResourceTemplate (
OUT AML_OBJECT_NODE_HANDLE * NewObjectNode OPTIONAL
);

+/** Add a _PRT entry.
+
+ AmlCodeGenPrtEntry (0x0FFFF, 0, "LNKA", 0, PrtNameNode) is
+ equivalent of the following ASL code:
+ Package (4) {
+ 0x0FFFF, // Address: Device address (([Device Id] << 16) | 0xFFFF).
+ 0, // Pin: PCI pin number of the device (0-INTA, ...).
+ LNKA // Source: Name of the device that allocates the interrupt
+ // to which the above pin is connected.
+ 0 // Source Index: Source is assumed to only describe one
+ // interrupt, so let it to index 0.
+ }
+
+ The package is added at the tail of the list of the input _PRT node
+ name:
+ Name (_PRT, Package () {
+ [Pre-existing _PRT entries],
+ [Newly created _PRT entry]
+ })
+
+ Cf. ACPI 6.4, s6.2.13 "_PRT (PCI Routing Table)"
+
+ @ingroup CodeGenApis
+
+ @param [in] Address Address. Cf ACPI 6.4 specification, Table 6.2:
+ "ADR Object Address Encodings":
+ High word-Device #, Low word-Function #. (for
+ example, device 3, function 2 is 0x00030002).
+ To refer to all the functions on a device #,
+ use a function number of FFFF).
+ @param [in] Pin PCI pin number of the device (0-INTA ... 3-INTD).
+ Must be between 0-3.
+ @param [in] LinkName Link Name, i.e. device in the AML NameSpace
+ describing the interrupt used.
+ The input string is copied.
+ @param [in] SourceIndex Source index or GSIV.
+ @param [in] PrtNameNode Prt Named node to add the object to ....
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
+**/
+EFI_STATUS
+EFIAPI
+AmlAddPrtEntry (
+ IN UINT32 Address,
+ IN UINT8 Pin,
+ IN CONST CHAR8 * LinkName,
+ IN UINT32 SourceIndex,
+ IN AML_OBJECT_NODE_HANDLE PrtNameNode
+ );
+
/** AML code generation for a Device object node.

AmlCodeGenDevice ("COM0", ParentNode, NewObjectNode) is
diff --git a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
index eaa49a5834c2..9bf4e110d05c 100644
--- a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
+++ b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
@@ -857,6 +857,216 @@ AmlCodeGenNameResourceTemplate (
return Status;
}

+/** Add a _PRT entry.
+
+ AmlCodeGenPrtEntry (0x0FFFF, 0, "LNKA", 0, PrtNameNode) is
+ equivalent of the following ASL code:
+ Package (4) {
+ 0x0FFFF, // Address: Device address (([Device Id] << 16) | 0xFFFF).
+ 0, // Pin: PCI pin number of the device (0-INTA, ...).
+ LNKA // Source: Name of the device that allocates the interrupt
+ // to which the above pin is connected.
+ 0 // Source Index: Source is assumed to only describe one
+ // interrupt, so let it to index 0.
+ }
+
+ The package is added at the tail of the list of the input _PRT node
+ name:
+ Name (_PRT, Package () {
+ [Pre-existing _PRT entries],
+ [Newly created _PRT entry]
+ })
+
+ Cf. ACPI 6.4 specification:
+ - s6.2.13 "_PRT (PCI Routing Table)"
+ - s6.1.1 "_ADR (Address)"
+
+ @param [in] Address Address. Cf ACPI 6.4 specification, Table 6.2:
+ "ADR Object Address Encodings":
+ High word-Device #, Low word-Function #. (for
+ example, device 3, function 2 is 0x00030002).
+ To refer to all the functions on a device #,
+ use a function number of FFFF).
+ @param [in] Pin PCI pin number of the device (0-INTA ... 3-INTD).
+ Must be between 0-3.
+ @param [in] LinkName Link Name, i.e. device in the AML NameSpace
+ describing the interrupt used.
+ The input string is copied.
+ @param [in] SourceIndex Source index or GSIV.
+ @param [in] PrtNameNode Prt Named node to add the object to ....
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
+**/
+EFI_STATUS
+EFIAPI
+AmlAddPrtEntry (
+ IN UINT32 Address,
+ IN UINT8 Pin,
+ IN CONST CHAR8 * LinkName,
+ IN UINT32 SourceIndex,
+ IN AML_OBJECT_NODE_HANDLE PrtNameNode
+ )
+{
+ EFI_STATUS Status;
+ AML_OBJECT_NODE * PrtEntryList;
+ AML_OBJECT_NODE * PackageNode;
+ AML_OBJECT_NODE * NewElementNode;
+
+ CHAR8 * AmlNameString;
+ UINT32 AmlNameStringSize;
+ AML_DATA_NODE * DataNode;
+
+ if ((Pin > 3) ||
+ (LinkName == NULL) ||
+ (PrtNameNode == NULL) ||
+ (AmlGetNodeType ((AML_NODE_HANDLE)PrtNameNode) != EAmlNodeObject) ||
+ (!AmlNodeHasOpCode (PrtNameNode, AML_NAME_OP, 0)) ||
+ !AmlNameOpCompareName (PrtNameNode, "_PRT")) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ NewElementNode = NULL;
+ AmlNameString = NULL;
+ DataNode = NULL;
+
+ // Get the Package object node of the _PRT node,
+ // which is the 2nd fixed argument (i.e. index 1).
+ PrtEntryList = (AML_OBJECT_NODE_HANDLE)AmlGetFixedArgument (
+ PrtNameNode,
+ EAmlParseIndexTerm1
+ );
+ if ((PrtEntryList == NULL) ||
+ (AmlGetNodeType ((AML_NODE_HANDLE)PrtEntryList) != EAmlNodeObject) ||
+ (!AmlNodeHasOpCode (PrtEntryList, AML_PACKAGE_OP, 0))) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // The new _PRT entry.
+ Status = AmlCodeGenPackage (&PackageNode);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ Status = AmlCodeGenInteger (Address, &NewElementNode);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ goto error_handler;
+ }
+
+ Status = AmlVarListAddTail (
+ (AML_NODE_HANDLE)PackageNode,
+ (AML_NODE_HANDLE)NewElementNode
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ goto error_handler;
+ }
+
+ NewElementNode = NULL;
+
+ Status = AmlCodeGenInteger (Pin, &NewElementNode);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ goto error_handler;
+ }
+
+ Status = AmlVarListAddTail (
+ (AML_NODE_HANDLE)PackageNode,
+ (AML_NODE_HANDLE)NewElementNode
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ goto error_handler;
+ }
+
+ NewElementNode = NULL;
+
+ Status = ConvertAslNameToAmlName (LinkName, &AmlNameString);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ goto error_handler;
+ }
+
+ Status = AmlGetNameStringSize (AmlNameString, &AmlNameStringSize);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ goto error_handler;
+ }
+
+ Status = AmlCreateDataNode (
+ EAmlNodeDataTypeNameString,
+ (UINT8*)AmlNameString,
+ AmlNameStringSize,
+ &DataNode
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ goto error_handler;
+ }
+
+ // AmlNameString will be freed before returning.
+
+ Status = AmlVarListAddTail (
+ (AML_NODE_HANDLE)PackageNode,
+ (AML_NODE_HANDLE)DataNode
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ goto error_handler;
+ }
+
+ DataNode = NULL;
+
+ Status = AmlCodeGenInteger (SourceIndex, &NewElementNode);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ goto error_handler;
+ }
+
+ Status = AmlVarListAddTail (
+ (AML_NODE_HANDLE)PackageNode,
+ (AML_NODE_HANDLE)NewElementNode
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ goto error_handler;
+ }
+
+ // Append to the the list of _PRT entries.
+ Status = AmlVarListAddTail (
+ (AML_NODE_HANDLE)PrtEntryList,
+ (AML_NODE_HANDLE)PackageNode
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ goto error_handler;
+ }
+
+ // Free AmlNameString before returning as it is copied
+ // in the call to AmlCreateDataNode().
+ goto exit_handler;
+
+error_handler:
+ AmlDeleteTree ((AML_NODE_HANDLE)PackageNode);
+ if (NewElementNode != NULL) {
+ AmlDeleteTree ((AML_NODE_HANDLE)NewElementNode);
+ }
+ if (DataNode != NULL) {
+ AmlDeleteTree ((AML_NODE_HANDLE)DataNode);
+ }
+
+exit_handler:
+ if (AmlNameString != NULL) {
+ FreePool (AmlNameString);
+ }
+ return Status;
+}
+
/** AML code generation for a Device object node.

AmlCodeGenDevice ("COM0", ParentNode, NewObjectNode) is
--
2.17.1


[PATCH v1 3/7] DynamicTablesPkg: AML Code generation to create a named ResourceTemplate()

PierreGondois
 

From: Pierre Gondois <Pierre.Gondois@...>

Add AmlCodeGenNameResourceTemplate() to generate code for a
ResourceTemplate().

AmlCodeGenNameResourceTemplate ("REST", ParentNode, NewObjectNode) is
equivalent of the following ASL code:
Name(REST, ResourceTemplate () {})

Signed-off-by: Pierre Gondois <Pierre.Gondois@...>
---
.../Include/Library/AmlLib/AmlLib.h | 28 ++++++++++
.../Common/AmlLib/CodeGen/AmlCodeGen.c | 55 +++++++++++++++++++
2 files changed, 83 insertions(+)

diff --git a/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h b/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h
index 412db886e1f2..544bc670c455 100644
--- a/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h
+++ b/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h
@@ -880,6 +880,34 @@ AmlCodeGenNamePackage (
OUT AML_OBJECT_NODE_HANDLE * NewObjectNode OPTIONAL
);

+/** AML code generation for a Name object node, containing a ResourceTemplate.
+
+ AmlCodeGenNameResourceTemplate ("PRS0", ParentNode, NewObjectNode) is
+ equivalent of the following ASL code:
+ Name(PRS0, ResourceTemplate () {})
+
+ @ingroup CodeGenApis
+
+ @param [in] NameString The new variable name.
+ Must be a NULL-terminated ASL NameString
+ e.g.: "DEV0", "DV15.DEV0", etc.
+ The input string is copied.
+ @param [in] ParentNode If provided, set ParentNode as the parent
+ of the node created.
+ @param [out] NewObjectNode If success, contains the created node.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
+**/
+EFI_STATUS
+EFIAPI
+AmlCodeGenNameResourceTemplate (
+ IN CONST CHAR8 * NameString,
+ IN AML_NODE_HANDLE ParentNode, OPTIONAL
+ OUT AML_OBJECT_NODE_HANDLE * NewObjectNode OPTIONAL
+ );
+
/** AML code generation for a Device object node.

AmlCodeGenDevice ("COM0", ParentNode, NewObjectNode) is
diff --git a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
index f9175c623622..eaa49a5834c2 100644
--- a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
+++ b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
@@ -802,6 +802,61 @@ AmlCodeGenNamePackage (
return Status;
}

+/** AML code generation for a Name object node, containing a ResourceTemplate.
+
+ AmlCodeGenNameResourceTemplate ("PRS0", ParentNode, NewObjectNode) is
+ equivalent of the following ASL code:
+ Name(PRS0, ResourceTemplate () {})
+
+ @param [in] NameString The new variable name.
+ Must be a NULL-terminated ASL NameString
+ e.g.: "DEV0", "DV15.DEV0", etc.
+ The input string is copied.
+ @param [in] ParentNode If provided, set ParentNode as the parent
+ of the node created.
+ @param [out] NewObjectNode If success, contains the created node.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
+**/
+EFI_STATUS
+EFIAPI
+AmlCodeGenNameResourceTemplate (
+ IN CONST CHAR8 * NameString,
+ IN AML_NODE_HEADER * ParentNode, OPTIONAL
+ OUT AML_OBJECT_NODE ** NewObjectNode OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ AML_OBJECT_NODE * ResourceTemplateNode;
+
+ if ((NameString == NULL) ||
+ ((ParentNode == NULL) && (NewObjectNode == NULL))) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = AmlCodeGenResourceTemplate (&ResourceTemplateNode);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ Status = AmlCodeGenName (
+ NameString,
+ ResourceTemplateNode,
+ ParentNode,
+ NewObjectNode
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ AmlDeleteTree ((AML_NODE_HEADER*)ResourceTemplateNode);
+ }
+
+ return Status;
+}
+
/** AML code generation for a Device object node.

AmlCodeGenDevice ("COM0", ParentNode, NewObjectNode) is
--
2.17.1


[PATCH v1 2/7] DynamicTablesPkg: AML Code generation to create a named Package()

PierreGondois
 

From: Pierre Gondois <Pierre.Gondois@...>

Add AmlCodeGenNamePackage() to generate code for a Package().

AmlCodeGenNamePackage ("PACK", ParentNode, NewObjectNode) is
equivalent of the following ASL code:
Name(PACK, Package () {})

Signed-off-by: Pierre Gondois <Pierre.Gondois@...>
---
.../Include/Library/AmlLib/AmlLib.h | 28 ++++++++++
.../Common/AmlLib/CodeGen/AmlCodeGen.c | 55 +++++++++++++++++++
2 files changed, 83 insertions(+)

diff --git a/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h b/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h
index cbbbb7a478f7..412db886e1f2 100644
--- a/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h
+++ b/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h
@@ -852,6 +852,34 @@ AmlCodeGenNameInteger (
OUT AML_OBJECT_NODE_HANDLE * NewObjectNode OPTIONAL
);

+/** AML code generation for a Name object node, containing a Package.
+
+ AmlCodeGenNamePackage ("PKG0", ParentNode, NewObjectNode) is
+ equivalent of the following ASL code:
+ Name(PKG0, Package () {})
+
+ @ingroup CodeGenApis
+
+ @param [in] NameString The new variable name.
+ Must be a NULL-terminated ASL NameString
+ e.g.: "DEV0", "DV15.DEV0", etc.
+ The input string is copied.
+ @param [in] ParentNode If provided, set ParentNode as the parent
+ of the node created.
+ @param [out] NewObjectNode If success, contains the created node.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
+**/
+EFI_STATUS
+EFIAPI
+AmlCodeGenNamePackage (
+ IN CONST CHAR8 * NameString,
+ IN AML_NODE_HANDLE ParentNode, OPTIONAL
+ OUT AML_OBJECT_NODE_HANDLE * NewObjectNode OPTIONAL
+ );
+
/** AML code generation for a Device object node.

AmlCodeGenDevice ("COM0", ParentNode, NewObjectNode) is
diff --git a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
index f0861040191f..f9175c623622 100644
--- a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
+++ b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
@@ -747,6 +747,61 @@ AmlCodeGenNameInteger (
return Status;
}

+/** AML code generation for a Name object node, containing a Package.
+
+ AmlCodeGenNamePackage ("PKG0", ParentNode, NewObjectNode) is
+ equivalent of the following ASL code:
+ Name(PKG0, Package () {})
+
+ @param [in] NameString The new variable name.
+ Must be a NULL-terminated ASL NameString
+ e.g.: "DEV0", "DV15.DEV0", etc.
+ The input string is copied.
+ @param [in] ParentNode If provided, set ParentNode as the parent
+ of the node created.
+ @param [out] NewObjectNode If success, contains the created node.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
+**/
+EFI_STATUS
+EFIAPI
+AmlCodeGenNamePackage (
+ IN CONST CHAR8 * NameString,
+ IN AML_NODE_HEADER * ParentNode, OPTIONAL
+ OUT AML_OBJECT_NODE ** NewObjectNode OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ AML_OBJECT_NODE * PackageNode;
+
+ if ((NameString == NULL) ||
+ ((ParentNode == NULL) && (NewObjectNode == NULL))) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = AmlCodeGenPackage (&PackageNode);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ Status = AmlCodeGenName (
+ NameString,
+ PackageNode,
+ ParentNode,
+ NewObjectNode
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ AmlDeleteTree ((AML_NODE_HEADER*)PackageNode);
+ }
+
+ return Status;
+}
+
/** AML code generation for a Device object node.

AmlCodeGenDevice ("COM0", ParentNode, NewObjectNode) is
--
2.17.1


[PATCH v1 1/7] DynamicTablesPkg: AML Code generation for memory ranges

PierreGondois
 

From: Pierre Gondois <Pierre.Gondois@...>

Add helper functions to generate AML Resource Data describing memory
ranges. Memory ranges can be one, double or four words long. They
can be of 'normal', IO or bus number memory type. The following
APIs are exposed:
- AmlCodeGenRdDWordIo ()
- AmlCodeGenRdDWordMemory ()
- AmlCodeGenRdWordBusNumber ()
- AmlCodeGenRdQWordMemory ()

Signed-off-by: Pierre Gondois <Pierre.Gondois@...>
---
.../Include/Library/AmlLib/AmlLib.h | 289 ++++++
.../AmlLib/CodeGen/AmlResourceDataCodeGen.c | 945 ++++++++++++++++++
2 files changed, 1234 insertions(+)

diff --git a/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h b/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h
index 4932f6fd9c8b..cbbbb7a478f7 100644
--- a/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h
+++ b/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h
@@ -418,6 +418,295 @@ AmlUpdateRdQWord (
IN UINT64 BaseAddressLength
);

+/** Code generation for the "DWordIO ()" ASL function.
+
+ The Resource Data effectively created is an Extended Interrupt Resource
+ Data. Cf ACPI 6.4:
+ - s6.4.3.5.2 "DWord Address Space Descriptor".
+ - s19.6.34 "DWordIO".
+
+ The created resource data node can be:
+ - appended to the list of resource data elements of the NameOpNode.
+ In such case NameOpNode must be defined by a the "Name ()" ASL statement
+ and initially contain a "ResourceTemplate ()".
+ - returned through the NewRdNode parameter.
+
+ @ingroup CodeGenApis
+
+ @param [in] IsResourceConsumer ResourceUsage parameter,
+ See ACPI 6.4 spec, s19.6.34 for more.
+ @param [in] IsMinFixed See ACPI 6.4 spec, s19.6.34 for more.
+ @param [in] IsMaxFixed See ACPI 6.4 spec, s19.6.34 for more.
+ @param [in] IsPosDecode Decode parameter,
+ See ACPI 6.4 spec, s19.6.34 for more.
+ @param [in] IsaRanges Available values are:
+ 0-Reserved
+ 1-NonISAOnly
+ 2-ISAOnly
+ 3-EntireRange
+ See ACPI 6.4 spec, s19.6.34 for more.
+ @param [in] AddressGranularity See ACPI 6.4 spec, s19.6.34 for more.
+ @param [in] AddressMinimum See ACPI 6.4 spec, s19.6.34 for more.
+ @param [in] AddressMaximum See ACPI 6.4 spec, s19.6.34 for more.
+ @param [in] AddressTranslation See ACPI 6.4 spec, s19.6.34 for more.
+ @param [in] RangeLength See ACPI 6.4 spec, s19.6.34 for more.
+ @param [in] ResourceSourceIndex See ACPI 6.4 spec, s19.6.34 for more.
+ Not supported.
+ @param [in] ResourceSource See ACPI 6.4 spec, s19.6.34 for more.
+ Not supported.
+ @param [in] IsDenseTranslation TranslationDensity parameter,
+ See ACPI 6.4 spec, s19.6.34 for more.
+ @param [in] IsTypeStatic TranslationType parameter,
+ See ACPI 6.4 spec, s19.6.34 for more.
+ @param [in] NameOpNode NameOp object node defining a named object.
+ If provided, append the new resource data
+ node to the list of resource data elements
+ of this node.
+ @param [out] NewRdNode If provided and success,
+ contain the created node.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
+**/
+EFI_STATUS
+EFIAPI
+AmlCodeGenRdDWordIo (
+ IN BOOLEAN IsResourceConsumer,
+ IN BOOLEAN IsMinFixed,
+ IN BOOLEAN IsMaxFixed,
+ IN BOOLEAN IsPosDecode,
+ IN UINT8 IsaRanges,
+ IN UINT32 AddressGranularity,
+ IN UINT32 AddressMinimum,
+ IN UINT32 AddressMaximum,
+ IN UINT32 AddressTranslation,
+ IN UINT32 RangeLength,
+ IN UINT8 ResourceSourceIndex,
+ IN CONST CHAR8 *ResourceSource,
+ IN BOOLEAN IsDenseTranslation,
+ IN BOOLEAN IsTypeStatic,
+ IN AML_OBJECT_NODE_HANDLE NameOpNode, OPTIONAL
+ OUT AML_DATA_NODE_HANDLE *NewRdNode OPTIONAL
+ );
+
+/** Code generation for the "DWordMemory ()" ASL function.
+
+ The Resource Data effectively created is an Extended Interrupt Resource
+ Data. Cf ACPI 6.4:
+ - s6.4.3.5.2 "DWord Address Space Descriptor".
+ - s19.6.35 "DWordMemory".
+
+ The created resource data node can be:
+ - appended to the list of resource data elements of the NameOpNode.
+ In such case NameOpNode must be defined by a the "Name ()" ASL statement
+ and initially contain a "ResourceTemplate ()".
+ - returned through the NewRdNode parameter.
+
+ @ingroup CodeGenApis
+
+ @param [in] IsResourceConsumer ResourceUsage parameter,
+ See ACPI 6.4 spec, s19.6.35 for more.
+ @param [in] IsPosDecode Decode parameter,
+ See ACPI 6.4 spec, s19.6.35 for more.
+ @param [in] IsMinFixed See ACPI 6.4 spec, s19.6.35 for more.
+ @param [in] IsMaxFixed See ACPI 6.4 spec, s19.6.35 for more.
+ @param [in] Cacheable Available values are:
+ 0-The memory is non-cacheable
+ 1-The memory is cacheable
+ 2-The memory is cacheable and supports
+ write combining
+ 3-The memory is cacheable and prefetchable
+ @param [in] IsReadWrite ReadAndWrite parameter,
+ See ACPI 6.4 spec, s19.6.35 for more.
+ @param [in] AddressGranularity See ACPI 6.4 spec, s19.6.35 for more.
+ @param [in] AddressMinimum See ACPI 6.4 spec, s19.6.35 for more.
+ @param [in] AddressMaximum See ACPI 6.4 spec, s19.6.35 for more.
+ @param [in] AddressTranslation See ACPI 6.4 spec, s19.6.35 for more.
+ @param [in] RangeLength See ACPI 6.4 spec, s19.6.35 for more.
+ @param [in] ResourceSourceIndex See ACPI 6.4 spec, s19.6.35 for more.
+ Not supported.
+ @param [in] ResourceSource See ACPI 6.4 spec, s19.6.35 for more.
+ Not supported.
+ @param [in] MemoryRangeType Available values are:
+ 0-AddressRangeMemory
+ 1-AddressRangeReserved
+ 2-AddressRangeACPI
+ 3-AddressRangeNVS
+ See ACPI 6.4 spec, s19.6.35 for more.
+ @param [in] IsTypeStatic TranslationType parameter,
+ See ACPI 6.4 spec, s19.6.35 for more.
+ @param [in] NameOpNode NameOp object node defining a named object.
+ If provided, append the new resource data
+ node to the list of resource data elements
+ of this node.
+ @param [out] NewRdNode If provided and success,
+ contain the created node.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
+**/
+EFI_STATUS
+EFIAPI
+AmlCodeGenRdDWordMemory (
+ IN BOOLEAN IsResourceConsumer,
+ IN BOOLEAN IsPosDecode,
+ IN BOOLEAN IsMinFixed,
+ IN BOOLEAN IsMaxFixed,
+ IN UINT8 Cacheable,
+ IN BOOLEAN IsReadWrite,
+ IN UINT32 AddressGranularity,
+ IN UINT32 AddressMinimum,
+ IN UINT32 AddressMaximum,
+ IN UINT32 AddressTranslation,
+ IN UINT32 RangeLength,
+ IN UINT8 ResourceSourceIndex,
+ IN CONST CHAR8 *ResourceSource,
+ IN UINT8 MemoryRangeType,
+ IN BOOLEAN IsTypeStatic,
+ IN AML_OBJECT_NODE_HANDLE NameOpNode, OPTIONAL
+ OUT AML_DATA_NODE_HANDLE *NewRdNode OPTIONAL
+ );
+
+/** Code generation for the "WordBusNumber ()" ASL function.
+
+ The Resource Data effectively created is an Extended Interrupt Resource
+ Data. Cf ACPI 6.4:
+ - s6.4.3.5.3 "Word Address Space Descriptor".
+ - s19.6.149 "WordBusNumber".
+
+ The created resource data node can be:
+ - appended to the list of resource data elements of the NameOpNode.
+ In such case NameOpNode must be defined by a the "Name ()" ASL statement
+ and initially contain a "ResourceTemplate ()".
+ - returned through the NewRdNode parameter.
+
+ @ingroup CodeGenApis
+
+ @param [in] IsResourceConsumer ResourceUsage parameter,
+ See ACPI 6.4 spec, s19.6.149 for more.
+ @param [in] IsMinFixed See ACPI 6.4 spec, s19.6.149 for more.
+ @param [in] IsMaxFixed See ACPI 6.4 spec, s19.6.149 for more.
+ @param [in] IsPosDecode Decode parameter,
+ See ACPI 6.4 spec, s19.6.149 for more.
+ @param [in] AddressGranularity See ACPI 6.4 spec, s19.6.149 for more.
+ @param [in] AddressMinimum See ACPI 6.4 spec, s19.6.149 for more.
+ @param [in] AddressMaximum See ACPI 6.4 spec, s19.6.149 for more.
+ @param [in] AddressTranslation See ACPI 6.4 spec, s19.6.149 for more.
+ @param [in] RangeLength See ACPI 6.4 spec, s19.6.149 for more.
+ @param [in] ResourceSourceIndex See ACPI 6.4 spec, s19.6.149 for more.
+ Not supported.
+ @param [in] ResourceSource See ACPI 6.4 spec, s19.6.149 for more.
+ Not supported.
+ @param [in] NameOpNode NameOp object node defining a named object.
+ If provided, append the new resource data
+ node to the list of resource data elements
+ of this node.
+ @param [out] NewRdNode If provided and success,
+ contain the created node.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
+**/
+EFI_STATUS
+EFIAPI
+AmlCodeGenRdWordBusNumber (
+ IN BOOLEAN IsResourceConsumer,
+ IN BOOLEAN IsMinFixed,
+ IN BOOLEAN IsMaxFixed,
+ IN BOOLEAN IsPosDecode,
+ IN UINT32 AddressGranularity,
+ IN UINT32 AddressMinimum,
+ IN UINT32 AddressMaximum,
+ IN UINT32 AddressTranslation,
+ IN UINT32 RangeLength,
+ IN UINT8 ResourceSourceIndex,
+ IN CONST CHAR8 *ResourceSource,
+ IN AML_OBJECT_NODE_HANDLE NameOpNode, OPTIONAL
+ OUT AML_DATA_NODE_HANDLE *NewRdNode OPTIONAL
+ );
+
+/** Code generation for the "QWordMemory ()" ASL function.
+
+ The Resource Data effectively created is an Extended Interrupt Resource
+ Data. Cf ACPI 6.4:
+ - s6.4.3.5.1 "QWord Address Space Descriptor".
+ - s19.6.110 "QWordMemory".
+
+ The created resource data node can be:
+ - appended to the list of resource data elements of the NameOpNode.
+ In such case NameOpNode must be defined by a the "Name ()" ASL statement
+ and initially contain a "ResourceTemplate ()".
+ - returned through the NewRdNode parameter.
+
+ @ingroup CodeGenApis
+
+ @param [in] IsResourceConsumer ResourceUsage parameter,
+ See ACPI 6.4 spec, s19.6.110 for more.
+ @param [in] IsPosDecode Decode parameter,
+ See ACPI 6.4 spec, s19.6.110 for more.
+ @param [in] IsMinFixed See ACPI 6.4 spec, s19.6.110 for more.
+ @param [in] IsMaxFixed See ACPI 6.4 spec, s19.6.110 for more.
+ @param [in] Cacheable Available values are:
+ 0-The memory is non-cacheable
+ 1-The memory is cacheable
+ 2-The memory is cacheable and supports
+ write combining
+ 3-The memory is cacheable and prefetchable
+ @param [in] IsReadWrite ReadAndWrite parameter,
+ See ACPI 6.4 spec, s19.6.110 for more.
+ @param [in] AddressGranularity See ACPI 6.4 spec, s19.6.110 for more.
+ @param [in] AddressMinimum See ACPI 6.4 spec, s19.6.110 for more.
+ @param [in] AddressMaximum See ACPI 6.4 spec, s19.6.110 for more.
+ @param [in] AddressTranslation See ACPI 6.4 spec, s19.6.110 for more.
+ @param [in] RangeLength See ACPI 6.4 spec, s19.6.110 for more.
+ @param [in] ResourceSourceIndex See ACPI 6.4 spec, s19.6.110 for more.
+ Not supported.
+ @param [in] ResourceSource See ACPI 6.4 spec, s19.6.110 for more.
+ Not supported.
+ @param [in] MemoryRangeType Available values are:
+ 0-AddressRangeMemory
+ 1-AddressRangeReserved
+ 2-AddressRangeACPI
+ 3-AddressRangeNVS
+ See ACPI 6.4 spec, s19.6.110 for more.
+ @param [in] IsTypeStatic TranslationType parameter,
+ See ACPI 6.4 spec, s19.6.110 for more.
+ @param [in] NameOpNode NameOp object node defining a named object.
+ If provided, append the new resource data
+ node to the list of resource data elements
+ of this node.
+ @param [out] NewRdNode If provided and success,
+ contain the created node.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
+**/
+EFI_STATUS
+EFIAPI
+AmlCodeGenRdQWordMemory (
+ IN BOOLEAN IsResourceConsumer,
+ IN BOOLEAN IsPosDecode,
+ IN BOOLEAN IsMinFixed,
+ IN BOOLEAN IsMaxFixed,
+ IN UINT8 Cacheable,
+ IN BOOLEAN IsReadWrite,
+ IN UINT64 AddressGranularity,
+ IN UINT64 AddressMinimum,
+ IN UINT64 AddressMaximum,
+ IN UINT64 AddressTranslation,
+ IN UINT64 RangeLength,
+ IN UINT8 ResourceSourceIndex,
+ IN CONST CHAR8 *ResourceSource,
+ IN UINT8 MemoryRangeType,
+ IN BOOLEAN IsTypeStatic,
+ IN AML_OBJECT_NODE_HANDLE NameOpNode, OPTIONAL
+ OUT AML_DATA_NODE_HANDLE *NewRdNode OPTIONAL
+ );
+
/** Code generation for the "Interrupt ()" ASL function.

The Resource Data effectively created is an Extended Interrupt Resource
diff --git a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlResourceDataCodeGen.c b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlResourceDataCodeGen.c
index 78910cc5d4b4..3ab78d4fce22 100644
--- a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlResourceDataCodeGen.c
+++ b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlResourceDataCodeGen.c
@@ -94,6 +94,951 @@ error_handler:
return Status;
}

+/** Populate the TypeSpecificFlags field for IO ranges.
+
+ @param [in] IsaRanges Available values are:
+ 0-Reserved
+ 1-NonISAOnly
+ 2-ISAOnly
+ 3-EntireRange
+ See ACPI 6.4 spec, s19.6.34 for more.
+ @param [in] IsDenseTranslation TranslationDensity parameter,
+ See ACPI 6.4 spec, s19.6.34 for more.
+ @param [in] IsTypeStatic TranslationType parameter,
+ See ACPI 6.4 spec, s19.6.34 for more.
+
+ @return A TypeSpecificFlagsvalue.
+ MAX_UINT8 if error.
+**/
+STATIC
+UINT8
+EFIAPI
+RdIoRangeSpecificFlags (
+ IN UINT8 IsaRanges,
+ IN BOOLEAN IsDenseTranslation,
+ IN BOOLEAN IsTypeStatic
+ )
+{
+ // Only check type specific parameters.
+ if (IsaRanges > 3) {
+ ASSERT (0);
+ return MAX_UINT8;
+ }
+
+ // Populate TypeSpecificFlags and call the generic function.
+ // Cf ACPI 6.4 specification, Table 6.50:
+ // "Table 6.50: I/O Resource Flag (Resource Type = 1) Definitions"
+ return IsaRanges |
+ (IsTypeStatic ? 0 : BIT4) |
+ (IsDenseTranslation ? 0 : BIT5);
+}
+
+/** Populate the TypeSpecificFlags field for Memory ranges.
+
+ @param [in] Cacheable Available values are:
+ 0-The memory is non-cacheable
+ 1-The memory is cacheable
+ 2-The memory is cacheable and supports
+ write combining
+ 3-The memory is cacheable and prefetchable
+ @param [in] IsReadWrite ReadAndWrite parameter,
+ See ACPI 6.4 spec, s19.6.35 for more.
+ @param [in] MemoryRangeType Available values are:
+ 0-AddressRangeMemory
+ 1-AddressRangeReserved
+ 2-AddressRangeACPI
+ 3-AddressRangeNVS
+ See ACPI 6.4 spec, s19.6.35 for more.
+ @param [in] IsTypeStatic TranslationType parameter,
+ See ACPI 6.4 spec, s19.6.35 for more.
+
+ @return A TypeSpecificFlagsvalue.
+ MAX_UINT8 if error.
+**/
+STATIC
+UINT8
+EFIAPI
+MemoryRangeSpecificFlags (
+ IN UINT8 Cacheable,
+ IN BOOLEAN IsReadWrite,
+ IN UINT8 MemoryRangeType,
+ IN BOOLEAN IsTypeStatic
+ )
+{
+ // Only check type specific parameters.
+ if ((Cacheable > 3) ||
+ (MemoryRangeType > 3)) {
+ ASSERT (0);
+ return MAX_UINT8;
+ }
+
+ // Populate TypeSpecificFlags and call the generic function.
+ // Cf ACPI 6.4 specification, Table 6.49:
+ // "Memory Resource Flag (Resource Type = 0) Definitions"
+ return (IsReadWrite ? BIT0 : 0) |
+ (Cacheable << 1) |
+ (MemoryRangeType << 3) |
+ (IsTypeStatic ? 0 : BIT5);
+}
+
+/** Populate the GeneralFlags field of any Address Space Resource Descriptors.
+
+ E.g.:
+ ACPI 6.4 specification, s6.4.3.5.1 "QWord Address Space Descriptor"
+ for QWord
+
+ @param [in] IsPosDecode Decode parameter,
+ See ACPI 6.4 spec, s19.6.36 for more.
+ @param [in] IsMinFixed See ACPI 6.4 spec, s19.6.36 for more.
+ @param [in] IsMaxFixed See ACPI 6.4 spec, s19.6.36 for more.
+
+ @return A TypeSpecificFlagsvalue.
+**/
+STATIC
+UINT8
+EFIAPI
+AddressSpaceGeneralFlags (
+ IN BOOLEAN IsPosDecode,
+ IN BOOLEAN IsMinFixed,
+ IN BOOLEAN IsMaxFixed
+ )
+{
+ return (IsPosDecode ? 0 : BIT1) |
+ (IsMinFixed ? BIT2 : 0) |
+ (IsMaxFixed ? BIT3 : 0);
+}
+
+/** Check Address Space Descriptor Fields.
+
+ Cf. ACPI 6.4 Table 6.44:
+ "Valid Combination of Address Space Descriptor Fields"
+
+ @param [in] IsMinFixed See ACPI 6.4 spec, s19.6.36 for more.
+ @param [in] IsMaxFixed See ACPI 6.4 spec, s19.6.36 for more.
+ @param [in] AddressGranularity See ACPI 6.4 spec, s19.6.36 for more.
+ @param [in] AddressMinimum See ACPI 6.4 spec, s19.6.36 for more.
+ @param [in] AddressMaximum See ACPI 6.4 spec, s19.6.36 for more.
+ @param [in] AddressTranslation See ACPI 6.4 spec, s19.6.36 for more.
+ @param [in] RangeLength See ACPI 6.4 spec, s19.6.36 for more.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+CheckAddressSpaceFields (
+ IN BOOLEAN IsMinFixed,
+ IN BOOLEAN IsMaxFixed,
+ IN UINT64 AddressGranularity,
+ IN UINT64 AddressMinimum,
+ IN UINT64 AddressMaximum,
+ IN UINT64 AddressTranslation,
+ IN UINT64 RangeLength
+ )
+{
+ if ((AddressMinimum > AddressMaximum) ||
+ (RangeLength > (AddressMaximum - AddressMinimum + 1)) ||
+ ((AddressGranularity != 0) &&
+ ((AddressGranularity + 1) & AddressGranularity) != 0)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (RangeLength != 0) {
+ if (IsMinFixed ^ IsMaxFixed) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ } else if (IsMinFixed &&
+ IsMaxFixed &&
+ (AddressGranularity != 0) &&
+ ((AddressMaximum - AddressMinimum + 1) != RangeLength)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+ } else {
+ if (IsMinFixed && IsMaxFixed) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ } else if (IsMinFixed &&
+ ((AddressMinimum & AddressGranularity) != 0)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ } else if (IsMaxFixed &&
+ (((AddressMaximum + 1) & AddressGranularity) != 0)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/** Code generation for the "DWordSpace ()" ASL function.
+
+ The Resource Data effectively created is an Extended Interrupt Resource
+ Data. Cf ACPI 6.4:
+ - s6.4.3.5.2 "DWord Address Space Descriptor".
+ - s19.6.36 "DWordSpace".
+
+ The created resource data node can be:
+ - appended to the list of resource data elements of the NameOpNode.
+ In such case NameOpNode must be defined by a the "Name ()" ASL statement
+ and initially contain a "ResourceTemplate ()".
+ - returned through the NewRdNode parameter.
+
+ @param [in] ResourceType See ACPI 6.4 spec, s6.4.3.5.2 for more.
+ Available values are:
+ 0: Memory range
+ 1: I/O range
+ 2: Bus number range
+ 3-191: Reserved
+ 192-255: Hardware Vendor Defined
+ @param [in] IsResourceConsumer ResourceUsage parameter,
+ See ACPI 6.4 spec, s19.6.36 for more.
+ @param [in] IsPosDecode Decode parameter,
+ See ACPI 6.4 spec, s19.6.36 for more.
+ @param [in] IsMinFixed See ACPI 6.4 spec, s19.6.36 for more.
+ @param [in] IsMaxFixed See ACPI 6.4 spec, s19.6.36 for more.
+ @param [in] TypeSpecificFlags See ACPI 6.4 spec, s6.4.3.5.5
+ "Resource Type Specific Flags".
+ @param [in] AddressGranularity See ACPI 6.4 spec, s19.6.36 for more.
+ @param [in] AddressMinimum See ACPI 6.4 spec, s19.6.36 for more.
+ @param [in] AddressMaximum See ACPI 6.4 spec, s19.6.36 for more.
+ @param [in] AddressTranslation See ACPI 6.4 spec, s19.6.36 for more.
+ @param [in] RangeLength See ACPI 6.4 spec, s19.6.36 for more.
+ @param [in] ResourceSourceIndex See ACPI 6.4 spec, s19.6.36 for more.
+ Not supported.
+ @param [in] ResourceSource See ACPI 6.4 spec, s19.6.36 for more.
+ Not supported.
+ @param [in] NameOpNode NameOp object node defining a named object.
+ If provided, append the new resource data
+ node to the list of resource data elements
+ of this node.
+ @param [out] NewRdNode If provided and success,
+ contain the created node.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+AmlCodeGenRdDWordSpace (
+ IN UINT8 ResourceType,
+ IN BOOLEAN IsResourceConsumer,
+ IN BOOLEAN IsPosDecode,
+ IN BOOLEAN IsMinFixed,
+ IN BOOLEAN IsMaxFixed,
+ IN UINT8 TypeSpecificFlags,
+ IN UINT32 AddressGranularity,
+ IN UINT32 AddressMinimum,
+ IN UINT32 AddressMaximum,
+ IN UINT32 AddressTranslation,
+ IN UINT32 RangeLength,
+ IN UINT8 ResourceSourceIndex,
+ IN CONST CHAR8 *ResourceSource,
+ IN AML_OBJECT_NODE_HANDLE NameOpNode, OPTIONAL
+ OUT AML_DATA_NODE_HANDLE *NewRdNode OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ AML_DATA_NODE * RdNode;
+ EFI_ACPI_DWORD_ADDRESS_SPACE_DESCRIPTOR RdDWord;
+
+ // ResourceSource and ResourceSourceIndex are not supported.
+ if ((TypeSpecificFlags == MAX_UINT8) ||
+ (ResourceSourceIndex != 0) ||
+ (ResourceSource != NULL) ||
+ ((NameOpNode == NULL) && (NewRdNode == NULL))) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = CheckAddressSpaceFields (
+ IsMinFixed,
+ IsMaxFixed,
+ AddressGranularity,
+ AddressMinimum,
+ AddressMaximum,
+ AddressTranslation,
+ RangeLength
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Header
+ RdDWord.Header.Header.Bits.Name =
+ ACPI_LARGE_DWORD_ADDRESS_SPACE_DESCRIPTOR_NAME;
+ RdDWord.Header.Header.Bits.Type = ACPI_LARGE_ITEM_FLAG;
+ RdDWord.Header.Length = sizeof (EFI_ACPI_DWORD_ADDRESS_SPACE_DESCRIPTOR) -
+ sizeof (ACPI_LARGE_RESOURCE_HEADER);
+
+ // Body
+ RdDWord.ResType = ResourceType;
+ RdDWord.GenFlag = AddressSpaceGeneralFlags (
+ IsPosDecode,
+ IsMinFixed,
+ IsMaxFixed
+ );
+ RdDWord.SpecificFlag = TypeSpecificFlags;
+ RdDWord.AddrSpaceGranularity = AddressGranularity;
+ RdDWord.AddrRangeMin = AddressMinimum;
+ RdDWord.AddrRangeMax = AddressMaximum;
+ RdDWord.AddrTranslationOffset = AddressTranslation;
+ RdDWord.AddrLen = RangeLength;
+
+ Status = AmlCreateDataNode (
+ EAmlNodeDataTypeResourceData,
+ (UINT8*)&RdDWord,
+ sizeof (EFI_ACPI_DWORD_ADDRESS_SPACE_DESCRIPTOR),
+ &RdNode
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ return LinkRdNode (RdNode, NameOpNode, NewRdNode);
+}
+
+/** Code generation for the "DWordIO ()" ASL function.
+
+ The Resource Data effectively created is an Extended Interrupt Resource
+ Data. Cf ACPI 6.4:
+ - s6.4.3.5.2 "DWord Address Space Descriptor".
+ - s19.6.34 "DWordIO".
+
+ The created resource data node can be:
+ - appended to the list of resource data elements of the NameOpNode.
+ In such case NameOpNode must be defined by a the "Name ()" ASL statement
+ and initially contain a "ResourceTemplate ()".
+ - returned through the NewRdNode parameter.
+
+ @param [in] IsResourceConsumer ResourceUsage parameter,
+ See ACPI 6.4 spec, s19.6.34 for more.
+ @param [in] IsMinFixed See ACPI 6.4 spec, s19.6.34 for more.
+ @param [in] IsMaxFixed See ACPI 6.4 spec, s19.6.34 for more.
+ @param [in] IsPosDecode Decode parameter,
+ See ACPI 6.4 spec, s19.6.34 for more.
+ @param [in] IsaRanges Available values are:
+ 0-Reserved
+ 1-NonISAOnly
+ 2-ISAOnly
+ 3-EntireRange
+ See ACPI 6.4 spec, s19.6.34 for more.
+ @param [in] AddressGranularity See ACPI 6.4 spec, s19.6.34 for more.
+ @param [in] AddressMinimum See ACPI 6.4 spec, s19.6.34 for more.
+ @param [in] AddressMaximum See ACPI 6.4 spec, s19.6.34 for more.
+ @param [in] AddressTranslation See ACPI 6.4 spec, s19.6.34 for more.
+ @param [in] RangeLength See ACPI 6.4 spec, s19.6.34 for more.
+ @param [in] ResourceSourceIndex See ACPI 6.4 spec, s19.6.34 for more.
+ Not supported.
+ @param [in] ResourceSource See ACPI 6.4 spec, s19.6.34 for more.
+ Not supported.
+ @param [in] IsDenseTranslation TranslationDensity parameter,
+ See ACPI 6.4 spec, s19.6.34 for more.
+ @param [in] IsTypeStatic TranslationType parameter,
+ See ACPI 6.4 spec, s19.6.34 for more.
+ @param [in] NameOpNode NameOp object node defining a named object.
+ If provided, append the new resource data
+ node to the list of resource data elements
+ of this node.
+ @param [out] NewRdNode If provided and success,
+ contain the created node.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
+**/
+EFI_STATUS
+EFIAPI
+AmlCodeGenRdDWordIo (
+ IN BOOLEAN IsResourceConsumer,
+ IN BOOLEAN IsMinFixed,
+ IN BOOLEAN IsMaxFixed,
+ IN BOOLEAN IsPosDecode,
+ IN UINT8 IsaRanges,
+ IN UINT32 AddressGranularity,
+ IN UINT32 AddressMinimum,
+ IN UINT32 AddressMaximum,
+ IN UINT32 AddressTranslation,
+ IN UINT32 RangeLength,
+ IN UINT8 ResourceSourceIndex,
+ IN CONST CHAR8 *ResourceSource,
+ IN BOOLEAN IsDenseTranslation,
+ IN BOOLEAN IsTypeStatic,
+ IN AML_OBJECT_NODE_HANDLE NameOpNode, OPTIONAL
+ OUT AML_DATA_NODE_HANDLE *NewRdNode OPTIONAL
+ )
+{
+ return AmlCodeGenRdDWordSpace (
+ ACPI_ADDRESS_SPACE_TYPE_IO,
+ IsResourceConsumer,
+ IsPosDecode,
+ IsMinFixed,
+ IsMaxFixed,
+ RdIoRangeSpecificFlags (
+ IsaRanges,
+ IsDenseTranslation,
+ IsTypeStatic
+ ),
+ AddressGranularity,
+ AddressMinimum,
+ AddressMaximum,
+ AddressTranslation,
+ RangeLength,
+ ResourceSourceIndex,
+ ResourceSource,
+ NameOpNode,
+ NewRdNode
+ );
+}
+
+/** Code generation for the "DWordMemory ()" ASL function.
+
+ The Resource Data effectively created is an Extended Interrupt Resource
+ Data. Cf ACPI 6.4:
+ - s6.4.3.5.2 "DWord Address Space Descriptor".
+ - s19.6.35 "DWordMemory".
+
+ The created resource data node can be:
+ - appended to the list of resource data elements of the NameOpNode.
+ In such case NameOpNode must be defined by a the "Name ()" ASL statement
+ and initially contain a "ResourceTemplate ()".
+ - returned through the NewRdNode parameter.
+
+ @param [in] IsResourceConsumer ResourceUsage parameter,
+ See ACPI 6.4 spec, s19.6.35 for more.
+ @param [in] IsPosDecode Decode parameter,
+ See ACPI 6.4 spec, s19.6.35 for more.
+ @param [in] IsMinFixed See ACPI 6.4 spec, s19.6.35 for more.
+ @param [in] IsMaxFixed See ACPI 6.4 spec, s19.6.35 for more.
+ @param [in] Cacheable Available values are:
+ 0-The memory is non-cacheable
+ 1-The memory is cacheable
+ 2-The memory is cacheable and supports
+ write combining
+ 3-The memory is cacheable and prefetchable
+ @param [in] IsReadWrite ReadAndWrite parameter,
+ See ACPI 6.4 spec, s19.6.35 for more.
+ @param [in] AddressGranularity See ACPI 6.4 spec, s19.6.35 for more.
+ @param [in] AddressMinimum See ACPI 6.4 spec, s19.6.35 for more.
+ @param [in] AddressMaximum See ACPI 6.4 spec, s19.6.35 for more.
+ @param [in] AddressTranslation See ACPI 6.4 spec, s19.6.35 for more.
+ @param [in] RangeLength See ACPI 6.4 spec, s19.6.35 for more.
+ @param [in] ResourceSourceIndex See ACPI 6.4 spec, s19.6.35 for more.
+ Not supported.
+ @param [in] ResourceSource See ACPI 6.4 spec, s19.6.35 for more.
+ Not supported.
+ @param [in] MemoryRangeType Available values are:
+ 0-AddressRangeMemory
+ 1-AddressRangeReserved
+ 2-AddressRangeACPI
+ 3-AddressRangeNVS
+ See ACPI 6.4 spec, s19.6.35 for more.
+ @param [in] IsTypeStatic TranslationType parameter,
+ See ACPI 6.4 spec, s19.6.35 for more.
+ @param [in] NameOpNode NameOp object node defining a named object.
+ If provided, append the new resource data
+ node to the list of resource data elements
+ of this node.
+ @param [out] NewRdNode If provided and success,
+ contain the created node.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
+**/
+EFI_STATUS
+EFIAPI
+AmlCodeGenRdDWordMemory (
+ IN BOOLEAN IsResourceConsumer,
+ IN BOOLEAN IsPosDecode,
+ IN BOOLEAN IsMinFixed,
+ IN BOOLEAN IsMaxFixed,
+ IN UINT8 Cacheable,
+ IN BOOLEAN IsReadWrite,
+ IN UINT32 AddressGranularity,
+ IN UINT32 AddressMinimum,
+ IN UINT32 AddressMaximum,
+ IN UINT32 AddressTranslation,
+ IN UINT32 RangeLength,
+ IN UINT8 ResourceSourceIndex,
+ IN CONST CHAR8 *ResourceSource,
+ IN UINT8 MemoryRangeType,
+ IN BOOLEAN IsTypeStatic,
+ IN AML_OBJECT_NODE_HANDLE NameOpNode, OPTIONAL
+ OUT AML_DATA_NODE_HANDLE *NewRdNode OPTIONAL
+ )
+{
+ return AmlCodeGenRdDWordSpace (
+ ACPI_ADDRESS_SPACE_TYPE_MEM,
+ IsResourceConsumer,
+ IsPosDecode,
+ IsMinFixed,
+ IsMaxFixed,
+ MemoryRangeSpecificFlags (
+ Cacheable,
+ IsReadWrite,
+ MemoryRangeType,
+ IsTypeStatic
+ ),
+ AddressGranularity,
+ AddressMinimum,
+ AddressMaximum,
+ AddressTranslation,
+ RangeLength,
+ ResourceSourceIndex,
+ ResourceSource,
+ NameOpNode,
+ NewRdNode
+ );
+}
+
+/** Code generation for the "WordSpace ()" ASL function.
+
+ The Resource Data effectively created is an Extended Interrupt Resource
+ Data. Cf ACPI 6.4:
+ - s6.4.3.5.3 "Word Address Space Descriptor".
+ - s19.6.151 "WordSpace".
+
+ The created resource data node can be:
+ - appended to the list of resource data elements of the NameOpNode.
+ In such case NameOpNode must be defined by a the "Name ()" ASL statement
+ and initially contain a "ResourceTemplate ()".
+ - returned through the NewRdNode parameter.
+
+ @param [in] ResourceType See ACPI 6.4 spec, s6.4.3.5.3 for more.
+ Available values are:
+ 0: Memory range
+ 1: I/O range
+ 2: Bus number range
+ 3-191: Reserved
+ 192-255: Hardware Vendor Defined
+ @param [in] IsResourceConsumer ResourceUsage parameter,
+ See ACPI 6.4 spec, s19.6.151 for more.
+ @param [in] IsPosDecode Decode parameter,
+ See ACPI 6.4 spec, s19.6.151 for more.
+ @param [in] IsMinFixed See ACPI 6.4 spec, s19.6.151 for more.
+ @param [in] IsMaxFixed See ACPI 6.4 spec, s19.6.151 for more.
+ @param [in] TypeSpecificFlags See ACPI 6.4 spec, s6.4.3.5.5
+ "Resource Type Specific Flags".
+ @param [in] AddressGranularity See ACPI 6.4 spec, s19.6.151 for more.
+ @param [in] AddressMinimum See ACPI 6.4 spec, s19.6.151 for more.
+ @param [in] AddressMaximum See ACPI 6.4 spec, s19.6.151 for more.
+ @param [in] AddressTranslation See ACPI 6.4 spec, s19.6.151 for more.
+ @param [in] RangeLength See ACPI 6.4 spec, s19.6.151 for more.
+ @param [in] ResourceSourceIndex See ACPI 6.4 spec, s19.6.151 for more.
+ Not supported.
+ @param [in] ResourceSource See ACPI 6.4 spec, s19.6.151 for more.
+ Not supported.
+ @param [in] NameOpNode NameOp object node defining a named object.
+ If provided, append the new resource data
+ node to the list of resource data elements
+ of this node.
+ @param [out] NewRdNode If provided and success,
+ contain the created node.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+AmlCodeGenRdWordSpace (
+ IN UINT8 ResourceType,
+ IN BOOLEAN IsResourceConsumer,
+ IN BOOLEAN IsPosDecode,
+ IN BOOLEAN IsMinFixed,
+ IN BOOLEAN IsMaxFixed,
+ IN UINT8 TypeSpecificFlags,
+ IN UINT16 AddressGranularity,
+ IN UINT16 AddressMinimum,
+ IN UINT16 AddressMaximum,
+ IN UINT16 AddressTranslation,
+ IN UINT16 RangeLength,
+ IN UINT8 ResourceSourceIndex,
+ IN CONST CHAR8 *ResourceSource,
+ IN AML_OBJECT_NODE_HANDLE NameOpNode, OPTIONAL
+ OUT AML_DATA_NODE_HANDLE *NewRdNode OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ AML_DATA_NODE * RdNode;
+ EFI_ACPI_WORD_ADDRESS_SPACE_DESCRIPTOR Rdword;
+
+ // ResourceSource and ResourceSourceIndex are not supported.
+ if ((TypeSpecificFlags == MAX_UINT8) ||
+ (ResourceSourceIndex != 0) ||
+ (ResourceSource != NULL) ||
+ ((NameOpNode == NULL) && (NewRdNode == NULL))) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = CheckAddressSpaceFields (
+ IsMinFixed,
+ IsMaxFixed,
+ AddressGranularity,
+ AddressMinimum,
+ AddressMaximum,
+ AddressTranslation,
+ RangeLength
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Header
+ Rdword.Header.Header.Bits.Name =
+ ACPI_LARGE_WORD_ADDRESS_SPACE_DESCRIPTOR_NAME;
+ Rdword.Header.Header.Bits.Type = ACPI_LARGE_ITEM_FLAG;
+ Rdword.Header.Length = sizeof (EFI_ACPI_WORD_ADDRESS_SPACE_DESCRIPTOR) -
+ sizeof (ACPI_LARGE_RESOURCE_HEADER);
+
+ // Body
+ Rdword.ResType = ResourceType;
+ Rdword.GenFlag = AddressSpaceGeneralFlags (
+ IsPosDecode,
+ IsMinFixed,
+ IsMaxFixed
+ );
+ Rdword.SpecificFlag = TypeSpecificFlags;
+ Rdword.AddrSpaceGranularity = AddressGranularity;
+ Rdword.AddrRangeMin = AddressMinimum;
+ Rdword.AddrRangeMax = AddressMaximum;
+ Rdword.AddrTranslationOffset = AddressTranslation;
+ Rdword.AddrLen = RangeLength;
+
+ Status = AmlCreateDataNode (
+ EAmlNodeDataTypeResourceData,
+ (UINT8*)&Rdword,
+ sizeof (EFI_ACPI_WORD_ADDRESS_SPACE_DESCRIPTOR),
+ &RdNode
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ return LinkRdNode (RdNode, NameOpNode, NewRdNode);
+}
+
+/** Code generation for the "WordBusNumber ()" ASL function.
+
+ The Resource Data effectively created is an Extended Interrupt Resource
+ Data. Cf ACPI 6.4:
+ - s6.4.3.5.3 "Word Address Space Descriptor".
+ - s19.6.149 "WordBusNumber".
+
+ The created resource data node can be:
+ - appended to the list of resource data elements of the NameOpNode.
+ In such case NameOpNode must be defined by a the "Name ()" ASL statement
+ and initially contain a "ResourceTemplate ()".
+ - returned through the NewRdNode parameter.
+
+ @param [in] IsResourceConsumer ResourceUsage parameter,
+ See ACPI 6.4 spec, s19.6.149 for more.
+ @param [in] IsMinFixed See ACPI 6.4 spec, s19.6.149 for more.
+ @param [in] IsMaxFixed See ACPI 6.4 spec, s19.6.149 for more.
+ @param [in] IsPosDecode Decode parameter,
+ See ACPI 6.4 spec, s19.6.149 for more.
+ @param [in] AddressGranularity See ACPI 6.4 spec, s19.6.149 for more.
+ @param [in] AddressMinimum See ACPI 6.4 spec, s19.6.149 for more.
+ @param [in] AddressMaximum See ACPI 6.4 spec, s19.6.149 for more.
+ @param [in] AddressTranslation See ACPI 6.4 spec, s19.6.149 for more.
+ @param [in] RangeLength See ACPI 6.4 spec, s19.6.149 for more.
+ @param [in] ResourceSourceIndex See ACPI 6.4 spec, s19.6.149 for more.
+ Not supported.
+ @param [in] ResourceSource See ACPI 6.4 spec, s19.6.149 for more.
+ Not supported.
+ @param [in] NameOpNode NameOp object node defining a named object.
+ If provided, append the new resource data
+ node to the list of resource data elements
+ of this node.
+ @param [out] NewRdNode If provided and success,
+ contain the created node.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
+**/
+EFI_STATUS
+EFIAPI
+AmlCodeGenRdWordBusNumber (
+ IN BOOLEAN IsResourceConsumer,
+ IN BOOLEAN IsMinFixed,
+ IN BOOLEAN IsMaxFixed,
+ IN BOOLEAN IsPosDecode,
+ IN UINT32 AddressGranularity,
+ IN UINT32 AddressMinimum,
+ IN UINT32 AddressMaximum,
+ IN UINT32 AddressTranslation,
+ IN UINT32 RangeLength,
+ IN UINT8 ResourceSourceIndex,
+ IN CONST CHAR8 *ResourceSource,
+ IN AML_OBJECT_NODE_HANDLE NameOpNode, OPTIONAL
+ OUT AML_DATA_NODE_HANDLE *NewRdNode OPTIONAL
+ )
+{
+ // There is no Type Specific Flags for buses.
+ return AmlCodeGenRdWordSpace (
+ ACPI_ADDRESS_SPACE_TYPE_BUS,
+ IsResourceConsumer,
+ IsPosDecode,
+ IsMinFixed,
+ IsMaxFixed,
+ 0,
+ AddressGranularity,
+ AddressMinimum,
+ AddressMaximum,
+ AddressTranslation,
+ RangeLength,
+ ResourceSourceIndex,
+ ResourceSource,
+ NameOpNode,
+ NewRdNode
+ );
+}
+
+/** Code generation for the "QWordSpace ()" ASL function.
+
+ The Resource Data effectively created is an Extended Interrupt Resource
+ Data. Cf ACPI 6.4:
+ - s6.4.3.5.1 "QWord Address Space Descriptor".
+ - s19.6.111 "QWordSpace".
+
+ The created resource data node can be:
+ - appended to the list of resource data elements of the NameOpNode.
+ In such case NameOpNode must be defined by a the "Name ()" ASL statement
+ and initially contain a "ResourceTemplate ()".
+ - returned through the NewRdNode parameter.
+
+ @param [in] ResourceType See ACPI 6.4 spec, s6.4.3.5.1 for more.
+ Available values are:
+ 0: Memory range
+ 1: I/O range
+ 2: Bus number range
+ 3-191: Reserved
+ 192-255: Hardware Vendor Defined
+ @param [in] IsResourceConsumer ResourceUsage parameter,
+ See ACPI 6.4 spec, s19.6.111 for more.
+ @param [in] IsPosDecode Decode parameter,
+ See ACPI 6.4 spec, s19.6.111 for more.
+ @param [in] IsMinFixed See ACPI 6.4 spec, s19.6.111 for more.
+ @param [in] IsMaxFixed See ACPI 6.4 spec, s19.6.111 for more.
+ @param [in] TypeSpecificFlags See ACPI 6.4 spec, s6.4.3.5.5
+ "Resource Type Specific Flags".
+ @param [in] AddressGranularity See ACPI 6.4 spec, s19.6.111 for more.
+ @param [in] AddressMinimum See ACPI 6.4 spec, s19.6.111 for more.
+ @param [in] AddressMaximum See ACPI 6.4 spec, s19.6.111 for more.
+ @param [in] AddressTranslation See ACPI 6.4 spec, s19.6.111 for more.
+ @param [in] RangeLength See ACPI 6.4 spec, s19.6.111 for more.
+ @param [in] ResourceSourceIndex See ACPI 6.4 spec, s19.6.111 for more.
+ Not supported.
+ @param [in] ResourceSource See ACPI 6.4 spec, s19.6.111 for more.
+ Not supported.
+ @param [in] NameOpNode NameOp object node defining a named object.
+ If provided, append the new resource data
+ node to the list of resource data elements
+ of this node.
+ @param [out] NewRdNode If provided and success,
+ contain the created node.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+AmlCodeGenRdQWordSpace (
+ IN UINT8 ResourceType,
+ IN BOOLEAN IsResourceConsumer,
+ IN BOOLEAN IsPosDecode,
+ IN BOOLEAN IsMinFixed,
+ IN BOOLEAN IsMaxFixed,
+ IN UINT8 TypeSpecificFlags,
+ IN UINT64 AddressGranularity,
+ IN UINT64 AddressMinimum,
+ IN UINT64 AddressMaximum,
+ IN UINT64 AddressTranslation,
+ IN UINT64 RangeLength,
+ IN UINT8 ResourceSourceIndex,
+ IN CONST CHAR8 *ResourceSource,
+ IN AML_OBJECT_NODE_HANDLE NameOpNode, OPTIONAL
+ OUT AML_DATA_NODE_HANDLE *NewRdNode OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ AML_DATA_NODE * RdNode;
+ EFI_ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR RdQword;
+
+ // ResourceSource and ResourceSourceIndex are not supported.
+ if ((TypeSpecificFlags == MAX_UINT8) ||
+ (ResourceSourceIndex != 0) ||
+ (ResourceSource != NULL) ||
+ ((NameOpNode == NULL) && (NewRdNode == NULL))) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = CheckAddressSpaceFields (
+ IsMinFixed,
+ IsMaxFixed,
+ AddressGranularity,
+ AddressMinimum,
+ AddressMaximum,
+ AddressTranslation,
+ RangeLength
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Header
+ RdQword.Header.Header.Bits.Name =
+ ACPI_LARGE_QWORD_ADDRESS_SPACE_DESCRIPTOR_NAME;
+ RdQword.Header.Header.Bits.Type = ACPI_LARGE_ITEM_FLAG;
+ RdQword.Header.Length = sizeof (EFI_ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR) -
+ sizeof (ACPI_LARGE_RESOURCE_HEADER);
+
+ // Body
+ RdQword.ResType = ResourceType;
+ RdQword.GenFlag = AddressSpaceGeneralFlags (
+ IsPosDecode,
+ IsMinFixed,
+ IsMaxFixed
+ );
+ RdQword.SpecificFlag = TypeSpecificFlags;
+ RdQword.AddrSpaceGranularity = AddressGranularity;
+ RdQword.AddrRangeMin = AddressMinimum;
+ RdQword.AddrRangeMax = AddressMaximum;
+ RdQword.AddrTranslationOffset = AddressTranslation;
+ RdQword.AddrLen = RangeLength;
+
+ Status = AmlCreateDataNode (
+ EAmlNodeDataTypeResourceData,
+ (UINT8*)&RdQword,
+ sizeof (EFI_ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR),
+ &RdNode
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ return LinkRdNode (RdNode, NameOpNode, NewRdNode);
+}
+
+/** Code generation for the "QWordMemory ()" ASL function.
+
+ The Resource Data effectively created is an Extended Interrupt Resource
+ Data. Cf ACPI 6.4:
+ - s6.4.3.5.1 "QWord Address Space Descriptor".
+ - s19.6.110 "QWordMemory".
+
+ The created resource data node can be:
+ - appended to the list of resource data elements of the NameOpNode.
+ In such case NameOpNode must be defined by a the "Name ()" ASL statement
+ and initially contain a "ResourceTemplate ()".
+ - returned through the NewRdNode parameter.
+
+ @param [in] IsResourceConsumer ResourceUsage parameter,
+ See ACPI 6.4 spec, s19.6.110 for more.
+ @param [in] IsPosDecode Decode parameter,
+ See ACPI 6.4 spec, s19.6.110 for more.
+ @param [in] IsMinFixed See ACPI 6.4 spec, s19.6.110 for more.
+ @param [in] IsMaxFixed See ACPI 6.4 spec, s19.6.110 for more.
+ @param [in] Cacheable Available values are:
+ 0-The memory is non-cacheable
+ 1-The memory is cacheable
+ 2-The memory is cacheable and supports
+ write combining
+ 3-The memory is cacheable and prefetchable
+ @param [in] IsReadWrite ReadAndWrite parameter,
+ See ACPI 6.4 spec, s19.6.110 for more.
+ @param [in] AddressGranularity See ACPI 6.4 spec, s19.6.110 for more.
+ @param [in] AddressMinimum See ACPI 6.4 spec, s19.6.110 for more.
+ @param [in] AddressMaximum See ACPI 6.4 spec, s19.6.110 for more.
+ @param [in] AddressTranslation See ACPI 6.4 spec, s19.6.110 for more.
+ @param [in] RangeLength See ACPI 6.4 spec, s19.6.110 for more.
+ @param [in] ResourceSourceIndex See ACPI 6.4 spec, s19.6.110 for more.
+ Not supported.
+ @param [in] ResourceSource See ACPI 6.4 spec, s19.6.110 for more.
+ Not supported.
+ @param [in] MemoryRangeType Available values are:
+ 0-AddressRangeMemory
+ 1-AddressRangeReserved
+ 2-AddressRangeACPI
+ 3-AddressRangeNVS
+ See ACPI 6.4 spec, s19.6.110 for more.
+ @param [in] IsTypeStatic TranslationType parameter,
+ See ACPI 6.4 spec, s19.6.110 for more.
+ @param [in] NameOpNode NameOp object node defining a named object.
+ If provided, append the new resource data
+ node to the list of resource data elements
+ of this node.
+ @param [out] NewRdNode If provided and success,
+ contain the created node.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
+**/
+EFI_STATUS
+EFIAPI
+AmlCodeGenRdQWordMemory (
+ IN BOOLEAN IsResourceConsumer,
+ IN BOOLEAN IsPosDecode,
+ IN BOOLEAN IsMinFixed,
+ IN BOOLEAN IsMaxFixed,
+ IN UINT8 Cacheable,
+ IN BOOLEAN IsReadWrite,
+ IN UINT64 AddressGranularity,
+ IN UINT64 AddressMinimum,
+ IN UINT64 AddressMaximum,
+ IN UINT64 AddressTranslation,
+ IN UINT64 RangeLength,
+ IN UINT8 ResourceSourceIndex,
+ IN CONST CHAR8 *ResourceSource,
+ IN UINT8 MemoryRangeType,
+ IN BOOLEAN IsTypeStatic,
+ IN AML_OBJECT_NODE_HANDLE NameOpNode, OPTIONAL
+ OUT AML_DATA_NODE_HANDLE *NewRdNode OPTIONAL
+ )
+{
+ return AmlCodeGenRdQWordSpace (
+ ACPI_ADDRESS_SPACE_TYPE_MEM,
+ IsResourceConsumer,
+ IsPosDecode,
+ IsMinFixed,
+ IsMaxFixed,
+ MemoryRangeSpecificFlags (
+ Cacheable,
+ IsReadWrite,
+ MemoryRangeType,
+ IsTypeStatic
+ ),
+ AddressGranularity,
+ AddressMinimum,
+ AddressMaximum,
+ AddressTranslation,
+ RangeLength,
+ ResourceSourceIndex,
+ ResourceSource,
+ NameOpNode,
+ NewRdNode
+ );
+}
+
/** Code generation for the "Interrupt ()" ASL function.

The Resource Data effectively created is an Extended Interrupt Resource
--
2.17.1


[PATCH v1 0/7] Create a SSDT PCIe generator

PierreGondois
 

From: Pierre Gondois <Pierre.Gondois@...>

As part of the DynamicTablesPkg, add a generator creating a
SSDT table describing a PCIe bus.
This patch-set also adds new functions to generate AML bytecode
in the AmlLib.

The changes can be seen at: https://github.com/PierreARM/edk2/tree/1781_Create_ssdt_pcie_generator_v1
The results of the CI can be seen at: https://github.com/tianocore/edk2/pull/1747

This patch-set is dependent over the following patch-sets:
[PATCH v1 00/10] Various DynamicTablesPkg modifications
https://edk2.groups.io/g/devel/message/76929
and:
[PATCH v1 00/13] Create a SSDT CPU topology generator
https://edk2.groups.io/g/devel/message/76941

Pierre Gondois (7):
DynamicTablesPkg: AML Code generation for memory ranges
DynamicTablesPkg: AML Code generation to create a named Package()
DynamicTablesPkg: AML Code generation to create a named
ResourceTemplate()
DynamicTablesPkg: AML Code generation to add _PRT entries
DynamicTablesPkg: Add AmlAttachNode()
DynamicTablesPkg: Add Pci related objects
DynamicTablesPkg: SSDT Pci express generator

DynamicTablesPkg/DynamicTables.dsc.inc | 2 +
DynamicTablesPkg/Include/AcpiTableGenerator.h | 5 +
.../Include/ArmNameSpaceObjects.h | 78 +
.../Include/Library/AmlLib/AmlLib.h | 430 +++++
.../AcpiSsdtPcieLibArm/SsdtPcieGenerator.c | 1417 +++++++++++++++++
.../AcpiSsdtPcieLibArm/SsdtPcieGenerator.h | 134 ++
.../Arm/AcpiSsdtPcieLibArm/SsdtPcieLibArm.inf | 32 +
.../SsdtPcieOscTemplate.asl | 80 +
.../Library/Common/AmlLib/Api/AmlApi.c | 36 +
.../Common/AmlLib/CodeGen/AmlCodeGen.c | 320 ++++
.../AmlLib/CodeGen/AmlResourceDataCodeGen.c | 945 +++++++++++
.../ConfigurationManagerObjectParser.c | 28 +-
12 files changed, 3506 insertions(+), 1 deletion(-)
create mode 100644 DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieGenerator.c
create mode 100644 DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieGenerator.h
create mode 100644 DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieLibArm.inf
create mode 100644 DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtPcieLibArm/SsdtPcieOscTemplate.asl

--
2.17.1

19641 - 19660 of 96543