--- /dev/null
+/** @file\r
+ AML Resource Data Parser.\r
+\r
+ Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>\r
+\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+ @par Glossary:\r
+ - Rd or RD - Resource Data\r
+ - Rds or RDS - Resource Data Small\r
+ - Rdl or RDL - Resource Data Large\r
+**/\r
+\r
+#include <Parser/AmlResourceDataParser.h>\r
+\r
+#include <AmlCoreInterface.h>\r
+#include <AmlDbgPrint/AmlDbgPrint.h>\r
+#include <Tree/AmlNode.h>\r
+#include <Tree/AmlTree.h>\r
+\r
+/** Get the size of a resource data element using a stream.\r
+\r
+ If the resource data element is of the large type, the Header\r
+ is expected to be at least 3 bytes long.\r
+\r
+ The use of a stream makes this function safer\r
+ than the version without stream.\r
+\r
+ @param [in] FStream Forward stream pointing to a resource data\r
+ element.\r
+ The stream must not be at its end.\r
+\r
+ @return The size of the resource data element.\r
+ Zero if error.\r
+**/\r
+UINT32\r
+EFIAPI\r
+AmlRdStreamGetRdSize (\r
+ IN CONST AML_STREAM * FStream\r
+ )\r
+{\r
+ CONST AML_RD_HEADER * CurrRdElement;\r
+\r
+ if (!IS_STREAM (FStream) ||\r
+ IS_END_OF_STREAM (FStream) ||\r
+ !IS_STREAM_FORWARD (FStream)) {\r
+ ASSERT (0);\r
+ return 0;\r
+ }\r
+\r
+ CurrRdElement = (CONST AML_RD_HEADER*)AmlStreamGetCurrPos (FStream);\r
+ if (CurrRdElement == NULL) {\r
+ ASSERT (0);\r
+ return 0;\r
+ }\r
+\r
+ // If the resource data element is of the large type, check for overflow.\r
+ if (AML_RD_IS_LARGE (CurrRdElement) &&\r
+ (AmlStreamGetFreeSpace (FStream) <\r
+ sizeof (ACPI_LARGE_RESOURCE_HEADER))) {\r
+ return 0;\r
+ }\r
+\r
+ return AmlRdGetSize (CurrRdElement);\r
+}\r
+\r
+/** Check the nesting of resource data elements that are dependent\r
+ function descriptors.\r
+\r
+ @param [in] FStream Forward stream pointing to a resource data\r
+ element. The stream is not\r
+ modified/progressing.\r
+ The stream must not be at its end.\r
+ @param [in, out] InFunctionDesc Pointer holding the nesting of the\r
+ resource data buffer.\r
+ InFunctionDesc holds TRUE if the resource\r
+ data at the address of Buffer is currently\r
+ in a dependent function descriptor list.\r
+\r
+ @retval FALSE The Header being parsed is ending a function descriptor\r
+ list when none started. This should not be possible for a\r
+ resource data buffer.\r
+ @retval TRUE Otherwise.\r
+**/\r
+STATIC\r
+BOOLEAN\r
+EFIAPI\r
+AmlRdCheckFunctionDescNesting (\r
+ IN CONST AML_STREAM * FStream,\r
+ IN OUT BOOLEAN * InFunctionDesc\r
+ )\r
+{\r
+ CONST AML_RD_HEADER * CurrRdElement;\r
+\r
+ if (!IS_STREAM (FStream) ||\r
+ IS_END_OF_STREAM (FStream) ||\r
+ (InFunctionDesc == NULL)) {\r
+ ASSERT (0);\r
+ return FALSE;\r
+ }\r
+\r
+ CurrRdElement = AmlStreamGetCurrPos (FStream);\r
+ if (CurrRdElement == NULL) {\r
+ ASSERT (0);\r
+ return FALSE;\r
+ }\r
+\r
+ // Starting a dependent function descriptor.\r
+ // It is possible to start one when one has already started.\r
+ if (AmlRdCompareDescId (\r
+ CurrRdElement,\r
+ AML_RD_BUILD_SMALL_DESC_ID (\r
+ ACPI_SMALL_START_DEPENDENT_DESCRIPTOR_NAME))) {\r
+ *InFunctionDesc = TRUE;\r
+ return TRUE;\r
+ }\r
+\r
+ // Ending a dependent function descriptor.\r
+ if (AmlRdCompareDescId (\r
+ CurrRdElement,\r
+ AML_RD_BUILD_SMALL_DESC_ID (\r
+ ACPI_SMALL_END_DEPENDENT_DESCRIPTOR_NAME))) {\r
+ if (*InFunctionDesc) {\r
+ *InFunctionDesc = FALSE;\r
+ return TRUE;\r
+ }\r
+\r
+ // It should not be possible to end a dependent function descriptor\r
+ // when none started.\r
+ return FALSE;\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+/** Check whether the input stream is pointing to a valid list\r
+ of resource data elements.\r
+\r
+ The check is based on the size of resource data elements.\r
+ This means that a buffer can pass this check with non-existing descriptor Ids\r
+ that have a correct size.\r
+\r
+ A list of resource data elements can contain one unique resource data\r
+ element, without an end tag resource data. This is the case for\r
+ a FieldList.\r
+\r
+ @param [in] FStream Forward stream ideally pointing to a resource\r
+ data element. The stream is not\r
+ modified/progressing.\r
+ The stream must not be at its end.\r
+\r
+ @retval TRUE The buffer is holding a valid list of resource data elements.\r
+ @retval FALSE Otherwise.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+AmlRdIsResourceDataBuffer (\r
+ IN CONST AML_STREAM * FStream\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 FreeSpace;\r
+ AML_STREAM SubStream;\r
+ CONST AML_RD_HEADER * CurrRdElement;\r
+ UINT32 CurrRdElementSize;\r
+ BOOLEAN InFunctionDesc;\r
+\r
+ if (!IS_STREAM (FStream) ||\r
+ IS_END_OF_STREAM (FStream) ||\r
+ !IS_STREAM_FORWARD (FStream)) {\r
+ ASSERT (0);\r
+ return FALSE;\r
+ }\r
+\r
+ // Create a sub-stream from the input stream to leave it untouched.\r
+ Status = AmlStreamInitSubStream (FStream, &SubStream);\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ return FALSE;\r
+ }\r
+\r
+ CurrRdElement = AmlStreamGetCurrPos (&SubStream);\r
+ if (CurrRdElement == NULL) {\r
+ ASSERT (0);\r
+ return FALSE;\r
+ }\r
+\r
+ // The first element cannot be an end tag.\r
+ if (AmlRdCompareDescId (\r
+ CurrRdElement,\r
+ AML_RD_BUILD_SMALL_DESC_ID (ACPI_SMALL_END_TAG_DESCRIPTOR_NAME))) {\r
+ return FALSE;\r
+ }\r
+\r
+ InFunctionDesc = FALSE;\r
+ while (TRUE) {\r
+ FreeSpace = AmlStreamGetFreeSpace (&SubStream);\r
+ CurrRdElement = AmlStreamGetCurrPos (&SubStream);\r
+ CurrRdElementSize = AmlRdStreamGetRdSize (&SubStream);\r
+ if ((FreeSpace == 0) ||\r
+ (CurrRdElement == NULL) ||\r
+ (CurrRdElementSize == 0)) {\r
+ return FALSE;\r
+ }\r
+\r
+ if (!AmlRdCheckFunctionDescNesting (&SubStream, &InFunctionDesc)) {\r
+ return FALSE;\r
+ }\r
+\r
+ if (CurrRdElementSize > FreeSpace) {\r
+ return FALSE;\r
+ } else if (CurrRdElementSize == FreeSpace) {\r
+ return TRUE;\r
+ }\r
+\r
+ // TODO Might want to check the CRC when available.\r
+ // An end tag resource data element must be the last element of the list.\r
+ // Thus the function should have already returned.\r
+ if (AmlRdCompareDescId (\r
+ CurrRdElement,\r
+ AML_RD_BUILD_SMALL_DESC_ID (ACPI_SMALL_END_TAG_DESCRIPTOR_NAME))) {\r
+ return FALSE;\r
+ }\r
+\r
+ Status = AmlStreamProgress (&SubStream, CurrRdElementSize);\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ return FALSE;\r
+ }\r
+ } // while\r
+\r
+ return FALSE;\r
+}\r
+\r
+/** Parse a ResourceDataBuffer.\r
+\r
+ For each resource data element, create a data node\r
+ and add them to the variable list of arguments of the BufferNode.\r
+\r
+ The input stream is expected to point to a valid list of resource data\r
+ elements. A function is available to check it for the caller.\r
+\r
+ @param [in] BufferNode Buffer node.\r
+ @param [in] FStream Forward stream pointing to a resource data\r
+ element.\r
+ The stream must not be at its end.\r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+ @retval EFI_INVALID_PARAMETER Invalid parameter.\r
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AmlParseResourceData (\r
+ IN AML_OBJECT_NODE * BufferNode,\r
+ IN AML_STREAM * FStream\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ AML_DATA_NODE * NewNode;\r
+ UINT32 FreeSpace;\r
+ CONST AML_RD_HEADER * CurrRdElement;\r
+ UINT32 CurrRdElementSize;\r
+\r
+ // Check that BufferNode is an ObjectNode and has a ByteList.\r
+ if (!AmlNodeHasAttribute (BufferNode, AML_HAS_BYTE_LIST) ||\r
+ !IS_STREAM (FStream) ||\r
+ IS_END_OF_STREAM (FStream) ||\r
+ !IS_STREAM_FORWARD (FStream)) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ // Iterate through the resource data elements and create nodes.\r
+ // We assume the Buffer has already been validated as a list of\r
+ // resource data elements, so less checks are made.\r
+ while (TRUE) {\r
+ FreeSpace = AmlStreamGetFreeSpace (FStream);\r
+ if (FreeSpace == 0) {\r
+ break;\r
+ }\r
+\r
+ CurrRdElement = (CONST AML_RD_HEADER*)AmlStreamGetCurrPos (FStream);\r
+ CurrRdElementSize = AmlRdStreamGetRdSize (FStream);\r
+\r
+ Status = AmlCreateDataNode (\r
+ EAmlNodeDataTypeResourceData,\r
+ (CONST UINT8*)CurrRdElement,\r
+ CurrRdElementSize,\r
+ &NewNode\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ return Status;\r
+ }\r
+\r
+ Status = AmlVarListAddTailInternal (\r
+ (AML_NODE_HEADER*)BufferNode,\r
+ (AML_NODE_HEADER*)NewNode\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ AmlDeleteTree ((AML_NODE_HEADER*)NewNode);\r
+ return Status;\r
+ }\r
+\r
+ Status = AmlStreamProgress (FStream, CurrRdElementSize);\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ return Status;\r
+ }\r
+\r
+ DumpRaw (CurrRdElement, CurrRdElementSize);\r
+\r
+ // Exit the loop when finding the resource data end tag.\r
+ if (AmlRdCompareDescId (\r
+ CurrRdElement,\r
+ AML_RD_BUILD_SMALL_DESC_ID (ACPI_SMALL_END_TAG_DESCRIPTOR_NAME))) {\r
+ if (FreeSpace != CurrRdElementSize) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ break;\r
+ }\r
+ } // while\r
+\r
+ return EFI_SUCCESS;\r
+}\r
--- /dev/null
+/** @file\r
+ AML Resource Data Parser.\r
+\r
+ Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>\r
+\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+ @par Glossary:\r
+ - Rd or RD - Resource Data\r
+ - Rds or RDS - Resource Data Small\r
+ - Rdl or RDL - Resource Data Large\r
+**/\r
+\r
+#ifndef AML_RESOURCE_DATA_PARSER_H_\r
+#define AML_RESOURCE_DATA_PARSER_H_\r
+\r
+#include <AmlNodeDefines.h>\r
+#include <Stream/AmlStream.h>\r
+#include <ResourceData/AmlResourceData.h>\r
+\r
+/** Check whether the input stream is pointing to a valid list\r
+ of resource data elements.\r
+\r
+ The check is based on the size of resource data elements.\r
+ This means that a buffer can pass this check with non-existing descriptor Ids\r
+ that have a correct size.\r
+\r
+ A list of resource data elements can contain one unique resource data\r
+ element, without an end tag resource data. This is the case for\r
+ a FieldList.\r
+\r
+ @param [in] FStream Forward stream ideally pointing to a resource\r
+ data element. The stream is not\r
+ modified/progressing.\r
+ The stream must not be at its end.\r
+\r
+ @retval TRUE The buffer is holding a valid list of resource data elements.\r
+ @retval FALSE Otherwise.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+AmlRdIsResourceDataBuffer (\r
+ IN CONST AML_STREAM * FStream\r
+ );\r
+\r
+/** Parse a ResourceDataBuffer.\r
+\r
+ For each resource data element, create a data node\r
+ and add them to the variable list of arguments of the BufferNode.\r
+\r
+ The input stream is expected to point to a valid list of resource data\r
+ elements. A function is available to check it for the caller.\r
+\r
+ @param [in] BufferNode Buffer node.\r
+ @param [in] FStream Forward stream pointing to a resource data\r
+ element.\r
+ The stream must not be at its end.\r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+ @retval EFI_INVALID_PARAMETER Invalid parameter.\r
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AmlParseResourceData (\r
+ IN AML_OBJECT_NODE * BufferNode,\r
+ IN AML_STREAM * FStream\r
+ );\r
+\r
+#endif // AML_RESOURCE_DATA_PARSER_H_\r
+\r