public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [PATCH v1 00/13] Create a SSDT CPU topology generator
@ 2021-06-23 11:40 PierreGondois
  2021-06-23 11:40 ` [PATCH v1 01/13] DynamicTablesPkg: Make AmlNodeGetIntegerValue public PierreGondois
                   ` (13 more replies)
  0 siblings, 14 replies; 30+ messages in thread
From: PierreGondois @ 2021-06-23 11:40 UTC (permalink / raw)
  To: devel, Sami Mujawar, Alexei Fedorov; +Cc: Akanksha Jain, Alexandru Elisei

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

As part of the DynamicTablesPkg, add a generator creating a
SSDT table representing a CPU topology. Low Power Idle (LPI)
states can also be generated along the CPUs.
This patch-set also adds new functions to generate AML bytecode.

The changes can be seen at: https://github.com/PierreARM/edk2/tree/1449_Create_ssdt_cpu_topology_generator_v1
The results of the CI can be seen at: https://github.com/tianocore/edk2/pull/1746
This patch-set is dependent over the following patch set:
  [PATCH v1 00/10] Various DynamicTablesPkg modifications 
  https://edk2.groups.io/g/devel/message/76929

Pierre Gondois (13):
  DynamicTablesPkg: Make AmlNodeGetIntegerValue public
  DynamicTablesPkg: AML Code generation for Register()
  DynamicTablesPkg: AML Code generation for Resource data EndTag
  DynamicTablesPkg: AML code generation for a Package
  DynamicTablesPkg: Helper function to compute package length
  DynamicTablesPkg: AML code generation for a ResourceTemplate
  DynamicTablesPkg: AML code generation for a Method
  DynamicTablesPkg: AML code generation to Return a NameString
  DynamicTablesPkg: AML code generation for a Method returning a NS
  DynamicTablesPkg: AML code generation for a _LPI object
  DynamicTablesPkg: AML code generation to add an _LPI state
  DynamicTablesPkg: Add CM_ARM_LPI_INFO object
  DynamicTablesPkg: SSDT CPU topology and LPI state generator

 DynamicTablesPkg/DynamicTables.dsc.inc        |    6 +
 DynamicTablesPkg/Include/AcpiTableGenerator.h |    7 +-
 .../Include/ArmNameSpaceObjects.h             |   68 +
 .../Include/Library/AmlLib/AmlLib.h           |  168 +++
 .../SsdtCpuTopologyGenerator.c                | 1230 ++++++++++++++++
 .../SsdtCpuTopologyGenerator.h                |  134 ++
 .../SsdtCpuTopologyLibArm.inf                 |   40 +
 .../Library/Common/AmlLib/AmlEncoding/Aml.c   |   87 +-
 .../Library/Common/AmlLib/AmlEncoding/Aml.h   |   47 +-
 .../Common/AmlLib/CodeGen/AmlCodeGen.c        | 1296 ++++++++++++++++-
 .../AmlLib/CodeGen/AmlResourceDataCodeGen.c   |  191 +++
 .../AmlLib/CodeGen/AmlResourceDataCodeGen.h   |   83 ++
 .../Library/Common/AmlLib/Utils/AmlUtility.c  |    3 +-
 .../Library/Common/AmlLib/Utils/AmlUtility.h  |   18 +-
 .../ConfigurationManagerObjectParser.c        |   35 +
 15 files changed, 3406 insertions(+), 7 deletions(-)
 create mode 100644 DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCpuTopologyLibArm/SsdtCpuTopologyGenerator.c
 create mode 100644 DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCpuTopologyLibArm/SsdtCpuTopologyGenerator.h
 create mode 100644 DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCpuTopologyLibArm/SsdtCpuTopologyLibArm.inf

-- 
2.17.1


^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH v1 01/13] DynamicTablesPkg: Make AmlNodeGetIntegerValue public
  2021-06-23 11:40 [PATCH v1 00/13] Create a SSDT CPU topology generator PierreGondois
@ 2021-06-23 11:40 ` PierreGondois
  2021-10-01 14:48   ` Sami Mujawar
  2021-06-23 11:40 ` [PATCH v1 02/13] DynamicTablesPkg: AML Code generation for Register() PierreGondois
                   ` (12 subsequent siblings)
  13 siblings, 1 reply; 30+ messages in thread
From: PierreGondois @ 2021-06-23 11:40 UTC (permalink / raw)
  To: devel, Sami Mujawar, Alexei Fedorov; +Cc: Akanksha Jain, Alexandru Elisei

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

Remove the STATIC qualifier for the AmlUtility function
AmlNodeGetIntegerValue() and add the definition to the
header file so that it can be used by other AmlLib
sub-modules.

Signed-off-by: Pierre Gondois <Pierre.Gondois@arm.com>
---
 .../Library/Common/AmlLib/Utils/AmlUtility.c   |  3 +--
 .../Library/Common/AmlLib/Utils/AmlUtility.h   | 18 +++++++++++++++++-
 2 files changed, 18 insertions(+), 3 deletions(-)

diff --git a/DynamicTablesPkg/Library/Common/AmlLib/Utils/AmlUtility.c b/DynamicTablesPkg/Library/Common/AmlLib/Utils/AmlUtility.c
index 7ebd08f945c0..3c8927acda6a 100644
--- a/DynamicTablesPkg/Library/Common/AmlLib/Utils/AmlUtility.c
+++ b/DynamicTablesPkg/Library/Common/AmlLib/Utils/AmlUtility.c
@@ -1,7 +1,7 @@
 /** @file
   AML Utility.
 
-  Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>
+  Copyright (c) 2019 - 2021, Arm Limited. All rights reserved.<BR>
 
   SPDX-License-Identifier: BSD-2-Clause-Patent
 **/
@@ -192,7 +192,6 @@ AmlComputeSize (
   @retval EFI_SUCCESS             The function completed successfully.
   @retval EFI_INVALID_PARAMETER   Invalid parameter.
 **/
-STATIC
 EFI_STATUS
 EFIAPI
 AmlNodeGetIntegerValue (
diff --git a/DynamicTablesPkg/Library/Common/AmlLib/Utils/AmlUtility.h b/DynamicTablesPkg/Library/Common/AmlLib/Utils/AmlUtility.h
index c57d780140d4..5013bfb81d2d 100644
--- a/DynamicTablesPkg/Library/Common/AmlLib/Utils/AmlUtility.h
+++ b/DynamicTablesPkg/Library/Common/AmlLib/Utils/AmlUtility.h
@@ -1,7 +1,7 @@
 /** @file
   AML Utility.
 
-  Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>
+  Copyright (c) 2019 - 2021, Arm Limited. All rights reserved.<BR>
 
   SPDX-License-Identifier: BSD-2-Clause-Patent
 **/
@@ -39,6 +39,22 @@ AmlComputeSize (
   IN  OUT       UINT32            * Size
   );
 
+/** Get the value contained in an integer node.
+
+  @param  [in]  Node    Pointer to an integer node.
+                        Must be an object node.
+  @param  [out] Value   Value contained in the integer node.
+
+  @retval EFI_SUCCESS             The function completed successfully.
+  @retval EFI_INVALID_PARAMETER   Invalid parameter.
+**/
+EFI_STATUS
+EFIAPI
+AmlNodeGetIntegerValue (
+  IN  AML_OBJECT_NODE   * Node,
+  OUT UINT64            * Value
+  );
+
 /** Set the value contained in an integer node.
 
   The OpCode is updated accordingly to the new value
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v1 02/13] DynamicTablesPkg: AML Code generation for Register()
  2021-06-23 11:40 [PATCH v1 00/13] Create a SSDT CPU topology generator PierreGondois
  2021-06-23 11:40 ` [PATCH v1 01/13] DynamicTablesPkg: Make AmlNodeGetIntegerValue public PierreGondois
@ 2021-06-23 11:40 ` PierreGondois
  2021-10-01 12:25   ` Sami Mujawar
  2021-06-23 11:40 ` [PATCH v1 03/13] DynamicTablesPkg: AML Code generation for Resource data EndTag PierreGondois
                   ` (11 subsequent siblings)
  13 siblings, 1 reply; 30+ messages in thread
From: PierreGondois @ 2021-06-23 11:40 UTC (permalink / raw)
  To: devel, Sami Mujawar, Alexei Fedorov; +Cc: Akanksha Jain, Alexandru Elisei

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

Add AmlCodeGenRegister() to generate AML code for the
Generic Register Resource Descriptor. This function is
equivalent to the ASL macro Register().

Signed-off-by: Pierre Gondois <Pierre.Gondois@arm.com>
---
 .../AmlLib/CodeGen/AmlResourceDataCodeGen.c   | 87 +++++++++++++++++++
 .../AmlLib/CodeGen/AmlResourceDataCodeGen.h   | 49 +++++++++++
 2 files changed, 136 insertions(+)

diff --git a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlResourceDataCodeGen.c b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlResourceDataCodeGen.c
index 089597a6c906..07a96725a4ef 100644
--- a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlResourceDataCodeGen.c
+++ b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlResourceDataCodeGen.c
@@ -187,6 +187,93 @@ AmlCodeGenRdInterrupt (
   return LinkRdNode (RdNode, NameOpNode, NewRdNode);
 }
 
+/** Code generation for the "Register ()" ASL function.
+
+  The Resource Data effectively created is a Generic Register Descriptor.
+  Data. Cf ACPI 6.4:
+   - s6.4.3.7 "Generic Register Descriptor".
+   - s19.6.114 "Register".
+
+  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]  AddressSpace    Address space where the register exists.
+                               Can be one of I/O space, System Memory, etc.
+  @param [in]  BitWidth        Number of bits in the register.
+  @param [in]  BitOffset       Offset in bits from the start of the register
+                               indicated by the Address.
+  @param [in]  Address         Register address.
+  @param [in]  AccessSize      Size of data values used when accessing the
+                               address space. Can be one of:
+                                 0 - Undefined, legacy (EFI_ACPI_6_3_UNDEFINED)
+                                 1 - Byte access (EFI_ACPI_6_3_BYTE)
+                                 2 - Word access (EFI_ACPI_6_3_WORD)
+                                 3 - DWord access (EFI_ACPI_6_3_DWORD)
+                                 4 - QWord access (EFI_ACPI_6_3_QWORD)
+  @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
+AmlCodeGenRdRegister (
+  IN  UINT8                   AddressSpace,
+  IN  UINT8                   BitWidth,
+  IN  UINT8                   BitOffset,
+  IN  UINT64                  Address,
+  IN  UINT8                   AccessSize,
+  IN  AML_OBJECT_NODE_HANDLE  NameOpNode, OPTIONAL
+  OUT AML_DATA_NODE_HANDLE    *NewRdNode  OPTIONAL
+  )
+{
+  EFI_STATUS                             Status;
+  AML_DATA_NODE                        * RdNode;
+  EFI_ACPI_GENERIC_REGISTER_DESCRIPTOR   RdRegister;
+
+  if ((AccessSize > EFI_ACPI_6_3_QWORD)  ||
+      ((NameOpNode == NULL) && (NewRdNode == NULL))) {
+    ASSERT (0);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // Header
+  RdRegister.Header.Header.Bits.Name =
+    ACPI_LARGE_GENERIC_REGISTER_DESCRIPTOR_NAME;
+  RdRegister.Header.Header.Bits.Type = ACPI_LARGE_ITEM_FLAG;
+  RdRegister.Header.Length = sizeof (EFI_ACPI_GENERIC_REGISTER_DESCRIPTOR) -
+                               sizeof (ACPI_LARGE_RESOURCE_HEADER);
+
+  // Body
+  RdRegister.AddressSpaceId = AddressSpace;
+  RdRegister.RegisterBitWidth = BitWidth;
+  RdRegister.RegisterBitOffset = BitOffset;
+  RdRegister.AddressSize = AccessSize;
+  RdRegister.RegisterAddress = Address;
+
+  Status = AmlCreateDataNode (
+             EAmlNodeDataTypeResourceData,
+             (UINT8*)&RdRegister,
+             sizeof (EFI_ACPI_GENERIC_REGISTER_DESCRIPTOR),
+             &RdNode
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    return Status;
+  }
+
+  return LinkRdNode (RdNode, NameOpNode, NewRdNode);
+}
+
 // DEPRECATED APIS
 #ifndef DISABLE_NEW_DEPRECATED_INTERFACES
 
diff --git a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlResourceDataCodeGen.h b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlResourceDataCodeGen.h
index 764051e3d7c9..3c9217d9ddab 100644
--- a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlResourceDataCodeGen.h
+++ b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlResourceDataCodeGen.h
@@ -55,4 +55,53 @@ AmlCodeGenRdInterrupt (
   OUT AML_DATA_NODE_HANDLE    *NewRdNode  OPTIONAL
   );
 
+/** Code generation for the "Register ()" ASL function.
+
+  The Resource Data effectively created is a Generic Register Descriptor.
+  Data. Cf ACPI 6.4:
+   - s6.4.3.7 "Generic Register Descriptor".
+   - s19.6.114 "Register".
+
+  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]  AddressSpace    Address space where the register exists.
+                               Can be one of I/O space, System Memory, etc.
+  @param [in]  BitWidth        Number of bits in the register.
+  @param [in]  BitOffset       Offset in bits from the start of the register
+                               indicated by the Address.
+  @param [in]  Address         Register address.
+  @param [in]  AccessSize      Size of data values used when accessing the
+                               address space. Can be one of:
+                                 0 - Undefined, legacy (EFI_ACPI_6_3_UNDEFINED)
+                                 1 - Byte access (EFI_ACPI_6_3_BYTE)
+                                 2 - Word access (EFI_ACPI_6_3_WORD)
+                                 3 - DWord access (EFI_ACPI_6_3_DWORD)
+                                 4 - QWord access (EFI_ACPI_6_3_QWORD)
+  @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
+AmlCodeGenRdRegister (
+  IN  UINT8                   AddressSpace,
+  IN  UINT8                   BitWidth,
+  IN  UINT8                   BitOffset,
+  IN  UINT64                  Address,
+  IN  UINT8                   AccessSize,
+  IN  AML_OBJECT_NODE_HANDLE  NameOpNode, OPTIONAL
+  OUT AML_DATA_NODE_HANDLE    *NewRdNode  OPTIONAL
+  );
+
 #endif // AML_RESOURCE_DATA_CODE_GEN_H_
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v1 03/13] DynamicTablesPkg: AML Code generation for Resource data EndTag
  2021-06-23 11:40 [PATCH v1 00/13] Create a SSDT CPU topology generator PierreGondois
  2021-06-23 11:40 ` [PATCH v1 01/13] DynamicTablesPkg: Make AmlNodeGetIntegerValue public PierreGondois
  2021-06-23 11:40 ` [PATCH v1 02/13] DynamicTablesPkg: AML Code generation for Register() PierreGondois
@ 2021-06-23 11:40 ` PierreGondois
  2021-10-01 12:48   ` Sami Mujawar
  2021-06-23 11:40 ` [PATCH v1 04/13] DynamicTablesPkg: AML code generation for a Package PierreGondois
                   ` (10 subsequent siblings)
  13 siblings, 1 reply; 30+ messages in thread
From: PierreGondois @ 2021-06-23 11:40 UTC (permalink / raw)
  To: devel, Sami Mujawar, Alexei Fedorov; +Cc: Akanksha Jain, Alexandru Elisei

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

Add a helper function AmlCodeGenEndTag() to generate AML Resource Data
EndTag. The EndTag resource data is automatically generated by the ASL
compiler at the end of a list of resource data elements. Therefore, an
equivalent function is not present in ASL.

However, AmlCodeGenEndTag() is useful when generating AML code for the
ResourceTemplate() macro.

Signed-off-by: Pierre Gondois <Pierre.Gondois@arm.com>
---
 .../AmlLib/CodeGen/AmlResourceDataCodeGen.c   | 104 ++++++++++++++++++
 .../AmlLib/CodeGen/AmlResourceDataCodeGen.h   |  34 ++++++
 2 files changed, 138 insertions(+)

diff --git a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlResourceDataCodeGen.c b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlResourceDataCodeGen.c
index 07a96725a4ef..78910cc5d4b4 100644
--- a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlResourceDataCodeGen.c
+++ b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlResourceDataCodeGen.c
@@ -274,6 +274,110 @@ AmlCodeGenRdRegister (
   return LinkRdNode (RdNode, NameOpNode, NewRdNode);
 }
 
+/** Code generation for the EndTag resource data.
+
+  The EndTag resource data is automatically generated by the ASL compiler
+  at the end of a list of resource data elements. Thus, it doesn't have
+  a corresponding ASL function.
+
+  This function allocates memory to create a data node. It is the caller's
+  responsibility to either:
+   - attach this node to an AML tree;
+   - delete this node.
+
+  @param [in]  CheckSum        CheckSum to store in the EndTag.
+                               Optional: can be let to 0. It is not
+                               updated when new resource data elements
+                               are added/removed/modified in the list.
+  @param [in]  ParentNode      If not NULL, add the generated node
+                               to the end of the variable list of
+                               argument of the ParentNode.
+                               The ParentNode must not initially contain
+                               an EndTag resource data element.
+  @param  [out] NewRdNode      If success, contains the generated 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
+AmlCodeGenEndTag (
+  IN  UINT8               CheckSum,   OPTIONAL
+  IN  AML_OBJECT_NODE   * ParentNode, OPTIONAL
+  OUT AML_DATA_NODE    ** NewRdNode   OPTIONAL
+  )
+{
+  EFI_STATUS                      Status;
+  AML_DATA_NODE                 * RdNode;
+  EFI_ACPI_END_TAG_DESCRIPTOR     EndTag;
+  ACPI_SMALL_RESOURCE_HEADER      SmallResHdr;
+
+  if ((ParentNode == NULL) && (NewRdNode == NULL)) {
+    ASSERT (0);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  RdNode = NULL;
+
+  // Header
+  SmallResHdr.Bits.Length = sizeof (EFI_ACPI_END_TAG_DESCRIPTOR) -
+                              sizeof (ACPI_SMALL_RESOURCE_HEADER);
+  SmallResHdr.Bits.Name = ACPI_SMALL_END_TAG_DESCRIPTOR_NAME;
+  SmallResHdr.Bits.Type = ACPI_SMALL_ITEM_FLAG;
+
+  // Body
+  EndTag.Desc = SmallResHdr.Byte;
+  EndTag.Checksum = CheckSum;
+
+  Status = AmlCreateDataNode (
+             EAmlNodeDataTypeResourceData,
+             (UINT8*)&EndTag,
+             sizeof (EFI_ACPI_END_TAG_DESCRIPTOR),
+             &RdNode
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    return Status;
+  }
+
+  if (NewRdNode != NULL) {
+    *NewRdNode = RdNode;
+  }
+
+  if (ParentNode != NULL) {
+    // Check the BufferOp doesn't contain any resource data yet.
+    // This is a hard check: do not allow to add an EndTag if the BufferNode
+    // already has resource data elements attached. Indeed, the EndTag should
+    // have already been added.
+    if (AmlGetNextVariableArgument ((AML_NODE_HEADER*)ParentNode, NULL) !=
+          NULL) {
+      ASSERT (0);
+      Status = EFI_INVALID_PARAMETER;
+      goto error_handler;
+    }
+
+    // Manually add the EndTag RdNode. Indeed, the AmlAppendRdNode function
+    // is looking for an EndTag, which we are adding here.
+    Status = AmlVarListAddTail (
+               (AML_NODE_HEADER*)ParentNode,
+               (AML_NODE_HEADER*)RdNode
+               );
+    if (EFI_ERROR (Status)) {
+      ASSERT (0);
+      goto error_handler;
+    }
+  }
+
+  return Status;
+
+error_handler:
+  if (RdNode != NULL) {
+    AmlDeleteTree ((AML_NODE_HEADER*)RdNode);
+  }
+  return Status;
+}
+
 // DEPRECATED APIS
 #ifndef DISABLE_NEW_DEPRECATED_INTERFACES
 
diff --git a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlResourceDataCodeGen.h b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlResourceDataCodeGen.h
index 3c9217d9ddab..0b464305da40 100644
--- a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlResourceDataCodeGen.h
+++ b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlResourceDataCodeGen.h
@@ -104,4 +104,38 @@ AmlCodeGenRdRegister (
   OUT AML_DATA_NODE_HANDLE    *NewRdNode  OPTIONAL
   );
 
+/** Code generation for the EndTag resource data.
+
+  The EndTag resource data is automatically generated by the ASL compiler
+  at the end of a list of resource data elements. Thus, it doesn't have
+  a corresponding ASL function.
+
+  This function allocates memory to create a data node. It is the caller's
+  responsibility to either:
+   - attach this node to an AML tree;
+   - delete this node.
+
+  @param [in]  CheckSum        CheckSum to store in the EndTag.
+                               Optional: can be let to 0. It is not
+                               updated when new resource data elements
+                               are added/removed/modified in the list.
+  @param [in]  ParentNode      If not NULL, add the generated node
+                               to the end of the variable list of
+                               argument of the ParentNode.
+                               The ParentNode must not initially contain
+                               an EndTag resource data element.
+  @param  [out] NewRdNode      If success, contains the generated 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
+AmlCodeGenEndTag (
+  IN  UINT8               CheckSum,   OPTIONAL
+  IN  AML_OBJECT_NODE   * ParentNode, OPTIONAL
+  OUT AML_DATA_NODE    ** NewRdNode   OPTIONAL
+  );
+
 #endif // AML_RESOURCE_DATA_CODE_GEN_H_
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v1 04/13] DynamicTablesPkg: AML code generation for a Package
  2021-06-23 11:40 [PATCH v1 00/13] Create a SSDT CPU topology generator PierreGondois
                   ` (2 preceding siblings ...)
  2021-06-23 11:40 ` [PATCH v1 03/13] DynamicTablesPkg: AML Code generation for Resource data EndTag PierreGondois
@ 2021-06-23 11:40 ` PierreGondois
  2021-10-01 12:55   ` Sami Mujawar
  2021-06-23 11:40 ` [PATCH v1 05/13] DynamicTablesPkg: Helper function to compute package length PierreGondois
                   ` (9 subsequent siblings)
  13 siblings, 1 reply; 30+ messages in thread
From: PierreGondois @ 2021-06-23 11:40 UTC (permalink / raw)
  To: devel, Sami Mujawar, Alexei Fedorov; +Cc: Akanksha Jain, Alexandru Elisei

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

Add AmlCodeGenPackage() to generate AML code for declaring
a Package() object. This function generates an empty package
node. New elements can then be added to the package's variable
argument list.

Signed-off-by: Pierre Gondois <Pierre.Gondois@arm.com>
---
 .../Common/AmlLib/CodeGen/AmlCodeGen.c        | 82 ++++++++++++++++++-
 1 file changed, 81 insertions(+), 1 deletion(-)

diff --git a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
index 5d310f201319..ea9b73b464a4 100644
--- a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
+++ b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
@@ -1,7 +1,7 @@
 /** @file
   AML Code Generation.
 
-  Copyright (c) 2020, Arm Limited. All rights reserved.<BR>
+  Copyright (c) 2020 - 2021, Arm Limited. All rights reserved.<BR>
 
   SPDX-License-Identifier: BSD-2-Clause-Patent
 **/
@@ -235,6 +235,86 @@ AmlCodeGenInteger (
   return Status;
 }
 
+/** AML code generation for a Package object node.
+
+  The package generated is empty. New elements can be added via its
+  list of variable arguments.
+
+  @param [out] NewObjectNode   If success, contains the created
+                               Package object node.
+
+  @retval EFI_SUCCESS             Success.
+  @retval EFI_INVALID_PARAMETER   Invalid parameter.
+  @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+AmlCodeGenPackage (
+  OUT AML_OBJECT_NODE    ** NewObjectNode
+  )
+{
+  EFI_STATUS        Status;
+  AML_DATA_NODE   * DataNode;
+  UINT8             NodeCount;
+
+  if (NewObjectNode == NULL) {
+    ASSERT (0);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  DataNode = NULL;
+  NodeCount = 0;
+
+  // Create an object node.
+  // PkgLen is 2:
+  //  - one byte to store the PkgLength
+  //  - one byte for the NumElements.
+  // Cf ACPI6.3, s20.2.5 "Term Objects Encoding"
+  // DefPackage  := PackageOp PkgLength NumElements PackageElementList
+  // NumElements := ByteData
+  Status = AmlCreateObjectNode (
+             AmlGetByteEncodingByOpCode (AML_PACKAGE_OP, 0),
+             2,
+             NewObjectNode
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    return Status;
+  }
+
+  // NumElements is a ByteData.
+  Status = AmlCreateDataNode (
+             EAmlNodeDataTypeUInt,
+             &NodeCount,
+             sizeof (NodeCount),
+             &DataNode
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler;
+  }
+
+  Status = AmlSetFixedArgument (
+             *NewObjectNode,
+             EAmlParseIndexTerm0,
+             (AML_NODE_HEADER*)DataNode
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler;
+  }
+
+  return Status;
+
+error_handler:
+  AmlDeleteTree ((AML_NODE_HEADER*)*NewObjectNode);
+  if (DataNode != NULL) {
+    AmlDeleteTree ((AML_NODE_HEADER*)DataNode);
+  }
+  return Status;
+}
+
 /** AML code generation for a Name object node.
 
   @param  [in] NameString     The new variable name.
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v1 05/13] DynamicTablesPkg: Helper function to compute package length
  2021-06-23 11:40 [PATCH v1 00/13] Create a SSDT CPU topology generator PierreGondois
                   ` (3 preceding siblings ...)
  2021-06-23 11:40 ` [PATCH v1 04/13] DynamicTablesPkg: AML code generation for a Package PierreGondois
@ 2021-06-23 11:40 ` PierreGondois
  2021-10-01 14:24   ` Sami Mujawar
  2021-06-23 11:40 ` [PATCH v1 06/13] DynamicTablesPkg: AML code generation for a ResourceTemplate PierreGondois
                   ` (8 subsequent siblings)
  13 siblings, 1 reply; 30+ messages in thread
From: PierreGondois @ 2021-06-23 11:40 UTC (permalink / raw)
  To: devel, Sami Mujawar, Alexei Fedorov; +Cc: Akanksha Jain, Alexandru Elisei

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

Some AML object have a PkgLen which indicates the size of the
AML object. The package length can be encoded in 1 to 4 bytes.
The bytes used to encode the PkgLen is itself counted in the
PkgLen value. So, if an AML object's size increments/decrements,
the number of bytes used to encode the PkgLen value can itself
increment/decrement.

Therefore, a helper function AmlComputePkgLength() is introduced
to simply computation of the PkgLen.

Signed-off-by: Pierre Gondois <Pierre.Gondois@arm.com>
---
 .../Library/Common/AmlLib/AmlEncoding/Aml.c   | 87 ++++++++++++++++++-
 .../Library/Common/AmlLib/AmlEncoding/Aml.h   | 47 +++++++++-
 2 files changed, 132 insertions(+), 2 deletions(-)

diff --git a/DynamicTablesPkg/Library/Common/AmlLib/AmlEncoding/Aml.c b/DynamicTablesPkg/Library/Common/AmlLib/AmlEncoding/Aml.c
index eadafca97ea5..d829b1869846 100644
--- a/DynamicTablesPkg/Library/Common/AmlLib/AmlEncoding/Aml.c
+++ b/DynamicTablesPkg/Library/Common/AmlLib/AmlEncoding/Aml.c
@@ -2,7 +2,7 @@
   AML grammar definitions.
 
   Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved. <BR>
-  Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>
+  Copyright (c) 2019 - 2021, Arm Limited. All rights reserved.<BR>
 
   SPDX-License-Identifier: BSD-2-Clause-Patent
 **/
@@ -803,3 +803,88 @@ AmlComputePkgLengthWidth (
   // Length < 2^6
   return 1;
 }
+
+/** Given a length, compute the value of a PkgLen.
+
+  In AML, some object have a PkgLen, telling the size of the AML object.
+  It can be encoded in 1 to 4 bytes. The bytes used to encode the PkgLen is
+  itself counted in the PkgLen value.
+  This means that if an AML object sees its size increment/decrement,
+  the number of bytes used to encode the PkgLen value can itself
+  increment/decrement.
+
+  For instance, the AML encoding of a DeviceOp is:
+    DefDevice := DeviceOp PkgLength NameString TermList
+  If:
+   - sizeof (NameString) = 4 (the name is "DEV0" for instance);
+   - sizeof (TermList) = (2^6-6)
+  then the PkgLen is encoded on 1 byte. Indeed, its value is:
+    sizeof (PkgLen) + sizeof (NameString) + sizeof (TermList) =
+    sizeof (PkgLen) + 4 + (2^6-6)
+  So:
+    PkgLen = sizeof (PkgLen) + (2^6-2)
+
+  The input arguments Length and PkgLen represent, for the DefDevice:
+    DefDevice := DeviceOp PkgLength NameString TermList
+                                    |------Length-----|
+                          |--------*PgkLength---------|
+
+  @param  [in]  Length  The length to encode as a PkgLen.
+                        Length cannot exceed 2^28 - 4 (4 bytes for the
+                        PkgLen encoding).
+                        The size of the PkgLen encoding bytes should not be
+                        counted in this length value.
+  @param  [out] PkgLen  If success, contains the value of the PkgLen,
+                        ready to encode in the PkgLen format.
+                        This value takes into account the size of PkgLen
+                        encoding.
+
+  @retval EFI_SUCCESS             The function completed successfully.
+  @retval EFI_INVALID_PARAMETER   Invalid parameter.
+**/
+EFI_STATUS
+EFIAPI
+AmlComputePkgLength (
+  IN  UINT32    Length,
+  OUT UINT32  * PkgLen
+  )
+{
+  UINT32  PkgLenWidth;
+  UINT32  ReComputedPkgLenWidth;
+
+  if (PkgLen == NULL) {
+    ASSERT (0);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // Compute the PkgLenWidth.
+  PkgLenWidth = AmlComputePkgLengthWidth (Length);
+  if (PkgLenWidth == 0) {
+    ASSERT (0);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // Add it to the Length.
+  Length += PkgLenWidth;
+
+  // Check that adding the PkgLenWidth didn't trigger a domino effect,
+  // increasing the encoding width of the PkgLen again.
+  // The PkgLen is encoded in at most 4 bytes. It is possible to increase
+  // the PkgLen width if its encoding is less than 3 bytes.
+  ReComputedPkgLenWidth = AmlComputePkgLengthWidth (Length);
+  if (ReComputedPkgLenWidth != PkgLenWidth) {
+    if ((ReComputedPkgLenWidth != 0)   &&
+        (ReComputedPkgLenWidth < 4)) {
+      // No need to recompute the PkgLen since a new threshold cannot
+      // be reached by incrementing the value by one.
+      Length += 1;
+    } else {
+      ASSERT (0);
+      return EFI_INVALID_PARAMETER;
+    }
+  }
+
+  *PkgLen = Length;
+
+  return EFI_SUCCESS;
+}
diff --git a/DynamicTablesPkg/Library/Common/AmlLib/AmlEncoding/Aml.h b/DynamicTablesPkg/Library/Common/AmlLib/AmlEncoding/Aml.h
index 35c0680b6159..0641500fcd5f 100644
--- a/DynamicTablesPkg/Library/Common/AmlLib/AmlEncoding/Aml.h
+++ b/DynamicTablesPkg/Library/Common/AmlLib/AmlEncoding/Aml.h
@@ -2,7 +2,7 @@
   AML grammar definitions.
 
   Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved. <BR>
-  Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>
+  Copyright (c) 2019 - 2021, Arm Limited. All rights reserved.<BR>
 
   SPDX-License-Identifier: BSD-2-Clause-Patent
 **/
@@ -326,5 +326,50 @@ AmlComputePkgLengthWidth (
   IN  UINT32  Length
   );
 
+/** Given a length, compute the value of a PkgLen.
+
+  In AML, some object have a PkgLen, telling the size of the AML object.
+  It can be encoded in 1 to 4 bytes. The bytes used to encode the PkgLen is
+  itself counted in the PkgLen value.
+  This means that if an AML object sees its size increment/decrement,
+  the number of bytes used to encode the PkgLen value can itself
+  increment/decrement.
+
+  For instance, the AML encoding of a DeviceOp is:
+    DefDevice := DeviceOp PkgLength NameString TermList
+  If:
+   - sizeof (NameString) = 4 (the name is "DEV0" for instance);
+   - sizeof (TermList) = (2^6-6)
+  then the PkgLen is encoded on 1 byte. Indeed, its value is:
+    sizeof (PkgLen) + sizeof (NameString) + sizeof (TermList) =
+    sizeof (PkgLen) + 4 + (2^6-6)
+  So:
+    PkgLen = sizeof (PkgLen) + (2^6-2)
+
+  The input arguments Length and PkgLen represent, for the DefDevice:
+    DefDevice := DeviceOp PkgLength NameString TermList
+                                    |------Length-----|
+                          |--------*PgkLength---------|
+
+  @param  [in]  Length  The length to encode as a PkgLen.
+                        Length cannot exceed 2^28 - 4 (4 bytes for the
+                        PkgLen encoding).
+                        The size of the PkgLen encoding bytes should not be
+                        counted in this length value.
+  @param  [out] PkgLen  If success, contains the value of the PkgLen,
+                        ready to encode in the PkgLen format.
+                        This value takes into account the size of PkgLen
+                        encoding.
+
+  @retval EFI_SUCCESS             The function completed successfully.
+  @retval EFI_INVALID_PARAMETER   Invalid parameter.
+**/
+EFI_STATUS
+EFIAPI
+AmlComputePkgLength (
+  IN  UINT32    Length,
+  OUT UINT32  * PkgLen
+  );
+
 #endif // AML_H_
 
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v1 06/13] DynamicTablesPkg: AML code generation for a ResourceTemplate
  2021-06-23 11:40 [PATCH v1 00/13] Create a SSDT CPU topology generator PierreGondois
                   ` (4 preceding siblings ...)
  2021-06-23 11:40 ` [PATCH v1 05/13] DynamicTablesPkg: Helper function to compute package length PierreGondois
@ 2021-06-23 11:40 ` PierreGondois
  2021-10-01 14:34   ` Sami Mujawar
  2021-06-23 11:40 ` [PATCH v1 07/13] DynamicTablesPkg: AML code generation for a Method PierreGondois
                   ` (7 subsequent siblings)
  13 siblings, 1 reply; 30+ messages in thread
From: PierreGondois @ 2021-06-23 11:40 UTC (permalink / raw)
  To: devel, Sami Mujawar, Alexei Fedorov; +Cc: Akanksha Jain, Alexandru Elisei

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

ASL provides a ResourceTemplate macro that creates a Buffer in which
resource descriptor macros can be listed. The ResourceTemplate macro
automatically generates an End descriptor and calculates the checksum
for the resource template.

Therefore, add AmlCodeGenResourceTemplate() to generate AML code for
the ResourceTemplate() macro. This function generates a Buffer node
with an EndTag resource data descriptor, which is similar to the ASL
ResourceTemplate() macro.

Signed-off-by: Pierre Gondois <Pierre.Gondois@arm.com>
---
 .../Common/AmlLib/CodeGen/AmlCodeGen.c        | 192 ++++++++++++++++++
 1 file changed, 192 insertions(+)

diff --git a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
index ea9b73b464a4..faf7902c1f21 100644
--- a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
+++ b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
@@ -12,6 +12,7 @@
 
 #include <AmlCoreInterface.h>
 #include <AmlEncoding/Aml.h>
+#include <CodeGen/AmlResourceDataCodeGen.h>
 #include <Tree/AmlNode.h>
 #include <Tree/AmlTree.h>
 #include <String/AmlString.h>
@@ -315,6 +316,197 @@ error_handler:
   return Status;
 }
 
+/** AML code generation for a Buffer object node.
+
+  To create a Buffer object node with an empty buffer,
+  call the function with (Buffer=NULL, BufferSize=0).
+
+  @param [in]  Buffer          Buffer to set for the created Buffer
+                               object node. The Buffer's content is copied.
+                               NULL if there is no buffer to set for
+                               the Buffer node.
+  @param [in]  BufferSize      Size of the Buffer.
+                               0 if there is no buffer to set for
+                               the Buffer node.
+  @param [out] NewObjectNode   If success, contains the created
+                               Buffer object node.
+
+  @retval EFI_SUCCESS             Success.
+  @retval EFI_INVALID_PARAMETER   Invalid parameter.
+  @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+AmlCodeGenBuffer (
+  IN  CONST UINT8             * Buffer,       OPTIONAL
+  IN        UINT32              BufferSize,   OPTIONAL
+  OUT       AML_OBJECT_NODE  ** NewObjectNode
+  )
+{
+  EFI_STATUS        Status;
+  AML_OBJECT_NODE * BufferNode;
+  AML_OBJECT_NODE * BufferSizeNode;
+  UINT32            BufferSizeNodeSize;
+  AML_DATA_NODE   * DataNode;
+  UINT32            PkgLen;
+
+  // Buffer and BufferSize must be either both set, or both clear.
+  if ((NewObjectNode == NULL)                 ||
+      ((Buffer == NULL) != (BufferSize == 0))) {
+    ASSERT (0);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  BufferNode = NULL;
+  DataNode = NULL;
+
+  // Cf ACPI 6.3 specification, s20.2.5.4 "Type 2 Opcodes Encoding"
+  // DefBuffer := BufferOp PkgLength BufferSize ByteList
+  // BufferOp  := 0x11
+  // BufferSize := TermArg => Integer
+
+  Status = AmlCodeGenInteger (BufferSize, &BufferSizeNode);
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    return Status;
+  }
+
+  // Get the number of bytes required to encode the BufferSizeNode.
+  Status = AmlComputeSize (
+             (AML_NODE_HEADER*)BufferSizeNode,
+             &BufferSizeNodeSize
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler;
+  }
+
+  // Compute the size to write in the PkgLen.
+  Status = AmlComputePkgLength (BufferSizeNodeSize + BufferSize, &PkgLen);
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler;
+  }
+
+  // Create an object node for the buffer.
+  Status = AmlCreateObjectNode (
+             AmlGetByteEncodingByOpCode (AML_BUFFER_OP, 0),
+             PkgLen,
+             &BufferNode
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler;
+  }
+
+  // Set the BufferSizeNode as a fixed argument of the BufferNode.
+  Status = AmlSetFixedArgument (
+             BufferNode,
+             EAmlParseIndexTerm0,
+             (AML_NODE_HEADER*)BufferSizeNode
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler;
+  }
+
+  // BufferSizeNode is now attached.
+  BufferSizeNode = NULL;
+
+  // If there is a buffer, create a DataNode and attach it to the BufferNode.
+  if (Buffer != NULL) {
+    Status = AmlCreateDataNode (
+               EAmlNodeDataTypeRaw,
+               Buffer,
+               BufferSize,
+               &DataNode
+               );
+    if (EFI_ERROR (Status)) {
+      ASSERT (0);
+      goto error_handler;
+    }
+
+    Status = AmlVarListAddTail (
+               (AML_NODE_HEADER*)BufferNode,
+               (AML_NODE_HEADER*)DataNode
+               );
+    if (EFI_ERROR (Status)) {
+      ASSERT (0);
+      goto error_handler;
+    }
+  }
+
+  *NewObjectNode = BufferNode;
+  return Status;
+
+error_handler:
+  if (BufferSizeNode != NULL) {
+    AmlDeleteTree ((AML_NODE_HEADER*)BufferSizeNode);
+  }
+  if (BufferNode != NULL) {
+    AmlDeleteTree ((AML_NODE_HEADER*)BufferNode);
+  }
+  if (DataNode != NULL) {
+    AmlDeleteTree ((AML_NODE_HEADER*)DataNode);
+  }
+  return Status;
+}
+
+/** AML code generation for a ResourceTemplate.
+
+  "ResourceTemplate" is a macro defined in ACPI 6.3, s19.3.3
+  "ASL Resource Templates". It allows to store resource data elements.
+
+  In AML, a ResourceTemplate is implemented as a Buffer storing resource
+  data elements. An EndTag resource data descriptor must be at the end
+  of the list of resource data elements.
+  This function generates a Buffer node with an EndTag resource data
+  descriptor. It can be seen as an empty list of resource data elements.
+
+  @param [out] NewObjectNode   If success, contains the created
+                               ResourceTemplate object node.
+
+  @retval EFI_SUCCESS             Success.
+  @retval EFI_INVALID_PARAMETER   Invalid parameter.
+  @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+AmlCodeGenResourceTemplate (
+  OUT AML_OBJECT_NODE    ** NewObjectNode
+  )
+{
+  EFI_STATUS          Status;
+  AML_OBJECT_NODE   * BufferNode;
+
+  if (NewObjectNode == NULL) {
+    ASSERT (0);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  BufferNode = NULL;
+
+  // Create a BufferNode with an empty buffer.
+  Status = AmlCodeGenBuffer (NULL, 0, &BufferNode);
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    return Status;
+  }
+
+  // Create an EndTag resource data element and attach it to the Buffer.
+  Status = AmlCodeGenEndTag (0, BufferNode, NULL);
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    AmlDeleteTree ((AML_NODE_HEADER*)BufferNode);
+    return Status;
+  }
+
+  *NewObjectNode = BufferNode;
+  return Status;
+}
+
 /** AML code generation for a Name object node.
 
   @param  [in] NameString     The new variable name.
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v1 07/13] DynamicTablesPkg: AML code generation for a Method
  2021-06-23 11:40 [PATCH v1 00/13] Create a SSDT CPU topology generator PierreGondois
                   ` (5 preceding siblings ...)
  2021-06-23 11:40 ` [PATCH v1 06/13] DynamicTablesPkg: AML code generation for a ResourceTemplate PierreGondois
@ 2021-06-23 11:40 ` PierreGondois
  2021-10-01 14:52   ` Sami Mujawar
  2021-06-23 11:40 ` [PATCH v1 08/13] DynamicTablesPkg: AML code generation to Return a NameString PierreGondois
                   ` (6 subsequent siblings)
  13 siblings, 1 reply; 30+ messages in thread
From: PierreGondois @ 2021-06-23 11:40 UTC (permalink / raw)
  To: devel, Sami Mujawar, Alexei Fedorov; +Cc: Akanksha Jain, Alexandru Elisei

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

Add AmlCodeGenMethod() to generate code for a control method.

AmlCodeGenMethod ("MET0", 1, TRUE, 3, ParentNode, NewObjectNode)
is equivalent of the following ASL code:
    Method(MET0, 1, Serialized, 3) {}

Signed-off-by: Pierre Gondois <Pierre.Gondois@arm.com>
---
 .../Common/AmlLib/CodeGen/AmlCodeGen.c        | 166 ++++++++++++++++++
 1 file changed, 166 insertions(+)

diff --git a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
index faf7902c1f21..32665f7f8d8f 100644
--- a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
+++ b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
@@ -971,3 +971,169 @@ error_handler1:
 
   return Status;
 }
+
+/** AML code generation for a Method object node.
+
+  AmlCodeGenMethod ("MET0", 1, TRUE, 3, ParentNode, NewObjectNode) is
+  equivalent of the following ASL code:
+    Method(MET0, 1, Serialized, 3) {}
+
+  The ASL parameters "ReturnType" and "ParameterTypes" are not asked
+  in this function. They are optional parameters in ASL.
+
+  @param [in]  NameString     The new Method's name.
+                              Must be a NULL-terminated ASL NameString
+                              e.g.: "MET0", "_SB.MET0", etc.
+                              The input string is copied.
+  @param [in]  NumArgs        Number of arguments.
+                              Must be 0 <= NumArgs <= 6.
+  @param [in]  IsSerialized   TRUE is equivalent to Serialized.
+                              FALSE is equivalent to NotSerialized.
+                              Default is NotSerialized in ASL spec.
+  @param [in]  SyncLevel      Synchronization level for the method.
+                              Must be 0 <= SyncLevel <= 15.
+                              Default is 0 in ASL.
+  @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.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+AmlCodeGenMethod (
+  IN  CONST CHAR8              * NameString,
+  IN        UINT8                NumArgs,
+  IN        BOOLEAN              IsSerialized,
+  IN        UINT8                SyncLevel,
+  IN        AML_NODE_HEADER    * ParentNode,     OPTIONAL
+  OUT       AML_OBJECT_NODE   ** NewObjectNode   OPTIONAL
+  )
+{
+  EFI_STATUS        Status;
+  UINT32            PkgLen;
+  UINT8             Flags;
+  AML_OBJECT_NODE * ObjectNode;
+  AML_DATA_NODE   * DataNode;
+  CHAR8           * AmlNameString;
+  UINT32            AmlNameStringSize;
+
+  if ((NameString == NULL)    ||
+      (NumArgs > 6)           ||
+      (SyncLevel > 15)        ||
+      ((ParentNode == NULL) && (NewObjectNode == NULL))) {
+    ASSERT (0);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  ObjectNode = NULL;
+  DataNode = NULL;
+
+  Status = ConvertAslNameToAmlName (NameString, &AmlNameString);
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    return Status;
+  }
+
+  Status = AmlGetNameStringSize (AmlNameString, &AmlNameStringSize);
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler1;
+  }
+
+  // Compute the size to write in the PkgLen.
+  // Add 1 byte (ByteData) for MethodFlags.
+  Status = AmlComputePkgLength (AmlNameStringSize + 1, &PkgLen);
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler1;
+  }
+
+  Status = AmlCreateObjectNode (
+             AmlGetByteEncodingByOpCode (AML_METHOD_OP, 0),
+             PkgLen,
+             &ObjectNode
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler1;
+  }
+
+  Status = AmlCreateDataNode (
+             EAmlNodeDataTypeNameString,
+             (UINT8*)AmlNameString,
+             AmlNameStringSize,
+             &DataNode
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler2;
+  }
+
+  Status = AmlSetFixedArgument (
+             ObjectNode,
+             EAmlParseIndexTerm0,
+             (AML_NODE_HEADER*)DataNode
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler2;
+  }
+
+  DataNode = NULL;
+
+  Flags = NumArgs                   |
+          (IsSerialized ? BIT3 : 0) |
+          (SyncLevel << 4);
+
+  Status = AmlCreateDataNode (EAmlNodeDataTypeUInt, &Flags, 1, &DataNode);
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler2;
+  }
+
+  Status = AmlSetFixedArgument (
+             ObjectNode,
+             EAmlParseIndexTerm1,
+             (AML_NODE_HEADER*)DataNode
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler2;
+  }
+
+  // Data node is attached so set the pointer to
+  // NULL to ensure correct error handling.
+  DataNode = NULL;
+
+  Status = LinkNode (
+             ObjectNode,
+             ParentNode,
+             NewObjectNode
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler2;
+  }
+
+  // Free AmlNameString before returning as it is copied
+  // in the call to AmlCreateDataNode().
+  goto error_handler1;
+
+error_handler2:
+  if (ObjectNode != NULL) {
+    AmlDeleteTree ((AML_NODE_HEADER*)ObjectNode);
+  }
+  if (DataNode != NULL) {
+    AmlDeleteTree ((AML_NODE_HEADER*)DataNode);
+  }
+
+error_handler1:
+  if (AmlNameString != NULL) {
+    FreePool (AmlNameString);
+  }
+  return Status;
+}
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v1 08/13] DynamicTablesPkg: AML code generation to Return a NameString
  2021-06-23 11:40 [PATCH v1 00/13] Create a SSDT CPU topology generator PierreGondois
                   ` (6 preceding siblings ...)
  2021-06-23 11:40 ` [PATCH v1 07/13] DynamicTablesPkg: AML code generation for a Method PierreGondois
@ 2021-06-23 11:40 ` PierreGondois
  2021-10-01 15:13   ` Sami Mujawar
  2021-06-23 11:40 ` [PATCH v1 09/13] DynamicTablesPkg: AML code generation for a Method returning a NS PierreGondois
                   ` (5 subsequent siblings)
  13 siblings, 1 reply; 30+ messages in thread
From: PierreGondois @ 2021-06-23 11:40 UTC (permalink / raw)
  To: devel, Sami Mujawar, Alexei Fedorov; +Cc: Akanksha Jain, Alexandru Elisei

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

Add AmlCodeGenReturnNameString() to generate AML code for a
Return object node, returning the object as a NameString.

AmlCodeGenReturn ("NAM1", ParentNode, NewObjectNode) is
equivalent of the following ASL code:
  Return(NAM1)

Signed-off-by: Pierre Gondois <Pierre.Gondois@arm.com>
---
 .../Common/AmlLib/CodeGen/AmlCodeGen.c        | 178 ++++++++++++++++++
 1 file changed, 178 insertions(+)

diff --git a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
index 32665f7f8d8f..75dadbaf4ac3 100644
--- a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
+++ b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
@@ -1137,3 +1137,181 @@ error_handler1:
   }
   return Status;
 }
+
+/** AML code generation for a Return object node.
+
+  AmlCodeGenReturn (ReturnNode, ParentNode, NewObjectNode) is
+  equivalent of the following ASL code:
+    Return([Content of the ReturnNode])
+
+  The ACPI 6.3 specification, s20.2.5.3 "Type 1 Opcodes Encoding" states:
+    DefReturn := ReturnOp ArgObject
+    ReturnOp := 0xA4
+    ArgObject := TermArg => DataRefObject
+
+  Thus, the ReturnNode must be evaluated as a DataRefObject. It can
+  be a NameString referencing an object. As this CodeGen Api doesn't
+  do semantic checking, it is strongly advised to check the AML bytecode
+  generated by this function against an ASL compiler.
+
+  The ReturnNode must be generated inside a Method body scope.
+
+  @param [in]  ReturnNode     The object returned by the Return ASL statement.
+                              This node is deleted if an error occurs.
+  @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.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+AmlCodeGenReturn (
+  IN  AML_NODE_HEADER     * ReturnNode,
+  IN  AML_NODE_HEADER     * ParentNode,     OPTIONAL
+  OUT AML_OBJECT_NODE    ** NewObjectNode   OPTIONAL
+  )
+{
+  EFI_STATUS        Status;
+  AML_OBJECT_NODE * ObjectNode;
+
+  if ((ReturnNode == NULL)  ||
+      ((ParentNode == NULL) && (NewObjectNode == NULL))) {
+    ASSERT (0);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  ObjectNode = NULL;
+
+  Status = AmlCreateObjectNode (
+             AmlGetByteEncodingByOpCode (AML_RETURN_OP, 0),
+             0,
+             &ObjectNode
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler;
+  }
+
+  Status = AmlSetFixedArgument (
+             ObjectNode,
+             EAmlParseIndexTerm0,
+             (AML_NODE_HEADER*)ReturnNode
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler;
+  }
+
+  ReturnNode = NULL;
+
+  Status = LinkNode (
+             ObjectNode,
+             ParentNode,
+             NewObjectNode
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler;
+  }
+
+  return Status;
+
+error_handler:
+  AmlDeleteTree (ReturnNode);
+  if (ObjectNode != NULL) {
+    AmlDeleteTree ((AML_NODE_HEADER*)ObjectNode);
+  }
+  return Status;
+}
+
+/** AML code generation for a Return object node,
+    returning the object as an input NameString.
+
+  AmlCodeGenReturn ("NAM1", ParentNode, NewObjectNode) is
+  equivalent of the following ASL code:
+    Return(NAM1)
+
+  The ACPI 6.3 specification, s20.2.5.3 "Type 1 Opcodes Encoding" states:
+    DefReturn := ReturnOp ArgObject
+    ReturnOp := 0xA4
+    ArgObject := TermArg => DataRefObject
+
+  Thus, the ReturnNode must be evaluated as a DataRefObject. It can
+  be a NameString referencing an object. As this CodeGen Api doesn't
+  do semantic checking, it is strongly advised to check the AML bytecode
+  generated by this function against an ASL compiler.
+
+  The ReturnNode must be generated inside a Method body scope.
+
+  @param [in]  NameString     The object referenced by this NameString
+                              is returned by the Return ASL statement.
+                              Must be a NULL-terminated ASL NameString
+                              e.g.: "NAM1", "_SB.NAM1", 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.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+AmlCodeGenReturnNameString (
+  IN  CONST CHAR8               * NameString,
+  IN        AML_NODE_HEADER     * ParentNode,     OPTIONAL
+  OUT       AML_OBJECT_NODE    ** NewObjectNode   OPTIONAL
+  )
+{
+  EFI_STATUS          Status;
+  AML_DATA_NODE     * DataNode;
+  CHAR8             * AmlNameString;
+  UINT32              AmlNameStringSize;
+
+  DataNode = NULL;
+
+  Status = ConvertAslNameToAmlName (NameString, &AmlNameString);
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    return Status;
+  }
+
+  Status = AmlGetNameStringSize (AmlNameString, &AmlNameStringSize);
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto exit_handler;
+  }
+
+  Status = AmlCreateDataNode (
+             EAmlNodeDataTypeNameString,
+             (UINT8*)AmlNameString,
+             AmlNameStringSize,
+             &DataNode
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto exit_handler;
+  }
+
+  // AmlCodeGenReturn() deletes DataNode if error.
+  Status = AmlCodeGenReturn (
+             (AML_NODE_HEADER*)DataNode,
+             ParentNode,
+             NewObjectNode
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+  }
+
+exit_handler:
+  if (AmlNameString != NULL) {
+    FreePool (AmlNameString);
+  }
+  return Status;
+}
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v1 09/13] DynamicTablesPkg: AML code generation for a Method returning a NS
  2021-06-23 11:40 [PATCH v1 00/13] Create a SSDT CPU topology generator PierreGondois
                   ` (7 preceding siblings ...)
  2021-06-23 11:40 ` [PATCH v1 08/13] DynamicTablesPkg: AML code generation to Return a NameString PierreGondois
@ 2021-06-23 11:40 ` PierreGondois
  2021-10-01 15:23   ` Sami Mujawar
  2021-06-23 11:40 ` [PATCH v1 09/13] DynamicTablesPkg: AML code generation to create " PierreGondois
                   ` (4 subsequent siblings)
  13 siblings, 1 reply; 30+ messages in thread
From: PierreGondois @ 2021-06-23 11:40 UTC (permalink / raw)
  To: devel, Sami Mujawar, Alexei Fedorov; +Cc: Akanksha Jain, Alexandru Elisei

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

Add AmlCodeGenMethodRetNameString() to generate AML code to create
a Method returning a NameString (NS).

AmlCodeGenMethodRetNameString (
  "MET0", "_CRS", 1, TRUE, 3, ParentNode, NewObjectNode
  );
is equivalent of the following ASL code:
Method(MET0, 1, Serialized, 3) {
  Return (_CRS)
}

Signed-off-by: Pierre Gondois <Pierre.Gondois@arm.com>
---
 .../Include/Library/AmlLib/AmlLib.h           |  53 +++++++++
 .../Common/AmlLib/CodeGen/AmlCodeGen.c        | 106 ++++++++++++++++++
 2 files changed, 159 insertions(+)

diff --git a/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h b/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h
index 6824cf3a6c82..7740aac24470 100644
--- a/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h
+++ b/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h
@@ -619,6 +619,59 @@ AmlCodeGenScope (
   OUT       AML_OBJECT_NODE_HANDLE  * NewObjectNode   OPTIONAL
   );
 
+/** AML code generation for a method returning a NameString.
+
+  AmlCodeGenMethodRetNameString (
+    "MET0", "_CRS", 1, TRUE, 3, ParentNode, NewObjectNode
+    );
+  is equivalent of the following ASL code:
+    Method(MET0, 1, Serialized, 3) {
+      Return (_CRS)
+    }
+
+  The ASL parameters "ReturnType" and "ParameterTypes" are not asked
+  in this function. They are optional parameters in ASL.
+
+  @ingroup CodeGenApis
+
+  @param [in]  MethodNameString     The new Method's name.
+                                    Must be a NULL-terminated ASL NameString
+                                    e.g.: "MET0", "_SB.MET0", etc.
+                                    The input string is copied.
+  @param [in]  ReturnedNameString   The name of the object returned by the
+                                    method. Optional parameter, can be:
+                                     - NULL (ignored).
+                                     - A NULL-terminated ASL NameString.
+                                       e.g.: "MET0", "_SB.MET0", etc.
+                                       The input string is copied.
+  @param [in]  NumArgs              Number of arguments.
+                                    Must be 0 <= NumArgs <= 6.
+  @param [in]  IsSerialized         TRUE is equivalent to Serialized.
+                                    FALSE is equivalent to NotSerialized.
+                                    Default is NotSerialized in ASL spec.
+  @param [in]  SyncLevel            Synchronization level for the method.
+                                    Must be 0 <= SyncLevel <= 15.
+                                    Default is 0 in ASL.
+  @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
+AmlCodeGenMethodRetNameString (
+  IN  CONST CHAR8                   * MethodNameString,
+  IN  CONST CHAR8                   * ReturnedNameString,  OPTIONAL
+  IN        UINT8                     NumArgs,
+  IN        BOOLEAN                   IsSerialized,
+  IN        UINT8                     SyncLevel,
+  IN        AML_NODE_HANDLE           ParentNode,          OPTIONAL
+  OUT       AML_OBJECT_NODE_HANDLE  * NewObjectNode        OPTIONAL
+  );
+
 // DEPRECATED APIS
 #ifndef DISABLE_NEW_DEPRECATED_INTERFACES
 
diff --git a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
index 75dadbaf4ac3..a9922871c311 100644
--- a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
+++ b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
@@ -1315,3 +1315,109 @@ exit_handler:
   }
   return Status;
 }
+
+/** AML code generation for a method returning a NameString.
+
+  AmlCodeGenMethodRetNameString (
+    "MET0", "_CRS", 1, TRUE, 3, ParentNode, NewObjectNode
+    );
+  is equivalent of the following ASL code:
+    Method(MET0, 1, Serialized, 3) {
+      Return (_CRS)
+    }
+
+  The ASL parameters "ReturnType" and "ParameterTypes" are not asked
+  in this function. They are optional parameters in ASL.
+
+  @param [in]  MethodNameString     The new Method's name.
+                                    Must be a NULL-terminated ASL NameString
+                                    e.g.: "MET0", "_SB.MET0", etc.
+                                    The input string is copied.
+  @param [in]  ReturnedNameString   The name of the object returned by the
+                                    method. Optional parameter, can be:
+                                     - NULL (ignored).
+                                     - A NULL-terminated ASL NameString.
+                                       e.g.: "MET0", "_SB.MET0", etc.
+                                       The input string is copied.
+  @param [in]  NumArgs              Number of arguments.
+                                    Must be 0 <= NumArgs <= 6.
+  @param [in]  IsSerialized         TRUE is equivalent to Serialized.
+                                    FALSE is equivalent to NotSerialized.
+                                    Default is NotSerialized in ASL spec.
+  @param [in]  SyncLevel            Synchronization level for the method.
+                                    Must be 0 <= SyncLevel <= 15.
+                                    Default is 0 in ASL.
+  @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
+AmlCodeGenMethodRetNameString (
+  IN  CONST CHAR8                   * MethodNameString,
+  IN  CONST CHAR8                   * ReturnedNameString,  OPTIONAL
+  IN        UINT8                     NumArgs,
+  IN        BOOLEAN                   IsSerialized,
+  IN        UINT8                     SyncLevel,
+  IN        AML_NODE_HANDLE           ParentNode,          OPTIONAL
+  OUT       AML_OBJECT_NODE_HANDLE  * NewObjectNode        OPTIONAL
+  )
+{
+  EFI_STATUS                Status;
+  AML_OBJECT_NODE_HANDLE    MethodNode;
+
+  if ((MethodNameString == NULL)  ||
+      ((ParentNode == NULL) && (NewObjectNode == NULL))) {
+    ASSERT (0);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // Create a Method named MethodNameString.
+  Status = AmlCodeGenMethod (
+             MethodNameString,
+             NumArgs,
+             IsSerialized,
+             SyncLevel,
+             NULL,
+             &MethodNode
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    return Status;
+  }
+
+  // Return ReturnedNameString if provided.
+  if (ReturnedNameString != NULL) {
+    Status = AmlCodeGenReturnNameString (
+               ReturnedNameString,
+               (AML_NODE_HANDLE)MethodNode,
+               NULL
+               );
+    if (EFI_ERROR (Status)) {
+      ASSERT (0);
+      goto error_handler;
+    }
+  }
+
+  Status = LinkNode (
+             MethodNode,
+             ParentNode,
+             NewObjectNode
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler;
+  }
+
+  return Status;
+
+error_handler:
+  if (MethodNode != NULL) {
+    AmlDeleteTree ((AML_NODE_HANDLE)MethodNode);
+  }
+  return Status;
+}
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v1 09/13] DynamicTablesPkg: AML code generation to create a Method returning a NS
  2021-06-23 11:40 [PATCH v1 00/13] Create a SSDT CPU topology generator PierreGondois
                   ` (8 preceding siblings ...)
  2021-06-23 11:40 ` [PATCH v1 09/13] DynamicTablesPkg: AML code generation for a Method returning a NS PierreGondois
@ 2021-06-23 11:40 ` PierreGondois
  2021-06-23 11:45   ` [edk2-devel] " PierreGondois
  2021-06-23 11:40 ` [PATCH v1 10/13] DynamicTablesPkg: AML code generation for a _LPI object PierreGondois
                   ` (3 subsequent siblings)
  13 siblings, 1 reply; 30+ messages in thread
From: PierreGondois @ 2021-06-23 11:40 UTC (permalink / raw)
  To: devel, Sami Mujawar, Alexei Fedorov; +Cc: Akanksha Jain, Alexandru Elisei

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

Add AmlCodeGenMethodRetNameString() to generate AML code to create
a Method returning a NameString (NS).

AmlCodeGenMethodRetNameString (
  "MET0", "_CRS", 1, TRUE, 3, ParentNode, NewObjectNode
  );
is equivalent of the following ASL code:
Method(MET0, 1, Serialized, 3) {
  Return (_CRS)
}

Signed-off-by: Pierre Gondois <Pierre.Gondois@arm.com>
---
 .../Include/Library/AmlLib/AmlLib.h           |  53 +++++++++
 .../Common/AmlLib/CodeGen/AmlCodeGen.c        | 106 ++++++++++++++++++
 2 files changed, 159 insertions(+)

diff --git a/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h b/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h
index 6824cf3a6c82..7740aac24470 100644
--- a/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h
+++ b/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h
@@ -619,6 +619,59 @@ AmlCodeGenScope (
   OUT       AML_OBJECT_NODE_HANDLE  * NewObjectNode   OPTIONAL
   );
 
+/** AML code generation for a method returning a NameString.
+
+  AmlCodeGenMethodRetNameString (
+    "MET0", "_CRS", 1, TRUE, 3, ParentNode, NewObjectNode
+    );
+  is equivalent of the following ASL code:
+    Method(MET0, 1, Serialized, 3) {
+      Return (_CRS)
+    }
+
+  The ASL parameters "ReturnType" and "ParameterTypes" are not asked
+  in this function. They are optional parameters in ASL.
+
+  @ingroup CodeGenApis
+
+  @param [in]  MethodNameString     The new Method's name.
+                                    Must be a NULL-terminated ASL NameString
+                                    e.g.: "MET0", "_SB.MET0", etc.
+                                    The input string is copied.
+  @param [in]  ReturnedNameString   The name of the object returned by the
+                                    method. Optional parameter, can be:
+                                     - NULL (ignored).
+                                     - A NULL-terminated ASL NameString.
+                                       e.g.: "MET0", "_SB.MET0", etc.
+                                       The input string is copied.
+  @param [in]  NumArgs              Number of arguments.
+                                    Must be 0 <= NumArgs <= 6.
+  @param [in]  IsSerialized         TRUE is equivalent to Serialized.
+                                    FALSE is equivalent to NotSerialized.
+                                    Default is NotSerialized in ASL spec.
+  @param [in]  SyncLevel            Synchronization level for the method.
+                                    Must be 0 <= SyncLevel <= 15.
+                                    Default is 0 in ASL.
+  @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
+AmlCodeGenMethodRetNameString (
+  IN  CONST CHAR8                   * MethodNameString,
+  IN  CONST CHAR8                   * ReturnedNameString,  OPTIONAL
+  IN        UINT8                     NumArgs,
+  IN        BOOLEAN                   IsSerialized,
+  IN        UINT8                     SyncLevel,
+  IN        AML_NODE_HANDLE           ParentNode,          OPTIONAL
+  OUT       AML_OBJECT_NODE_HANDLE  * NewObjectNode        OPTIONAL
+  );
+
 // DEPRECATED APIS
 #ifndef DISABLE_NEW_DEPRECATED_INTERFACES
 
diff --git a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
index 75dadbaf4ac3..a9922871c311 100644
--- a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
+++ b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
@@ -1315,3 +1315,109 @@ exit_handler:
   }
   return Status;
 }
+
+/** AML code generation for a method returning a NameString.
+
+  AmlCodeGenMethodRetNameString (
+    "MET0", "_CRS", 1, TRUE, 3, ParentNode, NewObjectNode
+    );
+  is equivalent of the following ASL code:
+    Method(MET0, 1, Serialized, 3) {
+      Return (_CRS)
+    }
+
+  The ASL parameters "ReturnType" and "ParameterTypes" are not asked
+  in this function. They are optional parameters in ASL.
+
+  @param [in]  MethodNameString     The new Method's name.
+                                    Must be a NULL-terminated ASL NameString
+                                    e.g.: "MET0", "_SB.MET0", etc.
+                                    The input string is copied.
+  @param [in]  ReturnedNameString   The name of the object returned by the
+                                    method. Optional parameter, can be:
+                                     - NULL (ignored).
+                                     - A NULL-terminated ASL NameString.
+                                       e.g.: "MET0", "_SB.MET0", etc.
+                                       The input string is copied.
+  @param [in]  NumArgs              Number of arguments.
+                                    Must be 0 <= NumArgs <= 6.
+  @param [in]  IsSerialized         TRUE is equivalent to Serialized.
+                                    FALSE is equivalent to NotSerialized.
+                                    Default is NotSerialized in ASL spec.
+  @param [in]  SyncLevel            Synchronization level for the method.
+                                    Must be 0 <= SyncLevel <= 15.
+                                    Default is 0 in ASL.
+  @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
+AmlCodeGenMethodRetNameString (
+  IN  CONST CHAR8                   * MethodNameString,
+  IN  CONST CHAR8                   * ReturnedNameString,  OPTIONAL
+  IN        UINT8                     NumArgs,
+  IN        BOOLEAN                   IsSerialized,
+  IN        UINT8                     SyncLevel,
+  IN        AML_NODE_HANDLE           ParentNode,          OPTIONAL
+  OUT       AML_OBJECT_NODE_HANDLE  * NewObjectNode        OPTIONAL
+  )
+{
+  EFI_STATUS                Status;
+  AML_OBJECT_NODE_HANDLE    MethodNode;
+
+  if ((MethodNameString == NULL)  ||
+      ((ParentNode == NULL) && (NewObjectNode == NULL))) {
+    ASSERT (0);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // Create a Method named MethodNameString.
+  Status = AmlCodeGenMethod (
+             MethodNameString,
+             NumArgs,
+             IsSerialized,
+             SyncLevel,
+             NULL,
+             &MethodNode
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    return Status;
+  }
+
+  // Return ReturnedNameString if provided.
+  if (ReturnedNameString != NULL) {
+    Status = AmlCodeGenReturnNameString (
+               ReturnedNameString,
+               (AML_NODE_HANDLE)MethodNode,
+               NULL
+               );
+    if (EFI_ERROR (Status)) {
+      ASSERT (0);
+      goto error_handler;
+    }
+  }
+
+  Status = LinkNode (
+             MethodNode,
+             ParentNode,
+             NewObjectNode
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler;
+  }
+
+  return Status;
+
+error_handler:
+  if (MethodNode != NULL) {
+    AmlDeleteTree ((AML_NODE_HANDLE)MethodNode);
+  }
+  return Status;
+}
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v1 10/13] DynamicTablesPkg: AML code generation for a _LPI object
  2021-06-23 11:40 [PATCH v1 00/13] Create a SSDT CPU topology generator PierreGondois
                   ` (9 preceding siblings ...)
  2021-06-23 11:40 ` [PATCH v1 09/13] DynamicTablesPkg: AML code generation to create " PierreGondois
@ 2021-06-23 11:40 ` PierreGondois
  2021-10-01 15:31   ` Sami Mujawar
  2021-06-23 11:40 ` [PATCH v1 11/13] DynamicTablesPkg: AML code generation to add an _LPI state PierreGondois
                   ` (2 subsequent siblings)
  13 siblings, 1 reply; 30+ messages in thread
From: PierreGondois @ 2021-06-23 11:40 UTC (permalink / raw)
  To: devel, Sami Mujawar, Alexei Fedorov; +Cc: Akanksha Jain, Alexandru Elisei

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

_LPI object provides a method to describe Low Power Idle
states that define the local power states for each node
in a hierarchical processor topology.

Therefore, add AmlCreateLpiNode() to generate code for a
_LPI object.

AmlCreateLpiNode ("_LPI", 0, 1, ParentNode, &LpiNode) is
equivalent of the following ASL code:
  Name (_LPI, Package (
		0,  // Revision
		1,  // LevelId
		0   // Count
		))

Signed-off-by: Pierre Gondois <Pierre.Gondois@arm.com>
---
 .../Include/Library/AmlLib/AmlLib.h           |  44 ++++++
 .../Common/AmlLib/CodeGen/AmlCodeGen.c        | 133 ++++++++++++++++++
 2 files changed, 177 insertions(+)

diff --git a/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h b/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h
index 7740aac24470..40c45073d303 100644
--- a/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h
+++ b/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h
@@ -672,6 +672,50 @@ AmlCodeGenMethodRetNameString (
   OUT       AML_OBJECT_NODE_HANDLE  * NewObjectNode        OPTIONAL
   );
 
+/** Create a _LPI name.
+
+  AmlCreateLpiNode ("_LPI", 0, 1, ParentNode, &LpiNode) is
+  equivalent of the following ASL code:
+    Name (_LPI, Package (
+                  0,  // Revision
+                  1,  // LevelId
+                  0   // Count
+                  ))
+
+  This function doesn't define any LPI state. As shown above, the count
+  of _LPI state is set to 0.
+  The AmlAddLpiState () function must be used to add LPI states.
+
+  Cf ACPI 6.3 specification, s8.4.4 "Lower Power Idle States".
+
+  @ingroup CodeGenApis
+
+  @param [in]  LpiNameString  The new LPI 's object name.
+                              Must be a NULL-terminated ASL NameString
+                              e.g.: "_LPI", "DEV0.PLPI", etc.
+                              The input string is copied.
+  @param [in]  Revision       Revision number of the _LPI states.
+  @param [in]  LevelId        A platform defined number that identifies the
+                              level of hierarchy of the processor node to
+                              which the LPI states apply.
+  @param [in]  ParentNode     If provided, set ParentNode as the parent
+                              of the node created.
+  @param [out] NewLpiNode     If success, contains the created node.
+
+  @retval EFI_SUCCESS             The function completed successfully.
+  @retval EFI_INVALID_PARAMETER   Invalid parameter.
+  @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
+**/
+EFI_STATUS
+EFIAPI
+AmlCreateLpiNode (
+  IN  CONST CHAR8                   * LpiNameString,
+  IN        UINT16                    Revision,
+  IN        UINT64                    LevelId,
+  IN        AML_NODE_HANDLE           ParentNode,  OPTIONAL
+  OUT       AML_OBJECT_NODE_HANDLE  * NewLpiNode   OPTIONAL
+  );
+
 // DEPRECATED APIS
 #ifndef DISABLE_NEW_DEPRECATED_INTERFACES
 
diff --git a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
index a9922871c311..89350f65f5df 100644
--- a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
+++ b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
@@ -1421,3 +1421,136 @@ error_handler:
   }
   return Status;
 }
