Building the DynamicTablesPkg for a NOOPT target
fails because unused variables are set.
Remove these variables.
Fixes: d9800046ea
Reported-by: Leif Lindholm <leif@nuviainc.com>
Signed-off-by: Pierre Gondois <Pierre.Gondois@arm.com>
Reviewed-by: Leif Lindholm <leif@nuviainc.com>
Reviewed-by: Sami Mujawar <sami.mujawar@arm.com>
		
	
		
			
				
	
	
		
			1497 lines
		
	
	
		
			48 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1497 lines
		
	
	
		
			48 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   AML NameSpace.
 | |
| 
 | |
|   Copyright (c) 2019 - 2021, 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;
 | |
| 
 | |
|   AML_STREAM                * CurrNodePathBStream;
 | |
|   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;
 | |
|   }
 | |
| 
 | |
|   // 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:"));
 | |
|   AMLDBG_PRINT_CHARS (
 | |
|     DEBUG_VERBOSE,
 | |
|     (CHAR8*)AmlStreamGetCurrPos (SearchPathBStream),
 | |
|     AmlStreamGetIndex (SearchPathBStream)
 | |
|     );
 | |
|   DEBUG ((DEBUG_VERBOSE, "\nPath of the current node: "));
 | |
|   AMLDBG_PRINT_CHARS (
 | |
|     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;
 | |
| }
 |