summaryrefslogtreecommitdiffstats
path: root/DynamicTablesPkg
diff options
context:
space:
mode:
Diffstat (limited to 'DynamicTablesPkg')
-rw-r--r--DynamicTablesPkg/Library/Common/AmlLib/Serialize/AmlSerialize.c324
1 files changed, 324 insertions, 0 deletions
diff --git a/DynamicTablesPkg/Library/Common/AmlLib/Serialize/AmlSerialize.c b/DynamicTablesPkg/Library/Common/AmlLib/Serialize/AmlSerialize.c
new file mode 100644
index 0000000000..2a47c229d7
--- /dev/null
+++ b/DynamicTablesPkg/Library/Common/AmlLib/Serialize/AmlSerialize.c
@@ -0,0 +1,324 @@
+/** @file
+ AML Serialize.
+
+ Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <AmlNodeDefines.h>
+
+#include <AmlCoreInterface.h>
+#include <Stream/AmlStream.h>
+#include <Tree/AmlNode.h>
+#include <Tree/AmlTree.h>
+#include <Utils/AmlUtility.h>
+
+/** Callback function to copy the AML bytecodes contained in a node
+ to the Stream stored in the Context.
+ The SDT header data contained in the root node is not serialized
+ by this function.
+
+ @param [in] Node Pointer to the node to copy the AML bytecodes
+ from.
+ @param [in, out] Context Contains a forward Stream to write to.
+ (AML_STREAM*)Context.
+ @param [in, out] Status At entry, contains the status returned by the
+ last call to this exact function during the
+ enumeration.
+ As exit, contains the returned status of the
+ call to this function.
+ Optional, can be NULL.
+
+ @retval TRUE if the enumeration can continue or has finished without
+ interruption.
+ @retval FALSE if the enumeration needs to stopped or has stopped.
+**/
+STATIC
+BOOLEAN
+EFIAPI
+AmlSerializeNodeCallback (
+ IN AML_NODE_HEADER * Node,
+ IN OUT VOID * Context, OPTIONAL
+ IN OUT EFI_STATUS * Status OPTIONAL
+ )
+{
+ EFI_STATUS Status1;
+
+ CONST AML_DATA_NODE * DataNode;
+ CONST AML_OBJECT_NODE * ObjectNode;
+ AML_STREAM * FStream;
+
+ // Bytes needed to store OpCode[1] + SubOpcode[1] + MaxPkgLen[4] = 6 bytes.
+ UINT8 ObjectNodeInfoArray[6];
+ UINT32 Index;
+ BOOLEAN ContinueEnum;
+
+ CONST AML_OBJECT_NODE * ParentNode;
+ EAML_PARSE_INDEX IndexPtr;
+
+ if (!IS_AML_NODE_VALID (Node) ||
+ (Context == NULL)) {
+ ASSERT (0);
+ Status1 = EFI_INVALID_PARAMETER;
+ ContinueEnum = FALSE;
+ goto error_handler;
+ }
+
+ // Ignore the second fixed argument of method invocation nodes
+ // as the information stored there (the argument count) is not in the
+ // ACPI specification.
+ ParentNode = (CONST AML_OBJECT_NODE*)AmlGetParent ((AML_NODE_HEADER*)Node);
+ if (IS_AML_OBJECT_NODE (ParentNode) &&
+ AmlNodeCompareOpCode (ParentNode, AML_METHOD_INVOC_OP, 0) &&
+ AmlIsNodeFixedArgument (Node, &IndexPtr)) {
+ if (IndexPtr == EAmlParseIndexTerm1) {
+ if (Status != NULL) {
+ *Status = EFI_SUCCESS;
+ }
+ return TRUE;
+ }
+ }
+
+ Status1 = EFI_SUCCESS;
+ ContinueEnum = TRUE;
+ FStream = (AML_STREAM*)Context;
+
+ if (IS_AML_DATA_NODE (Node)) {
+ // Copy the content of the Buffer for a DataNode.
+ DataNode = (AML_DATA_NODE*)Node;
+ Status1 = AmlStreamWrite (
+ FStream,
+ DataNode->Buffer,
+ DataNode->Size
+ );
+ if (EFI_ERROR (Status1)) {
+ ASSERT (0);
+ ContinueEnum = FALSE;
+ goto error_handler;
+ }
+
+ } else if (IS_AML_OBJECT_NODE (Node) &&
+ !AmlNodeHasAttribute (
+ (CONST AML_OBJECT_NODE*)Node,
+ AML_IS_PSEUDO_OPCODE)) {
+ // Ignore pseudo-opcodes as they are not part of the
+ // ACPI specification.
+
+ ObjectNode = (AML_OBJECT_NODE*)Node;
+
+ Index = 0;
+ // Copy the opcode(s).
+ ObjectNodeInfoArray[Index++] = ObjectNode->AmlByteEncoding->OpCode;
+ if (ObjectNode->AmlByteEncoding->OpCode == AML_EXT_OP) {
+ ObjectNodeInfoArray[Index++] = ObjectNode->AmlByteEncoding->SubOpCode;
+ }
+
+ // Copy the PkgLen.
+ if (AmlNodeHasAttribute (ObjectNode, AML_HAS_PKG_LENGTH)) {
+ Index += AmlSetPkgLength (
+ ObjectNode->PkgLen,
+ &ObjectNodeInfoArray[Index]
+ );
+ }
+
+ Status1 = AmlStreamWrite (
+ FStream,
+ ObjectNodeInfoArray,
+ Index
+ );
+ if (EFI_ERROR (Status1)) {
+ ASSERT (0);
+ ContinueEnum = FALSE;
+ goto error_handler;
+ }
+ } // IS_AML_OBJECT_NODE (Node)
+
+error_handler:
+ if (Status != NULL) {
+ *Status = Status1;
+ }
+ return ContinueEnum;
+}
+
+/** Serialize a tree to create an ACPI DSDT/SSDT table.
+
+ If:
+ - the content of BufferSize is >= to the size needed to serialize the
+ definition block;
+ - Buffer is not NULL;
+ first serialize the ACPI DSDT/SSDT header from the root node,
+ then serialize the AML blob from the rest of the tree.
+
+ The content of BufferSize is always updated to the size needed to
+ serialize the definition block.
+
+ @param [in] RootNode Pointer to a root node.
+ @param [in] Buffer Buffer to write the DSDT/SSDT table to.
+ If Buffer is NULL, the size needed to
+ serialize the DSDT/SSDT table is returned
+ in BufferSize.
+ @param [in, out] BufferSize Pointer holding the size of the Buffer.
+ Its content is always updated to the size
+ needed to serialize the DSDT/SSDT table.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
+**/
+EFI_STATUS
+EFIAPI
+AmlSerializeTree (
+ IN AML_ROOT_NODE * RootNode,
+ IN UINT8 * Buffer, OPTIONAL
+ IN OUT UINT32 * BufferSize
+ )
+{
+ EFI_STATUS Status;
+ AML_STREAM FStream;
+ UINT32 TableSize;
+
+ if (!IS_AML_ROOT_NODE (RootNode) ||
+ (BufferSize == NULL)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Compute the total size of the AML blob.
+ Status = AmlComputeSize (
+ (CONST AML_NODE_HEADER*)RootNode,
+ &TableSize
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Add the size of the ACPI header.
+ TableSize += (UINT32)sizeof (EFI_ACPI_DESCRIPTION_HEADER);
+
+ // Check the size against the SDT header.
+ // The Length field in the SDT Header is updated if the tree has
+ // been modified.
+ if (TableSize != RootNode->SdtHeader->Length) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Buffer is not big enough, or NULL.
+ if ((TableSize < *BufferSize) || (Buffer == NULL)) {
+ *BufferSize = TableSize;
+ return EFI_SUCCESS;
+ }
+
+ // Initialize the stream to the TableSize that is needed.
+ Status = AmlStreamInit (
+ &FStream,
+ Buffer,
+ TableSize,
+ EAmlStreamDirectionForward
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Serialize the header.
+ Status = AmlStreamWrite (
+ &FStream,
+ (UINT8*)RootNode->SdtHeader,
+ sizeof (EFI_ACPI_DESCRIPTION_HEADER)
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ Status = EFI_SUCCESS;
+ AmlEnumTree (
+ (AML_NODE_HEADER*)RootNode,
+ AmlSerializeNodeCallback,
+ (VOID*)&FStream,
+ &Status
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Update the checksum.
+ return AcpiPlatformChecksum ((EFI_ACPI_DESCRIPTION_HEADER*)Buffer);
+}
+
+/** Serialize an AML definition block.
+
+ This functions allocates memory with the "AllocateZeroPool ()"
+ function. This memory is used to serialize the AML tree and is
+ returned in the Table.
+
+ @param [in] RootNode Root node of the tree.
+ @param [out] Table On return, hold the serialized
+ definition block.
+
+ @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
+AmlSerializeDefinitionBlock (
+ IN AML_ROOT_NODE * RootNode,
+ OUT EFI_ACPI_DESCRIPTION_HEADER ** Table
+ )
+{
+ EFI_STATUS Status;
+ UINT8 * TableBuffer;
+ UINT32 TableSize;
+
+ if (!IS_AML_ROOT_NODE (RootNode) ||
+ (Table == NULL)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Table = NULL;
+ TableBuffer = NULL;
+ TableSize = 0;
+
+ // Get the size of the SSDT table.
+ Status = AmlSerializeTree (
+ RootNode,
+ TableBuffer,
+ &TableSize
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ TableBuffer = (UINT8*)AllocateZeroPool (TableSize);
+ if (TableBuffer == NULL) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: Failed to allocate memory for Table Buffer."
+ ));
+ ASSERT (0);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ // Serialize the tree to a SSDT table.
+ Status = AmlSerializeTree (
+ RootNode,
+ TableBuffer,
+ &TableSize
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (TableBuffer);
+ ASSERT (0);
+ } else {
+ // Save the allocated Table buffer in the table list
+ *Table = (EFI_ACPI_DESCRIPTION_HEADER*)TableBuffer;
+ }
+
+ return Status;
+}