aboutsummaryrefslogtreecommitdiffstats
path: root/roms/edk2/DynamicTablesPkg/Library/Common/AmlLib/Parser
diff options
context:
space:
mode:
authorAngelos Mouzakitis <a.mouzakitis@virtualopensystems.com>2023-10-10 14:33:42 +0000
committerAngelos Mouzakitis <a.mouzakitis@virtualopensystems.com>2023-10-10 14:33:42 +0000
commitaf1a266670d040d2f4083ff309d732d648afba2a (patch)
tree2fc46203448ddcc6f81546d379abfaeb323575e9 /roms/edk2/DynamicTablesPkg/Library/Common/AmlLib/Parser
parente02cda008591317b1625707ff8e115a4841aa889 (diff)
Add submodule dependency filesHEADmaster
Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
Diffstat (limited to 'roms/edk2/DynamicTablesPkg/Library/Common/AmlLib/Parser')
-rw-r--r--roms/edk2/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlFieldListParser.c375
-rw-r--r--roms/edk2/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlFieldListParser.h77
-rw-r--r--roms/edk2/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlMethodParser.c1458
-rw-r--r--roms/edk2/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlMethodParser.h188
-rw-r--r--roms/edk2/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlParser.c1448
-rw-r--r--roms/edk2/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlParser.h72
-rw-r--r--roms/edk2/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlResourceDataParser.c328
-rw-r--r--roms/edk2/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlResourceDataParser.h71
8 files changed, 4017 insertions, 0 deletions
diff --git a/roms/edk2/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlFieldListParser.c b/roms/edk2/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlFieldListParser.c
new file mode 100644
index 000000000..c25ee22dc
--- /dev/null
+++ b/roms/edk2/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlFieldListParser.c
@@ -0,0 +1,375 @@
+/** @file
+ AML Field List Parser.
+
+ Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Parser/AmlFieldListParser.h>
+
+#include <AmlCoreInterface.h>
+#include <AmlDbgPrint/AmlDbgPrint.h>
+#include <Parser/AmlMethodParser.h>
+#include <Parser/AmlParser.h>
+#include <Tree/AmlNode.h>
+#include <Tree/AmlTree.h>
+
+/** Parse a field element.
+
+ The field elements this function can parse are one of:
+ - ReservedField;
+ - AccessField;
+ - ConnectField;
+ - ExtendedAccessField.
+ Indeed, the NamedField field element doesn't have an OpCode. Thus it needs
+ to be parsed differently.
+
+ @param [in] FieldByteEncoding Field byte encoding to parse.
+ @param [in, out] FieldNode Field node to attach the field
+ element to.
+ Must have the AML_HAS_FIELD_LIST
+ attribute.
+ @param [in, out] FStream Forward stream pointing to a field
+ element not being a named field.
+ The stream must not be at its end.
+ @param [in, out] NameSpaceRefList List of namespace reference nodes,
+ allowing to associate an absolute
+ path to a node in 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.
+*/
+STATIC
+EFI_STATUS
+EFIAPI
+AmlParseFieldElement (
+ IN CONST AML_BYTE_ENCODING * FieldByteEncoding,
+ IN OUT AML_OBJECT_NODE * FieldNode,
+ IN OUT AML_STREAM * FStream,
+ IN OUT LIST_ENTRY * NameSpaceRefList
+ )
+{
+ EFI_STATUS Status;
+
+ UINT8 * CurrPos;
+ AML_OBJECT_NODE * NewNode;
+
+ UINT32 PkgLenOffset;
+ UINT32 PkgLenSize;
+
+ // Check whether the node is an Object Node and has a field list.
+ // The byte encoding must be a field element.
+ if ((FieldByteEncoding == NULL) ||
+ ((FieldByteEncoding->Attribute & AML_IS_FIELD_ELEMENT) == 0) ||
+ ((FieldByteEncoding->Attribute & AML_IS_PSEUDO_OPCODE) ==
+ AML_IS_PSEUDO_OPCODE) ||
+ !AmlNodeHasAttribute (FieldNode, AML_HAS_FIELD_LIST) ||
+ !IS_STREAM (FStream) ||
+ IS_END_OF_STREAM (FStream) ||
+ !IS_STREAM_FORWARD (FStream) ||
+ (NameSpaceRefList == NULL)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CurrPos = AmlStreamGetCurrPos (FStream);
+ if (CurrPos == NULL) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Skip the field opcode (1 byte) as it is already in the FieldByteEncoding.
+ DumpRaw (CurrPos, 1);
+ Status = AmlStreamProgress (FStream, 1);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ CurrPos = AmlStreamGetCurrPos (FStream);
+ if (CurrPos == NULL) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Parse the PkgLen if available.
+ PkgLenSize = 0;
+ if ((FieldByteEncoding->Attribute & AML_HAS_PKG_LENGTH) ==
+ AML_HAS_PKG_LENGTH) {
+ PkgLenOffset = AmlGetPkgLength (CurrPos, &PkgLenSize);
+ if (PkgLenOffset == 0) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Move stream forward as the PkgLen has been read.
+ DumpRaw (CurrPos, PkgLenOffset);
+ Status = AmlStreamProgress (FStream, PkgLenOffset);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Update the current position as PkgLen has been parsed.
+ CurrPos = AmlStreamGetCurrPos (FStream);
+ }
+
+ Status = AmlCreateObjectNode (
+ FieldByteEncoding,
+ PkgLenSize,
+ &NewNode
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Add the FieldElement to the Variable Argument List.
+ Status = AmlVarListAddTailInternal (
+ (AML_NODE_HEADER*)FieldNode,
+ (AML_NODE_HEADER*)NewNode
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ // Delete the sub-tree if the insertion failed.
+ // Otherwise its reference will be lost.
+ AmlDeleteTree ((AML_NODE_HEADER*)NewNode);
+ return Status;
+ }
+
+ // Some field elements do not have fixed arguments.
+ if (!IS_END_OF_STREAM (FStream)) {
+ // Parse the fixed arguments of the field element.
+ Status = AmlParseFixedArguments (
+ NewNode,
+ FStream,
+ NameSpaceRefList
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ }
+ }
+
+ return Status;
+}
+
+/** Parse a named field element.
+
+ Indeed, the NamedField field element doesn't have an OpCode. Thus it needs
+ to be parsed differently. NamedField field element start with a char.
+
+ @param [in] NamedFieldByteEncoding Field byte encoding to parse.
+ @param [in, out] FieldNode Field node to attach the field
+ element to.
+ Must have the AML_HAS_FIELD_LIST
+ attribute.
+ @param [in, out] FStream Forward stream pointing to a named
+ field element.
+ The stream must not be at its end.
+ @param [in, out] NameSpaceRefList List of namespace reference nodes,
+ allowing to associate an absolute
+ path to a node in 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.
+*/
+STATIC
+EFI_STATUS
+EFIAPI
+AmlParseNamedFieldElement (
+ IN CONST AML_BYTE_ENCODING * NamedFieldByteEncoding,
+ IN OUT AML_OBJECT_NODE * FieldNode,
+ IN OUT AML_STREAM * FStream,
+ IN OUT LIST_ENTRY * NameSpaceRefList
+)
+{
+ EFI_STATUS Status;
+ AML_OBJECT_NODE * NewNode;
+
+ // Check whether the node is an Object Node and has a field list.
+ // The byte encoding must be a char.
+ if ((NamedFieldByteEncoding == NULL) ||
+ ((NamedFieldByteEncoding->Attribute & AML_IS_NAME_CHAR) == 0) ||
+ !AmlNodeHasAttribute (FieldNode, AML_HAS_FIELD_LIST) ||
+ !IS_STREAM (FStream) ||
+ IS_END_OF_STREAM (FStream) ||
+ !IS_STREAM_FORWARD (FStream) ||
+ (NameSpaceRefList == NULL)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Create a NamedField node.
+ Status = AmlCreateObjectNode (
+ AmlGetFieldEncodingByOpCode (AML_FIELD_NAMED_OP, 0),
+ 0,
+ &NewNode
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Add the NamedField node to the variable argument list.
+ Status = AmlVarListAddTailInternal (
+ (AML_NODE_HEADER*)FieldNode,
+ (AML_NODE_HEADER*)NewNode
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ // Delete the sub-tree if the insertion failed.
+ // Otherwise its reference will be lost.
+ AmlDeleteTree ((AML_NODE_HEADER*)NewNode);
+ return Status;
+ }
+
+ // Parse the fixed arguments: [0]NameSeg, [1]PkgLen.
+ Status = AmlParseFixedArguments (
+ NewNode,
+ FStream,
+ NameSpaceRefList
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Add the NamedField to the namespace reference list.
+ Status = AmlAddNameSpaceReference (
+ NewNode,
+ NameSpaceRefList
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+/** Parse the FieldList contained in the stream.
+
+ Create an object node for each field element parsed in the field list
+ available in the Stream, and add them to the variable list of arguments
+ of the FieldNode.
+
+ Nodes that can have a field list are referred as field nodes. They have the
+ AML_HAS_FIELD_LIST attribute.
+
+ According to the ACPI 6.3 specification, s20.2.5.2 "Named Objects Encoding",
+ field elements can be:
+ - NamedField := NameSeg PkgLength;
+ - ReservedField := 0x00 PkgLength;
+ - AccessField := 0x01 AccessType AccessAttrib;
+ - ConnectField := <0x02 NameString> | <0x02 BufferData>;
+ - ExtendedAccessField := 0x03 AccessType ExtendedAccessAttrib AccessLength.
+
+ A small set of opcodes describes the field elements. They are referred as
+ field opcodes. An AML_BYTE_ENCODING table has been created for field OpCodes.
+ Field elements:
+ - don't have a SubOpCode;
+ - have at most 3 fixed arguments (as opposed to 6 for standard AML objects);
+ - don't have a variable list of arguments;
+ - only the NamedField field element is part of the AML namespace.
+
+ ConnectField's BufferData is a buffer node containing a single
+ resource data element.
+ NamedField field elements don't have an AML OpCode. NameSeg starts with a
+ Char type and can thus be differentiated from the Opcodes for other fields.
+ A pseudo OpCode has been created to simplify the parser.
+
+ The branch created from parsing a field node is as:
+ (FieldNode)
+ \
+ |- [FixedArg[0]][FixedArg[1]] # Fixed Arguments
+ |- {(FieldElement[0])->(FieldElement[1])->...)} # Variable Arguments
+
+ With FieldElement[n] being one of NamedField, ReservedField, AccessField,
+ ConnectField, ExtendedAccessField.
+
+ @param [in] FieldNode Field node.
+ Must have the AML_HAS_FIELD_LIST
+ attribute.
+ @param [in] FStream Forward stream pointing to a field list.
+ The stream must not be at its end.
+ @param [in] NameSpaceRefList List of namespace reference nodes,
+ allowing to associate an absolute
+ path to a node in 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
+AmlParseFieldList (
+ IN AML_OBJECT_NODE * FieldNode,
+ IN AML_STREAM * FStream,
+ IN LIST_ENTRY * NameSpaceRefList
+ )
+{
+ EFI_STATUS Status;
+
+ UINT8 * CurrPos;
+ CONST AML_BYTE_ENCODING * FieldByteEncoding;
+ CONST AML_BYTE_ENCODING * NamedFieldByteEncoding;
+
+ // Check whether the node is an Object Node and has a field list.
+ if (!AmlNodeHasAttribute (FieldNode, AML_HAS_FIELD_LIST) ||
+ !IS_STREAM (FStream) ||
+ IS_END_OF_STREAM (FStream) ||
+ !IS_STREAM_FORWARD (FStream) ||
+ (NameSpaceRefList == NULL)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Iterate through the field elements, creating nodes
+ // and adding them to the variable list of elements of Node.
+ while (!IS_END_OF_STREAM (FStream)) {
+ CurrPos = AmlStreamGetCurrPos (FStream);
+
+ // Check for a field opcode.
+ FieldByteEncoding = AmlGetFieldEncoding (CurrPos);
+ if (FieldByteEncoding != NULL) {
+ Status = AmlParseFieldElement (
+ FieldByteEncoding,
+ FieldNode,
+ FStream,
+ NameSpaceRefList
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+ } else {
+ // Handle the case of Pseudo OpCodes.
+ // NamedField has a Pseudo OpCode and starts with a NameChar. Therefore,
+ // call AmlGetByteEncoding() to check that the encoding is NameChar.
+ NamedFieldByteEncoding = AmlGetByteEncoding (CurrPos);
+ if ((NamedFieldByteEncoding != NULL) &&
+ (NamedFieldByteEncoding->Attribute & AML_IS_NAME_CHAR)) {
+ // This is a NamedField field element since it is starting with a char.
+ Status = AmlParseNamedFieldElement (
+ NamedFieldByteEncoding,
+ FieldNode,
+ FStream,
+ NameSpaceRefList
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+ } else {
+ // A field opcode or an AML byte encoding is expected.
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ } // while
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlFieldListParser.h b/roms/edk2/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlFieldListParser.h
new file mode 100644
index 000000000..576f6c41d
--- /dev/null
+++ b/roms/edk2/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlFieldListParser.h
@@ -0,0 +1,77 @@
+/** @file
+ AML Field List.
+
+ Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef AML_FIELD_LIST_PARSER_H_
+#define AML_FIELD_LIST_PARSER_H_
+
+#include <AmlNodeDefines.h>
+#include <Stream/AmlStream.h>
+
+/** Parse the FieldList contained in the stream.
+
+ Create an object node for each field element parsed in the field list
+ available in the Stream, and add them to the variable list of arguments
+ of the FieldNode.
+
+ Nodes that can have a field list are referred as field nodes. They have the
+ AML_HAS_FIELD_LIST attribute.
+
+ According to the ACPI 6.3 specification, s20.2.5.2 "Named Objects Encoding",
+ field elements can be:
+ - NamedField := NameSeg PkgLength;
+ - ReservedField := 0x00 PkgLength;
+ - AccessField := 0x01 AccessType AccessAttrib;
+ - ConnectField := <0x02 NameString> | <0x02 BufferData>;
+ - ExtendedAccessField := 0x03 AccessType ExtendedAccessAttrib AccessLength.
+
+ A small set of opcodes describes the field elements. They are referred as
+ field opcodes. An AML_BYTE_ENCODING table has been created for field OpCodes.
+ Field elements:
+ - don't have a SubOpCode;
+ - have at most 3 fixed arguments (as opposed to 6 for standard AML objects);
+ - don't have a variable list of arguments;
+ - only the NamedField field element is part of the AML namespace.
+
+ ConnectField's BufferData is a buffer node containing a single
+ resource data element.
+ NamedField field elements don't have an AML OpCode. NameSeg starts with a
+ Char type and can thus be differentiated from the Opcodes for other fields.
+ A pseudo OpCode has been created to simplify the parser.
+
+ The branch created from parsing a field node is as:
+ (FieldNode)
+ \
+ |- [FixedArg[0]][FixedArg[1]] # Fixed Arguments
+ |- {(FieldElement[0])->(FieldElement[1])->...)} # Variable Arguments
+
+ With FieldElement[n] being one of NamedField, ReservedField, AccessField,
+ ConnectField, ExtendedAccessField.
+
+ @param [in] FieldNode Field node.
+ Must have the AML_HAS_FIELD_LIST
+ attribute.
+ @param [in] FStream Forward stream pointing to a field list.
+ The stream must not be at its end.
+ @param [in] NameSpaceRefList List of namespace reference nodes,
+ allowing to associate an absolute
+ path to a node in 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
+AmlParseFieldList (
+ IN AML_OBJECT_NODE * FieldNode,
+ IN AML_STREAM * FStream,
+ IN LIST_ENTRY * NameSpaceRefList
+ );
+
+#endif // AML_FIELD_LIST_PARSER_H_
diff --git a/roms/edk2/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlMethodParser.c b/roms/edk2/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlMethodParser.c
new file mode 100644
index 000000000..bc98d950b
--- /dev/null
+++ b/roms/edk2/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlMethodParser.c
@@ -0,0 +1,1458 @@
+/** @file
+ AML Method Parser.
+
+ Copyright (c) 2020, Arm Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Parser/AmlMethodParser.h>
+
+#include <AmlCoreInterface.h>
+#include <AmlDbgPrint/AmlDbgPrint.h>
+#include <NameSpace/AmlNameSpace.h>
+#include <Parser/AmlParser.h>
+#include <Tree/AmlNode.h>
+#include <Tree/AmlTree.h>
+#include <String/AmlString.h>
+
+/** Delete a namespace reference node and its pathname.
+
+ It is the caller's responsibility to check the NameSpaceRefNode has been
+ removed from any list the node is part of.
+
+ @param [in] NameSpaceRefNode Pointer to an AML_NAMESPACE_REF_NODE.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+AmlDeleteNameSpaceRefNode (
+ IN AML_NAMESPACE_REF_NODE * NameSpaceRefNode
+ )
+{
+ if (NameSpaceRefNode == NULL) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (NameSpaceRefNode->RawAbsolutePath != NULL) {
+ FreePool ((CHAR8*)NameSpaceRefNode->RawAbsolutePath);
+ } else {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FreePool (NameSpaceRefNode);
+ return EFI_SUCCESS;
+}
+
+/** Delete a list of namespace reference nodes.
+
+ @param [in] NameSpaceRefList List of namespace reference nodes.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+EFI_STATUS
+EFIAPI
+AmlDeleteNameSpaceRefList (
+ IN LIST_ENTRY * NameSpaceRefList
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY * CurrentLink;
+
+ if (NameSpaceRefList == NULL) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ while (!IsListEmpty (NameSpaceRefList)) {
+ CurrentLink = NameSpaceRefList->ForwardLink;
+ RemoveEntryList (CurrentLink);
+ Status = AmlDeleteNameSpaceRefNode (
+ (AML_NAMESPACE_REF_NODE*)CurrentLink
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+ } // while
+
+ return EFI_SUCCESS;
+}
+
+/** Create an AML_NAMESPACE_REF_NODE.
+
+ A Buffer is allocated to store the raw AML absolute path.
+
+ @param [in] ObjectNode Node being part of the namespace.
+ Must be have the AML_IN_NAMESPACE
+ attribute.
+ @param [in] RawAbsolutePath AML raw absolute path of the ObjectNode.
+ A raw NameString is a concatenated list
+ of 4 chars long names.
+ @param [in] RawAbsolutePathSize Size of the RawAbsolutePath buffer.
+ @param [out] NameSpaceRefNodePtr The created AML_METHOD_REF_NODE.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+AmlCreateMethodRefNode (
+ IN CONST AML_OBJECT_NODE * ObjectNode,
+ IN CONST CHAR8 * RawAbsolutePath,
+ IN UINT32 RawAbsolutePathSize,
+ OUT AML_NAMESPACE_REF_NODE ** NameSpaceRefNodePtr
+ )
+{
+ AML_NAMESPACE_REF_NODE * NameSpaceRefNode;
+
+ if (!AmlNodeHasAttribute (ObjectNode, AML_IN_NAMESPACE) ||
+ (RawAbsolutePath == NULL) ||
+ (RawAbsolutePathSize == 0) ||
+ (NameSpaceRefNodePtr == NULL)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ NameSpaceRefNode = AllocateZeroPool (sizeof (AML_NAMESPACE_REF_NODE));
+ if (NameSpaceRefNode == NULL) {
+ ASSERT (0);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NameSpaceRefNode->RawAbsolutePathSize = RawAbsolutePathSize;
+ NameSpaceRefNode->RawAbsolutePath = AllocateCopyPool (
+ RawAbsolutePathSize,
+ RawAbsolutePath
+ );
+ if (NameSpaceRefNode->RawAbsolutePath == NULL) {
+ FreePool (NameSpaceRefNode);
+ ASSERT (0);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ InitializeListHead (&NameSpaceRefNode->Link);
+
+ NameSpaceRefNode->NodeRef = ObjectNode;
+ *NameSpaceRefNodePtr = NameSpaceRefNode;
+
+ return EFI_SUCCESS;
+}
+
+#if !defined (MDEPKG_NDEBUG)
+
+/** Print the list of raw absolute paths of the NameSpace reference list.
+
+ @param [in] NameSpaceRefList List of NameSpace reference nodes.
+**/
+VOID
+EFIAPI
+AmlDbgPrintNameSpaceRefList (
+ IN CONST LIST_ENTRY * NameSpaceRefList
+ )
+{
+ LIST_ENTRY * CurrLink;
+ AML_NAMESPACE_REF_NODE * CurrNameSpaceNode;
+
+ if (NameSpaceRefList == NULL) {
+ ASSERT (0);
+ return;
+ }
+
+ DEBUG ((DEBUG_INFO, "AmlMethodParser: List of available raw AML paths:\n"));
+
+ CurrLink = NameSpaceRefList->ForwardLink;
+ while (CurrLink != NameSpaceRefList) {
+ CurrNameSpaceNode = (AML_NAMESPACE_REF_NODE*)CurrLink;
+
+ AmlDbgPrintChars (
+ DEBUG_INFO,
+ CurrNameSpaceNode->RawAbsolutePath,
+ CurrNameSpaceNode->RawAbsolutePathSize
+ );
+ DEBUG ((DEBUG_INFO, "\n"));
+
+ CurrLink = CurrLink->ForwardLink;
+ }
+
+ DEBUG ((DEBUG_INFO, "\n"));
+}
+
+#endif // MDEPKG_NDEBUG
+
+/** From a forward stream pointing to a NameString,
+ initialize a raw backward stream.
+
+ StartOfStream
+ Fstream: CurrPos EndOfStream
+ v v
+ +-----------------------------------------+
+ |^^^[Multi-name prefix]AAAA.BBBB.CCCC |
+ +-----------------------------------------+
+ ^ ^
+ RawPathNameBStream: EndOfStream CurrPos
+ StartOfStream
+
+ No memory is allocated when initializing the stream.
+
+ @param [in] FStream Forward stream pointing to a NameString.
+ The stream must not be at its end.
+ @param [out] RawPathNameBStream Backward stream containing the
+ raw AML path.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+AmlInitRawPathBStream (
+ IN CONST AML_STREAM * FStream,
+ OUT AML_STREAM * RawPathNameBStream
+ )
+{
+ EFI_STATUS Status;
+
+ UINT8 * RawPathBuffer;
+ CONST CHAR8 * Buffer;
+
+ UINT32 Root;
+ UINT32 ParentPrefix;
+ UINT32 SegCount;
+
+ if (!IS_STREAM (FStream) ||
+ IS_END_OF_STREAM (FStream) ||
+ !IS_STREAM_FORWARD (FStream) ||
+ (RawPathNameBStream == NULL)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Buffer = (CONST CHAR8*)AmlStreamGetCurrPos (FStream);
+ if (Buffer == NULL) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Parse the NameString information.
+ Status = AmlParseNameStringInfo (
+ Buffer,
+ &Root,
+ &ParentPrefix,
+ &SegCount
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Get the beginning of the raw NameString.
+ RawPathBuffer = (UINT8*)AmlGetFirstNameSeg (
+ Buffer,
+ Root,
+ ParentPrefix
+ );
+ if (RawPathBuffer == NULL) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Initialize a backward stream containing the raw path.
+ Status = AmlStreamInit (
+ RawPathNameBStream,
+ RawPathBuffer,
+ (SegCount * AML_NAME_SEG_SIZE),
+ EAmlStreamDirectionBackward
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+/** Get the first node in the ParentNode branch that is part of the
+ AML namespace and has its name defined.
+
+ This is different from getting the first namespace node. This function is
+ necessary because an absolute path is built while the tree is not complete
+ yet. The parsing is ongoing.
+
+ For instance, the ASL statement "CreateXXXField ()" adds a field in the
+ AML namespace, but the name it defines is the last fixed argument of the
+ corresponding object.
+ If an AML path is referenced in its first fixed argument, it is not
+ possible to resolve the name of the CreateXXXField object. However, the AML
+ path is not part of the scope created by the CreateXXXField object, so this
+ scope can be skipped.
+
+ In the following ASL code, the method invocation to MET0 is done in the
+ "CreateField" statement. The "CreateField" statement defines the "FIEL"
+ path in the AML namespace. However, MET0 must be not be resolved in the
+ "CreateField" object scope. It needs to be resolved in its parent.
+ ASL code:
+ Method (MET0, 0,,, BuffObj) {
+ Return (Buffer (0x1000) {})
+ }
+ CreateField (MET0(), 0x100, 0x4, FIEL)
+
+ @param [in] Node Node to get the first named node from, in
+ its hierarchy.
+ @param [out] OutNamedNode First named node in Node's hierarchy.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+AmlGetFirstNamedAncestorNode (
+ IN CONST AML_NODE_HEADER * Node,
+ OUT AML_NODE_HEADER ** OutNamedNode
+ )
+{
+ EFI_STATUS Status;
+ CONST AML_NODE_HEADER * NameSpaceNode;
+
+ if ((!IS_AML_OBJECT_NODE (Node) &&
+ !IS_AML_ROOT_NODE (Node)) ||
+ (OutNamedNode == NULL)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // If Node is not the root node and doesn't have a name defined yet,
+ // get the ancestor NameSpace node.
+ while (!IS_AML_ROOT_NODE (Node) &&
+ !(AmlNodeHasAttribute (
+ (CONST AML_OBJECT_NODE*)Node,
+ AML_IN_NAMESPACE) &&
+ AmlNodeGetName ((CONST AML_OBJECT_NODE*)Node) != NULL)) {
+ Status = AmlGetFirstAncestorNameSpaceNode (
+ Node,
+ (AML_NODE_HEADER**)&NameSpaceNode
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+ // The NameSpaceNode may not have its name defined as yet. In this
+ // case get the next ancestor node.
+ Node = NameSpaceNode;
+ }
+
+ *OutNamedNode = (AML_NODE_HEADER*)Node;
+
+ return EFI_SUCCESS;
+}
+
+/** From a ParentNode and a forward stream pointing to a relative path,
+ build a raw AML absolute path and return it in a backward stream.
+
+ No memory is allocated in this function, the out stream must be initialized
+ with a buffer long enough to hold any raw absolute AML path.
+
+ @param [in] ParentNode Parent node of the namespace
+ node from which the absolute
+ path is built. ParentNode isn't
+ necessarily a namespace node.
+ Must be a root or an object node.
+ @param [in] PathnameFStream Forward stream pointing to the
+ beginning of a pathname (any
+ NameString).
+ The stream must not be at its end.
+ @param [in, out] AbsolutePathBStream Backward stream where the raw
+ absolute path is written. The
+ stream must be already initialized.
+ The stream must not be at its end.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+AmlBuildRawMethodAbsolutePath (
+ IN CONST AML_NODE_HEADER * ParentNode,
+ IN CONST AML_STREAM * PathnameFStream,
+ IN OUT AML_STREAM * AbsolutePathBStream
+ )
+{
+ EFI_STATUS Status;
+
+ AML_NODE_HEADER * NamedParentNode;
+ UINT8 * RawPathBuffer;
+ CONST CHAR8 * CurrPos;
+
+ UINT32 Root;
+ UINT32 ParentPrefix;
+ UINT32 SegCount;
+
+ if ((!IS_AML_OBJECT_NODE (ParentNode) &&
+ !IS_AML_ROOT_NODE (ParentNode)) ||
+ !IS_STREAM (PathnameFStream) ||
+ IS_END_OF_STREAM (PathnameFStream) ||
+ !IS_STREAM_FORWARD (PathnameFStream) ||
+ !IS_STREAM (AbsolutePathBStream) ||
+ IS_END_OF_STREAM (AbsolutePathBStream) ||
+ !IS_STREAM_BACKWARD (AbsolutePathBStream)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CurrPos = (CONST CHAR8*)AmlStreamGetCurrPos (PathnameFStream);
+ if (CurrPos == NULL) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Parse the NameString information.
+ Status = AmlParseNameStringInfo (
+ CurrPos,
+ &Root,
+ &ParentPrefix,
+ &SegCount
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Copy the method invocation raw relative path at the end of the Stream.
+ if (SegCount != 0) {
+ // Get the beginning of the raw NameString.
+ RawPathBuffer = (UINT8*)AmlGetFirstNameSeg (
+ CurrPos,
+ Root,
+ ParentPrefix
+ );
+
+ Status = AmlStreamWrite (
+ AbsolutePathBStream,
+ RawPathBuffer,
+ SegCount * AML_NAME_SEG_SIZE
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+ }
+
+ // If the pathname contained an absolute path, this is finished, return.
+ if (Root) {
+ return Status;
+ }
+
+ // Get the first named node of the parent node in its hierarchy.
+ Status = AmlGetFirstNamedAncestorNode (ParentNode, &NamedParentNode);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Build the raw absolute path of the namespace node.
+ Status = AmlGetRawNameSpacePath (
+ NamedParentNode,
+ ParentPrefix,
+ AbsolutePathBStream
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+/** Compare two raw NameStrings stored in forward streams.
+ Compare them NameSeg by NameSeg (a NameSeg is 4 bytes long).
+
+ The two raw NameStrings can be of different size.
+
+ @param [in] RawFStream1 First forward stream to compare.
+ Points to the beginning of the raw NameString.
+ @param [in] RawFStream2 Second forward stream to compare.
+ Points to the beginning of the raw NameString.
+ @param [out] CompareCount Count of identic bytes.
+ Must be a multiple of 4 (size of a NameSeg).
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+AmlCompareRawNameString (
+ IN CONST AML_STREAM * RawFStream1,
+ IN CONST AML_STREAM * RawFStream2,
+ OUT UINT32 * CompareCount
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Index;
+
+ AML_STREAM RawFStream1Clone;
+ AML_STREAM RawFStream2Clone;
+ UINT32 Stream1Size;
+ UINT32 Stream2Size;
+ UINT32 CompareLen;
+
+ // Raw NameStrings have a size that is a multiple of the size of NameSegs.
+ if (!IS_STREAM (RawFStream1) ||
+ IS_END_OF_STREAM (RawFStream1) ||
+ !IS_STREAM_FORWARD (RawFStream1) ||
+ !IS_STREAM (RawFStream2) ||
+ IS_END_OF_STREAM (RawFStream2) ||
+ (CompareCount == NULL)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Stream1Size = AmlStreamGetFreeSpace (RawFStream1);
+ if ((Stream1Size & (AML_NAME_SEG_SIZE - 1)) != 0) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Stream2Size = AmlStreamGetFreeSpace (RawFStream2);
+ if ((Stream2Size & (AML_NAME_SEG_SIZE - 1)) != 0) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = AmlStreamClone (RawFStream1, &RawFStream1Clone);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ Status = AmlStreamClone (RawFStream2, &RawFStream2Clone);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ CompareLen = MIN (Stream1Size, Stream2Size);
+ Index = 0;
+ // Check there is enough space for a NameSeg in both Stream1 and Stream2.
+ while (Index < CompareLen) {
+ if (!AmlStreamCmp (
+ &RawFStream1Clone,
+ &RawFStream2Clone,
+ AML_NAME_SEG_SIZE)
+ ) {
+ // NameSegs are different. Break.
+ break;
+ }
+
+ Status = AmlStreamProgress (&RawFStream1Clone, AML_NAME_SEG_SIZE);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+ Status = AmlStreamProgress (&RawFStream2Clone, AML_NAME_SEG_SIZE);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ Index += AML_NAME_SEG_SIZE;
+ }
+
+ *CompareCount = Index;
+
+ return EFI_SUCCESS;
+}
+
+/** Check whether an alias can be resolved to a method definition.
+
+ Indeed, the following ASL code must be handled:
+ Method (MET0, 1) {
+ Return (0x9)
+ }
+ Alias (\MET0, \ALI0)
+ Alias (\ALI0, \ALI1)
+ \ALI1(0x5)
+ When searching for \ALI1 in the AML NameSpace, it resolves to \ALI0.
+ When searching for \ALI0 in the AML NameSpace, it resolves to \MET0.
+ When searching for \MET0 in the AML NameSpace, it resolves to a method
+ definition.
+
+ This method is a wrapper to recursively call AmlFindMethodDefinition.
+
+ @param [in] AliasNode Pointer to an Alias object node.
+ @param [in] NameSpaceRefList List of NameSpaceRef nodes.
+ @param [out] OutNameSpaceRefNode If success, and if the alias is resolved
+ to a method definition (this can go
+ through other alias indirections),
+ containing the corresponding
+ NameSpaceRef node.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+AmlResolveAliasMethod (
+ IN CONST AML_OBJECT_NODE * AliasNode,
+ IN CONST LIST_ENTRY * NameSpaceRefList,
+ OUT AML_NAMESPACE_REF_NODE ** OutNameSpaceRefNode
+ )
+{
+ EFI_STATUS Status;
+ AML_STREAM SourceAliasFStream;
+ CONST AML_DATA_NODE * DataNode;
+
+ if (!AmlNodeCompareOpCode (AliasNode, AML_ALIAS_OP, 0) ||
+ (NameSpaceRefList == NULL) ||
+ (OutNameSpaceRefNode == NULL)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // The aliased NameString (the source name) is the first fixed argument,
+ // cf. ACPI6.3 spec, s19.6.4: Alias (SourceObject, AliasObject)
+ DataNode = (CONST AML_DATA_NODE*)AmlGetFixedArgument (
+ (AML_OBJECT_NODE*)AliasNode,
+ EAmlParseIndexTerm0
+ );
+ if (DataNode == NULL) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Initialize a stream on the source alias NameString.
+ Status = AmlStreamInit (
+ &SourceAliasFStream,
+ DataNode->Buffer,
+ DataNode->Size,
+ EAmlStreamDirectionForward
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Recursively check whether the source alias NameString
+ // is a method invocation.
+ Status = AmlIsMethodInvocation (
+ AmlGetParent ((AML_NODE_HEADER*)AliasNode),
+ &SourceAliasFStream,
+ NameSpaceRefList,
+ OutNameSpaceRefNode
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ }
+
+ return Status;
+}
+
+/** Iterate through the MethodList to find the best namespace resolution.
+ If the pathname resolves to a method definition, returns it.
+
+ For instance, if the AML namespace is:
+ \
+ \-MET0 <- Device definition, absolute path: \MET0
+ \-AAAA
+ \-MET0 <- Method definition, absolute path: \AAAA.MET0
+ \-MET1 <- Method definition, absolute path: \AAAA.MET1
+ \-BBBB
+ \-CCCC
+ \-DDDD
+ \-MET0 <- Method definition, absolute path: \AAAA.BBBB.CCCC.DDDD.MET0
+
+ The list of the available pathnames is:
+ [NameSpaceRefList]
+ - \MET0 <- Device definition
+ - \AAAA
+ - \AAAA.MET0 <- Method definition
+ - \AAAA.MET1 <- Method definition
+ - \AAAA.BBBB
+ - \AAAA.BBBB.CCCC
+ - \AAAA.BBBB.CCCC.DDDD
+ - \AAAA.BBBB.CCCC.DDDD.MET0 <- Method definition
+
+ Depending on where the method invocation is done, the method definition
+ referenced changes. If the method call "MET0" is done from
+ \AAAA.BBBB.CCCC:
+ 1. Identify which pathnames end with "MET0":
+ - \MET0 <- Device definition
+ - \AAAA.MET0 <- Method definition
+ - \AAAA.BBBB.CCCC.DDDD.MET0 <- Method definition
+ 2. Resolve the method invocation:
+ - \AAAA.MET0 <- Method definition
+ 3. \AAAA.MET0 is a method definition, so return the corresponding
+ reference node.
+
+ @param [in] RawAbsolutePathFStream Forward stream pointing to a raw
+ absolute path.
+ The stream must not be at its end.
+ @param [in] RawPathNameBStream Backward stream pointing to a raw
+ pathname. This raw pathname is the
+ raw NameString of namespace node.
+ The stream must not be at its end.
+ @param [in] NameSpaceRefList List of NameSpaceRef nodes.
+ @param [out] OutNameSpaceRefNode If the two input paths are
+ referencing a method definition,
+ returns the corresponding
+ NameSpaceRef node.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+AmlFindMethodDefinition (
+ IN CONST AML_STREAM * RawAbsolutePathFStream,
+ IN CONST AML_STREAM * RawPathNameBStream,
+ IN CONST LIST_ENTRY * NameSpaceRefList,
+ OUT AML_NAMESPACE_REF_NODE ** OutNameSpaceRefNode
+ )
+{
+ EFI_STATUS Status;
+
+ LIST_ENTRY * NextLink;
+
+ // To resolve a pathname, scope levels need to be compared.
+ UINT32 NameSegScopeCount;
+ UINT32 PathNameSegScopeCount;
+ UINT32 ProbedScopeCount;
+ UINT32 BestScopeCount;
+
+ AML_STREAM ProbedRawAbsoluteFStream;
+ AML_STREAM ProbedRawAbsoluteBStream;
+
+ AML_NAMESPACE_REF_NODE * ProbedNameSpaceRefNode;
+ AML_NAMESPACE_REF_NODE * BestNameSpaceRefNode;
+
+ if (!IS_STREAM (RawAbsolutePathFStream) ||
+ IS_END_OF_STREAM (RawAbsolutePathFStream) ||
+ !IS_STREAM_FORWARD (RawAbsolutePathFStream) ||
+ ((AmlStreamGetIndex (RawAbsolutePathFStream) &
+ (AML_NAME_SEG_SIZE - 1)) != 0) ||
+ !IS_STREAM (RawPathNameBStream) ||
+ IS_END_OF_STREAM (RawPathNameBStream) ||
+ !IS_STREAM_BACKWARD (RawPathNameBStream) ||
+ ((AmlStreamGetIndex (RawPathNameBStream) &
+ (AML_NAME_SEG_SIZE - 1)) != 0) ||
+ (NameSpaceRefList == NULL) ||
+ (OutNameSpaceRefNode == NULL)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DEBUG ((DEBUG_VERBOSE, "AmlMethodParser: Checking absolute name: "));
+ AmlDbgPrintChars (
+ DEBUG_VERBOSE,
+ (CONST CHAR8*)AmlStreamGetCurrPos (RawAbsolutePathFStream),
+ AmlStreamGetMaxBufferSize (RawAbsolutePathFStream)
+ );
+ DEBUG ((DEBUG_VERBOSE, ".\n"));
+
+ BestNameSpaceRefNode = NULL;
+ BestScopeCount = 0;
+ NameSegScopeCount = AmlStreamGetMaxBufferSize (RawAbsolutePathFStream);
+ PathNameSegScopeCount = AmlStreamGetMaxBufferSize (RawPathNameBStream);
+
+ // Iterate through the raw AML absolute path to find the best match.
+ DEBUG ((DEBUG_VERBOSE, "AmlMethodParser: Comparing with: "));
+ NextLink = NameSpaceRefList->ForwardLink;
+ while (NextLink != NameSpaceRefList) {
+ ProbedNameSpaceRefNode = (AML_NAMESPACE_REF_NODE*)NextLink;
+
+ // Print the raw absolute path of the probed node.
+ AmlDbgPrintChars (
+ DEBUG_VERBOSE,
+ ProbedNameSpaceRefNode->RawAbsolutePath,
+ ProbedNameSpaceRefNode->RawAbsolutePathSize
+ );
+ DEBUG ((DEBUG_VERBOSE, "; "));
+
+ // If the raw AML absolute path of the probed node is longer than the
+ // searched pathname, continue.
+ // E.g.: The method call \MET0 cannot resolve to a method defined at
+ // \AAAA.MET0. The method definition is out of scope.
+ if (PathNameSegScopeCount > ProbedNameSpaceRefNode->RawAbsolutePathSize) {
+ NextLink = NextLink->ForwardLink;
+ continue;
+ }
+
+ // Initialize a backward stream for the probed node.
+ // This stream is used to compare the ending of the pathnames.
+ // E.g. if the method searched ends with "MET0", pathnames not ending with
+ // "MET0" should be skipped.
+ Status = AmlStreamInit (
+ &ProbedRawAbsoluteBStream,
+ (UINT8*)ProbedNameSpaceRefNode->RawAbsolutePath,
+ ProbedNameSpaceRefNode->RawAbsolutePathSize,
+ EAmlStreamDirectionBackward
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Compare the pathname endings. If they don't match, continue.
+ if (!AmlStreamCmp (
+ RawPathNameBStream,
+ &ProbedRawAbsoluteBStream,
+ AmlStreamGetMaxBufferSize (RawPathNameBStream))) {
+ NextLink = NextLink->ForwardLink;
+ continue;
+ }
+
+ // Initialize a forward stream for the probed node.
+ // This stream is used to count how many scope levels from the root
+ // are common with the probed node. The more there are, the better it is.
+ // E.g.: For the method invocation \AAAA.BBBB.MET0, if there are 2
+ // pathnames ending with MET0:
+ // - \AAAA.MET0 has 1 NameSeg in common with \AAAA.BBBB.MET0
+ // from the root (this is "AAAA");
+ // - \MET0 has 0 NameSeg in common with \AAAA.BBBB.MET0
+ // from the root;
+ // Thus, the best match is \AAAA.MET0.
+ Status = AmlStreamInit (
+ &ProbedRawAbsoluteFStream,
+ (UINT8*)ProbedNameSpaceRefNode->RawAbsolutePath,
+ ProbedNameSpaceRefNode->RawAbsolutePathSize,
+ EAmlStreamDirectionForward
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Count how many namespace levels are in common from the root.
+ Status = AmlCompareRawNameString (
+ RawAbsolutePathFStream,
+ &ProbedRawAbsoluteFStream,
+ &ProbedScopeCount
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ProbedScopeCount == NameSegScopeCount) {
+ // This is a perfect match. Exit the loop.
+ BestNameSpaceRefNode = ProbedNameSpaceRefNode;
+ break;
+ } else if (ProbedScopeCount > BestScopeCount) {
+ // The probed node has more scope levels in common than the
+ // last best match. Update the best match.
+ BestScopeCount = ProbedScopeCount;
+ BestNameSpaceRefNode = ProbedNameSpaceRefNode;
+ } else if (ProbedScopeCount == BestScopeCount) {
+ // The probed node has the same number of scope levels in
+ // common as the last best match.
+ if (ProbedScopeCount == 0) {
+ // There was not best match previously. Set it.
+ BestNameSpaceRefNode = ProbedNameSpaceRefNode;
+ } else {
+ // (ProbedScopeCount != 0)
+ // If there is an equivalent candidate, the best has the shortest
+ // absolute path. Indeed, a similar ProbedScopeCount and a longer
+ // path means the definition is out of the scope.
+ // E.g.: For the method invocation \AAAA.BBBB.MET0, if there are 2
+ // pathnames ending with MET0:
+ // - \AAAA.MET0 has 1 NameSegs in common with \AAAA.BBBB.MET0
+ // from the root (this is "AAAA");
+ // - \AAAA.CCCC.MET0 has 1 NameSegs in common with
+ // \AAAA.BBBB.MET0 from the root (this is "AAAA");
+ // As \AAAA.CCCC.MET0 is longer than \AAAA.MET0, it means that
+ // the pathname could have matched on more NameSegs, but it
+ // didn't because it is out of scope.
+ // Thus, the best match is \AAAA.MET0.
+ if (AmlStreamGetIndex (&ProbedRawAbsoluteFStream) <
+ BestNameSpaceRefNode->RawAbsolutePathSize) {
+ BestScopeCount = ProbedScopeCount;
+ BestNameSpaceRefNode = ProbedNameSpaceRefNode;
+ } else if (AmlStreamGetIndex (&ProbedRawAbsoluteFStream) ==
+ BestNameSpaceRefNode->RawAbsolutePathSize) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ }
+
+ NextLink = NextLink->ForwardLink;
+ }
+
+ DEBUG ((DEBUG_VERBOSE, "\n"));
+
+ // Check whether the BestNameSpaceRefNode is a method definition.
+ if (BestNameSpaceRefNode != NULL) {
+ if (AmlIsMethodDefinitionNode (BestNameSpaceRefNode->NodeRef)) {
+ *OutNameSpaceRefNode = BestNameSpaceRefNode;
+ } else if (AmlNodeCompareOpCode (
+ BestNameSpaceRefNode->NodeRef,
+ AML_ALIAS_OP, 0)) {
+ // The path matches an alias. Resolve the alias and check whether
+ // this is a method defintion.
+ Status = AmlResolveAliasMethod (
+ BestNameSpaceRefNode->NodeRef,
+ NameSpaceRefList,
+ OutNameSpaceRefNode
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+ }
+ } else {
+ // If no, return NULL, even if a matching pathname has been found.
+ *OutNameSpaceRefNode = NULL;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/** Check whether a pathname is a method invocation.
+
+ If there is a matching method definition, returns the corresponding
+ NameSpaceRef node.
+
+ To do so, the NameSpaceRefList is keeping track of every namespace node
+ and its raw AML absolute path.
+ To check whether a pathname is a method invocation, a corresponding raw
+ absolute pathname is built. This raw absolute pathname is then compared
+ to the list of available pathnames. If a pathname defining a method
+ matches the scope of the input pathname, return.
+
+ @param [in] ParentNode Parent node. Node to which the node to be
+ created will be attached.
+ @param [in] FStream Forward stream pointing to the NameString
+ to find.
+ @param [in] NameSpaceRefList List of NameSpaceRef nodes.
+ @param [out] OutNameSpaceRefNode If the NameString pointed by FStream is
+ a method invocation, OutNameSpaceRefNode
+ contains the NameSpaceRef corresponding
+ to the method definition.
+ NULL otherwise.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+EFI_STATUS
+EFIAPI
+AmlIsMethodInvocation (
+ IN CONST AML_NODE_HEADER * ParentNode,
+ IN CONST AML_STREAM * FStream,
+ IN CONST LIST_ENTRY * NameSpaceRefList,
+ OUT AML_NAMESPACE_REF_NODE ** OutNameSpaceRefNode
+ )
+{
+ EFI_STATUS Status;
+
+ AML_STREAM RawPathNameBStream;
+ AML_STREAM RawAbsolutePathFStream;
+
+ AML_STREAM RawAbsolutePathBStream;
+ UINT8 * RawAbsolutePathBuffer;
+ UINT32 RawAbsolutePathBufferSize;
+
+ AML_NAMESPACE_REF_NODE * NameSpaceRefNode;
+
+ if ((!IS_AML_OBJECT_NODE (ParentNode) &&
+ !IS_AML_ROOT_NODE (ParentNode)) ||
+ !IS_STREAM (FStream) ||
+ IS_END_OF_STREAM (FStream) ||
+ !IS_STREAM_FORWARD (FStream) ||
+ (NameSpaceRefList == NULL) ||
+ (OutNameSpaceRefNode == NULL)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // There cannot be a method invocation in a field list. Return.
+ if (AmlNodeHasAttribute (
+ (CONST AML_OBJECT_NODE*)ParentNode,
+ AML_HAS_FIELD_LIST)) {
+ *OutNameSpaceRefNode = NULL;
+ return EFI_SUCCESS;
+ }
+
+ // Allocate memory for the raw absolute path.
+ RawAbsolutePathBufferSize = MAX_AML_NAMESTRING_SIZE;
+ RawAbsolutePathBuffer = AllocateZeroPool (RawAbsolutePathBufferSize);
+ if (RawAbsolutePathBuffer == NULL) {
+ ASSERT (0);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ // Initialize a backward stream to get the raw absolute path.
+ Status = AmlStreamInit (
+ &RawAbsolutePathBStream,
+ RawAbsolutePathBuffer,
+ RawAbsolutePathBufferSize,
+ EAmlStreamDirectionBackward
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ goto exit_handler;
+ }
+
+ // Build the raw AML absolute path of the namespace node.
+ Status = AmlBuildRawMethodAbsolutePath (
+ ParentNode,
+ FStream,
+ &RawAbsolutePathBStream
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ goto exit_handler;
+ }
+
+ // If this is the root path: it cannot be a method invocation. Just return.
+ if (AmlStreamGetIndex (&RawAbsolutePathBStream) == 0) {
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "AmlMethodParser: "
+ "Root node cannot be a method invocation\n"
+ ));
+ *OutNameSpaceRefNode = NULL;
+ Status = EFI_SUCCESS;
+ goto exit_handler;
+ }
+
+ // Create a forward stream for the raw absolute path.
+ // This forward stream only contains the raw absolute path with
+ // no extra free space.
+ Status = AmlStreamInit (
+ &RawAbsolutePathFStream,
+ AmlStreamGetCurrPos (&RawAbsolutePathBStream),
+ AmlStreamGetIndex (&RawAbsolutePathBStream),
+ EAmlStreamDirectionForward
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ goto exit_handler;
+ }
+
+ // Create a backward stream for the node name.
+ Status = AmlInitRawPathBStream (
+ FStream,
+ &RawPathNameBStream
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Go through the NameSpaceRefList elements to check for
+ // a corresponding method definition.
+ NameSpaceRefNode = NULL;
+ Status = AmlFindMethodDefinition (
+ &RawAbsolutePathFStream,
+ &RawPathNameBStream,
+ NameSpaceRefList,
+ &NameSpaceRefNode
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ goto exit_handler;
+ }
+
+#if !defined(MDEPKG_NDEBUG)
+ // Print whether a method definition has been found.
+ if (NameSpaceRefNode != NULL) {
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "AmlMethodParser: Corresponding method definition: "
+ ));
+ AmlDbgPrintChars (
+ DEBUG_VERBOSE,
+ NameSpaceRefNode->RawAbsolutePath,
+ NameSpaceRefNode->RawAbsolutePathSize
+ );
+ DEBUG ((DEBUG_VERBOSE, ".\n"));
+
+ } else {
+ DEBUG ((DEBUG_VERBOSE, "AmlMethodParser: No method definition found.\n"));
+ }
+#endif // MDEPKG_NDEBUG
+
+ *OutNameSpaceRefNode = NameSpaceRefNode;
+
+exit_handler:
+ // Free allocated memory.
+ FreePool (RawAbsolutePathBuffer);
+ return Status;
+}
+
+/** Create a namespace reference node and add it to the NameSpaceRefList.
+
+ When a namespace node is encountered, the namespace it defines must be
+ associated to the node. This allow to keep track of the nature of each
+ name present in the AML namespace.
+
+ In the end, this allows to recognize method invocations and parse the right
+ number of arguments after the method name.
+
+ @param [in] Node Namespace node.
+ @param [in, out] NameSpaceRefList List of namespace reference nodes.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+EFI_STATUS
+EFIAPI
+AmlAddNameSpaceReference (
+ IN CONST AML_OBJECT_NODE * Node,
+ IN OUT LIST_ENTRY * NameSpaceRefList
+ )
+{
+ EFI_STATUS Status;
+ AML_NAMESPACE_REF_NODE * NameSpaceRefNode;
+
+ AML_STREAM NodeNameFStream;
+ EAML_PARSE_INDEX NameIndex;
+ CONST AML_DATA_NODE * NameNode;
+
+ AML_STREAM RawAbsolutePathBStream;
+ UINT32 RawAbsolutePathBStreamSize;
+
+ CHAR8 * AbsolutePathBuffer;
+ UINT32 AbsolutePathBufferSize;
+
+ CONST AML_NODE_HEADER * ParentNode;
+
+ if (!AmlNodeHasAttribute (Node, AML_IN_NAMESPACE) ||
+ (NameSpaceRefList == NULL)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Allocate a buffer to get the raw AML absolute pathname of the
+ // namespace node.
+ AbsolutePathBufferSize = MAX_AML_NAMESTRING_SIZE;
+ AbsolutePathBuffer = AllocateZeroPool (AbsolutePathBufferSize);
+ if (AbsolutePathBuffer == NULL) {
+ ASSERT (0);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = AmlStreamInit (
+ &RawAbsolutePathBStream,
+ (UINT8*)AbsolutePathBuffer,
+ AbsolutePathBufferSize,
+ EAmlStreamDirectionBackward
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ Status = EFI_INVALID_PARAMETER;
+ goto exit_handler;
+ }
+
+ // Get the index where the name of the Node is stored in its
+ // fixed list of arguments.
+ Status = AmlNodeGetNameIndex (Node, &NameIndex);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ Status = EFI_INVALID_PARAMETER;
+ goto exit_handler;
+ }
+
+ // Get the Node name.
+ NameNode = (CONST AML_DATA_NODE*)AmlGetFixedArgument (
+ (AML_OBJECT_NODE*)Node,
+ NameIndex
+ );
+ if (!IS_AML_DATA_NODE (NameNode) ||
+ (NameNode->DataType != EAmlNodeDataTypeNameString)) {
+ ASSERT (0);
+ Status = EFI_INVALID_PARAMETER;
+ goto exit_handler;
+ }
+
+ // Initialize a stream on the node name of the namespace node.
+ // This is an AML NameString.
+ Status = AmlStreamInit (
+ &NodeNameFStream,
+ NameNode->Buffer,
+ NameNode->Size,
+ EAmlStreamDirectionForward
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ Status = EFI_INVALID_PARAMETER;
+ goto exit_handler;
+ }
+
+ ParentNode = AmlGetParent ((AML_NODE_HEADER*)Node);
+ if (ParentNode == NULL) {
+ ASSERT (0);
+ Status = EFI_INVALID_PARAMETER;
+ goto exit_handler;
+ }
+
+ // Build the raw AML absolute path of the namespace node.
+ Status = AmlBuildRawMethodAbsolutePath (
+ ParentNode,
+ &NodeNameFStream,
+ &RawAbsolutePathBStream
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ goto exit_handler;
+ }
+
+ RawAbsolutePathBStreamSize = AmlStreamGetIndex (&RawAbsolutePathBStream);
+ // This is the root path: this cannot be a method invocation.
+ if (RawAbsolutePathBStreamSize == 0) {
+ Status = EFI_SUCCESS;
+ goto exit_handler;
+ }
+
+ // Create a NameSpace reference node.
+ Status = AmlCreateMethodRefNode (
+ Node,
+ (CONST CHAR8*)AmlStreamGetCurrPos (&RawAbsolutePathBStream),
+ RawAbsolutePathBStreamSize,
+ &NameSpaceRefNode
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ goto exit_handler;
+ }
+
+ // Add the created NameSpaceRefNode to the list.
+ InsertTailList (NameSpaceRefList, &NameSpaceRefNode->Link);
+
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "AmlMethodParser: Adding namespace reference with name:\n"
+ ));
+ AmlDbgPrintChars (
+ DEBUG_VERBOSE,
+ (CONST CHAR8*)AmlStreamGetCurrPos (&RawAbsolutePathBStream),
+ AmlStreamGetIndex (&RawAbsolutePathBStream)
+ );
+ DEBUG ((DEBUG_VERBOSE, "\n"));
+
+exit_handler:
+ // Free allocated memory.
+ FreePool (AbsolutePathBuffer);
+
+ return Status;
+}
+
+/** Create a method invocation node.
+
+ The AML grammar does not attribute an OpCode/SubOpCode couple for
+ method invocations. This library is representing method invocations
+ as if they had one.
+
+ The AML encoding for method invocations in the ACPI specification 6.3 is:
+ MethodInvocation := NameString TermArgList
+ In this library, it is:
+ MethodInvocation := MethodInvocationOp NameString ArgumentCount TermArgList
+ ArgumentCount := ByteData
+
+ When computing the size of a tree or serializing it, the additional data is
+ not taken into account (i.e. the MethodInvocationOp and the ArgumentCount).
+
+ Method invocation nodes have the AML_METHOD_INVOVATION attribute.
+
+ @param [in] NameSpaceRefNode NameSpaceRef node pointing to the
+ the definition of the invoked
+ method.
+ @param [in] MethodInvocationName Data node containing the method
+ invocation name.
+ @param [out] MethodInvocationNodePtr Created method invocation node.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
+**/
+EFI_STATUS
+EFIAPI
+AmlCreateMethodInvocationNode (
+ IN CONST AML_NAMESPACE_REF_NODE * NameSpaceRefNode,
+ IN AML_DATA_NODE * MethodInvocationName,
+ OUT AML_OBJECT_NODE ** MethodInvocationNodePtr
+ )
+{
+ EFI_STATUS Status;
+
+ UINT8 ArgCount;
+ AML_DATA_NODE * ArgCountNode;
+ AML_NODE_HEADER ** FixedArgs;
+ AML_OBJECT_NODE * MethodDefinitionNode;
+ AML_OBJECT_NODE * MethodInvocationNode;
+
+ if ((NameSpaceRefNode == NULL) ||
+ !AmlIsMethodDefinitionNode (NameSpaceRefNode->NodeRef) ||
+ !IS_AML_DATA_NODE (MethodInvocationName) ||
+ (MethodInvocationName->DataType != EAmlNodeDataTypeNameString) ||
+ (MethodInvocationNodePtr == NULL)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Get the number of arguments of the method.
+ MethodDefinitionNode = (AML_OBJECT_NODE*)NameSpaceRefNode->NodeRef;
+ FixedArgs = MethodDefinitionNode->FixedArgs;
+ // The method definition is an actual method definition.
+ if (AmlNodeCompareOpCode (MethodDefinitionNode, AML_METHOD_OP, 0)) {
+ // Cf ACPI 6.3 specification:
+ // DefMethod := MethodOp PkgLength NameString MethodFlags TermList
+ // MethodOp := 0x14
+ // MethodFlags := ByteData bit 0-2: ArgCount (0-7)
+ // bit 3: SerializeFlag
+ // 0 NotSerialized
+ // 1 Serialized
+ // bit 4-7: SyncLevel (0x00-0x0f)
+
+ // Read the MethodFlags to decode the ArgCount.
+ ArgCountNode = (AML_DATA_NODE*)FixedArgs[EAmlParseIndexTerm1];
+ ArgCount = *((UINT8*)ArgCountNode->Buffer) & 0x7;
+ } else if (AmlNodeCompareOpCode (MethodDefinitionNode, AML_EXTERNAL_OP, 0)) {
+ // The method definition is an external statement.
+ // Cf ACPI 6.3 specification:
+ // DefExternal := ExternalOp NameString ObjectType ArgumentCount
+ // ExternalOp := 0x15
+ // ObjectType := ByteData
+ // ArgumentCount := ByteData (0 – 7)
+
+ // Read the ArgumentCount.
+ ArgCountNode = (AML_DATA_NODE*)FixedArgs[EAmlParseIndexTerm2];
+ ArgCount = *((UINT8*)ArgCountNode->Buffer);
+ } else {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Create the object node for the method invocation.
+ // MethodInvocation := MethodInvocationOp NameString ArgumentCount
+ // MethodInvocationOp := Pseudo Opcode for Method Invocation
+ // NameString := Method Name
+ // ArgumentCount := ByteData (0 – 7)
+ Status = AmlCreateObjectNode (
+ AmlGetByteEncodingByOpCode (AML_METHOD_INVOC_OP, 0),
+ 0,
+ &MethodInvocationNode
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // The first fixed argument is the method name.
+ Status = AmlSetFixedArgument (
+ MethodInvocationNode,
+ EAmlParseIndexTerm0,
+ (AML_NODE_HEADER*)MethodInvocationName
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ goto error_handler;
+ }
+
+ // Create a data node holding the number of arguments
+ // of the method invocation.
+ ArgCountNode = NULL;
+ Status = AmlCreateDataNode (
+ EAmlNodeDataTypeUInt,
+ &ArgCount,
+ sizeof (UINT8),
+ &ArgCountNode
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ goto error_handler;
+ }
+
+ // The second fixed argument is the number of arguments.
+ Status = AmlSetFixedArgument (
+ MethodInvocationNode,
+ EAmlParseIndexTerm1,
+ (AML_NODE_HEADER*)ArgCountNode
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ goto error_handler;
+ }
+
+ *MethodInvocationNodePtr = MethodInvocationNode;
+ return Status;
+
+error_handler:
+ // Delete the sub-tree: the method invocation name is already attached.
+ AmlDeleteTree ((AML_NODE_HEADER*)MethodInvocationNode);
+ if (ArgCountNode != NULL) {
+ AmlDeleteNode ((AML_NODE_HEADER*)ArgCountNode);
+ }
+
+ return Status;
+}
+
+/** Get the number of arguments of a method invocation node.
+
+ This function also allow to identify whether a node is a method invocation
+ node. If the input node is not a method invocation node, just return.
+
+ @param [in] MethodInvocationNode Method invocation node.
+ @param [out] IsMethodInvocation Boolean stating whether the input
+ node is a method invocation.
+ @param [out] ArgCount Number of arguments of the method
+ invocation.
+ Set to 0 if MethodInvocationNode
+ is not a method invocation.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
+*/
+EFI_STATUS
+EFIAPI
+AmlGetMethodInvocationArgCount (
+ IN CONST AML_OBJECT_NODE * MethodInvocationNode,
+ OUT BOOLEAN * IsMethodInvocation,
+ OUT UINT8 * ArgCount
+ )
+{
+ AML_DATA_NODE * NumArgsNode;
+
+ if (!IS_AML_NODE_VALID (MethodInvocationNode) ||
+ (IsMethodInvocation == NULL) ||
+ (ArgCount == NULL)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Check whether MethodInvocationNode is a method invocation.
+ if (!AmlNodeCompareOpCode (MethodInvocationNode, AML_METHOD_INVOC_OP, 0)) {
+ *IsMethodInvocation = FALSE;
+ *ArgCount = 0;
+ return EFI_SUCCESS;
+ }
+
+ // MethodInvocation := MethodInvocationOp NameString ArgumentCount
+ // MethodInvocationOp := Pseudo Opcode for Method Invocation
+ // NameString := Method Name
+ // ArgumentCount := ByteData (0 - 7)
+ NumArgsNode = (AML_DATA_NODE*)AmlGetFixedArgument (
+ (AML_OBJECT_NODE*)MethodInvocationNode,
+ EAmlParseIndexTerm1
+ );
+ if (!IS_AML_NODE_VALID (NumArgsNode) ||
+ (NumArgsNode->Buffer == NULL) ||
+ (NumArgsNode->DataType != EAmlNodeDataTypeUInt) ||
+ (NumArgsNode->Size != 1)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+ *ArgCount = *NumArgsNode->Buffer;
+
+ *IsMethodInvocation = TRUE;
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlMethodParser.h b/roms/edk2/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlMethodParser.h
new file mode 100644
index 000000000..b082f2deb
--- /dev/null
+++ b/roms/edk2/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlMethodParser.h
@@ -0,0 +1,188 @@
+/** @file
+ AML Method Parser.
+
+ Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef AML_METHOD_PARSER_H_
+#define AML_METHOD_PARSER_H_
+
+#include <AmlNodeDefines.h>
+#include <Stream/AmlStream.h>
+
+/** AML namespace reference node.
+
+ Namespace reference nodes allow to associate an AML absolute pathname
+ to the tree node defining this object in the namespace.
+
+ Namespace reference nodes are stored in a separate list. They are not part of
+ the tree.
+*/
+typedef struct AmlNameSpaceRefNode {
+ /// Double linked list.
+ /// This must be the first field in this structure.
+ LIST_ENTRY Link;
+
+ /// Node part of the AML namespace. It must have the AML_IN_NAMESPACE
+ /// attribute.
+ CONST AML_OBJECT_NODE * NodeRef;
+
+ /// Raw AML absolute pathname of the NodeRef.
+ /// This is a raw AML NameString (cf AmlNameSpace.c: A concatenated list
+ /// of 4 chars long names. The dual/multi NameString prefix have been
+ /// stripped.).
+ CONST CHAR8 * RawAbsolutePath;
+
+ /// Size of the raw AML absolute pathname buffer.
+ UINT32 RawAbsolutePathSize;
+} AML_NAMESPACE_REF_NODE;
+
+/** Delete a list of namespace reference nodes.
+
+ @param [in] NameSpaceRefList List of namespace reference nodes.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+EFI_STATUS
+EFIAPI
+AmlDeleteNameSpaceRefList (
+ IN LIST_ENTRY * NameSpaceRefList
+ );
+
+
+#if !defined (MDEPKG_NDEBUG)
+/** Print the list of raw absolute paths of the NameSpace reference list.
+
+ @param [in] NameSpaceRefList List of NameSpace reference nodes.
+**/
+VOID
+EFIAPI
+AmlDbgPrintNameSpaceRefList (
+ IN CONST LIST_ENTRY * NameSpaceRefList
+ );
+
+#endif // MDEPKG_NDEBUG
+
+/** Check whether a pathname is a method invocation.
+
+ If there is a matching method definition, returns the corresponding
+ NameSpaceRef node.
+
+ To do so, the NameSpaceRefList is keeping track of every namespace node
+ and its raw AML absolute path.
+ To check whether a pathname is a method invocation, a corresponding raw
+ absolute pathname is built. This raw absolute pathname is then compared
+ to the list of available pathnames. If a pathname defining a method
+ matches the scope of the input pathname, return.
+
+ @param [in] ParentNode Parent node. Node to which the node to be
+ created will be attached.
+ @param [in] FStream Forward stream pointing to the NameString
+ to find.
+ @param [in] NameSpaceRefList List of NameSpaceRef nodes.
+ @param [out] OutNameSpaceRefNode If the NameString pointed by FStream is
+ a method invocation, OutNameSpaceRefNode
+ contains the NameSpaceRef corresponding
+ to the method definition.
+ NULL otherwise.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+EFI_STATUS
+EFIAPI
+AmlIsMethodInvocation (
+ IN CONST AML_NODE_HEADER * ParentNode,
+ IN CONST AML_STREAM * FStream,
+ IN CONST LIST_ENTRY * NameSpaceRefList,
+ OUT AML_NAMESPACE_REF_NODE ** OutNameSpaceRefNode
+ );
+
+/** Create a namespace reference node and add it to the NameSpaceRefList.
+
+ When a namespace node is encountered, the namespace it defines must be
+ associated to the node. This allow to keep track of the nature of each
+ name present in the AML namespace.
+
+ In the end, this allows to recognize method invocations and parse the right
+ number of arguments after the method name.
+
+ @param [in] Node Namespace node.
+ @param [in, out] NameSpaceRefList List of namespace reference nodes.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+EFI_STATUS
+EFIAPI
+AmlAddNameSpaceReference (
+ IN CONST AML_OBJECT_NODE * Node,
+ IN OUT LIST_ENTRY * NameSpaceRefList
+ );
+
+/** Create a method invocation node.
+
+ The AML grammar does not attribute an OpCode/SubOpCode couple for
+ method invocations. This library is representing method invocations
+ as if they had one.
+
+ The AML encoding for method invocations in the ACPI specification 6.3 is:
+ MethodInvocation := NameString TermArgList
+ In this library, it is:
+ MethodInvocation := MethodInvocationOp NameString ArgumentCount TermArgList
+ ArgumentCount := ByteData
+
+ When computing the size of a tree or serializing it, the additional data is
+ not taken into account (i.e. the MethodInvocationOp and the ArgumentCount).
+
+ Method invocation nodes have the AML_METHOD_INVOVATION attribute.
+
+ @param [in] NameSpaceRefNode NameSpaceRef node pointing to the
+ the definition of the invoked
+ method.
+ @param [in] MethodInvocationName Data node containing the method
+ invocation name.
+ @param [out] MethodInvocationNodePtr Created method invocation node.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
+**/
+EFI_STATUS
+EFIAPI
+AmlCreateMethodInvocationNode (
+ IN CONST AML_NAMESPACE_REF_NODE * NameSpaceRefNode,
+ IN AML_DATA_NODE * MethodInvocationName,
+ OUT AML_OBJECT_NODE ** MethodInvocationNodePtr
+ );
+
+/** Get the number of arguments of a method invocation node.
+
+ This function also allow to identify whether a node is a method invocation
+ node. If the input node is not a method invocation node, just return.
+
+ @param [in] MethodInvocationNode Method invocation node.
+ @param [out] IsMethodInvocation Boolean stating whether the input
+ node is a method invocation.
+ @param [out] ArgCount Number of arguments of the method
+ invocation.
+ Set to 0 if MethodInvocationNode
+ is not a method invocation.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
+*/
+EFI_STATUS
+EFIAPI
+AmlGetMethodInvocationArgCount (
+ IN CONST AML_OBJECT_NODE * MethodInvocationNode,
+ OUT BOOLEAN * IsMethodInvocation,
+ OUT UINT8 * ArgCount
+ );
+
+#endif // AML_METHOD_PARSER_H_
diff --git a/roms/edk2/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlParser.c b/roms/edk2/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlParser.c
new file mode 100644
index 000000000..380ac9bbc
--- /dev/null
+++ b/roms/edk2/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/roms/edk2/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlParser.h b/roms/edk2/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlParser.h
new file mode 100644
index 000000000..096a9596e
--- /dev/null
+++ b/roms/edk2/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_
diff --git a/roms/edk2/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlResourceDataParser.c b/roms/edk2/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlResourceDataParser.c
new file mode 100644
index 000000000..09fb3e725
--- /dev/null
+++ b/roms/edk2/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlResourceDataParser.c
@@ -0,0 +1,328 @@
+/** @file
+ AML Resource Data Parser.
+
+ Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Glossary:
+ - Rd or RD - Resource Data
+ - Rds or RDS - Resource Data Small
+ - Rdl or RDL - Resource Data Large
+**/
+
+#include <Parser/AmlResourceDataParser.h>
+
+#include <AmlCoreInterface.h>
+#include <AmlDbgPrint/AmlDbgPrint.h>
+#include <Tree/AmlNode.h>
+#include <Tree/AmlTree.h>
+
+/** Get the size of a resource data element using a stream.
+
+ If the resource data element is of the large type, the Header
+ is expected to be at least 3 bytes long.
+
+ The use of a stream makes this function safer
+ than the version without stream.
+
+ @param [in] FStream Forward stream pointing to a resource data
+ element.
+ The stream must not be at its end.
+
+ @return The size of the resource data element.
+ Zero if error.
+**/
+UINT32
+EFIAPI
+AmlRdStreamGetRdSize (
+ IN CONST AML_STREAM * FStream
+ )
+{
+ CONST AML_RD_HEADER * CurrRdElement;
+
+ if (!IS_STREAM (FStream) ||
+ IS_END_OF_STREAM (FStream) ||
+ !IS_STREAM_FORWARD (FStream)) {
+ ASSERT (0);
+ return 0;
+ }
+
+ CurrRdElement = (CONST AML_RD_HEADER*)AmlStreamGetCurrPos (FStream);
+ if (CurrRdElement == NULL) {
+ ASSERT (0);
+ return 0;
+ }
+
+ // If the resource data element is of the large type, check for overflow.
+ if (AML_RD_IS_LARGE (CurrRdElement) &&
+ (AmlStreamGetFreeSpace (FStream) <
+ sizeof (ACPI_LARGE_RESOURCE_HEADER))) {
+ return 0;
+ }
+
+ return AmlRdGetSize (CurrRdElement);
+}
+
+/** Check the nesting of resource data elements that are dependent
+ function descriptors.
+
+ @param [in] FStream Forward stream pointing to a resource data
+ element. The stream is not
+ modified/progressing.
+ The stream must not be at its end.
+ @param [in, out] InFunctionDesc Pointer holding the nesting of the
+ resource data buffer.
+ InFunctionDesc holds TRUE if the resource
+ data at the address of Buffer is currently
+ in a dependent function descriptor list.
+
+ @retval FALSE The Header being parsed is ending a function descriptor
+ list when none started. This should not be possible for a
+ resource data buffer.
+ @retval TRUE Otherwise.
+**/
+STATIC
+BOOLEAN
+EFIAPI
+AmlRdCheckFunctionDescNesting (
+ IN CONST AML_STREAM * FStream,
+ IN OUT BOOLEAN * InFunctionDesc
+ )
+{
+ CONST AML_RD_HEADER * CurrRdElement;
+
+ if (!IS_STREAM (FStream) ||
+ IS_END_OF_STREAM (FStream) ||
+ (InFunctionDesc == NULL)) {
+ ASSERT (0);
+ return FALSE;
+ }
+
+ CurrRdElement = AmlStreamGetCurrPos (FStream);
+ if (CurrRdElement == NULL) {
+ ASSERT (0);
+ return FALSE;
+ }
+
+ // Starting a dependent function descriptor.
+ // It is possible to start one when one has already started.
+ if (AmlRdCompareDescId (
+ CurrRdElement,
+ AML_RD_BUILD_SMALL_DESC_ID (
+ ACPI_SMALL_START_DEPENDENT_DESCRIPTOR_NAME))) {
+ *InFunctionDesc = TRUE;
+ return TRUE;
+ }
+
+ // Ending a dependent function descriptor.
+ if (AmlRdCompareDescId (
+ CurrRdElement,
+ AML_RD_BUILD_SMALL_DESC_ID (
+ ACPI_SMALL_END_DEPENDENT_DESCRIPTOR_NAME))) {
+ if (*InFunctionDesc) {
+ *InFunctionDesc = FALSE;
+ return TRUE;
+ }
+
+ // It should not be possible to end a dependent function descriptor
+ // when none started.
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/** Check whether the input stream is pointing to a valid list
+ of resource data elements.
+
+ The check is based on the size of resource data elements.
+ This means that a buffer can pass this check with non-existing descriptor Ids
+ that have a correct size.
+
+ A list of resource data elements can contain one unique resource data
+ element, without an end tag resource data. This is the case for
+ a FieldList.
+
+ @param [in] FStream Forward stream ideally pointing to a resource
+ data element. The stream is not
+ modified/progressing.
+ The stream must not be at its end.
+
+ @retval TRUE The buffer is holding a valid list of resource data elements.
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+AmlRdIsResourceDataBuffer (
+ IN CONST AML_STREAM * FStream
+ )
+{
+ EFI_STATUS Status;
+ UINT32 FreeSpace;
+ AML_STREAM SubStream;
+ CONST AML_RD_HEADER * CurrRdElement;
+ UINT32 CurrRdElementSize;
+ BOOLEAN InFunctionDesc;
+
+ if (!IS_STREAM (FStream) ||
+ IS_END_OF_STREAM (FStream) ||
+ !IS_STREAM_FORWARD (FStream)) {
+ ASSERT (0);
+ return FALSE;
+ }
+
+ // Create a sub-stream from the input stream to leave it untouched.
+ Status = AmlStreamInitSubStream (FStream, &SubStream);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return FALSE;
+ }
+
+ CurrRdElement = AmlStreamGetCurrPos (&SubStream);
+ if (CurrRdElement == NULL) {
+ ASSERT (0);
+ return FALSE;
+ }
+
+ // The first element cannot be an end tag.
+ if (AmlRdCompareDescId (
+ CurrRdElement,
+ AML_RD_BUILD_SMALL_DESC_ID (ACPI_SMALL_END_TAG_DESCRIPTOR_NAME))) {
+ return FALSE;
+ }
+
+ InFunctionDesc = FALSE;
+ while (TRUE) {
+ FreeSpace = AmlStreamGetFreeSpace (&SubStream);
+ CurrRdElement = AmlStreamGetCurrPos (&SubStream);
+ CurrRdElementSize = AmlRdStreamGetRdSize (&SubStream);
+ if ((FreeSpace == 0) ||
+ (CurrRdElement == NULL) ||
+ (CurrRdElementSize == 0)) {
+ return FALSE;
+ }
+
+ if (!AmlRdCheckFunctionDescNesting (&SubStream, &InFunctionDesc)) {
+ return FALSE;
+ }
+
+ if (CurrRdElementSize > FreeSpace) {
+ return FALSE;
+ } else if (CurrRdElementSize == FreeSpace) {
+ return TRUE;
+ }
+
+ // TODO Might want to check the CRC when available.
+ // An end tag resource data element must be the last element of the list.
+ // Thus the function should have already returned.
+ if (AmlRdCompareDescId (
+ CurrRdElement,
+ AML_RD_BUILD_SMALL_DESC_ID (ACPI_SMALL_END_TAG_DESCRIPTOR_NAME))) {
+ return FALSE;
+ }
+
+ Status = AmlStreamProgress (&SubStream, CurrRdElementSize);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return FALSE;
+ }
+ } // while
+
+ return FALSE;
+}
+
+/** Parse a ResourceDataBuffer.
+
+ For each resource data element, create a data node
+ and add them to the variable list of arguments of the BufferNode.
+
+ The input stream is expected to point to a valid list of resource data
+ elements. A function is available to check it for the caller.
+
+ @param [in] BufferNode Buffer node.
+ @param [in] FStream Forward stream pointing to a resource data
+ element.
+ 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.
+**/
+EFI_STATUS
+EFIAPI
+AmlParseResourceData (
+ IN AML_OBJECT_NODE * BufferNode,
+ IN AML_STREAM * FStream
+ )
+{
+ EFI_STATUS Status;
+ AML_DATA_NODE * NewNode;
+ UINT32 FreeSpace;
+ CONST AML_RD_HEADER * CurrRdElement;
+ UINT32 CurrRdElementSize;
+
+ // Check that BufferNode is an ObjectNode and has a ByteList.
+ 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;
+ }
+
+ // Iterate through the resource data elements and create nodes.
+ // We assume the Buffer has already been validated as a list of
+ // resource data elements, so less checks are made.
+ while (TRUE) {
+ FreeSpace = AmlStreamGetFreeSpace (FStream);
+ if (FreeSpace == 0) {
+ break;
+ }
+
+ CurrRdElement = (CONST AML_RD_HEADER*)AmlStreamGetCurrPos (FStream);
+ CurrRdElementSize = AmlRdStreamGetRdSize (FStream);
+
+ Status = AmlCreateDataNode (
+ EAmlNodeDataTypeResourceData,
+ (CONST UINT8*)CurrRdElement,
+ CurrRdElementSize,
+ &NewNode
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ Status = AmlVarListAddTailInternal (
+ (AML_NODE_HEADER*)BufferNode,
+ (AML_NODE_HEADER*)NewNode
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ AmlDeleteTree ((AML_NODE_HEADER*)NewNode);
+ return Status;
+ }
+
+ Status = AmlStreamProgress (FStream, CurrRdElementSize);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ DumpRaw (CurrRdElement, CurrRdElementSize);
+
+ // Exit the loop when finding the resource data end tag.
+ if (AmlRdCompareDescId (
+ CurrRdElement,
+ AML_RD_BUILD_SMALL_DESC_ID (ACPI_SMALL_END_TAG_DESCRIPTOR_NAME))) {
+ if (FreeSpace != CurrRdElementSize) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+ break;
+ }
+ } // while
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlResourceDataParser.h b/roms/edk2/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlResourceDataParser.h
new file mode 100644
index 000000000..13dfb352c
--- /dev/null
+++ b/roms/edk2/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlResourceDataParser.h
@@ -0,0 +1,71 @@
+/** @file
+ AML Resource Data Parser.
+
+ Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Glossary:
+ - Rd or RD - Resource Data
+ - Rds or RDS - Resource Data Small
+ - Rdl or RDL - Resource Data Large
+**/
+
+#ifndef AML_RESOURCE_DATA_PARSER_H_
+#define AML_RESOURCE_DATA_PARSER_H_
+
+#include <AmlNodeDefines.h>
+#include <Stream/AmlStream.h>
+#include <ResourceData/AmlResourceData.h>
+
+/** Check whether the input stream is pointing to a valid list
+ of resource data elements.
+
+ The check is based on the size of resource data elements.
+ This means that a buffer can pass this check with non-existing descriptor Ids
+ that have a correct size.
+
+ A list of resource data elements can contain one unique resource data
+ element, without an end tag resource data. This is the case for
+ a FieldList.
+
+ @param [in] FStream Forward stream ideally pointing to a resource
+ data element. The stream is not
+ modified/progressing.
+ The stream must not be at its end.
+
+ @retval TRUE The buffer is holding a valid list of resource data elements.
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+AmlRdIsResourceDataBuffer (
+ IN CONST AML_STREAM * FStream
+ );
+
+/** Parse a ResourceDataBuffer.
+
+ For each resource data element, create a data node
+ and add them to the variable list of arguments of the BufferNode.
+
+ The input stream is expected to point to a valid list of resource data
+ elements. A function is available to check it for the caller.
+
+ @param [in] BufferNode Buffer node.
+ @param [in] FStream Forward stream pointing to a resource data
+ element.
+ 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.
+**/
+EFI_STATUS
+EFIAPI
+AmlParseResourceData (
+ IN AML_OBJECT_NODE * BufferNode,
+ IN AML_STREAM * FStream
+ );
+
+#endif // AML_RESOURCE_DATA_PARSER_H_
+