Fix ECC error 8001 reported errors in AmlDbgPrint.
  [8001] Only capital letters are allowed to be used
         for #define declarations.
Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
Reviewed-by: Alexei Fedorov <Alexei.Fedorov@arm.com>
		
	
		
			
				
	
	
		
			1449 lines
		
	
	
		
			46 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1449 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;
 | 
						|
}
 |