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>
		
			
				
	
	
		
			1474 lines
		
	
	
		
			46 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1474 lines
		
	
	
		
			46 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   AML Parser.
 | |
| 
 | |
|   Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>
 | |
| 
 | |
|   SPDX-License-Identifier: BSD-2-Clause-Patent
 | |
| **/
 | |
| 
 | |
| #include <Parser/AmlParser.h>
 | |
| 
 | |
| #include <AmlCoreInterface.h>
 | |
| #include <AmlDbgPrint/AmlDbgPrint.h>
 | |
| #include <Parser/AmlFieldListParser.h>
 | |
| #include <Parser/AmlMethodParser.h>
 | |
| #include <Parser/AmlResourceDataParser.h>
 | |
| #include <String/AmlString.h>
 | |
| #include <Tree/AmlNode.h>
 | |
| #include <Tree/AmlTree.h>
 | |
| 
 | |
| /*
 | |
|   AML Tree
 | |
|   --------
 | |
| 
 | |
|   Each ASL Statement is represented in AML as and ObjectNode.
 | |
|   Each ObjectNode has an Opcode and has up to six FixedArguments
 | |
|   followed by a list of VariableArguments.
 | |
|   (ObjectNode)
 | |
|     \
 | |
|     |- [0][1][2][3][4][5]                        # Fixed Arguments
 | |
|     |- {(VarArg1)->(VarArg2)->(VarArg3)->...N}   # Variable Arguments
 | |
| 
 | |
|   A RootNode is a special type of Object Node that does not have an
 | |
|   Opcode or Fixed Arguments. It only has a list of VariableArguments
 | |
|   (RootNode)
 | |
|     \
 | |
|     |- {(VarArg1)->(VarArg2)->(VarArg3)->...N}   # Variable Arguments
 | |
| 
 | |
|   A DataNode consists of a data buffer.
 | |
| 
 | |
|   A FixedArgument or VariableArgument can be either an ObjectNode or
 | |
|   a DataNode.
 | |
| 
 | |
|   Example:
 | |
|   ASL code sample:
 | |
|   Device (DEV0) {
 | |
|     Name (VAR0, 0x6)
 | |
|   }
 | |
| 
 | |
|   Tree generated from the ASL code:
 | |
|   (RootNode)
 | |
|     \
 | |
|     |- {(Device statement (ObjectNode))}                # Variable Arg of the
 | |
|           \                                             #   RootNode
 | |
|            |
 | |
|            |- [0] - Device Name (DataNode)(="DEV0")     # Fixed Arg0 of the
 | |
|            |                                            #   Device() statement
 | |
|            |
 | |
|            |- {(Name statement (ObjectNode))}           # Variable Arg of the
 | |
|                 \                                       #   Device() statement
 | |
|                 |
 | |
|                 |- [0] - Name statement(DataNode)(="VAR0")  # Fixed Arg0 of the
 | |
|                 |                                           #   Name() statement
 | |
|                 |- [1] - Value(DataNode)(=0x6)              # Fixed Arg1 of the
 | |
|                                                             #   Name() statement
 | |
| */
 | |
| 
 | |
| // Forward declaration.
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| AmlParseStream (
 | |
|   IN      AML_NODE_HEADER  *Node,
 | |
|   IN  OUT AML_STREAM       *FStream,
 | |
|   IN  OUT LIST_ENTRY       *NameSpaceRefList
 | |
|   );
 | |
| 
 | |
| /** Function pointer to parse an AML construct.
 | |
| 
 | |
|   The expected format of the AML construct is passed in the
 | |
|   ExpectedFormat argument. The available formats are available in
 | |
|   the AML_PARSE_FORMAT enum definition.
 | |
| 
 | |
|   An object node or a data node is created in the function,
 | |
|   and returned through the OutNode parameter. This node should
 | |
|   be attached after this function returns.
 | |
| 
 | |
|   @param  [in]      ParentNode      Parent node to which the parsed
 | |
|                                     AML construct will be attached.
 | |
|   @param  [in]      ExpectedFormat  Format of the AML construct to parse.
 | |
|   @param  [in, out] FStream         Forward stream containing the AML bytecode
 | |
|                                     to parse.
 | |
|                                     The stream must not be at its end.
 | |
|   @param  [out]     OutNode         Pointer holding the node created from the
 | |
|                                     parsed AML bytecode.
 | |
| 
 | |
|   @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.
 | |
| **/
 | |
| typedef
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| (*AML_PARSE_FUNCTION) (
 | |
|   IN      CONST AML_NODE_HEADER   *Node,
 | |
|   IN            AML_PARSE_FORMAT  ExpectedFormat,
 | |
|   IN  OUT       AML_STREAM        *FStream,
 | |
|   OUT       AML_NODE_HEADER       **OutNode
 | |
|   );
 | |
| 
 | |
