summaryrefslogtreecommitdiffstats
path: root/DynamicTablesPkg
diff options
context:
space:
mode:
authorPierre Gondois <pierre.gondois@arm.com>2020-08-05 15:43:33 +0100
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>2020-08-13 18:00:06 +0000
commitc85ac5245c0c47836fb9b599caff0b949066a412 (patch)
tree471c141145185ee96e7037838e214b408d3d7fd7 /DynamicTablesPkg
parent3196253710a1ed56b4dc04a728d33961ec7542c8 (diff)
downloadedk2-c85ac5245c0c47836fb9b599caff0b949066a412.tar.gz
edk2-c85ac5245c0c47836fb9b599caff0b949066a412.tar.bz2
edk2-c85ac5245c0c47836fb9b599caff0b949066a412.zip
DynamicTablesPkg: AmlLib APIs
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>
Diffstat (limited to 'DynamicTablesPkg')
-rw-r--r--DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h631
-rw-r--r--DynamicTablesPkg/Library/Common/AmlLib/Api/AmlApi.c382
-rw-r--r--DynamicTablesPkg/Library/Common/AmlLib/Api/AmlApiHelper.c219
-rw-r--r--DynamicTablesPkg/Library/Common/AmlLib/Api/AmlApiHelper.h93
-rw-r--r--DynamicTablesPkg/Library/Common/AmlLib/Api/AmlResourceDataApi.c320
5 files changed, 1645 insertions, 0 deletions
diff --git a/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h b/DynamicTablesPkg/Include/Library/AmlLib/AmlLib.h
new file mode 100644
index 0000000000..1dcb938614
--- /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 0000000000..fdf04acc62
--- /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 0000000000..9693f28b54
--- /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 0000000000..9872adddc3
--- /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 0000000000..913c8dcdb0
--- /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;
+}