public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Sami Mujawar" <sami.mujawar@arm.com>
To: <devel@edk2.groups.io>
Cc: Sami Mujawar <sami.mujawar@arm.com>, <Alexei.Fedorov@arm.com>,
	<pierre.gondois@arm.com>, <ard.biesheuvel@arm.com>,
	<Matteo.Carlini@arm.com>, <Ben.Adderson@arm.com>, <nd@arm.com>
Subject: [PATCH v1 24/30] DynamicTablesPkg: AmlLib APIs
Date: Wed, 12 Aug 2020 16:22:30 +0100	[thread overview]
Message-ID: <20200812152236.31164-25-sami.mujawar@arm.com> (raw)
In-Reply-To: <20200812152236.31164-1-sami.mujawar@arm.com>

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

AmlLib library implements an AML parser, AML tree interface,
serialiser, code generator and other interfaces to generate
Definition Block tables.

The AmlLib APIs are a collection of interfaces that enable
parsing, iterating, modifying, adding, and serialising AML
data to generate a Definition Block table.

The AmlLib APIs are declared in Include\AmlLib\AmlLib.h

Signed-off-by: Pierre Gondois <pierre.gondois@arm.com>
Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
---
 DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h                | 631 ++++++++++++++++++++
 DynamicTablesPkg/Library/Common/AmlLib/Api/AmlApi.c             | 382 ++++++++++++
 DynamicTablesPkg/Library/Common/AmlLib/Api/AmlApiHelper.c       | 219 +++++++
 DynamicTablesPkg/Library/Common/AmlLib/Api/AmlApiHelper.h       |  93 +++
 DynamicTablesPkg/Library/Common/AmlLib/Api/AmlResourceDataApi.c | 320 ++++++++++
 5 files changed, 1645 insertions(+)