+
+/** Create a _LPI name.
+
+  AmlCreateLpiNode ("_LPI", 0, 1, ParentNode, &LpiNode) is
+  equivalent of the following ASL code:
+    Name (_LPI, Package (
+                  0,  // Revision
+                  1,  // LevelId
+                  0   // Count
+                  ))
+
+  This function doesn't define any LPI state. As shown above, the count
+  of _LPI state is set to 0.
+  The AmlAddLpiState () function allows to add LPI states.
+
+  Cf ACPI 6.3 specification, s8.4.4 "Lower Power Idle States".
+
+  @param [in]  LpiNameString  The new LPI 's object name.
+                              Must be a NULL-terminated ASL NameString
+                              e.g.: "_LPI", "DEV0.PLPI", etc.
+                              The input string is copied.
+  @param [in]  Revision       Revision number of the _LPI states.
+  @param [in]  LevelId        A platform defined number that identifies the
+                              level of hierarchy of the processor node to
+                              which the LPI states apply.
+  @param [in]  ParentNode     If provided, set ParentNode as the parent
+                              of the node created.
+  @param [out] NewLpiNode     If success, contains the created node.
+
+  @retval EFI_SUCCESS             The function completed successfully.
+  @retval EFI_INVALID_PARAMETER   Invalid parameter.
+  @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
+**/
+EFI_STATUS
+EFIAPI
+AmlCreateLpiNode (
+  IN  CONST CHAR8                   * LpiNameString,
+  IN        UINT16                    Revision,
+  IN        UINT64                    LevelId,
+  IN        AML_NODE_HANDLE           ParentNode,  OPTIONAL
+  OUT       AML_OBJECT_NODE_HANDLE  * NewLpiNode   OPTIONAL
+  )
+{
+  EFI_STATUS                Status;
+  AML_OBJECT_NODE_HANDLE    PackageNode;
+  AML_OBJECT_NODE_HANDLE    IntegerNode;
+
+  if ((LpiNameString == NULL)                           ||
+      ((ParentNode == NULL) && (NewLpiNode == NULL))) {
+    ASSERT (0);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  IntegerNode = NULL;
+
+  Status = AmlCodeGenPackage (&PackageNode);
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    return Status;
+  }
+
+  // Create and attach Revision
+  Status = AmlCodeGenInteger (Revision, &IntegerNode);
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler;
+  }
+
+  Status = AmlVarListAddTail (
+             (AML_NODE_HANDLE)PackageNode,
+             (AML_NODE_HANDLE)IntegerNode
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler;
+  }
+
+  IntegerNode = NULL;
+
+  // Create and attach LevelId
+  Status = AmlCodeGenInteger (LevelId, &IntegerNode);
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler;
+  }
+
+  Status = AmlVarListAddTail (
+             (AML_NODE_HANDLE)PackageNode,
+             (AML_NODE_HANDLE)IntegerNode
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler;
+  }
+
+  IntegerNode = NULL;
+
+  // Create and attach Count. No LPI state is added, so 0.
+  Status = AmlCodeGenInteger (0, &IntegerNode);
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    IntegerNode = NULL;
+    goto error_handler;
+  }
+
+  Status = AmlVarListAddTail (
+             (AML_NODE_HANDLE)PackageNode,
+             (AML_NODE_HANDLE)IntegerNode
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler;
+  }
+
+  IntegerNode = NULL;
+
+  Status = AmlCodeGenName (LpiNameString, PackageNode, ParentNode, NewLpiNode);
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler;
+  }
+
+  return Status;
+
+error_handler:
+  if (PackageNode != NULL) {
+    AmlDeleteTree ((AML_NODE_HANDLE)PackageNode);
+  }
+  if (IntegerNode != NULL) {
+    AmlDeleteTree ((AML_NODE_HANDLE)IntegerNode);
+  }
+  return Status;
+}
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v1 11/13] DynamicTablesPkg: AML code generation to add an _LPI state
  2021-06-23 11:40 [PATCH v1 00/13] Create a SSDT CPU topology generator PierreGondois
                   ` (10 preceding siblings ...)
  2021-06-23 11:40 ` [PATCH v1 10/13] DynamicTablesPkg: AML code generation for a _LPI object PierreGondois
@ 2021-06-23 11:40 ` PierreGondois
  2021-10-01 15:43   ` Sami Mujawar
  2021-06-23 11:40 ` [PATCH v1 12/13] DynamicTablesPkg: Add CM_ARM_LPI_INFO object PierreGondois
  2021-06-23 11:40 ` [PATCH v1 13/13] DynamicTablesPkg: SSDT CPU topology and LPI state generator PierreGondois
  13 siblings, 1 reply; 30+ messages in thread
From: PierreGondois @ 2021-06-23 11:40 UTC (permalink / raw)
  To: devel, Sami Mujawar, Alexei Fedorov; +Cc: Akanksha Jain, Alexandru Elisei

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

Add AmlAddLpiState() to generates AML code to add an _LPI state
to an _LPI object created using AmlCreateLpiNode().

AmlAddLpiState increments the count of LPI states in the LPI
node by one, and adds the following package:
  Package() {
    MinResidency,
    WorstCaseWakeLatency,
    Flags,
    ArchFlags,
    ResCntFreq,
    EnableParentState,
    (GenericRegisterDescriptor != NULL) ?           // Entry method. If a
      ResourceTemplate(GenericRegisterDescriptor) : // Register is given,
      Integer,                                      // use it. Use the
                                                    // Integer otherwise
    ResourceTemplate() {                            // NULL Residency
      Register (SystemMemory, 0, 0, 0, 0)           // Counter
    },
    ResourceTemplate() {                            // NULL Usage Counter
      Register (SystemMemory, 0, 0, 0, 0)
    },
    ""                                              // NULL State Name
  },

Signed-off-by: Pierre Gondois <Pierre.Gondois@arm.com>
---
 .../Include/Library/AmlLib/AmlLib.h           |  71 +++
 .../Common/AmlLib/CodeGen/AmlCodeGen.c        | 439 ++++++++++++++++++
 2 files changed, 510 insertions(+)

diff --git a/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h b/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h
index 40c45073d303..4932f6fd9c8b 100644
--- a/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h
+++ b/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h
@@ -716,6 +716,77 @@ AmlCreateLpiNode (
   OUT       AML_OBJECT_NODE_HANDLE  * NewLpiNode   OPTIONAL
   );
 
