]> git.proxmox.com Git - mirror_edk2.git/commitdiff
DynamicTablesPkg: AmlLib APIs
authorPierre Gondois <pierre.gondois@arm.com>
Wed, 5 Aug 2020 14:43:33 +0000 (15:43 +0100)
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Thu, 13 Aug 2020 18:00:06 +0000 (18:00 +0000)
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>
Reviewed-by: Alexei Fedorov <Alexei.Fedorov@arm.com>
DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h [new file with mode: 0644]
DynamicTablesPkg/Library/Common/AmlLib/Api/AmlApi.c [new file with mode: 0644]
DynamicTablesPkg/Library/Common/AmlLib/Api/AmlApiHelper.c [new file with mode: 0644]
DynamicTablesPkg/Library/Common/AmlLib/Api/AmlApiHelper.h [new file with mode: 0644]
DynamicTablesPkg/Library/Common/AmlLib/Api/AmlResourceDataApi.c [new file with mode: 0644]

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