| /** @file | |
| AML Code Generation. | |
| Copyright (c) 2020 - 2022, Arm Limited. All rights reserved.<BR> | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #include <AmlNodeDefines.h> | |
| #include <AcpiTableGenerator.h> | |
| #include <AmlCoreInterface.h> | |
| #include <AmlCpcInfo.h> | |
| #include <AmlEncoding/Aml.h> | |
| #include <Api/AmlApiHelper.h> | |
| #include <CodeGen/AmlResourceDataCodeGen.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 not NULL: | |
| - and Success, contains the created Node. | |
| - and Error, reset to NULL. | |
| @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 = NULL; | |
| } | |
| // Add RdNode as the last element. | |
| if (ParentNode != NULL) { | |
| Status = AmlVarListAddTail (ParentNode, (AML_NODE_HEADER *)Node); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| return Status; | |
| } | |
| } | |
| if (NewObjectNode != NULL) { | |
| *NewObjectNode = Node; | |
| } | |
| 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; | |
| } | |
| 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: | |
| 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 Package object node. | |
| The package generated is empty. New elements can be added via its | |
| list of variable arguments. | |
| @param [out] NewObjectNode If success, contains the created | |
| Package 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 | |
| AmlCodeGenPackage ( | |
| OUT AML_OBJECT_NODE **NewObjectNode | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| AML_DATA_NODE *DataNode; | |
| UINT8 NodeCount; | |
| if (NewObjectNode == NULL) { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| NodeCount = 0; | |
| // Create an object node. | |
| // PkgLen is 2: | |
| // - one byte to store the PkgLength | |
| // - one byte for the NumElements. | |
| // Cf ACPI6.3, s20.2.5 "Term Objects Encoding" | |
| // DefPackage := PackageOp PkgLength NumElements PackageElementList | |
| // NumElements := ByteData | |
| Status = AmlCreateObjectNode ( | |
| AmlGetByteEncodingByOpCode (AML_PACKAGE_OP, 0), | |
| 2, | |
| NewObjectNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| return Status; | |
| } | |
| // NumElements is a ByteData. | |
| Status = AmlCreateDataNode ( | |
| EAmlNodeDataTypeUInt, | |
| &NodeCount, | |
| sizeof (NodeCount), | |
| &DataNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler; | |
| } | |
| Status = AmlSetFixedArgument ( | |
| *NewObjectNode, | |
| EAmlParseIndexTerm0, | |
| (AML_NODE_HEADER *)DataNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler; | |
| } | |
| return Status; | |
| error_handler: | |
| AmlDeleteTree ((AML_NODE_HEADER *)*NewObjectNode); | |
| if (DataNode != NULL) { | |
| AmlDeleteTree ((AML_NODE_HEADER *)DataNode); | |
| } | |
| return Status; | |
| } | |
| /** AML code generation for a Buffer object node. | |
| To create a Buffer object node with an empty buffer, | |
| call the function with (Buffer=NULL, BufferSize=0). | |
| @param [in] Buffer Buffer to set for the created Buffer | |
| object node. The Buffer's content is copied. | |
| NULL if there is no buffer to set for | |
| the Buffer node. | |
| @param [in] BufferSize Size of the Buffer. | |
| 0 if there is no buffer to set for | |
| the Buffer node. | |
| @param [out] NewObjectNode If success, contains the created | |
| Buffer 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 | |
| AmlCodeGenBuffer ( | |
| IN CONST UINT8 *Buffer OPTIONAL, | |
| IN UINT32 BufferSize OPTIONAL, | |
| OUT AML_OBJECT_NODE **NewObjectNode | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| AML_OBJECT_NODE *BufferNode; | |
| AML_OBJECT_NODE *BufferSizeNode; | |
| UINT32 BufferSizeNodeSize; | |
| AML_DATA_NODE *DataNode; | |
| UINT32 PkgLen; | |
| // Buffer and BufferSize must be either both set, or both clear. | |
| if ((NewObjectNode == NULL) || | |
| ((Buffer == NULL) != (BufferSize == 0))) | |
| { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| BufferNode = NULL; | |
| DataNode = NULL; | |
| // Cf ACPI 6.3 specification, s20.2.5.4 "Type 2 Opcodes Encoding" | |
| // DefBuffer := BufferOp PkgLength BufferSize ByteList | |
| // BufferOp := 0x11 | |
| // BufferSize := TermArg => Integer | |
| Status = AmlCodeGenInteger (BufferSize, &BufferSizeNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| return Status; | |
| } | |
| // Get the number of bytes required to encode the BufferSizeNode. | |
| Status = AmlComputeSize ( | |
| (AML_NODE_HEADER *)BufferSizeNode, | |
| &BufferSizeNodeSize | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler; | |
| } | |
| // Compute the size to write in the PkgLen. | |
| Status = AmlComputePkgLength (BufferSizeNodeSize + BufferSize, &PkgLen); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler; | |
| } | |
| // Create an object node for the buffer. | |
| Status = AmlCreateObjectNode ( | |
| AmlGetByteEncodingByOpCode (AML_BUFFER_OP, 0), | |
| PkgLen, | |
| &BufferNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler; | |
| } | |
| // Set the BufferSizeNode as a fixed argument of the BufferNode. | |
| Status = AmlSetFixedArgument ( | |
| BufferNode, | |
| EAmlParseIndexTerm0, | |
| (AML_NODE_HEADER *)BufferSizeNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler; | |
| } | |
| // BufferSizeNode is now attached. | |
| BufferSizeNode = NULL; | |
| // If there is a buffer, create a DataNode and attach it to the BufferNode. | |
| if (Buffer != NULL) { | |
| Status = AmlCreateDataNode ( | |
| EAmlNodeDataTypeRaw, | |
| Buffer, | |
| BufferSize, | |
| &DataNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler; | |
| } | |
| Status = AmlVarListAddTail ( | |
| (AML_NODE_HEADER *)BufferNode, | |
| (AML_NODE_HEADER *)DataNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler; | |
| } | |
| } | |
| *NewObjectNode = BufferNode; | |
| return Status; | |
| error_handler: | |
| if (BufferSizeNode != NULL) { | |
| AmlDeleteTree ((AML_NODE_HEADER *)BufferSizeNode); | |
| } | |
| if (BufferNode != NULL) { | |
| AmlDeleteTree ((AML_NODE_HEADER *)BufferNode); | |
| } | |
| if (DataNode != NULL) { | |
| AmlDeleteTree ((AML_NODE_HEADER *)DataNode); | |
| } | |
| return Status; | |
| } | |
| /** AML code generation for a ResourceTemplate. | |
| "ResourceTemplate" is a macro defined in ACPI 6.3, s19.3.3 | |
| "ASL Resource Templates". It allows to store resource data elements. | |
| In AML, a ResourceTemplate is implemented as a Buffer storing resource | |
| data elements. An EndTag resource data descriptor must be at the end | |
| of the list of resource data elements. | |
| This function generates a Buffer node with an EndTag resource data | |
| descriptor. It can be seen as an empty list of resource data elements. | |
| @param [out] NewObjectNode If success, contains the created | |
| ResourceTemplate 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 | |
| AmlCodeGenResourceTemplate ( | |
| OUT AML_OBJECT_NODE **NewObjectNode | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| AML_OBJECT_NODE *BufferNode; | |
| if (NewObjectNode == NULL) { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // Create a BufferNode with an empty buffer. | |
| Status = AmlCodeGenBuffer (NULL, 0, &BufferNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| return Status; | |
| } | |
| // Create an EndTag resource data element and attach it to the Buffer. | |
| Status = AmlCodeGenEndTag (0, BufferNode, NULL); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| AmlDeleteTree ((AML_NODE_HEADER *)BufferNode); | |
| return Status; | |
| } | |
| *NewObjectNode = BufferNode; | |
| 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 Name object node, containing a Package. | |
| AmlCodeGenNamePackage ("PKG0", ParentNode, NewObjectNode) is | |
| equivalent of the following ASL code: | |
| Name(PKG0, Package () {}) | |
| @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] 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 | |
| AmlCodeGenNamePackage ( | |
| IN CONST CHAR8 *NameString, | |
| IN AML_NODE_HEADER *ParentNode, OPTIONAL | |
| OUT AML_OBJECT_NODE **NewObjectNode OPTIONAL | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| AML_OBJECT_NODE *PackageNode; | |
| if ((NameString == NULL) || | |
| ((ParentNode == NULL) && (NewObjectNode == NULL))) | |
| { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Status = AmlCodeGenPackage (&PackageNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| return Status; | |
| } | |
| Status = AmlCodeGenName ( | |
| NameString, | |
| PackageNode, | |
| ParentNode, | |
| NewObjectNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| AmlDeleteTree ((AML_NODE_HEADER *)PackageNode); | |
| } | |
| return Status; | |
| } | |
| /** AML code generation for a Name object node, containing a ResourceTemplate. | |
| AmlCodeGenNameResourceTemplate ("PRS0", ParentNode, NewObjectNode) is | |
| equivalent of the following ASL code: | |
| Name(PRS0, ResourceTemplate () {}) | |
| @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] 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 | |
| AmlCodeGenNameResourceTemplate ( | |
| IN CONST CHAR8 *NameString, | |
| IN AML_NODE_HEADER *ParentNode, OPTIONAL | |
| OUT AML_OBJECT_NODE **NewObjectNode OPTIONAL | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| AML_OBJECT_NODE *ResourceTemplateNode; | |
| if ((NameString == NULL) || | |
| ((ParentNode == NULL) && (NewObjectNode == NULL))) | |
| { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Status = AmlCodeGenResourceTemplate (&ResourceTemplateNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| return Status; | |
| } | |
| Status = AmlCodeGenName ( | |
| NameString, | |
| ResourceTemplateNode, | |
| ParentNode, | |
| NewObjectNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| AmlDeleteTree ((AML_NODE_HEADER *)ResourceTemplateNode); | |
| } | |
| return Status; | |
| } | |
| /** Add a _PRT entry. | |
| AmlCodeGenPrtEntry (0x0FFFF, 0, "LNKA", 0, PrtNameNode) is | |
| equivalent of the following ASL code: | |
| Package (4) { | |
| 0x0FFFF, // Address: Device address (([Device Id] << 16) | 0xFFFF). | |
| 0, // Pin: PCI pin number of the device (0-INTA, ...). | |
| LNKA // Source: Name of the device that allocates the interrupt | |
| // to which the above pin is connected. | |
| 0 // Source Index: Source is assumed to only describe one | |
| // interrupt, so let it to index 0. | |
| } | |
| The 2 models described in ACPI 6.4, s6.2.13 "_PRT (PCI Routing Table)" can | |
| be generated by this function. The example above matches the first model. | |
| The package is added at the tail of the list of the input _PRT node | |
| name: | |
| Name (_PRT, Package () { | |
| [Pre-existing _PRT entries], | |
| [Newly created _PRT entry] | |
| }) | |
| Cf. ACPI 6.4 specification: | |
| - s6.2.13 "_PRT (PCI Routing Table)" | |
| - s6.1.1 "_ADR (Address)" | |
| @param [in] Address Address. Cf ACPI 6.4 specification, Table 6.2: | |
| "ADR Object Address Encodings": | |
| High word-Device #, Low word-Function #. (for | |
| example, device 3, function 2 is 0x00030002). | |
| To refer to all the functions on a device #, | |
| use a function number of FFFF). | |
| @param [in] Pin PCI pin number of the device (0-INTA ... 3-INTD). | |
| Must be between 0-3. | |
| @param [in] LinkName Link Name, i.e. device in the AML NameSpace | |
| describing the interrupt used. The input string | |
| is copied. | |
| If NULL, generate 0 in the 'Source' field (cf. | |
| second model, using GSIV). | |
| @param [in] SourceIndex Source index or GSIV. | |
| @param [in] PrtNameNode Prt Named node to add the object to .... | |
| @retval EFI_SUCCESS Success. | |
| @retval EFI_INVALID_PARAMETER Invalid parameter. | |
| @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| AmlAddPrtEntry ( | |
| IN UINT32 Address, | |
| IN UINT8 Pin, | |
| IN CONST CHAR8 *LinkName, | |
| IN UINT32 SourceIndex, | |
| IN AML_OBJECT_NODE_HANDLE PrtNameNode | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| AML_OBJECT_NODE *PrtEntryList; | |
| AML_OBJECT_NODE *PackageNode; | |
| AML_OBJECT_NODE *NewElementNode; | |
| CHAR8 *AmlNameString; | |
| UINT32 AmlNameStringSize; | |
| AML_DATA_NODE *DataNode; | |
| if ((Pin > 3) || | |
| (PrtNameNode == NULL) || | |
| (AmlGetNodeType ((AML_NODE_HANDLE)PrtNameNode) != EAmlNodeObject) || | |
| (!AmlNodeHasOpCode (PrtNameNode, AML_NAME_OP, 0)) || | |
| !AmlNameOpCompareName (PrtNameNode, "_PRT")) | |
| { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| NewElementNode = NULL; | |
| AmlNameString = NULL; | |
| DataNode = NULL; | |
| // Get the Package object node of the _PRT node, | |
| // which is the 2nd fixed argument (i.e. index 1). | |
| PrtEntryList = (AML_OBJECT_NODE_HANDLE)AmlGetFixedArgument ( | |
| PrtNameNode, | |
| EAmlParseIndexTerm1 | |
| ); | |
| if ((PrtEntryList == NULL) || | |
| (AmlGetNodeType ((AML_NODE_HANDLE)PrtEntryList) != EAmlNodeObject) || | |
| (!AmlNodeHasOpCode (PrtEntryList, AML_PACKAGE_OP, 0))) | |
| { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // The new _PRT entry. | |
| Status = AmlCodeGenPackage (&PackageNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| return Status; | |
| } | |
| Status = AmlCodeGenInteger (Address, &NewElementNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler; | |
| } | |
| Status = AmlVarListAddTail ( | |
| (AML_NODE_HANDLE)PackageNode, | |
| (AML_NODE_HANDLE)NewElementNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler; | |
| } | |
| NewElementNode = NULL; | |
| Status = AmlCodeGenInteger (Pin, &NewElementNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler; | |
| } | |
| Status = AmlVarListAddTail ( | |
| (AML_NODE_HANDLE)PackageNode, | |
| (AML_NODE_HANDLE)NewElementNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler; | |
| } | |
| NewElementNode = NULL; | |
| if (LinkName != NULL) { | |
| Status = ConvertAslNameToAmlName (LinkName, &AmlNameString); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| Status = AmlGetNameStringSize (AmlNameString, &AmlNameStringSize); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| Status = AmlCreateDataNode ( | |
| EAmlNodeDataTypeNameString, | |
| (UINT8 *)AmlNameString, | |
| AmlNameStringSize, | |
| &DataNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| // AmlNameString will be freed be fore returning. | |
| Status = AmlVarListAddTail ( | |
| (AML_NODE_HANDLE)PackageNode, | |
| (AML_NODE_HANDLE)DataNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| DataNode = NULL; | |
| } else { | |
| Status = AmlCodeGenInteger (0, &NewElementNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| Status = AmlVarListAddTail ( | |
| (AML_NODE_HANDLE)PackageNode, | |
| (AML_NODE_HANDLE)NewElementNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| } | |
| Status = AmlCodeGenInteger (SourceIndex, &NewElementNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler; | |
| } | |
| Status = AmlVarListAddTail ( | |
| (AML_NODE_HANDLE)PackageNode, | |
| (AML_NODE_HANDLE)NewElementNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler; | |
| } | |
| // Append to the list of _PRT entries. | |
| Status = AmlVarListAddTail ( | |
| (AML_NODE_HANDLE)PrtEntryList, | |
| (AML_NODE_HANDLE)PackageNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler; | |
| } | |
| // Free AmlNameString before returning as it is copied | |
| // in the call to AmlCreateDataNode(). | |
| goto exit_handler; | |
| error_handler: | |
| AmlDeleteTree ((AML_NODE_HANDLE)PackageNode); | |
| if (NewElementNode != NULL) { | |
| AmlDeleteTree ((AML_NODE_HANDLE)NewElementNode); | |
| } | |
| if (DataNode != NULL) { | |
| AmlDeleteTree ((AML_NODE_HANDLE)DataNode); | |
| } | |
| exit_handler: | |
| if (AmlNameString != NULL) { | |
| FreePool (AmlNameString); | |
| } | |
| 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; | |
| } | |
| /** AML code generation for a Method object node. | |
| AmlCodeGenMethod ("MET0", 1, TRUE, 3, ParentNode, NewObjectNode) is | |
| equivalent of the following ASL code: | |
| Method(MET0, 1, Serialized, 3) {} | |
| ACPI 6.4, s20.2.5.2 "Named Objects Encoding": | |
| DefMethod := MethodOp PkgLength NameString MethodFlags TermList | |
| MethodOp := 0x14 | |
| The ASL parameters "ReturnType" and "ParameterTypes" are not asked | |
| in this function. They are optional parameters in ASL. | |
| @param [in] NameString The new Method's name. | |
| Must be a NULL-terminated ASL NameString | |
| e.g.: "MET0", "_SB.MET0", etc. | |
| The input string is copied. | |
| @param [in] NumArgs Number of arguments. | |
| Must be 0 <= NumArgs <= 6. | |
| @param [in] IsSerialized TRUE is equivalent to Serialized. | |
| FALSE is equivalent to NotSerialized. | |
| Default is NotSerialized in ASL spec. | |
| @param [in] SyncLevel Synchronization level for the method. | |
| Must be 0 <= SyncLevel <= 15. | |
| Default is 0 in ASL. | |
| @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 | |
| AmlCodeGenMethod ( | |
| IN CONST CHAR8 *NameString, | |
| IN UINT8 NumArgs, | |
| IN BOOLEAN IsSerialized, | |
| IN UINT8 SyncLevel, | |
| IN AML_NODE_HEADER *ParentNode OPTIONAL, | |
| OUT AML_OBJECT_NODE **NewObjectNode OPTIONAL | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| UINT32 PkgLen; | |
| UINT8 Flags; | |
| AML_OBJECT_NODE *ObjectNode; | |
| AML_DATA_NODE *DataNode; | |
| CHAR8 *AmlNameString; | |
| UINT32 AmlNameStringSize; | |
| if ((NameString == NULL) || | |
| (NumArgs > 6) || | |
| (SyncLevel > 15) || | |
| ((ParentNode == NULL) && (NewObjectNode == NULL))) | |
| { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| ObjectNode = NULL; | |
| DataNode = NULL; | |
| // ACPI 6.4, s20.2.5.2 "Named Objects Encoding": | |
| // DefMethod := MethodOp PkgLength NameString MethodFlags TermList | |
| // MethodOp := 0x14 | |
| // So: | |
| // 1- Create the NameString | |
| // 2- Compute the size to write in the PkgLen | |
| // 3- Create nodes for the NameString and Method object node | |
| // 4- Set the NameString DataNode as a fixed argument | |
| // 5- Create and link the MethodFlags node | |
| // 1- Create the NameString | |
| 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; | |
| } | |
| // 2- Compute the size to write in the PkgLen | |
| // Add 1 byte (ByteData) for MethodFlags. | |
| Status = AmlComputePkgLength (AmlNameStringSize + 1, &PkgLen); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler1; | |
| } | |
| // 3- Create nodes for the NameString and Method object node | |
| Status = AmlCreateObjectNode ( | |
| AmlGetByteEncodingByOpCode (AML_METHOD_OP, 0), | |
| PkgLen, | |
| &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; | |
| } | |
| // 4- Set the NameString DataNode as a fixed argument | |
| Status = AmlSetFixedArgument ( | |
| ObjectNode, | |
| EAmlParseIndexTerm0, | |
| (AML_NODE_HEADER *)DataNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler2; | |
| } | |
| DataNode = NULL; | |
| // 5- Create and link the MethodFlags node | |
| Flags = NumArgs | | |
| (IsSerialized ? BIT3 : 0) | | |
| (SyncLevel << 4); | |
| Status = AmlCreateDataNode (EAmlNodeDataTypeUInt, &Flags, 1, &DataNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler2; | |
| } | |
| Status = AmlSetFixedArgument ( | |
| ObjectNode, | |
| EAmlParseIndexTerm1, | |
| (AML_NODE_HEADER *)DataNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler2; | |
| } | |
| // Data node is attached so set the pointer to | |
| // NULL to ensure correct error handling. | |
| DataNode = NULL; | |
| 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); | |
| } | |
| if (DataNode != NULL) { | |
| AmlDeleteTree ((AML_NODE_HEADER *)DataNode); | |
| } | |
| error_handler1: | |
| if (AmlNameString != NULL) { | |
| FreePool (AmlNameString); | |
| } | |
| return Status; | |
| } | |
| /** AML code generation for a Return object node. | |
| AmlCodeGenReturn (ReturnNode, ParentNode, NewObjectNode) is | |
| equivalent of the following ASL code: | |
| Return([Content of the ReturnNode]) | |
| The ACPI 6.3 specification, s20.2.5.3 "Type 1 Opcodes Encoding" states: | |
| DefReturn := ReturnOp ArgObject | |
| ReturnOp := 0xA4 | |
| ArgObject := TermArg => DataRefObject | |
| Thus, the ReturnNode must be evaluated as a DataRefObject. It can | |
| be a NameString referencing an object. As this CodeGen Api doesn't | |
| do semantic checking, it is strongly advised to check the AML bytecode | |
| generated by this function against an ASL compiler. | |
| The ReturnNode must be generated inside a Method body scope. | |
| @param [in] ReturnNode The object returned by the Return ASL statement. | |
| This node is deleted if an error occurs. | |
| @param [in] ParentNode If provided, set ParentNode as the parent | |
| of the node created. | |
| Must be a MethodOp node. | |
| @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 | |
| AmlCodeGenReturn ( | |
| IN AML_NODE_HEADER *ReturnNode, | |
| IN AML_NODE_HEADER *ParentNode OPTIONAL, | |
| OUT AML_OBJECT_NODE **NewObjectNode OPTIONAL | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| AML_OBJECT_NODE *ObjectNode; | |
| if ((ReturnNode == NULL) || | |
| ((ParentNode == NULL) && (NewObjectNode == NULL)) || | |
| ((ParentNode != NULL) && | |
| !AmlNodeCompareOpCode ( | |
| (AML_OBJECT_NODE *)ParentNode, | |
| AML_METHOD_OP, | |
| 0 | |
| ))) | |
| { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Status = AmlCreateObjectNode ( | |
| AmlGetByteEncodingByOpCode (AML_RETURN_OP, 0), | |
| 0, | |
| &ObjectNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler; | |
| } | |
| Status = AmlSetFixedArgument ( | |
| ObjectNode, | |
| EAmlParseIndexTerm0, | |
| ReturnNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler; | |
| } | |
| ReturnNode = NULL; | |
| Status = LinkNode ( | |
| ObjectNode, | |
| ParentNode, | |
| NewObjectNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler; | |
| } | |
| return Status; | |
| error_handler: | |
| if (ReturnNode != NULL) { | |
| AmlDeleteTree (ReturnNode); | |
| } | |
| if (ObjectNode != NULL) { | |
| AmlDeleteTree ((AML_NODE_HEADER *)ObjectNode); | |
| } | |
| return Status; | |
| } | |
| /** AML code generation for a Return object node, | |
| returning the object as an input NameString. | |
| AmlCodeGenReturn ("NAM1", ParentNode, NewObjectNode) is | |
| equivalent of the following ASL code: | |
| Return(NAM1) | |
| The ACPI 6.3 specification, s20.2.5.3 "Type 1 Opcodes Encoding" states: | |
| DefReturn := ReturnOp ArgObject | |
| ReturnOp := 0xA4 | |
| ArgObject := TermArg => DataRefObject | |
| Thus, the ReturnNode must be evaluated as a DataRefObject. It can | |
| be a NameString referencing an object. As this CodeGen Api doesn't | |
| do semantic checking, it is strongly advised to check the AML bytecode | |
| generated by this function against an ASL compiler. | |
| The ReturnNode must be generated inside a Method body scope. | |
| @param [in] NameString The object referenced by this NameString | |
| is returned by the Return ASL statement. | |
| Must be a NULL-terminated ASL NameString | |
| e.g.: "NAM1", "_SB.NAM1", etc. | |
| The input string is copied. | |
| @param [in] ParentNode If provided, set ParentNode as the parent | |
| of the node created. | |
| Must be a MethodOp node. | |
| @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 | |
| AmlCodeGenReturnNameString ( | |
| IN CONST CHAR8 *NameString, | |
| IN AML_NODE_HEADER *ParentNode OPTIONAL, | |
| OUT AML_OBJECT_NODE **NewObjectNode OPTIONAL | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| AML_DATA_NODE *DataNode; | |
| CHAR8 *AmlNameString; | |
| UINT32 AmlNameStringSize; | |
| DataNode = NULL; | |
| Status = ConvertAslNameToAmlName (NameString, &AmlNameString); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| return Status; | |
| } | |
| Status = AmlGetNameStringSize (AmlNameString, &AmlNameStringSize); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto exit_handler; | |
| } | |
| Status = AmlCreateDataNode ( | |
| EAmlNodeDataTypeNameString, | |
| (UINT8 *)AmlNameString, | |
| AmlNameStringSize, | |
| &DataNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto exit_handler; | |
| } | |
| // AmlCodeGenReturn() deletes DataNode if error. | |
| Status = AmlCodeGenReturn ( | |
| (AML_NODE_HEADER *)DataNode, | |
| ParentNode, | |
| NewObjectNode | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| exit_handler: | |
| if (AmlNameString != NULL) { | |
| FreePool (AmlNameString); | |
| } | |
| return Status; | |
| } | |
| /** AML code generation for a Return object node, | |
| returning an Integer. | |
| AmlCodeGenReturn (0), ParentNode, NewObjectNode) is | |
| equivalent of the following ASL code: | |
| Return (0) | |
| The ACPI 6.3 specification, 20.2.8 "Statement Opcodes Encoding" states: | |
| DefReturn := ReturnOp ArgObject | |
| ReturnOp := 0xA4 | |
| ArgObject := TermArg => DataRefObject | |
| Thus, the ReturnNode must be evaluated as a DataRefObject. | |
| The ReturnNode must be generated inside a Method body scope. | |
| @param [in] Integer The integer is returned by the Return | |
| ASL statement. | |
| @param [in] ParentNode If provided, set ParentNode as the parent | |
| of the node created. | |
| Must be a MethodOp node. | |
| @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 | |
| AmlCodeGenReturnInteger ( | |
| IN UINT64 Integer, | |
| IN AML_NODE_HEADER *ParentNode OPTIONAL, | |
| OUT AML_OBJECT_NODE **NewObjectNode OPTIONAL | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| AML_OBJECT_NODE *IntNode; | |
| IntNode = NULL; | |
| Status = AmlCodeGenInteger (Integer, &IntNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| return Status; | |
| } | |
| // AmlCodeGenReturn() deletes DataNode if error. | |
| Status = AmlCodeGenReturn ( | |
| (AML_NODE_HEADER *)IntNode, | |
| ParentNode, | |
| NewObjectNode | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| return Status; | |
| } | |
| /** AML code generation for a method returning a NameString. | |
| AmlCodeGenMethodRetNameString ( | |
| "MET0", "_CRS", 1, TRUE, 3, ParentNode, NewObjectNode | |
| ); | |
| is equivalent of the following ASL code: | |
| Method(MET0, 1, Serialized, 3) { | |
| Return (_CRS) | |
| } | |
| The ASL parameters "ReturnType" and "ParameterTypes" are not asked | |
| in this function. They are optional parameters in ASL. | |
| @param [in] MethodNameString The new Method's name. | |
| Must be a NULL-terminated ASL NameString | |
| e.g.: "MET0", "_SB.MET0", etc. | |
| The input string is copied. | |
| @param [in] ReturnedNameString The name of the object returned by the | |
| method. Optional parameter, can be: | |
| - NULL (ignored). | |
| - A NULL-terminated ASL NameString. | |
| e.g.: "MET0", "_SB.MET0", etc. | |
| The input string is copied. | |
| @param [in] NumArgs Number of arguments. | |
| Must be 0 <= NumArgs <= 6. | |
| @param [in] IsSerialized TRUE is equivalent to Serialized. | |
| FALSE is equivalent to NotSerialized. | |
| Default is NotSerialized in ASL spec. | |
| @param [in] SyncLevel Synchronization level for the method. | |
| Must be 0 <= SyncLevel <= 15. | |
| Default is 0 in ASL. | |
| @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 | |
| AmlCodeGenMethodRetNameString ( | |
| IN CONST CHAR8 *MethodNameString, | |
| IN CONST CHAR8 *ReturnedNameString OPTIONAL, | |
| IN UINT8 NumArgs, | |
| IN BOOLEAN IsSerialized, | |
| IN UINT8 SyncLevel, | |
| IN AML_NODE_HANDLE ParentNode OPTIONAL, | |
| OUT AML_OBJECT_NODE_HANDLE *NewObjectNode OPTIONAL | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| AML_OBJECT_NODE_HANDLE MethodNode; | |
| if ((MethodNameString == NULL) || | |
| ((ParentNode == NULL) && (NewObjectNode == NULL))) | |
| { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // Create a Method named MethodNameString. | |
| Status = AmlCodeGenMethod ( | |
| MethodNameString, | |
| NumArgs, | |
| IsSerialized, | |
| SyncLevel, | |
| NULL, | |
| &MethodNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| return Status; | |
| } | |
| // Return ReturnedNameString if provided. | |
| if (ReturnedNameString != NULL) { | |
| Status = AmlCodeGenReturnNameString ( | |
| ReturnedNameString, | |
| (AML_NODE_HANDLE)MethodNode, | |
| NULL | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler; | |
| } | |
| } | |
| Status = LinkNode ( | |
| MethodNode, | |
| ParentNode, | |
| NewObjectNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler; | |
| } | |
| return Status; | |
| error_handler: | |
| if (MethodNode != NULL) { | |
| AmlDeleteTree ((AML_NODE_HANDLE)MethodNode); | |
| } | |
| return Status; | |
| } | |
| /** AML code generation for a method returning an Integer. | |
| AmlCodeGenMethodRetInteger ( | |
| "_CBA", 0, 1, TRUE, 3, ParentNode, NewObjectNode | |
| ); | |
| is equivalent of the following ASL code: | |
| Method(_CBA, 1, Serialized, 3) { | |
| Return (0) | |
| } | |
| The ASL parameters "ReturnType" and "ParameterTypes" are not asked | |
| in this function. They are optional parameters in ASL. | |
| @param [in] MethodNameString The new Method's name. | |
| Must be a NULL-terminated ASL NameString | |
| e.g.: "MET0", "_SB.MET0", etc. | |
| The input string is copied. | |
| @param [in] ReturnedInteger The value of the integer returned by the | |
| method. | |
| @param [in] NumArgs Number of arguments. | |
| Must be 0 <= NumArgs <= 6. | |
| @param [in] IsSerialized TRUE is equivalent to Serialized. | |
| FALSE is equivalent to NotSerialized. | |
| Default is NotSerialized in ASL spec. | |
| @param [in] SyncLevel Synchronization level for the method. | |
| Must be 0 <= SyncLevel <= 15. | |
| Default is 0 in ASL. | |
| @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 | |
| AmlCodeGenMethodRetInteger ( | |
| IN CONST CHAR8 *MethodNameString, | |
| IN UINT64 ReturnedInteger, | |
| IN UINT8 NumArgs, | |
| IN BOOLEAN IsSerialized, | |
| IN UINT8 SyncLevel, | |
| IN AML_NODE_HANDLE ParentNode OPTIONAL, | |
| OUT AML_OBJECT_NODE_HANDLE *NewObjectNode OPTIONAL | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| AML_OBJECT_NODE_HANDLE MethodNode; | |
| if ((MethodNameString == NULL) || | |
| ((ParentNode == NULL) && (NewObjectNode == NULL))) | |
| { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // Create a Method named MethodNameString. | |
| Status = AmlCodeGenMethod ( | |
| MethodNameString, | |
| NumArgs, | |
| IsSerialized, | |
| SyncLevel, | |
| NULL, | |
| &MethodNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| return Status; | |
| } | |
| Status = AmlCodeGenReturnInteger ( | |
| ReturnedInteger, | |
| (AML_NODE_HANDLE)MethodNode, | |
| NULL | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler; | |
| } | |
| Status = LinkNode ( | |
| MethodNode, | |
| ParentNode, | |
| NewObjectNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler; | |
| } | |
| return Status; | |
| error_handler: | |
| if (MethodNode != NULL) { | |
| AmlDeleteTree ((AML_NODE_HANDLE)MethodNode); | |
| } | |
| return Status; | |
| } | |
| /** Create a _LPI name. | |
| AmlCreateLpiNode ("_LPI", 0, 1, ParentNode, &LpiNode) is | |
| equivalent of the following ASL code: | |
| Name (_LPI, Package ( | |
| 0, // Revision | |
| 1, // LevelId | |
| 0 // Count | |
| )) | |
| This function doesn't define any LPI state. As shown above, the count | |
| of _LPI state is set to 0. | |
| The AmlAddLpiState () function allows to add LPI states. | |
| Cf ACPI 6.3 specification, s8.4.4 "Lower Power Idle States". | |
| @param [in] LpiNameString The new LPI 's object name. | |
| Must be a NULL-terminated ASL NameString | |
| e.g.: "_LPI", "DEV0.PLPI", etc. | |
| The input string is copied. | |
| @param [in] Revision Revision number of the _LPI states. | |
| @param [in] LevelId A platform defined number that identifies the | |
| level of hierarchy of the processor node to | |
| which the LPI states apply. | |
| @param [in] ParentNode If provided, set ParentNode as the parent | |
| of the node created. | |
| @param [out] NewLpiNode If success, contains the created node. | |
| @retval EFI_SUCCESS The function completed successfully. | |
| @retval EFI_INVALID_PARAMETER Invalid parameter. | |
| @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| AmlCreateLpiNode ( | |
| IN CONST CHAR8 *LpiNameString, | |
| IN UINT16 Revision, | |
| IN UINT64 LevelId, | |
| IN AML_NODE_HANDLE ParentNode OPTIONAL, | |
| OUT AML_OBJECT_NODE_HANDLE *NewLpiNode OPTIONAL | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| AML_OBJECT_NODE_HANDLE PackageNode; | |
| AML_OBJECT_NODE_HANDLE IntegerNode; | |
| if ((LpiNameString == NULL) || | |
| ((ParentNode == NULL) && (NewLpiNode == NULL))) | |
| { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| IntegerNode = NULL; | |
| Status = AmlCodeGenPackage (&PackageNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| return Status; | |
| } | |
| // Create and attach Revision | |
| Status = AmlCodeGenInteger (Revision, &IntegerNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| IntegerNode = NULL; | |
| goto error_handler; | |
| } | |
| Status = AmlVarListAddTail ( | |
| (AML_NODE_HANDLE)PackageNode, | |
| (AML_NODE_HANDLE)IntegerNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler; | |
| } | |
| IntegerNode = NULL; | |
| // Create and attach LevelId | |
| Status = AmlCodeGenInteger (LevelId, &IntegerNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| IntegerNode = NULL; | |
| goto error_handler; | |
| } | |
| Status = AmlVarListAddTail ( | |
| (AML_NODE_HANDLE)PackageNode, | |
| (AML_NODE_HANDLE)IntegerNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler; | |
| } | |
| IntegerNode = NULL; | |
| // Create and attach Count. No LPI state is added, so 0. | |
| Status = AmlCodeGenInteger (0, &IntegerNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| IntegerNode = NULL; | |
| goto error_handler; | |
| } | |
| Status = AmlVarListAddTail ( | |
| (AML_NODE_HANDLE)PackageNode, | |
| (AML_NODE_HANDLE)IntegerNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler; | |
| } | |
| IntegerNode = NULL; | |
| Status = AmlCodeGenName (LpiNameString, PackageNode, ParentNode, NewLpiNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler; | |
| } | |
| return Status; | |
| error_handler: | |
| AmlDeleteTree ((AML_NODE_HANDLE)PackageNode); | |
| if (IntegerNode != NULL) { | |
| AmlDeleteTree ((AML_NODE_HANDLE)IntegerNode); | |
| } | |
| return Status; | |
| } | |
| /** Add an _LPI state to a LPI node created using AmlCreateLpiNode. | |
| AmlAddLpiState increments the Count of LPI states in the LPI node by one, | |
| and adds the following package: | |
| Package() { | |
| MinResidency, | |
| WorstCaseWakeLatency, | |
| Flags, | |
| ArchFlags, | |
| ResCntFreq, | |
| EnableParentState, | |
| (GenericRegisterDescriptor != NULL) ? // Entry method. If a | |
| ResourceTemplate(GenericRegisterDescriptor) : // Register is given, | |
| Integer, // use it. Use the | |
| // Integer otherwise. | |
| ResourceTemplate() { // NULL Residency Counter | |
| Register (SystemMemory, 0, 0, 0, 0) | |
| }, | |
| ResourceTemplate() { // NULL Usage Counter | |
| Register (SystemMemory, 0, 0, 0, 0) | |
| }, | |
| "" // NULL State Name | |
| }, | |
| Cf ACPI 6.3 specification, s8.4.4 "Lower Power Idle States". | |
| @param [in] MinResidency Minimum Residency. | |
| @param [in] WorstCaseWakeLatency Worst case wake-up latency. | |
| @param [in] Flags Flags. | |
| @param [in] ArchFlags Architectural flags. | |
| @param [in] ResCntFreq Residency Counter Frequency. | |
| @param [in] EnableParentState Enabled Parent State. | |
| @param [in] GenericRegisterDescriptor Entry Method. | |
| If not NULL, use this Register to | |
| describe the entry method address. | |
| @param [in] Integer Entry Method. | |
| If GenericRegisterDescriptor is NULL, | |
| take this value. | |
| @param [in] ResidencyCounterRegister If not NULL, use it to populate the | |
| residency counter register. | |
| @param [in] UsageCounterRegister If not NULL, use it to populate the | |
| usage counter register. | |
| @param [in] StateName If not NULL, use it to populate the | |
| state name. | |
| @param [in] LpiNode Lpi node created with the function | |
| AmlCreateLpiNode to which the new LPI | |
| state is appended. | |
| @retval EFI_SUCCESS The function completed successfully. | |
| @retval EFI_INVALID_PARAMETER Invalid parameter. | |
| @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| AmlAddLpiState ( | |
| IN UINT32 MinResidency, | |
| IN UINT32 WorstCaseWakeLatency, | |
| IN UINT32 Flags, | |
| IN UINT32 ArchFlags, | |
| IN UINT32 ResCntFreq, | |
| IN UINT32 EnableParentState, | |
| IN EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE *GenericRegisterDescriptor OPTIONAL, | |
| IN UINT64 Integer OPTIONAL, | |
| IN EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE *ResidencyCounterRegister OPTIONAL, | |
| IN EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE *UsageCounterRegister OPTIONAL, | |
| IN CHAR8 *StateName OPTIONAL, | |
| IN AML_OBJECT_NODE_HANDLE LpiNode | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| AML_DATA_NODE_HANDLE RdNode; | |
| AML_OBJECT_NODE_HANDLE PackageNode; | |
| AML_OBJECT_NODE_HANDLE IntegerNode; | |
| AML_OBJECT_NODE_HANDLE StringNode; | |
| AML_OBJECT_NODE_HANDLE NewLpiPackageNode; | |
| AML_OBJECT_NODE_HANDLE ResourceTemplateNode; | |
| UINT32 Index; | |
| AML_OBJECT_NODE_HANDLE CountNode; | |
| UINT64 Count; | |
| if ((LpiNode == NULL) || | |
| (AmlGetNodeType ((AML_NODE_HANDLE)LpiNode) != EAmlNodeObject) || | |
| (!AmlNodeHasOpCode (LpiNode, AML_NAME_OP, 0))) | |
| { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| RdNode = 0; | |
| StringNode = NULL; | |
| IntegerNode = NULL; | |
| ResourceTemplateNode = NULL; | |
| // AmlCreateLpiNode () created a LPI container such as: | |
| // Name (_LPI, Package ( | |
| // 0, // Revision | |
| // 1, // LevelId | |
| // 0 // Count | |
| // )) | |
| // Get the LPI container, a PackageOp object node stored as the 2nd fixed | |
| // argument (i.e. index 1) of LpiNode. | |
| PackageNode = (AML_OBJECT_NODE_HANDLE)AmlGetFixedArgument ( | |
| LpiNode, | |
| EAmlParseIndexTerm1 | |
| ); | |
| if ((PackageNode == NULL) || | |
| (AmlGetNodeType ((AML_NODE_HANDLE)PackageNode) != EAmlNodeObject) || | |
| (!AmlNodeHasOpCode (PackageNode, AML_PACKAGE_OP, 0))) | |
| { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| CountNode = NULL; | |
| // The third variable argument is the LPI Count node. | |
| for (Index = 0; Index < 3; Index++) { | |
| CountNode = (AML_OBJECT_NODE_HANDLE)AmlGetNextVariableArgument ( | |
| (AML_NODE_HANDLE)PackageNode, | |
| (AML_NODE_HANDLE)CountNode | |
| ); | |
| if (CountNode == NULL) { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| } | |
| Status = AmlNodeGetIntegerValue (CountNode, &Count); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| return Status; | |
| } | |
| Status = AmlUpdateInteger (CountNode, Count + 1); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| return Status; | |
| } | |
| Status = AmlCodeGenPackage (&NewLpiPackageNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| return Status; | |
| } | |
| // MinResidency | |
| Status = AmlCodeGenInteger (MinResidency, &IntegerNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| IntegerNode = NULL; | |
| goto error_handler; | |
| } | |
| Status = AmlVarListAddTail ( | |
| (AML_NODE_HANDLE)NewLpiPackageNode, | |
| (AML_NODE_HANDLE)IntegerNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler; | |
| } | |
| IntegerNode = NULL; | |
| // WorstCaseWakeLatency | |
| Status = AmlCodeGenInteger (WorstCaseWakeLatency, &IntegerNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| IntegerNode = NULL; | |
| goto error_handler; | |
| } | |
| Status = AmlVarListAddTail ( | |
| (AML_NODE_HANDLE)NewLpiPackageNode, | |
| (AML_NODE_HANDLE)IntegerNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler; | |
| } | |
| IntegerNode = NULL; | |
| // Flags | |
| Status = AmlCodeGenInteger (Flags, &IntegerNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| IntegerNode = NULL; | |
| goto error_handler; | |
| } | |
| Status = AmlVarListAddTail ( | |
| (AML_NODE_HANDLE)NewLpiPackageNode, | |
| (AML_NODE_HANDLE)IntegerNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler; | |
| } | |
| IntegerNode = NULL; | |
| // ArchFlags | |
| Status = AmlCodeGenInteger (ArchFlags, &IntegerNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| IntegerNode = NULL; | |
| goto error_handler; | |
| } | |
| Status = AmlVarListAddTail ( | |
| (AML_NODE_HANDLE)NewLpiPackageNode, | |
| (AML_NODE_HANDLE)IntegerNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler; | |
| } | |
| IntegerNode = NULL; | |
| // ResCntFreq | |
| Status = AmlCodeGenInteger (ResCntFreq, &IntegerNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| IntegerNode = NULL; | |
| goto error_handler; | |
| } | |
| Status = AmlVarListAddTail ( | |
| (AML_NODE_HANDLE)NewLpiPackageNode, | |
| (AML_NODE_HANDLE)IntegerNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler; | |
| } | |
| IntegerNode = NULL; | |
| // EnableParentState | |
| Status = AmlCodeGenInteger (EnableParentState, &IntegerNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| IntegerNode = NULL; | |
| goto error_handler; | |
| } | |
| Status = AmlVarListAddTail ( | |
| (AML_NODE_HANDLE)NewLpiPackageNode, | |
| (AML_NODE_HANDLE)IntegerNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler; | |
| } | |
| IntegerNode = NULL; | |
| // Entry Method | |
| if (GenericRegisterDescriptor != NULL) { | |
| // Entry Method: As a Register resource data | |
| Status = AmlCodeGenResourceTemplate (&ResourceTemplateNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| ResourceTemplateNode = NULL; | |
| goto error_handler; | |
| } | |
| Status = AmlCodeGenRdRegister ( | |
| GenericRegisterDescriptor->AddressSpaceId, | |
| GenericRegisterDescriptor->RegisterBitWidth, | |
| GenericRegisterDescriptor->RegisterBitOffset, | |
| GenericRegisterDescriptor->Address, | |
| GenericRegisterDescriptor->AccessSize, | |
| NULL, | |
| &RdNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| RdNode = NULL; | |
| goto error_handler; | |
| } | |
| Status = AmlAppendRdNode (ResourceTemplateNode, RdNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler; | |
| } | |
| RdNode = NULL; | |
| Status = AmlVarListAddTail ( | |
| (AML_NODE_HANDLE)NewLpiPackageNode, | |
| (AML_NODE_HANDLE)ResourceTemplateNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler; | |
| } | |
| ResourceTemplateNode = NULL; | |
| } else { | |
| // Entry Method: As an integer | |
| Status = AmlCodeGenInteger (Integer, &IntegerNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| IntegerNode = NULL; | |
| goto error_handler; | |
| } | |
| Status = AmlVarListAddTail ( | |
| (AML_NODE_HANDLE)NewLpiPackageNode, | |
| (AML_NODE_HANDLE)IntegerNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler; | |
| } | |
| IntegerNode = NULL; | |
| } | |
| // Residency Counter Register. | |
| Status = AmlCodeGenResourceTemplate (&ResourceTemplateNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| ResourceTemplateNode = NULL; | |
| goto error_handler; | |
| } | |
| if (ResidencyCounterRegister != NULL) { | |
| Status = AmlCodeGenRdRegister ( | |
| ResidencyCounterRegister->AddressSpaceId, | |
| ResidencyCounterRegister->RegisterBitWidth, | |
| ResidencyCounterRegister->RegisterBitOffset, | |
| ResidencyCounterRegister->Address, | |
| ResidencyCounterRegister->AccessSize, | |
| NULL, | |
| &RdNode | |
| ); | |
| } else { | |
| Status = AmlCodeGenRdRegister ( | |
| EFI_ACPI_6_4_SYSTEM_MEMORY, | |
| 0, | |
| 0, | |
| 0, | |
| 0, | |
| NULL, | |
| &RdNode | |
| ); | |
| } | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| RdNode = NULL; | |
| goto error_handler; | |
| } | |
| Status = AmlAppendRdNode (ResourceTemplateNode, RdNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler; | |
| } | |
| RdNode = NULL; | |
| Status = AmlVarListAddTail ( | |
| (AML_NODE_HANDLE)NewLpiPackageNode, | |
| (AML_NODE_HANDLE)ResourceTemplateNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler; | |
| } | |
| ResourceTemplateNode = NULL; | |
| // Usage Counter Register. | |
| Status = AmlCodeGenResourceTemplate (&ResourceTemplateNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| ResourceTemplateNode = NULL; | |
| goto error_handler; | |
| } | |
| if (UsageCounterRegister != NULL) { | |
| Status = AmlCodeGenRdRegister ( | |
| UsageCounterRegister->AddressSpaceId, | |
| UsageCounterRegister->RegisterBitWidth, | |
| UsageCounterRegister->RegisterBitOffset, | |
| UsageCounterRegister->Address, | |
| UsageCounterRegister->AccessSize, | |
| NULL, | |
| &RdNode | |
| ); | |
| } else { | |
| Status = AmlCodeGenRdRegister ( | |
| EFI_ACPI_6_4_SYSTEM_MEMORY, | |
| 0, | |
| 0, | |
| 0, | |
| 0, | |
| NULL, | |
| &RdNode | |
| ); | |
| } | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| RdNode = NULL; | |
| goto error_handler; | |
| } | |
| Status = AmlAppendRdNode (ResourceTemplateNode, RdNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler; | |
| } | |
| RdNode = NULL; | |
| Status = AmlVarListAddTail ( | |
| (AML_NODE_HANDLE)NewLpiPackageNode, | |
| (AML_NODE_HANDLE)ResourceTemplateNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler; | |
| } | |
| ResourceTemplateNode = NULL; | |
| // State name. | |
| if (UsageCounterRegister != NULL) { | |
| Status = AmlCodeGenString (StateName, &StringNode); | |
| } else { | |
| Status = AmlCodeGenString ("", &StringNode); | |
| } | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| StringNode = NULL; | |
| goto error_handler; | |
| } | |
| Status = AmlVarListAddTail ( | |
| (AML_NODE_HANDLE)NewLpiPackageNode, | |
| (AML_NODE_HANDLE)StringNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler; | |
| } | |
| StringNode = NULL; | |
| // Add the new LPI state to the LpiNode. | |
| Status = AmlVarListAddTail ( | |
| (AML_NODE_HANDLE)PackageNode, | |
| (AML_NODE_HANDLE)NewLpiPackageNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler; | |
| } | |
| return Status; | |
| error_handler: | |
| if (RdNode != NULL) { | |
| AmlDeleteTree ((AML_NODE_HANDLE)RdNode); | |
| } | |
| if (NewLpiPackageNode != NULL) { | |
| AmlDeleteTree ((AML_NODE_HANDLE)NewLpiPackageNode); | |
| } | |
| if (StringNode != NULL) { | |
| AmlDeleteTree ((AML_NODE_HANDLE)StringNode); | |
| } | |
| if (IntegerNode != NULL) { | |
| AmlDeleteTree ((AML_NODE_HANDLE)IntegerNode); | |
| } | |
| if (ResourceTemplateNode != NULL) { | |
| AmlDeleteTree ((AML_NODE_HANDLE)ResourceTemplateNode); | |
| } | |
| return Status; | |
| } | |
| /** AML code generation for a _DSD device data object. | |
| AmlAddDeviceDataDescriptorPackage (Uuid, DsdNode, PackageNode) is | |
| equivalent of the following ASL code: | |
| ToUUID(Uuid), | |
| Package () {} | |
| Cf ACPI 6.4 specification, s6.2.5 "_DSD (Device Specific Data)". | |
| _DSD (Device Specific Data) Implementation Guide | |
| https://github.com/UEFI/DSD-Guide | |
| Per s3. "'Well-Known _DSD UUIDs and Data Structure Formats'" | |
| If creating a Device Properties data then UUID daffd814-6eba-4d8c-8a91-bc9bbf4aa301 should be used. | |
| @param [in] Uuid The Uuid of the descriptor to be created | |
| @param [in] DsdNode Node of the DSD Package. | |
| @param [out] PackageNode If success, contains the created package node. | |
| @retval EFI_SUCCESS Success. | |
| @retval EFI_INVALID_PARAMETER Invalid parameter. | |
| @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| AmlAddDeviceDataDescriptorPackage ( | |
| IN CONST EFI_GUID *Uuid, | |
| IN AML_OBJECT_NODE_HANDLE DsdNode, | |
| OUT AML_OBJECT_NODE_HANDLE *PackageNode | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| AML_OBJECT_NODE *UuidNode; | |
| AML_DATA_NODE *UuidDataNode; | |
| AML_OBJECT_NODE_HANDLE DsdEntryList; | |
| if ((Uuid == NULL) || | |
| (PackageNode == NULL) || | |
| (AmlGetNodeType ((AML_NODE_HANDLE)DsdNode) != EAmlNodeObject) || | |
| (!AmlNodeHasOpCode (DsdNode, AML_NAME_OP, 0)) || | |
| !AmlNameOpCompareName (DsdNode, "_DSD")) | |
| { | |
| ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // Get the Package object node of the _DSD node, | |
| // which is the 2nd fixed argument (i.e. index 1). | |
| DsdEntryList = (AML_OBJECT_NODE_HANDLE)AmlGetFixedArgument ( | |
| DsdNode, | |
| EAmlParseIndexTerm1 | |
| ); | |
| if ((DsdEntryList == NULL) || | |
| (AmlGetNodeType ((AML_NODE_HANDLE)DsdEntryList) != EAmlNodeObject) || | |
| (!AmlNodeHasOpCode (DsdEntryList, AML_PACKAGE_OP, 0))) | |
| { | |
| ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| *PackageNode = NULL; | |
| UuidDataNode = NULL; | |
| Status = AmlCodeGenBuffer (NULL, 0, &UuidNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| return Status; | |
| } | |
| Status = AmlCreateDataNode ( | |
| EAmlNodeDataTypeRaw, | |
| (CONST UINT8 *)Uuid, | |
| sizeof (EFI_GUID), | |
| &UuidDataNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| Status = AmlVarListAddTail ( | |
| (AML_NODE_HEADER *)UuidNode, | |
| (AML_NODE_HEADER *)UuidDataNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| UuidDataNode = NULL; | |
| // Append to the list of _DSD entries. | |
| Status = AmlVarListAddTail ( | |
| (AML_NODE_HANDLE)DsdEntryList, | |
| (AML_NODE_HANDLE)UuidNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| Status = AmlCodeGenPackage (PackageNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler_detach; | |
| } | |
| // Append to the list of _DSD entries. | |
| Status = AmlVarListAddTail ( | |
| (AML_NODE_HANDLE)DsdEntryList, | |
| (AML_NODE_HANDLE)*PackageNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler_detach; | |
| } | |
| return Status; | |
| error_handler_detach: | |
| if (UuidNode != NULL) { | |
| AmlDetachNode ((AML_NODE_HANDLE)UuidNode); | |
| } | |
| error_handler: | |
| if (UuidNode != NULL) { | |
| AmlDeleteTree ((AML_NODE_HANDLE)UuidNode); | |
| } | |
| if (*PackageNode != NULL) { | |
| AmlDeleteTree ((AML_NODE_HANDLE)*PackageNode); | |
| *PackageNode = NULL; | |
| } | |
| if (UuidDataNode != NULL) { | |
| AmlDeleteTree ((AML_NODE_HANDLE)UuidDataNode); | |
| } | |
| return Status; | |
| } | |
| /** AML code generation to add a package with a name and value, | |
| to a parent package. | |
| This is useful to build the _DSD package but can be used in other cases. | |
| AmlAddNameIntegerPackage ("Name", Value, PackageNode) is | |
| equivalent of the following ASL code: | |
| Package (2) {"Name", Value} | |
| Cf ACPI 6.4 specification, s6.2.5 "_DSD (Device Specific Data)". | |
| @param [in] Name String to place in first entry of package | |
| @param [in] Value Integer to place in second entry of package | |
| @param [in] PackageNode Package to add new sub package to. | |
| @retval EFI_SUCCESS Success. | |
| @retval EFI_INVALID_PARAMETER Invalid parameter. | |
| @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| AmlAddNameIntegerPackage ( | |
| IN CHAR8 *Name, | |
| IN UINT64 Value, | |
| IN AML_OBJECT_NODE_HANDLE PackageNode | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| AML_OBJECT_NODE *NameNode; | |
| AML_OBJECT_NODE *ValueNode; | |
| AML_OBJECT_NODE *NewPackageNode; | |
| if ((Name == NULL) || | |
| (AmlGetNodeType ((AML_NODE_HANDLE)PackageNode) != EAmlNodeObject) || | |
| (!AmlNodeHasOpCode (PackageNode, AML_PACKAGE_OP, 0))) | |
| { | |
| ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| NameNode = NULL; | |
| ValueNode = NULL; | |
| // The new package entry. | |
| Status = AmlCodeGenPackage (&NewPackageNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| return Status; | |
| } | |
| Status = AmlCodeGenString (Name, &NameNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| Status = AmlVarListAddTail ( | |
| (AML_NODE_HANDLE)NewPackageNode, | |
| (AML_NODE_HANDLE)NameNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| NameNode = NULL; | |
| Status = AmlCodeGenInteger (Value, &ValueNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| Status = AmlVarListAddTail ( | |
| (AML_NODE_HANDLE)NewPackageNode, | |
| (AML_NODE_HANDLE)ValueNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| ValueNode = NULL; | |
| Status = AmlVarListAddTail ( | |
| (AML_NODE_HANDLE)PackageNode, | |
| (AML_NODE_HANDLE)NewPackageNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| return Status; | |
| error_handler: | |
| if (NewPackageNode != NULL) { | |
| AmlDeleteTree ((AML_NODE_HANDLE)NewPackageNode); | |
| } | |
| if (NameNode != NULL) { | |
| AmlDeleteTree ((AML_NODE_HANDLE)NameNode); | |
| } | |
| if (ValueNode != NULL) { | |
| AmlDeleteTree ((AML_NODE_HANDLE)ValueNode); | |
| } | |
| return Status; | |
| } | |
| /** Adds a register to the package | |
| @ingroup CodeGenApis | |
| @param [in] Register If provided, register that will be added to package. | |
| otherwise NULL register will be added | |
| @param [in] PackageNode Package to add value to | |
| @retval EFI_SUCCESS The function completed successfully. | |
| @retval EFI_INVALID_PARAMETER Invalid parameter. | |
| @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. | |
| **/ | |
| STATIC | |
| EFI_STATUS | |
| EFIAPI | |
| AmlAddRegisterToPackage ( | |
| IN EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE *Register OPTIONAL, | |
| IN AML_OBJECT_NODE_HANDLE PackageNode | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| AML_DATA_NODE_HANDLE RdNode; | |
| AML_OBJECT_NODE_HANDLE ResourceTemplateNode; | |
| RdNode = NULL; | |
| Status = AmlCodeGenResourceTemplate (&ResourceTemplateNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| return Status; | |
| } | |
| if (Register != NULL) { | |
| Status = AmlCodeGenRdRegister ( | |
| Register->AddressSpaceId, | |
| Register->RegisterBitWidth, | |
| Register->RegisterBitOffset, | |
| Register->Address, | |
| Register->AccessSize, | |
| NULL, | |
| &RdNode | |
| ); | |
| } else { | |
| Status = AmlCodeGenRdRegister ( | |
| EFI_ACPI_6_4_SYSTEM_MEMORY, | |
| 0, | |
| 0, | |
| 0, | |
| 0, | |
| NULL, | |
| &RdNode | |
| ); | |
| } | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| Status = AmlAppendRdNode (ResourceTemplateNode, RdNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| RdNode = NULL; | |
| Status = AmlVarListAddTail ( | |
| (AML_NODE_HANDLE)PackageNode, | |
| (AML_NODE_HANDLE)ResourceTemplateNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| return Status; | |
| error_handler: | |
| if (RdNode != NULL) { | |
| AmlDeleteTree ((AML_NODE_HANDLE)RdNode); | |
| } | |
| if (ResourceTemplateNode != NULL) { | |
| AmlDeleteTree ((AML_NODE_HANDLE)ResourceTemplateNode); | |
| } | |
| return Status; | |
| } | |
| /** Utility function to check if generic address points to NULL | |
| @param [in] Address Pointer to the Generic address | |
| @retval TRUE Address is system memory with an Address of 0. | |
| @retval FALSE Address does not point to NULL. | |
| **/ | |
| STATIC | |
| BOOLEAN | |
| EFIAPI | |
| IsNullGenericAddress ( | |
| IN EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE *Address | |
| ) | |
| { | |
| if ((Address == NULL) || | |
| ((Address->AddressSpaceId == EFI_ACPI_6_4_SYSTEM_MEMORY) && | |
| (Address->Address == 0x0))) | |
| { | |
| return TRUE; | |
| } | |
| return FALSE; | |
| } | |
| /** Adds an integer or register to the package | |
| @ingroup CodeGenApis | |
| @param [in] Register If provided, register that will be added to package | |
| @param [in] Integer If Register is NULL, integer that will be added to the package | |
| @param [in] PackageNode Package to add value to | |
| @retval EFI_SUCCESS The function completed successfully. | |
| @retval EFI_INVALID_PARAMETER Invalid parameter. | |
| @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. | |
| **/ | |
| STATIC | |
| EFI_STATUS | |
| EFIAPI | |
| AmlAddRegisterOrIntegerToPackage ( | |
| IN EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE *Register OPTIONAL, | |
| IN UINT32 Integer, | |
| IN AML_OBJECT_NODE_HANDLE PackageNode | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| AML_OBJECT_NODE_HANDLE IntegerNode; | |
| IntegerNode = NULL; | |
| if (!IsNullGenericAddress (Register)) { | |
| Status = AmlAddRegisterToPackage (Register, PackageNode); | |
| } else { | |
| Status = AmlCodeGenInteger (Integer, &IntegerNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| return Status; | |
| } | |
| Status = AmlVarListAddTail ( | |
| (AML_NODE_HANDLE)PackageNode, | |
| (AML_NODE_HANDLE)IntegerNode | |
| ); | |
| } | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| if (IntegerNode != NULL) { | |
| AmlDeleteTree ((AML_NODE_HANDLE)IntegerNode); | |
| } | |
| } | |
| return Status; | |
| } | |
| /** Create a _CPC node. | |
| Creates and optionally adds the following node | |
| Name(_CPC, Package() | |
| { | |
| NumEntries, // Integer | |
| Revision, // Integer | |
| HighestPerformance, // Integer or Buffer (Resource Descriptor) | |
| NominalPerformance, // Integer or Buffer (Resource Descriptor) | |
| LowestNonlinearPerformance, // Integer or Buffer (Resource Descriptor) | |
| LowestPerformance, // Integer or Buffer (Resource Descriptor) | |
| GuaranteedPerformanceRegister, // Buffer (Resource Descriptor) | |
| DesiredPerformanceRegister , // Buffer (Resource Descriptor) | |
| MinimumPerformanceRegister , // Buffer (Resource Descriptor) | |
| MaximumPerformanceRegister , // Buffer (Resource Descriptor) | |
| PerformanceReductionToleranceRegister, // Buffer (Resource Descriptor) | |
| TimeWindowRegister, // Buffer (Resource Descriptor) | |
| CounterWraparoundTime, // Integer or Buffer (Resource Descriptor) | |
| ReferencePerformanceCounterRegister, // Buffer (Resource Descriptor) | |
| DeliveredPerformanceCounterRegister, // Buffer (Resource Descriptor) | |
| PerformanceLimitedRegister, // Buffer (Resource Descriptor) | |
| CPPCEnableRegister // Buffer (Resource Descriptor) | |
| AutonomousSelectionEnable, // Integer or Buffer (Resource Descriptor) | |
| AutonomousActivityWindowRegister, // Buffer (Resource Descriptor) | |
| EnergyPerformancePreferenceRegister, // Buffer (Resource Descriptor) | |
| ReferencePerformance // Integer or Buffer (Resource Descriptor) | |
| LowestFrequency, // Integer or Buffer (Resource Descriptor) | |
| NominalFrequency // Integer or Buffer (Resource Descriptor) | |
| }) | |
| If resource buffer is NULL then integer will be used. | |
| Cf. ACPI 6.4, s8.4.7.1 _CPC (Continuous Performance Control) | |
| @ingroup CodeGenApis | |
| @param [in] CpcInfo CpcInfo object | |
| @param [in] ParentNode If provided, set ParentNode as the parent | |
| of the node created. | |
| @param [out] NewCpcNode If success and provided, contains the created node. | |
| @retval EFI_SUCCESS The function completed successfully. | |
| @retval EFI_INVALID_PARAMETER Invalid parameter. | |
| @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| AmlCreateCpcNode ( | |
| IN AML_CPC_INFO *CpcInfo, | |
| IN AML_NODE_HANDLE ParentNode OPTIONAL, | |
| OUT AML_OBJECT_NODE_HANDLE *NewCpcNode OPTIONAL | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| AML_OBJECT_NODE_HANDLE CpcNode; | |
| AML_OBJECT_NODE_HANDLE CpcPackage; | |
| UINT32 NumberOfEntries; | |
| if ((CpcInfo == NULL) || | |
| ((ParentNode == NULL) && (NewCpcNode == NULL))) | |
| { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // Revision 3 per ACPI 6.4 specification | |
| if (CpcInfo->Revision == 3) { | |
| // NumEntries 23 per ACPI 6.4 specification | |
| NumberOfEntries = 23; | |
| } else { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if ((IsNullGenericAddress (&CpcInfo->HighestPerformanceBuffer) && | |
| (CpcInfo->HighestPerformanceInteger == 0)) || | |
| (IsNullGenericAddress (&CpcInfo->NominalPerformanceBuffer) && | |
| (CpcInfo->NominalPerformanceInteger == 0)) || | |
| (IsNullGenericAddress (&CpcInfo->LowestNonlinearPerformanceBuffer) && | |
| (CpcInfo->LowestNonlinearPerformanceInteger == 0)) || | |
| (IsNullGenericAddress (&CpcInfo->LowestPerformanceBuffer) && | |
| (CpcInfo->LowestPerformanceInteger == 0)) || | |
| IsNullGenericAddress (&CpcInfo->DesiredPerformanceRegister) || | |
| IsNullGenericAddress (&CpcInfo->ReferencePerformanceCounterRegister) || | |
| IsNullGenericAddress (&CpcInfo->DeliveredPerformanceCounterRegister) || | |
| IsNullGenericAddress (&CpcInfo->PerformanceLimitedRegister)) | |
| { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| CpcPackage = NULL; | |
| Status = AmlCodeGenNamePackage ("_CPC", NULL, &CpcNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| return Status; | |
| } | |
| // Get the Package object node of the _CPC node, | |
| // which is the 2nd fixed argument (i.e. index 1). | |
| CpcPackage = (AML_OBJECT_NODE_HANDLE)AmlGetFixedArgument ( | |
| CpcNode, | |
| EAmlParseIndexTerm1 | |
| ); | |
| if ((CpcPackage == NULL) || | |
| (AmlGetNodeType ((AML_NODE_HANDLE)CpcPackage) != EAmlNodeObject) || | |
| (!AmlNodeHasOpCode (CpcPackage, AML_PACKAGE_OP, 0))) | |
| { | |
| ASSERT (0); | |
| Status = EFI_INVALID_PARAMETER; | |
| goto error_handler; | |
| } | |
| Status = AmlAddRegisterOrIntegerToPackage ( | |
| NULL, | |
| NumberOfEntries, | |
| CpcPackage | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| Status = AmlAddRegisterOrIntegerToPackage ( | |
| NULL, | |
| CpcInfo->Revision, | |
| CpcPackage | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| Status = AmlAddRegisterOrIntegerToPackage ( | |
| &CpcInfo->HighestPerformanceBuffer, | |
| CpcInfo->HighestPerformanceInteger, | |
| CpcPackage | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| Status = AmlAddRegisterOrIntegerToPackage ( | |
| &CpcInfo->NominalPerformanceBuffer, | |
| CpcInfo->NominalPerformanceInteger, | |
| CpcPackage | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| Status = AmlAddRegisterOrIntegerToPackage ( | |
| &CpcInfo->LowestNonlinearPerformanceBuffer, | |
| CpcInfo->LowestNonlinearPerformanceInteger, | |
| CpcPackage | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| Status = AmlAddRegisterOrIntegerToPackage ( | |
| &CpcInfo->LowestPerformanceBuffer, | |
| CpcInfo->LowestPerformanceInteger, | |
| CpcPackage | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| Status = AmlAddRegisterToPackage (&CpcInfo->GuaranteedPerformanceRegister, CpcPackage); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| Status = AmlAddRegisterToPackage (&CpcInfo->DesiredPerformanceRegister, CpcPackage); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| Status = AmlAddRegisterToPackage (&CpcInfo->MinimumPerformanceRegister, CpcPackage); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| Status = AmlAddRegisterToPackage (&CpcInfo->MaximumPerformanceRegister, CpcPackage); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| Status = AmlAddRegisterToPackage (&CpcInfo->PerformanceReductionToleranceRegister, CpcPackage); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| Status = AmlAddRegisterToPackage (&CpcInfo->TimeWindowRegister, CpcPackage); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| Status = AmlAddRegisterOrIntegerToPackage ( | |
| &CpcInfo->CounterWraparoundTimeBuffer, | |
| CpcInfo->CounterWraparoundTimeInteger, | |
| CpcPackage | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| Status = AmlAddRegisterToPackage (&CpcInfo->ReferencePerformanceCounterRegister, CpcPackage); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| Status = AmlAddRegisterToPackage (&CpcInfo->DeliveredPerformanceCounterRegister, CpcPackage); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| Status = AmlAddRegisterToPackage (&CpcInfo->PerformanceLimitedRegister, CpcPackage); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| Status = AmlAddRegisterToPackage (&CpcInfo->CPPCEnableRegister, CpcPackage); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| Status = AmlAddRegisterOrIntegerToPackage ( | |
| &CpcInfo->AutonomousSelectionEnableBuffer, | |
| CpcInfo->AutonomousSelectionEnableInteger, | |
| CpcPackage | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| Status = AmlAddRegisterToPackage (&CpcInfo->AutonomousActivityWindowRegister, CpcPackage); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| Status = AmlAddRegisterToPackage (&CpcInfo->EnergyPerformancePreferenceRegister, CpcPackage); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| Status = AmlAddRegisterOrIntegerToPackage ( | |
| &CpcInfo->ReferencePerformanceBuffer, | |
| CpcInfo->ReferencePerformanceInteger, | |
| CpcPackage | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| Status = AmlAddRegisterOrIntegerToPackage ( | |
| &CpcInfo->LowestFrequencyBuffer, | |
| CpcInfo->LowestFrequencyInteger, | |
| CpcPackage | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| Status = AmlAddRegisterOrIntegerToPackage ( | |
| &CpcInfo->NominalFrequencyBuffer, | |
| CpcInfo->NominalFrequencyInteger, | |
| CpcPackage | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| Status = LinkNode (CpcNode, ParentNode, NewCpcNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| return Status; | |
| error_handler: | |
| AmlDeleteTree ((AML_NODE_HANDLE)CpcNode); | |
| return Status; | |
| } |