+/** Add an _LPI state to a LPI node created using AmlCreateLpiNode ().
+
+  AmlAddLpiState () increments the Count of LPI states in the LPI node by one,
+  and adds the following package:
+    Package() {
+      MinResidency,
+      WorstCaseWakeLatency,
+      Flags,
+      ArchFlags,
+      ResCntFreq,
+      EnableParentState,
+      (GenericRegisterDescriptor != NULL) ?           // Entry method. If a
+        ResourceTemplate(GenericRegisterDescriptor) : // Register is given,
+        Integer,                                      // use it. Use the
+                                                      // Integer otherwise.
+      ResourceTemplate() {                            // NULL Residency Counter
+        Register (SystemMemory, 0, 0, 0, 0)
+      },
+      ResourceTemplate() {                            // NULL Usage Counter
+        Register (SystemMemory, 0, 0, 0, 0)
+      },
+      ""                                              // NULL State Name
+    },
+
+  Cf ACPI 6.3 specification, s8.4.4 "Lower Power Idle States".
+
+  @ingroup CodeGenApis
+
+  @param [in]  MinResidency               Minimum Residency.
+  @param [in]  WorstCaseWakeLatency       Worst case wake-up latency.
+  @param [in]  Flags                      Flags.
+  @param [in]  ArchFlags                  Architectural flags.
+  @param [in]  ResCntFreq                 Residency Counter Frequency.
+  @param [in]  EnableParentState          Enabled Parent State.
+  @param [in]  GenericRegisterDescriptor  Entry Method.
+                                          If not NULL, use this Register to
+                                          describe the entry method address.
+  @param [in]  Integer                    Entry Method.
+                                          If GenericRegisterDescriptor is NULL,
+                                          take this value.
+  @param [in]  ResidencyCounterRegister   If not NULL, use it to populate the
+                                          residency counter register.
+  @param [in]  UsageCounterRegister       If not NULL, use it to populate the
+                                          usage counter register.
+  @param [in]  StateName                  If not NULL, use it to populate the
+                                          state name.
+  @param [in]  LpiNode                    Lpi node created with the function
+                                          AmlCreateLpiNode to which the new LPI
+                                          state is appended.
+
+  @retval EFI_SUCCESS             The function completed successfully.
+  @retval EFI_INVALID_PARAMETER   Invalid parameter.
+  @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
+**/
+EFI_STATUS
+EFIAPI
+AmlAddLpiState (
+  IN  UINT32                                    MinResidency,
+  IN  UINT32                                    WorstCaseWakeLatency,
+  IN  UINT32                                    Flags,
+  IN  UINT32                                    ArchFlags,
+  IN  UINT32                                    ResCntFreq,
+  IN  UINT32                                    EnableParentState,
+  IN  EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE  * GenericRegisterDescriptor,  OPTIONAL
+  IN  UINT64                                    Integer,                    OPTIONAL
+  IN  EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE  * ResidencyCounterRegister,   OPTIONAL
+  IN  EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE  * UsageCounterRegister,       OPTIONAL
+  IN  CHAR8                                   * StateName,                  OPTIONAL
+  IN  AML_OBJECT_NODE_HANDLE                    LpiNode
+  );
+
 // DEPRECATED APIS
 #ifndef DISABLE_NEW_DEPRECATED_INTERFACES
 
diff --git a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
index 89350f65f5df..f0861040191f 100644
--- a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
+++ b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
@@ -12,6 +12,7 @@
 
 #include <AmlCoreInterface.h>
 #include <AmlEncoding/Aml.h>
+#include <Api/AmlApiHelper.h>
 #include <CodeGen/AmlResourceDataCodeGen.h>
 #include <Tree/AmlNode.h>
 #include <Tree/AmlTree.h>
@@ -1554,3 +1555,441 @@ error_handler:
   }
   return Status;
 }
+
+/** Add an _LPI state to a LPI node created using AmlCreateLpiNode.
+
+  AmlAddLpiState increments the Count of LPI states in the LPI node by one,
+  and adds the following package:
+    Package() {
+      MinResidency,
+      WorstCaseWakeLatency,
+      Flags,
+      ArchFlags,
+      ResCntFreq,
+      EnableParentState,
+      (GenericRegisterDescriptor != NULL) ?           // Entry method. If a
+        ResourceTemplate(GenericRegisterDescriptor) : // Register is given,
+        Integer,                                      // use it. Use the
+                                                      // Integer otherwise.
+      ResourceTemplate() {                            // NULL Residency Counter
+        Register (SystemMemory, 0, 0, 0, 0)
+      },
+      ResourceTemplate() {                            // NULL Usage Counter
+        Register (SystemMemory, 0, 0, 0, 0)
+      },
+      ""                                              // NULL State Name
+    },
+
+  Cf ACPI 6.3 specification, s8.4.4 "Lower Power Idle States".
+
+  @param [in]  MinResidency               Minimum Residency.
+  @param [in]  WorstCaseWakeLatency       Worst case wake-up latency.
+  @param [in]  Flags                      Flags.
+  @param [in]  ArchFlags                  Architectural flags.
+  @param [in]  ResCntFreq                 Residency Counter Frequency.
+  @param [in]  EnableParentState          Enabled Parent State.
+  @param [in]  GenericRegisterDescriptor  Entry Method.
+                                          If not NULL, use this Register to
+                                          describe the entry method address.
+  @param [in]  Integer                    Entry Method.
+                                          If GenericRegisterDescriptor is NULL,
+                                          take this value.
+  @param [in]  ResidencyCounterRegister   If not NULL, use it to populate the
+                                          residency counter register.
+  @param [in]  UsageCounterRegister       If not NULL, use it to populate the
+                                          usage counter register.
+  @param [in]  StateName                  If not NULL, use it to populate the
+                                          state name.
+  @param [in]  LpiNode                    Lpi node created with the function
+                                          AmlCreateLpiNode to which the new LPI
+                                          state is appended.
+
+  @retval EFI_SUCCESS             The function completed successfully.
+  @retval EFI_INVALID_PARAMETER   Invalid parameter.
+  @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
+**/
+EFI_STATUS
+EFIAPI
+AmlAddLpiState (
+  IN  UINT32                                    MinResidency,
+  IN  UINT32                                    WorstCaseWakeLatency,
+  IN  UINT32                                    Flags,
+  IN  UINT32                                    ArchFlags,
+  IN  UINT32                                    ResCntFreq,
+  IN  UINT32                                    EnableParentState,
+  IN  EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE  * GenericRegisterDescriptor,  OPTIONAL
+  IN  UINT64                                    Integer,                    OPTIONAL
+  IN  EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE  * ResidencyCounterRegister,   OPTIONAL
+  IN  EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE  * UsageCounterRegister,       OPTIONAL
+  IN  CHAR8                                   * StateName,                  OPTIONAL
+  IN  AML_OBJECT_NODE_HANDLE                    LpiNode
+  )
+{
+  EFI_STATUS                Status;
+  AML_DATA_NODE_HANDLE      RdNode;
+  AML_OBJECT_NODE_HANDLE    PackageNode;
+  AML_OBJECT_NODE_HANDLE    IntegerNode;
+  AML_OBJECT_NODE_HANDLE    StringNode;
+  AML_OBJECT_NODE_HANDLE    NewLpiPackageNode;
+  AML_OBJECT_NODE_HANDLE    ResourceTemplateNode;
+
+  UINT32                    Index;
+  AML_OBJECT_NODE_HANDLE    CountNode;
+  UINT64                    Count;
+
+  if ((LpiNode == NULL)                                              ||
+      (AmlGetNodeType ((AML_NODE_HANDLE)LpiNode) != EAmlNodeObject)  ||
+      (!AmlNodeHasOpCode (LpiNode, AML_NAME_OP, 0))) {
+    ASSERT (0);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  RdNode = 0;
+  StringNode = NULL;
+  IntegerNode = NULL;
+  ResourceTemplateNode = NULL;
+
+  // Get the LPI value which is represented as a PackageOp object node
+  // which is the 2nd fixed argument (i.e. index 1).
+  PackageNode = (AML_OBJECT_NODE_HANDLE)AmlGetFixedArgument (
+                                          LpiNode,
+                                          EAmlParseIndexTerm1
+                                          );
+  if ((PackageNode == NULL)                                             ||
+      (AmlGetNodeType ((AML_NODE_HANDLE)PackageNode) != EAmlNodeObject) ||
+      (!AmlNodeHasOpCode (PackageNode, AML_PACKAGE_OP, 0))) {
+    ASSERT (0);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  CountNode = NULL;
+  // The third variable argument is the LPI Count node.
+  for (Index = 0; Index < 3; Index++) {
+    CountNode = (AML_OBJECT_NODE_HANDLE)AmlGetNextVariableArgument (
+                                          (AML_NODE_HANDLE)PackageNode,
+                                          (AML_NODE_HANDLE)CountNode
+                                          );
+    if (CountNode == NULL) {
+      ASSERT (0);
+      return EFI_INVALID_PARAMETER;
+    }
+  }
+
+  Status = AmlNodeGetIntegerValue (CountNode, &Count);
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    return Status;
+  }
+  Status = AmlUpdateInteger (CountNode, Count + 1);
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    return Status;
+  }
+
+  Status = AmlCodeGenPackage (&NewLpiPackageNode);
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    return Status;
+  }
+
+  // MinResidency
+  Status = AmlCodeGenInteger (MinResidency, &IntegerNode);
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler;
+  }
+  Status = AmlVarListAddTail (
+             (AML_NODE_HANDLE)NewLpiPackageNode,
+             (AML_NODE_HANDLE)IntegerNode
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler;
+  }
+  IntegerNode = NULL;
+
+  // WorstCaseWakeLatency
+  Status = AmlCodeGenInteger (WorstCaseWakeLatency, &IntegerNode);
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler;
+  }
+  Status = AmlVarListAddTail (
+             (AML_NODE_HANDLE)NewLpiPackageNode,
+             (AML_NODE_HANDLE)IntegerNode
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler;
+  }
+  IntegerNode = NULL;
+
+  // Flags
+  Status = AmlCodeGenInteger (Flags, &IntegerNode);
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler;
+  }
+  Status = AmlVarListAddTail (
+             (AML_NODE_HANDLE)NewLpiPackageNode,
+             (AML_NODE_HANDLE)IntegerNode
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler;
+  }
+  IntegerNode = NULL;
+
+  // ArchFlags
+  Status = AmlCodeGenInteger (ArchFlags, &IntegerNode);
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler;
+  }
+  Status = AmlVarListAddTail (
+             (AML_NODE_HANDLE)NewLpiPackageNode,
+             (AML_NODE_HANDLE)IntegerNode
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler;
+  }
+  IntegerNode = NULL;
+
+  // ResCntFreq
+  Status = AmlCodeGenInteger (ResCntFreq, &IntegerNode);
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler;
+  }
+  Status = AmlVarListAddTail (
+             (AML_NODE_HANDLE)NewLpiPackageNode,
+             (AML_NODE_HANDLE)IntegerNode
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler;
+  }
+  IntegerNode = NULL;
+
+  // EnableParentState
+  Status = AmlCodeGenInteger (EnableParentState, &IntegerNode);
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler;
+  }
+  Status = AmlVarListAddTail (
+             (AML_NODE_HANDLE)NewLpiPackageNode,
+             (AML_NODE_HANDLE)IntegerNode
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler;
+  }
+  IntegerNode = NULL;
+
+  // Entry Method
+  if (GenericRegisterDescriptor != NULL) {
+    // Entry Method: As a Register resource data
+    Status = AmlCodeGenResourceTemplate (&ResourceTemplateNode);
+    if (EFI_ERROR (Status)) {
+      ASSERT (0);
+      goto error_handler;
+    }
+    Status = AmlCodeGenRdRegister (
+               GenericRegisterDescriptor->AddressSpaceId,
+               GenericRegisterDescriptor->RegisterBitWidth,
+               GenericRegisterDescriptor->RegisterBitOffset,
+               GenericRegisterDescriptor->Address,
+               GenericRegisterDescriptor->AccessSize,
+               NULL,
+               &RdNode
+               );
+    if (EFI_ERROR (Status)) {
+      ASSERT (0);
+      goto error_handler;
+    }
+
+    Status = AmlAppendRdNode (ResourceTemplateNode, RdNode);
+    if (EFI_ERROR (Status)) {
+      ASSERT (0);
+      goto error_handler;
+    }
+    RdNode = NULL;
+
+    Status = AmlVarListAddTail (
+               (AML_NODE_HANDLE)NewLpiPackageNode,
+               (AML_NODE_HANDLE)ResourceTemplateNode
+               );
+    if (EFI_ERROR (Status)) {
+      ASSERT (0);
+      goto error_handler;
+    }
+    ResourceTemplateNode = NULL;
+  } else {
+    // Entry Method: As an integer
+    Status = AmlCodeGenInteger (Integer, &IntegerNode);
+    if (EFI_ERROR (Status)) {
+      ASSERT (0);
+      goto error_handler;
+    }
+    Status = AmlVarListAddTail (
+               (AML_NODE_HANDLE)NewLpiPackageNode,
+               (AML_NODE_HANDLE)IntegerNode
+               );
+    if (EFI_ERROR (Status)) {
+      ASSERT (0);
+      goto error_handler;
+    }
+    IntegerNode = NULL;
+  }
+
+  // Residency Counter Register.
+  Status = AmlCodeGenResourceTemplate (&ResourceTemplateNode);
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler;
+  }
+  if (ResidencyCounterRegister != NULL) {
+    Status = AmlCodeGenRdRegister (
+               ResidencyCounterRegister->AddressSpaceId,
+               ResidencyCounterRegister->RegisterBitWidth,
+               ResidencyCounterRegister->RegisterBitOffset,
+               ResidencyCounterRegister->Address,
+               ResidencyCounterRegister->AccessSize,
+               NULL,
+               &RdNode
+               );
+  } else {
+    Status = AmlCodeGenRdRegister (
+               EFI_ACPI_2_0_SYSTEM_MEMORY,
+               0,
+               0,
+               0,
+               0,
+               NULL,
+               &RdNode
+               );
+  }
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler;
+  }
+
+  Status = AmlAppendRdNode (ResourceTemplateNode, RdNode);
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler;
+  }
+  RdNode = NULL;
+
+  Status = AmlVarListAddTail (
+             (AML_NODE_HANDLE)NewLpiPackageNode,
+             (AML_NODE_HANDLE)ResourceTemplateNode
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler;
+  }
+  ResourceTemplateNode = NULL;
+
+  // Usage Counter Register.
+  Status = AmlCodeGenResourceTemplate (&ResourceTemplateNode);
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler;
+  }
+  if (UsageCounterRegister != NULL) {
+    Status = AmlCodeGenRdRegister (
+               UsageCounterRegister->AddressSpaceId,
+               UsageCounterRegister->RegisterBitWidth,
+               UsageCounterRegister->RegisterBitOffset,
+               UsageCounterRegister->Address,
+               UsageCounterRegister->AccessSize,
+               NULL,
+               &RdNode
+               );
+  } else {
+    Status = AmlCodeGenRdRegister (
+               EFI_ACPI_2_0_SYSTEM_MEMORY,
+               0,
+               0,
+               0,
+               0,
+               NULL,
+               &RdNode
+               );
+  }
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler;
+  }
+
+  Status = AmlAppendRdNode (ResourceTemplateNode, RdNode);
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler;
+  }
+  RdNode = NULL;
+
+  Status = AmlVarListAddTail (
+             (AML_NODE_HANDLE)NewLpiPackageNode,
+             (AML_NODE_HANDLE)ResourceTemplateNode
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler;
+  }
+  ResourceTemplateNode = NULL;
+
+  // State name.
+  if (UsageCounterRegister != NULL) {
+    Status = AmlCodeGenString (StateName, &StringNode);
+  } else {
+    Status = AmlCodeGenString ("", &StringNode);
+  }
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler;
+  }
+  Status = AmlVarListAddTail (
+             (AML_NODE_HANDLE)NewLpiPackageNode,
+             (AML_NODE_HANDLE)StringNode
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler;
+  }
+  StringNode = NULL;
+
+  // Add the new LPI state to the LpiNode.
+  Status = AmlVarListAddTail (
+             (AML_NODE_HANDLE)PackageNode,
+             (AML_NODE_HANDLE)NewLpiPackageNode
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler;
+  }
+
+  return Status;
+
+error_handler:
+  if (RdNode != NULL) {
+    AmlDeleteTree ((AML_NODE_HANDLE)RdNode);
+  }
+  if (NewLpiPackageNode != NULL) {
+    AmlDeleteTree ((AML_NODE_HANDLE)NewLpiPackageNode);
+  }
+  if (StringNode != NULL) {
+    AmlDeleteTree ((AML_NODE_HANDLE)StringNode);
+  }
+  if (IntegerNode != NULL) {
+    AmlDeleteTree ((AML_NODE_HANDLE)IntegerNode);
+  }
+  if (ResourceTemplateNode != NULL) {
+    AmlDeleteTree ((AML_NODE_HANDLE)ResourceTemplateNode);
+  }
+
+  return Status;
+}
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v1 12/13] DynamicTablesPkg: Add CM_ARM_LPI_INFO object
  2021-06-23 11:40 [PATCH v1 00/13] Create a SSDT CPU topology generator PierreGondois
                   ` (11 preceding siblings ...)
  2021-06-23 11:40 ` [PATCH v1 11/13] DynamicTablesPkg: AML code generation to add an _LPI state PierreGondois
@ 2021-06-23 11:40 ` PierreGondois
  2021-10-05 14:39   ` Sami Mujawar
  2021-06-23 11:40 ` [PATCH v1 13/13] DynamicTablesPkg: SSDT CPU topology and LPI state generator PierreGondois
  13 siblings, 1 reply; 30+ messages in thread
From: PierreGondois @ 2021-06-23 11:40 UTC (permalink / raw)
  To: devel, Sami Mujawar, Alexei Fedorov; +Cc: Akanksha Jain, Alexandru Elisei

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

Introduce the CM_ARM_LPI_INFO CmObj in the ArmNameSpaceObjects.
This allows to describe LPI state information, as described in
ACPI 6.4, s8.4.4.3 "_LPI (Low Power Idle States)".

Signed-off-by: Pierre Gondois <Pierre.Gondois@arm.com>
---
 .../Include/ArmNameSpaceObjects.h             | 68 +++++++++++++++++++
 .../ConfigurationManagerObjectParser.c        | 35 ++++++++++
 2 files changed, 103 insertions(+)

diff --git a/DynamicTablesPkg/Include/ArmNameSpaceObjects.h b/DynamicTablesPkg/Include/ArmNameSpaceObjects.h
index 19dcae13b219..9c49091def59 100644
--- a/DynamicTablesPkg/Include/ArmNameSpaceObjects.h
+++ b/DynamicTablesPkg/Include/ArmNameSpaceObjects.h
@@ -58,6 +58,7 @@ typedef enum ArmObjectID {
   EArmObjGenericInitiatorAffinityInfo, ///< 34 - Generic Initiator Affinity
   EArmObjSerialPortInfo,               ///< 35 - Generic Serial Port Info
   EArmObjCmn600Info,                   ///< 36 - CMN-600 Info
+  EArmObjLpiInfo,                      ///< 37 - Lpi Info
   EArmObjMax
 } EARM_OBJECT_ID;
 
@@ -711,6 +712,10 @@ typedef struct CmArmProcHierarchyInfo {
   /// the NoOfPrivateResources is 0, in which case it is recommended to set
   /// this field to CM_NULL_TOKEN.
   CM_OBJECT_TOKEN   PrivateResourcesArrayToken;
+  /// Optional field: Reference Token for the Lpi state of this processor.
+  /// Token identifying a CM_ARM_OBJ_REF structure, itself referencing
+  /// CM_ARM_LPI_INFO objects.
+  CM_OBJECT_TOKEN   LpiToken;
 } CM_ARM_PROC_HIERARCHY_INFO;
 
 /** A structure that describes the Cache Type Structure (Type 1) in PPTT
@@ -878,6 +883,69 @@ typedef struct CmArmCmn600Info {
   CM_ARM_EXTENDED_INTERRUPT  DtcInterrupt[4];
 } CM_ARM_CMN_600_INFO;
 
+/** A structure that describes the Lpi information.
+
+  The Low Power Idle states are described in DSDT/SSDT and associated
+  to cpus/clusters in the cpu topology.
+
+  ID: EArmObjLpiInfo
+*/
+typedef struct CmArmLpiInfo {
+  /** Minimum Residency. Time in microseconds after which a
+      state becomes more energy efficient than any shallower state.
+  */
+  UINT32                                  MinResidency;
+
+  /** Worst case time in microseconds from a wake interrupt
+      being asserted to the return to a running state
+  */
+  UINT32                                  WorstCaseWakeLatency;
+
+  /** Flags.
+  */
+  UINT32                                  Flags;
+
+  /** Architecture specific context loss flags.
+  */
+  UINT32                                  ArchFlags;
+
+  /** Residency counter frequency in cycles-per-second (Hz).
+  */
+  UINT32                                  ResCntFreq;
+
+  /** Every shallower power state in the parent is also enabled.
+  */
+  UINT32                                  EnableParentState;
+
+  /** The EntryMethod _LPI field can be described as an integer
+      or in a Register resource data descriptor.
+
+  If IsInteger is TRUE, the IntegerEntryMethod field is used.
+  If IsInteger is FALSE, the RegisterEntryMethod field is used.
+  */
+  BOOLEAN                                 IsInteger;
+
+  /** EntryMethod described as an Integer.
+  */
+  UINT64                                  IntegerEntryMethod;
+
+  /** EntryMethod described as a EFI_ACPI_GENERIC_REGISTER_DESCRIPTOR.
+  */
+  EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE  RegisterEntryMethod;
+
+  /** Residency counter register.
+  */
+  EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE  ResidencyCounterRegister;
+
+  /** Usage counter register.
+  */
+  EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE  UsageCounterRegister;
+
+  /** String representing the Lpi state
+  */
+  CHAR8                                   StateName[16];
+} CM_ARM_LPI_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 654ead6878e6..da5f5846edd9 100644
--- a/DynamicTablesPkg/Library/Common/TableHelperLib/ConfigurationManagerObjectParser.c
+++ b/DynamicTablesPkg/Library/Common/TableHelperLib/ConfigurationManagerObjectParser.c
@@ -368,6 +368,39 @@ STATIC CONST CM_OBJ_PARSER CmArmCmn600InfoParser[] = {
   {"DtcFlags[3]", 4, "0x%x", NULL}
 };
 
+/** A parser for the EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE structure.
+*/
+STATIC CONST CM_OBJ_PARSER AcpiGenericAddressParser[] = {
+  {"AddressSpaceId", 1, "%d", NULL},
+  {"RegisterBitWidth", 1, "%d", NULL},
+  {"RegisterBitOffset", 1, "%d", NULL},
+  {"AccessSize", 1, "%d", NULL},
+  {"Address", 8, "0x%llx", NULL},
+};
+
+/** A parser for EArmObjLpiInfo.
+*/
+STATIC CONST CM_OBJ_PARSER CmArmLpiInfoParser[] = {
+  {"MinResidency", 4, "0x%llx", NULL},
+  {"WorstCaseWakeLatency", 4, "0x%llx", NULL},
+  {"Flags", 4, "0x%llx", NULL},
+  {"ArchFlags", 4, "0x%llx", NULL},
+  {"ResCntFreq", 4, "0x%llx", NULL},
+  {"EnableParentState", 4, "0x%llx", NULL},
+  {"IsInteger", 1, "%d", NULL},
+  {"IntegerEntryMethod", 8, "0x%llx", NULL},
+  {"RegisterEntryMethod", sizeof (EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE),
+    NULL, NULL, AcpiGenericAddressParser,
+    ARRAY_SIZE (AcpiGenericAddressParser)},
+  {"ResidencyCounterRegister", sizeof (EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE),
+    NULL, NULL, AcpiGenericAddressParser,
+    ARRAY_SIZE (AcpiGenericAddressParser)},
+  {"UsageCounterRegister", sizeof (EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE),
+    NULL, NULL, AcpiGenericAddressParser,
+    ARRAY_SIZE (AcpiGenericAddressParser)},
+  {"StateName", 16, "0x%a", NULL},
+};
+
 /** A parser for Arm namespace objects.
 */
 STATIC CONST CM_OBJ_PARSER_ARRAY ArmNamespaceObjectParser[] = {
@@ -440,6 +473,8 @@ STATIC CONST CM_OBJ_PARSER_ARRAY ArmNamespaceObjectParser[] = {
     ARRAY_SIZE (CmArmSerialPortInfoParser)},
   {"EArmObjCmn600Info", CmArmCmn600InfoParser,
     ARRAY_SIZE (CmArmCmn600InfoParser)},
+  {"EArmObjLpiInfo", CmArmLpiInfoParser,
+      ARRAY_SIZE (CmArmLpiInfoParser)},
   {"EArmObjMax", NULL, 0},
 };
 
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v1 13/13] DynamicTablesPkg: SSDT CPU topology and LPI state generator
  2021-06-23 11:40 [PATCH v1 00/13] Create a SSDT CPU topology generator PierreGondois
                   ` (12 preceding siblings ...)
  2021-06-23 11:40 ` [PATCH v1 12/13] DynamicTablesPkg: Add CM_ARM_LPI_INFO object PierreGondois
@ 2021-06-23 11:40 ` PierreGondois
  2021-10-05 14:38   ` Sami Mujawar
  13 siblings, 1 reply; 30+ messages in thread
From: PierreGondois @ 2021-06-23 11:40 UTC (permalink / raw)
  To: devel, Sami Mujawar, Alexei Fedorov; +Cc: Akanksha Jain, Alexandru Elisei

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

In the GIC interrupt model, 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.
Additionally, _LPI objects may be needed as they provide a method
to describe Low Power Idle states that defines the local power
states for each node in a hierarchical processor topology.

Therefore, add support to generate the CPU topology and the LPI
state information in an SSDT table.

Signed-off-by: Pierre Gondois <Pierre.Gondois@arm.com>
---
 DynamicTablesPkg/DynamicTables.dsc.inc        |    6 +
 DynamicTablesPkg/Include/AcpiTableGenerator.h |    7 +-
 .../SsdtCpuTopologyGenerator.c                | 1230 +++++++++++++++++
 .../SsdtCpuTopologyGenerator.h                |  134 ++
 .../SsdtCpuTopologyLibArm.inf                 |   40 +
 5 files changed, 1416 insertions(+), 1 deletion(-)
 create mode 100644 DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCpuTopologyLibArm/SsdtCpuTopologyGenerator.c
 create mode 100644 DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCpuTopologyLibArm/SsdtCpuTopologyGenerator.h
 create mode 100644 DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCpuTopologyLibArm/SsdtCpuTopologyLibArm.inf

diff --git a/DynamicTablesPkg/DynamicTables.dsc.inc b/DynamicTablesPkg/DynamicTables.dsc.inc
index ed221d1681eb..292215c39456 100644
--- a/DynamicTablesPkg/DynamicTables.dsc.inc
+++ b/DynamicTablesPkg/DynamicTables.dsc.inc
@@ -37,6 +37,9 @@ [Components.common]
   DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtSerialPortLibArm/SsdtSerialPortLibArm.inf
   DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCmn600LibArm/SsdtCmn600LibArm.inf
 
+  # AML Codegen
+  DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCpuTopologyLibArm/SsdtCpuTopologyLibArm.inf
+
   #
   # Dynamic Table Factory Dxe
   #
@@ -56,6 +59,9 @@ [Components.common]
       # AML Fixup
       NULL|DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtSerialPortLibArm/SsdtSerialPortLibArm.inf
       NULL|DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCmn600LibArm/SsdtCmn600LibArm.inf
+
+      # AML Codegen
+      NULL|DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCpuTopologyLibArm/SsdtCpuTopologyLibArm.inf
   }
 
   #
diff --git a/DynamicTablesPkg/Include/AcpiTableGenerator.h b/DynamicTablesPkg/Include/AcpiTableGenerator.h
index 352331d6dc95..45c808ba740d 100644
--- a/DynamicTablesPkg/Include/AcpiTableGenerator.h
+++ b/DynamicTablesPkg/Include/AcpiTableGenerator.h
@@ -1,6 +1,6 @@
 /** @file
 
-  Copyright (c) 2017 - 2020, Arm Limited. All rights reserved.<BR>
+  Copyright (c) 2017 - 2021, Arm Limited. All rights reserved.<BR>
 
   SPDX-License-Identifier: BSD-2-Clause-Patent
 
@@ -63,6 +63,10 @@ The Dynamic Tables Framework implements the following ACPI table generators:
             The SSDT CMN-600 generator collates the CMN-600 information
             from the Configuration Manager and patches the SSDT CMN-600
             template to build the SSDT CMN-600 table.
+  - SSDT Cpu-Topology:
+            The SSDT Cpu-Topology generator collates the cpu and LPI
+            information from the Configuration Manager and generates a
+            SSDT table describing the CPU hierarchy.
 */
 
 /** The ACPI_TABLE_GENERATOR_ID type describes ACPI table generator ID.
@@ -88,6 +92,7 @@ typedef enum StdAcpiTableId {
   EStdAcpiTableIdSrat,                          ///< SRAT Generator
   EStdAcpiTableIdSsdtSerialPort,                ///< SSDT Serial-Port Generator
   EStdAcpiTableIdSsdtCmn600,                    ///< SSDT Cmn-600 Generator
+  EStdAcpiTableIdSsdtCpuTopology,               ///< SSDT Cpu Topology
   EStdAcpiTableIdMax
 } ESTD_ACPI_TABLE_ID;
 
diff --git a/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCpuTopologyLibArm/SsdtCpuTopologyGenerator.c b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCpuTopologyLibArm/SsdtCpuTopologyGenerator.c
new file mode 100644
index 000000000000..88db808760f7
--- /dev/null
+++ b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCpuTopologyLibArm/SsdtCpuTopologyGenerator.c
@@ -0,0 +1,1230 @@
+/** @file
+  SSDT Cpu Topology Table Generator.
+
+  Copyright (c) 2021, Arm Limited. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  @par Reference(s):
+    - ACPI 6.3 Specification - January 2019 - s8.4 Declaring Processors
+**/
+
+#include <IndustryStandard/DebugPort2Table.h>
+#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 "SsdtCpuTopologyGenerator.h"
+
+/** ARM standard SSDT Cpu Topology Table Generator.
+
+Requirements:
+  The following Configuration Manager Object(s) are required by
+  this Generator:
+  - EArmObjProcHierarchyInfo
+  - EArmObjGicCInfo
+  - EArmObjCmRef
+  - EArmObjLpiInfo
+*/
+
+/** This macro expands to a function that retrieves the GIC
+    CPU interface Information from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+  EObjNameSpaceArm,
+  EArmObjGicCInfo,
+  CM_ARM_GICC_INFO
+  );
+
+/**
+  This macro expands to a function that retrieves the Processor Hierarchy
+  information from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+  EObjNameSpaceArm,
+  EArmObjProcHierarchyInfo,
+  CM_ARM_PROC_HIERARCHY_INFO
+  );
+
+/**
+  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 Lpi
+  information from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+  EObjNameSpaceArm,
+  EArmObjLpiInfo,
+  CM_ARM_LPI_INFO
+  );
+
+/** Initialize the TokenTable.
+
+  One entry should be allocated for each CM_ARM_PROC_HIERARCHY_INFO
+  structure of the platform. The TokenTable allows to have a mapping:
+  Index <-> CM_OBJECT_TOKEN (to CM_ARM_LPI_INFO structures).
+
+  There will always be less sets of Lpi states (CM_ARM_OBJ_REF)
+  than the number of cpus/clusters (CM_ARM_PROC_HIERARCHY_INFO).
+
+  @param [in]  Generator  The SSDT Cpu Topology generator.
+  @param [in]  Count      Number of entries to allocate in the TokenTable.
+
+  @retval EFI_SUCCESS            Success.
+  @retval EFI_INVALID_PARAMETER  Invalid parameter.
+  @retval EFI_OUT_OF_RESOURCES   Failed to allocate memory.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+TokenTableInitialize (
+  IN  ACPI_CPU_TOPOLOGY_GENERATOR   * Generator,
+  IN  UINT32                          Count
+  )
+{
+  CM_OBJECT_TOKEN   * Table;
+
+  if ((Generator == NULL) ||
+      (Count == 0)        ||
+      (Count >= MAX_INDEX_NAME)) {
+    ASSERT (0);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Table = AllocateZeroPool (sizeof (CM_OBJECT_TOKEN) * Count);
+  if (Table == NULL) {
+    ASSERT (0);
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Generator->TokenTable.Table = Table;
+
+  return EFI_SUCCESS;
+}
+
+/** Free the TokenTable.
+
+  @param [in]  Generator    The SSDT Cpu Topology generator.
+**/
+STATIC
+VOID
+EFIAPI
+TokenTableFree (
+  IN  ACPI_CPU_TOPOLOGY_GENERATOR   * Generator
+  )
+{
+  ASSERT (Generator != NULL);
+  ASSERT (Generator->TokenTable.Table != NULL);
+
+  if (Generator->TokenTable.Table != NULL) {
+    FreePool (Generator->TokenTable.Table);
+  }
+}
+
+/** Add a new entry to the TokenTable and return its index.
+
+  If an entry with Token is already available in the table,
+  return its index without adding a new entry.
+
+  @param [in]  Generator  The SSDT Cpu Topology generator.
+  @param [in]  Token      New Token entry to add.
+
+  @retval The index of the token entry in the TokenTable.
+**/
+STATIC
+UINT32
+EFIAPI
+TokenTableAdd (
+  IN  ACPI_CPU_TOPOLOGY_GENERATOR   * Generator,
+  IN  CM_OBJECT_TOKEN                 Token
+  )
+{
+  CM_OBJECT_TOKEN   * Table;
+  UINT32              Index;
+  UINT32              LastIndex;
+
+  ASSERT (Generator != NULL);
+  ASSERT (Generator->TokenTable.Table != NULL);
+
+  Table = Generator->TokenTable.Table;
+  LastIndex = Generator->TokenTable.LastIndex;
+
+  // Search if there is already an entry with this Token.
+  for (Index = 0; Index < LastIndex; Index++) {
+    if (Table[Index] == Token) {
+      return Index;
+    }
+  }
+
+  ASSERT (LastIndex < MAX_INDEX_NAME);
+  ASSERT (LastIndex < Generator->ProcNodeCount);
+
+  // If no, create a new entry.
+  Table[LastIndex] = Token;
+
+  return Generator->TokenTable.LastIndex++;
+}
+
+/** Write a string 'Xxxx\0' in AslName (5 bytes long),
+  with 'X' being the leading char of the name, and
+  with 'xxx' being Value in hexadecimal.
+
+  As 'xxx' in hexadecimal represents a number on 12 bits,
+  we have Value < (2 << 12)
+
+  @param [in]       LeadChar  Leading char of the name.
+  @param [in]       Value     Hex value of the name.
+                              Must be lower than (2 << 12).
+  @param [in, out]  AslName   Pointer to write the 'Xxxx' string to.
+                              Must be at least 5 bytes long.
+
+  @retval EFI_SUCCESS               Success.
+  @retval EFI_INVALID_PARAMETER     Invalid parameter.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+WriteAslName (
+  IN      CHAR8     LeadChar,
+  IN      UINT32    Value,
+  IN OUT  CHAR8   * AslName
+  )
+{
+  UINT8   Index;
+
+  if ((Value >= MAX_INDEX_NAME)  ||
+      (AslName == NULL)) {
+    ASSERT (0);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  AslName[0] = LeadChar;
+  AslName[AML_NAME_SEG_SIZE] = '\0';
+
+  for (Index = 0; Index < AML_NAME_SEG_SIZE - 1; Index++) {
+    AslName[AML_NAME_SEG_SIZE - Index - 1] =
+      AsciiFromHex (((Value >> (4 * Index)) & 0xF));
+  }
+
+  return EFI_SUCCESS;
+}
+
+/** Create and add an _LPI method to Cpu/Cluster Node.
+
+  For instance, transform an AML node from:
+  Device (C002)
+  {
+      Name (_UID, 2)
+      Name (_HID, "ACPI0007")
+  }
+
+  To:
+  Device (C002)
+  {
+      Name (_UID, 2)
+      Name (_HID, "ACPI0007")
+      Method (_LPI, 0, NotSerialized)
+      {
+          Return (\_SB.L003)
+      }
+  }
+
+  @param [in]  Generator              The SSDT Cpu Topology generator.
+  @param [in]  ProcHierarchyNodeInfo  CM_ARM_PROC_HIERARCHY_INFO describing
+                                      the Cpu.
+  @param [in]  Node                   Node to which the _LPI method is
+                                      attached. Can represent a Cpu or a
+                                      Cluster.
+
+  @retval EFI_SUCCESS             The function completed successfully.
+  @retval EFI_INVALID_PARAMETER   Invalid parameter.
+  @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+CreateAmlLpiMethod (
+  IN  ACPI_CPU_TOPOLOGY_GENERATOR   * Generator,
+  IN  CM_ARM_PROC_HIERARCHY_INFO    * ProcHierarchyNodeInfo,
+  IN  AML_OBJECT_NODE_HANDLE        * Node
+  )
+{
+  EFI_STATUS    Status;
+  UINT32        TokenIndex;
+  CHAR8         AslName[SB_SCOPE_PREFIX_SIZE + AML_NAME_SEG_SIZE];
+
+  ASSERT (Generator != NULL);
+  ASSERT (ProcHierarchyNodeInfo != NULL);
+  ASSERT (ProcHierarchyNodeInfo->LpiToken != CM_NULL_TOKEN);
+  ASSERT (Node != NULL);
+
+  TokenIndex = TokenTableAdd (Generator, ProcHierarchyNodeInfo->LpiToken);
+
+  CopyMem (AslName, SB_SCOPE_PREFIX, SB_SCOPE_PREFIX_SIZE);
+
+  Status = WriteAslName (
+             'L',
+             TokenIndex,
+             AslName + SB_SCOPE_PREFIX_SIZE - 1
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    return Status;
+  }
+
+  // ASL:
+  // Method (_LPI, 0) {
+  //   Return ([AslName])
+  // }
+  Status = AmlCodeGenMethodRetNameString (
+             "_LPI",
+             AslName,
+             0,
+             FALSE,
+             0,
+             Node,
+             NULL
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+  }
+
+  return Status;
+}
+
+/** Generate all the Lpi states under the '_SB' scope.
+
+  This function generates the following ASL code:
+  Scope (\_SB) {
+    Name (L000, Package() {
+      0, // Version
+      0, // Level Index
+      X, // Count
+      Package() {
+        [An Lpi state]
+      },
+      Package() {
+        [Another Lpi state]
+      },
+    } // Name L000
+
+    Name (L001, Package() {
+      ...
+    } // Name L001
+
+    ...
+  } // Scope /_SB
+
+  The Lpi states are fetched from the Configuration Manager.
+  The names of the Lpi states are generated from the TokenTable.
+
+  @param [in]  Generator        The SSDT Cpu Topology generator.
+  @param [in]  CfgMgrProtocol   Pointer to the Configuration Manager
+                                Protocol Interface.
+  @param [in] ScopeNode         Scope node handle ('\_SB' scope).
+
+  @retval EFI_SUCCESS             Success.
+  @retval EFI_INVALID_PARAMETER   Invalid parameter.
+  @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GenerateLpiStates (
+  IN        ACPI_CPU_TOPOLOGY_GENERATOR           *       Generator,
+  IN  CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL  * CONST CfgMgrProtocol,
+  IN        AML_OBJECT_NODE_HANDLE                        ScopeNode
+  )
+{
+  EFI_STATUS                Status;
+
+  UINT32                    Index;
+  UINT32                    LastIndex;
+
+  AML_OBJECT_NODE_HANDLE    LpiNode;
+  CM_ARM_OBJ_REF          * LpiRefInfo;
+  UINT32                    LpiRefInfoCount;
+  UINT32                    LpiRefIndex;
+  CM_ARM_LPI_INFO         * LpiInfo;
+  CHAR8                     AslName[AML_NAME_SEG_SIZE + 1];
+
+  ASSERT (Generator != NULL);
+  ASSERT (Generator->TokenTable.Table != NULL);
+  ASSERT (CfgMgrProtocol != NULL);
+  ASSERT (ScopeNode != NULL);
+
+  LastIndex = Generator->TokenTable.LastIndex;
+
+  // For each entry in the TokenTable, create a name in the AML namespace
+  // under SB_SCOPE, to store the Lpi states associated with the LpiToken.
+  for (Index = 0; Index < LastIndex; Index++) {
+    Status = WriteAslName ('L', Index, AslName);
+    if (EFI_ERROR (Status)) {
+      ASSERT (0);
+      return Status;
+    }
+
+    // We do not support the LevelId field for now, let it to 0.
+    Status = AmlCreateLpiNode (AslName, 1, 0, ScopeNode, &LpiNode);
+    if (EFI_ERROR (Status)) {
+      ASSERT (0);
+      return Status;
+    }
+
+    // Fetch the LPI objects referenced by the token.
+    Status = GetEArmObjCmRef (
+               CfgMgrProtocol,
+               Generator->TokenTable.Table[Index],
+               &LpiRefInfo,
+               &LpiRefInfoCount
+               );
+    if (EFI_ERROR (Status)) {
+      ASSERT (0);
+      return Status;
+    }
+
+    for (LpiRefIndex = 0; LpiRefIndex < LpiRefInfoCount; LpiRefIndex++) {
+      // For each CM_ARM_LPI_INFO referenced by the token, add an Lpi state.
+      Status = GetEArmObjLpiInfo (
+                 CfgMgrProtocol,
+                 LpiRefInfo[LpiRefIndex].ReferenceToken,
+                 &LpiInfo,
+                 NULL
+                 );
+      if (EFI_ERROR (Status)) {
+        ASSERT (0);
+        return Status;
+      }
+
+      Status = AmlAddLpiState (
+                 LpiInfo->MinResidency,
+                 LpiInfo->WorstCaseWakeLatency,
+                 LpiInfo->Flags,
+                 LpiInfo->ArchFlags,
+                 LpiInfo->ResCntFreq,
+                 LpiInfo->EnableParentState,
+                 LpiInfo->IsInteger ?
+                   NULL :
+                   &LpiInfo->RegisterEntryMethod,
+                 LpiInfo->IsInteger ?
+                   LpiInfo->IntegerEntryMethod :
+                   0,
+                 &LpiInfo->ResidencyCounterRegister,
+                 &LpiInfo->UsageCounterRegister,
+                 LpiInfo->StateName,
+                 LpiNode
+                 );
+      if (EFI_ERROR (Status)) {
+        ASSERT (0);
+        return Status;
+      }
+    } // for LpiRefIndex
+  } // for Index
+
+  return EFI_SUCCESS;
+}
+
+/** Create a Cpu in the AML namespace.
+
+  This generates the following ASL code:
+  Device (C002)
+  {
+      Name (_UID, 2)
+      Name (_HID, "ACPI0007")
+  }
+
+  @param [in]  Generator    The SSDT Cpu Topology generator.
+  @param [in]  ParentNode   Parent node to attach the Cpu node to.
+  @param [in]  GicCInfo     CM_ARM_GICC_INFO object used to create the node.
+  @param [in]  CpuIndex     Index used to generate the node name.
+  @param [out] CpuNodePtr   If not NULL, return the created Cpu node.
+
+  @retval EFI_SUCCESS             Success.
+  @retval EFI_INVALID_PARAMETER   Invalid parameter.
+  @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+CreateAmlCpu (
+  IN   ACPI_CPU_TOPOLOGY_GENERATOR   * Generator,
+  IN   AML_NODE_HANDLE                 ParentNode,
+  IN   CM_ARM_GICC_INFO              * GicCInfo,
+  IN   UINT32                          CpuIndex,
+  OUT  AML_OBJECT_NODE_HANDLE        * CpuNodePtr OPTIONAL
+  )
+{
+  EFI_STATUS                Status;
+  AML_OBJECT_NODE_HANDLE    CpuNode;
+  CHAR8                     AslName[AML_NAME_SEG_SIZE + 1];
+
+  ASSERT (Generator != NULL);
+  ASSERT (ParentNode != NULL);
+  ASSERT (GicCInfo != NULL);
+
+  Status = WriteAslName ('C', CpuIndex, AslName);
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    return Status;
+  }
+
+  Status = AmlCodeGenDevice (AslName, ParentNode, &CpuNode);
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    return Status;
+  }
+
+  Status = AmlCodeGenNameInteger (
+             "_UID",
+             GicCInfo->AcpiProcessorUid,
+             CpuNode,
+             NULL
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    return Status;
+  }
+
+  Status = AmlCodeGenNameString (
+             "_HID",
+             ACPI_HID_PROCESSOR_DEVICE,
+             CpuNode,
+             NULL
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    return Status;
+  }
+
+  // If requested, return the handle to the CpuNode.
+  if (CpuNodePtr != NULL) {
+    *CpuNodePtr = CpuNode;
+  }
+
+  return Status;
+}
+
+/** Create a Cpu in the AML namespace from a CM_ARM_PROC_HIERARCHY_INFO
+    CM object.
+
+  @param [in]  Generator              The SSDT Cpu Topology generator.
+  @param [in]  CfgMgrProtocol         Pointer to the Configuration Manager
+                                      Protocol Interface.
+  @param [in]  ParentNode             Parent node to attach the Cpu node to.
+  @param [in]  CpuIndex               Index used to generate the node name.
+  @param [in]  ProcHierarchyNodeInfo  CM_ARM_PROC_HIERARCHY_INFO describing
+                                      the Cpu.
+
+  @retval EFI_SUCCESS             Success.
+  @retval EFI_INVALID_PARAMETER   Invalid parameter.
+  @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+CreateAmlCpuFromProcHierarchy (
+  IN        ACPI_CPU_TOPOLOGY_GENERATOR           *       Generator,
+  IN  CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL  * CONST CfgMgrProtocol,
+  IN        AML_NODE_HANDLE                               ParentNode,
+  IN        UINT32                                        CpuIndex,
+  IN        CM_ARM_PROC_HIERARCHY_INFO            *       ProcHierarchyNodeInfo
+  )
+{
+  EFI_STATUS                Status;
+  CM_ARM_GICC_INFO        * GicCInfo;
+  AML_OBJECT_NODE_HANDLE    CpuNode;
+
+  ASSERT (Generator != NULL);
+  ASSERT (CfgMgrProtocol != NULL);
+  ASSERT (ParentNode != NULL);
+  ASSERT (ProcHierarchyNodeInfo != NULL);
+  ASSERT (ProcHierarchyNodeInfo->GicCToken != CM_NULL_TOKEN);
+
+  Status = GetEArmObjGicCInfo (
+             CfgMgrProtocol,
+             ProcHierarchyNodeInfo->GicCToken,
+             &GicCInfo,
+             NULL
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    return Status;
+  }
+
+  Status = CreateAmlCpu (Generator, ParentNode, GicCInfo, CpuIndex, &CpuNode);
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    return Status;
+  }
+
+  // If a set of Lpi states is associated with the
+  // CM_ARM_PROC_HIERARCHY_INFO, create an _LPI method returning them.
+  if (ProcHierarchyNodeInfo->LpiToken != CM_NULL_TOKEN) {
+    Status = CreateAmlLpiMethod (Generator, ProcHierarchyNodeInfo, CpuNode);
+    ASSERT_EFI_ERROR (Status);
+  }
+
+  return Status;
+}
+
+/** Create a Cluster in the AML namespace.
+
+  Any CM_ARM_PROC_HIERARCHY_INFO object with the following flags is
+  assumed to be a cluster:
+   - EFI_ACPI_6_3_PPTT_PACKAGE_NOT_PHYSICAL
+   - EFI_ACPI_6_3_PPTT_PROCESSOR_ID_INVALID
+   - EFI_ACPI_6_3_PPTT_NODE_IS_NOT_LEAF
+
+  This generates the following ASL code:
+  Device (C002)
+  {
+      Name (_UID, 2)
+      Name (_HID, "ACPI0010")
+  }
+
+  @param [in]  Generator              The SSDT Cpu Topology generator.
+  @param [in]  CfgMgrProtocol         Pointer to the Configuration Manager
+                                      Protocol Interface.
+  @param [in]  ParentNode             Parent node to attach the Cluster
+                                      node to.
+  @param [in]  ProcHierarchyNodeInfo  CM_ARM_PROC_HIERARCHY_INFO object used
+                                      to create the node.
+  @param [in]  ClusterIndex           Index used to generate the node name.
+  @param [out] ClusterNodePtr         If success, contains the created Cluster
+                                      node.
+
+  @retval EFI_SUCCESS             Success.
+  @retval EFI_INVALID_PARAMETER   Invalid parameter.
+  @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+CreateAmlCluster (
+  IN        ACPI_CPU_TOPOLOGY_GENERATOR           *       Generator,
+  IN  CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL  * CONST CfgMgrProtocol,
+  IN        AML_NODE_HANDLE                               ParentNode,
+  IN        CM_ARM_PROC_HIERARCHY_INFO            *       ProcHierarchyNodeInfo,
+  IN        UINT32                                        ClusterIndex,
+  OUT       AML_OBJECT_NODE_HANDLE                *       ClusterNodePtr
+  )
+{
+  EFI_STATUS                Status;
+  AML_OBJECT_NODE_HANDLE    ClusterNode;
+  CHAR8                     AslNameCluster[AML_NAME_SEG_SIZE + 1];
+
+  ASSERT (Generator != NULL);
+  ASSERT (CfgMgrProtocol != NULL);
+  ASSERT (ParentNode != NULL);
+  ASSERT (ProcHierarchyNodeInfo != NULL);
+  ASSERT (ClusterNodePtr != NULL);
+
+  Status = WriteAslName ('C', ClusterIndex, AslNameCluster);
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    return Status;
+  }
+
+  Status = AmlCodeGenDevice (AslNameCluster, ParentNode, &ClusterNode);
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    return Status;
+  }
+
+  // Use the ClusterIndex for the _UID value as there is no AcpiProcessorUid
+  // and EFI_ACPI_6_3_PPTT_PROCESSOR_ID_INVALID is set for non-Cpus.
+  Status = AmlCodeGenNameInteger (
+             "_UID",
+             ClusterIndex,
+             ClusterNode,
+             NULL
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    return Status;
+  }
+
+  Status = AmlCodeGenNameString (
+             "_HID",
+             ACPI_HID_PROCESSOR_CONTAINER_DEVICE,
+             ClusterNode,
+             NULL
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    return Status;
+  }
+
+  // If a set of Lpi states are associated with the
+  // CM_ARM_PROC_HIERARCHY_INFO, create an _LPI method returning them.
+  if (ProcHierarchyNodeInfo->LpiToken != CM_NULL_TOKEN) {
+    Status = CreateAmlLpiMethod (
+               Generator,
+               ProcHierarchyNodeInfo,
+               ClusterNode
+               );
+    if (EFI_ERROR (Status)) {
+      ASSERT (0);
+      return Status;
+    }
+  }
+
+  *ClusterNodePtr = ClusterNode;
+
+  return Status;
+}
+
+/** Create an AML representation of the Cpu topology.
+
+  A cluster is by extension any non-leave device in the cpu topology.
+
+  @param [in] Generator          The SSDT Cpu Topology generator.
+  @param [in] CfgMgrProtocol     Pointer to the Configuration Manager
+                                 Protocol Interface.
+  @param [in] NodeToken          Token of the CM_ARM_PROC_HIERARCHY_INFO
+                                 currently handled.
+                                 Cannot be CM_NULL_TOKEN.
+  @param [in] ParentNode         Parent node to attach the created
+                                 node to.
+
+  @retval EFI_SUCCESS             Success.
+  @retval EFI_INVALID_PARAMETER   Invalid parameter.
+  @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+CreateAmlCpuTopologyTree (
+  IN        ACPI_CPU_TOPOLOGY_GENERATOR           *       Generator,
+  IN  CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL  * CONST CfgMgrProtocol,
+  IN        CM_OBJECT_TOKEN                               NodeToken,
+  IN        AML_NODE_HANDLE                               ParentNode
+  )
+{
+  EFI_STATUS              Status;
+  UINT32                  Index;
+  UINT32                  CpuIndex;
+  UINT32                  ClusterIndex;
+  AML_OBJECT_NODE_HANDLE  ClusterNode;
+
+  ASSERT (Generator != NULL);
+  ASSERT (Generator->ProcNodeList != NULL);
+  ASSERT (Generator->ProcNodeCount != 0);
+  ASSERT (CfgMgrProtocol != NULL);
+  ASSERT (NodeToken != CM_NULL_TOKEN);
+  ASSERT (ParentNode != NULL);
+
+  CpuIndex = 0;
+  ClusterIndex = 0;
+
+  for (Index = 0; Index < Generator->ProcNodeCount; Index++) {
+    // Find the children of the CM_ARM_PROC_HIERARCHY_INFO
+    // currently being handled (i.e. ParentToken == NodeToken).
+    if (Generator->ProcNodeList[Index].ParentToken == NodeToken) {
+
+      // Only Cpus (leaves in this tree) have a GicCToken.
+      // Create a Cpu node.
+      if (Generator->ProcNodeList[Index].GicCToken != CM_NULL_TOKEN) {
+        if ((Generator->ProcNodeList[Index].Flags & PPTT_PROCESSOR_MASK) !=
+             PPTT_CPU_PROCESSOR_MASK) {
+          DEBUG ((
+            DEBUG_ERROR,
+            "ERROR: SSDT-CPU-TOPOLOGY: Invalid flags for cpu: 0x%x.\n",
+            Generator->ProcNodeList[Index].Flags
+            ));
+          ASSERT (0);
+          return EFI_INVALID_PARAMETER;
+        }
+
+        Status = CreateAmlCpuFromProcHierarchy (
+                   Generator,
+                   CfgMgrProtocol,
+                   ParentNode,
+                   CpuIndex,
+                   &Generator->ProcNodeList[Index]
+                   );
+        if (EFI_ERROR (Status)) {
+          ASSERT (0);
+          return Status;
+        }
+
+        CpuIndex++;
+
+      } else {
+        // If this is not a Cpu, then this is a cluster.
+
+        // Acpi processor Id for clusters is not handled.
+        if ((Generator->ProcNodeList[Index].Flags & PPTT_PROCESSOR_MASK) !=
+             PPTT_CLUSTER_PROCESSOR_MASK) {
+          DEBUG ((
+            DEBUG_ERROR,
+            "ERROR: SSDT-CPU-TOPOLOGY: Invalid flags for cluster: 0x%x.\n",
+            Generator->ProcNodeList[Index].Flags
+            ));
+          ASSERT (0);
+          return EFI_INVALID_PARAMETER;
+        }
+
+        Status = CreateAmlCluster (
+                   Generator,
+                   CfgMgrProtocol,
+                   ParentNode,
+                   &Generator->ProcNodeList[Index],
+                   ClusterIndex,
+                   &ClusterNode
+                   );
+        if (EFI_ERROR (Status)) {
+          ASSERT (0);
+          return Status;
+        }
+
+        // Nodes must have a unique name in the ASL namespace.
+        // Reset the Cpu index whenever we create a new Cluster.
+        ClusterIndex++;
+        CpuIndex = 0;
+
+        // Recursively continue creating an AML tree.
+        Status = CreateAmlCpuTopologyTree (
+                   Generator,
+                   CfgMgrProtocol,
+                   Generator->ProcNodeList[Index].Token,
+                   ClusterNode
+                   );
+        if (EFI_ERROR (Status)) {
+          ASSERT (0);
+          return Status;
+        }
+      }
+    } // if ParentToken == NodeToken
+  } // for
+
+  return EFI_SUCCESS;
+}
+
+/** Create the processor hierarchy AML tree from CM_ARM_PROC_HIERARCHY_INFO
+    CM objects.
+
+  @param [in] Generator        The SSDT Cpu Topology generator.
+  @param [in] CfgMgrProtocol   Pointer to the Configuration Manager
+                               Protocol Interface.
+  @param [in] ScopeNode        Scope node handle ('\_SB' scope).
+
+  @retval EFI_SUCCESS             Success.
+  @retval EFI_INVALID_PARAMETER   Invalid parameter.
+  @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+CreateTopologyFromProcHierarchy (
+  IN        ACPI_CPU_TOPOLOGY_GENERATOR           *       Generator,
+  IN  CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL  * CONST CfgMgrProtocol,
+  IN        AML_OBJECT_NODE_HANDLE                        ScopeNode
+  )
+{
+  EFI_STATUS  Status;
+  UINT32      Index;
+  UINT32      TopLevelProcNodeIndex;
+
+  ASSERT (Generator != NULL);
+  ASSERT (Generator->ProcNodeCount != 0);
+  ASSERT (Generator->ProcNodeList != NULL);
+  ASSERT (CfgMgrProtocol != NULL);
+  ASSERT (ScopeNode != NULL);
+
+  TopLevelProcNodeIndex = -1;
+
+  Status = TokenTableInitialize (Generator, Generator->ProcNodeCount);
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    return Status;
+  }
+
+  // It is assumed that there is one unique CM_ARM_PROC_HIERARCHY_INFO
+  // structure with no ParentToken and the EFI_ACPI_6_3_PPTT_PACKAGE_PHYSICAL
+  // flag set. All other CM_ARM_PROC_HIERARCHY_INFO are non-physical and
+  // have a ParentToken.
+  for (Index = 0; Index < Generator->ProcNodeCount; Index++) {
+    if ((Generator->ProcNodeList[Index].ParentToken == CM_NULL_TOKEN) &&
+        (Generator->ProcNodeList[Index].Flags &
+          EFI_ACPI_6_3_PPTT_PACKAGE_PHYSICAL)) {
+      if (TopLevelProcNodeIndex != -1) {
+        DEBUG ((
+          DEBUG_ERROR,
+          "ERROR: SSDT-CPU-TOPOLOGY: Top level CM_ARM_PROC_HIERARCHY_INFO "
+          "must be unique\n"
+          ));
+        ASSERT (0);
+        goto exit_handler;
+      }
+      TopLevelProcNodeIndex = Index;
+    }
+  } // for
+
+  Status = CreateAmlCpuTopologyTree (
+             Generator,
+             CfgMgrProtocol,
+             Generator->ProcNodeList[TopLevelProcNodeIndex].Token,
+             ScopeNode
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto exit_handler;
+  }
+
+  Status = GenerateLpiStates (Generator, CfgMgrProtocol, ScopeNode);
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto exit_handler;
+  }
+
+exit_handler:
+  TokenTableFree (Generator);
+  return Status;
+}
+
+/** Create the processor hierarchy AML tree from CM_ARM_GICC_INFO
+    CM objects.
+
+  A cluster is by extension any non-leave device in the cpu topology.
+
+  @param [in] Generator        The SSDT Cpu Topology generator.
+  @param [in] CfgMgrProtocol   Pointer to the Configuration Manager
+                               Protocol Interface.
+  @param [in] ScopeNode        Scope node handle ('\_SB' scope).
+
+  @retval EFI_SUCCESS             Success.
+  @retval EFI_INVALID_PARAMETER   Invalid parameter.
+  @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+CreateTopologyFromGicC (
+  IN        ACPI_CPU_TOPOLOGY_GENERATOR           *       Generator,
+  IN  CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL  * CONST CfgMgrProtocol,
+  IN        AML_OBJECT_NODE_HANDLE                        ScopeNode
+  )
+{
+  EFI_STATUS            Status;
+  CM_ARM_GICC_INFO    * GicCInfo;
+  UINT32                GicCInfoCount;
+  UINT32                Index;
+
+  ASSERT (Generator != NULL);
+  ASSERT (CfgMgrProtocol != NULL);
+  ASSERT (ScopeNode != NULL);
+
+  Status = GetEArmObjGicCInfo (
+             CfgMgrProtocol,
+             CM_NULL_TOKEN,
+             &GicCInfo,
+             &GicCInfoCount
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    return Status;
+  }
+
+  // For each CM_ARM_GICC_INFO object, create an AML node.
+  for (Index = 0; Index < GicCInfoCount; Index++) {
+    Status = CreateAmlCpu (
+               Generator,
+               ScopeNode,
+               &GicCInfo[Index],
+               Index,
+               NULL
+               );
+    if (EFI_ERROR (Status)) {
+      ASSERT (0);
+      break;
+    }
+  } // for
+
+  return Status;
+}
+
+/** Construct the SSDT Cpu Topology ACPI table.
+
+  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 FreeXXXXTableResources function.
+
+  @param [in]  This           Pointer to the table generator.
+  @param [in]  AcpiTableInfo  Pointer to the ACPI Table Info.
+  @param [in]  CfgMgrProtocol Pointer to the Configuration Manager
+                              Protocol Interface.
+  @param [out] Table          Pointer to the constructed ACPI Table.
+
+  @retval EFI_SUCCESS           Table generated successfully.
+  @retval EFI_INVALID_PARAMETER A parameter is invalid.
+  @retval EFI_NOT_FOUND         The required object was not found.
+  @retval EFI_BAD_BUFFER_SIZE   The size returned by the Configuration
+                                Manager is less than the Object size for the
+                                requested object.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+BuildSsdtCpuTopologyTable (
+  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,
+  OUT       EFI_ACPI_DESCRIPTION_HEADER          ** CONST Table
+  )
+{
+  EFI_STATUS                      Status;
+  AML_ROOT_NODE_HANDLE            RootNode;
+  AML_OBJECT_NODE_HANDLE          ScopeNode;
+  CM_ARM_PROC_HIERARCHY_INFO    * ProcHierarchyNodeList;
+  UINT32                          ProcHierarchyNodeCount;
+  ACPI_CPU_TOPOLOGY_GENERATOR   * Generator;
+
+  ASSERT (This != NULL);
+  ASSERT (AcpiTableInfo != NULL);
+  ASSERT (CfgMgrProtocol != NULL);
+  ASSERT (Table != NULL);
+  ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
+  ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
+
+  Generator = (ACPI_CPU_TOPOLOGY_GENERATOR*)This;
+
+  Status = AmlCodeGenDefinitionBlock (
+             "SSDT",
+             "ARMLTD",
+             "CPU-TOPO",
+             1,
+             &RootNode
+             );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = AmlCodeGenScope (SB_SCOPE, RootNode, &ScopeNode);
+  if (EFI_ERROR (Status)) {
+    goto exit_handler;
+  }
+
+  // Get the processor hierarchy info and update the processor topology
+  // structure count with Processor Hierarchy Nodes (Type 0)
+  Status = GetEArmObjProcHierarchyInfo (
+             CfgMgrProtocol,
+             CM_NULL_TOKEN,
+             &ProcHierarchyNodeList,
+             &ProcHierarchyNodeCount
+             );
+  if (EFI_ERROR (Status) &&
+      (Status != EFI_NOT_FOUND)) {
+    goto exit_handler;
+  }
+
+  if (Status == EFI_NOT_FOUND) {
+    // If hierarchy information is not found generate a flat topology
+    // using CM_ARM_GICC_INFO objects.
+    Status = CreateTopologyFromGicC (
+               Generator,
+               CfgMgrProtocol,
+               ScopeNode
+               );
+    if (EFI_ERROR (Status)) {
+      goto exit_handler;
+    }
+  } else {
+    // Generate the topology from CM_ARM_PROC_HIERARCHY_INFO objects.
+    Generator->ProcNodeList = ProcHierarchyNodeList;
+    Generator->ProcNodeCount = ProcHierarchyNodeCount;
+
+    Status = CreateTopologyFromProcHierarchy (
+               Generator,
+               CfgMgrProtocol,
+               ScopeNode
+               );
+    if (EFI_ERROR (Status)) {
+      goto exit_handler;
+    }
+  }
+
+  Status = AmlSerializeDefinitionBlock (
+             RootNode,
+             Table
+             );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "ERROR: SSDT-CPU-TOPOLOGY: Failed to Serialize SSDT Table Data."
+      " Status = %r\n",
+      Status
+      ));
+    goto exit_handler;
+  }
+
+exit_handler:
+  // Delete the RootNode and its attached children.
+  return AmlDeleteTree (RootNode);
+}
+
+/** Free any resources allocated for constructing the
+    SSDT Cpu Topology ACPI table.
+
+  @param [in]      This           Pointer to the 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 the ACPI Table.
+
+  @retval EFI_SUCCESS           The resources were freed successfully.
+  @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
+**/
+STATIC
+EFI_STATUS
+FreeSsdtCpuTopologyTableResources (
+  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
+  )
+{
+  ASSERT (This != NULL);
+  ASSERT (AcpiTableInfo != NULL);
+  ASSERT (CfgMgrProtocol != NULL);
+  ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
+  ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
+
+  if ((Table == NULL) || (*Table == NULL)) {
+    DEBUG ((DEBUG_ERROR, "ERROR: SSDT-CPU-TOPOLOGY: Invalid Table Pointer\n"));
+    ASSERT ((Table != NULL) && (*Table != NULL));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  FreePool (*Table);
+  *Table = NULL;
+  return EFI_SUCCESS;
+}
+
+/** This macro defines the SSDT Cpu Topology Table Generator revision.
+*/
+#define SSDT_CPU_TOPOLOGY_GENERATOR_REVISION CREATE_REVISION (1, 0)
+
+/** The interface for the SSDT Cpu Topology Table Generator.
+*/
+STATIC
+ACPI_CPU_TOPOLOGY_GENERATOR SsdtCpuTopologyGenerator = {
+  // ACPI table generator header
+  {
+    // Generator ID
+    CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdSsdtCpuTopology),
+    // Generator Description
+    L"ACPI.STD.SSDT.CPU.TOPOLOGY.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_CPU_TOPOLOGY_GENERATOR_REVISION,
+    // Build Table function
+    BuildSsdtCpuTopologyTable,
+    // Free Resource function
+    FreeSsdtCpuTopologyTableResources,
+    // Extended build function not needed
+    NULL,
+    // Extended build function not implemented by the generator.
+    // Hence extended free resource function is not required.
+    NULL
+  },
+
+  // Private fields are defined from here.
+
+  // TokenTable
+  {
+      // Table
+      NULL,
+      // LastIndex
+      0
+  },
+  // ProcNodeList
+  NULL,
+  // ProcNodeCount
+  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
+AcpiSsdtCpuTopologyLibConstructor (
+  IN  EFI_HANDLE           ImageHandle,
+  IN  EFI_SYSTEM_TABLE  *  SystemTable
+  )
+{
+  EFI_STATUS  Status;
+  Status = RegisterAcpiTableGenerator (&SsdtCpuTopologyGenerator.Header);
+  DEBUG ((
+    DEBUG_INFO,
+    "SSDT-CPU-TOPOLOGY: 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
+AcpiSsdtCpuTopologyLibDestructor (
+  IN  EFI_HANDLE           ImageHandle,
+  IN  EFI_SYSTEM_TABLE  *  SystemTable
+  )
+{
+  EFI_STATUS  Status;
+  Status = DeregisterAcpiTableGenerator (&SsdtCpuTopologyGenerator.Header);
+  DEBUG ((
+    DEBUG_INFO,
+    "SSDT-CPU-TOPOLOGY: Deregister Generator. Status = %r\n",
+    Status
+    ));
+  ASSERT_EFI_ERROR (Status);
+  return Status;
+}
diff --git a/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCpuTopologyLibArm/SsdtCpuTopologyGenerator.h b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCpuTopologyLibArm/SsdtCpuTopologyGenerator.h
new file mode 100644
index 000000000000..95930a86b186
--- /dev/null
+++ b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCpuTopologyLibArm/SsdtCpuTopologyGenerator.h
@@ -0,0 +1,134 @@
+/** @file
+  SSDT Cpu Topology Table Generator.
+
+  Copyright (c) 2021, Arm Limited. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  @par Reference(s):
+    - ACPI 6.3 Specification - January 2019 - s8.4 Declaring Processors
+**/
+
+#ifndef SSDT_CPU_TOPOLOGY_GENERATOR_H_
+#define SSDT_CPU_TOPOLOGY_GENERATOR_H_
+
+#pragma pack(1)
+
+// Mask for the flags that need to be checked.
+#define PPTT_PROCESSOR_MASK   (                                               \
+          (EFI_ACPI_6_3_PPTT_PACKAGE_PHYSICAL)          |                     \
+          (EFI_ACPI_6_3_PPTT_PROCESSOR_ID_VALID << 1)   |                     \
+          (EFI_ACPI_6_3_PPTT_NODE_IS_LEAF << 3))
+
+// Mask for the cpu flags.
+#define PPTT_CPU_PROCESSOR_MASK   (                                           \
+          (EFI_ACPI_6_3_PPTT_PACKAGE_NOT_PHYSICAL)      |                     \
+          (EFI_ACPI_6_3_PPTT_PROCESSOR_ID_VALID << 1)   |                     \
+          (EFI_ACPI_6_3_PPTT_NODE_IS_LEAF << 3))
+
+// Mask for the cluster flags.
+// Even though a _UID is generated for clusters, it is simpler to use
+// EFI_ACPI_6_3_PPTT_PROCESSOR_ID_INVALID and to not match the cluster id of
+// the PPTT table (not sure the PPTT table is generated).
+#define PPTT_CLUSTER_PROCESSOR_MASK   (                                       \
+          (EFI_ACPI_6_3_PPTT_PACKAGE_NOT_PHYSICAL)      |                     \
+          (EFI_ACPI_6_3_PPTT_PROCESSOR_ID_INVALID << 1) |                     \
+          (EFI_ACPI_6_3_PPTT_NODE_IS_NOT_LEAF << 3))
+
+/** LPI states are stored in the ASL namespace at '\_SB_.Lxxx',
+    with xxx being the node index of the LPI state.
+*/
+#define SB_SCOPE                            "\\_SB_"
+#define SB_SCOPE_PREFIX                     SB_SCOPE "."
+/// Size of the SB_SCOPE_PREFIX string.
+#define SB_SCOPE_PREFIX_SIZE                sizeof (SB_SCOPE_PREFIX)
+
+/// HID for a processor device.
+#define ACPI_HID_PROCESSOR_DEVICE           "ACPI0007"
+
+/// HID for a processor container device.
+#define ACPI_HID_PROCESSOR_CONTAINER_DEVICE "ACPI0010"
+
+/** Node names of Cpus and Clusters are 'Cxxx', and 'Lxxx' for LPI states.
+    The 'xxx' is an index on 12 bits is given to node name,
+    thus the limitation in the number of nodes.
+*/
+#define MAX_INDEX_NAME                      (1 << 12)
+
+/** A structure used to handle the Lpi structures referencing.
+
+  A CM_ARM_PROC_HIERARCHY_INFO structure references a CM_ARM_OBJ_REF.
+  This CM_ARM_OBJ_REF references CM_ARM_LPI_INFO structures.
+
+  Example:
+  (Cpu0)                                   (Cpu1)
+  CM_ARM_PROC_HIERARCHY_INFO               CM_ARM_PROC_HIERARCHY_INFO
+              |                                       |
+              +----------------------------------------
+              |
+              v
+  (List of references to Lpi states)
+  CM_ARM_OBJ_REF
+              |
+              +----------------------------------------
+              |                                       |
+              v                                       v
+  (A first Lpi state)                       (A second Lpi state)
+  CM_ARM_LPI_INFO[0]                        CM_ARM_LPI_INFO[1]
+
+  Here, Cpu0 and Cpu1 have the same Lpi states. Both CM_ARM_PROC_HIERARCHY_INFO
+  structures reference the same CM_ARM_OBJ_REF. An entry is created in the
+  TokenTable such as:
+  0 <-> CM_ARM_OBJ_REF
+
+  This will lead to the creation of this pseudo-ASL code where Cpu0 and Cpu1
+  return the same object at \_SB.L000:
+  Scope (\_SB) {
+    Device (C000) {
+      [...]
+      Method (_LPI) {
+        Return (\_SB.L000)
+      }
+    } // C000
+
+    Device (C001) {
+      [...]
+      Method (_LPI) {
+        Return (\_SB.L000)
+      }
+    } // C001
+
+    // Lpi states
+    Name (L000, Package (0x05) {
+      [...]
+    }
+  }
+*/
+typedef struct TokenTable {
+  /// TokenTable, a table allowing to map:
+  /// Index <-> CM_OBJECT_TOKEN (to CM_ARM_LPI_INFO structures).
+  CM_OBJECT_TOKEN             * Table;
+
+  /// Last used index of the TokenTable.
+  /// LastIndex is bound by ProcNodeCount.
+  UINT32                        LastIndex;
+} TOKEN_TABLE;
+
+/** A structure holding the Cpu topology generator and additional private data.
+*/
+typedef struct AcpiCpuTopologyGenerator {
+  /// ACPI Table generator header
+  ACPI_TABLE_GENERATOR          Header;
+
+  // Private fields are defined from here.
+
+  /// Private object used to handle token referencing.
+  TOKEN_TABLE                   TokenTable;
+  /// List of CM_ARM_PROC_HIERARCHY_INFO CM objects.
+  CM_ARM_PROC_HIERARCHY_INFO  * ProcNodeList;
+  /// Count of CM_ARM_PROC_HIERARCHY_INFO CM objects.
+  UINT32                        ProcNodeCount;
+} ACPI_CPU_TOPOLOGY_GENERATOR;
+
+#pragma pack()
+
+#endif // SSDT_CPU_TOPOLOGY_GENERATOR_H_
diff --git a/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCpuTopologyLibArm/SsdtCpuTopologyLibArm.inf b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCpuTopologyLibArm/SsdtCpuTopologyLibArm.inf
new file mode 100644
index 000000000000..4038499d963d
--- /dev/null
+++ b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCpuTopologyLibArm/SsdtCpuTopologyLibArm.inf
@@ -0,0 +1,40 @@
+## @file
+# Ssdt Cpu Topology Table Generator
+#
+#  Copyright (c) 2021, Arm Limited. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+  INF_VERSION    = 0x0001001B
+  BASE_NAME      = SsdtCpuTopologyLibArm
+  FILE_GUID      = F2835EB6-4B05-48D4-A475-147DA0F3755C
+  VERSION_STRING = 1.0
+  MODULE_TYPE    = DXE_DRIVER
+  LIBRARY_CLASS  = NULL|DXE_DRIVER
+  CONSTRUCTOR    = AcpiSsdtCpuTopologyLibConstructor
+  DESTRUCTOR     = AcpiSsdtCpuTopologyLibDestructor
+
+[Sources]
+  SsdtCpuTopologyGenerator.c
+  SsdtCpuTopologyGenerator.h
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  EmbeddedPkg/EmbeddedPkg.dec
+  ArmPlatformPkg/ArmPlatformPkg.dec
+  DynamicTablesPkg/DynamicTablesPkg.dec
+
+[LibraryClasses]
+  AcpiHelperLib
+  AmlLib
+  BaseLib
+
+[FixedPcd]
+
+[Protocols]
+
+[Guids]
+
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* Re: [edk2-devel] [PATCH v1 09/13] DynamicTablesPkg: AML code generation to create a Method returning a NS
  2021-06-23 11:40 ` [PATCH v1 09/13] DynamicTablesPkg: AML code generation to create " PierreGondois
@ 2021-06-23 11:45   ` PierreGondois
  0 siblings, 0 replies; 30+ messages in thread
From: PierreGondois @ 2021-06-23 11:45 UTC (permalink / raw)
  To: PierreGondois, devel

[-- Attachment #1: Type: text/plain, Size: 184 bytes --]

This patch is a duplicate of:
[PATCH v1 09/13] DynamicTablesPkg: AML code generation for a Method returning a NS
at https://edk2.groups.io/g/devel/message/76950.
Please ignore it.

[-- Attachment #2: Type: text/html, Size: 294 bytes --]

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v1 02/13] DynamicTablesPkg: AML Code generation for Register()
  2021-06-23 11:40 ` [PATCH v1 02/13] DynamicTablesPkg: AML Code generation for Register() PierreGondois