diff --git a/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h b/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h
new file mode 100644
index 0000000000000000000000000000000000000000..1dcb93861436851e848f9cb5fd69621ccd7bf7a1
--- /dev/null
+++ b/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h
@@ -0,0 +1,631 @@
+/** @file
+  AML Lib.
+
+  Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef AML_LIB_H_
+#define AML_LIB_H_
+
+/**
+  @mainpage Dynamic AML Generation
+  @{
+    @par Summary
+    @{
+    ACPI tables are categorized as data tables and definition block
+    tables. Dynamic Tables Framework currently supports generation of ACPI
+    data tables. Generation of definition block tables is difficult as these
+    tables are encoded in ACPI Machine Language (AML), which has a complex
+    grammar.
+
+    Dynamic AML Generation is an extension to the Dynamic tables Framework.
+    One of the techniques used to simplify definition block generation is to
+    fixup a template SSDT table.
+
+    Dynamic AML aims to provide a framework that allows fixing up of an ACPI
+    SSDT template with appropriate information about the hardware.
+
+    This framework consists of an:
+    - AMLLib core that implements a rich set of interfaces to parse, traverse
+      and update AML data.
+    - AMLLib library APIs that provides interfaces to search and updates nodes
+      in the AML namespace.
+    @}
+  @}
+*/
+
+#include <IndustryStandard/Acpi.h>
+
+#ifndef AML_HANDLE
+
+/** Node handle.
+*/
+typedef void* AML_NODE_HANDLE;
+
+/** Root Node handle.
+*/
+typedef void* AML_ROOT_NODE_HANDLE;
+
+/** Object Node handle.
+*/
+typedef void* AML_OBJECT_NODE_HANDLE;
+
+/** Data Node handle.
+*/
+typedef void* AML_DATA_NODE_HANDLE;
+
+#endif // AML_HANDLE
+
+/** Parse the definition block.
+
+  The function parses the whole AML blob. It starts with the ACPI DSDT/SSDT
+  header and then parses the AML bytestream.
+  A tree structure is returned via the RootPtr.
+  The tree must be deleted with the AmlDeleteTree function.
+
+  @ingroup UserApis
+
+  @param  [in]  DefinitionBlock   Pointer to the definition block.
+  @param  [out] RootPtr           Pointer to the root node of the AML tree.
+
+  @retval EFI_SUCCESS             The function completed successfully.
+  @retval EFI_BUFFER_TOO_SMALL    No space left in the buffer.
+  @retval EFI_INVALID_PARAMETER   Invalid parameter.
+  @retval EFI_OUT_OF_RESOURCES    Could not allocate memory.
+**/
+EFI_STATUS
+EFIAPI
+AmlParseDefinitionBlock (
+  IN  CONST EFI_ACPI_DESCRIPTION_HEADER   * DefinitionBlock,
+  OUT       AML_ROOT_NODE_HANDLE          * RootPtr
+  );
+
+/** Serialize an AML definition block.
+
+  This functions allocates memory with the "AllocateZeroPool ()"
+  function. This memory is used to serialize the AML tree and is
+  returned in the Table.
+
+  @ingroup UserApis
+
+  @param [in]  RootNode         Root node of the tree.
+  @param [out] Table            On return, hold the serialized
+                                definition block.
+
+  @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
+AmlSerializeDefinitionBlock (
+  IN  AML_ROOT_NODE_HANDLE              RootNode,
+  OUT EFI_ACPI_DESCRIPTION_HEADER    ** Table
+  );
+
+/** Clone a node and its children (clone a tree branch).
+
+  The cloned branch returned is not attached to any tree.
+
+  @ingroup UserApis
+
+  @param  [in]  Node        Pointer to a node.
+                            Node is the head of the branch to clone.
+  @param  [out] ClonedNode  Pointer holding the head of the created cloned
+                            branch.
+
+  @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
+AmlCloneTree (
+  IN  AML_NODE_HANDLE   Node,
+  OUT AML_NODE_HANDLE * ClonedNode
+  );
+
+/** Delete a Node and its children.
+
+  The Node must be removed from the tree first,
+  or must be the root node.
+
+  @ingroup UserApis
+
+  @param  [in]  Node  Pointer to the node to delete.
+
+  @retval EFI_SUCCESS             The function completed successfully.
+  @retval EFI_INVALID_PARAMETER   Invalid parameter.
+**/
+EFI_STATUS
+EFIAPI
+AmlDeleteTree (
+  IN  AML_NODE_HANDLE   Node
+  );
+
+/** Detach the Node from the tree.
+
+  The function will fail if the Node is in its parent's fixed
+  argument list.
+  The Node is not deleted. The deletion is done separately
+  from the removal.
+
+  @ingroup UserApis
+
+  @param  [in]  Node  Pointer to a Node.
+                      Must be a data node or an object node.
+
+  @retval EFI_SUCCESS             The function completed successfully.
+  @retval EFI_INVALID_PARAMETER   Invalid parameter.
+**/
+EFI_STATUS
+EFIAPI
+AmlDetachNode (
+  IN  AML_NODE_HANDLE   Node
+  );
+
+/** Find a node in the AML namespace, given an ASL path and a reference Node.
+
+   - The AslPath can be an absolute path, or a relative path from the
+     reference Node;
+   - Node must be a root node or a namespace node;
+   - A root node is expected to be at the top of the tree.
+
+  E.g.:
+  For the following AML namespace, with the ReferenceNode being the node with
+  the name "AAAA":
+   - the node with the name "BBBB" can be found by looking for the ASL
+     path "BBBB";
+   - the root node can be found by looking for the ASL relative path "^",
+      or the absolute path "\\".
+
+  AML namespace:
+  \
+  \-AAAA      <- ReferenceNode
+    \-BBBB
+
+  @ingroup NameSpaceApis
+
+  @param  [in]  ReferenceNode   Reference node.
+                                If a relative path is given, the
+                                search is done from this node. If
+                                an absolute path is given, the
+                                search is done from the root node.
+                                Must be a root node or an object
+                                node which is part of the
+                                namespace.
+  @param  [in]  AslPath         ASL path to the searched node in
+                                the namespace. An ASL path name is
+                                NULL terminated. Can be a relative
+                                or absolute path.
+                                E.g.: "\\_SB.CLU0.CPU0" or "^CPU0"
+  @param  [out] OutNode         Pointer to the found node.
+                                Contains NULL if not found.
+
+  @retval EFI_SUCCESS             The function completed successfully.
+  @retval EFI_BUFFER_TOO_SMALL    No space left in the buffer.
+  @retval EFI_INVALID_PARAMETER   Invalid parameter.
+  @retval EFI_OUT_OF_RESOURCES    Out of memory.
+**/
+EFI_STATUS
+EFIAPI
+AmlFindNode (
+  IN  AML_NODE_HANDLE       ReferenceNode,
+  IN  CHAR8               * AslPath,
+  OUT AML_NODE_HANDLE     * OutNode
+  );
+
+/**
+  @defgroup UserApis User APIs
+  @{
+    User APIs are implemented to ease most common actions that might be done
+    using the AmlLib. They allow to find specific objects like "_UID" or
+    "_CRS" and to update their value. It also shows what can be done using
+    AmlLib functions.
+  @}
+*/
+
+/** Update the name of a DeviceOp object node.
+
+  @ingroup UserApis
+
+  @param  [in] DeviceOpNode   Object node representing a Device.
+                              Must have an OpCode=AML_NAME_OP, SubOpCode=0.
+                              OpCode/SubOpCode.
+                              DeviceOp object nodes are defined in ASL
+                              using the "Device ()" function.
+  @param  [in] NewNameString  The new Device's name.
+                              Must be a NULL-terminated ASL NameString
+                              e.g.: "DEV0", "DV15.DEV0", etc.
+                              The input string is copied.
+
+  @retval EFI_SUCCESS             The function completed successfully.
+  @retval EFI_INVALID_PARAMETER   Invalid parameter.
+**/
+EFI_STATUS
+EFIAPI
+AmlDeviceOpUpdateName (
+  IN  AML_OBJECT_NODE_HANDLE    DeviceOpNode,
+  IN  CHAR8                   * NewNameString
+  );
+
+/** Update an integer value defined by a NameOp object node.
+
+  For compatibility reasons, the NameOpNode must initially
+  contain an integer.
+
+  @ingroup UserApis
+
+  @param  [in] NameOpNode   NameOp object node.
+                            Must have an OpCode=AML_NAME_OP, SubOpCode=0.
+                            NameOp object nodes are defined in ASL
+                            using the "Name ()" function.
+  @param  [in] NewInt       New Integer value to assign.
+                            Must be a UINT64.
+
+  @retval EFI_SUCCESS             The function completed successfully.
+  @retval EFI_INVALID_PARAMETER   Invalid parameter.
+**/
+EFI_STATUS
+EFIAPI
+AmlNameOpUpdateInteger (
+  IN  AML_OBJECT_NODE_HANDLE  NameOpNode,
+  IN  UINT64                  NewInt
+  );
+
+/** Update a string value defined by a NameOp object node.
+
+  The NameOpNode must initially contain a string.
+  The EISAID ASL macro converts a string to an integer. This, it is
+  not accepted.
+
+  @ingroup UserApis
+
+  @param  [in] NameOpNode   NameOp object node.
+                            Must have an OpCode=AML_NAME_OP, SubOpCode=0.
+                            NameOp object nodes are defined in ASL
+                            using the "Name ()" function.
+  @param  [in] NewName      New NULL terminated string to assign to
+                            the NameOpNode.
+                            The input string is copied.
+
+  @retval EFI_SUCCESS             The function completed successfully.
+  @retval EFI_INVALID_PARAMETER   Invalid parameter.
+**/
+EFI_STATUS
+EFIAPI
+AmlNameOpUpdateString (
+  IN        AML_OBJECT_NODE_HANDLE    NameOpNode,
+  IN  CONST CHAR8                   * NewName
+  );
+
+/** Get the first Resource Data element contained in a "_CRS" object.
+
+  In the following ASL code, the function will return the Resource Data
+  node corresponding to the "QWordMemory ()" ASL macro.
+  Name (_CRS, ResourceTemplate() {
+      QWordMemory (...) {...},
+      Interrupt (...) {...}
+    }
+  )
+
+  Note:
+   - The "_CRS" object must be declared using ASL "Name (Declare Named Object)".
+   - "_CRS" declared using ASL "Method (Declare Control Method)" is not
+     supported.
+
+  @ingroup UserApis
+
+  @param  [in] NameOpCrsNode  NameOp object node defining a "_CRS" object.
+                              Must have an OpCode=AML_NAME_OP, SubOpCode=0.
+                              NameOp object nodes are defined in ASL
+                              using the "Name ()" function.
+  @param  [out] OutRdNode     Pointer to the first Resource Data element of
+                              the "_CRS" object. A Resource Data element
+                              is stored in a data node.
+
+  @retval EFI_SUCCESS             The function completed successfully.
+  @retval EFI_INVALID_PARAMETER   Invalid parameter.
+**/
+EFI_STATUS
+EFIAPI
+AmlNameOpCrsGetFirstRdNode (
+  IN  AML_OBJECT_NODE_HANDLE   NameOpCrsNode,
+  OUT AML_DATA_NODE_HANDLE   * OutRdNode
+  );
+
+/** Get the Resource Data element following the CurrRdNode Resource Data.
+
+  In the following ASL code, if CurrRdNode corresponds to the first
+  "QWordMemory ()" ASL macro, the function will return the Resource Data
+  node corresponding to the "Interrupt ()" ASL macro.
+  Name (_CRS, ResourceTemplate() {
+      QwordMemory (...) {...},
+      Interrupt (...) {...}
+    }
+  )
+
+  The CurrRdNode Resource Data node must be defined in an object named "_CRS"
+  and defined by a "Name ()" ASL function.
+
+  @ingroup UserApis
+
+  @param  [in]  CurrRdNode   Pointer to the current Resource Data element of
+                             the "_CRS" variable.
+  @param  [out] OutRdNode    Pointer to the Resource Data element following
+                             the CurrRdNode.
+                             Contain a NULL pointer if CurrRdNode is the
+                             last Resource Data element in the list.
+                             The "End Tag" is not considered as a resource
+                             data element and is not returned.
+
+  @retval EFI_SUCCESS             The function completed successfully.
+  @retval EFI_INVALID_PARAMETER   Invalid parameter.
+**/
+EFI_STATUS
+EFIAPI
+AmlNameOpCrsGetNextRdNode (
+  IN  AML_DATA_NODE_HANDLE    CurrRdNode,
+  OUT AML_DATA_NODE_HANDLE  * OutRdNode
+  );
+
+/** Update the first interrupt of an Interrupt resource data node.
+
+  The flags of the Interrupt resource data are left unchanged.
+
+  The InterruptRdNode corresponds to the Resource Data created by the
+  "Interrupt ()" ASL macro. It is an Extended Interrupt Resource Data.
+  See ACPI 6.3 specification, s6.4.3.6 "Extended Interrupt Descriptor"
+  for more information about Extended Interrupt Resource Data.
+
+  @ingroup UserApis
+
+  @param  [in]  InterruptRdNode   Pointer to the an extended interrupt
+                                  resource data node.
+  @param  [in]  Irq               Interrupt value to update.
+
+  @retval  EFI_SUCCESS            The function completed successfully.
+  @retval  EFI_INVALID_PARAMETER  Invalid parameter.
+  @retval  EFI_OUT_OF_RESOURCES   Out of resources.
+**/
+EFI_STATUS
+EFIAPI
+AmlUpdateRdInterrupt (
+  IN  AML_DATA_NODE_HANDLE    InterruptRdNode,
+  IN  UINT32                  Irq
+  );
+
+/** Update the base address and length of a QWord resource data node.
+
+  @ingroup UserApis
+
+  @param  [in] QWordRdNode         Pointer a QWord resource data
+                                   node.
+  @param  [in] BaseAddress         Base address.
+  @param  [in] BaseAddressLength   Base address length.
+
+  @retval  EFI_SUCCESS            The function completed successfully.
+  @retval  EFI_INVALID_PARAMETER  Invalid parameter.
+  @retval  EFI_OUT_OF_RESOURCES   Out of resources.
+**/
+EFI_STATUS
+EFIAPI
+AmlUpdateRdQWord (
+  IN  AML_DATA_NODE_HANDLE  QWordRdNode,
+  IN  UINT64                BaseAddress,
+  IN  UINT64                BaseAddressLength
+  );
+
+/** Add an Interrupt Resource Data node.
+
+  This function creates a Resource Data element corresponding to the
+  "Interrupt ()" ASL function, stores it in an AML Data Node.
+
+  It then adds it after the input CurrRdNode in the list of resource data
+  element.
+
+  The Resource Data effectively created is an Extended Interrupt Resource
+  Data. See ACPI 6.3 specification, s6.4.3.6 "Extended Interrupt Descriptor"
+  for more information about Extended Interrupt Resource Data.
+
+  The Extended Interrupt contains one single interrupt.
+
+  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.
+
+  Note: The _CRS node must be defined using the ASL Name () function.
+        e.g. Name (_CRS, ResourceTemplate () {
+               ...
+             }
+
+  @ingroup UserApis
+
+  @param  [in]  NameOpCrsNode    NameOp object node defining a "_CRS" object.
+                                 Must have an OpCode=AML_NAME_OP, SubOpCode=0.
+                                 NameOp object nodes are defined in ASL
+                                 using the "Name ()" function.
+  @param  [in]  ResourceConsumer The device consumes the specified interrupt
+                                 or produces it for use by a child device.
+  @param  [in]  EdgeTriggered    The interrupt is edge triggered or
+                                 level triggered.
+  @param  [in]  ActiveLow        The interrupt is active-high or active-low.
+  @param  [in]  Shared           The interrupt can be shared with other
+                                 devices or not (Exclusive).
+  @param  [in]  IrqList          Interrupt list. Must be non-NULL.
+  @param  [in]  IrqCount         Interrupt count. Must be non-zero.
+
+
+  @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
+AmlCodeGenCrsAddRdInterrupt (
+  IN  AML_OBJECT_NODE_HANDLE  NameOpCrsNode,
+  IN  BOOLEAN                 ResourceConsumer,
+  IN  BOOLEAN                 EdgeTriggered,
+  IN  BOOLEAN                 ActiveLow,
+  IN  BOOLEAN                 Shared,
+  IN  UINT32                * IrqList,
+  IN  UINT8                   IrqCount
+  );
+
+/** AML code generation for DefinitionBlock.
+
+  Create a Root Node handle.
+  It is the caller's responsibility to free the allocated memory
+  with the AmlDeleteTree function.
+
+  AmlCodeGenDefinitionBlock (TableSignature, OemId, TableID, OEMRevision) is
+  equivalent to the following ASL code:
+    DefinitionBlock (AMLFileName, TableSignature, ComplianceRevision,
+      OemId, TableID, OEMRevision) {}
+  with the ComplianceRevision set to 2 and the AMLFileName is ignored.
+
+  @ingroup CodeGenApis
+
+  @param[in]  TableSignature       4-character ACPI signature.
+                                   Must be 'DSDT' or 'SSDT'.
+  @param[in]  OemId                6-character string OEM identifier.
+  @param[in]  OemTableId           8-character string OEM table identifier.
+  @param[in]  OemRevision          OEM revision number.
+  @param[out] DefinitionBlockTerm  The ASL Term handle representing a
+                                   Definition Block.
+
+  @retval EFI_SUCCESS             Success.
+  @retval EFI_INVALID_PARAMETER   Invalid parameter.
+  @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
+**/
+EFI_STATUS
+EFIAPI
+AmlCodeGenDefinitionBlock (
+  IN  CONST CHAR8                 * TableSignature,
+  IN  CONST CHAR8                 * OemId,
+  IN  CONST CHAR8                 * OemTableId,
+  IN        UINT32                  OemRevision,
+  OUT       AML_ROOT_NODE_HANDLE  * NewRootNode
+  );
+
+/** AML code generation for a Name object node, containing a String.
+
+  AmlCodeGenNameString ("_HID", "HID0000", ParentNode, NewObjectNode) is
+  equivalent of the following ASL code:
+    Name(_HID, "HID0000")
+
+  @ingroup CodeGenApis
+
+  @param  [in] NameString     The new variable name.
+                              Must be a NULL-terminated ASL NameString
+                              e.g.: "DEV0", "DV15.DEV0", etc.
+                              The input string is copied.
+  @param [in]  String         NULL terminated String to associate to the
+                              NameString.
+  @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
+AmlCodeGenNameString (
+  IN  CONST CHAR8                   * NameString,
+  IN        CHAR8                   * String,
+  IN        AML_NODE_HANDLE           ParentNode,     OPTIONAL
+  OUT       AML_OBJECT_NODE_HANDLE  * NewObjectNode   OPTIONAL
+  );
+
+/** AML code generation for a Name object node, containing an Integer.
+
+  AmlCodeGenNameInteger ("_UID", 1, ParentNode, NewObjectNode) is
+  equivalent of the following ASL code:
+    Name(_UID, One)
+
+  @ingroup CodeGenApis
+
+  @param  [in] NameString     The new variable name.
+                              Must be a NULL-terminated ASL NameString
+                              e.g.: "DEV0", "DV15.DEV0", etc.
+                              The input string is copied.
+  @param [in]  Integer        Integer to associate to the NameString.
+  @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
+AmlCodeGenNameInteger (
+  IN  CONST CHAR8                   * NameString,
+  IN        UINT64                    Integer,
+  IN        AML_NODE_HANDLE           ParentNode,     OPTIONAL
+  OUT       AML_OBJECT_NODE_HANDLE  * NewObjectNode   OPTIONAL
+  );
+
+/** AML code generation for a Device object node.
+
+  AmlCodeGenDevice ("COM0", ParentNode, NewObjectNode) is
+  equivalent of the following ASL code:
+    Device(COM0) {}
+
+  @ingroup CodeGenApis
+
+  @param  [in] NameString     The new Device's name.
+                              Must be a NULL-terminated ASL NameString
+                              e.g.: "DEV0", "DV15.DEV0", etc.
+                              The input string is copied.
+  @param [in]  ParentNode     If provided, set ParentNode as the parent
+                              of the node created.
+  @param [out] NewObjectNode  If success, contains the created node.
+
+  @retval EFI_SUCCESS             Success.
+  @retval EFI_INVALID_PARAMETER   Invalid parameter.
+  @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
+**/
+EFI_STATUS
+EFIAPI
+AmlCodeGenDevice (
+  IN  CONST CHAR8                   * NameString,
+  IN        AML_NODE_HANDLE           ParentNode,     OPTIONAL
+  OUT       AML_OBJECT_NODE_HANDLE  * NewObjectNode   OPTIONAL
+  );
+
+/** AML code generation for a Scope object node.
+
+  AmlCodeGenScope ("_SB", ParentNode, NewObjectNode) is
+  equivalent of the following ASL code:
+    Scope(_SB) {}
+
+  @ingroup CodeGenApis
+
+  @param  [in] NameString     The new Scope's name.
+                              Must be a NULL-terminated ASL NameString
+                              e.g.: "DEV0", "DV15.DEV0", etc.
+                              The input string is copied.
+  @param [in]  ParentNode     If provided, set ParentNode as the parent
+                              of the node created.
+  @param [out] NewObjectNode  If success, contains the created node.
+
+  @retval EFI_SUCCESS             Success.
+  @retval EFI_INVALID_PARAMETER   Invalid parameter.
+  @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
+**/
+EFI_STATUS
+EFIAPI
+AmlCodeGenScope (
+  IN  CONST CHAR8                   * NameString,
+  IN        AML_NODE_HANDLE           ParentNode,     OPTIONAL
+  OUT       AML_OBJECT_NODE_HANDLE  * NewObjectNode   OPTIONAL
+  );
+
+#endif // AML_LIB_H_
diff --git a/DynamicTablesPkg/Library/Common/AmlLib/Api/AmlApi.c b/DynamicTablesPkg/Library/Common/AmlLib/Api/AmlApi.c
new file mode 100644
index 0000000000000000000000000000000000000000..fdf04acc6212f9d6b6f691f30a60fea6f0b43e6f
--- /dev/null
+++ b/DynamicTablesPkg/Library/Common/AmlLib/Api/AmlApi.c
@@ -0,0 +1,382 @@
+/** @file
+  AML Api.
+
+  Copyright (c) 2020, Arm Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+/* Even though this file has access to the internal Node definition,
+   i.e. AML_ROOT_NODE, AML_OBJECT_NODE, etc. Only the external node
+   handle types should be used, i.e. AML_NODE_HANDLE, AML_ROOT_NODE_HANDLE,
+   etc.
+   Indeed, the functions in the "Api" folder should be implemented only
+   using the "safe" functions available in the "Include" folder. This
+   makes the functions available in the "Api" folder easy to export.
+*/
+#include <AmlNodeDefines.h>
+
+#include <AmlCoreInterface.h>
+#include <AmlInclude.h>
+#include <Api/AmlApiHelper.h>
+#include <String/AmlString.h>
+
+/** Update the name of a DeviceOp object node.
+
+  @param  [in] DeviceOpNode   Object node representing a Device.
+                              Must have an OpCode=AML_NAME_OP, SubOpCode=0.
+                              OpCode/SubOpCode.
+                              DeviceOp object nodes are defined in ASL
+                              using the "Device ()" function.
+  @param  [in] NewNameString  The new Device's name.
+                              Must be a NULL-terminated ASL NameString
+                              e.g.: "DEV0", "DV15.DEV0", etc.
+                              The input string is copied.
+
+  @retval EFI_SUCCESS             The function completed successfully.
+  @retval EFI_INVALID_PARAMETER   Invalid parameter.
+**/
+EFI_STATUS
+EFIAPI
+AmlDeviceOpUpdateName (
+  IN  AML_OBJECT_NODE_HANDLE    DeviceOpNode,
+  IN  CHAR8                   * NewNameString
+  )
+{
+  EFI_STATUS              Status;
+
+  AML_DATA_NODE_HANDLE    DeviceNameDataNode;
+  CHAR8                 * NewAmlNameString;
+  UINT32                  NewAmlNameStringSize;
+
+  // Check the input node is an object node.
+  if ((DeviceOpNode == NULL)                                              ||
+      (AmlGetNodeType ((AML_NODE_HANDLE)DeviceOpNode) != EAmlNodeObject)  ||
+      (!AmlNodeHasOpCode (DeviceOpNode, AML_EXT_OP, AML_EXT_DEVICE_OP))   ||
+      (NewNameString == NULL)) {
+    ASSERT (0);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // Get the Device's name, being a data node
+  // which is the 1st fixed argument (i.e. index 0).
+  DeviceNameDataNode = (AML_DATA_NODE_HANDLE)AmlGetFixedArgument (
+                                               DeviceOpNode,
+                                               EAmlParseIndexTerm0
+                                               );
+  if ((DeviceNameDataNode == NULL)                                            ||
+      (AmlGetNodeType ((AML_NODE_HANDLE)DeviceNameDataNode) != EAmlNodeData)  ||
+      (!AmlNodeHasDataType (DeviceNameDataNode, EAmlNodeDataTypeNameString))) {
+    ASSERT (0);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Status = ConvertAslNameToAmlName (NewNameString, &NewAmlNameString);
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    return Status;
+  }
+
+  Status = AmlGetNameStringSize (NewAmlNameString, &NewAmlNameStringSize);
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto exit_handler;
+  }
+
+  // Update the Device's name node.
+  Status = AmlUpdateDataNode (
+             DeviceNameDataNode,
+             EAmlNodeDataTypeNameString,
+             (UINT8*)NewAmlNameString,
+             NewAmlNameStringSize
+             );
+  ASSERT_EFI_ERROR (Status);
+
+exit_handler:
+  FreePool (NewAmlNameString);
+  return Status;
+}
+
+/** Update an integer value defined by a NameOp object node.
+
+  For compatibility reasons, the NameOpNode must initially
+  contain an integer.
+
+  @param  [in] NameOpNode   NameOp object node.
+                            Must have an OpCode=AML_NAME_OP, SubOpCode=0.
+                            NameOp object nodes are defined in ASL
+                            using the "Name ()" function.
+  @param  [in] NewInt       New Integer value to assign.
+                            Must be a UINT64.
+
+  @retval EFI_SUCCESS             The function completed successfully.
+  @retval EFI_INVALID_PARAMETER   Invalid parameter.
+**/
+EFI_STATUS
+EFIAPI
+AmlNameOpUpdateInteger (
+  IN  AML_OBJECT_NODE_HANDLE  NameOpNode,
+  IN  UINT64                  NewInt
+  )
+{
+  EFI_STATUS              Status;
+  AML_OBJECT_NODE_HANDLE  IntegerOpNode;
+
+  if ((NameOpNode == NULL)                                             ||
+      (AmlGetNodeType ((AML_NODE_HANDLE)NameOpNode) != EAmlNodeObject) ||
+      (!AmlNodeHasOpCode (NameOpNode, AML_NAME_OP, 0))) {
+    ASSERT (0);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // Get the Integer object node defined by the "Name ()" function:
+  // it must have an Integer OpCode (Byte/Word/DWord/QWord).
+  // It is the 2nd fixed argument (i.e. index 1) of the NameOp node.
+  // This can also be a ZeroOp or OneOp node.
+  IntegerOpNode = (AML_OBJECT_NODE_HANDLE)AmlGetFixedArgument (
+                                            NameOpNode,
+                                            EAmlParseIndexTerm1
+                                            );
+  if ((IntegerOpNode == NULL)  ||
+      (AmlGetNodeType ((AML_NODE_HANDLE)IntegerOpNode) != EAmlNodeObject)) {
+    ASSERT (0);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // Update the Integer value.
+  Status = AmlUpdateInteger (IntegerOpNode, NewInt);
+  ASSERT_EFI_ERROR (Status);
+
+  return Status;
+}
+
+/** Update a string value defined by a NameOp object node.
+
+  The NameOpNode must initially contain a string.
+  The EISAID ASL macro converts a string to an integer. This, it is
+  not accepted.
+
+  @param  [in] NameOpNode   NameOp object node.
+                            Must have an OpCode=AML_NAME_OP, SubOpCode=0.
+                            NameOp object nodes are defined in ASL
+                            using the "Name ()" function.
+  @param  [in] NewName      New NULL terminated string to assign to
+                            the NameOpNode.
+                            The input string is copied.
+
+  @retval EFI_SUCCESS             The function completed successfully.
+  @retval EFI_INVALID_PARAMETER   Invalid parameter.
+**/
+EFI_STATUS
+EFIAPI
+AmlNameOpUpdateString (
+  IN        AML_OBJECT_NODE_HANDLE    NameOpNode,
+  IN  CONST CHAR8                   * NewName
+  )
+{
+  EFI_STATUS              Status;
+  AML_OBJECT_NODE_HANDLE  StringOpNode;
+  AML_DATA_NODE_HANDLE    StringDataNode;
+
+  if ((NameOpNode == NULL)                                             ||
+      (AmlGetNodeType ((AML_NODE_HANDLE)NameOpNode) != EAmlNodeObject) ||
+      (!AmlNodeHasOpCode (NameOpNode, AML_NAME_OP, 0))) {
+    ASSERT (0);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // Get the String object node defined by the "Name ()" function:
+  // it must have a string OpCode.
+  // It is the 2nd fixed argument (i.e. index 1) of the NameOp node.
+  StringOpNode = (AML_OBJECT_NODE_HANDLE)AmlGetFixedArgument (
+                                           NameOpNode,
+                                           EAmlParseIndexTerm1
+                                           );
+  if ((StringOpNode == NULL)  ||
+      (AmlGetNodeType ((AML_NODE_HANDLE)StringOpNode) != EAmlNodeObject)) {
+    ASSERT (0);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // Get the string data node.
+  // It is the 1st fixed argument (i.e. index 0) of the StringOpNode node.
+  StringDataNode = (AML_DATA_NODE_HANDLE)AmlGetFixedArgument (
+                                           StringOpNode,
+                                           EAmlParseIndexTerm0
+                                           );
+  if ((StringDataNode == NULL)  ||
+      (AmlGetNodeType ((AML_NODE_HANDLE)StringDataNode) != EAmlNodeData)) {
+    ASSERT (0);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // Update the string value.
+  Status = AmlUpdateDataNode (
+             StringDataNode,
+             EAmlNodeDataTypeString,
+             (UINT8*)NewName,
+             (UINT32)AsciiStrLen (NewName) + 1
+             );
+  ASSERT_EFI_ERROR (Status);
+
+  return Status;
+}
+
+/** Get the first Resource Data element contained in a "_CRS" object.
+
+  In the following ASL code, the function will return the Resource Data
+  node corresponding to the "QWordMemory ()" ASL macro.
+  Name (_CRS, ResourceTemplate() {
+      QWordMemory (...) {...},
+      Interrupt (...) {...}
+    }
+  )
+
+  Note:
+   - The "_CRS" object must be declared using ASL "Name (Declare Named Object)".
+   - "_CRS" declared using ASL "Method (Declare Control Method)" is not
+     supported.
+
+  @param  [in] NameOpCrsNode  NameOp object node defining a "_CRS" object.
+                              Must have an OpCode=AML_NAME_OP, SubOpCode=0.
+                              NameOp object nodes are defined in ASL
+                              using the "Name ()" function.
+  @param  [out] OutRdNode     Pointer to the first Resource Data element of
+                              the "_CRS" object. A Resource Data element
+                              is stored in a data node.
+
+  @retval EFI_SUCCESS             The function completed successfully.
+  @retval EFI_INVALID_PARAMETER   Invalid parameter.
+**/
+EFI_STATUS
+EFIAPI
+AmlNameOpCrsGetFirstRdNode (
+  IN  AML_OBJECT_NODE_HANDLE   NameOpCrsNode,
+  OUT AML_DATA_NODE_HANDLE   * OutRdNode
+  )
+{
+  AML_OBJECT_NODE_HANDLE  BufferOpNode;
+  AML_DATA_NODE_HANDLE    FirstRdNode;
+
+  if ((NameOpCrsNode == NULL)                                              ||
+      (AmlGetNodeType ((AML_NODE_HANDLE)NameOpCrsNode) != EAmlNodeObject)  ||
+      (!AmlNodeHasOpCode (NameOpCrsNode, AML_NAME_OP, 0))                  ||
+      (!AmlNameOpCompareName (NameOpCrsNode, "_CRS"))                      ||
+      (OutRdNode == NULL)) {
+    ASSERT (0);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *OutRdNode = NULL;
+
+  // Get the _CRS value which is represented as a BufferOp object node
+  // which is the 2nd fixed argument (i.e. index 1).
+  BufferOpNode = (AML_OBJECT_NODE_HANDLE)AmlGetFixedArgument (
+                                           NameOpCrsNode,
+                                           EAmlParseIndexTerm1
+                                           );
+  if ((BufferOpNode == NULL)                                             ||
+      (AmlGetNodeType ((AML_NODE_HANDLE)BufferOpNode) != EAmlNodeObject) ||
+      (!AmlNodeHasOpCode (BufferOpNode, AML_BUFFER_OP, 0))) {
+    ASSERT (0);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // Get the first Resource data node in the variable list of
+  // argument of the BufferOp node.
+  FirstRdNode = (AML_DATA_NODE_HANDLE)AmlGetNextVariableArgument (
+                                        (AML_NODE_HANDLE)BufferOpNode,
+                                        NULL
+                                        );
+  if ((FirstRdNode == NULL)                                            ||
+      (AmlGetNodeType ((AML_NODE_HANDLE)FirstRdNode) != EAmlNodeData)  ||
+      (!AmlNodeHasDataType (FirstRdNode, EAmlNodeDataTypeResourceData))) {
+    ASSERT (0);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *OutRdNode = FirstRdNode;
+  return EFI_SUCCESS;
+}
+
+/** Get the Resource Data element following the CurrRdNode Resource Data.
+
+  In the following ASL code, if CurrRdNode corresponds to the first
+  "QWordMemory ()" ASL macro, the function will return the Resource Data
+  node corresponding to the "Interrupt ()" ASL macro.
+  Name (_CRS, ResourceTemplate() {
+      QwordMemory (...) {...},
+      Interrupt (...) {...}
+    }
+  )
+
+  The CurrRdNode Resource Data node must be defined in an object named "_CRS"
+  and defined by a "Name ()" ASL function.
+
+  @param  [in]  CurrRdNode   Pointer to the current Resource Data element of
+                             the "_CRS" object.
+  @param  [out] OutRdNode    Pointer to the Resource Data element following
+                             the CurrRdNode.
+                             Contain a NULL pointer if CurrRdNode is the
+                             last Resource Data element in the list.
+                             The "End Tag" is not considered as a resource
+                             data element and is not returned.
+
+  @retval EFI_SUCCESS             The function completed successfully.
+  @retval EFI_INVALID_PARAMETER   Invalid parameter.
+**/
+EFI_STATUS
+EFIAPI
+AmlNameOpCrsGetNextRdNode (
+  IN  AML_DATA_NODE_HANDLE    CurrRdNode,
+  OUT AML_DATA_NODE_HANDLE  * OutRdNode
+  )
+{
+  AML_OBJECT_NODE_HANDLE     NameOpCrsNode;
+  AML_OBJECT_NODE_HANDLE     BufferOpNode;
+
+  if ((CurrRdNode == NULL)                                              ||
+      (AmlGetNodeType ((AML_NODE_HANDLE)CurrRdNode) != EAmlNodeData)    ||
+      (!AmlNodeHasDataType (CurrRdNode, EAmlNodeDataTypeResourceData))  ||
+      (OutRdNode == NULL)) {
+    ASSERT (0);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *OutRdNode = NULL;
+
+  // The parent of the CurrRdNode must be a BufferOp node.
+  BufferOpNode = (AML_OBJECT_NODE_HANDLE)AmlGetParent (
+                                           (AML_NODE_HANDLE)CurrRdNode
+                                           );
+  if ((BufferOpNode == NULL)  ||
+      (!AmlNodeHasOpCode (BufferOpNode, AML_BUFFER_OP, 0))) {
+    ASSERT (0);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // The parent of the BufferOpNode must be a NameOp node.
+  NameOpCrsNode = (AML_OBJECT_NODE_HANDLE)AmlGetParent (
+                                            (AML_NODE_HANDLE)BufferOpNode
+                                            );
+  if ((NameOpCrsNode == NULL)                             ||
+      (!AmlNodeHasOpCode (NameOpCrsNode, AML_NAME_OP, 0)) ||
+      (!AmlNameOpCompareName (NameOpCrsNode, "_CRS"))) {
+    ASSERT (0);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *OutRdNode = (AML_DATA_NODE_HANDLE)AmlGetNextVariableArgument (
+                                       (AML_NODE_HANDLE)BufferOpNode,
+                                       (AML_NODE_HANDLE)CurrRdNode
+                                       );
+
+  // If the Resource Data is an End Tag, return NULL.
+  if (AmlNodeHasRdDataType (
+        *OutRdNode,
+        AML_RD_BUILD_SMALL_DESC_ID (ACPI_SMALL_END_TAG_DESCRIPTOR_NAME))) {
+    *OutRdNode = NULL;
+  }
+
+  return EFI_SUCCESS;
+}
diff --git a/DynamicTablesPkg/Library/Common/AmlLib/Api/AmlApiHelper.c b/DynamicTablesPkg/Library/Common/AmlLib/Api/AmlApiHelper.c
new file mode 100644
index 0000000000000000000000000000000000000000..9693f28b543f2008d17d09031ed3b53577935a5d
--- /dev/null
+++ b/DynamicTablesPkg/Library/Common/AmlLib/Api/AmlApiHelper.c
@@ -0,0 +1,219 @@
+/** @file
+  AML Helper.
+
+  Copyright (c) 2020, Arm Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+/* Even though this file has access to the internal Node definition,
+   i.e. AML_ROOT_NODE, AML_OBJECT_NODE, etc. Only the external node
+   handle types should be used, i.e. AML_NODE_HANDLE, AML_ROOT_NODE_HANDLE,
+   etc.
+   Indeed, the functions in the "Api" folder should be implemented only
+   using the "safe" functions available in the "Include" folder. This
+   makes the functions available in the "Api" folder easy to export.
+*/
+#include <Api/AmlApiHelper.h>
+
+#include <AmlCoreInterface.h>
+#include <AmlInclude.h>
+#include <String/AmlString.h>
+
+/** Compare the NameString defined by the "Name ()" ASL function,
+    and stored in the NameOpNode, with the input NameString.
+
+  An ASL NameString is expected to be NULL terminated, and can be composed
+  of NameSegs that have less that 4 chars, like "DEV". "DEV" will be expanded
+  as "DEV_".
+
+  An AML NameString is not NULL terminated and is is only composed of
+  4 chars long NameSegs.
+
+  @param  [in] NameOpNode   NameOp object node defining a variable.
+                            Must have an AML_NAME_OP/0 OpCode/SubOpCode.
+                            NameOp object nodes are defined in ASL
+                            using the "Name ()" function.
+  @param  [in] AslName      ASL NameString to compare the NameOp's name with.
+                            Must be NULL terminated.
+
+  @retval TRUE If the AslName and the AmlName defined by the NameOp node
+          are similar.
+  @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+AmlNameOpCompareName (
+  IN  AML_OBJECT_NODE_HANDLE    NameOpNode,
+  IN  CHAR8                   * AslName
+  )
+{
+  EFI_STATUS              Status;
+  AML_DATA_NODE_HANDLE    NameDataNode;
+
+  CHAR8                 * AmlName;
+  UINT32                  AmlNameSize;
+
+  BOOLEAN                 RetVal;
+
+  if ((NameOpNode == NULL)                                                ||
+      (AmlGetNodeType ((AML_NODE_HANDLE)NameOpNode) != EAmlNodeObject)    ||
+      (!AmlNodeHasOpCode (NameOpNode, AML_NAME_OP, 0))                    ||
+      (AslName == NULL)) {
+    ASSERT (0);
+    return FALSE;
+  }
+
+  // Get the NameOp name, being in a data node
+  // which is the first fixed argument (i.e. index 0).
+  NameDataNode = (AML_DATA_NODE_HANDLE)AmlGetFixedArgument (
+                                         NameOpNode,
+                                         EAmlParseIndexTerm0
+                                         );
+  if ((NameDataNode == NULL)                                            ||
+      (AmlGetNodeType ((AML_NODE_HANDLE)NameDataNode) != EAmlNodeData)  ||
+      (!AmlNodeHasDataType (NameDataNode, EAmlNodeDataTypeNameString))) {
+    ASSERT (0);
+    return FALSE;
+  }
+
+  // Get the size of the name.
+  Status = AmlGetDataNodeBuffer (NameDataNode, NULL, &AmlNameSize);
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    return FALSE;
+  }
+
+  // Allocate memory to fetch the name.
+  AmlName = AllocateZeroPool (AmlNameSize);
+  if (AmlName == NULL) {
+    ASSERT (0);
+    return FALSE;
+  }
+
+  // Fetch the name.
+  Status = AmlGetDataNodeBuffer (NameDataNode, (UINT8*)AmlName, &AmlNameSize);
+  if (EFI_ERROR (Status)) {
+    FreePool (AmlName);
+    ASSERT (0);
+    return FALSE;
+  }
+
+  // Compare the input AslName and the AmlName stored in the NameOp node.
+  RetVal = CompareAmlWithAslNameString (AmlName, AslName);
+
+  // Free the string buffer.
+  FreePool (AmlName);
+  return RetVal;
+}
+
+/** Check whether ObjectNode has the input OpCode/SubOpcode couple.
+
+  @param  [in]  ObjectNode  Pointer to an object node.
+  @param  [in]  OpCode      OpCode to check
+  @param  [in]  SubOpCode   SubOpCode to check
+
+  @retval TRUE    The node is an object node and
+                  the Opcode and SubOpCode match.
+  @retval FALSE   Otherwise.
+**/
+BOOLEAN
+EFIAPI
+AmlNodeHasOpCode (
+  IN  AML_OBJECT_NODE_HANDLE    ObjectNode,
+  IN  UINT8                     OpCode,
+  IN  UINT8                     SubOpCode
+  )
+{
+  EFI_STATUS    Status;
+  UINT8         NodeOpCode;
+  UINT8         NodeSubOpCode;
+
+  // Get the Node information.
+  Status = AmlGetObjectNodeInfo (
+             ObjectNode,
+             &NodeOpCode,
+             &NodeSubOpCode,
+             NULL,
+             NULL
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    return FALSE;
+  }
+
+  // Check the OpCode and SubOpCode.
+  if ((OpCode != NodeOpCode)  ||
+      (SubOpCode != NodeSubOpCode)) {
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+/** Check whether DataNode has the input DataType.
+
+  @param  [in]  DataNode   Pointer to a data node.
+  @param  [in]  DataType   DataType to check.
+
+  @retval TRUE    The node is a data node and
+                  the DataType match.
+  @retval FALSE   Otherwise.
+**/
+BOOLEAN
+EFIAPI
+AmlNodeHasDataType (
+  IN  AML_DATA_NODE_HANDLE    DataNode,
+  IN  EAML_NODE_DATA_TYPE     DataType
+  )
+{
+  EFI_STATUS            Status;
+  EAML_NODE_DATA_TYPE   NodeDataType;
+
+  // Get the data type.
+  Status = AmlGetNodeDataType (DataNode, &NodeDataType);
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    return FALSE;
+  }
+
+  // Check the data type.
+  if (NodeDataType != DataType) {
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+/** Check whether RdNode has the input RdDataType.
+
+  @param  [in]  RdNode      Pointer to a data node.
+  @param  [in]  RdDataType  DataType to check.
+
+  @retval TRUE    The node is a Resource Data node and
+                  the RdDataType match.
+  @retval FALSE   Otherwise.
+**/
+BOOLEAN
+EFIAPI
+AmlNodeHasRdDataType (
+  IN  AML_DATA_NODE_HANDLE    RdNode,
+  IN  AML_RD_HEADER           RdDataType
+  )
+{
+  EFI_STATUS      Status;
+  AML_RD_HEADER   NodeRdDataType;
+
+  // Get the resource data type.
+  Status = AmlGetResourceDataType (
+             RdNode,
+             &NodeRdDataType
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    return FALSE;
+  }
+
+  // Check the RdDataType.
+  return AmlRdCompareDescId (&NodeRdDataType, RdDataType);
+}
diff --git a/DynamicTablesPkg/Library/Common/AmlLib/Api/AmlApiHelper.h b/DynamicTablesPkg/Library/Common/AmlLib/Api/AmlApiHelper.h
new file mode 100644
index 0000000000000000000000000000000000000000..9872adddc36739559c86268564483480a6d65294
--- /dev/null
+++ b/DynamicTablesPkg/Library/Common/AmlLib/Api/AmlApiHelper.h
@@ -0,0 +1,93 @@
+/** @file
+  AML Helper.
+
+  Copyright (c) 2020, Arm Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef AML_HELPER_H_
+#define AML_HELPER_H_
+
+#include <AmlNodeDefines.h>
+#include <ResourceData/AmlResourceData.h>
+
+/** Compare the NameString defined by the "Name ()" ASL function,
+    and stored in the NameOpNode, with the input NameString.
+
+  An ASL NameString is expected to be NULL terminated, and can be composed
+  of NameSegs that have less that 4 chars, like "DEV". "DEV" will be expanded
+  as "DEV_".
+
+  An AML NameString is not NULL terminated and is is only composed of
+  4 chars long NameSegs.
+
+  @param  [in] NameOpNode   NameOp object node defining a variable.
+                            Must have an AML_NAME_OP/0 OpCode/SubOpCode.
+                            NameOp object nodes are defined in ASL
+                            using the "Name ()" function.
+  @param  [in] AslName      ASL NameString to compare the NameOp's name with.
+                            Must be NULL terminated.
+
+  @retval TRUE If the AslName and the AmlName defined by the NameOp node
+          are similar.
+  @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+AmlNameOpCompareName (
+  IN  AML_OBJECT_NODE_HANDLE    NameOpNode,
+  IN  CHAR8                   * AslName
+  );
+
+/** Check whether ObjectNode has the input OpCode/SubOpcode couple.
+
+  @param  [in]  ObjectNode  Pointer to an object node.
+  @param  [in]  OpCode      OpCode to check
+  @param  [in]  SubOpCode   SubOpCode to check
+
+  @retval TRUE    The node is an object node and
+                  the Opcode and SubOpCode match.
+  @retval FALSE   Otherwise.
+**/
+BOOLEAN
+EFIAPI
+AmlNodeHasOpCode (
+  IN  AML_OBJECT_NODE_HANDLE    ObjectNode,
+  IN  UINT8                     OpCode,
+  IN  UINT8                     SubOpCode
+  );
+
+/** Check whether DataNode has the input DataType.
+
+  @param  [in]  DataNode   Pointer to a data node.
+  @param  [in]  DataType   DataType to check.
+
+  @retval TRUE    The node is a data node and
+                  the DataType match.
+  @retval FALSE   Otherwise.
+**/
+BOOLEAN
+EFIAPI
+AmlNodeHasDataType (
+  IN  AML_DATA_NODE_HANDLE    DataNode,
+  IN  EAML_NODE_DATA_TYPE     DataType
+  );
+
+/** Check whether RdNode has the input RdDataType.
+
+  @param  [in]  RdNode      Pointer to a data node.
+  @param  [in]  RdDataType  DataType to check.
+
+  @retval TRUE    The node is a Resource Data node and
+                  the RdDataType match.
+  @retval FALSE   Otherwise.
+**/
+BOOLEAN
+EFIAPI
+AmlNodeHasRdDataType (
+  IN  AML_DATA_NODE_HANDLE    RdNode,
+  IN  AML_RD_HEADER           RdDataType
+  );
+
+#endif // AML_HELPER_H_
diff --git a/DynamicTablesPkg/Library/Common/AmlLib/Api/AmlResourceDataApi.c b/DynamicTablesPkg/Library/Common/AmlLib/Api/AmlResourceDataApi.c
new file mode 100644
index 0000000000000000000000000000000000000000..913c8dcdb0c04d7180a0732cfc6c5f495105f8e9
--- /dev/null
+++ b/DynamicTablesPkg/Library/Common/AmlLib/Api/AmlResourceDataApi.c
@@ -0,0 +1,320 @@
+/** @file
+  AML Update Resource Data.
+
+  Copyright (c) 2020, Arm Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+/* Even though this file has access to the internal Node definition,
+   i.e. AML_ROOT_NODE, AML_OBJECT_NODE, etc. Only the external node
+   handle types should be used, i.e. AML_NODE_HANDLE, AML_ROOT_NODE_HANDLE,
+   etc.
+   Indeed, the functions in the "Api" folder should be implemented only
+   using the "safe" functions available in the "Include" folder. This
+   makes the functions available in the "Api" folder easy to export.
+*/
+#include <AmlNodeDefines.h>
+
+#include <AmlCoreInterface.h>
+#include <AmlInclude.h>
+#include <Api/AmlApiHelper.h>
+#include <CodeGen/AmlResourceDataCodeGen.h>
+
+/** Update the first interrupt of an Interrupt resource data node.
+
+  The flags of the Interrupt resource data are left unchanged.
+
+  The InterruptRdNode corresponds to the Resource Data created by the
+  "Interrupt ()" ASL macro. It is an Extended Interrupt Resource Data.
+  See ACPI 6.3 specification, s6.4.3.6 "Extended Interrupt Descriptor"
+  for more information about Extended Interrupt Resource Data.
+
+  @param  [in]  InterruptRdNode   Pointer to the an extended interrupt
+                                  resource data node.
+  @param  [in]  Irq               Interrupt value to update.
+
+  @retval  EFI_SUCCESS            The function completed successfully.
+  @retval  EFI_INVALID_PARAMETER  Invalid parameter.
+  @retval  EFI_OUT_OF_RESOURCES   Out of resources.
+**/
+EFI_STATUS
+EFIAPI
+AmlUpdateRdInterrupt (
+  IN  AML_DATA_NODE_HANDLE    InterruptRdNode,
+  IN  UINT32                  Irq
+  )
+{
+  EFI_STATUS                    Status;
+  UINT32                      * FirstInterrupt;
+  UINT8                       * QueryBuffer;
+  UINT32                        QueryBufferSize;
+
+  if ((InterruptRdNode == NULL)                                           ||
+      (AmlGetNodeType ((AML_NODE_HANDLE)InterruptRdNode) != EAmlNodeData) ||
+      (!AmlNodeHasDataType (
+          InterruptRdNode,
+          EAmlNodeDataTypeResourceData))                                  ||
+      (!AmlNodeHasRdDataType (
+          InterruptRdNode,
+          AML_RD_BUILD_LARGE_DESC_ID (
+            ACPI_LARGE_EXTENDED_IRQ_DESCRIPTOR_NAME)))) {
+    ASSERT (0);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  QueryBuffer = NULL;
+
+  // Get the size of the InterruptRdNode buffer.
+  Status = AmlGetDataNodeBuffer (
+             InterruptRdNode,
+             NULL,
+             &QueryBufferSize
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    return Status;
+  }
+
+  // Check the Buffer is large enough.
+  if (QueryBufferSize < sizeof (EFI_ACPI_EXTENDED_INTERRUPT_DESCRIPTOR)) {
+    ASSERT (0);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // Allocate a buffer to fetch the data.
+  QueryBuffer = AllocatePool (QueryBufferSize);
+  if (QueryBuffer == NULL) {
+    ASSERT (0);
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  // Get the data.
+  Status = AmlGetDataNodeBuffer (
+             InterruptRdNode,
+             QueryBuffer,
+             &QueryBufferSize
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler;
+  }
+
+  // Get the address of the first interrupt field.
+  FirstInterrupt =
+    ((EFI_ACPI_EXTENDED_INTERRUPT_DESCRIPTOR*)QueryBuffer)->InterruptNumber;
+
+  *FirstInterrupt = Irq;
+
+  // Update the InterruptRdNode buffer.
+  Status = AmlUpdateDataNode (
+             InterruptRdNode,
+             EAmlNodeDataTypeResourceData,
+             QueryBuffer,
+             QueryBufferSize
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+  }
+
+error_handler:
+  if (QueryBuffer != NULL) {
+    FreePool (QueryBuffer);
+  }
+  return Status;
+}
+
+/** Update the interrupt list of an interrupt resource data node.
+
+  The InterruptRdNode corresponds to the Resource Data created by the
+  "Interrupt ()" ASL function. It is an Extended Interrupt Resource Data.
+  See ACPI 6.3 specification, s6.4.3.6 "Extended Interrupt Descriptor"
+  for more information about Extended Interrupt Resource Data.
+
+  @param  [in]  InterruptRdNode   Pointer to the an extended interrupt
+                                  resource data node.
+  @param  [in]  ResourceConsumer    The device consumes the specified interrupt
+                                    or produces it for use by a child device.
+  @param  [in]  EdgeTriggered       The interrupt is edge triggered or
+                                    level triggered.
+  @param  [in]  ActiveLow           The interrupt is active-high or active-low.
+  @param  [in]  Shared              The interrupt can be shared with other
+                                    devices or not (Exclusive).
+  @param  [in]  IrqList           Interrupt list. Must be non-NULL.
+  @param  [in]  IrqCount          Interrupt count. Must be non-zero.
+
+
+  @retval  EFI_SUCCESS            The function completed successfully.
+  @retval  EFI_INVALID_PARAMETER  Invalid parameter.
+  @retval  EFI_OUT_OF_RESOURCES   Out of resources.
+**/
+EFI_STATUS
+EFIAPI
+AmlUpdateRdInterruptEx (
+  IN  AML_DATA_NODE_HANDLE    InterruptRdNode,
+  IN  BOOLEAN                 ResourceConsumer,
+  IN  BOOLEAN                 EdgeTriggered,
+  IN  BOOLEAN                 ActiveLow,
+  IN  BOOLEAN                 Shared,
+  IN  UINT32                * IrqList,
+  IN  UINT8                   IrqCount
+  )
+{
+  EFI_STATUS                                 Status;
+
+  EFI_ACPI_EXTENDED_INTERRUPT_DESCRIPTOR   * RdInterrupt;
+  UINT32                                   * FirstInterrupt;
+  UINT8                                    * UpdateBuffer;
+  UINT16                                     UpdateBufferSize;
+
+  if ((InterruptRdNode == NULL)                                              ||
+      (AmlGetNodeType ((AML_NODE_HANDLE)InterruptRdNode) != EAmlNodeData)    ||
+      (!AmlNodeHasDataType (
+          InterruptRdNode,
+          EAmlNodeDataTypeResourceData))                                     ||
+      (!AmlNodeHasRdDataType (
+          InterruptRdNode,
+          AML_RD_BUILD_LARGE_DESC_ID (
+            ACPI_LARGE_EXTENDED_IRQ_DESCRIPTOR_NAME)))                       ||
+      (IrqList == NULL)                                                      ||
+      (IrqCount == 0)) {
+    ASSERT (0);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  UpdateBuffer = NULL;
+  UpdateBufferSize = sizeof (EFI_ACPI_EXTENDED_INTERRUPT_DESCRIPTOR) +
+                       ((IrqCount - 1) * sizeof (UINT32));
+
+  // Allocate a buffer to update the data.
+  UpdateBuffer = AllocatePool (UpdateBufferSize);
+  if (UpdateBuffer == NULL) {
+    ASSERT (0);
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  // Update the Resource Data information (structure size, interrupt count).
+  RdInterrupt = (EFI_ACPI_EXTENDED_INTERRUPT_DESCRIPTOR*)UpdateBuffer;
+  RdInterrupt->Header.Header.Byte =
+     AML_RD_BUILD_LARGE_DESC_ID (ACPI_LARGE_EXTENDED_IRQ_DESCRIPTOR_NAME);
+  RdInterrupt->Header.Length =
+    UpdateBufferSize - sizeof (ACPI_LARGE_RESOURCE_HEADER);
+  RdInterrupt->InterruptTableLength = IrqCount;
+  RdInterrupt->InterruptVectorFlags = (ResourceConsumer ? BIT0 : 0) |
+                                      (EdgeTriggered ? BIT1 : 0)    |
+                                      (ActiveLow ? BIT2 : 0)        |
+                                      (Shared ? BIT3 : 0);
+
+  // Get the address of the first interrupt field.
+  FirstInterrupt =
+    ((EFI_ACPI_EXTENDED_INTERRUPT_DESCRIPTOR*)UpdateBuffer)->InterruptNumber;
+
+  // Copy the input list of interrupts.
+  CopyMem (FirstInterrupt, IrqList, (sizeof (UINT32) * IrqCount));
+
+  // Update the InterruptRdNode buffer.
+  Status = AmlUpdateDataNode (
+             InterruptRdNode,
+             EAmlNodeDataTypeResourceData,
+             UpdateBuffer,
+             UpdateBufferSize
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+  }
+
+  // Cleanup
+  FreePool (UpdateBuffer);
+
+  return Status;
+}
+
+/** Update the base address and length of a QWord resource data node.
+
+  @param  [in] QWordRdNode         Pointer a QWord resource data
+                                   node.
+  @param  [in] BaseAddress         Base address.
+  @param  [in] BaseAddressLength   Base address length.
+
+  @retval  EFI_SUCCESS            The function completed successfully.
+  @retval  EFI_INVALID_PARAMETER  Invalid parameter.
+  @retval  EFI_OUT_OF_RESOURCES   Out of resources.
+**/
+EFI_STATUS
+EFIAPI
+AmlUpdateRdQWord (
+  IN  AML_DATA_NODE_HANDLE  QWordRdNode,
+  IN  UINT64                BaseAddress,
+  IN  UINT64                BaseAddressLength
+  )
+{
+  EFI_STATUS                                 Status;
+  EFI_ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR  * RdQWord;
+
+  UINT8                                    * QueryBuffer;
+  UINT32                                     QueryBufferSize;
+
+  if ((QWordRdNode == NULL)                                             ||
+      (AmlGetNodeType ((AML_NODE_HANDLE)QWordRdNode) != EAmlNodeData)   ||
+      (!AmlNodeHasDataType (QWordRdNode, EAmlNodeDataTypeResourceData)) ||
+      (!AmlNodeHasRdDataType (
+          QWordRdNode,
+          AML_RD_BUILD_LARGE_DESC_ID (
+            ACPI_LARGE_QWORD_ADDRESS_SPACE_DESCRIPTOR_NAME)))) {
+    ASSERT (0);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // Get the size of the QWordRdNode's buffer.
+  Status = AmlGetDataNodeBuffer (
+             QWordRdNode,
+             NULL,
+             &QueryBufferSize
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    return Status;
+  }
+
+  // Allocate a buffer to fetch the data.
+  QueryBuffer = AllocatePool (QueryBufferSize);
+  if (QueryBuffer == NULL) {
+    ASSERT (0);
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  // Get the data.
+  Status = AmlGetDataNodeBuffer (
+             QWordRdNode,
+             QueryBuffer,
+             &QueryBufferSize
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+    goto error_handler;
+  }
+
+  RdQWord = (EFI_ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR*)QueryBuffer;
+
+  // Update the Base Address and Length.
+  RdQWord->AddrRangeMin = BaseAddress;
+  RdQWord->AddrRangeMax = BaseAddress + BaseAddressLength - 1;
+  RdQWord->AddrLen = BaseAddressLength;
+
+  // Update Base Address Resource Data node.
+  Status = AmlUpdateDataNode (
+             QWordRdNode,
+             EAmlNodeDataTypeResourceData,
+             QueryBuffer,
+             QueryBufferSize
+             );
+  if (EFI_ERROR (Status)) {
+    ASSERT (0);
+  }
+
+error_handler:
+  if (QueryBuffer != NULL) {
+    FreePool (QueryBuffer);
+  }
+  return Status;
+}
-- 
'Guid(CE165669-3EF3-493F-B85D-6190EE5B9759)'


  parent reply	other threads:[~2020-08-12 15:23 UTC|newest]

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-08-12 15:22 [PATCH v1 00/30] Add Dynamic AML generation support Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 01/30] DynamicTablesPkg: Introduction to Dynamic AML Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 02/30] DynamicTablesPkg: AmlLib definitions Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 03/30] DynamicTablesPkg: AML grammar definition Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 04/30] DynamicTablesPkg: AML node definitions Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 05/30] DynamicTablesPkg: AML tree interface Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 06/30] DynamicTablesPkg: AML tree enumerator Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 07/30] DynamicTablesPkg: AML tree traversal Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 08/30] DynamicTablesPkg: AML tree iterator Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 09/30] DynamicTablesPkg: AML tree/node cloning Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 10/30] DynamicTablesPkg: AML utility interfaces Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 11/30] DynamicTablesPkg: AML and ASL string helper Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 12/30] DynamicTablesPkg: AML stream interface Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 13/30] DynamicTablesPkg: AML serialise interface Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 14/30] DynamicTablesPkg: AML debug logging Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 15/30] DynamicTablesPkg: AML ACPI Namespace interface Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 16/30] DynamicTablesPkg: AML Parser Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 17/30] DynamicTablesPkg: AML resource data helper Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 18/30] DynamicTablesPkg: AML resource data parser Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 19/30] DynamicTablesPkg: AML Method parser Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 20/30] DynamicTablesPkg: AML Field list parser Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 21/30] DynamicTablesPkg: AML Codegen Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 22/30] DynamicTablesPkg: AML Resource Data Codegen Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 23/30] DynamicTablesPkg: AML Core interface Sami Mujawar
2020-08-12 15:22 ` Sami Mujawar [this message]
2020-08-12 15:22 ` [PATCH v1 25/30] DynamicTablesPkg: Dynamic AML: Add AmlLib library Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 26/30] DynamicTablesPkg: Add AsciiFromHex helper function Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 27/30] DynamicTablesPkg: SSDT Serial Port Fixup library Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 28/30] DynamicTablesPkg: SSDT Serial Port generator Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 29/30] DynamicTablesPkg: Add SSDT Serial port for SPCR Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 30/30] DynamicTablesPkg: Add SSDT Serial port for DBG2 Sami Mujawar
2020-08-13 15:16 ` [edk2-devel] [PATCH v1 00/30] Add Dynamic AML generation support Alexei Fedorov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200812152236.31164-25-sami.mujawar@arm.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox