summaryrefslogtreecommitdiffstats
path: root/DynamicTablesPkg
diff options
context:
space:
mode:
authorPierre Gondois <pierre.gondois@arm.com>2020-08-05 10:40:22 +0100
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>2020-08-13 18:00:06 +0000
commit9f2d50f145191733e502667327c2129034a93099 (patch)
treed51df8db1150bd5f50677ef6fe52a4cc154f59fe /DynamicTablesPkg
parentd9800046ea43cdbd16e91ba5abf9742eb075d57f (diff)
downloadedk2-9f2d50f145191733e502667327c2129034a93099.tar.gz
edk2-9f2d50f145191733e502667327c2129034a93099.tar.bz2
edk2-9f2d50f145191733e502667327c2129034a93099.zip
DynamicTablesPkg: AML Parser
Both ASL and AML are declarative language. The ASL code is compiled to AML bytecode. The AML bytecode is processed by the ACPI AML interpreter that runs as part of an OS. AML has a complex encoding making dynamic generation of Definition Block tables difficult. Dynamic AML generation involves techniques like AML Fixup and AML Codegen, both requiring parsing of AML bytecode. The AML parser is a module that parses an AML byte stream and represents it as an AML tree. Representing the AML bytecode as an AML tree is key to reducing the complexity and enabling Dynamic AML generation. In an AML Tree each AML statement (that also corresponds to an ASL statement) is represented as an 'Object Node'. Each Object Node has an OpCode and up to 6 Fixed Arguments followed by a list of Variable Arguments. (ObjectNode) \ |- [0][1][2][3][4][5] # Fixed Arguments |- {(VarArg1)->(VarArg2)->...N} # Variable Arguments A Fixed Argument or Variable Argument can be either an Object Node or a Data Node. A 'Data Node' consists of a data buffer. A 'Root Node' is a special type of Object Node that does not have an Opcode or Fixed Arguments. It only has a list of Variable Arguments. The Root Node is at the top of the AML tree and contains the Definition Block Header. The AML parser uses the 'AML Encoding' to parse an AML byte stream and represents it as an AML Tree. Representing in the form of an AML tree simplifies modification, addition and removal of the tree nodes. The modified tree can then be serialised to a buffer representing a Definition Block table. Signed-off-by: Pierre Gondois <pierre.gondois@arm.com> Signed-off-by: Sami Mujawar <sami.mujawar@arm.com> Reviewed-by: Alexei Fedorov <Alexei.Fedorov@arm.com>
Diffstat (limited to 'DynamicTablesPkg')
-rw-r--r--DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlParser.c1448
-rw-r--r--DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlParser.h72
2 files changed, 1520 insertions, 0 deletions
diff --git a/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlParser.c b/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlParser.c
new file mode 100644
index 0000000000..380ac9bbce
--- /dev/null
+++ b/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlParser.c
@@ -0,0 +1,1448 @@
+/** @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;
+ }
+
+ DumpRaw (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;
+ }
+
+ DumpRaw (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');
+
+ DumpRaw (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.
+ DumpRaw (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.
+ DumpRaw (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;
+ }
+
+ DumpRaw (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;
+ }
+
+ DumpRaw (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;
+}
diff --git a/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlParser.h b/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlParser.h
new file mode 100644
index 0000000000..096a9596e1
--- /dev/null
+++ b/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlParser.h
@@ -0,0 +1,72 @@
+/** @file
+ AML Parser.
+
+ Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef AML_PARSER_H_
+#define AML_PARSER_H_
+
+#include <AmlNodeDefines.h>
+#include <Stream/AmlStream.h>
+
+/** 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
+ );
+
+/** 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
+ );
+
+#endif // AML_PARSER_H_