@ 2021-10-01 12:25   ` Sami Mujawar
  0 siblings, 0 replies; 30+ messages in thread
From: Sami Mujawar @ 2021-10-01 12:25 UTC (permalink / raw)
  To: Pierre.Gondois, devel, Alexei Fedorov; +Cc: Akanksha Jain, Alexandru Elisei, nd

Hi Pierre,

Thank you for this patch.

I have a minor suggestion marked inline as [SAMI].

With that changed,

Reviewed-by: Sami Mujawar <sami.mujawar@arm.com>

Regards,

Sami Mujawar


On 23/06/2021 12:40 PM, Pierre.Gondois@arm.com wrote:
> From: Pierre Gondois <Pierre.Gondois@arm.com>
>
> Add AmlCodeGenRegister() to generate AML code for the
> Generic Register Resource Descriptor. This function is
> equivalent to the ASL macro Register().
>
> Signed-off-by: Pierre Gondois <Pierre.Gondois@arm.com>
> ---
>   .../AmlLib/CodeGen/AmlResourceDataCodeGen.c   | 87 +++++++++++++++++++
>   .../AmlLib/CodeGen/AmlResourceDataCodeGen.h   | 49 +++++++++++
>   2 files changed, 136 insertions(+)
>
> diff --git a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlResourceDataCodeGen.c b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlResourceDataCodeGen.c
> index 089597a6c906..07a96725a4ef 100644
> --- a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlResourceDataCodeGen.c
> +++ b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlResourceDataCodeGen.c
> @@ -187,6 +187,93 @@ AmlCodeGenRdInterrupt (
>     return LinkRdNode (RdNode, NameOpNode, NewRdNode);
>   }
>   
> +/** Code generation for the "Register ()" ASL function.
> +
> +  The Resource Data effectively created is a Generic Register Descriptor.
> +  Data. Cf ACPI 6.4:
> +   - s6.4.3.7 "Generic Register Descriptor".
> +   - s19.6.114 "Register".
> +
> +  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]  AddressSpace    Address space where the register exists.
> +                               Can be one of I/O space, System Memory, etc.
> +  @param [in]  BitWidth        Number of bits in the register.
> +  @param [in]  BitOffset       Offset in bits from the start of the register
> +                               indicated by the Address.
> +  @param [in]  Address         Register address.
> +  @param [in]  AccessSize      Size of data values used when accessing the
> +                               address space. Can be one of:
> +                                 0 - Undefined, legacy (EFI_ACPI_6_3_UNDEFINED)
> +                                 1 - Byte access (EFI_ACPI_6_3_BYTE)
> +                                 2 - Word access (EFI_ACPI_6_3_WORD)
> +                                 3 - DWord access (EFI_ACPI_6_3_DWORD)
> +                                 4 - QWord access (EFI_ACPI_6_3_QWORD)
> +  @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
> +AmlCodeGenRdRegister (
> +  IN  UINT8                   AddressSpace,
> +  IN  UINT8                   BitWidth,
> +  IN  UINT8                   BitOffset,
> +  IN  UINT64                  Address,
> +  IN  UINT8                   AccessSize,
> +  IN  AML_OBJECT_NODE_HANDLE  NameOpNode, OPTIONAL
> +  OUT AML_DATA_NODE_HANDLE    *NewRdNode  OPTIONAL
> +  )
> +{
> +  EFI_STATUS                             Status;
> +  AML_DATA_NODE                        * RdNode;
> +  EFI_ACPI_GENERIC_REGISTER_DESCRIPTOR   RdRegister;
> +
> +  if ((AccessSize > EFI_ACPI_6_3_QWORD)  ||
[SAMI] Can we use the EFI_ACPI_6_4* defines, please? Corresponding 
changes are also needed at other places in this patch.
> +      ((NameOpNode == NULL) && (NewRdNode == NULL))) {
> +    ASSERT (0);
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  // Header
> +  RdRegister.Header.Header.Bits.Name =
> +    ACPI_LARGE_GENERIC_REGISTER_DESCRIPTOR_NAME;
> +  RdRegister.Header.Header.Bits.Type = ACPI_LARGE_ITEM_FLAG;
> +  RdRegister.Header.Length = sizeof (EFI_ACPI_GENERIC_REGISTER_DESCRIPTOR) -
> +                               sizeof (ACPI_LARGE_RESOURCE_HEADER);
> +
> +  // Body
> +  RdRegister.AddressSpaceId = AddressSpace;
> +  RdRegister.RegisterBitWidth = BitWidth;
> +  RdRegister.RegisterBitOffset = BitOffset;
> +  RdRegister.AddressSize = AccessSize;
> +  RdRegister.RegisterAddress = Address;
> +
> +  Status = AmlCreateDataNode (
> +             EAmlNodeDataTypeResourceData,
> +             (UINT8*)&RdRegister,
> +             sizeof (EFI_ACPI_GENERIC_REGISTER_DESCRIPTOR),
> +             &RdNode
> +             );
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    return Status;
> +  }
> +
> +  return LinkRdNode (RdNode, NameOpNode, NewRdNode);
> +}
> +
>   // DEPRECATED APIS
>   #ifndef DISABLE_NEW_DEPRECATED_INTERFACES
>   
> diff --git a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlResourceDataCodeGen.h b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlResourceDataCodeGen.h
> index 764051e3d7c9..3c9217d9ddab 100644
> --- a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlResourceDataCodeGen.h
> +++ b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlResourceDataCodeGen.h
> @@ -55,4 +55,53 @@ AmlCodeGenRdInterrupt (
>     OUT AML_DATA_NODE_HANDLE    *NewRdNode  OPTIONAL
>     );
>   
> +/** Code generation for the "Register ()" ASL function.
> +
> +  The Resource Data effectively created is a Generic Register Descriptor.
> +  Data. Cf ACPI 6.4:
> +   - s6.4.3.7 "Generic Register Descriptor".
> +   - s19.6.114 "Register".
> +
> +  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]  AddressSpace    Address space where the register exists.
> +                               Can be one of I/O space, System Memory, etc.
> +  @param [in]  BitWidth        Number of bits in the register.
> +  @param [in]  BitOffset       Offset in bits from the start of the register
> +                               indicated by the Address.
> +  @param [in]  Address         Register address.
> +  @param [in]  AccessSize      Size of data values used when accessing the
> +                               address space. Can be one of:
> +                                 0 - Undefined, legacy (EFI_ACPI_6_3_UNDEFINED)
> +                                 1 - Byte access (EFI_ACPI_6_3_BYTE)
> +                                 2 - Word access (EFI_ACPI_6_3_WORD)
> +                                 3 - DWord access (EFI_ACPI_6_3_DWORD)
> +                                 4 - QWord access (EFI_ACPI_6_3_QWORD)
> +  @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
> +AmlCodeGenRdRegister (
> +  IN  UINT8                   AddressSpace,
> +  IN  UINT8                   BitWidth,
> +  IN  UINT8                   BitOffset,
> +  IN  UINT64                  Address,
> +  IN  UINT8                   AccessSize,
> +  IN  AML_OBJECT_NODE_HANDLE  NameOpNode, OPTIONAL
> +  OUT AML_DATA_NODE_HANDLE    *NewRdNode  OPTIONAL
> +  );
> +
>   #endif // AML_RESOURCE_DATA_CODE_GEN_H_


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v1 03/13] DynamicTablesPkg: AML Code generation for Resource data EndTag
  2021-06-23 11:40 ` [PATCH v1 03/13] DynamicTablesPkg: AML Code generation for Resource data EndTag PierreGondois
@ 2021-10-01 12:48   ` Sami Mujawar
  0 siblings, 0 replies; 30+ messages in thread
From: Sami Mujawar @ 2021-10-01 12:48 UTC (permalink / raw)
  To: Pierre.Gondois, devel, Alexei Fedorov; +Cc: Akanksha Jain, Alexandru Elisei, nd

Hi Pierre,

Thank you for this patch.

Please find my response inline marked [SAMI].

Regards,

Sami Mujawar


On 23/06/2021 12:40 PM, Pierre.Gondois@arm.com wrote:
> From: Pierre Gondois <Pierre.Gondois@arm.com>
>
> Add a helper function AmlCodeGenEndTag() to generate AML Resource Data
> EndTag. The EndTag resource data is automatically generated by the ASL
> compiler at the end of a list of resource data elements. Therefore, an
> equivalent function is not present in ASL.
>
> However, AmlCodeGenEndTag() is useful when generating AML code for the
> ResourceTemplate() macro.
>
> Signed-off-by: Pierre Gondois <Pierre.Gondois@arm.com>
> ---
>   .../AmlLib/CodeGen/AmlResourceDataCodeGen.c   | 104 ++++++++++++++++++
>   .../AmlLib/CodeGen/AmlResourceDataCodeGen.h   |  34 ++++++
>   2 files changed, 138 insertions(+)
>
> diff --git a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlResourceDataCodeGen.c b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlResourceDataCodeGen.c
> index 07a96725a4ef..78910cc5d4b4 100644
> --- a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlResourceDataCodeGen.c
> +++ b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlResourceDataCodeGen.c
> @@ -274,6 +274,110 @@ AmlCodeGenRdRegister (
>     return LinkRdNode (RdNode, NameOpNode, NewRdNode);
>   }
>   
> +/** Code generation for the EndTag resource data.
> +
> +  The EndTag resource data is automatically generated by the ASL compiler
> +  at the end of a list of resource data elements. Thus, it doesn't have
> +  a corresponding ASL function.
> +
> +  This function allocates memory to create a data node. It is the caller's
> +  responsibility to either:
> +   - attach this node to an AML tree;
> +   - delete this node.
> +
> +  @param [in]  CheckSum        CheckSum to store in the EndTag.
> +                               Optional: can be let to 0. It is not
> +                               updated when new resource data elements
> +                               are added/removed/modified in the list.
[SAMI] Can you rephrase the description, please? If I understand 
correctly, the current implementation does not compute the checksum. 
However, if the checksum value provided is not zero then an update to 
the resource nodes would need to recompute the checksum, right?
> +  @param [in]  ParentNode      If not NULL, add the generated node
> +                               to the end of the variable list of
> +                               argument of the ParentNode.
> +                               The ParentNode must not initially contain
> +                               an EndTag resource data element.
> +  @param  [out] NewRdNode      If success, contains the generated 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
> +AmlCodeGenEndTag (
> +  IN  UINT8               CheckSum,   OPTIONAL
> +  IN  AML_OBJECT_NODE   * ParentNode, OPTIONAL
> +  OUT AML_DATA_NODE    ** NewRdNode   OPTIONAL
> +  )
> +{
> +  EFI_STATUS                      Status;
> +  AML_DATA_NODE                 * RdNode;
> +  EFI_ACPI_END_TAG_DESCRIPTOR     EndTag;
> +  ACPI_SMALL_RESOURCE_HEADER      SmallResHdr;
> +
> +  if ((ParentNode == NULL) && (NewRdNode == NULL)) {
> +    ASSERT (0);
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  RdNode = NULL;
> +
> +  // Header
> +  SmallResHdr.Bits.Length = sizeof (EFI_ACPI_END_TAG_DESCRIPTOR) -
> +                              sizeof (ACPI_SMALL_RESOURCE_HEADER);
> +  SmallResHdr.Bits.Name = ACPI_SMALL_END_TAG_DESCRIPTOR_NAME;
> +  SmallResHdr.Bits.Type = ACPI_SMALL_ITEM_FLAG;
> +
> +  // Body
> +  EndTag.Desc = SmallResHdr.Byte;
> +  EndTag.Checksum = CheckSum;
> +
> +  Status = AmlCreateDataNode (
> +             EAmlNodeDataTypeResourceData,
> +             (UINT8*)&EndTag,
> +             sizeof (EFI_ACPI_END_TAG_DESCRIPTOR),
> +             &RdNode
> +             );
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    return Status;
> +  }
> +
> +  if (NewRdNode != NULL) {
> +    *NewRdNode = RdNode;
> +  }
> +
> +  if (ParentNode != NULL) {
> +    // Check the BufferOp doesn't contain any resource data yet.
> +    // This is a hard check: do not allow to add an EndTag if the BufferNode
> +    // already has resource data elements attached. Indeed, the EndTag should
> +    // have already been added.
> +    if (AmlGetNextVariableArgument ((AML_NODE_HEADER*)ParentNode, NULL) !=
> +          NULL) {
> +      ASSERT (0);
> +      Status = EFI_INVALID_PARAMETER;
> +      goto error_handler;
> +    }
> +
> +    // Manually add the EndTag RdNode. Indeed, the AmlAppendRdNode function
> +    // is looking for an EndTag, which we are adding here.
> +    Status = AmlVarListAddTail (
> +               (AML_NODE_HEADER*)ParentNode,
> +               (AML_NODE_HEADER*)RdNode
> +               );
> +    if (EFI_ERROR (Status)) {
> +      ASSERT (0);
> +      goto error_handler;
> +    }
> +  }
> +
> +  return Status;
> +
> +error_handler:
> +  if (RdNode != NULL) {
> +    AmlDeleteTree ((AML_NODE_HEADER*)RdNode);
> +  }
> +  return Status;
> +}
> +
>   // DEPRECATED APIS
>   #ifndef DISABLE_NEW_DEPRECATED_INTERFACES
>   
> diff --git a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlResourceDataCodeGen.h b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlResourceDataCodeGen.h
> index 3c9217d9ddab..0b464305da40 100644
> --- a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlResourceDataCodeGen.h
> +++ b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlResourceDataCodeGen.h
> @@ -104,4 +104,38 @@ AmlCodeGenRdRegister (
>     OUT AML_DATA_NODE_HANDLE    *NewRdNode  OPTIONAL
>     );
>   
> +/** Code generation for the EndTag resource data.
> +
> +  The EndTag resource data is automatically generated by the ASL compiler
> +  at the end of a list of resource data elements. Thus, it doesn't have
> +  a corresponding ASL function.
> +
> +  This function allocates memory to create a data node. It is the caller's
> +  responsibility to either:
> +   - attach this node to an AML tree;
> +   - delete this node.
> +
> +  @param [in]  CheckSum        CheckSum to store in the EndTag.
> +                               Optional: can be let to 0. It is not
> +                               updated when new resource data elements
> +                               are added/removed/modified in the list.
> +  @param [in]  ParentNode      If not NULL, add the generated node
> +                               to the end of the variable list of
> +                               argument of the ParentNode.
> +                               The ParentNode must not initially contain
> +                               an EndTag resource data element.
> +  @param  [out] NewRdNode      If success, contains the generated 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
> +AmlCodeGenEndTag (
> +  IN  UINT8               CheckSum,   OPTIONAL
> +  IN  AML_OBJECT_NODE   * ParentNode, OPTIONAL
> +  OUT AML_DATA_NODE    ** NewRdNode   OPTIONAL
> +  );
> +
>   #endif // AML_RESOURCE_DATA_CODE_GEN_H_


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v1 04/13] DynamicTablesPkg: AML code generation for a Package
  2021-06-23 11:40 ` [PATCH v1 04/13] DynamicTablesPkg: AML code generation for a Package PierreGondois
@ 2021-10-01 12:55   ` Sami Mujawar
  0 siblings, 0 replies; 30+ messages in thread
From: Sami Mujawar @ 2021-10-01 12:55 UTC (permalink / raw)
  To: Pierre.Gondois, devel, Alexei Fedorov; +Cc: Akanksha Jain, Alexandru Elisei, nd

Hi Pierre,

Thank you for this patch. This patch looks good to me.

Reviewed-by: Sami Mujawar <sami.mujawar@arm.com>

Regards,

Sami Mujawar


On 23/06/2021 12:40 PM, Pierre.Gondois@arm.com wrote:
> From: Pierre Gondois <Pierre.Gondois@arm.com>
>
> Add AmlCodeGenPackage() to generate AML code for declaring
> a Package() object. This function generates an empty package
> node. New elements can then be added to the package's variable
> argument list.
>
> Signed-off-by: Pierre Gondois <Pierre.Gondois@arm.com>
> ---
>   .../Common/AmlLib/CodeGen/AmlCodeGen.c        | 82 ++++++++++++++++++-
>   1 file changed, 81 insertions(+), 1 deletion(-)
>
> diff --git a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
> index 5d310f201319..ea9b73b464a4 100644
> --- a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
> +++ b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
> @@ -1,7 +1,7 @@
>   /** @file
>     AML Code Generation.
>   
> -  Copyright (c) 2020, Arm Limited. All rights reserved.<BR>
> +  Copyright (c) 2020 - 2021, Arm Limited. All rights reserved.<BR>
>   
>     SPDX-License-Identifier: BSD-2-Clause-Patent
>   **/
> @@ -235,6 +235,86 @@ AmlCodeGenInteger (
>     return Status;
>   }
>   
> +/** AML code generation for a Package object node.
> +
> +  The package generated is empty. New elements can be added via its
> +  list of variable arguments.
> +
> +  @param [out] NewObjectNode   If success, contains the created
> +                               Package object node.
> +
> +  @retval EFI_SUCCESS             Success.
> +  @retval EFI_INVALID_PARAMETER   Invalid parameter.
> +  @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
> +**/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +AmlCodeGenPackage (
> +  OUT AML_OBJECT_NODE    ** NewObjectNode
> +  )
> +{
> +  EFI_STATUS        Status;
> +  AML_DATA_NODE   * DataNode;
> +  UINT8             NodeCount;
> +
> +  if (NewObjectNode == NULL) {
> +    ASSERT (0);
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  DataNode = NULL;
> +  NodeCount = 0;
> +
> +  // Create an object node.
> +  // PkgLen is 2:
> +  //  - one byte to store the PkgLength
> +  //  - one byte for the NumElements.
> +  // Cf ACPI6.3, s20.2.5 "Term Objects Encoding"
> +  // DefPackage  := PackageOp PkgLength NumElements PackageElementList
> +  // NumElements := ByteData
> +  Status = AmlCreateObjectNode (
> +             AmlGetByteEncodingByOpCode (AML_PACKAGE_OP, 0),
> +             2,
> +             NewObjectNode
> +             );
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    return Status;
> +  }
> +
> +  // NumElements is a ByteData.
> +  Status = AmlCreateDataNode (
> +             EAmlNodeDataTypeUInt,
> +             &NodeCount,
> +             sizeof (NodeCount),
> +             &DataNode
> +             );
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler;
> +  }
> +
> +  Status = AmlSetFixedArgument (
> +             *NewObjectNode,
> +             EAmlParseIndexTerm0,
> +             (AML_NODE_HEADER*)DataNode
> +             );
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler;
> +  }
> +
> +  return Status;
> +
> +error_handler:
> +  AmlDeleteTree ((AML_NODE_HEADER*)*NewObjectNode);
> +  if (DataNode != NULL) {
> +    AmlDeleteTree ((AML_NODE_HEADER*)DataNode);
> +  }
> +  return Status;
> +}
> +
>   /** AML code generation for a Name object node.
>   
>     @param  [in] NameString     The new variable name.


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v1 05/13] DynamicTablesPkg: Helper function to compute package length
  2021-06-23 11:40 ` [PATCH v1 05/13] DynamicTablesPkg: Helper function to compute package length PierreGondois
@ 2021-10-01 14:24   ` Sami Mujawar
  0 siblings, 0 replies; 30+ messages in thread
From: Sami Mujawar @ 2021-10-01 14:24 UTC (permalink / raw)
  To: Pierre.Gondois, devel, Alexei Fedorov; +Cc: Akanksha Jain, Alexandru Elisei, nd

  Hi Pierre,

This patch looks good to me.

Reviewed-by: Sami Mujawar <sami.mujawar@arm.com>

Regards,

Sami Mujawar


On 23/06/2021 12:40 PM, Pierre.Gondois@arm.com wrote:
> From: Pierre Gondois <Pierre.Gondois@arm.com>
>
> Some AML object have a PkgLen which indicates the size of the
> AML object. The package length can be encoded in 1 to 4 bytes.
> The bytes used to encode the PkgLen is itself counted in the
> PkgLen value. So, if an AML object's size increments/decrements,
> the number of bytes used to encode the PkgLen value can itself
> increment/decrement.
>
> Therefore, a helper function AmlComputePkgLength() is introduced
> to simply computation of the PkgLen.
>
> Signed-off-by: Pierre Gondois <Pierre.Gondois@arm.com>
> ---
>   .../Library/Common/AmlLib/AmlEncoding/Aml.c   | 87 ++++++++++++++++++-
>   .../Library/Common/AmlLib/AmlEncoding/Aml.h   | 47 +++++++++-
>   2 files changed, 132 insertions(+), 2 deletions(-)
>
> diff --git a/DynamicTablesPkg/Library/Common/AmlLib/AmlEncoding/Aml.c b/DynamicTablesPkg/Library/Common/AmlLib/AmlEncoding/Aml.c
> index eadafca97ea5..d829b1869846 100644
> --- a/DynamicTablesPkg/Library/Common/AmlLib/AmlEncoding/Aml.c
> +++ b/DynamicTablesPkg/Library/Common/AmlLib/AmlEncoding/Aml.c
> @@ -2,7 +2,7 @@
>     AML grammar definitions.
>   
>     Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved. <BR>
> -  Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>
> +  Copyright (c) 2019 - 2021, Arm Limited. All rights reserved.<BR>
>   
>     SPDX-License-Identifier: BSD-2-Clause-Patent
>   **/
> @@ -803,3 +803,88 @@ AmlComputePkgLengthWidth (
>     // Length < 2^6
>     return 1;
>   }
> +
> +/** Given a length, compute the value of a PkgLen.
> +
> +  In AML, some object have a PkgLen, telling the size of the AML object.
> +  It can be encoded in 1 to 4 bytes. The bytes used to encode the PkgLen is
> +  itself counted in the PkgLen value.
> +  This means that if an AML object sees its size increment/decrement,
> +  the number of bytes used to encode the PkgLen value can itself
> +  increment/decrement.
> +
> +  For instance, the AML encoding of a DeviceOp is:
> +    DefDevice := DeviceOp PkgLength NameString TermList
> +  If:
> +   - sizeof (NameString) = 4 (the name is "DEV0" for instance);
> +   - sizeof (TermList) = (2^6-6)
> +  then the PkgLen is encoded on 1 byte. Indeed, its value is:
> +    sizeof (PkgLen) + sizeof (NameString) + sizeof (TermList) =
> +    sizeof (PkgLen) + 4 + (2^6-6)
> +  So:
> +    PkgLen = sizeof (PkgLen) + (2^6-2)
> +
> +  The input arguments Length and PkgLen represent, for the DefDevice:
> +    DefDevice := DeviceOp PkgLength NameString TermList
> +                                    |------Length-----|
> +                          |--------*PgkLength---------|
> +
> +  @param  [in]  Length  The length to encode as a PkgLen.
> +                        Length cannot exceed 2^28 - 4 (4 bytes for the
> +                        PkgLen encoding).
> +                        The size of the PkgLen encoding bytes should not be
> +                        counted in this length value.
> +  @param  [out] PkgLen  If success, contains the value of the PkgLen,
> +                        ready to encode in the PkgLen format.
> +                        This value takes into account the size of PkgLen
> +                        encoding.
> +
> +  @retval EFI_SUCCESS             The function completed successfully.
> +  @retval EFI_INVALID_PARAMETER   Invalid parameter.
> +**/
> +EFI_STATUS
> +EFIAPI
> +AmlComputePkgLength (
> +  IN  UINT32    Length,
> +  OUT UINT32  * PkgLen
> +  )
> +{
> +  UINT32  PkgLenWidth;
> +  UINT32  ReComputedPkgLenWidth;
> +
> +  if (PkgLen == NULL) {
> +    ASSERT (0);
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  // Compute the PkgLenWidth.
> +  PkgLenWidth = AmlComputePkgLengthWidth (Length);
> +  if (PkgLenWidth == 0) {
> +    ASSERT (0);
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  // Add it to the Length.
> +  Length += PkgLenWidth;
> +
> +  // Check that adding the PkgLenWidth didn't trigger a domino effect,
> +  // increasing the encoding width of the PkgLen again.
> +  // The PkgLen is encoded in at most 4 bytes. It is possible to increase
> +  // the PkgLen width if its encoding is less than 3 bytes.
> +  ReComputedPkgLenWidth = AmlComputePkgLengthWidth (Length);
> +  if (ReComputedPkgLenWidth != PkgLenWidth) {
> +    if ((ReComputedPkgLenWidth != 0)   &&
> +        (ReComputedPkgLenWidth < 4)) {
> +      // No need to recompute the PkgLen since a new threshold cannot
> +      // be reached by incrementing the value by one.
> +      Length += 1;
> +    } else {
> +      ASSERT (0);
> +      return EFI_INVALID_PARAMETER;
> +    }
> +  }
> +
> +  *PkgLen = Length;
> +
> +  return EFI_SUCCESS;
> +}
> diff --git a/DynamicTablesPkg/Library/Common/AmlLib/AmlEncoding/Aml.h b/DynamicTablesPkg/Library/Common/AmlLib/AmlEncoding/Aml.h
> index 35c0680b6159..0641500fcd5f 100644
> --- a/DynamicTablesPkg/Library/Common/AmlLib/AmlEncoding/Aml.h
> +++ b/DynamicTablesPkg/Library/Common/AmlLib/AmlEncoding/Aml.h
> @@ -2,7 +2,7 @@
>     AML grammar definitions.
>   
>     Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved. <BR>
> -  Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>
> +  Copyright (c) 2019 - 2021, Arm Limited. All rights reserved.<BR>
>   
>     SPDX-License-Identifier: BSD-2-Clause-Patent
>   **/
> @@ -326,5 +326,50 @@ AmlComputePkgLengthWidth (
>     IN  UINT32  Length
>     );
>   
> +/** Given a length, compute the value of a PkgLen.
> +
> +  In AML, some object have a PkgLen, telling the size of the AML object.
> +  It can be encoded in 1 to 4 bytes. The bytes used to encode the PkgLen is
> +  itself counted in the PkgLen value.
> +  This means that if an AML object sees its size increment/decrement,
> +  the number of bytes used to encode the PkgLen value can itself
> +  increment/decrement.
> +
> +  For instance, the AML encoding of a DeviceOp is:
> +    DefDevice := DeviceOp PkgLength NameString TermList
> +  If:
> +   - sizeof (NameString) = 4 (the name is "DEV0" for instance);
> +   - sizeof (TermList) = (2^6-6)
> +  then the PkgLen is encoded on 1 byte. Indeed, its value is:
> +    sizeof (PkgLen) + sizeof (NameString) + sizeof (TermList) =
> +    sizeof (PkgLen) + 4 + (2^6-6)
> +  So:
> +    PkgLen = sizeof (PkgLen) + (2^6-2)
> +
> +  The input arguments Length and PkgLen represent, for the DefDevice:
> +    DefDevice := DeviceOp PkgLength NameString TermList
> +                                    |------Length-----|
> +                          |--------*PgkLength---------|
> +
> +  @param  [in]  Length  The length to encode as a PkgLen.
> +                        Length cannot exceed 2^28 - 4 (4 bytes for the
> +                        PkgLen encoding).
> +                        The size of the PkgLen encoding bytes should not be
> +                        counted in this length value.
> +  @param  [out] PkgLen  If success, contains the value of the PkgLen,
> +                        ready to encode in the PkgLen format.
> +                        This value takes into account the size of PkgLen
> +                        encoding.
> +
> +  @retval EFI_SUCCESS             The function completed successfully.
> +  @retval EFI_INVALID_PARAMETER   Invalid parameter.
> +**/
> +EFI_STATUS
> +EFIAPI
> +AmlComputePkgLength (
> +  IN  UINT32    Length,
> +  OUT UINT32  * PkgLen
> +  );
> +
>   #endif // AML_H_
>   


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v1 06/13] DynamicTablesPkg: AML code generation for a ResourceTemplate
  2021-06-23 11:40 ` [PATCH v1 06/13] DynamicTablesPkg: AML code generation for a ResourceTemplate PierreGondois
@ 2021-10-01 14:34   ` Sami Mujawar
  0 siblings, 0 replies; 30+ messages in thread
From: Sami Mujawar @ 2021-10-01 14:34 UTC (permalink / raw)
  To: Pierre.Gondois, devel, Alexei Fedorov; +Cc: Akanksha Jain, Alexandru Elisei, nd

Hi Pierre,

Thank you for this patch.

Reviewed-by: Sami Mujawar <sami.mujawar@arm.com>

Regards,

Sami Mujawar


On 23/06/2021 12:40 PM, Pierre.Gondois@arm.com wrote:
> From: Pierre Gondois <Pierre.Gondois@arm.com>
>
> ASL provides a ResourceTemplate macro that creates a Buffer in which
> resource descriptor macros can be listed. The ResourceTemplate macro
> automatically generates an End descriptor and calculates the checksum
> for the resource template.
>
> Therefore, add AmlCodeGenResourceTemplate() to generate AML code for
> the ResourceTemplate() macro. This function generates a Buffer node
> with an EndTag resource data descriptor, which is similar to the ASL
> ResourceTemplate() macro.
>
> Signed-off-by: Pierre Gondois <Pierre.Gondois@arm.com>
> ---
>   .../Common/AmlLib/CodeGen/AmlCodeGen.c        | 192 ++++++++++++++++++
>   1 file changed, 192 insertions(+)
>
> diff --git a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
> index ea9b73b464a4..faf7902c1f21 100644
> --- a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
> +++ b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
> @@ -12,6 +12,7 @@
>   
>   #include <AmlCoreInterface.h>
>   #include <AmlEncoding/Aml.h>
> +#include <CodeGen/AmlResourceDataCodeGen.h>
>   #include <Tree/AmlNode.h>
>   #include <Tree/AmlTree.h>
>   #include <String/AmlString.h>
> @@ -315,6 +316,197 @@ error_handler:
>     return Status;
>   }
>   
> +/** AML code generation for a Buffer object node.
> +
> +  To create a Buffer object node with an empty buffer,
> +  call the function with (Buffer=NULL, BufferSize=0).
> +
> +  @param [in]  Buffer          Buffer to set for the created Buffer
> +                               object node. The Buffer's content is copied.
> +                               NULL if there is no buffer to set for
> +                               the Buffer node.
> +  @param [in]  BufferSize      Size of the Buffer.
> +                               0 if there is no buffer to set for
> +                               the Buffer node.
> +  @param [out] NewObjectNode   If success, contains the created
> +                               Buffer object node.
> +
> +  @retval EFI_SUCCESS             Success.
> +  @retval EFI_INVALID_PARAMETER   Invalid parameter.
> +  @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
> +**/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +AmlCodeGenBuffer (
> +  IN  CONST UINT8             * Buffer,       OPTIONAL
> +  IN        UINT32              BufferSize,   OPTIONAL
> +  OUT       AML_OBJECT_NODE  ** NewObjectNode
> +  )
> +{
> +  EFI_STATUS        Status;
> +  AML_OBJECT_NODE * BufferNode;
> +  AML_OBJECT_NODE * BufferSizeNode;
> +  UINT32            BufferSizeNodeSize;
> +  AML_DATA_NODE   * DataNode;
> +  UINT32            PkgLen;
> +
> +  // Buffer and BufferSize must be either both set, or both clear.
> +  if ((NewObjectNode == NULL)                 ||
> +      ((Buffer == NULL) != (BufferSize == 0))) {
> +    ASSERT (0);
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  BufferNode = NULL;
> +  DataNode = NULL;
> +
> +  // Cf ACPI 6.3 specification, s20.2.5.4 "Type 2 Opcodes Encoding"
> +  // DefBuffer := BufferOp PkgLength BufferSize ByteList
> +  // BufferOp  := 0x11
> +  // BufferSize := TermArg => Integer
> +
> +  Status = AmlCodeGenInteger (BufferSize, &BufferSizeNode);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    return Status;
> +  }
> +
> +  // Get the number of bytes required to encode the BufferSizeNode.
> +  Status = AmlComputeSize (
> +             (AML_NODE_HEADER*)BufferSizeNode,
> +             &BufferSizeNodeSize
> +             );
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler;
> +  }
> +
> +  // Compute the size to write in the PkgLen.
> +  Status = AmlComputePkgLength (BufferSizeNodeSize + BufferSize, &PkgLen);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler;
> +  }
> +
> +  // Create an object node for the buffer.
> +  Status = AmlCreateObjectNode (
> +             AmlGetByteEncodingByOpCode (AML_BUFFER_OP, 0),
> +             PkgLen,
> +             &BufferNode
> +             );
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler;
> +  }
> +
> +  // Set the BufferSizeNode as a fixed argument of the BufferNode.
> +  Status = AmlSetFixedArgument (
> +             BufferNode,
> +             EAmlParseIndexTerm0,
> +             (AML_NODE_HEADER*)BufferSizeNode
> +             );
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler;
> +  }
> +
> +  // BufferSizeNode is now attached.
> +  BufferSizeNode = NULL;
> +
> +  // If there is a buffer, create a DataNode and attach it to the BufferNode.
> +  if (Buffer != NULL) {
> +    Status = AmlCreateDataNode (
> +               EAmlNodeDataTypeRaw,
> +               Buffer,
> +               BufferSize,
> +               &DataNode
> +               );
> +    if (EFI_ERROR (Status)) {
> +      ASSERT (0);
> +      goto error_handler;
> +    }
> +
> +    Status = AmlVarListAddTail (
> +               (AML_NODE_HEADER*)BufferNode,
> +               (AML_NODE_HEADER*)DataNode
> +               );
> +    if (EFI_ERROR (Status)) {
> +      ASSERT (0);
> +      goto error_handler;
> +    }
> +  }
> +
> +  *NewObjectNode = BufferNode;
> +  return Status;
> +
> +error_handler:
> +  if (BufferSizeNode != NULL) {
> +    AmlDeleteTree ((AML_NODE_HEADER*)BufferSizeNode);
> +  }
> +  if (BufferNode != NULL) {
> +    AmlDeleteTree ((AML_NODE_HEADER*)BufferNode);
> +  }
> +  if (DataNode != NULL) {
> +    AmlDeleteTree ((AML_NODE_HEADER*)DataNode);
> +  }
> +  return Status;
> +}
> +
> +/** AML code generation for a ResourceTemplate.
> +
> +  "ResourceTemplate" is a macro defined in ACPI 6.3, s19.3.3
> +  "ASL Resource Templates". It allows to store resource data elements.
> +
> +  In AML, a ResourceTemplate is implemented as a Buffer storing resource
> +  data elements. An EndTag resource data descriptor must be at the end
> +  of the list of resource data elements.
> +  This function generates a Buffer node with an EndTag resource data
> +  descriptor. It can be seen as an empty list of resource data elements.
> +
> +  @param [out] NewObjectNode   If success, contains the created
> +                               ResourceTemplate object node.
> +
> +  @retval EFI_SUCCESS             Success.
> +  @retval EFI_INVALID_PARAMETER   Invalid parameter.
> +  @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
> +**/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +AmlCodeGenResourceTemplate (
> +  OUT AML_OBJECT_NODE    ** NewObjectNode
> +  )
> +{
> +  EFI_STATUS          Status;
> +  AML_OBJECT_NODE   * BufferNode;
> +
> +  if (NewObjectNode == NULL) {
> +    ASSERT (0);
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  BufferNode = NULL;
> +
> +  // Create a BufferNode with an empty buffer.
> +  Status = AmlCodeGenBuffer (NULL, 0, &BufferNode);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    return Status;
> +  }
> +
> +  // Create an EndTag resource data element and attach it to the Buffer.
> +  Status = AmlCodeGenEndTag (0, BufferNode, NULL);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    AmlDeleteTree ((AML_NODE_HEADER*)BufferNode);
> +    return Status;
> +  }
> +
> +  *NewObjectNode = BufferNode;
> +  return Status;
> +}
> +
>   /** AML code generation for a Name object node.
>   
>     @param  [in] NameString     The new variable name.


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v1 01/13] DynamicTablesPkg: Make AmlNodeGetIntegerValue public
  2021-06-23 11:40 ` [PATCH v1 01/13] DynamicTablesPkg: Make AmlNodeGetIntegerValue public PierreGondois
@ 2021-10-01 14:48   ` Sami Mujawar
  0 siblings, 0 replies; 30+ messages in thread
From: Sami Mujawar @ 2021-10-01 14:48 UTC (permalink / raw)
  To: Pierre.Gondois, devel, Alexei Fedorov; +Cc: Akanksha Jain, Alexandru Elisei, nd

Hi Pierre,

Thank you for this patch. This patch looks good to me.

Reviewed-by: Sami Mujawar <sami.mujawar@arm.com>

Regards,

Sami Mujawar

On 23/06/2021 12:40 PM, Pierre.Gondois@arm.com wrote:
> From: Pierre Gondois <Pierre.Gondois@arm.com>
>
> Remove the STATIC qualifier for the AmlUtility function
> AmlNodeGetIntegerValue() and add the definition to the
> header file so that it can be used by other AmlLib
> sub-modules.
>
> Signed-off-by: Pierre Gondois <Pierre.Gondois@arm.com>
> ---
>   .../Library/Common/AmlLib/Utils/AmlUtility.c   |  3 +--
>   .../Library/Common/AmlLib/Utils/AmlUtility.h   | 18 +++++++++++++++++-
>   2 files changed, 18 insertions(+), 3 deletions(-)
>
> diff --git a/DynamicTablesPkg/Library/Common/AmlLib/Utils/AmlUtility.c b/DynamicTablesPkg/Library/Common/AmlLib/Utils/AmlUtility.c
> index 7ebd08f945c0..3c8927acda6a 100644
> --- a/DynamicTablesPkg/Library/Common/AmlLib/Utils/AmlUtility.c
> +++ b/DynamicTablesPkg/Library/Common/AmlLib/Utils/AmlUtility.c
> @@ -1,7 +1,7 @@
>   /** @file
>     AML Utility.
>   
> -  Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>
> +  Copyright (c) 2019 - 2021, Arm Limited. All rights reserved.<BR>
>   
>     SPDX-License-Identifier: BSD-2-Clause-Patent
>   **/
> @@ -192,7 +192,6 @@ AmlComputeSize (
>     @retval EFI_SUCCESS             The function completed successfully.
>     @retval EFI_INVALID_PARAMETER   Invalid parameter.
>   **/
> -STATIC
>   EFI_STATUS
>   EFIAPI
>   AmlNodeGetIntegerValue (
> diff --git a/DynamicTablesPkg/Library/Common/AmlLib/Utils/AmlUtility.h b/DynamicTablesPkg/Library/Common/AmlLib/Utils/AmlUtility.h
> index c57d780140d4..5013bfb81d2d 100644
> --- a/DynamicTablesPkg/Library/Common/AmlLib/Utils/AmlUtility.h
> +++ b/DynamicTablesPkg/Library/Common/AmlLib/Utils/AmlUtility.h
> @@ -1,7 +1,7 @@
>   /** @file
>     AML Utility.
>   
> -  Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>
> +  Copyright (c) 2019 - 2021, Arm Limited. All rights reserved.<BR>
>   
>     SPDX-License-Identifier: BSD-2-Clause-Patent
>   **/
> @@ -39,6 +39,22 @@ AmlComputeSize (
>     IN  OUT       UINT32            * Size
>     );
>   
> +/** Get the value contained in an integer node.
> +
> +  @param  [in]  Node    Pointer to an integer node.
> +                        Must be an object node.
> +  @param  [out] Value   Value contained in the integer node.
> +
> +  @retval EFI_SUCCESS             The function completed successfully.
> +  @retval EFI_INVALID_PARAMETER   Invalid parameter.
> +**/
> +EFI_STATUS
> +EFIAPI
> +AmlNodeGetIntegerValue (
> +  IN  AML_OBJECT_NODE   * Node,
> +  OUT UINT64            * Value
> +  );
> +
>   /** Set the value contained in an integer node.
>   
>     The OpCode is updated accordingly to the new value


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v1 07/13] DynamicTablesPkg: AML code generation for a Method
  2021-06-23 11:40 ` [PATCH v1 07/13] DynamicTablesPkg: AML code generation for a Method PierreGondois
