--- /dev/null
+/** @file\r
+ AML Node Definition.\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_NODE_DEFINES_H_\r
+#define AML_NODE_DEFINES_H_\r
+\r
+#include <AmlEncoding/Aml.h>\r
+#include <IndustryStandard/Acpi.h>\r
+\r
+/** AML header node.\r
+\r
+ This abstract class represents either a root/object/data node.\r
+ All the enumerated nodes have this same common header.\r
+*/\r
+typedef struct AmlNodeHeader {\r
+ /// This must be the first field in this structure.\r
+ LIST_ENTRY Link;\r
+\r
+ /// Parent of this node. NULL for the root node.\r
+ struct AmlNodeHeader * Parent;\r
+\r
+ /// Node type allowing to identify a root/object/data node.\r
+ EAML_NODE_TYPE NodeType;\r
+} AML_NODE_HEADER;\r
+\r
+/** Node handle.\r
+*/\r
+typedef AML_NODE_HEADER* AML_NODE_HANDLE;\r
+\r
+/** AML root node.\r
+\r
+ The root node is unique and at the head of of tree. It is a fake node used\r
+ to maintain the list of AML statements (stored as object nodes) which are\r
+ at the first scope level.\r
+*/\r
+typedef struct AmlRootNode {\r
+ /// Header information. Must be the first field of the struct.\r
+ AML_NODE_HEADER NodeHeader;\r
+\r
+ /// List of object nodes being at the first scope level.\r
+ /// These are children and can only be object nodes.\r
+ LIST_ENTRY VariableArgs;\r
+\r
+ /// ACPI DSDT/SSDT header.\r
+ EFI_ACPI_DESCRIPTION_HEADER * SdtHeader;\r
+} AML_ROOT_NODE;\r
+\r
+/** Root Node handle.\r
+*/\r
+typedef AML_ROOT_NODE* AML_ROOT_NODE_HANDLE;\r
+\r
+/** AML object node.\r
+\r
+ Object nodes match AML statements. They are associated with an\r
+ OpCode/SubOpCode, and can have children.\r
+*/\r
+typedef struct AmlObjectNode {\r
+ /// Header information. Must be the first field of the struct.\r
+ AML_NODE_HEADER NodeHeader;\r
+\r
+ /// Some object nodes have a variable list of arguments.\r
+ /// These are children and can only be object/data nodes.\r
+ /// Cf ACPI specification, s20.3.\r
+ LIST_ENTRY VariableArgs;\r
+\r
+ /// Fixed arguments of this object node.\r
+ /// These are children and can be object/data nodes.\r
+ /// Cf ACPI specification, s20.3.\r
+ AML_NODE_HEADER * FixedArgs[EAmlParseIndexMax];\r
+\r
+ /// AML byte encoding. Stores the encoding information:\r
+ /// (OpCode/SubOpCode/number of fixed arguments/ attributes).\r
+ CONST AML_BYTE_ENCODING * AmlByteEncoding;\r
+\r
+ /// Some nodes have a PkgLen following their OpCode/SubOpCode in the\r
+ /// AML bytestream. This field stores the decoded value of the PkgLen.\r
+ UINT32 PkgLen;\r
+} AML_OBJECT_NODE;\r
+\r
+/** Object Node handle.\r
+*/\r
+typedef AML_OBJECT_NODE* AML_OBJECT_NODE_HANDLE;\r
+\r
+/** AML data node.\r
+\r
+ Data nodes store the smallest pieces of information.\r
+ E.g.: UINT8, UINT64, NULL terminated string, etc.\r
+ Data node don't have children nodes.\r
+*/\r
+typedef struct AmlDataNode {\r
+ /// Header information. Must be the first field of the struct.\r
+ AML_NODE_HEADER NodeHeader;\r
+\r
+ /// Tag identifying what data is stored in this node.\r
+ /// E.g. UINT, NULL terminated string, resource data element, etc.\r
+ EAML_NODE_DATA_TYPE DataType;\r
+\r
+ /// Buffer containing the data stored by this node.\r
+ UINT8 * Buffer;\r
+\r
+ /// Size of the Buffer.\r
+ UINT32 Size;\r
+} AML_DATA_NODE;\r
+\r
+/** Data Node handle.\r
+*/\r
+typedef AML_DATA_NODE* AML_DATA_NODE_HANDLE;\r
+\r
+/** Check whether a Node has a valid NodeType.\r
+\r
+ @param [in] Node The node to check.\r
+\r
+ @retval TRUE The Node has a valid NodeType.\r
+ @retval FALSE Otherwise.\r
+*/\r
+#define IS_AML_NODE_VALID(Node) \\r
+ ((Node != NULL) && \\r
+ ((((CONST AML_NODE_HEADER*)Node)->NodeType > EAmlNodeUnknown) || \\r
+ (((CONST AML_NODE_HEADER*)Node)->NodeType < EAmlNodeMax)))\r
+\r
+/** Check whether a Node is a root node.\r
+\r
+ @param [in] Node The node to check.\r
+\r
+ @retval TRUE The Node is a root node.\r
+ @retval FALSE Otherwise.\r
+*/\r
+#define IS_AML_ROOT_NODE(Node) \\r
+ ((Node != NULL) && \\r
+ (((CONST AML_NODE_HEADER*)Node)->NodeType == EAmlNodeRoot))\r
+\r
+/** Check whether a Node is an object node.\r
+\r
+ @param [in] Node The node to check.\r
+\r
+ @retval TRUE The Node is an object node.\r
+ @retval FALSE Otherwise.\r
+*/\r
+#define IS_AML_OBJECT_NODE(Node) \\r
+ ((Node != NULL) && \\r
+ (((CONST AML_NODE_HEADER*)Node)->NodeType == EAmlNodeObject))\r
+\r
+/** Check whether a Node is a data node.\r
+\r
+ @param [in] Node The node to check.\r
+\r
+ @retval TRUE The Node is a data node.\r
+ @retval FALSE Otherwise.\r
+*/\r
+#define IS_AML_DATA_NODE(Node) \\r
+ ((Node != NULL) && \\r
+ (((CONST AML_NODE_HEADER*)Node)->NodeType == EAmlNodeData))\r
+\r
+/** Check whether a Node has a parent.\r
+\r
+ @param [in] Node The node to check.\r
+\r
+ @retval TRUE The Node is a data node.\r
+ @retval FALSE Otherwise.\r
+*/\r
+#define AML_NODE_HAS_PARENT(Node) \\r
+ (IS_AML_NODE_VALID (Node) && \\r
+ (((CONST AML_NODE_HEADER*)Node)->Parent != NULL))\r
+\r
+/** Check that the Node is not attached somewhere.\r
+ This doesn't mean the node cannot have children.\r
+\r
+ @param [in] Node The node to check.\r
+\r
+ @retval TRUE The Node has been detached.\r
+ @retval FALSE Otherwise.\r
+*/\r
+#define AML_NODE_IS_DETACHED(Node) \\r
+ (IS_AML_NODE_VALID (Node) && \\r
+ IsListEmpty ((CONST LIST_ENTRY*)Node) && \\r
+ (((CONST AML_NODE_HEADER*)Node)->Parent == NULL))\r
+\r
+#endif // AML_NODE_DEFINES_H_\r
--- /dev/null
+/** @file\r
+ AML Node.\r
+\r
+ Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>\r
+\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+**/\r
+\r
+#include <Tree/AmlNode.h>\r
+\r
+#include <AmlCoreInterface.h>\r
+#include <Tree/AmlTree.h>\r
+\r
+/** Initialize an AML_NODE_HEADER structure.\r
+\r
+ @param [in] Node Pointer to a node header.\r
+ @param [in] NodeType NodeType to initialize the Node with.\r
+ Must be an EAML_NODE_TYPE.\r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+ @retval EFI_INVALID_PARAMETER Invalid parameter.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+AmlInitializeNodeHeader (\r
+ IN AML_NODE_HEADER * Node,\r
+ IN EAML_NODE_TYPE NodeType\r
+ )\r
+{\r
+ if (Node == NULL) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ InitializeListHead (&Node->Link);\r
+\r
+ Node->Parent = NULL;\r
+ Node->NodeType = NodeType;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/** Delete a root node and its ACPI DSDT/SSDT header.\r
+\r
+ It is the caller's responsibility to check the RootNode has been removed\r
+ from the tree and is not referencing any other node in the tree.\r
+\r
+ @param [in] RootNode Pointer to a root node.\r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+ @retval EFI_INVALID_PARAMETER Invalid parameter.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+AmlDeleteRootNode (\r
+ IN AML_ROOT_NODE * RootNode\r
+ )\r
+{\r
+ if (!IS_AML_ROOT_NODE (RootNode)) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((RootNode->SdtHeader != NULL)) {\r
+ FreePool (RootNode->SdtHeader);\r
+ } else {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ FreePool (RootNode);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/** Create an AML_ROOT_NODE.\r
+ This node will be the root of the tree.\r
+\r
+ @param [in] SdtHeader Pointer to an ACPI DSDT/SSDT header to copy\r
+ the data from.\r
+ @param [out] NewRootNodePtr The created AML_ROOT_NODE.\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
+AmlCreateRootNode (\r
+ IN CONST EFI_ACPI_DESCRIPTION_HEADER * SdtHeader,\r
+ OUT AML_ROOT_NODE ** NewRootNodePtr\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ AML_ROOT_NODE * RootNode;\r
+\r
+ if ((SdtHeader == NULL) ||\r
+ (NewRootNodePtr == NULL)) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ RootNode = AllocateZeroPool (sizeof (AML_ROOT_NODE));\r
+ if (RootNode == NULL) {\r
+ ASSERT (0);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Status = AmlInitializeNodeHeader (&RootNode->NodeHeader, EAmlNodeRoot);\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (RootNode);\r
+ ASSERT (0);\r
+ return Status;\r
+ }\r
+\r
+ InitializeListHead (&RootNode->VariableArgs);\r
+\r
+ RootNode->SdtHeader = AllocateCopyPool (\r
+ sizeof (EFI_ACPI_DESCRIPTION_HEADER),\r
+ SdtHeader\r
+ );\r
+ if (RootNode->SdtHeader == NULL) {\r
+ ASSERT (0);\r
+ AmlDeleteRootNode (RootNode);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ *NewRootNodePtr = RootNode;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/** Delete an object node.\r
+\r
+ It is the caller's responsibility to check the ObjectNode has been removed\r
+ from the tree and is not referencing any other node in the tree.\r
+\r
+ @param [in] ObjectNode Pointer to an object node.\r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+ @retval EFI_INVALID_PARAMETER Invalid parameter.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+AmlDeleteObjectNode (\r
+ IN AML_OBJECT_NODE * ObjectNode\r
+ )\r
+{\r
+ if (!IS_AML_OBJECT_NODE (ObjectNode)) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ FreePool (ObjectNode);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/** Create an AML_OBJECT_NODE.\r
+\r
+ @param [in] AmlByteEncoding Byte encoding entry.\r
+ @param [in] PkgLength PkgLength of the node if the AmlByteEncoding\r
+ has the PkgLen attribute.\r
+ 0 otherwise.\r
+ @param [out] NewObjectNodePtr The created AML_OBJECT_NODE.\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
+AmlCreateObjectNode (\r
+ IN CONST AML_BYTE_ENCODING * AmlByteEncoding,\r
+ IN UINT32 PkgLength,\r
+ OUT AML_OBJECT_NODE ** NewObjectNodePtr\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ AML_OBJECT_NODE * ObjectNode;\r
+\r
+ if ((AmlByteEncoding == NULL) ||\r
+ (NewObjectNodePtr == NULL)) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ ObjectNode = AllocateZeroPool (sizeof (AML_OBJECT_NODE));\r
+ if (ObjectNode == NULL) {\r
+ ASSERT (0);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Status = AmlInitializeNodeHeader (&ObjectNode->NodeHeader, EAmlNodeObject);\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (ObjectNode);\r
+ ASSERT (0);\r
+ return Status;\r
+ }\r
+\r
+ InitializeListHead (&ObjectNode->VariableArgs);\r
+\r
+ // ObjectNode->FixedArgs[...] is already initialised to NULL as the\r
+ // ObjectNode is Zero allocated.\r
+ ObjectNode->AmlByteEncoding = AmlByteEncoding;\r
+ ObjectNode->PkgLen = PkgLength;\r
+\r
+ *NewObjectNodePtr = ObjectNode;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/** Delete a data node and its buffer.\r
+\r
+ It is the caller's responsibility to check the DataNode has been removed\r
+ from the tree and is not referencing any other node in the tree.\r
+\r
+ @param [in] DataNode Pointer to a data node.\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
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+AmlDeleteDataNode (\r
+ IN AML_DATA_NODE * DataNode\r
+ )\r
+{\r
+ if (!IS_AML_DATA_NODE (DataNode)) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (DataNode->Buffer != NULL) {\r
+ FreePool (DataNode->Buffer);\r
+ } else {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ FreePool (DataNode);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/** Create an AML_DATA_NODE.\r
+\r
+ @param [in] DataType DataType of the node.\r
+ @param [in] Data Pointer to the AML bytecode corresponding to\r
+ this node. Data is copied from there.\r
+ @param [in] DataSize Number of bytes to consider at the address\r
+ pointed by Data.\r
+ @param [out] NewDataNodePtr The created AML_DATA_NODE.\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
+AmlCreateDataNode (\r
+ IN EAML_NODE_DATA_TYPE DataType,\r
+ IN CONST UINT8 * Data,\r
+ IN UINT32 DataSize,\r
+ OUT AML_DATA_NODE ** NewDataNodePtr\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ AML_DATA_NODE * DataNode;\r
+\r
+ // A data node must not be created for certain data types.\r
+ if ((DataType == EAmlNodeDataTypeNone) ||\r
+ (DataType == EAmlNodeDataTypeReserved1) ||\r
+ (DataType == EAmlNodeDataTypeReserved2) ||\r
+ (DataType == EAmlNodeDataTypeReserved3) ||\r
+ (DataType == EAmlNodeDataTypeReserved4) ||\r
+ (DataType == EAmlNodeDataTypeReserved5) ||\r
+ (Data == NULL) ||\r
+ (DataSize == 0) ||\r
+ (NewDataNodePtr == NULL)) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ DataNode = AllocateZeroPool (sizeof (AML_DATA_NODE));\r
+ if (DataNode == NULL) {\r
+ ASSERT (0);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Status = AmlInitializeNodeHeader (&DataNode->NodeHeader, EAmlNodeData);\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (DataNode);\r
+ ASSERT (0);\r
+ return Status;\r
+ }\r
+\r
+ DataNode->Buffer = AllocateCopyPool (DataSize, Data);\r
+ if (DataNode->Buffer == NULL) {\r
+ AmlDeleteDataNode (DataNode);\r
+ ASSERT (0);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ DataNode->DataType = DataType;\r
+ DataNode->Size = DataSize;\r
+\r
+ *NewDataNodePtr = DataNode;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/** Delete a Node.\r
+\r
+ @param [in] Node Pointer to a Node.\r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+ @retval EFI_INVALID_PARAMETER Invalid parameter.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AmlDeleteNode (\r
+ IN AML_NODE_HEADER * Node\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EAML_PARSE_INDEX Index;\r
+\r
+ // Check that the node being deleted is unlinked.\r
+ // When removing the node, its parent and list are reset\r
+ // with InitializeListHead. Thus it must be empty.\r
+ if (!IS_AML_NODE_VALID (Node) ||\r
+ !AML_NODE_IS_DETACHED (Node)) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ switch (Node->NodeType) {\r
+ case EAmlNodeRoot:\r
+ {\r
+ // Check the variable list of arguments has been cleaned.\r
+ if (!IsListEmpty (AmlNodeGetVariableArgList (Node))) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Status = AmlDeleteRootNode ((AML_ROOT_NODE*)Node);\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ }\r
+ break;\r
+ }\r
+\r
+ case EAmlNodeObject:\r
+ {\r
+ // Check the variable list of arguments has been cleaned.\r
+ if (!IsListEmpty (AmlNodeGetVariableArgList (Node))) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ // Check the fixed argument list has been cleaned.\r
+ for (Index = EAmlParseIndexTerm0; Index < EAmlParseIndexMax; Index++) {\r
+ if (((AML_OBJECT_NODE*)Node)->FixedArgs[Index] != NULL) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+\r
+ Status = AmlDeleteObjectNode ((AML_OBJECT_NODE*)Node);\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ }\r
+ break;\r
+ }\r
+\r
+ case EAmlNodeData:\r
+ {\r
+ Status = AmlDeleteDataNode ((AML_DATA_NODE*)Node);\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ }\r
+ break;\r
+ }\r
+\r
+ default:\r
+ {\r
+ ASSERT (0);\r
+ Status = EFI_INVALID_PARAMETER;\r
+ break;\r
+ }\r
+ } // switch\r
+\r
+ return Status;\r
+}\r
+\r
+/** Check whether ObjectNode has the input attribute.\r
+ This function can be used to check ObjectNode is an object node\r
+ at the same time.\r
+\r
+ @param [in] ObjectNode Pointer to an object node.\r
+ @param [in] Attribute Attribute to check for.\r
+\r
+ @retval TRUE The node is an AML object and the attribute is present.\r
+ @retval FALSE Otherwise.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+AmlNodeHasAttribute (\r
+ IN CONST AML_OBJECT_NODE * ObjectNode,\r
+ IN AML_OP_ATTRIBUTE Attribute\r
+ )\r
+{\r
+ if (!IS_AML_OBJECT_NODE (ObjectNode) ||\r
+ (ObjectNode->AmlByteEncoding == NULL)) {\r
+ return FALSE;\r
+ }\r
+\r
+ return ((ObjectNode->AmlByteEncoding->Attribute &\r
+ Attribute) == 0 ? FALSE : TRUE);\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 AML object and\r
+ the Opcode and the SubOpCode match.\r
+ @retval FALSE Otherwise.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+AmlNodeCompareOpCode (\r
+ IN CONST AML_OBJECT_NODE * ObjectNode,\r
+ IN UINT8 OpCode,\r
+ IN UINT8 SubOpCode\r
+ )\r
+{\r
+ if (!IS_AML_OBJECT_NODE (ObjectNode) ||\r
+ (ObjectNode->AmlByteEncoding == NULL)) {\r
+ return FALSE;\r
+ }\r
+\r
+ ASSERT (AmlIsOpCodeValid (OpCode, SubOpCode));\r
+\r
+ return ((ObjectNode->AmlByteEncoding->OpCode == OpCode) &&\r
+ (ObjectNode->AmlByteEncoding->SubOpCode == SubOpCode)) ?\r
+ TRUE : FALSE;\r
+}\r
+\r
+/** Check whether a Node is an integer node.\r
+\r
+ By integer node we mean an object node having one of the following opcode:\r
+ - AML_BYTE_PREFIX;\r
+ - AML_WORD_PREFIX;\r
+ - AML_DWORD_PREFIX;\r
+ - AML_QWORD_PREFIX.\r
+\r
+ @param [in] Node The node to check.\r
+\r
+ @retval TRUE The Node is an integer node.\r
+ @retval FALSE Otherwise.\r
+*/\r
+BOOLEAN\r
+EFIAPI\r
+IsIntegerNode (\r
+ IN AML_OBJECT_NODE * Node\r
+ )\r
+{\r
+ UINT8 OpCode;\r
+\r
+ if (!IS_AML_OBJECT_NODE (Node) ||\r
+ (Node->AmlByteEncoding == NULL)) {\r
+ return FALSE;\r
+ }\r
+\r
+ // Check Node is an integer node.\r
+ OpCode = Node->AmlByteEncoding->OpCode;\r
+ if ((OpCode != AML_BYTE_PREFIX) &&\r
+ (OpCode != AML_WORD_PREFIX) &&\r
+ (OpCode != AML_DWORD_PREFIX) &&\r
+ (OpCode != AML_QWORD_PREFIX)) {\r
+ return FALSE;\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+/** Check whether a Node is a ZeroOp, a OneOp or a OnesOp.\r
+\r
+ These two objects don't have a data node holding\r
+ a value. This require special handling.\r
+\r
+ @param [in] Node The node to check.\r
+\r
+ @retval TRUE The Node is a ZeroOp or OneOp.\r
+ @retval FALSE Otherwise.\r
+*/\r
+BOOLEAN\r
+EFIAPI\r
+IsSpecialIntegerNode (\r
+ IN AML_OBJECT_NODE * Node\r
+ )\r
+{\r
+ UINT8 OpCode;\r
+\r
+ if (!IS_AML_OBJECT_NODE (Node) ||\r
+ (Node->AmlByteEncoding == NULL)) {\r
+ return FALSE;\r
+ }\r
+\r
+ OpCode = Node->AmlByteEncoding->OpCode;\r
+\r
+ if ((OpCode != AML_ZERO_OP) &&\r
+ (OpCode != AML_ONE_OP) &&\r
+ (OpCode != AML_ONES_OP)) {\r
+ return FALSE;\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+/** Check whether Node corresponds to a method definition.\r
+\r
+ A method definition can be introduced:\r
+ - By a method object, having an AML_METHOD_OP OpCode;\r
+ - By an external definition of a method, having an AML_EXTERNAL_OP OpCode\r
+ and an ObjectType byte set to the MethodObj.\r
+\r
+ Note:\r
+ An alias node, having an AML_ALIAS_OP, can be resolved to a method\r
+ definition. This function doesn't handle this case.\r
+\r
+ @param [in] Node Node to check whether it is a method definition.\r
+\r
+ @retval TRUE The Node is a method definition.\r
+ @retval FALSE Otherwise.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+AmlIsMethodDefinitionNode (\r
+ IN CONST AML_OBJECT_NODE * Node\r
+ )\r
+{\r
+ AML_DATA_NODE * ObjectType;\r
+\r
+ // Node is checked to be an object node aswell.\r
+ if (AmlNodeCompareOpCode (Node, AML_METHOD_OP, 0)) {\r
+ return TRUE;\r
+ } else if (AmlNodeCompareOpCode (Node, AML_EXTERNAL_OP, 0)) {\r
+ // If the node is an external definition, check this is a method.\r
+ // DefExternal := ExternalOp NameString ObjectType ArgumentCount\r
+ // ExternalOp := 0x15\r
+ // ObjectType := ByteData\r
+ // ArgumentCount := ByteData (0 – 7)\r
+ ObjectType = (AML_DATA_NODE*)AmlGetFixedArgument (\r
+ (AML_OBJECT_NODE*)Node,\r
+ EAmlParseIndexTerm1\r
+ );\r
+ if (IS_AML_DATA_NODE (ObjectType) &&\r
+ (ObjectType->DataType == EAmlNodeDataTypeUInt) &&\r
+ ((ObjectType->Size == 1))) {\r
+ if (*((UINT8*)ObjectType->Buffer) == (UINT8)EAmlObjTypeMethodObj) {\r
+ // The external definition is a method.\r
+ return TRUE;\r
+ } else {\r
+ // The external definition is not a method.\r
+ return FALSE;\r
+ }\r
+ } else {\r
+ // The tree is inconsistent.\r
+ ASSERT (0);\r
+ return FALSE;\r
+ }\r
+ }\r
+\r
+ // This is not a method definition.\r
+ return FALSE;\r
+}\r
+\r
+/** Get the index at which the name of the node is stored.\r
+\r
+ @param [in] ObjectNode Pointer to an object node.\r
+ Must have the AML_IN_NAMESPACE attribute.\r
+ @param [out] Index Index of the name in the fixed list of arguments.\r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+ @retval EFI_INVALID_PARAMETER Invalid parameter.\r
+**/\r
+EFI_STATUS\r
+AmlNodeGetNameIndex (\r
+ IN CONST AML_OBJECT_NODE * ObjectNode,\r
+ OUT EAML_PARSE_INDEX * Index\r
+ )\r
+{\r
+ EAML_PARSE_INDEX NameIndex;\r
+\r
+ if (!AmlNodeHasAttribute (ObjectNode, AML_IN_NAMESPACE) ||\r
+ (ObjectNode->AmlByteEncoding == NULL) ||\r
+ (Index == NULL)) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ NameIndex = ObjectNode->AmlByteEncoding->NameIndex;\r
+\r
+ if ((NameIndex > ObjectNode->AmlByteEncoding->MaxIndex) ||\r
+ (ObjectNode->AmlByteEncoding->Format[NameIndex] != EAmlName)) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ *Index = NameIndex;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/** Get the name of the Node.\r
+\r
+ Node must be part of the namespace.\r
+\r
+ @param [in] ObjectNode Pointer to an object node,\r
+ which is part of the namespace.\r
+\r
+ @return A pointer to the name.\r
+ NULL otherwise.\r
+ Return NULL for the root node.\r
+**/\r
+CHAR8 *\r
+EFIAPI\r
+AmlNodeGetName (\r
+ IN CONST AML_OBJECT_NODE * ObjectNode\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EAML_PARSE_INDEX NameIndex;\r
+ AML_DATA_NODE * DataNode;\r
+\r
+ if (!AmlNodeHasAttribute (ObjectNode, AML_IN_NAMESPACE)) {\r
+ ASSERT (0);\r
+ return NULL;\r
+ }\r
+\r
+ // Get the index at which the name is stored in the fixed arguments list.\r
+ Status = AmlNodeGetNameIndex (ObjectNode, &NameIndex);\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ return NULL;\r
+ }\r
+\r
+ // The name is stored in a Data node.\r
+ DataNode = (AML_DATA_NODE*)ObjectNode->FixedArgs[NameIndex];\r
+ if (IS_AML_DATA_NODE (DataNode) &&\r
+ (DataNode->DataType == EAmlNodeDataTypeNameString)) {\r
+ return (CHAR8*)DataNode->Buffer;\r
+ }\r
+\r
+ /* Return NULL if no name is found.\r
+ This can occur if the name of a node is defined as a further\r
+ fixed argument.\r
+ E.g.: CreateField (BD03, 0x28, Add (ID03 + 0x08), BF33)\r
+ ^\r
+ The parser is here.\r
+ The parent of the Add statement is the CreateField statement. This\r
+ statement defines a name in the AML namespace. This name defined as\r
+ the fourth fixed argument. It hasn't been parsed yet.\r
+ */\r
+ return NULL;\r
+}\r
--- /dev/null
+/** @file\r
+ AML Node.\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_NODE_H_\r
+#define AML_NODE_H_\r
+\r
+#include <AmlNodeDefines.h>\r
+#include <IndustryStandard/Acpi.h>\r
+\r
+/** Create an AML_ROOT_NODE.\r
+ This node will be the root of the tree.\r
+\r
+ @param [in] SdtHeader Pointer to an ACPI DSDT/SSDT header to copy\r
+ the data from.\r
+ @param [out] NewRootNodePtr The created AML_ROOT_NODE.\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
+AmlCreateRootNode (\r
+ IN CONST EFI_ACPI_DESCRIPTION_HEADER * SdtHeader,\r
+ OUT AML_ROOT_NODE ** NewRootNodePtr\r
+ );\r
+\r
+/** Create an AML_OBJECT_NODE.\r
+\r
+ @param [in] AmlByteEncoding Byte encoding entry.\r
+ @param [in] PkgLength PkgLength of the node if the AmlByteEncoding\r
+ has the PkgLen attribute.\r
+ 0 otherwise.\r
+ @param [out] NewObjectNodePtr The created AML_OBJECT_NODE.\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
+AmlCreateObjectNode (\r
+ IN CONST AML_BYTE_ENCODING * AmlByteEncoding,\r
+ IN UINT32 PkgLength,\r
+ OUT AML_OBJECT_NODE ** NewObjectNodePtr\r
+ );\r
+\r
+/** Create an AML_DATA_NODE.\r
+\r
+ @param [in] DataType DataType of the node.\r
+ @param [in] Data Pointer to the AML bytecode corresponding to\r
+ this node. Data is copied from there.\r
+ @param [in] DataSize Number of bytes to consider at the address\r
+ pointed by Data.\r
+ @param [out] NewDataNodePtr The created AML_DATA_NODE.\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
+AmlCreateDataNode (\r
+ IN EAML_NODE_DATA_TYPE DataType,\r
+ IN CONST UINT8 * Data,\r
+ IN UINT32 DataSize,\r
+ OUT AML_DATA_NODE ** NewDataNodePtr\r
+ );\r
+\r
+/** Delete a Node.\r
+\r
+ @param [in] Node Pointer to a Node.\r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+ @retval EFI_INVALID_PARAMETER Invalid parameter.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AmlDeleteNode (\r
+ IN AML_NODE_HEADER * Node\r
+ );\r
+\r
+/** Check whether ObjectNode has the input attribute.\r
+ This function can be used to check ObjectNode is an object node\r
+ at the same time.\r
+\r
+ @param [in] ObjectNode Pointer to an object node.\r
+ @param [in] Attribute Attribute to check for.\r
+\r
+ @retval TRUE The node is an AML object and the attribute is present.\r
+ @retval FALSE Otherwise.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+AmlNodeHasAttribute (\r
+ IN CONST AML_OBJECT_NODE * ObjectNode,\r
+ IN AML_OP_ATTRIBUTE Attribute\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 AML object and\r
+ the Opcode and the SubOpCode match.\r
+ @retval FALSE Otherwise.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+AmlNodeCompareOpCode (\r
+ IN CONST AML_OBJECT_NODE * ObjectNode,\r
+ IN UINT8 OpCode,\r
+ IN UINT8 SubOpCode\r
+ );\r
+\r
+/** Check whether a Node is an integer node.\r
+\r
+ By integer node we mean an object node having one of the following opcode:\r
+ - AML_BYTE_PREFIX;\r
+ - AML_WORD_PREFIX;\r
+ - AML_DWORD_PREFIX;\r
+ - AML_QWORD_PREFIX.\r
+\r
+ @param [in] Node The node to check.\r
+\r
+ @retval TRUE The Node is an integer node.\r
+ @retval FALSE Otherwise.\r
+*/\r
+BOOLEAN\r
+EFIAPI\r
+IsIntegerNode (\r
+ IN AML_OBJECT_NODE * Node\r
+ );\r
+\r
+/** Check whether a Node is a ZeroOp, a OneOp or a OnesOp.\r
+\r
+ These two objects don't have a data node holding\r
+ a value. This require special handling.\r
+\r
+ @param [in] Node The node to check.\r
+\r
+ @retval TRUE The Node is a ZeroOp or OneOp.\r
+ @retval FALSE Otherwise.\r
+*/\r
+BOOLEAN\r
+EFIAPI\r
+IsSpecialIntegerNode (\r
+ IN AML_OBJECT_NODE * Node\r
+ );\r
+\r
+/** Check whether Node corresponds to a method definition.\r
+\r
+ A method definition can be introduced:\r
+ - By a method object, having an AML_METHOD_OP OpCode;\r
+ - By an external definition of a method, having an AML_EXTERNAL_OP OpCode\r
+ and an ObjectType byte set to the MethodObj.\r
+\r
+ Note:\r
+ An alias node, having an AML_ALIAS_OP, can be resolved to a method\r
+ definition. This function doesn't handle this case.\r
+\r
+ @param [in] Node Node to check whether it is a method definition.\r
+\r
+ @retval TRUE The Node is a method definition.\r
+ @retval FALSE Otherwise.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+AmlIsMethodDefinitionNode (\r
+ IN CONST AML_OBJECT_NODE * Node\r
+ );\r
+\r
+/** Get the index at which the name of the node is stored.\r
+\r
+ @param [in] ObjectNode Pointer to an object node.\r
+ Must have the AML_IN_NAMESPACE attribute.\r
+ @param [out] Index Index of the name in the fixed list of arguments.\r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+ @retval EFI_INVALID_PARAMETER Invalid parameter.\r
+**/\r
+EFI_STATUS\r
+AmlNodeGetNameIndex (\r
+ IN CONST AML_OBJECT_NODE * ObjectNode,\r
+ OUT EAML_PARSE_INDEX * Index\r
+ );\r
+\r
+/** Get the name of the Node.\r
+\r
+ Node must be part of the namespace.\r
+\r
+ @param [in] ObjectNode Pointer to an object node,\r
+ which is part of the namespace.\r
+\r
+ @return A pointer to the name.\r
+ NULL otherwise.\r
+ Return NULL for the root node.\r
+**/\r
+CHAR8 *\r
+EFIAPI\r
+AmlNodeGetName (\r
+ IN CONST AML_OBJECT_NODE * ObjectNode\r
+ );\r
+\r
+#endif // AML_NODE_H_\r
--- /dev/null
+/** @file\r
+ AML Node Interface.\r
+\r
+ Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>\r
+\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+**/\r
+\r
+#include <AmlNodeDefines.h>\r
+\r
+#include <AmlCoreInterface.h>\r
+#include <ResourceData/AmlResourceData.h>\r
+#include <String/AmlString.h>\r
+#include <Tree/AmlNode.h>\r
+#include <Tree/AmlTree.h>\r
+#include <Utils/AmlUtility.h>\r
+\r
+/** Returns the tree node type (Root/Object/Data).\r
+\r
+ @param [in] Node Pointer to a Node.\r
+\r
+ @return The node type.\r
+ EAmlNodeUnknown if invalid parameter.\r
+**/\r
+EAML_NODE_TYPE\r
+EFIAPI\r
+AmlGetNodeType (\r
+ IN AML_NODE_HEADER * Node\r
+ )\r
+{\r
+ if (!IS_AML_NODE_VALID (Node)) {\r
+ ASSERT (0);\r
+ return EAmlNodeUnknown;\r
+ }\r
+\r
+ return Node->NodeType;\r
+}\r
+\r
+/** Get the RootNode information.\r
+ The Node must be a root node.\r
+\r
+ @param [in] RootNode Pointer to a root node.\r
+ @param [out] SdtHeaderBuffer Buffer to copy the ACPI DSDT/SSDT header to.\r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+ @retval EFI_INVALID_PARAMETER Invalid parameter.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AmlGetRootNodeInfo (\r
+ IN AML_ROOT_NODE * RootNode,\r
+ OUT EFI_ACPI_DESCRIPTION_HEADER * SdtHeaderBuffer\r
+ )\r
+{\r
+ if (!IS_AML_ROOT_NODE (RootNode) ||\r
+ (SdtHeaderBuffer == NULL)) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ CopyMem (\r
+ SdtHeaderBuffer,\r
+ RootNode->SdtHeader,\r
+ sizeof (EFI_ACPI_DESCRIPTION_HEADER)\r
+ );\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/** Get the ObjectNode information.\r
+ The Node must be an object node.\r
+\r
+ @ingroup NodeInterfaceApi\r
+\r
+ @param [in] ObjectNode Pointer to an object node.\r
+ @param [out] OpCode Pointer holding the OpCode.\r
+ Optional, can be NULL.\r
+ @param [out] SubOpCode Pointer holding the SubOpCode.\r
+ Optional, can be NULL.\r
+ @param [out] PkgLen Pointer holding the PkgLen.\r
+ The PkgLen is 0 for nodes\r
+ not having the Pkglen attribute.\r
+ Optional, can be NULL.\r
+ @param [out] IsNameSpaceNode Pointer holding TRUE if the node is defining\r
+ or changing the NameSpace scope.\r
+ E.g.: The "Name ()" and "Scope ()" ASL\r
+ statements add/modify the NameSpace scope.\r
+ Their corresponding node are NameSpace nodes.\r
+ Optional, can be NULL.\r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+ @retval EFI_INVALID_PARAMETER Invalid parameter.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AmlGetObjectNodeInfo (\r
+ IN AML_OBJECT_NODE * ObjectNode,\r
+ OUT UINT8 * OpCode, OPTIONAL\r
+ OUT UINT8 * SubOpCode, OPTIONAL\r
+ OUT UINT32 * PkgLen, OPTIONAL\r
+ OUT BOOLEAN * IsNameSpaceNode OPTIONAL\r
+ )\r
+{\r
+ if (!IS_AML_OBJECT_NODE (ObjectNode)) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (OpCode != NULL) {\r
+ *OpCode = ObjectNode->AmlByteEncoding->OpCode;\r
+ }\r
+ if (SubOpCode != NULL) {\r
+ *SubOpCode = ObjectNode->AmlByteEncoding->SubOpCode;\r
+ }\r
+ if (PkgLen != NULL) {\r
+ *PkgLen = ObjectNode->PkgLen;\r
+ }\r
+ if (IsNameSpaceNode != NULL) {\r
+ *IsNameSpaceNode = AmlNodeHasAttribute (ObjectNode, AML_IN_NAMESPACE);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/** Returns the count of the fixed arguments for the input Node.\r
+\r
+ @param [in] Node Pointer to an object node.\r
+\r
+ @return Number of fixed arguments of the object node.\r
+ Return 0 if the node is not an object node.\r
+**/\r
+UINT8\r
+AmlGetFixedArgumentCount (\r
+ IN AML_OBJECT_NODE * Node\r
+ )\r
+{\r
+ if (IS_AML_OBJECT_NODE (Node) &&\r
+ (Node->AmlByteEncoding != NULL)) {\r
+ return (UINT8)Node->AmlByteEncoding->MaxIndex;\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+/** Get the data type of the DataNode.\r
+ The Node must be a data node.\r
+\r
+ @param [in] DataNode Pointer to a data node.\r
+ @param [out] DataType Pointer holding the data type of the data buffer.\r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+ @retval EFI_INVALID_PARAMETER Invalid parameter.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AmlGetNodeDataType (\r
+ IN AML_DATA_NODE * DataNode,\r
+ OUT EAML_NODE_DATA_TYPE * DataType\r
+ )\r
+{\r
+ if (!IS_AML_DATA_NODE (DataNode) ||\r
+ (DataType == NULL)) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ *DataType = DataNode->DataType;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/** Get the descriptor Id of the resource data element\r
+ contained in the DataNode.\r
+\r
+ The Node must be a data node.\r
+ The Node must have the resource data type, i.e. have the\r
+ EAmlNodeDataTypeResourceData data type.\r
+\r
+ @param [in] DataNode Pointer to a data node containing a\r
+ resource data element.\r
+ @param [out] ResourceDataType Pointer holding the descriptor Id of\r
+ the resource data.\r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+ @retval EFI_INVALID_PARAMETER Invalid parameter.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AmlGetResourceDataType (\r
+ IN AML_DATA_NODE * DataNode,\r
+ OUT AML_RD_HEADER * ResourceDataType\r
+ )\r
+{\r
+ if (!IS_AML_DATA_NODE (DataNode) ||\r
+ (ResourceDataType == NULL) ||\r
+ (DataNode->DataType != EAmlNodeDataTypeResourceData)) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ *ResourceDataType = AmlRdGetDescId (DataNode->Buffer);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/** Get the data buffer and size of the DataNode.\r
+ The Node must be a data node.\r
+\r
+ BufferSize is always updated to the size of buffer of the DataNode.\r
+\r
+ If:\r
+ - the content of BufferSize is >= to the DataNode's buffer size;\r
+ - Buffer is not NULL;\r
+ then copy the content of the DataNode's buffer in Buffer.\r
+\r
+ @param [in] DataNode Pointer to a data node.\r
+ @param [out] Buffer Buffer to write the data to.\r
+ Optional, if NULL, only update BufferSize.\r
+ @param [in, out] BufferSize Pointer holding:\r
+ - At entry, the size of the Buffer;\r
+ - At exit, the size of the DataNode's\r
+ buffer size.\r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+ @retval EFI_INVALID_PARAMETER Invalid parameter.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AmlGetDataNodeBuffer (\r
+ IN AML_DATA_NODE * DataNode,\r
+ OUT UINT8 * Buffer, OPTIONAL\r
+ IN OUT UINT32 * BufferSize\r
+ )\r
+{\r
+ if (!IS_AML_DATA_NODE (DataNode) ||\r
+ (BufferSize == NULL)) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((*BufferSize >= DataNode->Size) &&\r
+ (Buffer != NULL)) {\r
+ CopyMem (Buffer, DataNode->Buffer, DataNode->Size);\r
+ }\r
+\r
+ *BufferSize = DataNode->Size;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/** Update the ACPI DSDT/SSDT table header.\r
+\r
+ The input SdtHeader information is copied to the tree RootNode.\r
+ The table Length field is automatically updated.\r
+ The checksum field is only updated when serializing the tree.\r
+\r
+ @param [in] RootNode Pointer to a root node.\r
+ @param [in] SdtHeader Pointer to an ACPI DSDT/SSDT table header.\r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+ @retval EFI_INVALID_PARAMETER Invalid parameter.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AmlUpdateRootNode (\r
+ IN AML_ROOT_NODE * RootNode,\r
+ IN CONST EFI_ACPI_DESCRIPTION_HEADER * SdtHeader\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 Length;\r
+\r
+ if (!IS_AML_ROOT_NODE (RootNode) ||\r
+ (SdtHeader == NULL) ||\r
+ ((SdtHeader->Signature !=\r
+ EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) &&\r
+ (SdtHeader->Signature !=\r
+ EFI_ACPI_6_3_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE))) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ CopyMem (\r
+ RootNode->SdtHeader,\r
+ SdtHeader,\r
+ sizeof (EFI_ACPI_DESCRIPTION_HEADER)\r
+ );\r
+\r
+ // Update the Length field.\r
+ Status = AmlComputeSize ((AML_NODE_HEADER*)RootNode, &Length);\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ return Status;\r
+ }\r
+\r
+ RootNode->SdtHeader->Length = Length +\r
+ (UINT32)sizeof (EFI_ACPI_DESCRIPTION_HEADER);\r
+\r
+ return Status;\r
+}\r
+\r
+/** Update an object node representing an integer with a new value.\r
+\r
+ The object node must have one of the following OpCodes:\r
+ - AML_BYTE_PREFIX\r
+ - AML_WORD_PREFIX\r
+ - AML_DWORD_PREFIX\r
+ - AML_QWORD_PREFIX\r
+ - AML_ZERO_OP\r
+ - AML_ONE_OP\r
+\r
+ The following OpCode is not supported:\r
+ - AML_ONES_OP\r
+\r
+ @param [in] IntegerOpNode Pointer an object node containing an integer.\r
+ Must not be an object node with an AML_ONES_OP\r
+ OpCode.\r
+ @param [in] NewInteger New integer value to set.\r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+ @retval EFI_INVALID_PARAMETER Invalid parameter.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AmlUpdateInteger (\r
+ IN AML_OBJECT_NODE * IntegerOpNode,\r
+ IN UINT64 NewInteger\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ INT8 ValueWidthDiff;\r
+\r
+ if (!IS_AML_OBJECT_NODE (IntegerOpNode) ||\r
+ (!IsIntegerNode (IntegerOpNode) &&\r
+ !IsSpecialIntegerNode (IntegerOpNode)) ||\r
+ AmlNodeCompareOpCode (IntegerOpNode, AML_ONES_OP, 0)) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Status = AmlNodeSetIntegerValue (IntegerOpNode, NewInteger, &ValueWidthDiff);\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ return Status;\r
+ }\r
+\r
+ // If the new size is different from the old size, propagate the new size.\r
+ if (ValueWidthDiff != 0) {\r
+ // Propagate the information.\r
+ Status = AmlPropagateInformation (\r
+ (AML_NODE_HEADER*)IntegerOpNode,\r
+ (ValueWidthDiff > 0) ? TRUE : FALSE,\r
+ ABS (ValueWidthDiff),\r
+ 0\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/** Update the buffer of a data node.\r
+\r
+ Note: The data type of the buffer's content must match the data type of the\r
+ DataNode. This is a hard restriction to prevent undesired behaviour.\r
+\r
+ @param [in] DataNode Pointer to a data node.\r
+ @param [in] DataType Data type of the Buffer's content.\r
+ @param [in] Buffer Buffer containing the new data. The content of\r
+ the Buffer is copied.\r
+ @param [in] Size Size of the Buffer.\r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+ @retval EFI_INVALID_PARAMETER Invalid parameter.\r
+ @retval EFI_UNSUPPORTED Operation not supporter.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AmlUpdateDataNode (\r
+ IN AML_DATA_NODE * DataNode,\r
+ IN EAML_NODE_DATA_TYPE DataType,\r
+ IN UINT8 * Buffer,\r
+ IN UINT32 Size\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ UINT32 ExpectedSize;\r
+ AML_OBJECT_NODE * ParentNode;\r
+ EAML_NODE_DATA_TYPE ExpectedArgType;\r
+ EAML_PARSE_INDEX Index;\r
+\r
+ if (!IS_AML_DATA_NODE (DataNode) ||\r
+ (DataType > EAmlNodeDataTypeMax) ||\r
+ (Buffer == NULL) ||\r
+ (Size == 0)) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ ParentNode = (AML_OBJECT_NODE*)AmlGetParent ((AML_NODE_HEADER*)DataNode);\r
+ if (!IS_AML_OBJECT_NODE (ParentNode)) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ // The NewNode and OldNode must have the same type.\r
+ // We do not allow to change the argument type of a data node.\r
+ // If required, the initial ASL template should be modified\r
+ // accordingly.\r
+ // It is however possible to interchange a raw buffer and a\r
+ // resource data element, since raw data can be misinterpreted\r
+ // as a resource data element.\r
+ ExpectedArgType = DataNode->DataType;\r
+ if ((ExpectedArgType != DataType) &&\r
+ (((ExpectedArgType != EAmlNodeDataTypeRaw) &&\r
+ (ExpectedArgType != EAmlNodeDataTypeResourceData)) ||\r
+ ((DataType != EAmlNodeDataTypeRaw) &&\r
+ (DataType != EAmlNodeDataTypeResourceData)))) {\r
+ ASSERT (0);\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ // Perform some compatibility checks.\r
+ switch (DataType) {\r
+ case EAmlNodeDataTypeNameString:\r
+ {\r
+ // Check the name contained in the Buffer is an AML name\r
+ // with the right size.\r
+ Status = AmlGetNameStringSize ((CONST CHAR8*)Buffer, &ExpectedSize);\r
+ if (EFI_ERROR (Status) ||\r
+ (Size != ExpectedSize)) {\r
+ ASSERT (0);\r
+ return Status;\r
+ }\r
+ break;\r
+ }\r
+ case EAmlNodeDataTypeString:\r
+ {\r
+ ExpectedSize = 0;\r
+ while (ExpectedSize < Size) {\r
+ // Cf ACPI 6.3 specification 20.2.3 Data Objects Encoding.\r
+ // AsciiCharList := Nothing | <AsciiChar AsciiCharList>\r
+ // AsciiChar := 0x01 - 0x7F\r
+ // NullChar := 0x00\r
+ if (Buffer[ExpectedSize] > 0x7F) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ ExpectedSize++;\r
+ }\r
+\r
+ if (ExpectedSize != Size) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ break;\r
+ }\r
+ case EAmlNodeDataTypeUInt:\r
+ {\r
+ if (AmlIsNodeFixedArgument ((CONST AML_NODE_HEADER*)DataNode, &Index)) {\r
+ if ((ParentNode->AmlByteEncoding == NULL) ||\r
+ (ParentNode->AmlByteEncoding->Format == NULL)) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ // It is not possible to change the size of a fixed length UintX.\r
+ // E.g. for PackageOp the first fixed argument is of type EAmlUInt8\r
+ // and represents the count of elements. This type cannot be changed.\r
+ if ((ParentNode->AmlByteEncoding->Format[Index] != EAmlObject) &&\r
+ (DataNode->Size != Size)) {\r
+ ASSERT (0);\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ }\r
+ break;\r
+ }\r
+ case EAmlNodeDataTypeRaw:\r
+ {\r
+ // Check if the parent node has the byte list flag set.\r
+ if (!AmlNodeHasAttribute (ParentNode, AML_HAS_BYTE_LIST)) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ break;\r
+ }\r
+ case EAmlNodeDataTypeResourceData:\r
+ {\r
+ // The resource data can be either small or large resource data.\r
+ // Small resource data must be at least 1 byte.\r
+ // Large resource data must be at least as long as the header\r
+ // of a large resource data.\r
+ if (AML_RD_IS_LARGE (Buffer) &&\r
+ (Size < sizeof (ACPI_LARGE_RESOURCE_HEADER))) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ // Check if the parent node has the byte list flag set.\r
+ if (!AmlNodeHasAttribute (ParentNode, AML_HAS_BYTE_LIST)) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ // Check the size of the buffer is equal to the resource data size\r
+ // encoded in the input buffer.\r
+ ExpectedSize = AmlRdGetSize (Buffer);\r
+ if (ExpectedSize != Size) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ break;\r
+ }\r
+ case EAmlNodeDataTypeFieldPkgLen:\r
+ {\r
+ // Check the parent is a FieldNamed field element.\r
+ if (!AmlNodeCompareOpCode (ParentNode, AML_FIELD_NAMED_OP, 0)) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ break;\r
+ }\r
+ // None and reserved types.\r
+ default:\r
+ {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ break;\r
+ }\r
+ } // switch\r
+\r
+ // If the new size is different from the old size, propagate the new size.\r
+ if (DataNode->Size != Size) {\r
+ // Propagate the information.\r
+ Status = AmlPropagateInformation (\r
+ DataNode->NodeHeader.Parent,\r
+ (Size > DataNode->Size) ? TRUE : FALSE,\r
+ (Size > DataNode->Size) ?\r
+ (Size - DataNode->Size) :\r
+ (DataNode->Size - Size),\r
+ 0\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ return Status;\r
+ }\r
+\r
+ // Free the old DataNode buffer and allocate a new buffer to store the\r
+ // new data.\r
+ FreePool (DataNode->Buffer);\r
+ DataNode->Buffer = AllocateZeroPool (Size);\r
+ if (DataNode->Buffer == NULL) {\r
+ ASSERT (0);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ DataNode->Size = Size;\r
+ }\r
+\r
+ CopyMem (DataNode->Buffer, Buffer, Size);\r
+\r
+ return EFI_SUCCESS;\r
+}\r