| /** Parse a UInt<X> (where X=8, 16, 32 or 64).
 | |
| 
 | |
|   A data node is created and returned through the OutNode parameter.
 | |
| 
 | |
|   @param  [in]      ParentNode      Parent node to which the parsed
 | |
|                                     AML construct will be attached.
 | |
|   @param  [in]      ExpectedFormat  Format of the AML construct to parse.
 | |
|   @param  [in, out] FStream         Forward stream containing the AML bytecode
 | |
|                                     to parse.
 | |
|                                     The stream must not be at its end.
 | |
|   @param  [out]     OutNode         Pointer holding the node created from the
 | |
|                                     parsed AML bytecode.
 | |
| 
 | |
|   @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.
 | |
| **/
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| AmlParseUIntX (
 | |
|   IN      CONST AML_NODE_HEADER   *ParentNode,
 | |
|   IN            AML_PARSE_FORMAT  ExpectedFormat,
 | |
|   IN  OUT       AML_STREAM        *FStream,
 | |
|   OUT       AML_NODE_HEADER       **OutNode
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   UINT32      UIntXSize;
 | |
| 
 | |
|   if ((!IS_AML_ROOT_NODE (ParentNode)       &&
 | |
|        !IS_AML_OBJECT_NODE (ParentNode))    ||
 | |
|       ((ExpectedFormat != EAmlUInt8)        &&
 | |
|        (ExpectedFormat != EAmlUInt16)       &&
 | |
|        (ExpectedFormat != EAmlUInt32)       &&
 | |
|        (ExpectedFormat != EAmlUInt64))      ||
 | |
|       !IS_STREAM (FStream)                  ||
 | |
|       IS_END_OF_STREAM (FStream)            ||
 | |
|       !IS_STREAM_FORWARD (FStream)          ||
 | |
|       (OutNode == NULL))
 | |
|   {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   switch (ExpectedFormat) {
 | |
|     case EAmlUInt8:
 | |
|       UIntXSize = 1;
 | |
|       break;
 | |
|     case EAmlUInt16:
 | |
|       UIntXSize = 2;
 | |
|       break;
 | |
|     case EAmlUInt32:
 | |
|       UIntXSize = 4;
 | |
|       break;
 | |
|     case EAmlUInt64:
 | |
|       UIntXSize = 8;
 | |
|       break;
 | |
|     default:
 | |
|       ASSERT (0);
 | |
|       return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   Status = AmlCreateDataNode (
 | |
|              AmlTypeToNodeDataType (ExpectedFormat),
 | |
|              AmlStreamGetCurrPos (FStream),
 | |
|              UIntXSize,
 | |
|              (AML_DATA_NODE **)OutNode
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     ASSERT (0);
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   AMLDBG_DUMP_RAW (AmlStreamGetCurrPos (FStream), UIntXSize);
 | |
| 
 | |
|   // Move stream forward by the size of UIntX.
 | |
|   Status = AmlStreamProgress (FStream, UIntXSize);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     AmlDeleteTree (*OutNode);
 | |
|     ASSERT (0);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /** Parse an AML NameString.
 | |
| 
 | |
|   A data node is created and returned through the OutNode parameter.
 | |
| 
 | |
|   @param  [in]      ParentNode      Parent node to which the parsed
 | |
|                                     AML construct will be attached.
 | |
|   @param  [in]      ExpectedFormat  Format of the AML construct to parse.
 | |
|   @param  [in, out] FStream         Forward stream containing the AML bytecode
 | |
|                                     to parse.
 | |
|                                     The stream must not be at its end.
 | |
|   @param  [out]     OutNode         Pointer holding the node created from the
 | |
|                                     parsed AML bytecode.
 | |
| 
 | |
|   @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.
 | |
| **/
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| AmlParseNameString (
 | |
|   IN      CONST AML_NODE_HEADER   *ParentNode,
 | |
|   IN            AML_PARSE_FORMAT  ExpectedFormat,
 | |
|   IN  OUT       AML_STREAM        *FStream,
 | |
|   OUT       AML_NODE_HEADER       **OutNode
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   CONST UINT8              *Buffer;
 | |
|   CONST AML_BYTE_ENCODING  *ByteEncoding;
 | |
|   UINT32                   StrSize;
 | |
| 
 | |
|   if ((!IS_AML_ROOT_NODE (ParentNode)     &&
 | |
|        !IS_AML_OBJECT_NODE (ParentNode))  ||
 | |
|       (ExpectedFormat != EAmlName)        ||
 | |
|       !IS_STREAM (FStream)                ||
 | |
|       IS_END_OF_STREAM (FStream)          ||
 | |
|       !IS_STREAM_FORWARD (FStream)        ||
 | |
|       (OutNode == NULL))
 | |
|   {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   Buffer       = (CONST UINT8 *)AmlStreamGetCurrPos (FStream);
 | |
|   ByteEncoding = AmlGetByteEncoding (Buffer);
 | |
|   if ((ByteEncoding == NULL)    ||
 | |
|       ((ByteEncoding->Attribute & AML_IS_NAME_CHAR) == 0))
 | |
|   {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   // Parse the NameString.
 | |
|   Status = AmlGetNameStringSize ((CONST CHAR8 *)Buffer, &StrSize);
 | |
|   if ((EFI_ERROR (Status))  ||
 | |
|       (StrSize > AmlStreamGetFreeSpace (FStream)))
 | |
|   {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   Status = AmlCreateDataNode (
 | |
|              EAmlNodeDataTypeNameString,
 | |
|              Buffer,
 | |
|              StrSize,
 | |
|              (AML_DATA_NODE **)OutNode
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     ASSERT (0);
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   AMLDBG_DUMP_RAW (AmlStreamGetCurrPos (FStream), StrSize);
 | |
| 
 | |
|   // Move the stream forward by StrSize.
 | |
|   Status = AmlStreamProgress (FStream, StrSize);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     AmlDeleteTree (*OutNode);
 | |
|     ASSERT (0);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /** Parse an AML String.
 | |
| 
 | |
|   A data node is created and returned through the OutNode parameter.
 | |
| 
 | |
|   @param  [in]      ParentNode      Parent node to which the parsed
 | |
|                                     AML construct will be attached.
 | |
|   @param  [in]      ExpectedFormat  Format of the AML construct to parse.
 | |
|   @param  [in, out] FStream         Forward stream containing the AML bytecode
 | |
|                                     to parse.
 | |
|                                     The stream must not be at its end.
 | |
|   @param  [out]     OutNode         Pointer holding the node created from the
 | |
|                                     parsed AML bytecode.
 | |
| 
 | |
|   @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.
 | |
| **/
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| AmlParseString (
 | |
|   IN      CONST AML_NODE_HEADER   *ParentNode,
 | |
|   IN            AML_PARSE_FORMAT  ExpectedFormat,
 | |
|   IN  OUT       AML_STREAM        *FStream,
 | |
|   OUT       AML_NODE_HEADER       **OutNode
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS   Status;
 | |
|   UINT32       StrSize;
 | |
|   UINT8        Byte;
 | |
|   CONST UINT8  *Buffer;
 | |
| 
 | |
|   if ((!IS_AML_ROOT_NODE (ParentNode)     &&
 | |
|        !IS_AML_OBJECT_NODE (ParentNode))  ||
 | |
|       (ExpectedFormat != EAmlString)      ||
 | |
|       !IS_STREAM (FStream)                ||
 | |
|       IS_END_OF_STREAM (FStream)          ||
 | |
|       !IS_STREAM_FORWARD (FStream)        ||
 | |
|       (OutNode == NULL))
 | |
|   {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   Buffer  = (CONST UINT8 *)AmlStreamGetCurrPos (FStream);
 | |
|   StrSize = 0;
 | |
|   // AML String is NULL terminated.
 | |
|   do {
 | |
|     // Reading the stream moves the stream forward aswell.
 | |
|     Status = AmlStreamReadByte (FStream, &Byte);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       ASSERT (0);
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     StrSize++;
 | |
|   } while (Byte != '\0');
 | |
| 
 | |
|   AMLDBG_DUMP_RAW (Buffer, StrSize);
 | |
| 
 | |
|   Status = AmlCreateDataNode (
 | |
|              AmlTypeToNodeDataType (ExpectedFormat),
 | |
|              Buffer,
 | |
|              StrSize,
 | |
|              (AML_DATA_NODE **)OutNode
 | |
|              );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /** Parse an AML object.
 | |
| 
 | |
|   An object can be resolved as an AML object with an OpCode,
 | |
|   or a NameString. An object node or a data node is created
 | |
|   and returned through the OutNode parameter.
 | |
| 
 | |
|   @param  [in]      ParentNode      Parent node to which the parsed
 | |
|                                     AML construct will be attached.
 | |
|   @param  [in]      ExpectedFormat  Format of the AML construct to parse.
 | |
|   @param  [in, out] FStream         Forward stream containing the AML bytecode
 | |
|                                     to parse.
 | |
|                                     The stream must not be at its end.
 | |
|   @param  [out]     OutNode         Pointer holding the node created from the
 | |
|                                     parsed AML bytecode.
 | |
| 
 | |
|   @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.
 | |
| **/
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| AmlParseObject (
 | |
|   IN      CONST AML_NODE_HEADER   *ParentNode,
 | |
|   IN            AML_PARSE_FORMAT  ExpectedFormat,
 | |
|   IN  OUT       AML_STREAM        *FStream,
 | |
|   OUT       AML_NODE_HEADER       **OutNode
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   UINT8   OpCodeSize;
 | |
|   UINT32  PkgLength;
 | |
|   UINT32  PkgOffset;
 | |
|   UINT32  FreeSpace;
 | |
| 
 | |
|   CONST AML_BYTE_ENCODING  *AmlByteEncoding;
 | |
|   CONST UINT8              *Buffer;
 | |
| 
 | |
|   if ((!IS_AML_ROOT_NODE (ParentNode)     &&
 | |
|        !IS_AML_OBJECT_NODE (ParentNode))  ||
 | |
|       (ExpectedFormat != EAmlObject)      ||
 | |
|       !IS_STREAM (FStream)                ||
 | |
|       IS_END_OF_STREAM (FStream)          ||
 | |
|       !IS_STREAM_FORWARD (FStream)        ||
 | |
|       (OutNode == NULL))
 | |
|   {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   PkgLength = 0;
 | |
| 
 | |
|   // 0. Get the AML Byte encoding.
 | |
|   AmlByteEncoding = AmlGetByteEncoding (AmlStreamGetCurrPos (FStream));
 | |
|   if (AmlByteEncoding == NULL) {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   // 1. Check for NameString.
 | |
|   //    Indeed a NameString can be found when an AML object is expected.
 | |
|   //    e.g. VAR0 = 3         // VAR0 is assigned an object which is a UINT.
 | |
|   //         VAR1 = VAR2      // VAR2 is a NameString.
 | |
|   //    If this is a NameString, return. A NameString can be a variable, a
 | |
|   //    method invocation, etc.
 | |
|   if ((AmlByteEncoding->Attribute & AML_IS_NAME_CHAR) != 0) {
 | |
|     Status = AmlParseNameString (
 | |
|                ParentNode,
 | |
|                EAmlName,
 | |
|                FStream,
 | |
|                OutNode
 | |
|                );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       ASSERT (0);
 | |
|     }
 | |
| 
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   // 2. Determine the OpCode size to move the stream forward.
 | |
|   Buffer = (CONST UINT8 *)AmlStreamGetCurrPos (FStream);
 | |
|   if (*Buffer == AML_EXT_OP) {
 | |
|     OpCodeSize = 2;
 | |
|   } else {
 | |
|     OpCodeSize = 1;
 | |
|   }
 | |
| 
 | |
|   Status = AmlStreamProgress (FStream, OpCodeSize);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     ASSERT (0);
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   // Print the opcode.
 | |
|   AMLDBG_DUMP_RAW (Buffer, OpCodeSize);
 | |
| 
 | |
|   if (!IS_END_OF_STREAM (FStream)) {
 | |
|     // 3. Parse the PkgLength field, if present.
 | |
|     if ((AmlByteEncoding->Attribute & AML_HAS_PKG_LENGTH) != 0) {
 | |
|       Buffer    = (CONST UINT8 *)AmlStreamGetCurrPos (FStream);
 | |
|       PkgOffset = AmlGetPkgLength (Buffer, &PkgLength);
 | |
|       if (PkgOffset == 0) {
 | |
|         ASSERT (0);
 | |
|         return EFI_INVALID_PARAMETER;
 | |
|       }
 | |
| 
 | |
|       // Print the package length.
 | |
|       AMLDBG_DUMP_RAW (Buffer, PkgOffset);
 | |
| 
 | |
|       // Adjust the size of the stream if it is valid  package length.
 | |
|       FreeSpace = AmlStreamGetFreeSpace (FStream);
 | |
|       if (FreeSpace > PkgLength) {
 | |
|         // Reduce the stream size by (FreeSpace - PkgLength) bytes.
 | |
|         AmlStreamReduceMaxBufferSize (FStream, FreeSpace - PkgLength);
 | |
|       } else if (FreeSpace != PkgLength) {
 | |
|         ASSERT (0);
 | |
|         return EFI_INVALID_PARAMETER;
 | |
|       }
 | |
| 
 | |
|       Status = AmlStreamProgress (FStream, PkgOffset);
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         ASSERT (0);
 | |
|         return Status;
 | |
|       }
 | |
|     }
 | |
|   } else if ((AmlByteEncoding->Attribute & AML_HAS_PKG_LENGTH) != 0) {
 | |
|     // The stream terminated unexpectedly. A PkgLen had to be parsed.
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   // 4. Create an Object Node.
 | |
|   Status = AmlCreateObjectNode (
 | |
|              AmlByteEncoding,
 | |
|              PkgLength,
 | |
|              (AML_OBJECT_NODE **)OutNode
 | |
|              );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /** Parse a FieldPkgLen.
 | |
| 
 | |
|   A FieldPkgLen can only be found in a field list, i.e. in a NamedField field
 | |
|   element. The PkgLen is otherwise part of the object node structure.
 | |
|   A data node is created and returned through the OutNode parameter.
 | |
| 
 | |
|   @param  [in]      ParentNode      Parent node to which the parsed
 | |
|                                     AML construct will be attached.
 | |
|   @param  [in]      ExpectedFormat  Format of the AML construct to parse.
 | |
|   @param  [in, out] FStream         Forward stream containing the AML bytecode
 | |
|                                     to parse.
 | |
|                                     The stream must not be at its end.
 | |
|   @param  [out]     OutNode         Pointer holding the node created from the
 | |
|                                     parsed AML bytecode.
 | |
| 
 | |
|   @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.
 | |
| **/
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| AmlParseFieldPkgLen (
 | |
|   IN      CONST AML_NODE_HEADER   *ParentNode,
 | |
|   IN            AML_PARSE_FORMAT  ExpectedFormat,
 | |
|   IN  OUT       AML_STREAM        *FStream,
 | |
|   OUT       AML_NODE_HEADER       **OutNode
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS   Status;
 | |
|   EFI_STATUS   Status1;
 | |
|   CONST UINT8  *Buffer;
 | |
|   UINT32       PkgOffset;
 | |
|   UINT32       PkgLength;
 | |
| 
 | |
|   if (!AmlNodeHasAttribute (
 | |
|          (CONST AML_OBJECT_NODE *)ParentNode,
 | |
|          AML_IS_FIELD_ELEMENT
 | |
|          )                                ||
 | |
|       (ExpectedFormat != EAmlFieldPkgLen) ||
 | |
|       !IS_STREAM (FStream)                ||
 | |
|       IS_END_OF_STREAM (FStream)          ||
 | |
|       !IS_STREAM_FORWARD (FStream)        ||
 | |
|       (OutNode == NULL))
 | |
|   {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   Buffer = (CONST UINT8 *)AmlStreamGetCurrPos (FStream);
 | |
| 
 | |
|   PkgOffset = AmlGetPkgLength (Buffer, &PkgLength);
 | |
|   if (PkgOffset == 0) {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   // Warning: Since, updating of field elements is not supported, store the
 | |
|   // FieldPkgLength in a Data Node as a raw buffer.
 | |
|   Status = AmlCreateDataNode (
 | |
|              AmlTypeToNodeDataType (ExpectedFormat),
 | |
|              Buffer,
 | |
|              PkgOffset,
 | |
|              (AML_DATA_NODE **)OutNode
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     ASSERT (0);
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   AMLDBG_DUMP_RAW (Buffer, PkgOffset);
 | |
| 
 | |
|   Status = AmlStreamProgress (FStream, PkgOffset);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status1 = AmlDeleteNode (*OutNode);
 | |
|     ASSERT_EFI_ERROR (Status1);
 | |
|     ASSERT (0);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /** Array of functions pointers to parse the AML constructs.
 | |
| 
 | |
|   The AML Byte encoding tables in Aml.c describe the format of the AML
 | |
|   statements. The AML_PARSE_FORMAT enum definition lists these constructs
 | |
|   and the corresponding parsing functions.
 | |
| */
 | |
| AML_PARSE_FUNCTION  mParseType[EAmlParseFormatMax] = {
 | |
|   NULL,                    // EAmlNone
 | |
|   AmlParseUIntX,           // EAmlUInt8
 | |
|   AmlParseUIntX,           // EAmlUInt16
 | |
|   AmlParseUIntX,           // EAmlUInt32
 | |
|   AmlParseUIntX,           // EAmlUInt64
 | |
|   AmlParseObject,          // EAmlObject
 | |
|   AmlParseNameString,      // EAmlName
 | |
|   AmlParseString,          // EAmlString
 | |
|   AmlParseFieldPkgLen      // EAmlFieldPkgLen
 | |
| };
 | |
| 
 | |
| /** Check whether the NameString stored in the data node is a method invocation.
 | |
|     If so, create a method invocation node and return it.
 | |
| 
 | |
|   @param  [in]      ParentNode        Node to which the parsed AML construct
 | |
|                                       will be attached.
 | |
|   @param  [in]      DataNode          Data node containing a NameString,
 | |
|                                       potentially being a method invocation.
 | |
|   @param  [in, out] NameSpaceRefList  List of namespace reference nodes.
 | |
|   @param  [out]     OutNode           Pointer holding the method invocation
 | |
|                                       node if the NameString contained in the
 | |
|                                       data node is a method invocation.
 | |
|                                       NULL otherwise.
 | |
| 
 | |
|   @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.
 | |
| **/
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| AmlCheckAndParseMethodInvoc (
 | |
|   IN  CONST AML_NODE_HEADER  *ParentNode,
 | |
|   IN        AML_DATA_NODE    *DataNode,
 | |
|   IN  OUT   LIST_ENTRY       *NameSpaceRefList,
 | |
|   OUT   AML_OBJECT_NODE      **OutNode
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS              Status;
 | |
|   AML_NAMESPACE_REF_NODE  *NameSpaceRefNode;
 | |
|   AML_OBJECT_NODE         *MethodInvocationNode;
 | |
|   AML_STREAM              FStream;
 | |
| 
 | |
|   if ((!IS_AML_ROOT_NODE (ParentNode)                     &&
 | |
|        !IS_AML_OBJECT_NODE (ParentNode))                  ||
 | |
|       !IS_AML_DATA_NODE (DataNode)                        ||
 | |
|       (DataNode->DataType != EAmlNodeDataTypeNameString)  ||
 | |
|       (NameSpaceRefList == NULL)                          ||
 | |
|       (OutNode == NULL))
 | |
|   {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   // Initialize a stream containing the NameString which is checked.
 | |
|   Status = AmlStreamInit (
 | |
|              &FStream,
 | |
|              DataNode->Buffer,
 | |
|              DataNode->Size,
 | |
|              EAmlStreamDirectionForward
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     ASSERT (0);
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   // Check whether the NameString is a method invocation.
 | |
|   NameSpaceRefNode = NULL;
 | |
|   Status           = AmlIsMethodInvocation (
 | |
|                        ParentNode,
 | |
|                        &FStream,
 | |
|                        NameSpaceRefList,
 | |
|                        &NameSpaceRefNode
 | |
|                        );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     ASSERT (0);
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   MethodInvocationNode = NULL;
 | |
|   if (NameSpaceRefNode != NULL) {
 | |
|     // A matching method definition has been found.
 | |
|     // Create a method invocation node.
 | |
|     Status = AmlCreateMethodInvocationNode (
 | |
|                NameSpaceRefNode,
 | |
|                (AML_DATA_NODE *)DataNode,
 | |
|                &MethodInvocationNode
 | |
|                );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       ASSERT (0);
 | |
|       return Status;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   *OutNode = MethodInvocationNode;
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /** Call the appropriate function to parse the AML construct in the stream.
 | |
| 
 | |
|   The ExpectedFormat parameter allows to choose the right parsing function.
 | |
|   An object node or a data node is created according to format.
 | |
| 
 | |
|   @param  [in]      ParentNode        Node to which the parsed AML construct
 | |
|                                       will be attached.
 | |
|   @param  [in]      ExpectedFormat    Format of the AML construct to parse.
 | |
|   @param  [in, out] FStream           Forward stream containing the AML
 | |
|                                       bytecode to parse.
 | |
|                                       The stream must not be at its end.
 | |
|   @param  [in, out] NameSpaceRefList  List of namespace reference nodes.
 | |
|   @param  [out]     OutNode           Pointer holding the node created from the
 | |
|                                       parsed AML bytecode.
 | |
| 
 | |
|   @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.
 | |
| **/
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| AmlParseArgument (
 | |
|   IN      CONST AML_NODE_HEADER   *ParentNode,
 | |
|   IN            AML_PARSE_FORMAT  ExpectedFormat,
 | |
|   IN  OUT       AML_STREAM        *FStream,
 | |
|   IN  OUT       LIST_ENTRY        *NameSpaceRefList,
 | |
|   OUT       AML_NODE_HEADER       **OutNode
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS          Status;
 | |
|   AML_PARSE_FUNCTION  ParsingFunction;
 | |
|   AML_DATA_NODE       *DataNode;
 | |
|   AML_OBJECT_NODE     *MethodInvocationNode;
 | |
| 
 | |
|   if ((!IS_AML_ROOT_NODE (ParentNode)         &&
 | |
|        !IS_AML_OBJECT_NODE (ParentNode))      ||
 | |
|       (ExpectedFormat >= EAmlParseFormatMax)  ||
 | |
|       !IS_STREAM (FStream)                    ||
 | |
|       IS_END_OF_STREAM (FStream)              ||
 | |
|       !IS_STREAM_FORWARD (FStream)            ||
 | |
|       (NameSpaceRefList == NULL)              ||
 | |
|       (OutNode == NULL))
 | |
|   {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   ParsingFunction = mParseType[ExpectedFormat];
 | |
|   if (ParsingFunction == NULL) {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   // Note: The ParsingFunction moves the stream forward as it
 | |
|   // consumes the AML bytecode
 | |
|   Status = ParsingFunction (
 | |
|              ParentNode,
 | |
|              ExpectedFormat,
 | |
|              FStream,
 | |
|              OutNode
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     ASSERT (0);
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   // Check whether the parsed argument is a NameString when an object
 | |
|   // is expected. In such case, it could be a method invocation.
 | |
|   DataNode = (AML_DATA_NODE *)*OutNode;
 | |
|   if (IS_AML_DATA_NODE (DataNode)                         &&
 | |
|       (DataNode->DataType == EAmlNodeDataTypeNameString)  &&
 | |
|       (ExpectedFormat == EAmlObject))
 | |
|   {
 | |
|     Status = AmlCheckAndParseMethodInvoc (
 | |
|                ParentNode,
 | |
|                (AML_DATA_NODE *)*OutNode,
 | |
|                NameSpaceRefList,
 | |
|                &MethodInvocationNode
 | |
|                );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       ASSERT (0);
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     // A method invocation node has been created and the DataNode containing
 | |
|     // the NameString has been attached to the MethodInvocationNode.
 | |
|     // Replace the OutNode with the MethodInvocationNode.
 | |
|     if (MethodInvocationNode != NULL) {
 | |
|       *OutNode = (AML_NODE_HEADER *)MethodInvocationNode;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /** Parse the Bytelist in the stream.
 | |
|     According to the content of the stream, create data node(s)
 | |
|     and add them to the variable list of arguments.
 | |
|     The byte list may be a list of resource data element or a simple byte list.
 | |
| 
 | |
|   @param  [in]  BufferNode    Object node having a byte list.
 | |
|   @param  [in, out] FStream   Forward stream containing the AML bytecode
 | |
|                               to parse.
 | |
|                               The stream must not be at its end.
 | |
| 
 | |
|   @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
 | |
| AmlParseByteList (
 | |
|   IN      AML_OBJECT_NODE  *BufferNode,
 | |
|   IN  OUT AML_STREAM       *FStream
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS       Status;
 | |
|   AML_NODE_HEADER  *NewNode;
 | |
|   CONST UINT8      *Buffer;
 | |
|   UINT32           BufferSize;
 | |
| 
 | |
|   // Check whether the node is an Object Node and has byte list.
 | |
|   if (!AmlNodeHasAttribute (BufferNode, AML_HAS_BYTE_LIST)  ||
 | |
|       !IS_STREAM (FStream)                                  ||
 | |
|       IS_END_OF_STREAM (FStream)                            ||
 | |
|       !IS_STREAM_FORWARD (FStream))
 | |
|   {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   // The buffer contains a list of resource data elements.
 | |
|   if (AmlRdIsResourceDataBuffer (FStream)) {
 | |
|     // Parse the resource data elements and add them as data nodes.
 | |
|     // AmlParseResourceData() moves the stream forward.
 | |
|     Status = AmlParseResourceData (BufferNode, FStream);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       ASSERT (0);
 | |
|     }
 | |
|   } else {
 | |
|     // The buffer doesn't contain a list of resource data elements.
 | |
|     // Create a single node holding the whole buffer data.
 | |
| 
 | |
|     // CreateDataNode checks the Buffer and BufferSize values.
 | |
|     Buffer     = (CONST UINT8 *)AmlStreamGetCurrPos (FStream);
 | |
|     BufferSize = AmlStreamGetFreeSpace (FStream);
 | |
| 
 | |
|     Status = AmlCreateDataNode (
 | |
|                EAmlNodeDataTypeRaw,
 | |
|                Buffer,
 | |
|                BufferSize,
 | |
|                (AML_DATA_NODE **)&NewNode
 | |
|                );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       ASSERT (0);
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     Status = AmlVarListAddTailInternal (
 | |
|                (AML_NODE_HEADER *)BufferNode,
 | |
|                NewNode
 | |
|                );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       ASSERT (0);
 | |
|       AmlDeleteTree (NewNode);
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     AMLDBG_DUMP_RAW (Buffer, BufferSize);
 | |
| 
 | |
|     // Move the stream forward as we have consumed the Buffer.
 | |
|     Status = AmlStreamProgress (FStream, BufferSize);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       ASSERT (0);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /** Parse the list of fixed arguments of the input ObjectNode.
 | |
| 
 | |
|   For each argument, create a node and add it to the fixed argument list
 | |
|   of the Node.
 | |
|   If a fixed argument has children, parse them.
 | |
| 
 | |
|   @param  [in]  ObjectNode        Object node to parse the fixed arguments
 | |
|                                   from.
 | |
|   @param  [in]  FStream           Forward stream containing the AML
 | |
|                                   bytecode to parse.
 | |
|                                   The stream must not be at its end.
 | |
|   @param  [in]  NameSpaceRefList  List of namespace reference nodes.
 | |
| 
 | |
|   @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
 | |
| AmlParseFixedArguments (
 | |
|   IN  AML_OBJECT_NODE  *ObjectNode,
 | |
|   IN  AML_STREAM       *FStream,
 | |
|   IN  LIST_ENTRY       *NameSpaceRefList
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   AML_NODE_HEADER  *FixedArgNode;
 | |
|   AML_STREAM       FixedArgFStream;
 | |
| 
 | |
|   EAML_PARSE_INDEX        TermIndex;
 | |
|   EAML_PARSE_INDEX        MaxIndex;
 | |
|   CONST AML_PARSE_FORMAT  *Format;
 | |
| 
 | |
|   // Fixed arguments of method invocations node are handled differently.
 | |
|   if (!IS_AML_OBJECT_NODE (ObjectNode)                              ||
 | |
|       AmlNodeCompareOpCode (ObjectNode, AML_METHOD_INVOC_OP, 0)     ||
 | |
|       !IS_STREAM (FStream)                                          ||
 | |
|       IS_END_OF_STREAM (FStream)                                    ||
 | |
|       !IS_STREAM_FORWARD (FStream)                                  ||
 | |
|       (NameSpaceRefList == NULL))
 | |
|   {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   TermIndex = EAmlParseIndexTerm0;
 | |
|   MaxIndex  = (EAML_PARSE_INDEX)AmlGetFixedArgumentCount (
 | |
|                                   (AML_OBJECT_NODE *)ObjectNode
 | |
|                                   );
 | |
|   if ((ObjectNode->AmlByteEncoding != NULL)   &&
 | |
|       (ObjectNode->AmlByteEncoding->Format != NULL))
 | |
|   {
 | |
|     Format = ObjectNode->AmlByteEncoding->Format;
 | |
|   } else {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   // Parse all the FixedArgs.
 | |
|   while ((TermIndex < MaxIndex)       &&
 | |
|          !IS_END_OF_STREAM (FStream)  &&
 | |
|          (Format[TermIndex] != EAmlNone))
 | |
|   {
 | |
|     // Initialize a FixedArgStream to parse the current fixed argument.
 | |
|     Status = AmlStreamInitSubStream (FStream, &FixedArgFStream);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       ASSERT (0);
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     // Parse the current fixed argument.
 | |
|     Status = AmlParseArgument (
 | |
|                (CONST AML_NODE_HEADER *)ObjectNode,
 | |
|                Format[TermIndex],
 | |
|                &FixedArgFStream,
 | |
|                NameSpaceRefList,
 | |
|                &FixedArgNode
 | |
|                );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       ASSERT (0);
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     // Add the fixed argument to the parent node's fixed argument list.
 | |
|     // FixedArgNode can be an object or data node.
 | |
|     Status = AmlSetFixedArgument (
 | |
|                (AML_OBJECT_NODE *)ObjectNode,
 | |
|                TermIndex,
 | |
|                FixedArgNode
 | |
|                );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       ASSERT (0);
 | |
|       // Delete the sub-tree if the insertion failed.
 | |
|       // Otherwise its reference will be lost.
 | |
|       // Use DeleteTree because if the argument was a method invocation,
 | |
|       // multiple nodes have been created.
 | |
|       AmlDeleteTree (FixedArgNode);
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     // Parse the AML bytecode of the FixedArgNode if this is an object node.
 | |
|     if (IS_AML_OBJECT_NODE (FixedArgNode) &&
 | |
|         !IS_END_OF_STREAM (&FixedArgFStream))
 | |
|     {
 | |
|       Status = AmlParseStream (
 | |
|                  FixedArgNode,
 | |
|                  &FixedArgFStream,
 | |
|                  NameSpaceRefList
 | |
|                  );
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         ASSERT (0);
 | |
|         return Status;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     // Move the stream forward as we have consumed the sub-stream.
 | |
|     Status = AmlStreamProgress (
 | |
|                FStream,
 | |
|                AmlStreamGetIndex (&FixedArgFStream)
 | |
|                );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       ASSERT (0);
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     TermIndex++;
 | |
|   } // while
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /** Parse the variable list of arguments of the input ObjectNode.
 | |
| 
 | |
|   For each variable argument, create a node and add it to the variable list of
 | |
|   arguments of the Node.
 | |
|   If a variable argument has children, parse them recursively.
 | |
| 
 | |
|   The arguments of method invocation nodes are added to the variable list of
 | |
|   arguments of the method invocation node. It is necessary to first get
 | |
|   the number of arguments to parse for this kind of node. A method invocation
 | |
|   can have at most 7 fixed arguments.
 | |
| 
 | |
|   @param  [in]  Node              Node to parse the variable arguments
 | |
|                                   from.
 | |
|   @param  [in]  FStream           Forward stream containing the AML
 | |
|                                   bytecode to parse.
 | |
|                                   The stream must not be at its end.
 | |
|   @param  [in]  NameSpaceRefList  List of namespace reference nodes.
 | |
| 
 | |
|   @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
 | |
| AmlParseVariableArguments (
 | |
|   IN  AML_NODE_HEADER  *Node,
 | |
|   IN  AML_STREAM       *FStream,
 | |
|   IN  LIST_ENTRY       *NameSpaceRefList
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   BOOLEAN  IsMethodInvocation;
 | |
|   UINT8    MethodInvocationArgCount;
 | |
| 
 | |
|   AML_NODE_HEADER  *VarArgNode;
 | |
|   AML_STREAM       VarArgFStream;
 | |
| 
 | |
|   if ((!AmlNodeHasAttribute (
 | |
|           (CONST AML_OBJECT_NODE *)Node,
 | |
|           AML_HAS_CHILD_OBJ
 | |
|           ) &&
 | |
|        !IS_AML_ROOT_NODE (Node))        ||
 | |
|       !IS_STREAM (FStream)              ||
 | |
|       IS_END_OF_STREAM (FStream)        ||
 | |
|       !IS_STREAM_FORWARD (FStream)      ||
 | |
|       (NameSpaceRefList == NULL))
 | |
|   {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   Status = AmlGetMethodInvocationArgCount (
 | |
|              (CONST AML_OBJECT_NODE *)Node,
 | |
|              &IsMethodInvocation,
 | |
|              &MethodInvocationArgCount
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     ASSERT (0);
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   // Parse variable arguments while the Stream is not empty.
 | |
|   while (!IS_END_OF_STREAM (FStream)) {
 | |
|     // If the number of variable arguments are counted, decrement the counter.
 | |
|     if ((IsMethodInvocation) && (MethodInvocationArgCount-- == 0)) {
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
| 
 | |
|     // Initialize a VarArgStream to parse the current variable argument.
 | |
|     Status = AmlStreamInitSubStream (FStream, &VarArgFStream);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       ASSERT (0);
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     // Parse the current variable argument.
 | |
|     Status = AmlParseArgument (
 | |
|                Node,
 | |
|                EAmlObject,
 | |
|                &VarArgFStream,
 | |
|                NameSpaceRefList,
 | |
|                &VarArgNode
 | |
|                );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       ASSERT (0);
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     // Add the variable argument to its parent variable list of arguments.
 | |
|     // VarArgNode can be an object or data node.
 | |
|     Status = AmlVarListAddTailInternal (
 | |
|                (AML_NODE_HEADER *)Node,
 | |
|                VarArgNode
 | |
|                );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       ASSERT (0);
 | |
|       // Delete the sub-tree if the insertion failed.
 | |
|       // Otherwise its reference will be lost.
 | |
|       // Use DeleteTree because if the argument was a method invocation,
 | |
|       // multiple nodes have been created.
 | |
|       AmlDeleteTree (VarArgNode);
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     // Parse the AML bytecode of the VarArgNode if this is an object node.
 | |
|     if (IS_AML_OBJECT_NODE (VarArgNode)       &&
 | |
|         (!IS_END_OF_STREAM (&VarArgFStream)))
 | |
|     {
 | |
|       Status = AmlParseStream (VarArgNode, &VarArgFStream, NameSpaceRefList);
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         ASSERT (0);
 | |
|         return Status;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     // Move the stream forward as we have consumed the sub-stream.
 | |
|     Status = AmlStreamProgress (
 | |
|                FStream,
 | |
|                AmlStreamGetIndex (&VarArgFStream)
 | |
|                );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       ASSERT (0);
 | |
|       return Status;
 | |
|     }
 | |
|   } // while
 | |
| 
 | |
|   // If the number of variable arguments are counted, check all the
 | |
|   // MethodInvocationArgCount have been parsed.
 | |
|   if (IsMethodInvocation && (MethodInvocationArgCount != 0)) {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /** Parse the AML stream and populate the root node.
 | |
| 
 | |
|   @param  [in]      RootNode          RootNode to which the children are
 | |
|                                       added.
 | |
|   @param  [in, out] FStream           Forward stream containing the AML
 | |
|                                       bytecode to parse.
 | |
|                                       The stream must not be at its end.
 | |
|   @param  [in, out] NameSpaceRefList  List of namespace reference nodes.
 | |
| 
 | |
|   @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.
 | |
| **/
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| AmlPopulateRootNode (
 | |
|   IN      AML_ROOT_NODE  *RootNode,
 | |
|   IN  OUT AML_STREAM     *FStream,
 | |
|   IN  OUT LIST_ENTRY     *NameSpaceRefList
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   if (!IS_AML_ROOT_NODE (RootNode)  ||
 | |
|       !IS_STREAM (FStream)          ||
 | |
|       IS_END_OF_STREAM (FStream)    ||
 | |
|       !IS_STREAM_FORWARD (FStream)  ||
 | |
|       (NameSpaceRefList == NULL))
 | |
|   {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   // A Root Node only has variable arguments.
 | |
|   Status = AmlParseVariableArguments (
 | |
|              (AML_NODE_HEADER *)RootNode,
 | |
|              FStream,
 | |
|              NameSpaceRefList
 | |
|              );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /** Parse the AML stream an populate the object node.
 | |
| 
 | |
|   @param  [in]      ObjectNode        ObjectNode to which the children are
 | |
|                                       added.
 | |
|   @param  [in, out] FStream           Forward stream containing the AML
 | |
|                                       bytecode to parse.
 | |
|                                       The stream must not be at its end.
 | |
|   @param  [in, out] NameSpaceRefList  List of namespace reference nodes.
 | |
| 
 | |
|   @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.
 | |
| **/
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| AmlPopulateObjectNode (
 | |
|   IN      AML_OBJECT_NODE  *ObjectNode,
 | |
|   IN  OUT AML_STREAM       *FStream,
 | |
|   IN  OUT LIST_ENTRY       *NameSpaceRefList
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   if (!IS_AML_OBJECT_NODE (ObjectNode)  ||
 | |
|       !IS_STREAM (FStream)              ||
 | |
|       IS_END_OF_STREAM (FStream)        ||
 | |
|       !IS_STREAM_FORWARD (FStream)      ||
 | |
|       (NameSpaceRefList == NULL))
 | |
|   {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   Status = EFI_SUCCESS;
 | |
| 
 | |
|   // Don't parse the fixed arguments of method invocation nodes.
 | |
|   // The AML encoding for method invocations in the ACPI specification 6.3 is:
 | |
|   // MethodInvocation := NameString TermArgList
 | |
|   // Since the AML specification does not define an OpCode for method
 | |
|   // invocation, this AML parser defines a pseudo opcode and redefines the
 | |
|   // grammar for simplicity as:
 | |
|   // MethodInvocation := MethodInvocationOp NameString ArgumentCount TermArgList
 | |
|   // ArgumentCount    := ByteData
 | |
|   // Due to this difference, the MethodInvocationOp and the fixed argument
 | |
|   // i.e. ArgumentCount is not available in the AML stream and need to be
 | |
|   // handled differently.
 | |
|   if (!AmlNodeCompareOpCode (ObjectNode, AML_METHOD_INVOC_OP, 0)) {
 | |
|     // Parse the fixed list of arguments.
 | |
|     Status = AmlParseFixedArguments (
 | |
|                ObjectNode,
 | |
|                FStream,
 | |
|                NameSpaceRefList
 | |
|                );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       ASSERT (0);
 | |
|       return Status;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // Save the association [node reference/pathname] in the NameSpaceRefList.
 | |
|   // This allows to identify method invocations from other namespace
 | |
|   // paths. Method invocation need to be parsed differently.
 | |
|   if (AmlNodeHasAttribute (
 | |
|         (CONST AML_OBJECT_NODE *)ObjectNode,
 | |
|         AML_IN_NAMESPACE
 | |
|         ))
 | |
|   {
 | |
|     Status = AmlAddNameSpaceReference (
 | |
|                (CONST AML_OBJECT_NODE *)ObjectNode,
 | |
|                NameSpaceRefList
 | |
|                );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       ASSERT (0);
 | |
|       return Status;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (!IS_END_OF_STREAM (FStream)) {
 | |
|     // Parse the variable list of arguments if present.
 | |
|     if (AmlNodeHasAttribute (ObjectNode, AML_HAS_CHILD_OBJ)) {
 | |
|       Status = AmlParseVariableArguments (
 | |
|                  (AML_NODE_HEADER *)ObjectNode,
 | |
|                  FStream,
 | |
|                  NameSpaceRefList
 | |
|                  );
 | |
|     } else if (AmlNodeHasAttribute (ObjectNode, AML_HAS_BYTE_LIST)) {
 | |
|       // Parse the byte list if present.
 | |
|       Status = AmlParseByteList (
 | |
|                  ObjectNode,
 | |
|                  FStream
 | |
|                  );
 | |
|     } else if (AmlNodeHasAttribute (ObjectNode, AML_HAS_FIELD_LIST)) {
 | |
|       // Parse the field list if present.
 | |
|       Status = AmlParseFieldList (
 | |
|                  ObjectNode,
 | |
|                  FStream,
 | |
|                  NameSpaceRefList
 | |
|                  );
 | |
|     }
 | |
| 
 | |
|     // Check status and assert
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       ASSERT (0);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /** Invoke the appropriate parsing functions based on the Node type.
 | |
| 
 | |
|   @param  [in]      Node              Node from which the children are parsed.
 | |
|                                       Must be a root node or an object node.
 | |
|   @param  [in]      FStream           Forward stream containing the AML
 | |
|                                       bytecode to parse.
 | |
|                                       The stream must not be at its end.
 | |
|   @param  [in]      NameSpaceRefList  List of namespace reference nodes.
 | |
| 
 | |
|   @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.
 | |
| **/
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| AmlParseStream (
 | |
|   IN  AML_NODE_HEADER  *Node,
 | |
|   IN  AML_STREAM       *FStream,
 | |
|   IN  LIST_ENTRY       *NameSpaceRefList
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   if (IS_AML_ROOT_NODE (Node)) {
 | |
|     Status = AmlPopulateRootNode (
 | |
|                (AML_ROOT_NODE *)Node,
 | |
|                FStream,
 | |
|                NameSpaceRefList
 | |
|                );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       ASSERT (0);
 | |
|     }
 | |
|   } else if (IS_AML_OBJECT_NODE (Node)) {
 | |
|     Status = AmlPopulateObjectNode (
 | |
|                (AML_OBJECT_NODE *)Node,
 | |
|                FStream,
 | |
|                NameSpaceRefList
 | |
|                );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       ASSERT (0);
 | |
|     }
 | |
|   } else {
 | |
|     // Data node or other.
 | |
|     ASSERT (0);
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /** Parse the definition block.
 | |
| 
 | |
|   This function parses the whole AML blob. It starts with the ACPI DSDT/SSDT
 | |
|   header and then parses the AML bytestream.
 | |
|   A tree structure is returned via the RootPtr.
 | |
|   The tree must be deleted with the AmlDeleteTree function.
 | |
| 
 | |
|   @param  [in]  DefinitionBlock   Pointer to the definition block.
 | |
|   @param  [out] RootPtr           Pointer to the root node of the tree.
 | |
| 
 | |
|   @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
 | |
| AmlParseDefinitionBlock (
 | |
|   IN  CONST EFI_ACPI_DESCRIPTION_HEADER  *DefinitionBlock,
 | |
|   OUT       AML_ROOT_NODE                **RootPtr
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS     Status;
 | |
|   EFI_STATUS     Status1;
 | |
|   AML_STREAM     Stream;
 | |
|   AML_ROOT_NODE  *Root;
 | |
| 
 | |
|   LIST_ENTRY  NameSpaceRefList;
 | |
| 
 | |
|   UINT8   *Buffer;
 | |
|   UINT32  MaxBufferSize;
 | |
| 
 | |
|   if ((DefinitionBlock == NULL)   ||
 | |
|       (RootPtr == NULL))
 | |
|   {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   Buffer = (UINT8 *)DefinitionBlock + sizeof (EFI_ACPI_DESCRIPTION_HEADER);
 | |
|   if (DefinitionBlock->Length < sizeof (EFI_ACPI_DESCRIPTION_HEADER)) {
 | |
|     ASSERT (0);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   MaxBufferSize = DefinitionBlock->Length -
 | |
|                   (UINT32)sizeof (EFI_ACPI_DESCRIPTION_HEADER);
 | |
| 
 | |
|   // Create a root node.
 | |
|   Status = AmlCreateRootNode (
 | |
|              (EFI_ACPI_DESCRIPTION_HEADER *)DefinitionBlock,
 | |
|              &Root
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     ASSERT (0);
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   *RootPtr = Root;
 | |
| 
 | |
|   if (MaxBufferSize == 0) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   // Initialize a stream to parse the AML bytecode.
 | |
|   Status = AmlStreamInit (
 | |
|              &Stream,
 | |
|              Buffer,
 | |
|              MaxBufferSize,
 | |
|              EAmlStreamDirectionForward
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     ASSERT (0);
 | |
|     goto error_handler;
 | |
|   }
 | |
| 
 | |
|   // Initialize the NameSpaceRefList, holding references to nodes declaring
 | |
|   // a name in the AML namespace.
 | |
|   InitializeListHead (&NameSpaceRefList);
 | |
| 
 | |
|   // Parse the whole AML blob.
 | |
|   Status = AmlParseStream (
 | |
|              (AML_NODE_HEADER *)Root,
 | |
|              &Stream,
 | |
|              &NameSpaceRefList
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     ASSERT (0);
 | |
|     goto error_handler;
 | |
|   }
 | |
| 
 | |
|   // Check the whole AML blob has been parsed.
 | |
|   if (!IS_END_OF_STREAM (&Stream)) {
 | |
|     ASSERT (0);
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     goto error_handler;
 | |
|   }
 | |
| 
 | |
|   // Print the list of NameSpace reference nodes.
 | |
|   // AmlDbgPrintNameSpaceRefList (&NameSpaceRefList);
 | |
| 
 | |
|   // Delete the NameSpaceRefList
 | |
|   goto exit_handler;
 | |
| 
 | |
| error_handler:
 | |
|   if (Root != NULL) {
 | |
|     AmlDeleteTree ((AML_NODE_HEADER *)Root);
 | |
|   }
 | |
| 
 | |
| exit_handler:
 | |
|   Status1 = AmlDeleteNameSpaceRefList (&NameSpaceRefList);
 | |
|   if (EFI_ERROR (Status1)) {
 | |
|     ASSERT (0);
 | |
|     if (!EFI_ERROR (Status)) {
 | |
|       return Status1;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 |