@ 2021-10-01 14:52   ` Sami Mujawar
  0 siblings, 0 replies; 30+ messages in thread
From: Sami Mujawar @ 2021-10-01 14:52 UTC (permalink / raw)
  To: Pierre.Gondois, devel, Alexei Fedorov; +Cc: Akanksha Jain, Alexandru Elisei, nd

Hi Pierre,

I have a minor suggestion marked inline as [SAMI].

Otherwise this patch looks good to me.

Reviewed-by: Sami Mujawar <sami.mujawar@arm.com>

Regards,

Sami Mujawar


On 23/06/2021 12:40 PM, Pierre.Gondois@arm.com wrote:
> From: Pierre Gondois <Pierre.Gondois@arm.com>
>
> Add AmlCodeGenMethod() to generate code for a control method.
>
> AmlCodeGenMethod ("MET0", 1, TRUE, 3, ParentNode, NewObjectNode)
> is equivalent of the following ASL code:
>      Method(MET0, 1, Serialized, 3) {}
>
> Signed-off-by: Pierre Gondois <Pierre.Gondois@arm.com>
> ---
>   .../Common/AmlLib/CodeGen/AmlCodeGen.c        | 166 ++++++++++++++++++
>   1 file changed, 166 insertions(+)
>
> diff --git a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
> index faf7902c1f21..32665f7f8d8f 100644
> --- a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
> +++ b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
> @@ -971,3 +971,169 @@ error_handler1:
>   
>     return Status;
>   }
> +
> +/** AML code generation for a Method object node.
> +
> +  AmlCodeGenMethod ("MET0", 1, TRUE, 3, ParentNode, NewObjectNode) is
> +  equivalent of the following ASL code:
> +    Method(MET0, 1, Serialized, 3) {}
> +
> +  The ASL parameters "ReturnType" and "ParameterTypes" are not asked
> +  in this function. They are optional parameters in ASL.
> +
> +  @param [in]  NameString     The new Method's name.
> +                              Must be a NULL-terminated ASL NameString
> +                              e.g.: "MET0", "_SB.MET0", etc.
> +                              The input string is copied.
> +  @param [in]  NumArgs        Number of arguments.
> +                              Must be 0 <= NumArgs <= 6.
> +  @param [in]  IsSerialized   TRUE is equivalent to Serialized.
> +                              FALSE is equivalent to NotSerialized.
> +                              Default is NotSerialized in ASL spec.
> +  @param [in]  SyncLevel      Synchronization level for the method.
> +                              Must be 0 <= SyncLevel <= 15.
> +                              Default is 0 in ASL.
> +  @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.
> +**/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +AmlCodeGenMethod (
> +  IN  CONST CHAR8              * NameString,
> +  IN        UINT8                NumArgs,
> +  IN        BOOLEAN              IsSerialized,
> +  IN        UINT8                SyncLevel,
> +  IN        AML_NODE_HEADER    * ParentNode,     OPTIONAL
> +  OUT       AML_OBJECT_NODE   ** NewObjectNode   OPTIONAL
> +  )
> +{
> +  EFI_STATUS        Status;
> +  UINT32            PkgLen;
> +  UINT8             Flags;
> +  AML_OBJECT_NODE * ObjectNode;
> +  AML_DATA_NODE   * DataNode;
> +  CHAR8           * AmlNameString;
> +  UINT32            AmlNameStringSize;
> +
> +  if ((NameString == NULL)    ||
> +      (NumArgs > 6)           ||
> +      (SyncLevel > 15)        ||
> +      ((ParentNode == NULL) && (NewObjectNode == NULL))) {
> +    ASSERT (0);
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  ObjectNode = NULL;
> +  DataNode = NULL;
> +
> +  Status = ConvertAslNameToAmlName (NameString, &AmlNameString);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    return Status;
> +  }
> +
> +  Status = AmlGetNameStringSize (AmlNameString, &AmlNameStringSize);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler1;
> +  }
> +
> +  // Compute the size to write in the PkgLen.
> +  // Add 1 byte (ByteData) for MethodFlags.
[SAMI] Is it possible to add description of the encoding for MethodOp, 
please? Also it will help if some comments are added describing each 
encoding step using a numberd list.
> +  Status = AmlComputePkgLength (AmlNameStringSize + 1, &PkgLen);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler1;
> +  }
> +
> +  Status = AmlCreateObjectNode (
> +             AmlGetByteEncodingByOpCode (AML_METHOD_OP, 0),
> +             PkgLen,
> +             &ObjectNode
> +             );
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler1;
> +  }
> +
> +  Status = AmlCreateDataNode (
> +             EAmlNodeDataTypeNameString,
> +             (UINT8*)AmlNameString,
> +             AmlNameStringSize,
> +             &DataNode
> +             );
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler2;
> +  }
> +
> +  Status = AmlSetFixedArgument (
> +             ObjectNode,
> +             EAmlParseIndexTerm0,
> +             (AML_NODE_HEADER*)DataNode
> +             );
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler2;
> +  }
> +
> +  DataNode = NULL;
> +
> +  Flags = NumArgs                   |
> +          (IsSerialized ? BIT3 : 0) |
> +          (SyncLevel << 4);
> +
> +  Status = AmlCreateDataNode (EAmlNodeDataTypeUInt, &Flags, 1, &DataNode);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler2;
> +  }
> +
> +  Status = AmlSetFixedArgument (
> +             ObjectNode,
> +             EAmlParseIndexTerm1,
> +             (AML_NODE_HEADER*)DataNode
> +             );
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler2;
> +  }
> +
> +  // Data node is attached so set the pointer to
> +  // NULL to ensure correct error handling.
> +  DataNode = NULL;
> +
> +  Status = LinkNode (
> +             ObjectNode,
> +             ParentNode,
> +             NewObjectNode
> +             );
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler2;
> +  }
> +
> +  // Free AmlNameString before returning as it is copied
> +  // in the call to AmlCreateDataNode().
[SAMI] You could mention the encoding step here.
> +  goto error_handler1;
> +
> +error_handler2:
> +  if (ObjectNode != NULL) {
> +    AmlDeleteTree ((AML_NODE_HEADER*)ObjectNode);
> +  }
> +  if (DataNode != NULL) {
> +    AmlDeleteTree ((AML_NODE_HEADER*)DataNode);
> +  }
> +
> +error_handler1:
> +  if (AmlNameString != NULL) {
> +    FreePool (AmlNameString);
> +  }
> +  return Status;
> +}


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v1 08/13] DynamicTablesPkg: AML code generation to Return a NameString
  2021-06-23 11:40 ` [PATCH v1 08/13] DynamicTablesPkg: AML code generation to Return a NameString PierreGondois
@ 2021-10-01 15:13   ` Sami Mujawar
  0 siblings, 0 replies; 30+ messages in thread
From: Sami Mujawar @ 2021-10-01 15:13 UTC (permalink / raw)
  To: Pierre.Gondois, devel, Alexei Fedorov; +Cc: Akanksha Jain, Alexandru Elisei, nd

[-- Attachment #1: Type: text/plain, Size: 6912 bytes --]

Hi Pierre,

Please find my feedback inline marked [SAMI].

Regards,

Sami Mujawar


On 23/06/2021 12:40 PM, Pierre.Gondois@arm.com wrote:
> From: Pierre Gondois <Pierre.Gondois@arm.com>
>
> Add AmlCodeGenReturnNameString() to generate AML code for a
> Return object node, returning the object as a NameString.
>
> AmlCodeGenReturn ("NAM1", ParentNode, NewObjectNode) is
> equivalent of the following ASL code:
>    Return(NAM1)
>
> Signed-off-by: Pierre Gondois <Pierre.Gondois@arm.com>
> ---
>   .../Common/AmlLib/CodeGen/AmlCodeGen.c        | 178 ++++++++++++++++++
>   1 file changed, 178 insertions(+)
>
> diff --git a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
> index 32665f7f8d8f..75dadbaf4ac3 100644
> --- a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
> +++ b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
> @@ -1137,3 +1137,181 @@ error_handler1:
>     }
>     return Status;
>   }
> +
> +/** AML code generation for a Return object node.
> +
> +  AmlCodeGenReturn (ReturnNode, ParentNode, NewObjectNode) is
> +  equivalent of the following ASL code:
> +    Return([Content of the ReturnNode])
> +
> +  The ACPI 6.3 specification, s20.2.5.3 "Type 1 Opcodes Encoding" states:
> +    DefReturn := ReturnOp ArgObject
> +    ReturnOp := 0xA4
> +    ArgObject := TermArg => DataRefObject
> +
> +  Thus, the ReturnNode must be evaluated as a DataRefObject. It can
> +  be a NameString referencing an object. As this CodeGen Api doesn't
> +  do semantic checking, it is strongly advised to check the AML bytecode
> +  generated by this function against an ASL compiler.
> +
> +  The ReturnNode must be generated inside a Method body scope.
> +
> +  @param [in]  ReturnNode     The object returned by the Return ASL statement.
> +                              This node is deleted if an error occurs.
> +  @param [in]  ParentNode     If provided, set ParentNode as the parent
> +                              of the node created.
[SAMI] Can we mention here that the ParentNode must be a MethodOp Node, 
please? Also is it possible to add a check to that effect.
> +  @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.
> +**/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +AmlCodeGenReturn (
> +  IN  AML_NODE_HEADER     * ReturnNode,
> +  IN  AML_NODE_HEADER     * ParentNode,     OPTIONAL
> +  OUT AML_OBJECT_NODE    ** NewObjectNode   OPTIONAL
> +  )
> +{
> +  EFI_STATUS        Status;
> +  AML_OBJECT_NODE * ObjectNode;
> +
> +  if ((ReturnNode == NULL)  ||
> +      ((ParentNode == NULL) && (NewObjectNode == NULL))) {
> +    ASSERT (0);
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  ObjectNode = NULL;
> +
> +  Status = AmlCreateObjectNode (
> +             AmlGetByteEncodingByOpCode (AML_RETURN_OP, 0),
> +             0,
> +             &ObjectNode
> +             );
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler;
> +  }
> +
> +  Status = AmlSetFixedArgument (
> +             ObjectNode,
> +             EAmlParseIndexTerm0,
> +             (AML_NODE_HEADER*)ReturnNode
> +             );
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler;
> +  }
> +
> +  ReturnNode = NULL;
> +
> +  Status = LinkNode (
> +             ObjectNode,
> +             ParentNode,
> +             NewObjectNode
> +             );
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler;
> +  }
> +
> +  return Status;
> +
> +error_handler:
> +  AmlDeleteTree (ReturnNode);
[SAMI] Add a check to see if ReturnNode is NULL before deleting.
> +  if (ObjectNode != NULL) {
> +    AmlDeleteTree ((AML_NODE_HEADER*)ObjectNode);
> +  }
> +  return Status;
> +}
> +
> +/** AML code generation for a Return object node,
> +    returning the object as an input NameString.
> +
> +  AmlCodeGenReturn ("NAM1", ParentNode, NewObjectNode) is
> +  equivalent of the following ASL code:
> +    Return(NAM1)
> +
> +  The ACPI 6.3 specification, s20.2.5.3 "Type 1 Opcodes Encoding" states:
> +    DefReturn := ReturnOp ArgObject
> +    ReturnOp := 0xA4
> +    ArgObject := TermArg => DataRefObject
> +
> +  Thus, the ReturnNode must be evaluated as a DataRefObject. It can
> +  be a NameString referencing an object. As this CodeGen Api doesn't
> +  do semantic checking, it is strongly advised to check the AML bytecode
> +  generated by this function against an ASL compiler.
> +
> +  The ReturnNode must be generated inside a Method body scope.
> +
> +  @param [in]  NameString     The object referenced by this NameString
> +                              is returned by the Return ASL statement.
> +                              Must be a NULL-terminated ASL NameString
> +                              e.g.: "NAM1", "_SB.NAM1", etc.
> +                              The input string is copied.
> +  @param [in]  ParentNode     If provided, set ParentNode as the parent
> +                              of the node created.
[SAMI] Same comment as above.
> +  @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.
> +**/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +AmlCodeGenReturnNameString (
> +  IN  CONST CHAR8               * NameString,
> +  IN        AML_NODE_HEADER     * ParentNode,     OPTIONAL
> +  OUT       AML_OBJECT_NODE    ** NewObjectNode   OPTIONAL
> +  )
> +{
> +  EFI_STATUS          Status;
> +  AML_DATA_NODE     * DataNode;
> +  CHAR8             * AmlNameString;
> +  UINT32              AmlNameStringSize;
> +
> +  DataNode = NULL;
> +
> +  Status = ConvertAslNameToAmlName (NameString, &AmlNameString);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    return Status;
> +  }
> +
> +  Status = AmlGetNameStringSize (AmlNameString, &AmlNameStringSize);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto exit_handler;
> +  }
> +
> +  Status = AmlCreateDataNode (
> +             EAmlNodeDataTypeNameString,
> +             (UINT8*)AmlNameString,
> +             AmlNameStringSize,
> +             &DataNode
> +             );
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto exit_handler;
> +  }
> +
> +  // AmlCodeGenReturn() deletes DataNode if error.
> +  Status = AmlCodeGenReturn (
> +             (AML_NODE_HEADER*)DataNode,
> +             ParentNode,
> +             NewObjectNode
> +             );
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +  }
[SAMI] Can we replace this withASSERT_EFI_ERROR()?
> +
> +exit_handler:
> +  if (AmlNameString != NULL) {
> +    FreePool (AmlNameString);
> +  }
> +  return Status;
> +}


[-- Attachment #2: Type: text/html, Size: 7828 bytes --]

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v1 09/13] DynamicTablesPkg: AML code generation for a Method returning a NS
  2021-06-23 11:40 ` [PATCH v1 09/13] DynamicTablesPkg: AML code generation for a Method returning a NS PierreGondois
@ 2021-10-01 15:23   ` Sami Mujawar
  2021-10-06 13:33     ` PierreGondois
  0 siblings, 1 reply; 30+ messages in thread
From: Sami Mujawar @ 2021-10-01 15:23 UTC (permalink / raw)
  To: Pierre.Gondois, devel, Alexei Fedorov; +Cc: Akanksha Jain, Alexandru Elisei, nd

Hi Pierre,

Please find my response inline marked [SAMI].

Regards,

Sami Mujawar


On 23/06/2021 12:40 PM, Pierre.Gondois@arm.com wrote:
> From: Pierre Gondois <Pierre.Gondois@arm.com>
>
> Add AmlCodeGenMethodRetNameString() to generate AML code to create
> a Method returning a NameString (NS).
>
> AmlCodeGenMethodRetNameString (
>    "MET0", "_CRS", 1, TRUE, 3, ParentNode, NewObjectNode
>    );
> is equivalent of the following ASL code:
> Method(MET0, 1, Serialized, 3) {
>    Return (_CRS)
> }
>
> Signed-off-by: Pierre Gondois <Pierre.Gondois@arm.com>
> ---
>   .../Include/Library/AmlLib/AmlLib.h           |  53 +++++++++
>   .../Common/AmlLib/CodeGen/AmlCodeGen.c        | 106 ++++++++++++++++++
>   2 files changed, 159 insertions(+)
>
> diff --git a/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h b/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h
> index 6824cf3a6c82..7740aac24470 100644
> --- a/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h
> +++ b/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h
> @@ -619,6 +619,59 @@ AmlCodeGenScope (
>     OUT       AML_OBJECT_NODE_HANDLE  * NewObjectNode   OPTIONAL
>     );
>   
> +/** AML code generation for a method returning a NameString.
> +
> +  AmlCodeGenMethodRetNameString (
> +    "MET0", "_CRS", 1, TRUE, 3, ParentNode, NewObjectNode
> +    );
> +  is equivalent of the following ASL code:
> +    Method(MET0, 1, Serialized, 3) {
> +      Return (_CRS)
> +    }
> +
> +  The ASL parameters "ReturnType" and "ParameterTypes" are not asked
> +  in this function. They are optional parameters in ASL.
> +
> +  @ingroup CodeGenApis
> +
> +  @param [in]  MethodNameString     The new Method's name.
> +                                    Must be a NULL-terminated ASL NameString
> +                                    e.g.: "MET0", "_SB.MET0", etc.
> +                                    The input string is copied.
> +  @param [in]  ReturnedNameString   The name of the object returned by the
> +                                    method. Optional parameter, can be:
> +                                     - NULL (ignored).
> +                                     - A NULL-terminated ASL NameString.
> +                                       e.g.: "MET0", "_SB.MET0", etc.
> +                                       The input string is copied.
[SAMI] I think this should be a mandatory parameter and corresponding 
change is needed to the function code.
> +  @param [in]  NumArgs              Number of arguments.
> +                                    Must be 0 <= NumArgs <= 6.
> +  @param [in]  IsSerialized         TRUE is equivalent to Serialized.
> +                                    FALSE is equivalent to NotSerialized.
> +                                    Default is NotSerialized in ASL spec.
> +  @param [in]  SyncLevel            Synchronization level for the method.
> +                                    Must be 0 <= SyncLevel <= 15.
> +                                    Default is 0 in ASL.
> +  @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
> +AmlCodeGenMethodRetNameString (
> +  IN  CONST CHAR8                   * MethodNameString,
> +  IN  CONST CHAR8                   * ReturnedNameString,  OPTIONAL
> +  IN        UINT8                     NumArgs,
> +  IN        BOOLEAN                   IsSerialized,
> +  IN        UINT8                     SyncLevel,
> +  IN        AML_NODE_HANDLE           ParentNode,          OPTIONAL
> +  OUT       AML_OBJECT_NODE_HANDLE  * NewObjectNode        OPTIONAL
> +  );
> +
>   // DEPRECATED APIS
>   #ifndef DISABLE_NEW_DEPRECATED_INTERFACES
>   
> diff --git a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
> index 75dadbaf4ac3..a9922871c311 100644
> --- a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
> +++ b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
> @@ -1315,3 +1315,109 @@ exit_handler:
>     }
>     return Status;
>   }
> +
> +/** AML code generation for a method returning a NameString.
> +
> +  AmlCodeGenMethodRetNameString (
> +    "MET0", "_CRS", 1, TRUE, 3, ParentNode, NewObjectNode
> +    );
> +  is equivalent of the following ASL code:
> +    Method(MET0, 1, Serialized, 3) {
> +      Return (_CRS)
> +    }
> +
> +  The ASL parameters "ReturnType" and "ParameterTypes" are not asked
> +  in this function. They are optional parameters in ASL.
> +
> +  @param [in]  MethodNameString     The new Method's name.
> +                                    Must be a NULL-terminated ASL NameString
> +                                    e.g.: "MET0", "_SB.MET0", etc.
> +                                    The input string is copied.
> +  @param [in]  ReturnedNameString   The name of the object returned by the
> +                                    method. Optional parameter, can be:
> +                                     - NULL (ignored).
> +                                     - A NULL-terminated ASL NameString.
> +                                       e.g.: "MET0", "_SB.MET0", etc.
> +                                       The input string is copied.
> +  @param [in]  NumArgs              Number of arguments.
> +                                    Must be 0 <= NumArgs <= 6.
> +  @param [in]  IsSerialized         TRUE is equivalent to Serialized.
> +                                    FALSE is equivalent to NotSerialized.
> +                                    Default is NotSerialized in ASL spec.
> +  @param [in]  SyncLevel            Synchronization level for the method.
> +                                    Must be 0 <= SyncLevel <= 15.
> +                                    Default is 0 in ASL.
> +  @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
> +AmlCodeGenMethodRetNameString (
> +  IN  CONST CHAR8                   * MethodNameString,
> +  IN  CONST CHAR8                   * ReturnedNameString,  OPTIONAL
> +  IN        UINT8                     NumArgs,
> +  IN        BOOLEAN                   IsSerialized,
> +  IN        UINT8                     SyncLevel,
> +  IN        AML_NODE_HANDLE           ParentNode,          OPTIONAL
> +  OUT       AML_OBJECT_NODE_HANDLE  * NewObjectNode        OPTIONAL
> +  )
> +{
> +  EFI_STATUS                Status;
> +  AML_OBJECT_NODE_HANDLE    MethodNode;
> +
> +  if ((MethodNameString == NULL)  ||
> +      ((ParentNode == NULL) && (NewObjectNode == NULL))) {
> +    ASSERT (0);
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  // Create a Method named MethodNameString.
> +  Status = AmlCodeGenMethod (
> +             MethodNameString,
> +             NumArgs,
> +             IsSerialized,
> +             SyncLevel,
> +             NULL,
> +             &MethodNode
> +             );
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    return Status;
> +  }
> +
> +  // Return ReturnedNameString if provided.
> +  if (ReturnedNameString != NULL) {
> +    Status = AmlCodeGenReturnNameString (
> +               ReturnedNameString,
> +               (AML_NODE_HANDLE)MethodNode,
> +               NULL
> +               );
> +    if (EFI_ERROR (Status)) {
> +      ASSERT (0);
> +      goto error_handler;
> +    }
> +  }
> +
> +  Status = LinkNode (
> +             MethodNode,
> +             ParentNode,
> +             NewObjectNode
> +             );
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler;
> +  }
> +
> +  return Status;
> +
> +error_handler:
> +  if (MethodNode != NULL) {
> +    AmlDeleteTree ((AML_NODE_HANDLE)MethodNode);
> +  }
> +  return Status;
> +}


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v1 10/13] DynamicTablesPkg: AML code generation for a _LPI object
  2021-06-23 11:40 ` [PATCH v1 10/13] DynamicTablesPkg: AML code generation for a _LPI object PierreGondois
@ 2021-10-01 15:31   ` Sami Mujawar
  0 siblings, 0 replies; 30+ messages in thread
From: Sami Mujawar @ 2021-10-01 15:31 UTC (permalink / raw)
  To: Pierre.Gondois, devel, Alexei Fedorov; +Cc: Akanksha Jain, Alexandru Elisei, nd

Hi Pierre,

Please find my response inline marked [SAMI].

Regards,

Sami Mujawar


On 23/06/2021 12:40 PM, Pierre.Gondois@arm.com wrote:
> From: Pierre Gondois <Pierre.Gondois@arm.com>
>
> _LPI object provides a method to describe Low Power Idle
> states that define the local power states for each node
> in a hierarchical processor topology.
>
> Therefore, add AmlCreateLpiNode() to generate code for a
> _LPI object.
>
> AmlCreateLpiNode ("_LPI", 0, 1, ParentNode, &LpiNode) is
> equivalent of the following ASL code:
>    Name (_LPI, Package (
> 		0,  // Revision
> 		1,  // LevelId
> 		0   // Count
> 		))
>
> Signed-off-by: Pierre Gondois <Pierre.Gondois@arm.com>
> ---
>   .../Include/Library/AmlLib/AmlLib.h           |  44 ++++++
>   .../Common/AmlLib/CodeGen/AmlCodeGen.c        | 133 ++++++++++++++++++
>   2 files changed, 177 insertions(+)
>
> diff --git a/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h b/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h
> index 7740aac24470..40c45073d303 100644
> --- a/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h
> +++ b/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h
> @@ -672,6 +672,50 @@ AmlCodeGenMethodRetNameString (
>     OUT       AML_OBJECT_NODE_HANDLE  * NewObjectNode        OPTIONAL
>     );
>   
> +/** Create a _LPI name.
> +
> +  AmlCreateLpiNode ("_LPI", 0, 1, ParentNode, &LpiNode) is
> +  equivalent of the following ASL code:
> +    Name (_LPI, Package (
> +                  0,  // Revision
> +                  1,  // LevelId
> +                  0   // Count
> +                  ))
> +
> +  This function doesn't define any LPI state. As shown above, the count
> +  of _LPI state is set to 0.
> +  The AmlAddLpiState () function must be used to add LPI states.
> +
> +  Cf ACPI 6.3 specification, s8.4.4 "Lower Power Idle States".
> +
> +  @ingroup CodeGenApis
> +
> +  @param [in]  LpiNameString  The new LPI 's object name.
> +                              Must be a NULL-terminated ASL NameString
> +                              e.g.: "_LPI", "DEV0.PLPI", etc.
> +                              The input string is copied.
> +  @param [in]  Revision       Revision number of the _LPI states.
> +  @param [in]  LevelId        A platform defined number that identifies the
> +                              level of hierarchy of the processor node to
> +                              which the LPI states apply.
> +  @param [in]  ParentNode     If provided, set ParentNode as the parent
> +                              of the node created.
> +  @param [out] NewLpiNode     If success, contains the created node.
> +
> +  @retval EFI_SUCCESS             The function completed successfully.
> +  @retval EFI_INVALID_PARAMETER   Invalid parameter.
> +  @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
> +**/
> +EFI_STATUS
> +EFIAPI
> +AmlCreateLpiNode (
> +  IN  CONST CHAR8                   * LpiNameString,
> +  IN        UINT16                    Revision,
> +  IN        UINT64                    LevelId,
> +  IN        AML_NODE_HANDLE           ParentNode,  OPTIONAL
> +  OUT       AML_OBJECT_NODE_HANDLE  * NewLpiNode   OPTIONAL
> +  );
> +
>   // DEPRECATED APIS
>   #ifndef DISABLE_NEW_DEPRECATED_INTERFACES
>   
> diff --git a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
> index a9922871c311..89350f65f5df 100644
> --- a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
> +++ b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
> @@ -1421,3 +1421,136 @@ error_handler:
>     }
>     return Status;
>   }
> +
> +/** Create a _LPI name.
> +
> +  AmlCreateLpiNode ("_LPI", 0, 1, ParentNode, &LpiNode) is
> +  equivalent of the following ASL code:
> +    Name (_LPI, Package (
> +                  0,  // Revision
> +                  1,  // LevelId
> +                  0   // Count
> +                  ))
> +
> +  This function doesn't define any LPI state. As shown above, the count
> +  of _LPI state is set to 0.
> +  The AmlAddLpiState () function allows to add LPI states.
> +
> +  Cf ACPI 6.3 specification, s8.4.4 "Lower Power Idle States".
> +
> +  @param [in]  LpiNameString  The new LPI 's object name.
> +                              Must be a NULL-terminated ASL NameString
> +                              e.g.: "_LPI", "DEV0.PLPI", etc.
> +                              The input string is copied.
> +  @param [in]  Revision       Revision number of the _LPI states.
> +  @param [in]  LevelId        A platform defined number that identifies the
> +                              level of hierarchy of the processor node to
> +                              which the LPI states apply.
> +  @param [in]  ParentNode     If provided, set ParentNode as the parent
> +                              of the node created.
> +  @param [out] NewLpiNode     If success, contains the created node.
> +
> +  @retval EFI_SUCCESS             The function completed successfully.
> +  @retval EFI_INVALID_PARAMETER   Invalid parameter.
> +  @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
> +**/
> +EFI_STATUS
> +EFIAPI
> +AmlCreateLpiNode (
> +  IN  CONST CHAR8                   * LpiNameString,
> +  IN        UINT16                    Revision,
> +  IN        UINT64                    LevelId,
> +  IN        AML_NODE_HANDLE           ParentNode,  OPTIONAL
> +  OUT       AML_OBJECT_NODE_HANDLE  * NewLpiNode   OPTIONAL
> +  )
> +{
> +  EFI_STATUS                Status;
> +  AML_OBJECT_NODE_HANDLE    PackageNode;
> +  AML_OBJECT_NODE_HANDLE    IntegerNode;
> +
> +  if ((LpiNameString == NULL)                           ||
> +      ((ParentNode == NULL) && (NewLpiNode == NULL))) {
> +    ASSERT (0);
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  IntegerNode = NULL;
> +
> +  Status = AmlCodeGenPackage (&PackageNode);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    return Status;
> +  }
> +
> +  // Create and attach Revision
> +  Status = AmlCodeGenInteger (Revision, &IntegerNode);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler;
> +  }
> +
> +  Status = AmlVarListAddTail (
> +             (AML_NODE_HANDLE)PackageNode,
> +             (AML_NODE_HANDLE)IntegerNode
> +             );
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler;
> +  }
> +
> +  IntegerNode = NULL;
> +
> +  // Create and attach LevelId
> +  Status = AmlCodeGenInteger (LevelId, &IntegerNode);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler;
> +  }
> +
> +  Status = AmlVarListAddTail (
> +             (AML_NODE_HANDLE)PackageNode,
> +             (AML_NODE_HANDLE)IntegerNode
> +             );
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler;
> +  }
> +
> +  IntegerNode = NULL;
> +
> +  // Create and attach Count. No LPI state is added, so 0.
> +  Status = AmlCodeGenInteger (0, &IntegerNode);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    IntegerNode = NULL;
[SAMI] Can you check if setting the IntegerNode to NULL is needed here?
> +    goto error_handler;
> +  }
> +
> +  Status = AmlVarListAddTail (
> +             (AML_NODE_HANDLE)PackageNode,
> +             (AML_NODE_HANDLE)IntegerNode
> +             );
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler;
> +  }
> +
> +  IntegerNode = NULL;
> +
> +  Status = AmlCodeGenName (LpiNameString, PackageNode, ParentNode, NewLpiNode);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler;
> +  }
> +
> +  return Status;
> +
> +error_handler:
> +  if (PackageNode != NULL) {
> +    AmlDeleteTree ((AML_NODE_HANDLE)PackageNode);
> +  }
> +  if (IntegerNode != NULL) {
> +    AmlDeleteTree ((AML_NODE_HANDLE)IntegerNode);
> +  }
> +  return Status;
> +}


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v1 11/13] DynamicTablesPkg: AML code generation to add an _LPI state
  2021-06-23 11:40 ` [PATCH v1 11/13] DynamicTablesPkg: AML code generation to add an _LPI state PierreGondois
@ 2021-10-01 15:43   ` Sami Mujawar
  0 siblings, 0 replies; 30+ messages in thread
From: Sami Mujawar @ 2021-10-01 15:43 UTC (permalink / raw)
  To: Pierre.Gondois, devel, Alexei Fedorov; +Cc: Akanksha Jain, Alexandru Elisei, nd

[-- Attachment #1: Type: text/plain, Size: 21069 bytes --]

Hi Pierre,

Please find my response inline marked [SAMI].

Regards,

Sami Mujawar

On 23/06/2021 12:40 PM, Pierre.Gondois@arm.com wrote:
> From: Pierre Gondois <Pierre.Gondois@arm.com>
>
> Add AmlAddLpiState() to generates AML code to add an _LPI state
> to an _LPI object created using AmlCreateLpiNode().
>
> AmlAddLpiState increments the count of LPI states in the LPI
> node by one, and adds the following package:
>    Package() {
>      MinResidency,
>      WorstCaseWakeLatency,
>      Flags,
>      ArchFlags,
>      ResCntFreq,
>      EnableParentState,
>      (GenericRegisterDescriptor != NULL) ?           // Entry method. If a
>        ResourceTemplate(GenericRegisterDescriptor) : // Register is given,
>        Integer,                                      // use it. Use the
>                                                      // Integer otherwise
>      ResourceTemplate() {                            // NULL Residency
>        Register (SystemMemory, 0, 0, 0, 0)           // Counter
>      },
>      ResourceTemplate() {                            // NULL Usage Counter
>        Register (SystemMemory, 0, 0, 0, 0)
>      },
>      ""                                              // NULL State Name
>    },
>
> Signed-off-by: Pierre Gondois <Pierre.Gondois@arm.com>
> ---
>   .../Include/Library/AmlLib/AmlLib.h           |  71 +++
>   .../Common/AmlLib/CodeGen/AmlCodeGen.c        | 439 ++++++++++++++++++
>   2 files changed, 510 insertions(+)
>
> diff --git a/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h b/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h
> index 40c45073d303..4932f6fd9c8b 100644
> --- a/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h
> +++ b/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h
> @@ -716,6 +716,77 @@ AmlCreateLpiNode (
>     OUT       AML_OBJECT_NODE_HANDLE  * NewLpiNode   OPTIONAL
>     );
>   
> +/** Add an _LPI state to a LPI node created using AmlCreateLpiNode ().
> +
> +  AmlAddLpiState () increments the Count of LPI states in the LPI node by one,
> +  and adds the following package:
> +    Package() {
> +      MinResidency,
> +      WorstCaseWakeLatency,
> +      Flags,
> +      ArchFlags,
> +      ResCntFreq,
> +      EnableParentState,
> +      (GenericRegisterDescriptor != NULL) ?           // Entry method. If a
> +        ResourceTemplate(GenericRegisterDescriptor) : // Register is given,
> +        Integer,                                      // use it. Use the
> +                                                      // Integer otherwise.
> +      ResourceTemplate() {                            // NULL Residency Counter
> +        Register (SystemMemory, 0, 0, 0, 0)
> +      },
> +      ResourceTemplate() {                            // NULL Usage Counter
> +        Register (SystemMemory, 0, 0, 0, 0)
> +      },
> +      ""                                              // NULL State Name
> +    },
> +
> +  Cf ACPI 6.3 specification, s8.4.4 "Lower Power Idle States".
> +
> +  @ingroup CodeGenApis
> +
> +  @param [in]  MinResidency               Minimum Residency.
> +  @param [in]  WorstCaseWakeLatency       Worst case wake-up latency.
> +  @param [in]  Flags                      Flags.
> +  @param [in]  ArchFlags                  Architectural flags.
> +  @param [in]  ResCntFreq                 Residency Counter Frequency.
> +  @param [in]  EnableParentState          Enabled Parent State.
> +  @param [in]  GenericRegisterDescriptor  Entry Method.
> +                                          If not NULL, use this Register to
> +                                          describe the entry method address.
> +  @param [in]  Integer                    Entry Method.
> +                                          If GenericRegisterDescriptor is NULL,
> +                                          take this value.
> +  @param [in]  ResidencyCounterRegister   If not NULL, use it to populate the
> +                                          residency counter register.
> +  @param [in]  UsageCounterRegister       If not NULL, use it to populate the
> +                                          usage counter register.
> +  @param [in]  StateName                  If not NULL, use it to populate the
> +                                          state name.
> +  @param [in]  LpiNode                    Lpi node created with the function
> +                                          AmlCreateLpiNode to which the new LPI
> +                                          state is appended.
> +
> +  @retval EFI_SUCCESS             The function completed successfully.
> +  @retval EFI_INVALID_PARAMETER   Invalid parameter.
> +  @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
> +**/
> +EFI_STATUS
> +EFIAPI
> +AmlAddLpiState (
> +  IN  UINT32                                    MinResidency,
> +  IN  UINT32                                    WorstCaseWakeLatency,
> +  IN  UINT32                                    Flags,
> +  IN  UINT32                                    ArchFlags,
> +  IN  UINT32                                    ResCntFreq,
> +  IN  UINT32                                    EnableParentState,
> +  IN  EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE  * GenericRegisterDescriptor,  OPTIONAL
> +  IN  UINT64                                    Integer,                    OPTIONAL
> +  IN  EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE  * ResidencyCounterRegister,   OPTIONAL
> +  IN  EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE  * UsageCounterRegister,       OPTIONAL
> +  IN  CHAR8                                   * StateName,                  OPTIONAL
> +  IN  AML_OBJECT_NODE_HANDLE                    LpiNode
> +  );
> +
>   // DEPRECATED APIS
>   #ifndef DISABLE_NEW_DEPRECATED_INTERFACES
>   
> diff --git a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
> index 89350f65f5df..f0861040191f 100644
> --- a/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
> +++ b/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
> @@ -12,6 +12,7 @@
>   
>   #include <AmlCoreInterface.h>
>   #include <AmlEncoding/Aml.h>
> +#include <Api/AmlApiHelper.h>
>   #include <CodeGen/AmlResourceDataCodeGen.h>
>   #include <Tree/AmlNode.h>
>   #include <Tree/AmlTree.h>
> @@ -1554,3 +1555,441 @@ error_handler:
>     }
>     return Status;
>   }
> +
> +/** Add an _LPI state to a LPI node created using AmlCreateLpiNode.
> +
> +  AmlAddLpiState increments the Count of LPI states in the LPI node by one,
> +  and adds the following package:
> +    Package() {
> +      MinResidency,
> +      WorstCaseWakeLatency,
> +      Flags,
> +      ArchFlags,
> +      ResCntFreq,
> +      EnableParentState,
> +      (GenericRegisterDescriptor != NULL) ?           // Entry method. If a
> +        ResourceTemplate(GenericRegisterDescriptor) : // Register is given,
> +        Integer,                                      // use it. Use the
> +                                                      // Integer otherwise.
> +      ResourceTemplate() {                            // NULL Residency Counter
> +        Register (SystemMemory, 0, 0, 0, 0)
> +      },
> +      ResourceTemplate() {                            // NULL Usage Counter
> +        Register (SystemMemory, 0, 0, 0, 0)
> +      },
> +      ""                                              // NULL State Name
> +    },
> +
> +  Cf ACPI 6.3 specification, s8.4.4 "Lower Power Idle States".
> +
> +  @param [in]  MinResidency               Minimum Residency.
> +  @param [in]  WorstCaseWakeLatency       Worst case wake-up latency.
> +  @param [in]  Flags                      Flags.
> +  @param [in]  ArchFlags                  Architectural flags.
> +  @param [in]  ResCntFreq                 Residency Counter Frequency.
> +  @param [in]  EnableParentState          Enabled Parent State.
> +  @param [in]  GenericRegisterDescriptor  Entry Method.
> +                                          If not NULL, use this Register to
> +                                          describe the entry method address.
> +  @param [in]  Integer                    Entry Method.
> +                                          If GenericRegisterDescriptor is NULL,
> +                                          take this value.
> +  @param [in]  ResidencyCounterRegister   If not NULL, use it to populate the
> +                                          residency counter register.
> +  @param [in]  UsageCounterRegister       If not NULL, use it to populate the
> +                                          usage counter register.
> +  @param [in]  StateName                  If not NULL, use it to populate the
> +                                          state name.
> +  @param [in]  LpiNode                    Lpi node created with the function
> +                                          AmlCreateLpiNode to which the new LPI
> +                                          state is appended.
> +
> +  @retval EFI_SUCCESS             The function completed successfully.
> +  @retval EFI_INVALID_PARAMETER   Invalid parameter.
> +  @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
> +**/
> +EFI_STATUS
> +EFIAPI
> +AmlAddLpiState (
> +  IN  UINT32                                    MinResidency,
> +  IN  UINT32                                    WorstCaseWakeLatency,
> +  IN  UINT32                                    Flags,
> +  IN  UINT32                                    ArchFlags,
> +  IN  UINT32                                    ResCntFreq,
> +  IN  UINT32                                    EnableParentState,
> +  IN  EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE  * GenericRegisterDescriptor,  OPTIONAL
> +  IN  UINT64                                    Integer,                    OPTIONAL
> +  IN  EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE  * ResidencyCounterRegister,   OPTIONAL
> +  IN  EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE  * UsageCounterRegister,       OPTIONAL
> +  IN  CHAR8                                   * StateName,                  OPTIONAL
> +  IN  AML_OBJECT_NODE_HANDLE                    LpiNode
> +  )
> +{
> +  EFI_STATUS                Status;
> +  AML_DATA_NODE_HANDLE      RdNode;
> +  AML_OBJECT_NODE_HANDLE    PackageNode;
> +  AML_OBJECT_NODE_HANDLE    IntegerNode;
> +  AML_OBJECT_NODE_HANDLE    StringNode;
> +  AML_OBJECT_NODE_HANDLE    NewLpiPackageNode;
> +  AML_OBJECT_NODE_HANDLE    ResourceTemplateNode;
> +
> +  UINT32                    Index;
> +  AML_OBJECT_NODE_HANDLE    CountNode;
> +  UINT64                    Count;
> +
> +  if ((LpiNode == NULL)                                              ||
> +      (AmlGetNodeType ((AML_NODE_HANDLE)LpiNode) != EAmlNodeObject)  ||
> +      (!AmlNodeHasOpCode (LpiNode, AML_NAME_OP, 0))) {
> +    ASSERT (0);
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  RdNode = 0;
> +  StringNode = NULL;
> +  IntegerNode = NULL;
> +  ResourceTemplateNode = NULL;
> +
> +  // Get the LPI value which is represented as a PackageOp object node
> +  // which is the 2nd fixed argument (i.e. index 1).
> +  PackageNode = (AML_OBJECT_NODE_HANDLE)AmlGetFixedArgument (
> +                                          LpiNode,
> +                                          EAmlParseIndexTerm1
> +                                          );
> +  if ((PackageNode == NULL)                                             ||
> +      (AmlGetNodeType ((AML_NODE_HANDLE)PackageNode) != EAmlNodeObject) ||
> +      (!AmlNodeHasOpCode (PackageNode, AML_PACKAGE_OP, 0))) {
> +    ASSERT (0);
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  CountNode = NULL;
> +  // The third variable argument is the LPI Count node.
> +  for (Index = 0; Index < 3; Index++) {
> +    CountNode = (AML_OBJECT_NODE_HANDLE)AmlGetNextVariableArgument (
> +                                          (AML_NODE_HANDLE)PackageNode,
> +                                          (AML_NODE_HANDLE)CountNode
> +                                          );
> +    if (CountNode == NULL) {
> +      ASSERT (0);
> +      return EFI_INVALID_PARAMETER;
> +    }
> +  }
> +
> +  Status = AmlNodeGetIntegerValue (CountNode, &Count);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    return Status;
> +  }
> +  Status = AmlUpdateInteger (CountNode, Count + 1);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    return Status;
> +  }
> +
> +  Status = AmlCodeGenPackage (&NewLpiPackageNode);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    return Status;
> +  }
> +
> +  // MinResidency
> +  Status = AmlCodeGenInteger (MinResidency, &IntegerNode);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler;
> +  }
> +  Status = AmlVarListAddTail (
> +             (AML_NODE_HANDLE)NewLpiPackageNode,
> +             (AML_NODE_HANDLE)IntegerNode
> +             );
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler;
> +  }
> +  IntegerNode = NULL;
> +
> +  // WorstCaseWakeLatency
> +  Status = AmlCodeGenInteger (WorstCaseWakeLatency, &IntegerNode);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler;
> +  }
> +  Status = AmlVarListAddTail (
> +             (AML_NODE_HANDLE)NewLpiPackageNode,
> +             (AML_NODE_HANDLE)IntegerNode
> +             );
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler;
> +  }
> +  IntegerNode = NULL;
> +
> +  // Flags
> +  Status = AmlCodeGenInteger (Flags, &IntegerNode);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler;
> +  }
> +  Status = AmlVarListAddTail (
> +             (AML_NODE_HANDLE)NewLpiPackageNode,
> +             (AML_NODE_HANDLE)IntegerNode
> +             );
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler;
> +  }
> +  IntegerNode = NULL;
> +
> +  // ArchFlags
> +  Status = AmlCodeGenInteger (ArchFlags, &IntegerNode);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler;
> +  }
> +  Status = AmlVarListAddTail (
> +             (AML_NODE_HANDLE)NewLpiPackageNode,
> +             (AML_NODE_HANDLE)IntegerNode
> +             );
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler;
> +  }
> +  IntegerNode = NULL;
> +
> +  // ResCntFreq
> +  Status = AmlCodeGenInteger (ResCntFreq, &IntegerNode);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler;
> +  }
> +  Status = AmlVarListAddTail (
> +             (AML_NODE_HANDLE)NewLpiPackageNode,
> +             (AML_NODE_HANDLE)IntegerNode
> +             );
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler;
> +  }
> +  IntegerNode = NULL;
> +
> +  // EnableParentState
> +  Status = AmlCodeGenInteger (EnableParentState, &IntegerNode);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler;
> +  }
> +  Status = AmlVarListAddTail (
> +             (AML_NODE_HANDLE)NewLpiPackageNode,
> +             (AML_NODE_HANDLE)IntegerNode
> +             );
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler;
> +  }
> +  IntegerNode = NULL;
> +
> +  // Entry Method
> +  if (GenericRegisterDescriptor != NULL) {
> +    // Entry Method: As a Register resource data
> +    Status = AmlCodeGenResourceTemplate (&ResourceTemplateNode);
> +    if (EFI_ERROR (Status)) {
> +      ASSERT (0);
> +      goto error_handler;
> +    }
> +    Status = AmlCodeGenRdRegister (
> +               GenericRegisterDescriptor->AddressSpaceId,
> +               GenericRegisterDescriptor->RegisterBitWidth,
> +               GenericRegisterDescriptor->RegisterBitOffset,
> +               GenericRegisterDescriptor->Address,
> +               GenericRegisterDescriptor->AccessSize,
> +               NULL,
> +               &RdNode
> +               );
> +    if (EFI_ERROR (Status)) {
> +      ASSERT (0);
> +      goto error_handler;
> +    }
> +
> +    Status = AmlAppendRdNode (ResourceTemplateNode, RdNode);
> +    if (EFI_ERROR (Status)) {
> +      ASSERT (0);
> +      goto error_handler;
> +    }
> +    RdNode = NULL;
> +
> +    Status = AmlVarListAddTail (
> +               (AML_NODE_HANDLE)NewLpiPackageNode,
> +               (AML_NODE_HANDLE)ResourceTemplateNode
> +               );
> +    if (EFI_ERROR (Status)) {
> +      ASSERT (0);
> +      goto error_handler;
> +    }
> +    ResourceTemplateNode = NULL;
> +  } else {
> +    // Entry Method: As an integer
> +    Status = AmlCodeGenInteger (Integer, &IntegerNode);
> +    if (EFI_ERROR (Status)) {
> +      ASSERT (0);
> +      goto error_handler;
> +    }
> +    Status = AmlVarListAddTail (
> +               (AML_NODE_HANDLE)NewLpiPackageNode,
> +               (AML_NODE_HANDLE)IntegerNode
> +               );
> +    if (EFI_ERROR (Status)) {
> +      ASSERT (0);
> +      goto error_handler;
> +    }
> +    IntegerNode = NULL;
> +  }
> +
> +  // Residency Counter Register.
> +  Status = AmlCodeGenResourceTemplate (&ResourceTemplateNode);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler;
> +  }
> +  if (ResidencyCounterRegister != NULL) {
> +    Status = AmlCodeGenRdRegister (
> +               ResidencyCounterRegister->AddressSpaceId,
> +               ResidencyCounterRegister->RegisterBitWidth,
> +               ResidencyCounterRegister->RegisterBitOffset,
> +               ResidencyCounterRegister->Address,
> +               ResidencyCounterRegister->AccessSize,
> +               NULL,
> +               &RdNode
> +               );
> +  } else {
> +    Status = AmlCodeGenRdRegister (
> +               EFI_ACPI_2_0_SYSTEM_MEMORY,
> +               0,
> +               0,
> +               0,
> +               0,
> +               NULL,
> +               &RdNode
> +               );
> +  }
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler;
> +  }
> +
> +  Status = AmlAppendRdNode (ResourceTemplateNode, RdNode);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler;
> +  }
> +  RdNode = NULL;
> +
> +  Status = AmlVarListAddTail (
> +             (AML_NODE_HANDLE)NewLpiPackageNode,
> +             (AML_NODE_HANDLE)ResourceTemplateNode
> +             );
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler;
> +  }
> +  ResourceTemplateNode = NULL;
> +
> +  // Usage Counter Register.
> +  Status = AmlCodeGenResourceTemplate (&ResourceTemplateNode);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler;
> +  }
> +  if (UsageCounterRegister != NULL) {
> +    Status = AmlCodeGenRdRegister (
> +               UsageCounterRegister->AddressSpaceId,
> +               UsageCounterRegister->RegisterBitWidth,
> +               UsageCounterRegister->RegisterBitOffset,
> +               UsageCounterRegister->Address,
> +               UsageCounterRegister->AccessSize,
> +               NULL,
> +               &RdNode
> +               );
> +  } else {
> +    Status = AmlCodeGenRdRegister (
> +               EFI_ACPI_2_0_SYSTEM_MEMORY,
[SAMI] Can we useEFI_ACPI_6_4_SYSTEM_MEMORY here instead?
> +               0,
> +               0,
> +               0,
> +               0,
> +               NULL,
> +               &RdNode
> +               );
> +  }
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler;
> +  }
> +
> +  Status = AmlAppendRdNode (ResourceTemplateNode, RdNode);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler;
> +  }
> +  RdNode = NULL;
> +
> +  Status = AmlVarListAddTail (
> +             (AML_NODE_HANDLE)NewLpiPackageNode,
> +             (AML_NODE_HANDLE)ResourceTemplateNode
> +             );
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler;
> +  }
> +  ResourceTemplateNode = NULL;
> +
> +  // State name.
> +  if (UsageCounterRegister != NULL) {
> +    Status = AmlCodeGenString (StateName, &StringNode);
> +  } else {
> +    Status = AmlCodeGenString ("", &StringNode);
> +  }
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler;
> +  }
> +  Status = AmlVarListAddTail (
> +             (AML_NODE_HANDLE)NewLpiPackageNode,
> +             (AML_NODE_HANDLE)StringNode
> +             );
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler;
> +  }
> +  StringNode = NULL;
> +
> +  // Add the new LPI state to the LpiNode.
> +  Status = AmlVarListAddTail (
> +             (AML_NODE_HANDLE)PackageNode,
> +             (AML_NODE_HANDLE)NewLpiPackageNode
> +             );
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto error_handler;
> +  }
> +
> +  return Status;
> +
> +error_handler:
> +  if (RdNode != NULL) {
> +    AmlDeleteTree ((AML_NODE_HANDLE)RdNode);
> +  }
> +  if (NewLpiPackageNode != NULL) {
> +    AmlDeleteTree ((AML_NODE_HANDLE)NewLpiPackageNode);
> +  }
> +  if (StringNode != NULL) {
> +    AmlDeleteTree ((AML_NODE_HANDLE)StringNode);
> +  }
> +  if (IntegerNode != NULL) {
> +    AmlDeleteTree ((AML_NODE_HANDLE)IntegerNode);
> +  }
> +  if (ResourceTemplateNode != NULL) {
> +    AmlDeleteTree ((AML_NODE_HANDLE)ResourceTemplateNode);
> +  }
> +
> +  return Status;
> +}


