REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3737 Apply uncrustify changes to .c/.h files in the DynamicTablesPkg package Cc: Andrew Fish <afish@apple.com> Cc: Leif Lindholm <leif@nuviainc.com> Cc: Michael D Kinney <michael.d.kinney@intel.com> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com> Reviewed-by: Sami Mujawar <sami.mujawar@arm.com>
		
			
				
	
	
		
			1488 lines
		
	
	
		
			48 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1488 lines
		
	
	
		
			48 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   AML Method Parser.
 | |
| 
 | |
|   Copyright (c) 2020, Arm Limited. All rights reserved.<BR>
 | |
| 
 | |
|   SPDX-License-Identifier: BSD-2-Clause-Patent
 | |
| **/
 | |
| 
 | |
| #include <Parser/AmlMethodParser.h>
 | |
| 
 | |
| #include <AmlCoreInterface.h>
 | |
| #include <AmlDbgPrint/AmlDbgPrint.h>
 | |
| #include <NameSpace/AmlNameSpace.h>
 | |
| #include <Parser/AmlParser.h>
 | |
| #include <Tree/AmlNode.h>
 | |
| #include <Tree/AmlTree.h>
 | |
| #include <String/AmlString.h>
 | |
| 
 | |
| /** Delete a namespace reference node and its pathname.
 | |
| 
 | |
|   It is the caller's responsibility to check the NameSpaceRefNode has been
 | |
|   removed from any list the node is part of.
 | |
| 
 | |
|   @param  [in]  NameSpaceRefNode   Pointer to an AML_NAMESPACE_REF_NODE.
 | |
| 
 | |
|   @retval EFI_SUCCESS             The function completed successfully.
 | |
|   @retval EFI_INVALID_PARAMETER   Invalid parameter.
 | |
| **/
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| AmlDeleteNameSpaceRefNode (
 | |
|   IN  AML_NAMESPACE_REF_NODE  *NameSpaceRefNode
 | |
|   )
 | |
