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