diff options
-rw-r--r-- | DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlFieldListParser.c | 375 | ||||
-rw-r--r-- | DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlFieldListParser.h | 77 |
2 files changed, 452 insertions, 0 deletions
diff --git a/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlFieldListParser.c b/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlFieldListParser.c new file mode 100644 index 0000000..c25ee22 --- /dev/null +++ b/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/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlFieldListParser.h b/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlFieldListParser.h new file mode 100644 index 0000000..576f6c4 --- /dev/null +++ b/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_
|