| {
 | |
|   if (NameSpaceRefNode == NULL) {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if (NameSpaceRefNode->RawAbsolutePath != NULL) {
 | |
|     FreePool ((CHAR8 *)NameSpaceRefNode->RawAbsolutePath);
 | |
|   } else {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   FreePool (NameSpaceRefNode);
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /** Delete a list of namespace reference nodes.
 | |
| 
 | |
|   @param  [in]  NameSpaceRefList    List of namespace reference nodes.
 | |
| 
 | |
|   @retval EFI_SUCCESS             The function completed successfully.
 | |
|   @retval EFI_INVALID_PARAMETER   Invalid parameter.
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| AmlDeleteNameSpaceRefList (
 | |
|   IN  LIST_ENTRY  *NameSpaceRefList
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   LIST_ENTRY  *CurrentLink;
 | |
| 
 | |
|   if (NameSpaceRefList == NULL) {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   while (!IsListEmpty (NameSpaceRefList)) {
 | |
|     CurrentLink = NameSpaceRefList->ForwardLink;
 | |
|     RemoveEntryList (CurrentLink);
 | |
|     Status = AmlDeleteNameSpaceRefNode (
 | |
|                (AML_NAMESPACE_REF_NODE *)CurrentLink
 | |
|                );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       ASSERT (0);
 | |
|       return Status;
 | |
|     }
 | |
|   } // while
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /** Create an AML_NAMESPACE_REF_NODE.
 | |
| 
 | |
|   A Buffer is allocated to store the raw AML absolute path.
 | |
| 
 | |
|   @param  [in]  ObjectNode          Node being part of the namespace.
 | |
|                                     Must be have the AML_IN_NAMESPACE
 | |
|                                     attribute.
 | |
|   @param  [in]  RawAbsolutePath     AML raw absolute path of the ObjectNode.
 | |
|                                     A raw NameString is a concatenated list
 | |
|                                     of 4 chars long names.
 | |
|   @param  [in]  RawAbsolutePathSize Size of the RawAbsolutePath buffer.
 | |
|   @param  [out] NameSpaceRefNodePtr The created AML_METHOD_REF_NODE.
 | |
| 
 | |
|   @retval EFI_SUCCESS             The function completed successfully.
 | |
|   @retval EFI_INVALID_PARAMETER   Invalid parameter.
 | |
|   @retval EFI_OUT_OF_RESOURCES    Could not allocate memory.
 | |
| **/
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| AmlCreateMethodRefNode (
 | |
|   IN  CONST AML_OBJECT_NODE         *ObjectNode,
 | |
|   IN  CONST CHAR8                   *RawAbsolutePath,
 | |
|   IN        UINT32                  RawAbsolutePathSize,
 | |
|   OUT       AML_NAMESPACE_REF_NODE  **NameSpaceRefNodePtr
 | |
|   )
 | |
| {
 | |
|   AML_NAMESPACE_REF_NODE  *NameSpaceRefNode;
 | |
| 
 | |
|   if (!AmlNodeHasAttribute (ObjectNode, AML_IN_NAMESPACE) ||
 | |
|       (RawAbsolutePath == NULL)                           ||
 | |
|       (RawAbsolutePathSize == 0)                          ||
 | |
|       (NameSpaceRefNodePtr == NULL))
 | |
|   {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   NameSpaceRefNode = AllocateZeroPool (sizeof (AML_NAMESPACE_REF_NODE));
 | |
|   if (NameSpaceRefNode == NULL) {
 | |
|     ASSERT (0);
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   NameSpaceRefNode->RawAbsolutePathSize = RawAbsolutePathSize;
 | |
|   NameSpaceRefNode->RawAbsolutePath     = AllocateCopyPool (
 | |
|                                             RawAbsolutePathSize,
 | |
|                                             RawAbsolutePath
 | |
|                                             );
 | |
|   if (NameSpaceRefNode->RawAbsolutePath == NULL) {
 | |
|     FreePool (NameSpaceRefNode);
 | |
|     ASSERT (0);
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   InitializeListHead (&NameSpaceRefNode->Link);
 | |
| 
 | |
|   NameSpaceRefNode->NodeRef = ObjectNode;
 | |
|   *NameSpaceRefNodePtr      = NameSpaceRefNode;
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| #if !defined (MDEPKG_NDEBUG)
 | |
| 
 | |
| /** Print the list of raw absolute paths of the NameSpace reference list.
 | |
| 
 | |
|   @param  [in]  NameSpaceRefList    List of NameSpace reference nodes.
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| AmlDbgPrintNameSpaceRefList (
 | |
|   IN  CONST LIST_ENTRY  *NameSpaceRefList
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY              *CurrLink;
 | |
|   AML_NAMESPACE_REF_NODE  *CurrNameSpaceNode;
 | |
| 
 | |
|   if (NameSpaceRefList == NULL) {
 | |
|     ASSERT (0);
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   DEBUG ((DEBUG_INFO, "AmlMethodParser: List of available raw AML paths:\n"));
 | |
| 
 | |
|   CurrLink = NameSpaceRefList->ForwardLink;
 | |
|   while (CurrLink != NameSpaceRefList) {
 | |
|     CurrNameSpaceNode = (AML_NAMESPACE_REF_NODE *)CurrLink;
 | |
| 
 | |
|     AMLDBG_PRINT_CHARS (
 | |
|       DEBUG_INFO,
 | |
|       CurrNameSpaceNode->RawAbsolutePath,
 | |
|       CurrNameSpaceNode->RawAbsolutePathSize
 | |
|       );
 | |
|     DEBUG ((DEBUG_INFO, "\n"));
 | |
| 
 | |
|     CurrLink = CurrLink->ForwardLink;
 | |
|   }
 | |
| 
 | |
|   DEBUG ((DEBUG_INFO, "\n"));
 | |
| }
 | |
| 
 | |
| #endif // MDEPKG_NDEBUG
 | |
| 
 | |
| /** From a forward stream pointing to a NameString,
 | |
|     initialize a raw backward stream.
 | |
| 
 | |
|         StartOfStream
 | |
|   Fstream: CurrPos                                 EndOfStream
 | |
|              v                                        v
 | |
|              +-----------------------------------------+
 | |
|              |^^^[Multi-name prefix]AAAA.BBBB.CCCC     |
 | |
|              +-----------------------------------------+
 | |
|                                     ^            ^
 | |
|   RawPathNameBStream:           EndOfStream    CurrPos
 | |
|                                             StartOfStream
 | |
| 
 | |
|   No memory is allocated when initializing the stream.
 | |
| 
 | |
|   @param  [in]  FStream             Forward stream pointing to a NameString.
 | |
|                                     The stream must not be at its end.
 | |
|   @param  [out] RawPathNameBStream  Backward stream containing the
 | |
|                                     raw AML path.
 | |
| 
 | |
|   @retval EFI_SUCCESS             The function completed successfully.
 | |
|   @retval EFI_INVALID_PARAMETER   Invalid parameter.
 | |
| **/
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| AmlInitRawPathBStream (
 | |
|   IN  CONST AML_STREAM  *FStream,
 | |
|   OUT       AML_STREAM  *RawPathNameBStream
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   UINT8        *RawPathBuffer;
 | |
|   CONST CHAR8  *Buffer;
 | |
| 
 | |
|   UINT32  Root;
 | |
|   UINT32  ParentPrefix;
 | |
|   UINT32  SegCount;
 | |
| 
 | |
|   if (!IS_STREAM (FStream)          ||
 | |
|       IS_END_OF_STREAM (FStream)    ||
 | |
|       !IS_STREAM_FORWARD (FStream) ||
 | |
|       (RawPathNameBStream == NULL))
 | |
|   {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   Buffer = (CONST CHAR8 *)AmlStreamGetCurrPos (FStream);
 | |
|   if (Buffer == NULL) {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   // Parse the NameString information.
 | |
|   Status = AmlParseNameStringInfo (
 | |
|              Buffer,
 | |
|              &Root,
 | |
|              &ParentPrefix,
 | |
|              &SegCount
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     ASSERT (0);
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   // Get the beginning of the raw NameString.
 | |
|   RawPathBuffer = (UINT8 *)AmlGetFirstNameSeg (
 | |
|                              Buffer,
 | |
|                              Root,
 | |
|                              ParentPrefix
 | |
|                              );
 | |
|   if (RawPathBuffer == NULL) {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   // Initialize a backward stream containing the raw path.
 | |
|   Status = AmlStreamInit (
 | |
|              RawPathNameBStream,
 | |
|              RawPathBuffer,
 | |
|              (SegCount * AML_NAME_SEG_SIZE),
 | |
|              EAmlStreamDirectionBackward
 | |
|              );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /** Get the first node in the ParentNode branch that is part of the
 | |
|     AML namespace and has its name defined.
 | |
| 
 | |
|   This is different from getting the first namespace node. This function is
 | |
|   necessary because an absolute path is built while the tree is not complete
 | |
|   yet. The parsing is ongoing.
 | |
| 
 | |
|   For instance, the ASL statement "CreateXXXField ()" adds a field in the
 | |
|   AML namespace, but the name it defines is the last fixed argument of the
 | |
|   corresponding object.
 | |
|   If an AML path is referenced in its first fixed argument, it is not
 | |
|   possible to resolve the name of the CreateXXXField object. However, the AML
 | |
|   path is not part of the scope created by the CreateXXXField object, so this
 | |
|   scope can be skipped.
 | |
| 
 | |
|   In the following ASL code, the method invocation to MET0 is done in the
 | |
|   "CreateField" statement. The "CreateField" statement defines the "FIEL"
 | |
|   path in the AML namespace. However, MET0 must be not be resolved in the
 | |
|   "CreateField" object scope. It needs to be resolved in its parent.
 | |
|   ASL code:
 | |
|   Method (MET0, 0,,, BuffObj) {
 | |
|     Return (Buffer (0x1000) {})
 | |
|   }
 | |
|   CreateField (MET0(), 0x100, 0x4, FIEL)
 | |
| 
 | |
|   @param  [in]  Node          Node to get the first named node from, in
 | |
|                               its hierarchy.
 | |
|   @param  [out] OutNamedNode  First named node in Node's hierarchy.
 | |
| 
 | |
|   @retval EFI_SUCCESS             The function completed successfully.
 | |
|   @retval EFI_INVALID_PARAMETER   Invalid parameter.
 | |
| **/
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| AmlGetFirstNamedAncestorNode (
 | |
|   IN  CONST AML_NODE_HEADER  *Node,
 | |
|   OUT       AML_NODE_HEADER  **OutNamedNode
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS             Status;
 | |
|   CONST AML_NODE_HEADER  *NameSpaceNode;
 | |
| 
 | |
|   if ((!IS_AML_OBJECT_NODE (Node)   &&
 | |
|        !IS_AML_ROOT_NODE (Node))    ||
 | |
|       (OutNamedNode == NULL))
 | |
|   {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   // If Node is not the root node and doesn't have a name defined yet,
 | |
|   // get the ancestor NameSpace node.
 | |
|   while (!IS_AML_ROOT_NODE (Node)             &&
 | |
|          !(AmlNodeHasAttribute (
 | |
|              (CONST AML_OBJECT_NODE *)Node,
 | |
|              AML_IN_NAMESPACE
 | |
|              )               &&
 | |
|            AmlNodeGetName ((CONST AML_OBJECT_NODE *)Node) != NULL))
 | |
|   {
 | |
|     Status = AmlGetFirstAncestorNameSpaceNode (
 | |
|                Node,
 | |
|                (AML_NODE_HEADER **)&NameSpaceNode
 | |
|                );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       ASSERT (0);
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     // The NameSpaceNode may not have its name defined as yet. In this
 | |
|     // case get the next ancestor node.
 | |
|     Node = NameSpaceNode;
 | |
|   }
 | |
| 
 | |
|   *OutNamedNode = (AML_NODE_HEADER *)Node;
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /** From a ParentNode and a forward stream pointing to a relative path,
 | |
|     build a raw AML absolute path and return it in a backward stream.
 | |
| 
 | |
|   No memory is allocated in this function, the out stream must be initialized
 | |
|   with a buffer long enough to hold any raw absolute AML path.
 | |
| 
 | |
|   @param  [in]  ParentNode                  Parent node of the namespace
 | |
|                                             node from which the absolute
 | |
|                                             path is built. ParentNode isn't
 | |
|                                             necessarily a namespace node.
 | |
|                                             Must be a root or an object node.
 | |
|   @param  [in]  PathnameFStream             Forward stream pointing to the
 | |
|                                             beginning of a pathname (any
 | |
|                                             NameString).
 | |
|                                             The stream must not be at its end.
 | |
|   @param  [in, out] AbsolutePathBStream     Backward stream where the raw
 | |
|                                             absolute path is written. The
 | |
|                                             stream must be already initialized.
 | |
|                                             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
 | |
| AmlBuildRawMethodAbsolutePath (
 | |
|   IN      CONST AML_NODE_HEADER  *ParentNode,
 | |
|   IN      CONST AML_STREAM       *PathnameFStream,
 | |
|   IN  OUT       AML_STREAM       *AbsolutePathBStream
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   AML_NODE_HEADER  *NamedParentNode;
 | |
|   UINT8            *RawPathBuffer;
 | |
|   CONST CHAR8      *CurrPos;
 | |
| 
 | |
|   UINT32  Root;
 | |
|   UINT32  ParentPrefix;
 | |
|   UINT32  SegCount;
 | |
| 
 | |
|   if ((!IS_AML_OBJECT_NODE (ParentNode)         &&
 | |
|        !IS_AML_ROOT_NODE (ParentNode))          ||
 | |
|       !IS_STREAM (PathnameFStream)              ||
 | |
|       IS_END_OF_STREAM (PathnameFStream)        ||
 | |
|       !IS_STREAM_FORWARD (PathnameFStream)      ||
 | |
|       !IS_STREAM (AbsolutePathBStream)          ||
 | |
|       IS_END_OF_STREAM (AbsolutePathBStream)    ||
 | |
|       !IS_STREAM_BACKWARD (AbsolutePathBStream))
 | |
|   {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   CurrPos = (CONST CHAR8 *)AmlStreamGetCurrPos (PathnameFStream);
 | |
|   if (CurrPos == NULL) {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   // Parse the NameString information.
 | |
|   Status = AmlParseNameStringInfo (
 | |
|              CurrPos,
 | |
|              &Root,
 | |
|              &ParentPrefix,
 | |
|              &SegCount
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     ASSERT (0);
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   // Copy the method invocation raw relative path at the end of the Stream.
 | |
|   if (SegCount != 0) {
 | |
|     // Get the beginning of the raw NameString.
 | |
|     RawPathBuffer = (UINT8 *)AmlGetFirstNameSeg (
 | |
|                                CurrPos,
 | |
|                                Root,
 | |
|                                ParentPrefix
 | |
|                                );
 | |
| 
 | |
|     Status = AmlStreamWrite (
 | |
|                AbsolutePathBStream,
 | |
|                RawPathBuffer,
 | |
|                SegCount * AML_NAME_SEG_SIZE
 | |
|                );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       ASSERT (0);
 | |
|       return Status;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // If the pathname contained an absolute path, this is finished, return.
 | |
|   if (Root) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   // Get the first named node of the parent node in its hierarchy.
 | |
|   Status = AmlGetFirstNamedAncestorNode (ParentNode, &NamedParentNode);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     ASSERT (0);
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   // Build the raw absolute path of the namespace node.
 | |
|   Status = AmlGetRawNameSpacePath (
 | |
|              NamedParentNode,
 | |
|              ParentPrefix,
 | |
|              AbsolutePathBStream
 | |
|              );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /** Compare two raw NameStrings stored in forward streams.
 | |
|     Compare them NameSeg by NameSeg (a NameSeg is 4 bytes long).
 | |
| 
 | |
|   The two raw NameStrings can be of different size.
 | |
| 
 | |
|   @param  [in]  RawFStream1     First forward stream to compare.
 | |
|                                 Points to the beginning of the raw NameString.
 | |
|   @param  [in]  RawFStream2     Second forward stream to compare.
 | |
|                                 Points to the beginning of the raw NameString.
 | |
|   @param  [out] CompareCount    Count of identic bytes.
 | |
|                                 Must be a multiple of 4 (size of a NameSeg).
 | |
| 
 | |
|   @retval EFI_SUCCESS             The function completed successfully.
 | |
|   @retval EFI_INVALID_PARAMETER   Invalid parameter.
 | |
| **/
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| AmlCompareRawNameString (
 | |
|   IN  CONST AML_STREAM  *RawFStream1,
 | |
|   IN  CONST AML_STREAM  *RawFStream2,
 | |
|   OUT       UINT32      *CompareCount
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   UINT32      Index;
 | |
| 
 | |
|   AML_STREAM  RawFStream1Clone;
 | |
|   AML_STREAM  RawFStream2Clone;
 | |
|   UINT32      Stream1Size;
 | |
|   UINT32      Stream2Size;
 | |
|   UINT32      CompareLen;
 | |
| 
 | |
|   // Raw NameStrings have a size that is a multiple of the size of NameSegs.
 | |
|   if (!IS_STREAM (RawFStream1)          ||
 | |
|       IS_END_OF_STREAM (RawFStream1)    ||
 | |
|       !IS_STREAM_FORWARD (RawFStream1)  ||
 | |
|       !IS_STREAM (RawFStream2)          ||
 | |
|       IS_END_OF_STREAM (RawFStream2)    ||
 | |
|       (CompareCount == NULL))
 | |
|   {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   Stream1Size = AmlStreamGetFreeSpace (RawFStream1);
 | |
|   if ((Stream1Size & (AML_NAME_SEG_SIZE - 1)) != 0) {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   Stream2Size = AmlStreamGetFreeSpace (RawFStream2);
 | |
|   if ((Stream2Size & (AML_NAME_SEG_SIZE - 1)) != 0) {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   Status = AmlStreamClone (RawFStream1, &RawFStream1Clone);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     ASSERT (0);
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   Status = AmlStreamClone (RawFStream2, &RawFStream2Clone);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     ASSERT (0);
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   CompareLen = MIN (Stream1Size, Stream2Size);
 | |
|   Index      = 0;
 | |
|   // Check there is enough space for a NameSeg in both Stream1 and Stream2.
 | |
|   while (Index < CompareLen) {
 | |
|     if (!AmlStreamCmp (
 | |
|            &RawFStream1Clone,
 | |
|            &RawFStream2Clone,
 | |
|            AML_NAME_SEG_SIZE
 | |
|            )
 | |
|         )
 | |
|     {
 | |
|       // NameSegs are different. Break.
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     Status = AmlStreamProgress (&RawFStream1Clone, AML_NAME_SEG_SIZE);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       ASSERT (0);
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     Status = AmlStreamProgress (&RawFStream2Clone, AML_NAME_SEG_SIZE);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       ASSERT (0);
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     Index += AML_NAME_SEG_SIZE;
 | |
|   }
 | |
| 
 | |
|   *CompareCount = Index;
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /** Check whether an alias can be resolved to a method definition.
 | |
| 
 | |
|   Indeed, the following ASL code must be handled:
 | |
|     Method (MET0, 1) {
 | |
|       Return (0x9)
 | |
|     }
 | |
|     Alias (\MET0, \ALI0)
 | |
|     Alias (\ALI0, \ALI1)
 | |
|     \ALI1(0x5)
 | |
|   When searching for \ALI1 in the AML NameSpace, it resolves to \ALI0.
 | |
|   When searching for \ALI0 in the AML NameSpace, it resolves to \MET0.
 | |
|   When searching for \MET0 in the AML NameSpace, it resolves to a method
 | |
|   definition.
 | |
| 
 | |
|   This method is a wrapper to recursively call AmlFindMethodDefinition.
 | |
| 
 | |
|   @param  [in]  AliasNode             Pointer to an Alias object node.
 | |
|   @param  [in]  NameSpaceRefList      List of NameSpaceRef nodes.
 | |
|   @param  [out] OutNameSpaceRefNode   If success, and if the alias is resolved
 | |
|                                       to a method definition (this can go
 | |
|                                       through other alias indirections),
 | |
|                                       containing the corresponding
 | |
|                                       NameSpaceRef node.
 | |
| 
 | |
|   @retval EFI_SUCCESS             The function completed successfully.
 | |
|   @retval EFI_INVALID_PARAMETER   Invalid parameter.
 | |
| **/
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| AmlResolveAliasMethod (
 | |
|   IN  CONST AML_OBJECT_NODE         *AliasNode,
 | |
|   IN  CONST LIST_ENTRY              *NameSpaceRefList,
 | |
|   OUT       AML_NAMESPACE_REF_NODE  **OutNameSpaceRefNode
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS           Status;
 | |
|   AML_STREAM           SourceAliasFStream;
 | |
|   CONST AML_DATA_NODE  *DataNode;
 | |
| 
 | |
|   if (!AmlNodeCompareOpCode (AliasNode, AML_ALIAS_OP, 0)  ||
 | |
|       (NameSpaceRefList == NULL)                          ||
 | |
|       (OutNameSpaceRefNode == NULL))
 | |
|   {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   // The aliased NameString (the source name) is the first fixed argument,
 | |
|   // cf. ACPI6.3 spec, s19.6.4: Alias (SourceObject, AliasObject)
 | |
|   DataNode = (CONST AML_DATA_NODE *)AmlGetFixedArgument (
 | |
|                                       (AML_OBJECT_NODE *)AliasNode,
 | |
|                                       EAmlParseIndexTerm0
 | |
|                                       );
 | |
|   if (DataNode == NULL) {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   // Initialize a stream on the source alias NameString.
 | |
|   Status = AmlStreamInit (
 | |
|              &SourceAliasFStream,
 | |
|              DataNode->Buffer,
 | |
|              DataNode->Size,
 | |
|              EAmlStreamDirectionForward
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     ASSERT (0);
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   // Recursively check whether the source alias NameString
 | |
|   // is a method invocation.
 | |
|   Status = AmlIsMethodInvocation (
 | |
|              AmlGetParent ((AML_NODE_HEADER *)AliasNode),
 | |
|              &SourceAliasFStream,
 | |
|              NameSpaceRefList,
 | |
|              OutNameSpaceRefNode
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     ASSERT (0);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /** Iterate through the MethodList to find the best namespace resolution.
 | |
|     If the pathname resolves to a method definition, returns it.
 | |
| 
 | |
|   For instance, if the AML namespace is:
 | |
|   \
 | |
|   \-MET0         <- Device definition, absolute path: \MET0
 | |
|   \-AAAA
 | |
|     \-MET0       <- Method definition, absolute path: \AAAA.MET0
 | |
|     \-MET1       <- Method definition, absolute path: \AAAA.MET1
 | |
|     \-BBBB
 | |
|       \-CCCC
 | |
|         \-DDDD
 | |
|           \-MET0 <- Method definition, absolute path: \AAAA.BBBB.CCCC.DDDD.MET0
 | |
| 
 | |
|   The list of the available pathnames is:
 | |
|   [NameSpaceRefList]
 | |
|    - \MET0                          <-  Device definition
 | |
|    - \AAAA
 | |
|    - \AAAA.MET0                     <-  Method definition
 | |
|    - \AAAA.MET1                     <-  Method definition
 | |
|    - \AAAA.BBBB
 | |
|    - \AAAA.BBBB.CCCC
 | |
|    - \AAAA.BBBB.CCCC.DDDD
 | |
|    - \AAAA.BBBB.CCCC.DDDD.MET0      <-  Method definition
 | |
| 
 | |
|   Depending on where the method invocation is done, the method definition
 | |
|   referenced changes. If the method call "MET0" is done from
 | |
|   \AAAA.BBBB.CCCC:
 | |
|     1. Identify which pathnames end with "MET0":
 | |
|      - \MET0                          <-  Device definition
 | |
|      - \AAAA.MET0                     <-  Method definition
 | |
|      - \AAAA.BBBB.CCCC.DDDD.MET0      <-  Method definition
 | |
|     2. Resolve the method invocation:
 | |
|      - \AAAA.MET0                     <-  Method definition
 | |
|     3. \AAAA.MET0 is a method definition, so return the corresponding
 | |
|        reference node.
 | |
| 
 | |
|   @param  [in]  RawAbsolutePathFStream    Forward stream pointing to a raw
 | |
|                                           absolute path.
 | |
|                                           The stream must not be at its end.
 | |
|   @param  [in]  RawPathNameBStream        Backward stream pointing to a raw
 | |
|                                           pathname. This raw pathname is the
 | |
|                                           raw NameString of namespace node.
 | |
|                                           The stream must not be at its end.
 | |
|   @param  [in]  NameSpaceRefList          List of NameSpaceRef nodes.
 | |
|   @param  [out] OutNameSpaceRefNode       If the two input paths are
 | |
|                                           referencing a method definition,
 | |
|                                           returns the corresponding
 | |
|                                           NameSpaceRef node.
 | |
| 
 | |
|   @retval EFI_SUCCESS             The function completed successfully.
 | |
|   @retval EFI_INVALID_PARAMETER   Invalid parameter.
 | |
| **/
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| AmlFindMethodDefinition (
 | |
|   IN  CONST AML_STREAM              *RawAbsolutePathFStream,
 | |
|   IN  CONST AML_STREAM              *RawPathNameBStream,
 | |
|   IN  CONST LIST_ENTRY              *NameSpaceRefList,
 | |
|   OUT       AML_NAMESPACE_REF_NODE  **OutNameSpaceRefNode
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   LIST_ENTRY  *NextLink;
 | |
| 
 | |
|   // To resolve a pathname, scope levels need to be compared.
 | |
|   UINT32  NameSegScopeCount;
 | |
|   UINT32  PathNameSegScopeCount;
 | |
|   UINT32  ProbedScopeCount;
 | |
|   UINT32  BestScopeCount;
 | |
| 
 | |
|   AML_STREAM  ProbedRawAbsoluteFStream;
 | |
|   AML_STREAM  ProbedRawAbsoluteBStream;
 | |
| 
 | |
|   AML_NAMESPACE_REF_NODE  *ProbedNameSpaceRefNode;
 | |
|   AML_NAMESPACE_REF_NODE  *BestNameSpaceRefNode;
 | |
| 
 | |
|   if (!IS_STREAM (RawAbsolutePathFStream)                               ||
 | |
|       IS_END_OF_STREAM (RawAbsolutePathFStream)                         ||
 | |
|       !IS_STREAM_FORWARD (RawAbsolutePathFStream)                       ||
 | |
|       ((AmlStreamGetIndex (RawAbsolutePathFStream) &
 | |
|         (AML_NAME_SEG_SIZE - 1)) != 0)                                  ||
 | |
|       !IS_STREAM (RawPathNameBStream)                                   ||
 | |
|       IS_END_OF_STREAM (RawPathNameBStream)                             ||
 | |
|       !IS_STREAM_BACKWARD (RawPathNameBStream)                          ||
 | |
|       ((AmlStreamGetIndex (RawPathNameBStream) &
 | |
|         (AML_NAME_SEG_SIZE - 1)) != 0)                                  ||
 | |
|       (NameSpaceRefList == NULL)                                        ||
 | |
|       (OutNameSpaceRefNode == NULL))
 | |
|   {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   DEBUG ((DEBUG_VERBOSE, "AmlMethodParser: Checking absolute name: "));
 | |
|   AMLDBG_PRINT_CHARS (
 | |
|     DEBUG_VERBOSE,
 | |
|     (CONST CHAR8 *)AmlStreamGetCurrPos (RawAbsolutePathFStream),
 | |
|     AmlStreamGetMaxBufferSize (RawAbsolutePathFStream)
 | |
|     );
 | |
|   DEBUG ((DEBUG_VERBOSE, ".\n"));
 | |
| 
 | |
|   BestNameSpaceRefNode  = NULL;
 | |
|   BestScopeCount        = 0;
 | |
|   NameSegScopeCount     = AmlStreamGetMaxBufferSize (RawAbsolutePathFStream);
 | |
|   PathNameSegScopeCount = AmlStreamGetMaxBufferSize (RawPathNameBStream);
 | |
| 
 | |
|   // Iterate through the raw AML absolute path to find the best match.
 | |
|   DEBUG ((DEBUG_VERBOSE, "AmlMethodParser: Comparing with: "));
 | |
|   NextLink = NameSpaceRefList->ForwardLink;
 | |
|   while (NextLink != NameSpaceRefList) {
 | |
|     ProbedNameSpaceRefNode = (AML_NAMESPACE_REF_NODE *)NextLink;
 | |
| 
 | |
|     // Print the raw absolute path of the probed node.
 | |
|     AMLDBG_PRINT_CHARS (
 | |
|       DEBUG_VERBOSE,
 | |
|       ProbedNameSpaceRefNode->RawAbsolutePath,
 | |
|       ProbedNameSpaceRefNode->RawAbsolutePathSize
 | |
|       );
 | |
|     DEBUG ((DEBUG_VERBOSE, "; "));
 | |
| 
 | |
|     // If the raw AML absolute path of the probed node is longer than the
 | |
|     // searched pathname, continue.
 | |
|     // E.g.: The method call \MET0 cannot resolve to a method defined at
 | |
|     //       \AAAA.MET0. The method definition is out of scope.
 | |
|     if (PathNameSegScopeCount > ProbedNameSpaceRefNode->RawAbsolutePathSize) {
 | |
|       NextLink = NextLink->ForwardLink;
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     // Initialize a backward stream for the probed node.
 | |
|     // This stream is used to compare the ending of the pathnames.
 | |
|     // E.g. if the method searched ends with "MET0", pathnames not ending with
 | |
|     //      "MET0" should be skipped.
 | |
|     Status = AmlStreamInit (
 | |
|                &ProbedRawAbsoluteBStream,
 | |
|                (UINT8 *)ProbedNameSpaceRefNode->RawAbsolutePath,
 | |
|                ProbedNameSpaceRefNode->RawAbsolutePathSize,
 | |
|                EAmlStreamDirectionBackward
 | |
|                );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       ASSERT (0);
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     // Compare the pathname endings. If they don't match, continue.
 | |
|     if (!AmlStreamCmp (
 | |
|            RawPathNameBStream,
 | |
|            &ProbedRawAbsoluteBStream,
 | |
|            AmlStreamGetMaxBufferSize (RawPathNameBStream)
 | |
|            ))
 | |
|     {
 | |
|       NextLink = NextLink->ForwardLink;
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     // Initialize a forward stream for the probed node.
 | |
|     // This stream is used to count how many scope levels from the root
 | |
|     // are common with the probed node. The more there are, the better it is.
 | |
|     // E.g.: For the method invocation \AAAA.BBBB.MET0, if there are 2
 | |
|     //       pathnames ending with MET0:
 | |
|     //        - \AAAA.MET0 has 1 NameSeg in common with \AAAA.BBBB.MET0
 | |
|     //          from the root (this is "AAAA");
 | |
|     //        - \MET0 has 0 NameSeg in common with \AAAA.BBBB.MET0
 | |
|     //          from the root;
 | |
|     //       Thus, the best match is \AAAA.MET0.
 | |
|     Status = AmlStreamInit (
 | |
|                &ProbedRawAbsoluteFStream,
 | |
|                (UINT8 *)ProbedNameSpaceRefNode->RawAbsolutePath,
 | |
|                ProbedNameSpaceRefNode->RawAbsolutePathSize,
 | |
|                EAmlStreamDirectionForward
 | |
|                );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       ASSERT (0);
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     // Count how many namespace levels are in common from the root.
 | |
|     Status = AmlCompareRawNameString (
 | |
|                RawAbsolutePathFStream,
 | |
|                &ProbedRawAbsoluteFStream,
 | |
|                &ProbedScopeCount
 | |
|                );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       ASSERT (0);
 | |
|       return EFI_INVALID_PARAMETER;
 | |
|     }
 | |
| 
 | |
|     if (ProbedScopeCount == NameSegScopeCount) {
 | |
|       // This is a perfect match. Exit the loop.
 | |
|       BestNameSpaceRefNode = ProbedNameSpaceRefNode;
 | |
|       break;
 | |
|     } else if (ProbedScopeCount > BestScopeCount) {
 | |
|       // The probed node has more scope levels in common than the
 | |
|       // last best match. Update the best match.
 | |
|       BestScopeCount       = ProbedScopeCount;
 | |
|       BestNameSpaceRefNode = ProbedNameSpaceRefNode;
 | |
|     } else if (ProbedScopeCount == BestScopeCount) {
 | |
|       // The probed node has the same number of scope levels in
 | |
|       // common as the last best match.
 | |
|       if (ProbedScopeCount == 0) {
 | |
|         // There was not best match previously. Set it.
 | |
|         BestNameSpaceRefNode = ProbedNameSpaceRefNode;
 | |
|       } else {
 | |
|         // (ProbedScopeCount != 0)
 | |
|         // If there is an equivalent candidate, the best has the shortest
 | |
|         // absolute path. Indeed, a similar ProbedScopeCount and a longer
 | |
|         // path means the definition is out of the scope.
 | |
|         // E.g.: For the method invocation \AAAA.BBBB.MET0, if there are 2
 | |
|         //       pathnames ending with MET0:
 | |
|         //        - \AAAA.MET0 has 1 NameSegs in common with \AAAA.BBBB.MET0
 | |
|         //          from the root (this is "AAAA");
 | |
|         //        - \AAAA.CCCC.MET0 has 1 NameSegs in common with
 | |
|         //          \AAAA.BBBB.MET0 from the root (this is "AAAA");
 | |
|         //       As \AAAA.CCCC.MET0 is longer than \AAAA.MET0, it means that
 | |
|         //       the pathname could have matched on more NameSegs, but it
 | |
|         //       didn't because it is out of scope.
 | |
|         //       Thus, the best match is \AAAA.MET0.
 | |
|         if (AmlStreamGetIndex (&ProbedRawAbsoluteFStream) <
 | |
|             BestNameSpaceRefNode->RawAbsolutePathSize)
 | |
|         {
 | |
|           BestScopeCount       = ProbedScopeCount;
 | |
|           BestNameSpaceRefNode = ProbedNameSpaceRefNode;
 | |
|         } else if (AmlStreamGetIndex (&ProbedRawAbsoluteFStream) ==
 | |
|                    BestNameSpaceRefNode->RawAbsolutePathSize)
 | |
|         {
 | |
|           ASSERT (0);
 | |
|           return EFI_INVALID_PARAMETER;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     NextLink = NextLink->ForwardLink;
 | |
|   }
 | |
| 
 | |
|   DEBUG ((DEBUG_VERBOSE, "\n"));
 | |
| 
 | |
|   // Check whether the BestNameSpaceRefNode is a method definition.
 | |
|   if (BestNameSpaceRefNode != NULL) {
 | |
|     if (AmlIsMethodDefinitionNode (BestNameSpaceRefNode->NodeRef)) {
 | |
|       *OutNameSpaceRefNode = BestNameSpaceRefNode;
 | |
|     } else if (AmlNodeCompareOpCode (
 | |
|                  BestNameSpaceRefNode->NodeRef,
 | |
|                  AML_ALIAS_OP,
 | |
|                  0
 | |
|                  ))
 | |
|     {
 | |
|       // The path matches an alias. Resolve the alias and check whether
 | |
|       // this is a method defintion.
 | |
|       Status = AmlResolveAliasMethod (
 | |
|                  BestNameSpaceRefNode->NodeRef,
 | |
|                  NameSpaceRefList,
 | |
|                  OutNameSpaceRefNode
 | |
|                  );
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         ASSERT (0);
 | |
|         return Status;
 | |
|       }
 | |
|     }
 | |
|   } else {
 | |
|     // If no, return NULL, even if a matching pathname has been found.
 | |
|     *OutNameSpaceRefNode = NULL;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /** Check whether a pathname is a method invocation.
 | |
| 
 | |
|   If there is a matching method definition, returns the corresponding
 | |
|   NameSpaceRef node.
 | |
| 
 | |
|   To do so, the NameSpaceRefList is keeping track of every namespace node
 | |
|   and its raw AML absolute path.
 | |
|   To check whether a pathname is a method invocation, a corresponding raw
 | |
|   absolute pathname is built. This raw absolute pathname is then compared
 | |
|   to the list of available pathnames. If a pathname defining a method
 | |
|   matches the scope of the input pathname, return.
 | |
| 
 | |
|   @param  [in]  ParentNode          Parent node. Node to which the node to be
 | |
|                                     created will be attached.
 | |
|   @param  [in]  FStream             Forward stream pointing to the NameString
 | |
|                                     to find.
 | |
|   @param  [in]  NameSpaceRefList    List of NameSpaceRef nodes.
 | |
|   @param  [out] OutNameSpaceRefNode If the NameString pointed by FStream is
 | |
|                                     a method invocation, OutNameSpaceRefNode
 | |
|                                     contains the NameSpaceRef corresponding
 | |
|                                     to the method definition.
 | |
|                                     NULL otherwise.
 | |
| 
 | |
|   @retval EFI_SUCCESS             The function completed successfully.
 | |
|   @retval EFI_INVALID_PARAMETER   Invalid parameter.
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| AmlIsMethodInvocation (
 | |
|   IN  CONST AML_NODE_HEADER   *ParentNode,
 | |
|   IN  CONST AML_STREAM        *FStream,
 | |
|   IN  CONST LIST_ENTRY        *NameSpaceRefList,
 | |
|   OUT AML_NAMESPACE_REF_NODE  **OutNameSpaceRefNode
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   AML_STREAM  RawPathNameBStream;
 | |
|   AML_STREAM  RawAbsolutePathFStream;
 | |
| 
 | |
|   AML_STREAM  RawAbsolutePathBStream;
 | |
|   UINT8       *RawAbsolutePathBuffer;
 | |
|   UINT32      RawAbsolutePathBufferSize;
 | |
| 
 | |
|   AML_NAMESPACE_REF_NODE  *NameSpaceRefNode;
 | |
| 
 | |
|   if ((!IS_AML_OBJECT_NODE (ParentNode) &&
 | |
|        !IS_AML_ROOT_NODE (ParentNode))  ||
 | |
|       !IS_STREAM (FStream)              ||
 | |
|       IS_END_OF_STREAM (FStream)        ||
 | |
|       !IS_STREAM_FORWARD (FStream)      ||
 | |
|       (NameSpaceRefList == NULL)        ||
 | |
|       (OutNameSpaceRefNode == NULL))
 | |
|   {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   // There cannot be a method invocation in a field list. Return.
 | |
|   if (AmlNodeHasAttribute (
 | |
|         (CONST AML_OBJECT_NODE *)ParentNode,
 | |
|         AML_HAS_FIELD_LIST
 | |
|         ))
 | |
|   {
 | |
|     *OutNameSpaceRefNode = NULL;
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   // Allocate memory for the raw absolute path.
 | |
|   RawAbsolutePathBufferSize = MAX_AML_NAMESTRING_SIZE;
 | |
|   RawAbsolutePathBuffer     = AllocateZeroPool (RawAbsolutePathBufferSize);
 | |
|   if (RawAbsolutePathBuffer == NULL) {
 | |
|     ASSERT (0);
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   // Initialize a backward stream to get the raw absolute path.
 | |
|   Status = AmlStreamInit (
 | |
|              &RawAbsolutePathBStream,
 | |
|              RawAbsolutePathBuffer,
 | |
|              RawAbsolutePathBufferSize,
 | |
|              EAmlStreamDirectionBackward
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     ASSERT (0);
 | |
|     goto exit_handler;
 | |
|   }
 | |
| 
 | |
|   // Build the raw AML absolute path of the namespace node.
 | |
|   Status = AmlBuildRawMethodAbsolutePath (
 | |
|              ParentNode,
 | |
|              FStream,
 | |
|              &RawAbsolutePathBStream
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     ASSERT (0);
 | |
|     goto exit_handler;
 | |
|   }
 | |
| 
 | |
|   // If this is the root path: it cannot be a method invocation. Just return.
 | |
|   if (AmlStreamGetIndex (&RawAbsolutePathBStream) == 0) {
 | |
|     DEBUG ((
 | |
|       DEBUG_VERBOSE,
 | |
|       "AmlMethodParser: "
 | |
|       "Root node cannot be a method invocation\n"
 | |
|       ));
 | |
|     *OutNameSpaceRefNode = NULL;
 | |
|     Status               = EFI_SUCCESS;
 | |
|     goto exit_handler;
 | |
|   }
 | |
| 
 | |
|   // Create a forward stream for the raw absolute path.
 | |
|   // This forward stream only contains the raw absolute path with
 | |
|   // no extra free space.
 | |
|   Status = AmlStreamInit (
 | |
|              &RawAbsolutePathFStream,
 | |
|              AmlStreamGetCurrPos (&RawAbsolutePathBStream),
 | |
|              AmlStreamGetIndex (&RawAbsolutePathBStream),
 | |
|              EAmlStreamDirectionForward
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     ASSERT (0);
 | |
|     goto exit_handler;
 | |
|   }
 | |
| 
 | |
|   // Create a backward stream for the node name.
 | |
|   Status = AmlInitRawPathBStream (
 | |
|              FStream,
 | |
|              &RawPathNameBStream
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     ASSERT (0);
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   // Go through the NameSpaceRefList elements to check for
 | |
|   // a corresponding method definition.
 | |
|   NameSpaceRefNode = NULL;
 | |
|   Status           = AmlFindMethodDefinition (
 | |
|                        &RawAbsolutePathFStream,
 | |
|                        &RawPathNameBStream,
 | |
|                        NameSpaceRefList,
 | |
|                        &NameSpaceRefNode
 | |
|                        );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     ASSERT (0);
 | |
|     goto exit_handler;
 | |
|   }
 | |
| 
 | |
|  #if !defined (MDEPKG_NDEBUG)
 | |
|   // Print whether a method definition has been found.
 | |
|   if (NameSpaceRefNode != NULL) {
 | |
|     DEBUG ((
 | |
|       DEBUG_VERBOSE,
 | |
|       "AmlMethodParser: Corresponding method definition: "
 | |
|       ));
 | |
|     AMLDBG_PRINT_CHARS (
 | |
|       DEBUG_VERBOSE,
 | |
|       NameSpaceRefNode->RawAbsolutePath,
 | |
|       NameSpaceRefNode->RawAbsolutePathSize
 | |
|       );
 | |
|     DEBUG ((DEBUG_VERBOSE, ".\n"));
 | |
|   } else {
 | |
|     DEBUG ((DEBUG_VERBOSE, "AmlMethodParser: No method definition found.\n"));
 | |
|   }
 | |
| 
 | |
|  #endif // MDEPKG_NDEBUG
 | |
| 
 | |
|   *OutNameSpaceRefNode = NameSpaceRefNode;
 | |
| 
 | |
| exit_handler:
 | |
|   // Free allocated memory.
 | |
|   FreePool (RawAbsolutePathBuffer);
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /** Create a namespace reference node and add it to the NameSpaceRefList.
 | |
| 
 | |
|   When a namespace node is encountered, the namespace it defines must be
 | |
|   associated to the node. This allow to keep track of the nature of each
 | |
|   name present in the AML namespace.
 | |
| 
 | |
|   In the end, this allows to recognize method invocations and parse the right
 | |
|   number of arguments after the method name.
 | |
| 
 | |
|   @param [in]       Node              Namespace node.
 | |
|   @param [in, out]  NameSpaceRefList  List of namespace reference nodes.
 | |
| 
 | |
|   @retval EFI_SUCCESS             The function completed successfully.
 | |
|   @retval EFI_INVALID_PARAMETER   Invalid parameter.
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| AmlAddNameSpaceReference (
 | |
|   IN      CONST AML_OBJECT_NODE  *Node,
 | |
|   IN  OUT       LIST_ENTRY       *NameSpaceRefList
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS              Status;
 | |
|   AML_NAMESPACE_REF_NODE  *NameSpaceRefNode;
 | |
| 
 | |
|   AML_STREAM           NodeNameFStream;
 | |
|   EAML_PARSE_INDEX     NameIndex;
 | |
|   CONST AML_DATA_NODE  *NameNode;
 | |
| 
 | |
|   AML_STREAM  RawAbsolutePathBStream;
 | |
|   UINT32      RawAbsolutePathBStreamSize;
 | |
| 
 | |
|   CHAR8   *AbsolutePathBuffer;
 | |
|   UINT32  AbsolutePathBufferSize;
 | |
| 
 | |
|   CONST AML_NODE_HEADER  *ParentNode;
 | |
| 
 | |
|   if (!AmlNodeHasAttribute (Node, AML_IN_NAMESPACE)   ||
 | |
|       (NameSpaceRefList == NULL))
 | |
|   {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   // Allocate a buffer to get the raw AML absolute pathname of the
 | |
|   // namespace node.
 | |
|   AbsolutePathBufferSize = MAX_AML_NAMESTRING_SIZE;
 | |
|   AbsolutePathBuffer     = AllocateZeroPool (AbsolutePathBufferSize);
 | |
|   if (AbsolutePathBuffer == NULL) {
 | |
|     ASSERT (0);
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   Status = AmlStreamInit (
 | |
|              &RawAbsolutePathBStream,
 | |
|              (UINT8 *)AbsolutePathBuffer,
 | |
|              AbsolutePathBufferSize,
 | |
|              EAmlStreamDirectionBackward
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     ASSERT (0);
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     goto exit_handler;
 | |
|   }
 | |
| 
 | |
|   // Get the index where the name of the Node is stored in its
 | |
|   // fixed list of arguments.
 | |
|   Status = AmlNodeGetNameIndex (Node, &NameIndex);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     ASSERT (0);
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     goto exit_handler;
 | |
|   }
 | |
| 
 | |
|   // Get the Node name.
 | |
|   NameNode = (CONST AML_DATA_NODE *)AmlGetFixedArgument (
 | |
|                                       (AML_OBJECT_NODE *)Node,
 | |
|                                       NameIndex
 | |
|                                       );
 | |
|   if (!IS_AML_DATA_NODE (NameNode)    ||
 | |
|       (NameNode->DataType != EAmlNodeDataTypeNameString))
 | |
|   {
 | |
|     ASSERT (0);
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     goto exit_handler;
 | |
|   }
 | |
| 
 | |
|   // Initialize a stream on the node name of the namespace node.
 | |
|   // This is an AML NameString.
 | |
|   Status = AmlStreamInit (
 | |
|              &NodeNameFStream,
 | |
|              NameNode->Buffer,
 | |
|              NameNode->Size,
 | |
|              EAmlStreamDirectionForward
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     ASSERT (0);
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     goto exit_handler;
 | |
|   }
 | |
| 
 | |
|   ParentNode = AmlGetParent ((AML_NODE_HEADER *)Node);
 | |
|   if (ParentNode == NULL) {
 | |
|     ASSERT (0);
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     goto exit_handler;
 | |
|   }
 | |
| 
 | |
|   // Build the raw AML absolute path of the namespace node.
 | |
|   Status = AmlBuildRawMethodAbsolutePath (
 | |
|              ParentNode,
 | |
|              &NodeNameFStream,
 | |
|              &RawAbsolutePathBStream
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     ASSERT (0);
 | |
|     goto exit_handler;
 | |
|   }
 | |
| 
 | |
|   RawAbsolutePathBStreamSize = AmlStreamGetIndex (&RawAbsolutePathBStream);
 | |
|   // This is the root path: this cannot be a method invocation.
 | |
|   if (RawAbsolutePathBStreamSize == 0) {
 | |
|     Status = EFI_SUCCESS;
 | |
|     goto exit_handler;
 | |
|   }
 | |
| 
 | |
|   // Create a NameSpace reference node.
 | |
|   Status = AmlCreateMethodRefNode (
 | |
|              Node,
 | |
|              (CONST CHAR8 *)AmlStreamGetCurrPos (&RawAbsolutePathBStream),
 | |
|              RawAbsolutePathBStreamSize,
 | |
|              &NameSpaceRefNode
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     ASSERT (0);
 | |
|     goto exit_handler;
 | |
|   }
 | |
| 
 | |
|   // Add the created NameSpaceRefNode to the list.
 | |
|   InsertTailList (NameSpaceRefList, &NameSpaceRefNode->Link);
 | |
| 
 | |
|   DEBUG ((
 | |
|     DEBUG_VERBOSE,
 | |
|     "AmlMethodParser: Adding namespace reference with name:\n"
 | |
|     ));
 | |
|   AMLDBG_PRINT_CHARS (
 | |
|     DEBUG_VERBOSE,
 | |
|     (CONST CHAR8 *)AmlStreamGetCurrPos (&RawAbsolutePathBStream),
 | |
|     AmlStreamGetIndex (&RawAbsolutePathBStream)
 | |
|     );
 | |
|   DEBUG ((DEBUG_VERBOSE, "\n"));
 | |
| 
 | |
| exit_handler:
 | |
|   // Free allocated memory.
 | |
|   FreePool (AbsolutePathBuffer);
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /** Create a method invocation node.
 | |
| 
 | |
|   The AML grammar does not attribute an OpCode/SubOpCode couple for
 | |
|   method invocations. This library is representing method invocations
 | |
|   as if they had one.
 | |
| 
 | |
|   The AML encoding for method invocations in the ACPI specification 6.3 is:
 | |
|     MethodInvocation := NameString TermArgList
 | |
|   In this library, it is:
 | |
|     MethodInvocation := MethodInvocationOp NameString ArgumentCount TermArgList
 | |
|     ArgumentCount    := ByteData
 | |
| 
 | |
|   When computing the size of a tree or serializing it, the additional data is
 | |
|   not taken into account (i.e. the MethodInvocationOp and the ArgumentCount).
 | |
| 
 | |
|   Method invocation nodes have the AML_METHOD_INVOVATION attribute.
 | |
| 
 | |
|   @param  [in]  NameSpaceRefNode          NameSpaceRef node pointing to the
 | |
|                                           the definition of the invoked
 | |
|                                           method.
 | |
|   @param  [in]  MethodInvocationName      Data node containing the method
 | |
|                                           invocation name.
 | |
|   @param  [out] MethodInvocationNodePtr   Created method invocation node.
 | |
| 
 | |
|   @retval EFI_SUCCESS             The function completed successfully.
 | |
|   @retval EFI_INVALID_PARAMETER   Invalid parameter.
 | |
|   @retval EFI_OUT_OF_RESOURCES    Could not allocate memory.
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| AmlCreateMethodInvocationNode (
 | |
|   IN  CONST AML_NAMESPACE_REF_NODE  *NameSpaceRefNode,
 | |
|   IN        AML_DATA_NODE           *MethodInvocationName,
 | |
|   OUT       AML_OBJECT_NODE         **MethodInvocationNodePtr
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   UINT8            ArgCount;
 | |
|   AML_DATA_NODE    *ArgCountNode;
 | |
|   AML_NODE_HEADER  **FixedArgs;
 | |
|   AML_OBJECT_NODE  *MethodDefinitionNode;
 | |
|   AML_OBJECT_NODE  *MethodInvocationNode;
 | |
| 
 | |
|   if ((NameSpaceRefNode == NULL)                                      ||
 | |
|       !AmlIsMethodDefinitionNode (NameSpaceRefNode->NodeRef)          ||
 | |
|       !IS_AML_DATA_NODE (MethodInvocationName)                        ||
 | |
|       (MethodInvocationName->DataType != EAmlNodeDataTypeNameString)  ||
 | |
|       (MethodInvocationNodePtr == NULL))
 | |
|   {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   // Get the number of arguments of the method.
 | |
|   MethodDefinitionNode = (AML_OBJECT_NODE *)NameSpaceRefNode->NodeRef;
 | |
|   FixedArgs            = MethodDefinitionNode->FixedArgs;
 | |
|   // The method definition is an actual method definition.
 | |
|   if (AmlNodeCompareOpCode (MethodDefinitionNode, AML_METHOD_OP, 0)) {
 | |
|     // Cf ACPI 6.3 specification:
 | |
|     //  DefMethod := MethodOp PkgLength NameString MethodFlags TermList
 | |
|     //  MethodOp := 0x14
 | |
|     //  MethodFlags := ByteData  bit 0-2: ArgCount (0-7)
 | |
|     //                           bit 3: SerializeFlag
 | |
|     //                                    0 NotSerialized
 | |
|     //                                    1 Serialized
 | |
|     //                           bit 4-7: SyncLevel (0x00-0x0f)
 | |
| 
 | |
|     // Read the MethodFlags to decode the ArgCount.
 | |
|     ArgCountNode = (AML_DATA_NODE *)FixedArgs[EAmlParseIndexTerm1];
 | |
|     ArgCount     = *((UINT8 *)ArgCountNode->Buffer) & 0x7;
 | |
|   } else if (AmlNodeCompareOpCode (MethodDefinitionNode, AML_EXTERNAL_OP, 0)) {
 | |
|     // The method definition is an external statement.
 | |
|     // Cf ACPI 6.3 specification:
 | |
|     //  DefExternal := ExternalOp NameString ObjectType ArgumentCount
 | |
|     //  ExternalOp := 0x15
 | |
|     //  ObjectType := ByteData
 | |
|     //  ArgumentCount := ByteData (0 - 7)
 | |
| 
 | |
|     // Read the ArgumentCount.
 | |
|     ArgCountNode = (AML_DATA_NODE *)FixedArgs[EAmlParseIndexTerm2];
 | |
|     ArgCount     = *((UINT8 *)ArgCountNode->Buffer);
 | |
|   } else {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   // Create the object node for the method invocation.
 | |
|   // MethodInvocation := MethodInvocationOp NameString ArgumentCount
 | |
|   // MethodInvocationOp := Pseudo Opcode for Method Invocation
 | |
|   // NameString := Method Name
 | |
|   // ArgumentCount := ByteData (0 - 7)
 | |
|   Status = AmlCreateObjectNode (
 | |
|              AmlGetByteEncodingByOpCode (AML_METHOD_INVOC_OP, 0),
 | |
|              0,
 | |
|              &MethodInvocationNode
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     ASSERT (0);
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   // The first fixed argument is the method name.
 | |
|   Status = AmlSetFixedArgument (
 | |
|              MethodInvocationNode,
 | |
|              EAmlParseIndexTerm0,
 | |
|              (AML_NODE_HEADER *)MethodInvocationName
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     ASSERT (0);
 | |
|     goto error_handler;
 | |
|   }
 | |
| 
 | |
|   // Create a data node holding the number of arguments
 | |
|   // of the method invocation.
 | |
|   ArgCountNode = NULL;
 | |
|   Status       = AmlCreateDataNode (
 | |
|                    EAmlNodeDataTypeUInt,
 | |
|                    &ArgCount,
 | |
|                    sizeof (UINT8),
 | |
|                    &ArgCountNode
 | |
|                    );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     ASSERT (0);
 | |
|     goto error_handler;
 | |
|   }
 | |
| 
 | |
|   // The second fixed argument is the number of arguments.
 | |
|   Status = AmlSetFixedArgument (
 | |
|              MethodInvocationNode,
 | |
|              EAmlParseIndexTerm1,
 | |
|              (AML_NODE_HEADER *)ArgCountNode
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     ASSERT (0);
 | |
|     goto error_handler;
 | |
|   }
 | |
| 
 | |
|   *MethodInvocationNodePtr = MethodInvocationNode;
 | |
|   return Status;
 | |
| 
 | |
| error_handler:
 | |
|   // Delete the sub-tree: the method invocation name is already attached.
 | |
|   AmlDeleteTree ((AML_NODE_HEADER *)MethodInvocationNode);
 | |
|   if (ArgCountNode != NULL) {
 | |
|     AmlDeleteNode ((AML_NODE_HEADER *)ArgCountNode);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /** Get the number of arguments of a method invocation node.
 | |
| 
 | |
|   This function also allow to identify whether a node is a method invocation
 | |
|   node. If the input node is not a method invocation node, just return.
 | |
| 
 | |
|   @param  [in]  MethodInvocationNode  Method invocation node.
 | |
|   @param  [out] IsMethodInvocation    Boolean stating whether the input
 | |
|                                       node is a method invocation.
 | |
|   @param  [out] ArgCount              Number of arguments of the method
 | |
|                                       invocation.
 | |
|                                       Set to 0 if MethodInvocationNode
 | |
|                                       is not a method invocation.
 | |
| 
 | |
|   @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    Could not allocate memory.
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| AmlGetMethodInvocationArgCount (
 | |
|   IN  CONST AML_OBJECT_NODE  *MethodInvocationNode,
 | |
|   OUT       BOOLEAN          *IsMethodInvocation,
 | |
|   OUT       UINT8            *ArgCount
 | |
|   )
 | |
| {
 | |
|   AML_DATA_NODE  *NumArgsNode;
 | |
| 
 | |
|   if (!IS_AML_NODE_VALID (MethodInvocationNode) ||
 | |
|       (IsMethodInvocation == NULL)              ||
 | |
|       (ArgCount == NULL))
 | |
|   {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   // Check whether MethodInvocationNode is a method invocation.
 | |
|   if (!AmlNodeCompareOpCode (MethodInvocationNode, AML_METHOD_INVOC_OP, 0)) {
 | |
|     *IsMethodInvocation = FALSE;
 | |
|     *ArgCount           = 0;
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   // MethodInvocation := MethodInvocationOp NameString ArgumentCount
 | |
|   // MethodInvocationOp := Pseudo Opcode for Method Invocation
 | |
|   // NameString := Method Name
 | |
|   // ArgumentCount := ByteData (0 - 7)
 | |
|   NumArgsNode = (AML_DATA_NODE *)AmlGetFixedArgument (
 | |
|                                    (AML_OBJECT_NODE *)MethodInvocationNode,
 | |
|                                    EAmlParseIndexTerm1
 | |
|                                    );
 | |
|   if (!IS_AML_NODE_VALID (NumArgsNode)                ||
 | |
|       (NumArgsNode->Buffer == NULL)                   ||
 | |
|       (NumArgsNode->DataType != EAmlNodeDataTypeUInt) ||
 | |
|       (NumArgsNode->Size != 1))
 | |
|   {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   *ArgCount = *NumArgsNode->Buffer;
 | |
| 
 | |
|   *IsMethodInvocation = TRUE;
 | |
|   return EFI_SUCCESS;
 | |
| }
 |