[-- Attachment #2: Type: text/html, Size: 20890 bytes --]

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v1 13/13] DynamicTablesPkg: SSDT CPU topology and LPI state generator
  2021-06-23 11:40 ` [PATCH v1 13/13] DynamicTablesPkg: SSDT CPU topology and LPI state generator PierreGondois
@ 2021-10-05 14:38   ` Sami Mujawar
  0 siblings, 0 replies; 30+ messages in thread
From: Sami Mujawar @ 2021-10-05 14:38 UTC (permalink / raw)
  To: Pierre.Gondois, devel, Alexei Fedorov; +Cc: Akanksha Jain, Alexandru Elisei, nd

Hi Pierre,

I ahve a few minor suggestions marked inline as [SAMI].

With those changed.

Reviewed-by: Sami Mujawar <sami.mujawar@arm.com>

Regards,

Sami Mujawar


On 23/06/2021 12:40 PM, Pierre.Gondois@arm.com wrote:
> From: Pierre Gondois <Pierre.Gondois@arm.com>
>
> In the GIC interrupt model, 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.
> Additionally, _LPI objects may be needed as they provide a method
> to describe Low Power Idle states that defines the local power
> states for each node in a hierarchical processor topology.
>
> Therefore, add support to generate the CPU topology and the LPI
> state information in an SSDT table.
>
> Signed-off-by: Pierre Gondois <Pierre.Gondois@arm.com>
> ---
>   DynamicTablesPkg/DynamicTables.dsc.inc        |    6 +
>   DynamicTablesPkg/Include/AcpiTableGenerator.h |    7 +-
>   .../SsdtCpuTopologyGenerator.c                | 1230 +++++++++++++++++
>   .../SsdtCpuTopologyGenerator.h                |  134 ++
>   .../SsdtCpuTopologyLibArm.inf                 |   40 +
>   5 files changed, 1416 insertions(+), 1 deletion(-)
>   create mode 100644 DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCpuTopologyLibArm/SsdtCpuTopologyGenerator.c
>   create mode 100644 DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCpuTopologyLibArm/SsdtCpuTopologyGenerator.h
>   create mode 100644 DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCpuTopologyLibArm/SsdtCpuTopologyLibArm.inf
>
> diff --git a/DynamicTablesPkg/DynamicTables.dsc.inc b/DynamicTablesPkg/DynamicTables.dsc.inc
> index ed221d1681eb..292215c39456 100644
> --- a/DynamicTablesPkg/DynamicTables.dsc.inc
> +++ b/DynamicTablesPkg/DynamicTables.dsc.inc
> @@ -37,6 +37,9 @@ [Components.common]
>     DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtSerialPortLibArm/SsdtSerialPortLibArm.inf
>     DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCmn600LibArm/SsdtCmn600LibArm.inf
>   
> +  # AML Codegen
> +  DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCpuTopologyLibArm/SsdtCpuTopologyLibArm.inf
> +
>     #
>     # Dynamic Table Factory Dxe
>     #
> @@ -56,6 +59,9 @@ [Components.common]
>         # AML Fixup
>         NULL|DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtSerialPortLibArm/SsdtSerialPortLibArm.inf
>         NULL|DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCmn600LibArm/SsdtCmn600LibArm.inf
> +
> +      # AML Codegen
> +      NULL|DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCpuTopologyLibArm/SsdtCpuTopologyLibArm.inf
>     }
>   
>     #
> diff --git a/DynamicTablesPkg/Include/AcpiTableGenerator.h b/DynamicTablesPkg/Include/AcpiTableGenerator.h
> index 352331d6dc95..45c808ba740d 100644
> --- a/DynamicTablesPkg/Include/AcpiTableGenerator.h
> +++ b/DynamicTablesPkg/Include/AcpiTableGenerator.h
> @@ -1,6 +1,6 @@
>   /** @file
>   
> -  Copyright (c) 2017 - 2020, Arm Limited. All rights reserved.<BR>
> +  Copyright (c) 2017 - 2021, Arm Limited. All rights reserved.<BR>
>   
>     SPDX-License-Identifier: BSD-2-Clause-Patent
>   
> @@ -63,6 +63,10 @@ The Dynamic Tables Framework implements the following ACPI table generators:
>               The SSDT CMN-600 generator collates the CMN-600 information
>               from the Configuration Manager and patches the SSDT CMN-600
>               template to build the SSDT CMN-600 table.
> +  - SSDT Cpu-Topology:
> +            The SSDT Cpu-Topology generator collates the cpu and LPI
> +            information from the Configuration Manager and generates a
> +            SSDT table describing the CPU hierarchy.
>   */
>   
>   /** The ACPI_TABLE_GENERATOR_ID type describes ACPI table generator ID.
> @@ -88,6 +92,7 @@ typedef enum StdAcpiTableId {
>     EStdAcpiTableIdSrat,                          ///< SRAT Generator
>     EStdAcpiTableIdSsdtSerialPort,                ///< SSDT Serial-Port Generator
>     EStdAcpiTableIdSsdtCmn600,                    ///< SSDT Cmn-600 Generator
> +  EStdAcpiTableIdSsdtCpuTopology,               ///< SSDT Cpu Topology
>     EStdAcpiTableIdMax
>   } ESTD_ACPI_TABLE_ID;
>   
> diff --git a/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCpuTopologyLibArm/SsdtCpuTopologyGenerator.c b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCpuTopologyLibArm/SsdtCpuTopologyGenerator.c
> new file mode 100644
> index 000000000000..88db808760f7
> --- /dev/null
> +++ b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCpuTopologyLibArm/SsdtCpuTopologyGenerator.c
> @@ -0,0 +1,1230 @@
> +/** @file
> +  SSDT Cpu Topology Table Generator.
> +
> +  Copyright (c) 2021, Arm Limited. All rights reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +  @par Reference(s):
> +    - ACPI 6.3 Specification - January 2019 - s8.4 Declaring Processors
> +**/
> +
> +#include <IndustryStandard/DebugPort2Table.h>
[SAMI] I think the DBG2 header is not required here. Can you check this 
and if any other includes below can be removed, please?
> +#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 "SsdtCpuTopologyGenerator.h"
> +
> +/** ARM standard SSDT Cpu Topology Table Generator.
> +
> +Requirements:
> +  The following Configuration Manager Object(s) are required by
> +  this Generator:
> +  - EArmObjProcHierarchyInfo
> +  - EArmObjGicCInfo
> +  - EArmObjCmRef
> +  - EArmObjLpiInfo
[SAMI] I think the LPI information should be marked as (OPTIONAL).
> +*/
> +
> +/** This macro expands to a function that retrieves the GIC
> +    CPU interface Information from the Configuration Manager.
> +*/
> +GET_OBJECT_LIST (
> +  EObjNameSpaceArm,
> +  EArmObjGicCInfo,
> +  CM_ARM_GICC_INFO
> +  );
> +
> +/**
> +  This macro expands to a function that retrieves the Processor Hierarchy
> +  information from the Configuration Manager.
> +*/
> +GET_OBJECT_LIST (
> +  EObjNameSpaceArm,
> +  EArmObjProcHierarchyInfo,
> +  CM_ARM_PROC_HIERARCHY_INFO
> +  );
> +
> +/**
> +  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 Lpi
> +  information from the Configuration Manager.
> +*/
> +GET_OBJECT_LIST (
> +  EObjNameSpaceArm,
> +  EArmObjLpiInfo,
> +  CM_ARM_LPI_INFO
> +  );
> +
> +/** Initialize the TokenTable.
> +
> +  One entry should be allocated for each CM_ARM_PROC_HIERARCHY_INFO
> +  structure of the platform. The TokenTable allows to have a mapping:
> +  Index <-> CM_OBJECT_TOKEN (to CM_ARM_LPI_INFO structures).
> +
> +  There will always be less sets of Lpi states (CM_ARM_OBJ_REF)
> +  than the number of cpus/clusters (CM_ARM_PROC_HIERARCHY_INFO).
> +
> +  @param [in]  Generator  The SSDT Cpu Topology generator.
> +  @param [in]  Count      Number of entries to allocate in the TokenTable.
> +
> +  @retval EFI_SUCCESS            Success.
> +  @retval EFI_INVALID_PARAMETER  Invalid parameter.
> +  @retval EFI_OUT_OF_RESOURCES   Failed to allocate memory.
> +**/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +TokenTableInitialize (
> +  IN  ACPI_CPU_TOPOLOGY_GENERATOR   * Generator,
> +  IN  UINT32                          Count
> +  )
> +{
> +  CM_OBJECT_TOKEN   * Table;
> +
> +  if ((Generator == NULL) ||
> +      (Count == 0)        ||
> +      (Count >= MAX_INDEX_NAME)) {
> +    ASSERT (0);
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  Table = AllocateZeroPool (sizeof (CM_OBJECT_TOKEN) * Count);
> +  if (Table == NULL) {
> +    ASSERT (0);
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  Generator->TokenTable.Table = Table;
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/** Free the TokenTable.
> +
> +  @param [in]  Generator    The SSDT Cpu Topology generator.
> +**/
> +STATIC
> +VOID
> +EFIAPI
> +TokenTableFree (
> +  IN  ACPI_CPU_TOPOLOGY_GENERATOR   * Generator
> +  )
> +{
> +  ASSERT (Generator != NULL);
> +  ASSERT (Generator->TokenTable.Table != NULL);
> +
> +  if (Generator->TokenTable.Table != NULL) {
> +    FreePool (Generator->TokenTable.Table);
> +  }
> +}
> +
> +/** Add a new entry to the TokenTable and return its index.
> +
> +  If an entry with Token is already available in the table,
> +  return its index without adding a new entry.
> +
> +  @param [in]  Generator  The SSDT Cpu Topology generator.
> +  @param [in]  Token      New Token entry to add.
> +
> +  @retval The index of the token entry in the TokenTable.
> +**/
> +STATIC
> +UINT32
> +EFIAPI
> +TokenTableAdd (
> +  IN  ACPI_CPU_TOPOLOGY_GENERATOR   * Generator,
> +  IN  CM_OBJECT_TOKEN                 Token
> +  )
> +{
> +  CM_OBJECT_TOKEN   * Table;
> +  UINT32              Index;
> +  UINT32              LastIndex;
> +
> +  ASSERT (Generator != NULL);
> +  ASSERT (Generator->TokenTable.Table != NULL);
> +
> +  Table = Generator->TokenTable.Table;
> +  LastIndex = Generator->TokenTable.LastIndex;
> +
> +  // Search if there is already an entry with this Token.
> +  for (Index = 0; Index < LastIndex; Index++) {
> +    if (Table[Index] == Token) {
> +      return Index;
> +    }
> +  }
> +
> +  ASSERT (LastIndex < MAX_INDEX_NAME);
> +  ASSERT (LastIndex < Generator->ProcNodeCount);
> +
> +  // If no, create a new entry.
> +  Table[LastIndex] = Token;
> +
> +  return Generator->TokenTable.LastIndex++;
> +}
> +
> +/** Write a string 'Xxxx\0' in AslName (5 bytes long),
> +  with 'X' being the leading char of the name, and
> +  with 'xxx' being Value in hexadecimal.
> +
> +  As 'xxx' in hexadecimal represents a number on 12 bits,
> +  we have Value < (2 << 12)
> +
> +  @param [in]       LeadChar  Leading char of the name.
> +  @param [in]       Value     Hex value of the name.
> +                              Must be lower than (2 << 12).
> +  @param [in, out]  AslName   Pointer to write the 'Xxxx' string to.
> +                              Must be at least 5 bytes long.
> +
> +  @retval EFI_SUCCESS               Success.
> +  @retval EFI_INVALID_PARAMETER     Invalid parameter.
> +**/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +WriteAslName (
> +  IN      CHAR8     LeadChar,
> +  IN      UINT32    Value,
> +  IN OUT  CHAR8   * AslName
> +  )
> +{
> +  UINT8   Index;
> +
> +  if ((Value >= MAX_INDEX_NAME)  ||
> +      (AslName == NULL)) {
> +    ASSERT (0);
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  AslName[0] = LeadChar;
> +  AslName[AML_NAME_SEG_SIZE] = '\0';
> +
> +  for (Index = 0; Index < AML_NAME_SEG_SIZE - 1; Index++) {
> +    AslName[AML_NAME_SEG_SIZE - Index - 1] =
> +      AsciiFromHex (((Value >> (4 * Index)) & 0xF));
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/** Create and add an _LPI method to Cpu/Cluster Node.
> +
> +  For instance, transform an AML node from:
> +  Device (C002)
> +  {
> +      Name (_UID, 2)
> +      Name (_HID, "ACPI0007")
> +  }
> +
> +  To:
> +  Device (C002)
> +  {
> +      Name (_UID, 2)
> +      Name (_HID, "ACPI0007")
> +      Method (_LPI, 0, NotSerialized)
> +      {
> +          Return (\_SB.L003)
> +      }
> +  }
> +
> +  @param [in]  Generator              The SSDT Cpu Topology generator.
> +  @param [in]  ProcHierarchyNodeInfo  CM_ARM_PROC_HIERARCHY_INFO describing
> +                                      the Cpu.
> +  @param [in]  Node                   Node to which the _LPI method is
> +                                      attached. Can represent a Cpu or a
> +                                      Cluster.
> +
> +  @retval EFI_SUCCESS             The function completed successfully.
> +  @retval EFI_INVALID_PARAMETER   Invalid parameter.
> +  @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
> +**/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +CreateAmlLpiMethod (
> +  IN  ACPI_CPU_TOPOLOGY_GENERATOR   * Generator,
> +  IN  CM_ARM_PROC_HIERARCHY_INFO    * ProcHierarchyNodeInfo,
> +  IN  AML_OBJECT_NODE_HANDLE        * Node
> +  )
> +{
> +  EFI_STATUS    Status;
> +  UINT32        TokenIndex;
> +  CHAR8         AslName[SB_SCOPE_PREFIX_SIZE + AML_NAME_SEG_SIZE];
> +
> +  ASSERT (Generator != NULL);
> +  ASSERT (ProcHierarchyNodeInfo != NULL);
> +  ASSERT (ProcHierarchyNodeInfo->LpiToken != CM_NULL_TOKEN);
> +  ASSERT (Node != NULL);
> +
> +  TokenIndex = TokenTableAdd (Generator, ProcHierarchyNodeInfo->LpiToken);
> +
> +  CopyMem (AslName, SB_SCOPE_PREFIX, SB_SCOPE_PREFIX_SIZE);
> +
> +  Status = WriteAslName (
> +             'L',
> +             TokenIndex,
> +             AslName + SB_SCOPE_PREFIX_SIZE - 1
> +             );
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    return Status;
> +  }
> +
> +  // ASL:
> +  // Method (_LPI, 0) {
> +  //   Return ([AslName])
> +  // }
> +  Status = AmlCodeGenMethodRetNameString (
> +             "_LPI",
> +             AslName,
> +             0,
> +             FALSE,
> +             0,
> +             Node,
> +             NULL
> +             );
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +  }
> +
> +  return Status;
> +}
> +
> +/** Generate all the Lpi states under the '_SB' scope.
> +
> +  This function generates the following ASL code:
> +  Scope (\_SB) {
> +    Name (L000, Package() {
> +      0, // Version
> +      0, // Level Index
> +      X, // Count
> +      Package() {
> +        [An Lpi state]
> +      },
> +      Package() {
> +        [Another Lpi state]
> +      },
> +    } // Name L000
> +
> +    Name (L001, Package() {
> +      ...
> +    } // Name L001
> +
> +    ...
> +  } // Scope /_SB
> +
> +  The Lpi states are fetched from the Configuration Manager.
> +  The names of the Lpi states are generated from the TokenTable.
> +
> +  @param [in]  Generator        The SSDT Cpu Topology generator.
> +  @param [in]  CfgMgrProtocol   Pointer to the Configuration Manager
> +                                Protocol Interface.
> +  @param [in] ScopeNode         Scope node handle ('\_SB' scope).
> +
> +  @retval EFI_SUCCESS             Success.
> +  @retval EFI_INVALID_PARAMETER   Invalid parameter.
> +  @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
> +**/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +GenerateLpiStates (
> +  IN        ACPI_CPU_TOPOLOGY_GENERATOR           *       Generator,
> +  IN  CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL  * CONST CfgMgrProtocol,
> +  IN        AML_OBJECT_NODE_HANDLE                        ScopeNode
> +  )
> +{
> +  EFI_STATUS                Status;
> +
> +  UINT32                    Index;
> +  UINT32                    LastIndex;
> +
> +  AML_OBJECT_NODE_HANDLE    LpiNode;
> +  CM_ARM_OBJ_REF          * LpiRefInfo;
> +  UINT32                    LpiRefInfoCount;
> +  UINT32                    LpiRefIndex;
> +  CM_ARM_LPI_INFO         * LpiInfo;
> +  CHAR8                     AslName[AML_NAME_SEG_SIZE + 1];
> +
> +  ASSERT (Generator != NULL);
> +  ASSERT (Generator->TokenTable.Table != NULL);
> +  ASSERT (CfgMgrProtocol != NULL);
> +  ASSERT (ScopeNode != NULL);
> +
> +  LastIndex = Generator->TokenTable.LastIndex;
> +
> +  // For each entry in the TokenTable, create a name in the AML namespace
> +  // under SB_SCOPE, to store the Lpi states associated with the LpiToken.
> +  for (Index = 0; Index < LastIndex; Index++) {
> +    Status = WriteAslName ('L', Index, AslName);
> +    if (EFI_ERROR (Status)) {
> +      ASSERT (0);
> +      return Status;
> +    }
> +
> +    // We do not support the LevelId field for now, let it to 0.
> +    Status = AmlCreateLpiNode (AslName, 1, 0, ScopeNode, &LpiNode);
> +    if (EFI_ERROR (Status)) {
> +      ASSERT (0);
> +      return Status;
> +    }
> +
> +    // Fetch the LPI objects referenced by the token.
> +    Status = GetEArmObjCmRef (
> +               CfgMgrProtocol,
> +               Generator->TokenTable.Table[Index],
> +               &LpiRefInfo,
> +               &LpiRefInfoCount
> +               );
> +    if (EFI_ERROR (Status)) {
> +      ASSERT (0);
> +      return Status;
> +    }
> +
> +    for (LpiRefIndex = 0; LpiRefIndex < LpiRefInfoCount; LpiRefIndex++) {
> +      // For each CM_ARM_LPI_INFO referenced by the token, add an Lpi state.
> +      Status = GetEArmObjLpiInfo (
> +                 CfgMgrProtocol,
> +                 LpiRefInfo[LpiRefIndex].ReferenceToken,
> +                 &LpiInfo,
> +                 NULL
> +                 );
> +      if (EFI_ERROR (Status)) {
> +        ASSERT (0);
> +        return Status;
> +      }
> +
> +      Status = AmlAddLpiState (
> +                 LpiInfo->MinResidency,
> +                 LpiInfo->WorstCaseWakeLatency,
> +                 LpiInfo->Flags,
> +                 LpiInfo->ArchFlags,
> +                 LpiInfo->ResCntFreq,
> +                 LpiInfo->EnableParentState,
> +                 LpiInfo->IsInteger ?
> +                   NULL :
> +                   &LpiInfo->RegisterEntryMethod,
> +                 LpiInfo->IsInteger ?
> +                   LpiInfo->IntegerEntryMethod :
> +                   0,
> +                 &LpiInfo->ResidencyCounterRegister,
> +                 &LpiInfo->UsageCounterRegister,
> +                 LpiInfo->StateName,
> +                 LpiNode
> +                 );
> +      if (EFI_ERROR (Status)) {
> +        ASSERT (0);
> +        return Status;
> +      }
> +    } // for LpiRefIndex
> +  } // for Index
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/** Create a Cpu in the AML namespace.
> +
> +  This generates the following ASL code:
> +  Device (C002)
> +  {
> +      Name (_UID, 2)
> +      Name (_HID, "ACPI0007")
> +  }
> +
> +  @param [in]  Generator    The SSDT Cpu Topology generator.
> +  @param [in]  ParentNode   Parent node to attach the Cpu node to.
> +  @param [in]  GicCInfo     CM_ARM_GICC_INFO object used to create the node.
> +  @param [in]  CpuIndex     Index used to generate the node name.
> +  @param [out] CpuNodePtr   If not NULL, return the created Cpu node.
> +
> +  @retval EFI_SUCCESS             Success.
> +  @retval EFI_INVALID_PARAMETER   Invalid parameter.
> +  @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
> +**/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +CreateAmlCpu (
> +  IN   ACPI_CPU_TOPOLOGY_GENERATOR   * Generator,
> +  IN   AML_NODE_HANDLE                 ParentNode,
> +  IN   CM_ARM_GICC_INFO              * GicCInfo,
> +  IN   UINT32                          CpuIndex,
> +  OUT  AML_OBJECT_NODE_HANDLE        * CpuNodePtr OPTIONAL
> +  )
> +{
> +  EFI_STATUS                Status;
> +  AML_OBJECT_NODE_HANDLE    CpuNode;
> +  CHAR8                     AslName[AML_NAME_SEG_SIZE + 1];
> +
> +  ASSERT (Generator != NULL);
> +  ASSERT (ParentNode != NULL);
> +  ASSERT (GicCInfo != NULL);
> +
> +  Status = WriteAslName ('C', CpuIndex, AslName);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    return Status;
> +  }
> +
> +  Status = AmlCodeGenDevice (AslName, ParentNode, &CpuNode);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    return Status;
> +  }
> +
> +  Status = AmlCodeGenNameInteger (
> +             "_UID",
> +             GicCInfo->AcpiProcessorUid,
> +             CpuNode,
> +             NULL
> +             );
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    return Status;
> +  }
> +
> +  Status = AmlCodeGenNameString (
> +             "_HID",
> +             ACPI_HID_PROCESSOR_DEVICE,
> +             CpuNode,
> +             NULL
> +             );
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    return Status;
> +  }
> +
> +  // If requested, return the handle to the CpuNode.
> +  if (CpuNodePtr != NULL) {
> +    *CpuNodePtr = CpuNode;
> +  }
> +
> +  return Status;
> +}
> +
> +/** Create a Cpu in the AML namespace from a CM_ARM_PROC_HIERARCHY_INFO
> +    CM object.
> +
> +  @param [in]  Generator              The SSDT Cpu Topology generator.
> +  @param [in]  CfgMgrProtocol         Pointer to the Configuration Manager
> +                                      Protocol Interface.
> +  @param [in]  ParentNode             Parent node to attach the Cpu node to.
> +  @param [in]  CpuIndex               Index used to generate the node name.
> +  @param [in]  ProcHierarchyNodeInfo  CM_ARM_PROC_HIERARCHY_INFO describing
> +                                      the Cpu.
> +
> +  @retval EFI_SUCCESS             Success.
> +  @retval EFI_INVALID_PARAMETER   Invalid parameter.
> +  @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
> +**/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +CreateAmlCpuFromProcHierarchy (
> +  IN        ACPI_CPU_TOPOLOGY_GENERATOR           *       Generator,
> +  IN  CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL  * CONST CfgMgrProtocol,
> +  IN        AML_NODE_HANDLE                               ParentNode,
> +  IN        UINT32                                        CpuIndex,
> +  IN        CM_ARM_PROC_HIERARCHY_INFO            *       ProcHierarchyNodeInfo
> +  )
> +{
> +  EFI_STATUS                Status;
> +  CM_ARM_GICC_INFO        * GicCInfo;
> +  AML_OBJECT_NODE_HANDLE    CpuNode;
> +
> +  ASSERT (Generator != NULL);
> +  ASSERT (CfgMgrProtocol != NULL);
> +  ASSERT (ParentNode != NULL);
> +  ASSERT (ProcHierarchyNodeInfo != NULL);
> +  ASSERT (ProcHierarchyNodeInfo->GicCToken != CM_NULL_TOKEN);
> +
> +  Status = GetEArmObjGicCInfo (
> +             CfgMgrProtocol,
> +             ProcHierarchyNodeInfo->GicCToken,
> +             &GicCInfo,
> +             NULL
> +             );
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    return Status;
> +  }
> +
> +  Status = CreateAmlCpu (Generator, ParentNode, GicCInfo, CpuIndex, &CpuNode);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    return Status;
> +  }
> +
> +  // If a set of Lpi states is associated with the
> +  // CM_ARM_PROC_HIERARCHY_INFO, create an _LPI method returning them.
> +  if (ProcHierarchyNodeInfo->LpiToken != CM_NULL_TOKEN) {
> +    Status = CreateAmlLpiMethod (Generator, ProcHierarchyNodeInfo, CpuNode);
> +    ASSERT_EFI_ERROR (Status);
> +  }
> +
> +  return Status;
> +}
> +
> +/** Create a Cluster in the AML namespace.
> +
> +  Any CM_ARM_PROC_HIERARCHY_INFO object with the following flags is
> +  assumed to be a cluster:
> +   - EFI_ACPI_6_3_PPTT_PACKAGE_NOT_PHYSICAL
> +   - EFI_ACPI_6_3_PPTT_PROCESSOR_ID_INVALID
> +   - EFI_ACPI_6_3_PPTT_NODE_IS_NOT_LEAF
> +
> +  This generates the following ASL code:
> +  Device (C002)
> +  {
> +      Name (_UID, 2)
> +      Name (_HID, "ACPI0010")
> +  }
> +
> +  @param [in]  Generator              The SSDT Cpu Topology generator.
> +  @param [in]  CfgMgrProtocol         Pointer to the Configuration Manager
> +                                      Protocol Interface.
> +  @param [in]  ParentNode             Parent node to attach the Cluster
> +                                      node to.
> +  @param [in]  ProcHierarchyNodeInfo  CM_ARM_PROC_HIERARCHY_INFO object used
> +                                      to create the node.
> +  @param [in]  ClusterIndex           Index used to generate the node name.
> +  @param [out] ClusterNodePtr         If success, contains the created Cluster
> +                                      node.
> +
> +  @retval EFI_SUCCESS             Success.
> +  @retval EFI_INVALID_PARAMETER   Invalid parameter.
> +  @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
> +**/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +CreateAmlCluster (
> +  IN        ACPI_CPU_TOPOLOGY_GENERATOR           *       Generator,
> +  IN  CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL  * CONST CfgMgrProtocol,
> +  IN        AML_NODE_HANDLE                               ParentNode,
> +  IN        CM_ARM_PROC_HIERARCHY_INFO            *       ProcHierarchyNodeInfo,
> +  IN        UINT32                                        ClusterIndex,
> +  OUT       AML_OBJECT_NODE_HANDLE                *       ClusterNodePtr
> +  )
> +{
> +  EFI_STATUS                Status;
> +  AML_OBJECT_NODE_HANDLE    ClusterNode;
> +  CHAR8                     AslNameCluster[AML_NAME_SEG_SIZE + 1];
> +
> +  ASSERT (Generator != NULL);
> +  ASSERT (CfgMgrProtocol != NULL);
> +  ASSERT (ParentNode != NULL);
> +  ASSERT (ProcHierarchyNodeInfo != NULL);
> +  ASSERT (ClusterNodePtr != NULL);
> +
> +  Status = WriteAslName ('C', ClusterIndex, AslNameCluster);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    return Status;
> +  }
> +
> +  Status = AmlCodeGenDevice (AslNameCluster, ParentNode, &ClusterNode);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    return Status;
> +  }
> +
> +  // Use the ClusterIndex for the _UID value as there is no AcpiProcessorUid
> +  // and EFI_ACPI_6_3_PPTT_PROCESSOR_ID_INVALID is set for non-Cpus.
> +  Status = AmlCodeGenNameInteger (
> +             "_UID",
> +             ClusterIndex,
> +             ClusterNode,
> +             NULL
> +             );
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    return Status;
> +  }
> +
> +  Status = AmlCodeGenNameString (
> +             "_HID",
> +             ACPI_HID_PROCESSOR_CONTAINER_DEVICE,
> +             ClusterNode,
> +             NULL
> +             );
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    return Status;
> +  }
> +
> +  // If a set of Lpi states are associated with the
> +  // CM_ARM_PROC_HIERARCHY_INFO, create an _LPI method returning them.
> +  if (ProcHierarchyNodeInfo->LpiToken != CM_NULL_TOKEN) {
> +    Status = CreateAmlLpiMethod (
> +               Generator,
> +               ProcHierarchyNodeInfo,
> +               ClusterNode
> +               );
> +    if (EFI_ERROR (Status)) {
> +      ASSERT (0);
> +      return Status;
> +    }
> +  }
> +
> +  *ClusterNodePtr = ClusterNode;
> +
> +  return Status;
> +}
> +
> +/** Create an AML representation of the Cpu topology.
> +
> +  A cluster is by extension any non-leave device in the cpu topology.
> +
> +  @param [in] Generator          The SSDT Cpu Topology generator.
> +  @param [in] CfgMgrProtocol     Pointer to the Configuration Manager
> +                                 Protocol Interface.
> +  @param [in] NodeToken          Token of the CM_ARM_PROC_HIERARCHY_INFO
> +                                 currently handled.
> +                                 Cannot be CM_NULL_TOKEN.
> +  @param [in] ParentNode         Parent node to attach the created
> +                                 node to.
> +
> +  @retval EFI_SUCCESS             Success.
> +  @retval EFI_INVALID_PARAMETER   Invalid parameter.
> +  @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
> +**/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +CreateAmlCpuTopologyTree (
> +  IN        ACPI_CPU_TOPOLOGY_GENERATOR           *       Generator,
> +  IN  CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL  * CONST CfgMgrProtocol,
> +  IN        CM_OBJECT_TOKEN                               NodeToken,
> +  IN        AML_NODE_HANDLE                               ParentNode
> +  )
> +{
> +  EFI_STATUS              Status;
> +  UINT32                  Index;
> +  UINT32                  CpuIndex;
> +  UINT32                  ClusterIndex;
> +  AML_OBJECT_NODE_HANDLE  ClusterNode;
> +
> +  ASSERT (Generator != NULL);
> +  ASSERT (Generator->ProcNodeList != NULL);
> +  ASSERT (Generator->ProcNodeCount != 0);
> +  ASSERT (CfgMgrProtocol != NULL);
> +  ASSERT (NodeToken != CM_NULL_TOKEN);
> +  ASSERT (ParentNode != NULL);
> +
> +  CpuIndex = 0;
> +  ClusterIndex = 0;
> +
> +  for (Index = 0; Index < Generator->ProcNodeCount; Index++) {
> +    // Find the children of the CM_ARM_PROC_HIERARCHY_INFO
> +    // currently being handled (i.e. ParentToken == NodeToken).
> +    if (Generator->ProcNodeList[Index].ParentToken == NodeToken) {
> +
> +      // Only Cpus (leaves in this tree) have a GicCToken.
> +      // Create a Cpu node.
> +      if (Generator->ProcNodeList[Index].GicCToken != CM_NULL_TOKEN) {
> +        if ((Generator->ProcNodeList[Index].Flags & PPTT_PROCESSOR_MASK) !=
> +             PPTT_CPU_PROCESSOR_MASK) {
> +          DEBUG ((
> +            DEBUG_ERROR,
> +            "ERROR: SSDT-CPU-TOPOLOGY: Invalid flags for cpu: 0x%x.\n",
> +            Generator->ProcNodeList[Index].Flags
> +            ));
> +          ASSERT (0);
> +          return EFI_INVALID_PARAMETER;
> +        }
> +
> +        Status = CreateAmlCpuFromProcHierarchy (
> +                   Generator,
> +                   CfgMgrProtocol,
> +                   ParentNode,
> +                   CpuIndex,
> +                   &Generator->ProcNodeList[Index]
> +                   );
> +        if (EFI_ERROR (Status)) {
> +          ASSERT (0);
> +          return Status;
> +        }
> +
> +        CpuIndex++;
> +
> +      } else {
> +        // If this is not a Cpu, then this is a cluster.
> +
> +        // Acpi processor Id for clusters is not handled.
> +        if ((Generator->ProcNodeList[Index].Flags & PPTT_PROCESSOR_MASK) !=
> +             PPTT_CLUSTER_PROCESSOR_MASK) {
> +          DEBUG ((
> +            DEBUG_ERROR,
> +            "ERROR: SSDT-CPU-TOPOLOGY: Invalid flags for cluster: 0x%x.\n",
> +            Generator->ProcNodeList[Index].Flags
> +            ));
> +          ASSERT (0);
> +          return EFI_INVALID_PARAMETER;
> +        }
> +
> +        Status = CreateAmlCluster (
> +                   Generator,
> +                   CfgMgrProtocol,
> +                   ParentNode,
> +                   &Generator->ProcNodeList[Index],
> +                   ClusterIndex,
> +                   &ClusterNode
> +                   );
> +        if (EFI_ERROR (Status)) {
> +          ASSERT (0);
> +          return Status;
> +        }
> +
> +        // Nodes must have a unique name in the ASL namespace.
> +        // Reset the Cpu index whenever we create a new Cluster.
> +        ClusterIndex++;
> +        CpuIndex = 0;
> +
> +        // Recursively continue creating an AML tree.
> +        Status = CreateAmlCpuTopologyTree (
> +                   Generator,
> +                   CfgMgrProtocol,
> +                   Generator->ProcNodeList[Index].Token,
> +                   ClusterNode
> +                   );
> +        if (EFI_ERROR (Status)) {
> +          ASSERT (0);
> +          return Status;
> +        }
> +      }
> +    } // if ParentToken == NodeToken
> +  } // for
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/** Create the processor hierarchy AML tree from CM_ARM_PROC_HIERARCHY_INFO
> +    CM objects.
> +
> +  @param [in] Generator        The SSDT Cpu Topology generator.
> +  @param [in] CfgMgrProtocol   Pointer to the Configuration Manager
> +                               Protocol Interface.
> +  @param [in] ScopeNode        Scope node handle ('\_SB' scope).
> +
> +  @retval EFI_SUCCESS             Success.
> +  @retval EFI_INVALID_PARAMETER   Invalid parameter.
> +  @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
> +**/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +CreateTopologyFromProcHierarchy (
> +  IN        ACPI_CPU_TOPOLOGY_GENERATOR           *       Generator,
> +  IN  CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL  * CONST CfgMgrProtocol,
> +  IN        AML_OBJECT_NODE_HANDLE                        ScopeNode
> +  )
> +{
> +  EFI_STATUS  Status;
> +  UINT32      Index;
> +  UINT32      TopLevelProcNodeIndex;
> +
> +  ASSERT (Generator != NULL);
> +  ASSERT (Generator->ProcNodeCount != 0);
> +  ASSERT (Generator->ProcNodeList != NULL);
> +  ASSERT (CfgMgrProtocol != NULL);
> +  ASSERT (ScopeNode != NULL);
> +
> +  TopLevelProcNodeIndex = -1;
[SAMI] I think it would be good to use MAX_UINT32 instead of -1 here. 
Same for the if condition a few lines below.
> +
> +  Status = TokenTableInitialize (Generator, Generator->ProcNodeCount);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    return Status;
> +  }
> +
> +  // It is assumed that there is one unique CM_ARM_PROC_HIERARCHY_INFO
> +  // structure with no ParentToken and the EFI_ACPI_6_3_PPTT_PACKAGE_PHYSICAL
> +  // flag set. All other CM_ARM_PROC_HIERARCHY_INFO are non-physical and
> +  // have a ParentToken.
> +  for (Index = 0; Index < Generator->ProcNodeCount; Index++) {
> +    if ((Generator->ProcNodeList[Index].ParentToken == CM_NULL_TOKEN) &&
> +        (Generator->ProcNodeList[Index].Flags &
> +          EFI_ACPI_6_3_PPTT_PACKAGE_PHYSICAL)) {
> +      if (TopLevelProcNodeIndex != -1) {
> +        DEBUG ((
> +          DEBUG_ERROR,
> +          "ERROR: SSDT-CPU-TOPOLOGY: Top level CM_ARM_PROC_HIERARCHY_INFO "
> +          "must be unique\n"
> +          ));
> +        ASSERT (0);
> +        goto exit_handler;
> +      }
> +      TopLevelProcNodeIndex = Index;
> +    }
> +  } // for
> +
> +  Status = CreateAmlCpuTopologyTree (
> +             Generator,
> +             CfgMgrProtocol,
> +             Generator->ProcNodeList[TopLevelProcNodeIndex].Token,
> +             ScopeNode
> +             );
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto exit_handler;
> +  }
> +
> +  Status = GenerateLpiStates (Generator, CfgMgrProtocol, ScopeNode);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    goto exit_handler;
> +  }
> +
> +exit_handler:
> +  TokenTableFree (Generator);
> +  return Status;
> +}
> +
> +/** Create the processor hierarchy AML tree from CM_ARM_GICC_INFO
> +    CM objects.
> +
> +  A cluster is by extension any non-leave device in the cpu topology.
> +
> +  @param [in] Generator        The SSDT Cpu Topology generator.
> +  @param [in] CfgMgrProtocol   Pointer to the Configuration Manager
> +                               Protocol Interface.
> +  @param [in] ScopeNode        Scope node handle ('\_SB' scope).
> +
> +  @retval EFI_SUCCESS             Success.
> +  @retval EFI_INVALID_PARAMETER   Invalid parameter.
> +  @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
> +**/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +CreateTopologyFromGicC (
> +  IN        ACPI_CPU_TOPOLOGY_GENERATOR           *       Generator,
> +  IN  CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL  * CONST CfgMgrProtocol,
> +  IN        AML_OBJECT_NODE_HANDLE                        ScopeNode
> +  )
> +{
> +  EFI_STATUS            Status;
> +  CM_ARM_GICC_INFO    * GicCInfo;
> +  UINT32                GicCInfoCount;
> +  UINT32                Index;
> +
> +  ASSERT (Generator != NULL);
> +  ASSERT (CfgMgrProtocol != NULL);
> +  ASSERT (ScopeNode != NULL);
> +
> +  Status = GetEArmObjGicCInfo (
> +             CfgMgrProtocol,
> +             CM_NULL_TOKEN,
> +             &GicCInfo,
> +             &GicCInfoCount
> +             );
> +  if (EFI_ERROR (Status)) {
> +    ASSERT (0);
> +    return Status;
> +  }
> +
> +  // For each CM_ARM_GICC_INFO object, create an AML node.
> +  for (Index = 0; Index < GicCInfoCount; Index++) {
> +    Status = CreateAmlCpu (
> +               Generator,
> +               ScopeNode,
> +               &GicCInfo[Index],
> +               Index,
> +               NULL
> +               );
> +    if (EFI_ERROR (Status)) {
> +      ASSERT (0);
> +      break;
> +    }
> +  } // for
> +
> +  return Status;
> +}
> +
> +/** Construct the SSDT Cpu Topology ACPI table.
> +
> +  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 FreeXXXXTableResources function.
> +
> +  @param [in]  This           Pointer to the table generator.
> +  @param [in]  AcpiTableInfo  Pointer to the ACPI Table Info.
> +  @param [in]  CfgMgrProtocol Pointer to the Configuration Manager
> +                              Protocol Interface.
> +  @param [out] Table          Pointer to the constructed ACPI Table.
> +
> +  @retval EFI_SUCCESS           Table generated successfully.
> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +  @retval EFI_NOT_FOUND         The required object was not found.
> +  @retval EFI_BAD_BUFFER_SIZE   The size returned by the Configuration
> +                                Manager is less than the Object size for the
> +                                requested object.
> +**/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +BuildSsdtCpuTopologyTable (
> +  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,
> +  OUT       EFI_ACPI_DESCRIPTION_HEADER          ** CONST Table
> +  )
> +{
> +  EFI_STATUS                      Status;
> +  AML_ROOT_NODE_HANDLE            RootNode;
> +  AML_OBJECT_NODE_HANDLE          ScopeNode;
> +  CM_ARM_PROC_HIERARCHY_INFO    * ProcHierarchyNodeList;
> +  UINT32                          ProcHierarchyNodeCount;
> +  ACPI_CPU_TOPOLOGY_GENERATOR   * Generator;
> +
> +  ASSERT (This != NULL);
> +  ASSERT (AcpiTableInfo != NULL);
> +  ASSERT (CfgMgrProtocol != NULL);
> +  ASSERT (Table != NULL);
> +  ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
> +  ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
> +
> +  Generator = (ACPI_CPU_TOPOLOGY_GENERATOR*)This;
> +
> +  Status = AmlCodeGenDefinitionBlock (
> +             "SSDT",
> +             "ARMLTD",
> +             "CPU-TOPO",
> +             1,
> +             &RootNode
> +             );
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  Status = AmlCodeGenScope (SB_SCOPE, RootNode, &ScopeNode);
> +  if (EFI_ERROR (Status)) {
> +    goto exit_handler;
> +  }
> +
> +  // Get the processor hierarchy info and update the processor topology
> +  // structure count with Processor Hierarchy Nodes (Type 0)
> +  Status = GetEArmObjProcHierarchyInfo (
> +             CfgMgrProtocol,
> +             CM_NULL_TOKEN,
> +             &ProcHierarchyNodeList,
> +             &ProcHierarchyNodeCount
> +             );
> +  if (EFI_ERROR (Status) &&
> +      (Status != EFI_NOT_FOUND)) {
> +    goto exit_handler;
> +  }
> +
> +  if (Status == EFI_NOT_FOUND) {
> +    // If hierarchy information is not found generate a flat topology
> +    // using CM_ARM_GICC_INFO objects.
> +    Status = CreateTopologyFromGicC (
> +               Generator,
> +               CfgMgrProtocol,
> +               ScopeNode
> +               );
> +    if (EFI_ERROR (Status)) {
> +      goto exit_handler;
> +    }
> +  } else {
> +    // Generate the topology from CM_ARM_PROC_HIERARCHY_INFO objects.
> +    Generator->ProcNodeList = ProcHierarchyNodeList;
> +    Generator->ProcNodeCount = ProcHierarchyNodeCount;
> +
> +    Status = CreateTopologyFromProcHierarchy (
> +               Generator,
> +               CfgMgrProtocol,
> +               ScopeNode
> +               );
> +    if (EFI_ERROR (Status)) {
> +      goto exit_handler;
> +    }
> +  }
> +
> +  Status = AmlSerializeDefinitionBlock (
> +             RootNode,
> +             Table
> +             );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: SSDT-CPU-TOPOLOGY: Failed to Serialize SSDT Table Data."
> +      " Status = %r\n",
> +      Status
> +      ));
> +    goto exit_handler;
> +  }
> +
> +exit_handler:
> +  // Delete the RootNode and its attached children.
> +  return AmlDeleteTree (RootNode);
> +}
> +
> +/** Free any resources allocated for constructing the
> +    SSDT Cpu Topology ACPI table.
> +
> +  @param [in]      This           Pointer to the 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 the ACPI Table.
> +
> +  @retval EFI_SUCCESS           The resources were freed successfully.
> +  @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
> +**/
> +STATIC
> +EFI_STATUS
> +FreeSsdtCpuTopologyTableResources (
> +  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
> +  )
> +{
> +  ASSERT (This != NULL);
> +  ASSERT (AcpiTableInfo != NULL);
> +  ASSERT (CfgMgrProtocol != NULL);
> +  ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
> +  ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
> +
> +  if ((Table == NULL) || (*Table == NULL)) {
> +    DEBUG ((DEBUG_ERROR, "ERROR: SSDT-CPU-TOPOLOGY: Invalid Table Pointer\n"));
> +    ASSERT ((Table != NULL) && (*Table != NULL));
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  FreePool (*Table);
> +  *Table = NULL;
> +  return EFI_SUCCESS;
> +}
> +
> +/** This macro defines the SSDT Cpu Topology Table Generator revision.
> +*/
> +#define SSDT_CPU_TOPOLOGY_GENERATOR_REVISION CREATE_REVISION (1, 0)
> +
> +/** The interface for the SSDT Cpu Topology Table Generator.
> +*/
> +STATIC
> +ACPI_CPU_TOPOLOGY_GENERATOR SsdtCpuTopologyGenerator = {
> +  // ACPI table generator header
> +  {
> +    // Generator ID
> +    CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdSsdtCpuTopology),
> +    // Generator Description
> +    L"ACPI.STD.SSDT.CPU.TOPOLOGY.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_CPU_TOPOLOGY_GENERATOR_REVISION,
> +    // Build Table function
> +    BuildSsdtCpuTopologyTable,
> +    // Free Resource function
> +    FreeSsdtCpuTopologyTableResources,
> +    // Extended build function not needed
> +    NULL,
> +    // Extended build function not implemented by the generator.
> +    // Hence extended free resource function is not required.
> +    NULL
> +  },
> +
> +  // Private fields are defined from here.
> +
> +  // TokenTable
> +  {
> +      // Table
> +      NULL,
> +      // LastIndex
> +      0
> +  },
> +  // ProcNodeList
> +  NULL,
> +  // ProcNodeCount
> +  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
> +AcpiSsdtCpuTopologyLibConstructor (
> +  IN  EFI_HANDLE           ImageHandle,
> +  IN  EFI_SYSTEM_TABLE  *  SystemTable
> +  )
> +{
> +  EFI_STATUS  Status;
> +  Status = RegisterAcpiTableGenerator (&SsdtCpuTopologyGenerator.Header);
> +  DEBUG ((
> +    DEBUG_INFO,
> +    "SSDT-CPU-TOPOLOGY: 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
> +AcpiSsdtCpuTopologyLibDestructor (
> +  IN  EFI_HANDLE           ImageHandle,
> +  IN  EFI_SYSTEM_TABLE  *  SystemTable
> +  )
> +{
> +  EFI_STATUS  Status;
> +  Status = DeregisterAcpiTableGenerator (&SsdtCpuTopologyGenerator.Header);
> +  DEBUG ((
> +    DEBUG_INFO,
> +    "SSDT-CPU-TOPOLOGY: Deregister Generator. Status = %r\n",
> +    Status
> +    ));
> +  ASSERT_EFI_ERROR (Status);
> +  return Status;
> +}
> diff --git a/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCpuTopologyLibArm/SsdtCpuTopologyGenerator.h b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCpuTopologyLibArm/SsdtCpuTopologyGenerator.h
> new file mode 100644
> index 000000000000..95930a86b186
> --- /dev/null
> +++ b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCpuTopologyLibArm/SsdtCpuTopologyGenerator.h
> @@ -0,0 +1,134 @@
> +/** @file
> +  SSDT Cpu Topology Table Generator.
> +
> +  Copyright (c) 2021, Arm Limited. All rights reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +  @par Reference(s):
> +    - ACPI 6.3 Specification - January 2019 - s8.4 Declaring Processors
> +**/
> +
> +#ifndef SSDT_CPU_TOPOLOGY_GENERATOR_H_
> +#define SSDT_CPU_TOPOLOGY_GENERATOR_H_
> +
> +#pragma pack(1)
> +
> +// Mask for the flags that need to be checked.
> +#define PPTT_PROCESSOR_MASK   (                                               \
> +          (EFI_ACPI_6_3_PPTT_PACKAGE_PHYSICAL)          |                     \
> +          (EFI_ACPI_6_3_PPTT_PROCESSOR_ID_VALID << 1)   |                     \
> +          (EFI_ACPI_6_3_PPTT_NODE_IS_LEAF << 3))
> +
> +// Mask for the cpu flags.
> +#define PPTT_CPU_PROCESSOR_MASK   (                                           \
> +          (EFI_ACPI_6_3_PPTT_PACKAGE_NOT_PHYSICAL)      |                     \
> +          (EFI_ACPI_6_3_PPTT_PROCESSOR_ID_VALID << 1)   |                     \
> +          (EFI_ACPI_6_3_PPTT_NODE_IS_LEAF << 3))
> +
> +// Mask for the cluster flags.
> +// Even though a _UID is generated for clusters, it is simpler to use
> +// EFI_ACPI_6_3_PPTT_PROCESSOR_ID_INVALID and to not match the cluster id of
> +// the PPTT table (not sure the PPTT table is generated).
> +#define PPTT_CLUSTER_PROCESSOR_MASK   (                                       \
> +          (EFI_ACPI_6_3_PPTT_PACKAGE_NOT_PHYSICAL)      |                     \
> +          (EFI_ACPI_6_3_PPTT_PROCESSOR_ID_INVALID << 1) |                     \
> +          (EFI_ACPI_6_3_PPTT_NODE_IS_NOT_LEAF << 3))
> +
> +/** LPI states are stored in the ASL namespace at '\_SB_.Lxxx',
> +    with xxx being the node index of the LPI state.
> +*/
> +#define SB_SCOPE                            "\\_SB_"
> +#define SB_SCOPE_PREFIX                     SB_SCOPE "."
> +/// Size of the SB_SCOPE_PREFIX string.
> +#define SB_SCOPE_PREFIX_SIZE                sizeof (SB_SCOPE_PREFIX)
> +
> +/// HID for a processor device.
> +#define ACPI_HID_PROCESSOR_DEVICE           "ACPI0007"
> +
> +/// HID for a processor container device.
> +#define ACPI_HID_PROCESSOR_CONTAINER_DEVICE "ACPI0010"
> +
> +/** Node names of Cpus and Clusters are 'Cxxx', and 'Lxxx' for LPI states.
> +    The 'xxx' is an index on 12 bits is given to node name,
> +    thus the limitation in the number of nodes.
> +*/
> +#define MAX_INDEX_NAME                      (1 << 12)
[SAMI] I think this macro should be renamed to MAX_NODE_COUNT.
> +
> +/** A structure used to handle the Lpi structures referencing.
> +
> +  A CM_ARM_PROC_HIERARCHY_INFO structure references a CM_ARM_OBJ_REF.
> +  This CM_ARM_OBJ_REF references CM_ARM_LPI_INFO structures.
> +
> +  Example:
> +  (Cpu0)                                   (Cpu1)
> +  CM_ARM_PROC_HIERARCHY_INFO               CM_ARM_PROC_HIERARCHY_INFO
> +              |                                       |
> +              +----------------------------------------
> +              |
> +              v
> +  (List of references to Lpi states)
> +  CM_ARM_OBJ_REF
> +              |
> +              +----------------------------------------
> +              |                                       |
> +              v                                       v
> +  (A first Lpi state)                       (A second Lpi state)
> +  CM_ARM_LPI_INFO[0]                        CM_ARM_LPI_INFO[1]
> +
> +  Here, Cpu0 and Cpu1 have the same Lpi states. Both CM_ARM_PROC_HIERARCHY_INFO
> +  structures reference the same CM_ARM_OBJ_REF. An entry is created in the
> +  TokenTable such as:
> +  0 <-> CM_ARM_OBJ_REF
> +
> +  This will lead to the creation of this pseudo-ASL code where Cpu0 and Cpu1
> +  return the same object at \_SB.L000:
> +  Scope (\_SB) {
> +    Device (C000) {
> +      [...]
> +      Method (_LPI) {
> +        Return (\_SB.L000)
> +      }
> +    } // C000
> +
> +    Device (C001) {
> +      [...]
> +      Method (_LPI) {
> +        Return (\_SB.L000)
> +      }
> +    } // C001
> +
> +    // Lpi states
> +    Name (L000, Package (0x05) {
> +      [...]
> +    }
> +  }
> +*/
> +typedef struct TokenTable {
> +  /// TokenTable, a table allowing to map:
> +  /// Index <-> CM_OBJECT_TOKEN (to CM_ARM_LPI_INFO structures).
> +  CM_OBJECT_TOKEN             * Table;
> +
> +  /// Last used index of the TokenTable.
> +  /// LastIndex is bound by ProcNodeCount.
> +  UINT32                        LastIndex;
> +} TOKEN_TABLE;
> +
> +/** A structure holding the Cpu topology generator and additional private data.
> +*/
> +typedef struct AcpiCpuTopologyGenerator {
> +  /// ACPI Table generator header
> +  ACPI_TABLE_GENERATOR          Header;
> +
> +  // Private fields are defined from here.
> +
> +  /// Private object used to handle token referencing.
> +  TOKEN_TABLE                   TokenTable;
> +  /// List of CM_ARM_PROC_HIERARCHY_INFO CM objects.
> +  CM_ARM_PROC_HIERARCHY_INFO  * ProcNodeList;
> +  /// Count of CM_ARM_PROC_HIERARCHY_INFO CM objects.
> +  UINT32                        ProcNodeCount;
> +} ACPI_CPU_TOPOLOGY_GENERATOR;
> +
> +#pragma pack()
> +
> +#endif // SSDT_CPU_TOPOLOGY_GENERATOR_H_
> diff --git a/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCpuTopologyLibArm/SsdtCpuTopologyLibArm.inf b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCpuTopologyLibArm/SsdtCpuTopologyLibArm.inf
> new file mode 100644
> index 000000000000..4038499d963d
> --- /dev/null
> +++ b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCpuTopologyLibArm/SsdtCpuTopologyLibArm.inf
> @@ -0,0 +1,40 @@
> +## @file
> +# Ssdt Cpu Topology Table Generator
> +#
> +#  Copyright (c) 2021, Arm Limited. All rights reserved.<BR>
> +#
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> +##
> +
> +[Defines]
> +  INF_VERSION    = 0x0001001B
> +  BASE_NAME      = SsdtCpuTopologyLibArm
> +  FILE_GUID      = F2835EB6-4B05-48D4-A475-147DA0F3755C
> +  VERSION_STRING = 1.0
> +  MODULE_TYPE    = DXE_DRIVER
> +  LIBRARY_CLASS  = NULL|DXE_DRIVER
> +  CONSTRUCTOR    = AcpiSsdtCpuTopologyLibConstructor
> +  DESTRUCTOR     = AcpiSsdtCpuTopologyLibDestructor
> +
> +[Sources]
> +  SsdtCpuTopologyGenerator.c
> +  SsdtCpuTopologyGenerator.h
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +  EmbeddedPkg/EmbeddedPkg.dec
> +  ArmPlatformPkg/ArmPlatformPkg.dec
> +  DynamicTablesPkg/DynamicTablesPkg.dec
> +
> +[LibraryClasses]
> +  AcpiHelperLib
> +  AmlLib
> +  BaseLib
> +
> +[FixedPcd]
> +
> +[Protocols]
> +
> +[Guids]
[SAMI] Please remove unused sections.
> +


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v1 12/13] DynamicTablesPkg: Add CM_ARM_LPI_INFO object
  2021-06-23 11:40 ` [PATCH v1 12/13] DynamicTablesPkg: Add CM_ARM_LPI_INFO object PierreGondois
@ 2021-10-05 14:39   ` Sami Mujawar
  0 siblings, 0 replies; 30+ messages in thread
