public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Sami Mujawar" <sami.mujawar@arm.com>
To: <devel@edk2.groups.io>
Cc: Sami Mujawar <sami.mujawar@arm.com>, <Alexei.Fedorov@arm.com>,
	<pierre.gondois@arm.com>, <ard.biesheuvel@arm.com>,
	<Matteo.Carlini@arm.com>, <Ben.Adderson@arm.com>, <nd@arm.com>
Subject: [PATCH v1 15/30] DynamicTablesPkg: AML ACPI Namespace interface
Date: Wed, 12 Aug 2020 16:22:21 +0100	[thread overview]
Message-ID: <20200812152236.31164-16-sami.mujawar@arm.com> (raw)
In-Reply-To: <20200812152236.31164-1-sami.mujawar@arm.com>

From: Pierre Gondois <pierre.gondois@arm.com>

AML is a declarative language that is processed by the
ACPI AML interpreter. The ACPI AML interpreter will
compile the set of declarations into the ACPI Namespace
at definition block load time.

The hardware information described in AML is effectively
mapped in the ACPI Namespace. The AML ACPI namespace
interface implement the functionality to search the ACPI
Namespace. Example: The AmlFindNode() can be used to locate
a device node in the ACPI namespace using an ASL path as
the search input.

Signed-off-by: Pierre Gondois <pierre.gondois@arm.com>
Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
---
 DynamicTablesPkg/Library/Common/AmlLib/NameSpace/AmlNameSpace.c | 1501 ++++++++++++++++++++
 DynamicTablesPkg/Library/Common/AmlLib/NameSpace/AmlNameSpace.h |   74 +
 2 files changed, 1575 insertions(+)

diff --git a/DynamicTablesPkg/Library/Common/AmlLib/NameSpace/AmlNameSpace.c b/DynamicTablesPkg/Library/Common/AmlLib/NameSpace/AmlNameSpace.c
new file mode 100644
index 0000000000000000000000000000000000000000..dc373748903dd55fa4492874329f2b433c698c02
--- /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 0000000000000000000000000000000000000000..3d8ebc8b182983606af7e7ddfe3078fd729fb5b6
--- /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_
-- 
'Guid(CE165669-3EF3-493F-B85D-6190EE5B9759)'


  parent reply	other threads:[~2020-08-12 15:23 UTC|newest]

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-08-12 15:22 [PATCH v1 00/30] Add Dynamic AML generation support Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 01/30] DynamicTablesPkg: Introduction to Dynamic AML Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 02/30] DynamicTablesPkg: AmlLib definitions Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 03/30] DynamicTablesPkg: AML grammar definition Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 04/30] DynamicTablesPkg: AML node definitions Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 05/30] DynamicTablesPkg: AML tree interface Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 06/30] DynamicTablesPkg: AML tree enumerator Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 07/30] DynamicTablesPkg: AML tree traversal Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 08/30] DynamicTablesPkg: AML tree iterator Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 09/30] DynamicTablesPkg: AML tree/node cloning Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 10/30] DynamicTablesPkg: AML utility interfaces Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 11/30] DynamicTablesPkg: AML and ASL string helper Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 12/30] DynamicTablesPkg: AML stream interface Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 13/30] DynamicTablesPkg: AML serialise interface Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 14/30] DynamicTablesPkg: AML debug logging Sami Mujawar
2020-08-12 15:22 ` Sami Mujawar [this message]
2020-08-12 15:22 ` [PATCH v1 16/30] DynamicTablesPkg: AML Parser Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 17/30] DynamicTablesPkg: AML resource data helper Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 18/30] DynamicTablesPkg: AML resource data parser Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 19/30] DynamicTablesPkg: AML Method parser Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 20/30] DynamicTablesPkg: AML Field list parser Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 21/30] DynamicTablesPkg: AML Codegen Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 22/30] DynamicTablesPkg: AML Resource Data Codegen Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 23/30] DynamicTablesPkg: AML Core interface Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 24/30] DynamicTablesPkg: AmlLib APIs Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 25/30] DynamicTablesPkg: Dynamic AML: Add AmlLib library Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 26/30] DynamicTablesPkg: Add AsciiFromHex helper function Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 27/30] DynamicTablesPkg: SSDT Serial Port Fixup library Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 28/30] DynamicTablesPkg: SSDT Serial Port generator Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 29/30] DynamicTablesPkg: Add SSDT Serial port for SPCR Sami Mujawar
2020-08-12 15:22 ` [PATCH v1 30/30] DynamicTablesPkg: Add SSDT Serial port for DBG2 Sami Mujawar
2020-08-13 15:16 ` [edk2-devel] [PATCH v1 00/30] Add Dynamic AML generation support Alexei Fedorov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200812152236.31164-16-sami.mujawar@arm.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox