diff options
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c')
-rw-r--r-- | src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c | 701 |
1 files changed, 701 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c new file mode 100644 index 00000000..d7ea7bbe --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c @@ -0,0 +1,701 @@ +/** @file + AML Code Generation. + + Copyright (c) 2020, Arm Limited. All rights reserved.<BR> + + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include <AmlNodeDefines.h> + +#include <AcpiTableGenerator.h> + +#include <AmlCoreInterface.h> +#include <AmlEncoding/Aml.h> +#include <Tree/AmlNode.h> +#include <Tree/AmlTree.h> +#include <String/AmlString.h> +#include <Utils/AmlUtility.h> + +/** Utility function to link a node when returning from a CodeGen function. + + @param [in] Node Newly created node. + @param [in] ParentNode If provided, set ParentNode as the parent + of the node created. + @param [out] NewObjectNode If success, contains the created object node. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_INVALID_PARAMETER Invalid parameter. +**/ +STATIC +EFI_STATUS +EFIAPI +LinkNode ( + IN AML_OBJECT_NODE * Node, + IN AML_NODE_HEADER * ParentNode, + OUT AML_OBJECT_NODE ** NewObjectNode + ) +{ + EFI_STATUS Status; + + if (NewObjectNode != NULL) { + *NewObjectNode = Node; + } + + // Add RdNode as the last element. + if (ParentNode != NULL) { + Status = AmlVarListAddTail (ParentNode, (AML_NODE_HEADER*)Node); + if (EFI_ERROR (Status)) { + ASSERT (0); + return Status; + } + } + + return EFI_SUCCESS; +} + +/** AML code generation for DefinitionBlock. + + Create a Root Node handle. + It is the caller's responsibility to free the allocated memory + with the AmlDeleteTree function. + + AmlCodeGenDefinitionBlock (TableSignature, OemID, TableID, OEMRevision) is + equivalent to the following ASL code: + DefinitionBlock (AMLFileName, TableSignature, ComplianceRevision, + OemID, TableID, OEMRevision) {} + with the ComplianceRevision set to 2 and the AMLFileName is ignored. + + @param[in] TableSignature 4-character ACPI signature. + Must be 'DSDT' or 'SSDT'. + @param[in] OemId 6-character string OEM identifier. + @param[in] OemTableId 8-character string OEM table identifier. + @param[in] OemRevision OEM revision number. + @param[out] NewRootNode Pointer to the root node representing a + Definition Block. + + @retval EFI_SUCCESS Success. + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. +**/ +EFI_STATUS +EFIAPI +AmlCodeGenDefinitionBlock ( + IN CONST CHAR8 * TableSignature, + IN CONST CHAR8 * OemId, + IN CONST CHAR8 * OemTableId, + IN UINT32 OemRevision, + OUT AML_ROOT_NODE ** NewRootNode + ) +{ + EFI_STATUS Status; + EFI_ACPI_DESCRIPTION_HEADER AcpiHeader; + + if ((TableSignature == NULL) || + (OemId == NULL) || + (OemTableId == NULL) || + (NewRootNode == NULL)) { + ASSERT (0); + return EFI_INVALID_PARAMETER; + } + + CopyMem (&AcpiHeader.Signature, TableSignature, 4); + AcpiHeader.Length = sizeof (EFI_ACPI_DESCRIPTION_HEADER); + AcpiHeader.Revision = 2; + CopyMem (&AcpiHeader.OemId, OemId, 6); + CopyMem (&AcpiHeader.OemTableId, OemTableId, 8); + AcpiHeader.OemRevision = OemRevision; + AcpiHeader.CreatorId = TABLE_GENERATOR_CREATOR_ID_ARM; + AcpiHeader.CreatorRevision = CREATE_REVISION (1, 0); + + Status = AmlCreateRootNode (&AcpiHeader, NewRootNode); + ASSERT_EFI_ERROR (Status); + + return Status; +} + +/** AML code generation for a String object node. + + @param [in] String Pointer to a NULL terminated string. + @param [out] NewObjectNode If success, contains the created + String object node. + + @retval EFI_SUCCESS Success. + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. +**/ +STATIC +EFI_STATUS +EFIAPI +AmlCodeGenString ( + IN CHAR8 * String, + OUT AML_OBJECT_NODE ** NewObjectNode + ) +{ + EFI_STATUS Status; + AML_OBJECT_NODE * ObjectNode; + AML_DATA_NODE * DataNode; + + if ((String == NULL) || + (NewObjectNode == NULL)) { + ASSERT (0); + return EFI_INVALID_PARAMETER; + } + + ObjectNode = NULL; + DataNode = NULL; + + Status = AmlCreateObjectNode ( + AmlGetByteEncodingByOpCode (AML_STRING_PREFIX, 0), + 0, + &ObjectNode + ); + if (EFI_ERROR (Status)) { + ASSERT (0); + return Status; + } + + Status = AmlCreateDataNode ( + EAmlNodeDataTypeString, + (UINT8*)String, + (UINT32)AsciiStrLen (String) + 1, + &DataNode + ); + if (EFI_ERROR (Status)) { + ASSERT (0); + goto error_handler; + } + + Status = AmlSetFixedArgument ( + ObjectNode, + EAmlParseIndexTerm0, + (AML_NODE_HEADER*)DataNode + ); + if (EFI_ERROR (Status)) { + ASSERT (0); + AmlDeleteTree ((AML_NODE_HEADER*)DataNode); + goto error_handler; + } + + *NewObjectNode = ObjectNode; + return Status; + +error_handler: + if (ObjectNode != NULL) { + AmlDeleteTree ((AML_NODE_HEADER*)ObjectNode); + } + + return Status; +} + +/** AML code generation for an Integer object node. + + @param [in] Integer Integer of the Integer object node. + @param [out] NewObjectNode If success, contains the created + Integer object node. + + @retval EFI_SUCCESS Success. + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. +**/ +STATIC +EFI_STATUS +EFIAPI +AmlCodeGenInteger ( + IN UINT64 Integer, + OUT AML_OBJECT_NODE ** NewObjectNode + ) +{ + EFI_STATUS Status; + INT8 ValueWidthDiff; + + if (NewObjectNode == NULL) { + ASSERT (0); + return EFI_INVALID_PARAMETER; + } + + // Create an object node containing Zero. + Status = AmlCreateObjectNode ( + AmlGetByteEncodingByOpCode (AML_ZERO_OP, 0), + 0, + NewObjectNode + ); + if (EFI_ERROR (Status)) { + ASSERT (0); + return Status; + } + + // Update the object node with integer value. + Status = AmlNodeSetIntegerValue (*NewObjectNode, Integer, &ValueWidthDiff); + if (EFI_ERROR (Status)) { + ASSERT (0); + AmlDeleteTree ((AML_NODE_HEADER*)*NewObjectNode); + } + + return Status; +} + +/** AML code generation for a Name object node. + + @param [in] NameString The new variable name. + Must be a NULL-terminated ASL NameString + e.g.: "DEV0", "DV15.DEV0", etc. + This input string is copied. + @param [in] Object Object associated to the NameString. + @param [in] ParentNode If provided, set ParentNode as the parent + of the node created. + @param [out] NewObjectNode If success, contains the created node. + + @retval EFI_SUCCESS Success. + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. +**/ +STATIC +EFI_STATUS +EFIAPI +AmlCodeGenName ( + IN CONST CHAR8 * NameString, + IN AML_OBJECT_NODE * Object, + IN AML_NODE_HEADER * ParentNode, OPTIONAL + OUT AML_OBJECT_NODE ** NewObjectNode OPTIONAL + ) +{ + EFI_STATUS Status; + AML_OBJECT_NODE * ObjectNode; + AML_DATA_NODE * DataNode; + CHAR8 * AmlNameString; + UINT32 AmlNameStringSize; + + if ((NameString == NULL) || + (Object == NULL) || + ((ParentNode == NULL) && (NewObjectNode == NULL))) { + ASSERT (0); + return EFI_INVALID_PARAMETER; + } + + ObjectNode = NULL; + DataNode = NULL; + AmlNameString = NULL; + + Status = ConvertAslNameToAmlName (NameString, &AmlNameString); + if (EFI_ERROR (Status)) { + ASSERT (0); + return Status; + } + + Status = AmlGetNameStringSize (AmlNameString, &AmlNameStringSize); + if (EFI_ERROR (Status)) { + ASSERT (0); + goto error_handler1; + } + + Status = AmlCreateObjectNode ( + AmlGetByteEncodingByOpCode (AML_NAME_OP, 0), + 0, + &ObjectNode + ); + if (EFI_ERROR (Status)) { + ASSERT (0); + goto error_handler1; + } + + Status = AmlCreateDataNode ( + EAmlNodeDataTypeNameString, + (UINT8*)AmlNameString, + AmlNameStringSize, + &DataNode + ); + if (EFI_ERROR (Status)) { + ASSERT (0); + goto error_handler2; + } + + Status = AmlSetFixedArgument ( + ObjectNode, + EAmlParseIndexTerm0, + (AML_NODE_HEADER*)DataNode + ); + if (EFI_ERROR (Status)) { + ASSERT (0); + AmlDeleteTree ((AML_NODE_HEADER*)DataNode); + goto error_handler2; + } + + Status = AmlSetFixedArgument ( + ObjectNode, + EAmlParseIndexTerm1, + (AML_NODE_HEADER*)Object + ); + if (EFI_ERROR (Status)) { + ASSERT (0); + goto error_handler2; + } + + Status = LinkNode ( + ObjectNode, + ParentNode, + NewObjectNode + ); + if (EFI_ERROR (Status)) { + ASSERT (0); + goto error_handler2; + } + + // Free AmlNameString before returning as it is copied + // in the call to AmlCreateDataNode(). + goto error_handler1; + +error_handler2: + if (ObjectNode != NULL) { + AmlDeleteTree ((AML_NODE_HEADER*)ObjectNode); + } + +error_handler1: + if (AmlNameString != NULL) { + FreePool (AmlNameString); + } + + return Status; +} + +/** AML code generation for a Name object node, containing a String. + + AmlCodeGenNameString ("_HID", "HID0000", ParentNode, NewObjectNode) is + equivalent of the following ASL code: + Name(_HID, "HID0000") + + @param [in] NameString The new variable name. + Must be a NULL-terminated ASL NameString + e.g.: "DEV0", "DV15.DEV0", etc. + The input string is copied. + @param [in] String NULL terminated String to associate to the + NameString. + @param [in] ParentNode If provided, set ParentNode as the parent + of the node created. + @param [out] NewObjectNode If success, contains the created node. + + @retval EFI_SUCCESS Success. + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. +**/ +EFI_STATUS +EFIAPI +AmlCodeGenNameString ( + IN CONST CHAR8 * NameString, + IN CHAR8 * String, + IN AML_NODE_HEADER * ParentNode, OPTIONAL + OUT AML_OBJECT_NODE ** NewObjectNode OPTIONAL + ) +{ + EFI_STATUS Status; + AML_OBJECT_NODE * ObjectNode; + + if ((NameString == NULL) || + (String == NULL) || + ((ParentNode == NULL) && (NewObjectNode == NULL))) { + ASSERT (0); + return EFI_INVALID_PARAMETER; + } + + Status = AmlCodeGenString (String, &ObjectNode); + if (EFI_ERROR (Status)) { + ASSERT (0); + return Status; + } + + Status = AmlCodeGenName ( + NameString, + ObjectNode, + ParentNode, + NewObjectNode + ); + if (EFI_ERROR (Status)) { + ASSERT (0); + AmlDeleteTree ((AML_NODE_HEADER*)ObjectNode); + } + + return Status; +} + +/** AML code generation for a Name object node, containing an Integer. + + AmlCodeGenNameInteger ("_UID", 1, ParentNode, NewObjectNode) is + equivalent of the following ASL code: + Name(_UID, One) + + @param [in] NameString The new variable name. + Must be a NULL-terminated ASL NameString + e.g.: "DEV0", "DV15.DEV0", etc. + The input string is copied. + @param [in] Integer Integer to associate to the NameString. + @param [in] ParentNode If provided, set ParentNode as the parent + of the node created. + @param [out] NewObjectNode If success, contains the created node. + + @retval EFI_SUCCESS Success. + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. +**/ +EFI_STATUS +EFIAPI +AmlCodeGenNameInteger ( + IN CONST CHAR8 * NameString, + IN UINT64 Integer, + IN AML_NODE_HEADER * ParentNode, OPTIONAL + OUT AML_OBJECT_NODE ** NewObjectNode OPTIONAL + ) +{ + EFI_STATUS Status; + AML_OBJECT_NODE * ObjectNode; + + if ((NameString == NULL) || + ((ParentNode == NULL) && (NewObjectNode == NULL))) { + ASSERT (0); + return EFI_INVALID_PARAMETER; + } + + Status = AmlCodeGenInteger (Integer, &ObjectNode); + if (EFI_ERROR (Status)) { + ASSERT (0); + return Status; + } + + Status = AmlCodeGenName ( + NameString, + ObjectNode, + ParentNode, + NewObjectNode + ); + if (EFI_ERROR (Status)) { + ASSERT (0); + AmlDeleteTree ((AML_NODE_HEADER*)ObjectNode); + } + + return Status; +} + +/** AML code generation for a Device object node. + + AmlCodeGenDevice ("COM0", ParentNode, NewObjectNode) is + equivalent of the following ASL code: + Device(COM0) {} + + @param [in] NameString The new Device's name. + Must be a NULL-terminated ASL NameString + e.g.: "DEV0", "DV15.DEV0", etc. + The input string is copied. + @param [in] ParentNode If provided, set ParentNode as the parent + of the node created. + @param [out] NewObjectNode If success, contains the created node. + + @retval EFI_SUCCESS Success. + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. +**/ +EFI_STATUS +EFIAPI +AmlCodeGenDevice ( + IN CONST CHAR8 * NameString, + IN AML_NODE_HEADER * ParentNode, OPTIONAL + OUT AML_OBJECT_NODE ** NewObjectNode OPTIONAL + ) +{ + EFI_STATUS Status; + AML_OBJECT_NODE * ObjectNode; + AML_DATA_NODE * DataNode; + CHAR8 * AmlNameString; + UINT32 AmlNameStringSize; + + if ((NameString == NULL) || + ((ParentNode == NULL) && (NewObjectNode == NULL))) { + ASSERT (0); + return EFI_INVALID_PARAMETER; + } + + ObjectNode = NULL; + DataNode = NULL; + AmlNameString = NULL; + + Status = ConvertAslNameToAmlName (NameString, &AmlNameString); + if (EFI_ERROR (Status)) { + ASSERT (0); + return Status; + } + + Status = AmlGetNameStringSize (AmlNameString, &AmlNameStringSize); + if (EFI_ERROR (Status)) { + ASSERT (0); + goto error_handler1; + } + + Status = AmlCreateObjectNode ( + AmlGetByteEncodingByOpCode (AML_EXT_OP, AML_EXT_DEVICE_OP), + AmlNameStringSize + AmlComputePkgLengthWidth (AmlNameStringSize), + &ObjectNode + ); + if (EFI_ERROR (Status)) { + ASSERT (0); + goto error_handler1; + } + + Status = AmlCreateDataNode ( + EAmlNodeDataTypeNameString, + (UINT8*)AmlNameString, + AmlNameStringSize, + &DataNode + ); + if (EFI_ERROR (Status)) { + ASSERT (0); + goto error_handler2; + } + + Status = AmlSetFixedArgument ( + ObjectNode, + EAmlParseIndexTerm0, + (AML_NODE_HEADER*)DataNode + ); + if (EFI_ERROR (Status)) { + ASSERT (0); + AmlDeleteTree ((AML_NODE_HEADER*)DataNode); + goto error_handler2; + } + + Status = LinkNode ( + ObjectNode, + ParentNode, + NewObjectNode + ); + if (EFI_ERROR (Status)) { + ASSERT (0); + goto error_handler2; + } + + // Free AmlNameString before returning as it is copied + // in the call to AmlCreateDataNode(). + goto error_handler1; + +error_handler2: + if (ObjectNode != NULL) { + AmlDeleteTree ((AML_NODE_HEADER*)ObjectNode); + } + +error_handler1: + if (AmlNameString != NULL) { + FreePool (AmlNameString); + } + + return Status; +} + +/** AML code generation for a Scope object node. + + AmlCodeGenScope ("_SB", ParentNode, NewObjectNode) is + equivalent of the following ASL code: + Scope(_SB) {} + + @param [in] NameString The new Scope's name. + Must be a NULL-terminated ASL NameString + e.g.: "DEV0", "DV15.DEV0", etc. + The input string is copied. + @param [in] ParentNode If provided, set ParentNode as the parent + of the node created. + @param [out] NewObjectNode If success, contains the created node. + + @retval EFI_SUCCESS Success. + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. +**/ +EFI_STATUS +EFIAPI +AmlCodeGenScope ( + IN CONST CHAR8 * NameString, + IN AML_NODE_HEADER * ParentNode, OPTIONAL + OUT AML_OBJECT_NODE ** NewObjectNode OPTIONAL + ) +{ + EFI_STATUS Status; + AML_OBJECT_NODE * ObjectNode; + AML_DATA_NODE * DataNode; + CHAR8 * AmlNameString; + UINT32 AmlNameStringSize; + + if ((NameString == NULL) || + ((ParentNode == NULL) && (NewObjectNode == NULL))) { + ASSERT (0); + return EFI_INVALID_PARAMETER; + } + + ObjectNode = NULL; + DataNode = NULL; + AmlNameString = NULL; + + Status = ConvertAslNameToAmlName (NameString, &AmlNameString); + if (EFI_ERROR (Status)) { + ASSERT (0); + return Status; + } + + Status = AmlGetNameStringSize (AmlNameString, &AmlNameStringSize); + if (EFI_ERROR (Status)) { + ASSERT (0); + goto error_handler1; + } + + Status = AmlCreateObjectNode ( + AmlGetByteEncodingByOpCode (AML_SCOPE_OP, 0), + AmlNameStringSize + AmlComputePkgLengthWidth (AmlNameStringSize), + &ObjectNode + ); + if (EFI_ERROR (Status)) { + ASSERT (0); + goto error_handler1; + } + + Status = AmlCreateDataNode ( + EAmlNodeDataTypeNameString, + (UINT8*)AmlNameString, + AmlNameStringSize, + &DataNode + ); + if (EFI_ERROR (Status)) { + ASSERT (0); + goto error_handler2; + } + + Status = AmlSetFixedArgument ( + ObjectNode, + EAmlParseIndexTerm0, + (AML_NODE_HEADER*)DataNode + ); + if (EFI_ERROR (Status)) { + ASSERT (0); + AmlDeleteTree ((AML_NODE_HEADER*)DataNode); + goto error_handler2; + } + + Status = LinkNode ( + ObjectNode, + ParentNode, + NewObjectNode + ); + if (EFI_ERROR (Status)) { + ASSERT (0); + goto error_handler2; + } + + // Free AmlNameString before returning as it is copied + // in the call to AmlCreateDataNode(). + goto error_handler1; + +error_handler2: + if (ObjectNode != NULL) { + AmlDeleteTree ((AML_NODE_HEADER*)ObjectNode); + } + +error_handler1: + if (AmlNameString != NULL) { + FreePool (AmlNameString); + } + + return Status; +} |