From: Sami Mujawar @ 2021-10-05 14:39 UTC (permalink / raw)
  To: Pierre.Gondois, devel, Alexei Fedorov; +Cc: Akanksha Jain, Alexandru Elisei, nd

Hi Pierre,

Thank you for this patch.

Reviewed-by: Sami Mujawar <sami.mujawar@arm.com>

Regards,

Sami Mujawar


On 23/06/2021 12:40 PM, Pierre.Gondois@arm.com wrote:
> From: Pierre Gondois <Pierre.Gondois@arm.com>
>
> Introduce the CM_ARM_LPI_INFO CmObj in the ArmNameSpaceObjects.
> This allows to describe LPI state information, as described in
> ACPI 6.4, s8.4.4.3 "_LPI (Low Power Idle States)".
>
> Signed-off-by: Pierre Gondois <Pierre.Gondois@arm.com>
> ---
>   .../Include/ArmNameSpaceObjects.h             | 68 +++++++++++++++++++
>   .../ConfigurationManagerObjectParser.c        | 35 ++++++++++
>   2 files changed, 103 insertions(+)
>
> diff --git a/DynamicTablesPkg/Include/ArmNameSpaceObjects.h b/DynamicTablesPkg/Include/ArmNameSpaceObjects.h
> index 19dcae13b219..9c49091def59 100644
> --- a/DynamicTablesPkg/Include/ArmNameSpaceObjects.h
> +++ b/DynamicTablesPkg/Include/ArmNameSpaceObjects.h
> @@ -58,6 +58,7 @@ typedef enum ArmObjectID {
>     EArmObjGenericInitiatorAffinityInfo, ///< 34 - Generic Initiator Affinity
>     EArmObjSerialPortInfo,               ///< 35 - Generic Serial Port Info
>     EArmObjCmn600Info,                   ///< 36 - CMN-600 Info
> +  EArmObjLpiInfo,                      ///< 37 - Lpi Info
>     EArmObjMax
>   } EARM_OBJECT_ID;
>   
> @@ -711,6 +712,10 @@ typedef struct CmArmProcHierarchyInfo {
>     /// the NoOfPrivateResources is 0, in which case it is recommended to set
>     /// this field to CM_NULL_TOKEN.
>     CM_OBJECT_TOKEN   PrivateResourcesArrayToken;
> +  /// Optional field: Reference Token for the Lpi state of this processor.
> +  /// Token identifying a CM_ARM_OBJ_REF structure, itself referencing
> +  /// CM_ARM_LPI_INFO objects.
> +  CM_OBJECT_TOKEN   LpiToken;
>   } CM_ARM_PROC_HIERARCHY_INFO;
>   
>   /** A structure that describes the Cache Type Structure (Type 1) in PPTT
> @@ -878,6 +883,69 @@ typedef struct CmArmCmn600Info {
>     CM_ARM_EXTENDED_INTERRUPT  DtcInterrupt[4];
>   } CM_ARM_CMN_600_INFO;
>   
> +/** A structure that describes the Lpi information.
> +
> +  The Low Power Idle states are described in DSDT/SSDT and associated
> +  to cpus/clusters in the cpu topology.
> +
> +  ID: EArmObjLpiInfo
> +*/
> +typedef struct CmArmLpiInfo {
> +  /** Minimum Residency. Time in microseconds after which a
> +      state becomes more energy efficient than any shallower state.
> +  */
> +  UINT32                                  MinResidency;
> +
> +  /** Worst case time in microseconds from a wake interrupt
> +      being asserted to the return to a running state
> +  */
> +  UINT32                                  WorstCaseWakeLatency;
> +
> +  /** Flags.
> +  */
> +  UINT32                                  Flags;
> +
> +  /** Architecture specific context loss flags.
> +  */
> +  UINT32                                  ArchFlags;
> +
> +  /** Residency counter frequency in cycles-per-second (Hz).
> +  */
> +  UINT32                                  ResCntFreq;
> +
> +  /** Every shallower power state in the parent is also enabled.
> +  */
> +  UINT32                                  EnableParentState;
> +
> +  /** The EntryMethod _LPI field can be described as an integer
> +      or in a Register resource data descriptor.
> +
> +  If IsInteger is TRUE, the IntegerEntryMethod field is used.
> +  If IsInteger is FALSE, the RegisterEntryMethod field is used.
> +  */
> +  BOOLEAN                                 IsInteger;
> +
> +  /** EntryMethod described as an Integer.
> +  */
> +  UINT64                                  IntegerEntryMethod;
> +
> +  /** EntryMethod described as a EFI_ACPI_GENERIC_REGISTER_DESCRIPTOR.
> +  */
> +  EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE  RegisterEntryMethod;
> +
> +  /** Residency counter register.
> +  */
> +  EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE  ResidencyCounterRegister;
> +
> +  /** Usage counter register.
> +  */
> +  EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE  UsageCounterRegister;
> +
> +  /** String representing the Lpi state
> +  */
> +  CHAR8                                   StateName[16];
> +} CM_ARM_LPI_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 654ead6878e6..da5f5846edd9 100644
> --- a/DynamicTablesPkg/Library/Common/TableHelperLib/ConfigurationManagerObjectParser.c
> +++ b/DynamicTablesPkg/Library/Common/TableHelperLib/ConfigurationManagerObjectParser.c
> @@ -368,6 +368,39 @@ STATIC CONST CM_OBJ_PARSER CmArmCmn600InfoParser[] = {
>     {"DtcFlags[3]", 4, "0x%x", NULL}
>   };
>   
> +/** A parser for the EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE structure.
> +*/
> +STATIC CONST CM_OBJ_PARSER AcpiGenericAddressParser[] = {
> +  {"AddressSpaceId", 1, "%d", NULL},
> +  {"RegisterBitWidth", 1, "%d", NULL},
> +  {"RegisterBitOffset", 1, "%d", NULL},
> +  {"AccessSize", 1, "%d", NULL},
> +  {"Address", 8, "0x%llx", NULL},
> +};
> +
> +/** A parser for EArmObjLpiInfo.
> +*/
> +STATIC CONST CM_OBJ_PARSER CmArmLpiInfoParser[] = {
> +  {"MinResidency", 4, "0x%llx", NULL},
> +  {"WorstCaseWakeLatency", 4, "0x%llx", NULL},
> +  {"Flags", 4, "0x%llx", NULL},
> +  {"ArchFlags", 4, "0x%llx", NULL},
> +  {"ResCntFreq", 4, "0x%llx", NULL},
> +  {"EnableParentState", 4, "0x%llx", NULL},
> +  {"IsInteger", 1, "%d", NULL},
> +  {"IntegerEntryMethod", 8, "0x%llx", NULL},
> +  {"RegisterEntryMethod", sizeof (EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE),
> +    NULL, NULL, AcpiGenericAddressParser,
> +    ARRAY_SIZE (AcpiGenericAddressParser)},
> +  {"ResidencyCounterRegister", sizeof (EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE),
> +    NULL, NULL, AcpiGenericAddressParser,
> +    ARRAY_SIZE (AcpiGenericAddressParser)},
> +  {"UsageCounterRegister", sizeof (EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE),
> +    NULL, NULL, AcpiGenericAddressParser,
> +    ARRAY_SIZE (AcpiGenericAddressParser)},
> +  {"StateName", 16, "0x%a", NULL},
> +};
> +
>   /** A parser for Arm namespace objects.
>   */
>   STATIC CONST CM_OBJ_PARSER_ARRAY ArmNamespaceObjectParser[] = {
> @@ -440,6 +473,8 @@ STATIC CONST CM_OBJ_PARSER_ARRAY ArmNamespaceObjectParser[] = {
>       ARRAY_SIZE (CmArmSerialPortInfoParser)},
>     {"EArmObjCmn600Info", CmArmCmn600InfoParser,
>       ARRAY_SIZE (CmArmCmn600InfoParser)},
> +  {"EArmObjLpiInfo", CmArmLpiInfoParser,
> +      ARRAY_SIZE (CmArmLpiInfoParser)},
>     {"EArmObjMax", NULL, 0},
>   };
>   


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v1 09/13] DynamicTablesPkg: AML code generation for a Method returning a NS
  2021-10-01 15:23   ` Sami Mujawar
@ 2021-10-06 13:33     ` PierreGondois
  0 siblings, 0 replies; 30+ messages in thread
From: PierreGondois @ 2021-10-06 13:33 UTC (permalink / raw)
  To: Sami Mujawar, devel, Alexei Fedorov; +Cc: Akanksha Jain, Alexandru Elisei, nd

Hi Sami,

Thanks for the review, please find my answer as [Pierre]

On 10/1/21 4:23 PM, Sami Mujawar wrote:
> Hi Pierre,
>
> Please find my response inline marked [SAMI].
>
> Regards,
>
> Sami Mujawar
>
>
> On 23/06/2021 12:40 PM, Pierre.Gondois@arm.com wrote:
>> From: Pierre Gondois <Pierre.Gondois@arm.com>
>>
>> Add AmlCodeGenMethodRetNameString() to generate AML code to create
>> a Method returning a NameString (NS).
>>
>> AmlCodeGenMethodRetNameString (
>>    "MET0", "_CRS", 1, TRUE, 3, ParentNode, NewObjectNode
>>    );
>> is equivalent of the following ASL code:
>> Method(MET0, 1, Serialized, 3) {
>>    Return (_CRS)
>> }
>>
>> Signed-off-by: Pierre Gondois <Pierre.Gondois@arm.com>
>> ---
>>   .../Include/Library/AmlLib/AmlLib.h           |  53 +++++++++
>>   .../Common/AmlLib/CodeGen/AmlCodeGen.c        | 106 ++++++++++++++++++
>>   2 files changed, 159 insertions(+)
>>
>> diff --git a/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h
>> b/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h
>> index 6824cf3a6c82..7740aac24470 100644
>> --- a/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h
>> +++ b/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h
>> @@ -619,6 +619,59 @@ AmlCodeGenScope (
>>     OUT       AML_OBJECT_NODE_HANDLE  * NewObjectNode   OPTIONAL
>>     );
>>   +/** AML code generation for a method returning a NameString.
>> +
>> +  AmlCodeGenMethodRetNameString (
>> +    "MET0", "_CRS", 1, TRUE, 3, ParentNode, NewObjectNode
>> +    );
>> +  is equivalent of the following ASL code:
>> +    Method(MET0, 1, Serialized, 3) {
>> +      Return (_CRS)
>> +    }
>> +
>> +  The ASL parameters "ReturnType" and "ParameterTypes" are not asked
>> +  in this function. They are optional parameters in ASL.
>> +
>> +  @ingroup CodeGenApis
>> +
>> +  @param [in]  MethodNameString     The new Method's name.
>> +                                    Must be a NULL-terminated ASL
>> NameString
>> +                                    e.g.: "MET0", "_SB.MET0", etc.
>> +                                    The input string is copied.
>> +  @param [in]  ReturnedNameString   The name of the object returned
>> by the
>> +                                    method. Optional parameter, can be:
>> +                                     - NULL (ignored).
>> +                                     - A NULL-terminated ASL
>> NameString.
>> +                                       e.g.: "MET0", "_SB.MET0", etc.
>> +                                       The input string is copied.
> [SAMI] I think this should be a mandatory parameter and corresponding
> change is needed to the function code.

[Pierre]

Some methods don't have to return a specific object.
E.g.: The _SRS method (ACPI 6.4, s6.2.16 _SRS (Set Resource Settings))
which returns None as specified.
In such case, it is not necessary to return a NameString/path to a real
object.

>> +  @param [in]  NumArgs              Number of arguments.
>> +                                    Must be 0 <= NumArgs <= 6.
>> +  @param [in]  IsSerialized         TRUE is equivalent to Serialized.
>> +                                    FALSE is equivalent to
>> NotSerialized.
>> +                                    Default is NotSerialized in ASL
>> spec.
>> +  @param [in]  SyncLevel            Synchronization level for the
>> method.
>> +                                    Must be 0 <= SyncLevel <= 15.
>> +                                    Default is 0 in ASL.
>> +  @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
>> +AmlCodeGenMethodRetNameString (
>> +  IN  CONST CHAR8                   * MethodNameString,
>> +  IN  CONST CHAR8                   * ReturnedNameString,  OPTIONAL
>> +  IN        UINT8                     NumArgs,
>> +  IN        BOOLEAN                   IsSerialized,
>> +  IN        UINT8                     SyncLevel,
>> +  IN        AML_NODE_HANDLE           ParentNode,          OPTIONAL
>> +  OUT       AML_OBJECT_NODE_HANDLE  * NewObjectNode        OPTIONAL
>> +  );
>> +
>
[snip]

^ permalink raw reply	[flat|nested] 30+ messages in thread

end of thread, other threads:[~2021-10-06 13:33 UTC | newest]

Thread overview: 30+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2021-06-23 11:40 [PATCH v1 00/13] Create a SSDT CPU topology generator PierreGondois
2021-06-23 11:40 ` [PATCH v1 01/13] DynamicTablesPkg: Make AmlNodeGetIntegerValue public PierreGondois
2021-10-01 14:48   ` Sami Mujawar
2021-06-23 11:40 ` [PATCH v1 02/13] DynamicTablesPkg: AML Code generation for Register() PierreGondois
2021-10-01 12:25   ` Sami Mujawar
2021-06-23 11:40 ` [PATCH v1 03/13] DynamicTablesPkg: AML Code generation for Resource data EndTag PierreGondois
2021-10-01 12:48   ` Sami Mujawar
2021-06-23 11:40 ` [PATCH v1 04/13] DynamicTablesPkg: AML code generation for a Package PierreGondois
2021-10-01 12:55   ` Sami Mujawar
2021-06-23 11:40 ` [PATCH v1 05/13] DynamicTablesPkg: Helper function to compute package length PierreGondois
2021-10-01 14:24   ` Sami Mujawar
2021-06-23 11:40 ` [PATCH v1 06/13] DynamicTablesPkg: AML code generation for a ResourceTemplate PierreGondois
2021-10-01 14:34   ` Sami Mujawar
2021-06-23 11:40 ` [PATCH v1 07/13] DynamicTablesPkg: AML code generation for a Method PierreGondois
2021-10-01 14:52   ` Sami Mujawar
2021-06-23 11:40 ` [PATCH v1 08/13] DynamicTablesPkg: AML code generation to Return a NameString PierreGondois
2021-10-01 15:13   ` Sami Mujawar
2021-06-23 11:40 ` [PATCH v1 09/13] DynamicTablesPkg: AML code generation for a Method returning a NS PierreGondois
2021-10-01 15:23   ` Sami Mujawar
2021-10-06 13:33     ` PierreGondois
2021-06-23 11:40 ` [PATCH v1 09/13] DynamicTablesPkg: AML code generation to create " PierreGondois
2021-06-23 11:45   ` [edk2-devel] " PierreGondois
2021-06-23 11:40 ` [PATCH v1 10/13] DynamicTablesPkg: AML code generation for a _LPI object PierreGondois
2021-10-01 15:31   ` Sami Mujawar
2021-06-23 11:40 ` [PATCH v1 11/13] DynamicTablesPkg: AML code generation to add an _LPI state PierreGondois
2021-10-01 15:43   ` Sami Mujawar
2021-06-23 11:40 ` [PATCH v1 12/13] DynamicTablesPkg: Add CM_ARM_LPI_INFO object PierreGondois
2021-10-05 14:39   ` Sami Mujawar
2021-06-23 11:40 ` [PATCH v1 13/13] DynamicTablesPkg: SSDT CPU topology and LPI state generator PierreGondois
2021-10-05 14:38   ` Sami Mujawar

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox