--- /dev/null
+/** @file\r
+ AML NameSpace.\r
+\r
+ Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>\r
+\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+**/\r
+\r
+/* Lexicon:\r
+\r
+ NameSeg:\r
+ - An ASL NameSeg is a name made of at most 4 chars.\r
+ Cf. ACPI 6.3 specification, s19.2.2 'Name and Pathname Terms'.\r
+ - An AML NameSeg is a name made of 4 chars.\r
+ Cf. ACPI 6.3 specification, s20.2.2 'Name Objects Encoding'.\r
+\r
+ NameString:\r
+ A NameString is analogous to a pathname. It is made of 0 to 255 NameSegs.\r
+ A NameString can be prefixed by a root char ('\') or 0 to 255 carets ('^').\r
+\r
+ A NameString can be ASL or AML encoded.\r
+ AML NameStrings can have a NameString prefix (dual or multi-name prefix)\r
+ between the root/carets and the list of NameSegs. If the prefix is the\r
+ multi-name prefix, then the number of NameSegs is encoded on one single byte.\r
+ Cf. ACPI 6.3 specification, s19.2.2 'Name and Pathname Terms'.\r
+ Cf. ACPI 6.3 specification, s20.2.2 'Name Objects Encoding'.\r
+\r
+ Namespace level:\r
+ One level in the AML Namespace level corresponds to one NameSeg. In ASL,\r
+ objects names are NameStrings. This means a device can have a name which\r
+ spans multiple levels.\r
+ E.g.: The ASL code: Device (CLU0.CPU0) corresponds to 2 levels.\r
+\r
+ Namespace node:\r
+ A namespace node is an object node which has an associated name, and which\r
+ changes the current scope.\r
+ E.g.:\r
+ 1. The "Device ()" ASL statement adds a name to the AML namespace and\r
+ changes the current scope to the device scope, this is a namespace node.\r
+ 2. The "Scope ()" ASL statement changes the current scope, this is a\r
+ namespace node.\r
+ 3. A method invocation has a name, but does not add nor change the current\r
+ AML scope. This is not a namespace node.\r
+\r
+ - Object nodes with the AML_IN_NAMESPACE attribute are namespace nodes.\r
+ Buffers (), Packages (), etc. are not part of the namespace. It is however\r
+ possible to associate them with a name with the Name () ASL statement.\r
+ - The root node is considered as being part of the namespace.\r
+ - Some resource data elements can have a name when defining them in\r
+ an ASL statement. However, this name is stripped by the ASL compiler.\r
+ Thus, they don't have a name in the AML bytestream, and are therefore\r
+ not part of the AML namespace.\r
+ - Field list elements are part of the namespace.\r
+ Fields created by an CreateXXXField () ASL statement are part of the\r
+ namespace. The name of these node can be found in the third or fourth\r
+ fixed argument. The exact index of the name can be found in the NameIndex\r
+ field of the AML_BYTE_ENCODING array.\r
+ Field are at the same level as their ASL statement in the namespace.\r
+ E.g:\r
+ Scope (\) {\r
+ OperationRegion (REG0, SystemIO, 0x100, 0x100)\r
+ Field (REG0, ByteAcc, NoLock, Preserve) {\r
+ FIE0, 1,\r
+ FIE1, 5\r
+ }\r
+\r
+ Name (BUF0, Buffer (100) {})\r
+ CreateField (BUF0, 5, 2, MEM0)\r
+ }\r
+\r
+ produces this namespace:\r
+ \ (Root)\r
+ \-REG0\r
+ \-FIE0\r
+ \-FIE1\r
+ \-BUF0\r
+ \-MEM0\r
+\r
+ Raw AML pathname or Raw AML NameString:\r
+ In order to easily manipulate AML NameStrings, the non-NameSegs chars are\r
+ removed in raw pathnames/NameStrings. Non-NameSegs chars are the\r
+ root char ('\'), carets ('^') and NameString prefixes (Dual/Multi name char).\r
+ E.g. The following terminology is defined in this AML Library.\r
+ ASL absolute path: "[RootChar]AAAA.BBBB.CCCC\0"\r
+ AML absolute path: "[RootChar][MultiNamePrefix][3(NameSegs)]AAAABBBBCCCC"\r
+ Raw absolute path: "AAAABBBBCCCC"\r
+\r
+ Multi-name:\r
+ A NameString with at least 2 NameSegs. A node can have a name which spans\r
+ multiple namespace levels.\r
+*/\r
+\r
+#include <NameSpace/AmlNameSpace.h>\r
+\r
+#include <AmlCoreInterface.h>\r
+#include <AmlDbgPrint/AmlDbgPrint.h>\r
+#include <String/AmlString.h>\r
+#include <Tree/AmlNode.h>\r
+#include <Tree/AmlTree.h>\r
+#include <Tree/AmlTreeTraversal.h>\r
+\r
+/** Context of the path search callback function.\r
+\r
+ The function finding a node from a path and a reference node enumerates\r
+ the namespace nodes in the tree and compares their absolute path with the\r
+ searched path. The enumeration function uses a callback function that can\r
+ receive a context.\r
+ This structure is used to store the context information required in the\r
+ callback function.\r
+*/\r
+typedef struct AmlPathSearchContext {\r
+ /// Backward stream holding the raw AML absolute searched path.\r
+ AML_STREAM * SearchPathBStream;\r
+\r
+ /// An empty backward stream holding a pre-allocated buffer. This prevents\r
+ /// from having to do multiple allocations during the search.\r
+ /// This stream is used to query the raw AML absolute path of the node\r
+ /// currently being probed.\r
+ AML_STREAM * CurrNodePathBStream;\r
+\r
+ /// If the node being visited is the node being searched,\r
+ /// i.e. its path and the searched path match,\r
+ /// save its reference in this pointer.\r
+ AML_NODE_HEADER * OutNode;\r
+} AML_PATH_SEARCH_CONTEXT;\r
+\r
+/** Return the first AML namespace node up in the parent hierarchy.\r
+\r
+ Return the root node if no namespace node is found is the hierarchy.\r
+\r
+ @param [in] Node Node to look at the parents from.\r
+ If Node is the root node, OutNode is NULL.\r
+ @param [out] OutNode If a namespace node is found, pointer to the\r
+ first namespace node of Node's parents.\r
+ Stop at the root node otherwise.\r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+ @retval EFI_INVALID_PARAMETER Invalid parameter.\r
+ **/\r
+EFI_STATUS\r
+EFIAPI\r
+AmlGetFirstAncestorNameSpaceNode (\r
+ IN CONST AML_NODE_HEADER * Node,\r
+ OUT AML_NODE_HEADER ** OutNode\r
+ )\r
+{\r
+ if (!IS_AML_NODE_VALID (Node) ||\r
+ (OutNode == NULL)) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ // If Node is the root node, return NULL.\r
+ if (IS_AML_ROOT_NODE (Node)) {\r
+ *OutNode = NULL;\r
+ return EFI_SUCCESS;\r
+ } else {\r
+ // Else, get the parent node.\r
+ Node = AmlGetParent ((AML_NODE_HEADER*)Node);\r
+ if (!IS_AML_NODE_VALID (Node)) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+\r
+ // Continue getting the parent node while no namespace node is encountered.\r
+ while (TRUE) {\r
+ if (IS_AML_ROOT_NODE (Node)) {\r
+ break;\r
+ } else if (AmlNodeHasAttribute (\r
+ (CONST AML_OBJECT_NODE*)Node,\r
+ AML_IN_NAMESPACE\r
+ )) {\r
+ break;\r
+ } else {\r
+ Node = AmlGetParent ((AML_NODE_HEADER*)Node);\r
+ if (!IS_AML_NODE_VALID (Node)) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+ } // while\r
+\r
+ *OutNode = (AML_NODE_HEADER*)Node;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/** Climb up the AML namespace hierarchy.\r
+\r
+ This function get the ancestor namespace node in the AML namespace.\r
+ If Levels is not zero, skip Levels namespace nodes in the AML namespace.\r
+ If Levels is zero, return the first ancestor namespace node.\r
+ I.e. if Levels = n, this function returns the (n + 1) ancestor.\r
+\r
+ @param [in] Node Pointer to an object node.\r
+ @param [in, out] Levels Pointer holding a number of AML namespace levels:\r
+ - At entry, the number of levels to go up in\r
+ the AML namespace;\r
+ - At exit, the number of levels that still need\r
+ to be climbed in case of a multi-named node.\r
+ Indeed, if a node with a multi-name is found,\r
+ and Levels is less than the number of NameSegs\r
+ in this name, then the function returns with\r
+ the number of levels that still need to be\r
+ climbed.\r
+ E.g.: If the first ancestor node's name is\r
+ "AAAA.BBBB.CCCC" and\r
+ Levels = 2 -> i.e go up 3 levels\r
+ \\r
+ ...\r
+ \-"AAAA.BBBB.CCCC" <----- OutNode\r
+ \-"DDDD" <----- Node (Input)\r
+\r
+ The function should ideally return a node\r
+ with the name "AAAA". However, it is not\r
+ possible to split the node name\r
+ "AAAA.BBBB.CCCC" to "AAAA".\r
+ Thus, OutNode is set to the input node,\r
+ and Levels = 2.\r
+ In most cases the number of levels to climb\r
+ correspond to non multi-name node, and therefore\r
+ Levels = 0 at exit.\r
+ @param [out] HasRoot The returned node in OutNode has an AML absolute\r
+ name, starting with a root char ('\'), or if OutNode\r
+ is the root node.\r
+ @param [out] OutNode The Levels+1 namespace ancestor of the input node in\r
+ the AML namespace. Must be the root node or a\r
+ namespace 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
+AmlGetAncestorNameSpaceNode (\r
+ IN CONST AML_OBJECT_NODE * Node,\r
+ IN OUT UINT32 * Levels,\r
+ OUT UINT32 * HasRoot,\r
+ OUT CONST AML_NODE_HEADER ** OutNode\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ CONST AML_NODE_HEADER * NameSpaceNode;\r
+ CHAR8 * NodeName;\r
+ UINT32 ParentCnt;\r
+\r
+ UINT32 Root;\r
+ UINT32 ParentPrefix;\r
+ UINT32 SegCount;\r
+\r
+ if (!IS_AML_OBJECT_NODE (Node) ||\r
+ (Levels == NULL) ||\r
+ (HasRoot == NULL) ||\r
+ (OutNode == NULL)) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ ParentCnt = *Levels;\r
+ *HasRoot = 0;\r
+\r
+ // ParentCnt namespace levels need to be climbed.\r
+ do {\r
+ // Get the next namespace node in the hierarchy.\r
+ Status = AmlGetFirstAncestorNameSpaceNode (\r
+ (CONST AML_NODE_HEADER*)Node,\r
+ (AML_NODE_HEADER**)&NameSpaceNode\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ return Status;\r
+ }\r
+\r
+ Node = (CONST AML_OBJECT_NODE*)NameSpaceNode;\r
+\r
+ if (IS_AML_ROOT_NODE (Node)) {\r
+ // Node is the root node. It is not possible to go beyond.\r
+ if (ParentCnt != 0) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ *HasRoot = 1;\r
+ break;\r
+ }\r
+\r
+ NodeName = AmlNodeGetName ((CONST AML_OBJECT_NODE*)Node);\r
+ if (NodeName == NULL) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ // Analyze the node name.\r
+ Status = AmlParseNameStringInfo (\r
+ NodeName,\r
+ &Root,\r
+ &ParentPrefix,\r
+ &SegCount\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ return Status;\r
+ }\r
+\r
+ if (Root != 0) {\r
+ // NodeName is an absolute pathname.\r
+ *HasRoot = Root;\r
+\r
+ // If the node has Root then it cannot have ParentPrefixes (Carets).\r
+ if (ParentPrefix != 0) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (SegCount == ParentCnt) {\r
+ // There are exactly enough AML namespace levels to consume.\r
+ // This means the root node was the searched node.\r
+ Node = (CONST AML_OBJECT_NODE*)AmlGetRootNode (\r
+ (CONST AML_NODE_HEADER*)Node\r
+ );\r
+ if (!IS_AML_ROOT_NODE (Node)) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ ParentCnt = 0;\r
+ break;\r
+ } else if (ParentCnt < SegCount) {\r
+ // There are too many AML namespace levels in this name.\r
+ // ParentCnt has the right value, just return.\r
+ break;\r
+ } else {\r
+ // ParentCnt > SegCount\r
+ // Return error as there must be at least ParentCnt AML namespace\r
+ // levels left in the absolute path.\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ } else {\r
+ // Root is 0.\r
+ if (ParentCnt < SegCount) {\r
+ // NodeName is a relative path.\r
+ // NodeName has enough levels to consume all the ParentCnt.\r
+ // Exit.\r
+ break;\r
+ } else if (SegCount == ParentCnt) {\r
+ // There are exactly enough AML namespace levels to consume.\r
+ if (ParentPrefix == 0) {\r
+ // The node name doesn't have any carets. Get the next namespace\r
+ // node and return.\r
+ Status = AmlGetFirstAncestorNameSpaceNode (\r
+ (CONST AML_NODE_HEADER*)Node,\r
+ (AML_NODE_HEADER**)&NameSpaceNode\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ return Status;\r
+ }\r
+ Node = (CONST AML_OBJECT_NODE*)NameSpaceNode;\r
+ ParentCnt = 0;\r
+ break;\r
+ } else {\r
+ // The node name has carets. Need to continue climbing the\r
+ // AML namespace.\r
+ ParentCnt = ParentPrefix;\r
+ }\r
+ } else {\r
+ // ParentCnt > SegCount\r
+ // NodeName doesn't have enough levels to consume all the ParentCnt.\r
+ // Update ParentCnt: Consume SegCount levels and add ParentPrefix\r
+ // levels. Continue climbing the tree.\r
+ ParentCnt = ParentCnt + ParentPrefix - SegCount;\r
+ }\r
+ }\r
+ } while (ParentCnt != 0);\r
+\r
+ *OutNode = (CONST AML_NODE_HEADER*)Node;\r
+ *Levels = ParentCnt;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/** Build the raw absolute AML pathname to Node and write it to a stream.\r
+\r
+ A raw AML pathname is an AML pathname where the root char ('\'),\r
+ prefix chars ('^') and NameString prefix byte (e.g.: DualNamePrefix)\r
+ have been removed. A raw AML pathname is a list of concatenated\r
+ NameSegs.\r
+\r
+ E.g.:\r
+ ASL absolute path: "[RootChar]AAAA.BBBB.CCCC\0"\r
+ AML absolute path: "[RootChar][MultiNamePrefix][3(NameSegs)]AAAABBBBCCCC"\r
+ Raw absolute path: "AAAABBBBCCCC"\r
+\r
+ @param [in] Node Node to build the raw absolute path to\r
+ Must be a root node, or a namespace node.\r
+ @param [in] InputParent Skip InputParent AML namespace levels before\r
+ starting building the raw absolute pathname.\r
+ E.g.: - Node's name being "^AAAA.BBBB.CCCC";\r
+ - InputParent = 2;\r
+ "BBBB.CCCC" will be skipped (2\r
+ levels), and "^AAAA" will remain. The\r
+ first caret is not related to InputParent.\r
+ @param [out] RawAbsPathBStream Backward stream to write the raw\r
+ pathname to.\r
+ If Node is the root node, the Stream data\r
+ Buffer will stay empty.\r
+ The stream must not be at its end.\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
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AmlGetRawNameSpacePath (\r
+ IN CONST AML_NODE_HEADER * Node,\r
+ IN UINT32 InputParent,\r
+ OUT AML_STREAM * RawAbsPathBStream\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ AML_NODE_HEADER * ParentNode;\r
+ CHAR8 * NodeName;\r
+\r
+ UINT32 Root;\r
+ UINT32 ParentPrefix;\r
+ UINT32 SegCount;\r
+ CONST CHAR8 * NameSeg;\r
+\r
+ if ((!IS_AML_ROOT_NODE (Node) &&\r
+ !AmlNodeHasAttribute (\r
+ (CONST AML_OBJECT_NODE*)Node,\r
+ AML_IN_NAMESPACE)) ||\r
+ !IS_STREAM (RawAbsPathBStream) ||\r
+ IS_END_OF_STREAM (RawAbsPathBStream) ||\r
+ !IS_STREAM_BACKWARD (RawAbsPathBStream) ||\r
+ (InputParent > MAX_UINT8)) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ while (1) {\r
+ if (IS_AML_ROOT_NODE (Node)) {\r
+ break;\r
+ }\r
+\r
+ NodeName = AmlNodeGetName ((CONST AML_OBJECT_NODE*)Node);\r
+ if (NodeName == NULL) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Status = AmlParseNameStringInfo (\r
+ NodeName,\r
+ &Root,\r
+ &ParentPrefix,\r
+ &SegCount\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ return Status;\r
+ }\r
+\r
+ if (SegCount > InputParent) {\r
+ // 1.1. If the Node's name has enough levels to consume all the\r
+ // InputParent carets, write the levels that are left.\r
+ NameSeg = AmlGetFirstNameSeg (NodeName, Root, ParentPrefix);\r
+ Status = AmlStreamWrite (\r
+ RawAbsPathBStream,\r
+ (CONST UINT8*)NameSeg,\r
+ (SegCount - InputParent) * AML_NAME_SEG_SIZE\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ return Status;\r
+ }\r
+ InputParent = 0;\r
+ } else {\r
+ // (SegCount <= InputParent)\r
+ // 1.2. Else save the InputParent in TotalParent to climb\r
+ // them later.\r
+ InputParent -= SegCount;\r
+ }\r
+\r
+ InputParent += ParentPrefix;\r
+\r
+ if (Root != 0) {\r
+ // 2. The Node's name is an absolute path.\r
+ // Exit, the root has been reached.\r
+ if (InputParent != 0) {\r
+ ASSERT (0);\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ break;\r
+ }\r
+\r
+ Status = AmlGetAncestorNameSpaceNode (\r
+ (CONST AML_OBJECT_NODE*)Node,\r
+ &InputParent,\r
+ &Root,\r
+ (CONST AML_NODE_HEADER**)&ParentNode\r
+ );\r
+ if (EFI_ERROR (Status) ||\r
+ (!IS_AML_NODE_VALID (ParentNode))) {\r
+ ASSERT (0);\r
+ return Status;\r
+ }\r
+\r
+ Node = ParentNode;\r
+\r
+ if (IS_AML_ROOT_NODE (Node)) {\r
+ // 3.1. If the root node has been found while climbing,\r
+ // no need to write NameSegs.\r
+ // Exit.\r
+ break;\r
+ } else if (Root != 0) {\r
+ // 3.2. An absolute path has been found while climbing the tree.\r
+ // If (InputParent != 0), the raw pathname is not the root.\r
+ // Write the first [SegCount - InputParent] NameSegs of this\r
+ // absolute path.\r
+ // Then exit.\r
+ if (InputParent != 0) {\r
+ // Get the absolute pathname.\r
+ NodeName = AmlNodeGetName ((CONST AML_OBJECT_NODE*)Node);\r
+ if (NodeName == NULL) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ // Analyze the absolute pathname.\r
+ Status = AmlParseNameStringInfo (\r
+ NodeName,\r
+ &Root,\r
+ &ParentPrefix,\r
+ &SegCount\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ return Status;\r
+ }\r
+\r
+ // Writing the n first NameSegs.\r
+ // n = SegCount - InputParent\r
+ NameSeg = AmlGetFirstNameSeg (NodeName, Root, ParentPrefix);\r
+ Status = AmlStreamWrite (\r
+ RawAbsPathBStream,\r
+ (CONST UINT8*)NameSeg,\r
+ (SegCount - InputParent) * AML_NAME_SEG_SIZE\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ return Status;\r
+ }\r
+\r
+ break;\r
+ } // (InputParent != 0)\r
+\r
+ }\r
+ } // while\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/** Add the RootChar and prefix byte to the raw AML NameString in the\r
+ input Stream to create a valid absolute path.\r
+\r
+ The prefix byte can be AML_DUAL_NAME_PREFIX, AML_MULTI_NAME_PREFIX\r
+ or nothing.\r
+\r
+ @param [in, out] AmlPathBStream The Stream initially contains a raw\r
+ NameString (i.e. a list of NameSegs).\r
+ The Stream can be empty (e.g.: for the\r
+ root path).\r
+ The stream must not be at its end.\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
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+AmlAddPrefix (\r
+ IN OUT AML_STREAM * AmlPathBStream\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 NameSegCount;\r
+ UINT32 NameSegSize;\r
+\r
+ // At most 3 bytes are needed for: RootChar + MultiNamePrefix + SegCount.\r
+ CHAR8 Prefix[3];\r
+ UINT32 PrefixSize;\r
+\r
+ // The Stream contains concatenated NameSegs.\r
+ if (!IS_STREAM (AmlPathBStream) ||\r
+ IS_END_OF_STREAM (AmlPathBStream) ||\r
+ !IS_STREAM_BACKWARD (AmlPathBStream)) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ // Its size should be a multiple of AML_NAME_SEG_SIZE.\r
+ // AML_NAME_SEG_SIZE = 4. Check the 2 lowest bits.\r
+ NameSegSize = AmlStreamGetIndex (AmlPathBStream);\r
+ if ((NameSegSize & (AML_NAME_SEG_SIZE - 1)) != 0) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ // Each NameSeg is 4 bytes so divide the NameSegSize by 4.\r
+ NameSegCount = NameSegSize >> 2;\r
+ if (NameSegCount > MAX_UINT8) {\r
+ // There can be at most 255 NameSegs.\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Prefix[0] = AML_ROOT_CHAR;\r
+\r
+ switch (NameSegCount) {\r
+ case 0:\r
+ {\r
+ // Root and parents only NameString (no NameSeg(s)) end with '\0'.\r
+ Prefix[1] = AML_ZERO_OP;\r
+ PrefixSize = 2;\r
+ break;\r
+ }\r
+ case 1:\r
+ {\r
+ PrefixSize = 1;\r
+ break;\r
+ }\r
+ case 2:\r
+ {\r
+ Prefix[1] = AML_DUAL_NAME_PREFIX;\r
+ PrefixSize = 2;\r
+ break;\r
+ }\r
+ default:\r
+ {\r
+ Prefix[1] = AML_MULTI_NAME_PREFIX;\r
+ Prefix[2] = (UINT8)NameSegCount;\r
+ PrefixSize = 3;\r
+ break;\r
+ }\r
+ }\r
+\r
+ // Add the RootChar + prefix (if needed) at the beginning of the pathname.\r
+ Status = AmlStreamWrite (AmlPathBStream, (CONST UINT8*)Prefix, PrefixSize);\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ return Status;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/** Remove the prefix bytes of an AML NameString stored in a backward stream\r
+ to get a raw NameString.\r
+\r
+ The AML encoding for '\', '^', Dual name or multi-name prefix are\r
+ stripped off.\r
+ E.g: If the ASL path was "\AAAA.BBBB", the AML equivalent would be\r
+ "{RootChar}{DualNamePrefix}AAAABBBB". So resultant raw NameString\r
+ is "AAAABBBB".\r
+\r
+ @param [in, out] AmlPathBStream Backward stream containing an AML\r
+ NameString.\r
+ The stream must not be at its end.\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
+AmlRemovePrefix (\r
+ IN OUT AML_STREAM * AmlPathBStream\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ UINT32 TotalSize;\r
+ UINT32 RewindSize;\r
+\r
+ UINT32 Root;\r
+ UINT32 ParentPrefix;\r
+ UINT32 SegCount;\r
+\r
+ if (!IS_STREAM (AmlPathBStream) ||\r
+ IS_END_OF_STREAM (AmlPathBStream) ||\r
+ !IS_STREAM_BACKWARD (AmlPathBStream)) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Status = AmlParseNameStringInfo (\r
+ (CHAR8*)AmlStreamGetCurrPos (AmlPathBStream),\r
+ &Root,\r
+ &ParentPrefix,\r
+ &SegCount\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ return Status;\r
+ }\r
+\r
+ TotalSize = AmlComputeNameStringSize (Root, ParentPrefix, SegCount);\r
+ if (TotalSize == 0) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ // Rewind the stream of all the bytes that are not SegCounts\r
+ // to drop the prefix.\r
+ RewindSize = TotalSize - (SegCount * AML_NAME_SEG_SIZE);\r
+ if (RewindSize != 0) {\r
+ Status = AmlStreamRewind (AmlPathBStream, RewindSize);\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/** Build the absolute ASL pathname to Node.\r
+\r
+ BufferSize is always updated to the size of the pathname.\r
+\r
+ If:\r
+ - the content of BufferSize is >= to the size of the pathname AND;\r
+ - Buffer is not NULL.\r
+ then copy the pathname in the Buffer. A buffer of the size\r
+ MAX_ASL_NAMESTRING_SIZE is big enough to receive any ASL pathname.\r
+\r
+ @param [in] Node Node to build the absolute path to.\r
+ Must be a root node, or a namespace node.\r
+ @param [out] Buffer Buffer to write the path to.\r
+ 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 pathname.\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
+AmlGetAslPathName (\r
+ IN AML_NODE_HEADER * Node,\r
+ OUT CHAR8 * Buffer,\r
+ IN OUT UINT32 * BufferSize\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ // Backward stream used to build the raw AML absolute path to the node.\r
+ AML_STREAM RawAmlAbsPathBStream;\r
+ CHAR8 * RawAmlAbsPathBuffer;\r
+ UINT32 RawAmlAbsPathBufferSize;\r
+\r
+ CHAR8 * AmlPathName;\r
+ CHAR8 * AslPathName;\r
+ UINT32 AslPathNameSize;\r
+\r
+ UINT32 Root;\r
+ UINT32 ParentPrefix;\r
+ UINT32 SegCount;\r
+\r
+ if ((!IS_AML_ROOT_NODE (Node) &&\r
+ !AmlNodeHasAttribute (\r
+ (CONST AML_OBJECT_NODE*)Node,\r
+ AML_IN_NAMESPACE)) ||\r
+ (BufferSize == NULL)) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ AslPathName = NULL;\r
+\r
+ // Allocate a Stream to get the raw AML absolute pathname.\r
+ RawAmlAbsPathBufferSize = MAX_AML_NAMESTRING_SIZE;\r
+ RawAmlAbsPathBuffer = AllocateZeroPool (RawAmlAbsPathBufferSize);\r
+ if (RawAmlAbsPathBuffer == NULL) {\r
+ ASSERT (0);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Status = AmlStreamInit (\r
+ &RawAmlAbsPathBStream,\r
+ (UINT8*)RawAmlAbsPathBuffer,\r
+ RawAmlAbsPathBufferSize,\r
+ EAmlStreamDirectionBackward\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ goto exit_handler;\r
+ }\r
+\r
+ // Get the raw pathname of the Node. The raw pathname being an\r
+ // AML NameString without the RootChar and prefix byte.\r
+ // It is a list of concatenated NameSegs.\r
+ Status = AmlGetRawNameSpacePath (Node, 0, &RawAmlAbsPathBStream);\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ goto exit_handler;\r
+ }\r
+\r
+ // Add the RootChar and prefix byte.\r
+ Status = AmlAddPrefix (&RawAmlAbsPathBStream);\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ goto exit_handler;\r
+ }\r
+\r
+ AmlPathName = (CHAR8*)AmlStreamGetCurrPos (&RawAmlAbsPathBStream);\r
+\r
+ // Analyze the NameString.\r
+ Status = AmlParseNameStringInfo (\r
+ (CONST CHAR8*)AmlPathName,\r
+ &Root,\r
+ &ParentPrefix,\r
+ &SegCount\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ goto exit_handler;\r
+ }\r
+\r
+ // Compute the size the ASL pathname will take.\r
+ AslPathNameSize = AslComputeNameStringSize (Root, ParentPrefix, SegCount);\r
+ if (AslPathNameSize == 0) {\r
+ ASSERT (0);\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto exit_handler;\r
+ }\r
+\r
+ // Input Buffer is large enough. Copy the pathname if the Buffer is valid.\r
+ if ((Buffer != NULL) && (AslPathNameSize <= *BufferSize)) {\r
+ Status = ConvertAmlNameToAslName (AmlPathName, &AslPathName);\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto exit_handler;\r
+ }\r
+\r
+ CopyMem (Buffer, AslPathName, AslPathNameSize);\r
+ }\r
+\r
+ *BufferSize = AslPathNameSize;\r
+\r
+exit_handler:\r
+ // Free allocated memory.\r
+ FreePool (RawAmlAbsPathBuffer);\r
+ if (AslPathName != NULL) {\r
+ FreePool (AslPathName);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+#if !defined (MDEPKG_NDEBUG)\r
+\r
+/** Recursively print the pathnames in the AML namespace in Node's branch.\r
+\r
+ @param [in] Node Pointer to a node.\r
+ @param [in] Context An empty forward stream holding a pre-allocated\r
+ buffer. This prevents from having to do multiple\r
+ allocations during the enumeration.\r
+ @param [in, out] Status At entry, contains the status returned by the\r
+ last call to this exact function during the\r
+ enumeration.\r
+ As exit, contains the returned status of the\r
+ call to this function.\r
+ Optional, can be NULL.\r
+\r
+ @retval TRUE if the enumeration can continue or has finished without\r
+ interruption.\r
+ @retval FALSE if the enumeration needs to stopped or has stopped.\r
+**/\r
+STATIC\r
+BOOLEAN\r
+EFIAPI\r
+AmlDbgPrintNameSpaceCallback (\r
+ IN AML_NODE_HEADER * Node,\r
+ IN VOID * Context,\r
+ IN OUT EFI_STATUS * Status OPTIONAL\r
+ )\r
+{\r
+ BOOLEAN ContinueEnum;\r
+ EFI_STATUS Status1;\r
+\r
+ AML_STREAM * CurrNodePathFStream;\r
+ CHAR8 * CurrNodePathBuffer;\r
+ UINT32 CurrNodePathBufferSize;\r
+\r
+ ContinueEnum = TRUE;\r
+ Status1 = EFI_SUCCESS;\r
+\r
+ if (!IS_AML_NODE_VALID (Node) ||\r
+ (Context == NULL)) {\r
+ ASSERT (0);\r
+ Status1 = EFI_INVALID_PARAMETER;\r
+ ContinueEnum = FALSE;\r
+ goto exit_handler;\r
+ }\r
+\r
+ if (!IS_AML_ROOT_NODE (Node) &&\r
+ !AmlNodeHasAttribute (\r
+ (CONST AML_OBJECT_NODE*)Node,\r
+ AML_IN_NAMESPACE)) {\r
+ // Skip this node and continue enumeration.\r
+ goto exit_handler;\r
+ }\r
+\r
+ if (IS_AML_ROOT_NODE (Node)) {\r
+ DEBUG ((DEBUG_INFO, "\\\n"));\r
+ } else if (AmlNodeHasAttribute (\r
+ (CONST AML_OBJECT_NODE*)Node,\r
+ AML_IN_NAMESPACE)) {\r
+\r
+ CurrNodePathFStream = (AML_STREAM*)Context;\r
+\r
+ // Check the Context's content.\r
+ if (!IS_STREAM (CurrNodePathFStream) ||\r
+ IS_END_OF_STREAM (CurrNodePathFStream) ||\r
+ !IS_STREAM_FORWARD (CurrNodePathFStream)) {\r
+ ASSERT (0);\r
+ Status1 = EFI_INVALID_PARAMETER;\r
+ ContinueEnum = FALSE;\r
+ goto exit_handler;\r
+ }\r
+\r
+ CurrNodePathBuffer = (CHAR8*)AmlStreamGetBuffer (CurrNodePathFStream);\r
+ CurrNodePathBufferSize = AmlStreamGetMaxBufferSize (CurrNodePathFStream);\r
+\r
+ Status1 = AmlGetAslPathName (\r
+ (AML_NODE_HEADER*)Node,\r
+ CurrNodePathBuffer,\r
+ &CurrNodePathBufferSize\r
+ );\r
+ if (EFI_ERROR (Status1)) {\r
+ ASSERT (0);\r
+ ContinueEnum = FALSE;\r
+ goto exit_handler;\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "%a\n", CurrNodePathBuffer));\r
+\r
+ } else {\r
+ ASSERT (0);\r
+ Status1 = EFI_INVALID_PARAMETER;\r
+ ContinueEnum = FALSE;\r
+ }\r
+\r
+exit_handler:\r
+ if (Status != NULL) {\r
+ *Status = Status1;\r
+ }\r
+\r
+ return ContinueEnum;\r
+}\r
+\r
+/** Print the absolute pathnames in the AML namespace of\r
+ all the nodes in the tree starting from the Root node.\r
+\r
+ @param [in] RootNode Pointer to a root node.\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
+AmlDbgPrintNameSpace (\r
+ IN AML_ROOT_NODE * RootNode\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ AML_STREAM CurrNodePathFStream;\r
+ CHAR8 * CurrNodePathBuffer;\r
+ UINT32 CurrNodePathBufferSize;\r
+\r
+ if (!IS_AML_ROOT_NODE (RootNode)) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "AmlNameSpace: AML namespace:\n"));\r
+\r
+ // Allocate memory to build the absolute ASL path to each node.\r
+ CurrNodePathBufferSize = MAX_AML_NAMESTRING_SIZE;\r
+ CurrNodePathBuffer = AllocateZeroPool (CurrNodePathBufferSize);\r
+ if (CurrNodePathBuffer == NULL) {\r
+ ASSERT (0);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ // An empty forward stream holding a pre-allocated buffer is used\r
+ // to avoid multiple allocations during the enumeration.\r
+ Status = AmlStreamInit (\r
+ &CurrNodePathFStream,\r
+ (UINT8*)CurrNodePathBuffer,\r
+ CurrNodePathBufferSize,\r
+ EAmlStreamDirectionForward\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ goto exit_handler;\r
+ }\r
+\r
+ AmlEnumTree (\r
+ (AML_NODE_HEADER*)RootNode,\r
+ AmlDbgPrintNameSpaceCallback,\r
+ (VOID*)&CurrNodePathFStream,\r
+ &Status\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+exit_handler:\r
+ FreePool (CurrNodePathBuffer);\r
+\r
+ return Status;\r
+}\r
+\r
+#endif // MDEPKG_NDEBUG\r
+\r
+/** Callback function to find the node corresponding to an absolute pathname.\r
+\r
+ For each namespace node, build its raw AML absolute path. Then compare this\r
+ path with the raw AML absolute path of the search node available in the\r
+ Context.\r
+\r
+ @param [in] Node Pointer to the node to whose pathname is being\r
+ tested.\r
+ @param [in, out] Context A pointer to AML_PATH_SEARCH_CONTEXT that has:\r
+ - The searched path stored in a stream;\r
+ - An empty stream to query the pathname of the\r
+ probed node;\r
+ - A node pointer to store the searched node\r
+ if found.\r
+ @param [in, out] Status At entry, contains the status returned by the\r
+ last call to this exact function during the\r
+ enumeration.\r
+ As exit, contains the returned status of the\r
+ call to this function.\r
+ Optional, can be NULL.\r
+\r
+ @retval TRUE if the enumeration can continue or has finished without\r
+ interruption.\r
+ @retval FALSE if the enumeration needs to stopped or has stopped.\r
+**/\r
+STATIC\r
+BOOLEAN\r
+EFIAPI\r
+AmlEnumeratePathCallback (\r
+ IN AML_NODE_HEADER * Node,\r
+ IN OUT VOID * Context,\r
+ IN OUT EFI_STATUS * Status OPTIONAL\r
+)\r
+{\r
+ BOOLEAN ContinueEnum;\r
+ EFI_STATUS Status1;\r
+\r
+ AML_PATH_SEARCH_CONTEXT * PathSearchContext;\r
+\r
+ AML_STREAM * SearchPathBStream;\r
+ CHAR8 * SearchedPath;\r
+\r
+ AML_STREAM * CurrNodePathBStream;\r
+ CHAR8 * CurrNodePath;\r
+ UINT32 CurrNodePathSize;\r
+\r
+ ContinueEnum = TRUE;\r
+ Status1 = EFI_SUCCESS;\r
+\r
+ if (!IS_AML_NODE_VALID (Node) ||\r
+ (Context == NULL)) {\r
+ ASSERT (0);\r
+ Status1 = EFI_INVALID_PARAMETER;\r
+ ContinueEnum = FALSE;\r
+ goto exit_handler;\r
+ }\r
+\r
+ if (!AmlNodeHasAttribute (\r
+ (CONST AML_OBJECT_NODE*)Node,\r
+ AML_IN_NAMESPACE)) {\r
+ goto exit_handler;\r
+ }\r
+\r
+ PathSearchContext = (AML_PATH_SEARCH_CONTEXT*)Context;\r
+ SearchPathBStream = PathSearchContext->SearchPathBStream;\r
+ CurrNodePathBStream = PathSearchContext->CurrNodePathBStream;\r
+\r
+ // Check the Context's content.\r
+ if (!IS_STREAM (SearchPathBStream) ||\r
+ IS_END_OF_STREAM (SearchPathBStream) ||\r
+ !IS_STREAM_BACKWARD (SearchPathBStream) ||\r
+ !IS_STREAM (CurrNodePathBStream) ||\r
+ IS_END_OF_STREAM (CurrNodePathBStream) ||\r
+ !IS_STREAM_BACKWARD (CurrNodePathBStream)) {\r
+ ASSERT (0);\r
+ Status1 = EFI_INVALID_PARAMETER;\r
+ ContinueEnum = FALSE;\r
+ goto exit_handler;\r
+ }\r
+\r
+ CurrNodePathSize = AmlStreamGetMaxBufferSize (CurrNodePathBStream);\r
+ if (CurrNodePathSize == 0) {\r
+ ASSERT (0);\r
+ Status1 = EFI_INVALID_PARAMETER;\r
+ ContinueEnum = FALSE;\r
+ goto exit_handler;\r
+ }\r
+\r
+ SearchedPath = (CHAR8*)AmlStreamGetCurrPos (SearchPathBStream);\r
+ CurrNodePath = (CHAR8*)AmlStreamGetCurrPos (CurrNodePathBStream);\r
+\r
+ // Get the raw AML absolute pathname of the current node.\r
+ Status1 = AmlGetRawNameSpacePath (Node, 0, CurrNodePathBStream);\r
+ if (EFI_ERROR (Status1)) {\r
+ ASSERT (0);\r
+ ContinueEnum = FALSE;\r
+ goto exit_handler;\r
+ }\r
+\r
+ DEBUG ((\r
+ DEBUG_VERBOSE,\r
+ "AmlNameSpace: "\r
+ "Comparing search path with current node path.\n"\r
+ ));\r
+ DEBUG ((DEBUG_VERBOSE, "Search path:"));\r
+ AmlDbgPrintChars (\r
+ DEBUG_VERBOSE,\r
+ (CHAR8*)AmlStreamGetCurrPos (SearchPathBStream),\r
+ AmlStreamGetIndex (SearchPathBStream)\r
+ );\r
+ DEBUG ((DEBUG_VERBOSE, "\nPath of the current node: "));\r
+ AmlDbgPrintChars (\r
+ DEBUG_VERBOSE,\r
+ (CHAR8*)AmlStreamGetCurrPos (CurrNodePathBStream),\r
+ AmlStreamGetIndex (CurrNodePathBStream)\r
+ );\r
+ DEBUG ((DEBUG_VERBOSE, "\n"));\r
+\r
+ // Compare the searched path and Node's path.\r
+ if ((AmlStreamGetIndex (CurrNodePathBStream) ==\r
+ AmlStreamGetIndex (SearchPathBStream)) &&\r
+ (CompareMem (\r
+ AmlStreamGetCurrPos (CurrNodePathBStream),\r
+ AmlStreamGetCurrPos (SearchPathBStream),\r
+ AmlStreamGetIndex (SearchPathBStream)) == 0)) {\r
+ Status1 = EFI_SUCCESS;\r
+ ContinueEnum = FALSE;\r
+ PathSearchContext->OutNode = Node;\r
+ } else {\r
+ // If the paths don't match, reset the CurrNodePathStream's content.\r
+ Status1 = AmlStreamReset (CurrNodePathBStream);\r
+ if (EFI_ERROR (Status1)) {\r
+ ASSERT (0);\r
+ ContinueEnum = FALSE;\r
+ }\r
+ }\r
+\r
+exit_handler:\r
+ if (Status != NULL) {\r
+ *Status = Status1;\r
+ }\r
+\r
+ return ContinueEnum;\r
+}\r
+\r
+/** Build a raw AML absolute path from a reference node and a relative\r
+ ASL path.\r
+\r
+ The AslPath can be a relative path or an absolute path.\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
+ @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".\r
+ @param [in, out] RawAmlAbsSearchPathBStream Backward stream to write the\r
+ raw absolute AML path of the\r
+ searched node.\r
+ The stream must not be at\r
+ its end.\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
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+AmlBuildAbsoluteAmlPath (\r
+ IN AML_NODE_HEADER * ReferenceNode,\r
+ IN CHAR8 * AslPath,\r
+ IN OUT AML_STREAM * RawAmlAbsSearchPathBStream\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ CHAR8 * AmlPath;\r
+\r
+ UINT32 AmlNameStringSize;\r
+ UINT32 Root;\r
+ UINT32 ParentPrefix;\r
+ UINT32 SegCount;\r
+\r
+ if ((!IS_AML_ROOT_NODE (ReferenceNode) &&\r
+ !AmlNodeHasAttribute (\r
+ (CONST AML_OBJECT_NODE*)ReferenceNode,\r
+ AML_IN_NAMESPACE)) ||\r
+ (AslPath == NULL) ||\r
+ !IS_STREAM (RawAmlAbsSearchPathBStream) ||\r
+ IS_END_OF_STREAM (RawAmlAbsSearchPathBStream) ||\r
+ !IS_STREAM_BACKWARD (RawAmlAbsSearchPathBStream)) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ // 1. Validate, analyze and convert the AslPath to an AmlPath.\r
+ Status = ConvertAslNameToAmlName (AslPath, &AmlPath);\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ return Status;\r
+ }\r
+\r
+ Status = AmlParseNameStringInfo (AmlPath, &Root, &ParentPrefix, &SegCount);\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ goto exit_handler;\r
+ }\r
+\r
+ // Not possible to go beyond the root.\r
+ if (IS_AML_ROOT_NODE (ReferenceNode) && (ParentPrefix != 0)) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ ASSERT (0);\r
+ goto exit_handler;\r
+ }\r
+\r
+ AmlNameStringSize = AmlComputeNameStringSize (Root, ParentPrefix, SegCount);\r
+ if (AmlNameStringSize == 0) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ ASSERT (0);\r
+ goto exit_handler;\r
+ }\r
+\r
+ // 2.1. Write the AML path to the stream.\r
+ Status = AmlStreamWrite (\r
+ RawAmlAbsSearchPathBStream,\r
+ (CONST UINT8*)AmlPath,\r
+ AmlNameStringSize\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ goto exit_handler;\r
+ }\r
+\r
+ // 2.2. Then remove the AML prefix (root char, parent prefix, etc.)\r
+ // to obtain a raw AML NameString. Raw AML NameString are easier\r
+ // to manipulate.\r
+ Status = AmlRemovePrefix (RawAmlAbsSearchPathBStream);\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ goto exit_handler;\r
+ }\r
+\r
+ // 3. If AslPath is a relative path and the reference Node is not\r
+ // the root node, fill the Stream with the absolute path to the\r
+ // reference node.\r
+ if ((Root == 0) && !IS_AML_ROOT_NODE (ReferenceNode)) {\r
+ Status = AmlGetRawNameSpacePath (\r
+ ReferenceNode,\r
+ ParentPrefix,\r
+ RawAmlAbsSearchPathBStream\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ }\r
+ }\r
+\r
+exit_handler:\r
+ // Free allocated memory.\r
+ FreePool (AmlPath);\r
+\r
+ return Status;\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
+ @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_HEADER * ReferenceNode,\r
+ IN CHAR8 * AslPath,\r
+ OUT AML_NODE_HEADER ** OutNode\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ AML_PATH_SEARCH_CONTEXT PathSearchContext;\r
+ AML_ROOT_NODE * RootNode;\r
+\r
+ // Backward stream used to build the raw AML absolute path to the searched\r
+ // node.\r
+ AML_STREAM RawAmlAbsSearchPathBStream;\r
+ CHAR8 * RawAmlAbsSearchPathBuffer;\r
+ UINT32 RawAmlAbsSearchPathBufferSize;\r
+\r
+ // Backward stream used to store the raw AML absolute path of the node\r
+ // currently enumerated in the tree. This path can then be compared to the\r
+ // RawAmlAbsSearchPath.\r
+ AML_STREAM RawAmlAbsCurrNodePathBStream;\r
+ CHAR8 * RawAmlAbsCurrNodePathBuffer;\r
+ UINT32 RawAmlAbsCurrNodePathBufferSize;\r
+\r
+ if ((!IS_AML_ROOT_NODE (ReferenceNode) &&\r
+ !AmlNodeHasAttribute (\r
+ (CONST AML_OBJECT_NODE*)ReferenceNode,\r
+ AML_IN_NAMESPACE)) ||\r
+ (AslPath == NULL) ||\r
+ (OutNode == NULL)) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ *OutNode = NULL;\r
+ RawAmlAbsCurrNodePathBuffer = NULL;\r
+\r
+ // 1. Build a raw absolute AML path from the reference node and the ASL\r
+ // path. For this:\r
+ // 1.1. First initialize a backward stream.\r
+ RawAmlAbsSearchPathBufferSize = MAX_AML_NAMESTRING_SIZE;\r
+ RawAmlAbsSearchPathBuffer = AllocateZeroPool (RawAmlAbsSearchPathBufferSize);\r
+ if (RawAmlAbsSearchPathBuffer == NULL) {\r
+ ASSERT (0);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Status = AmlStreamInit (\r
+ &RawAmlAbsSearchPathBStream,\r
+ (UINT8*)RawAmlAbsSearchPathBuffer,\r
+ RawAmlAbsSearchPathBufferSize,\r
+ EAmlStreamDirectionBackward\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ goto exit_handler;\r
+ }\r
+\r
+ // 1.2. Then build the raw AML absolute path.\r
+ Status = AmlBuildAbsoluteAmlPath (\r
+ ReferenceNode,\r
+ AslPath,\r
+ &RawAmlAbsSearchPathBStream\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ goto exit_handler;\r
+ }\r
+\r
+ // 2. Find the root node by climbing up the tree from the reference node.\r
+ RootNode = AmlGetRootNode (ReferenceNode);\r
+ if (RootNode == NULL) {\r
+ ASSERT (0);\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto exit_handler;\r
+ }\r
+\r
+ // 3. If the searched node is the root node, return.\r
+ // For the Root Node there is no NameSegs so the length of\r
+ // the stream will be zero.\r
+ if (AmlStreamGetIndex (&RawAmlAbsSearchPathBStream) == 0) {\r
+ *OutNode = (AML_NODE_HEADER*)RootNode;\r
+ Status = EFI_SUCCESS;\r
+ goto exit_handler;\r
+ }\r
+\r
+ // 4. Create a backward stream large enough to hold the current node path\r
+ // during enumeration. This prevents from doing multiple allocation/free\r
+ // operations.\r
+ RawAmlAbsCurrNodePathBufferSize = MAX_ASL_NAMESTRING_SIZE;\r
+ RawAmlAbsCurrNodePathBuffer = AllocateZeroPool (\r
+ RawAmlAbsCurrNodePathBufferSize\r
+ );\r
+ if (RawAmlAbsCurrNodePathBuffer == NULL) {\r
+ ASSERT (0);\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto exit_handler;\r
+ }\r
+\r
+ Status = AmlStreamInit (\r
+ &RawAmlAbsCurrNodePathBStream,\r
+ (UINT8*)RawAmlAbsCurrNodePathBuffer,\r
+ RawAmlAbsCurrNodePathBufferSize,\r
+ EAmlStreamDirectionBackward\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ goto exit_handler;\r
+ }\r
+\r
+ // 5. Fill a path search context structure with:\r
+ // - SearchPathStream: backward stream containing the raw absolute AML\r
+ // path to the searched node;\r
+ // - CurrNodePathStream: backward stream containing the raw absolute AML\r
+ // of the node currently being enumerated;\r
+ // - OutNode: node pointer to the store the potentially found node.\r
+ PathSearchContext.SearchPathBStream = &RawAmlAbsSearchPathBStream;\r
+ PathSearchContext.CurrNodePathBStream = &RawAmlAbsCurrNodePathBStream;\r
+ PathSearchContext.OutNode = NULL;\r
+\r
+ // 6. Iterate through the namespace nodes of the tree.\r
+ // For each namespace node, build its raw AML absolute path. Then compare\r
+ // it with the search path.\r
+ AmlEnumTree (\r
+ (AML_NODE_HEADER*)RootNode,\r
+ AmlEnumeratePathCallback,\r
+ (VOID*)&PathSearchContext,\r
+ &Status\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ goto exit_handler;\r
+ }\r
+\r
+ *OutNode = PathSearchContext.OutNode;\r
+ if (*OutNode == NULL) {\r
+ Status = EFI_NOT_FOUND;\r
+ }\r
+\r
+exit_handler:\r
+ // Free allocated memory.\r
+ FreePool (RawAmlAbsSearchPathBuffer);\r
+ if (RawAmlAbsCurrNodePathBuffer != NULL) {\r
+ FreePool (RawAmlAbsCurrNodePathBuffer);\r
+ }\r
+\r
+ return Status;\r
+}\r