summaryrefslogtreecommitdiffstats
path: root/DynamicTablesPkg
diff options
context:
space:
mode:
Diffstat (limited to 'DynamicTablesPkg')
-rw-r--r--DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlResourceDataParser.c328
-rw-r--r--DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlResourceDataParser.h71
2 files changed, 399 insertions, 0 deletions
diff --git a/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlResourceDataParser.c b/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlResourceDataParser.c
new file mode 100644
index 0000000000..09fb3e7258
--- /dev/null
+++ b/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/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlResourceDataParser.h b/DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlResourceDataParser.h
new file mode 100644
index 0000000000..13dfb352c4
--- /dev/null
+++ b/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_
+