--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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