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