diff options
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Common/AmlLib/Serialize/AmlSerialize.c')
-rw-r--r-- | src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Common/AmlLib/Serialize/AmlSerialize.c | 324 |
1 files changed, 324 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Common/AmlLib/Serialize/AmlSerialize.c b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Common/AmlLib/Serialize/AmlSerialize.c new file mode 100644 index 00000000..7f86d646 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/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; +} |