| /** @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; | |
| } |