| /** @file | |
| AML Code Generation. | |
| Copyright (c) 2020 - 2023, Arm Limited. All rights reserved.<BR> | |
| Copyright (C) 2023 - 2024, Advanced Micro Devices, Inc. All rights reserved.<BR> | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #include <AmlNodeDefines.h> | |
| #include <AcpiTableGenerator.h> | |
| #include <AmlCoreInterface.h> | |
| #include <AcpiObjects.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; | |
| } | |
| /** AML code generation for a Name object node, containing a String. | |
| AmlCodeGenNameUnicodeString ("_STR", L"String", ParentNode, NewObjectNode) is | |
| equivalent of the following ASL code: | |
| Name(_STR, Unicode ("String")) | |
| @ingroup CodeGenApis | |
| @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 Unicode 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 | |
| AmlCodeGenNameUnicodeString ( | |
| IN CONST CHAR8 *NameString, | |
| IN CHAR16 *String, | |
| IN AML_NODE_HANDLE ParentNode OPTIONAL, | |
| OUT AML_OBJECT_NODE_HANDLE *NewObjectNode OPTIONAL | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| AML_OBJECT_NODE *ObjectNode; | |
| AML_DATA_NODE *DataNode; | |
| if ((NameString == NULL) || | |
| (String == NULL) || | |
| ((ParentNode == NULL) && (NewObjectNode == NULL))) | |
| { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Status = AmlCodeGenBuffer (NULL, 0, &ObjectNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| return Status; | |
| } | |
| Status = AmlCreateDataNode ( | |
| EAmlNodeDataTypeRaw, | |
| (CONST UINT8 *)String, | |
| (UINT32)StrSize (String), | |
| &DataNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| AmlDeleteTree ((AML_NODE_HEADER *)ObjectNode); | |
| return Status; | |
| } | |
| Status = AmlVarListAddTail ( | |
| (AML_NODE_HEADER *)ObjectNode, | |
| (AML_NODE_HEADER *)DataNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| AmlDeleteTree ((AML_NODE_HEADER *)ObjectNode); | |
| AmlDeleteTree ((AML_NODE_HANDLE)DataNode); | |
| return Status; | |
| } | |
| Status = AmlCodeGenName ( | |
| NameString, | |
| ObjectNode, | |
| ParentNode, | |
| NewObjectNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| AmlDeleteTree ((AML_NODE_HEADER *)ObjectNode); | |
| } | |
| 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 ThermalZone object node. | |
| AmlCodeGenThermalZone ("TZ00", ParentNode, NewObjectNode) is | |
| equivalent of the following ASL code: | |
| ThermalZone(TZ00) {} | |
| @ingroup CodeGenApis | |
| @param [in] NameString The new ThermalZone'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 | |
| AmlCodeGenThermalZone ( | |
| IN CONST CHAR8 *NameString, | |
| IN AML_NODE_HANDLE ParentNode OPTIONAL, | |
| OUT AML_OBJECT_NODE_HANDLE *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_THERMAL_ZONE_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 Return object node, | |
| returning the object as an input NameString with a integer argument. | |
| AmlCodeGenReturn ("NAM1", 6, ParentNode, NewObjectNode) is | |
| equivalent of the following ASL code: | |
| Return(NAM1 (6)) | |
| 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] Integer Argument to pass to the NameString | |
| @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 | |
| AmlCodeGenReturnNameStringIntegerArgument ( | |
| IN CONST CHAR8 *NameString, | |
| IN UINT64 Integer, | |
| IN AML_NODE_HEADER *ParentNode OPTIONAL, | |
| OUT AML_OBJECT_NODE **NewObjectNode OPTIONAL | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| AML_DATA_NODE *DataNode; | |
| AML_OBJECT_NODE *IntNode; | |
| CHAR8 *AmlNameString; | |
| UINT32 AmlNameStringSize; | |
| AML_OBJECT_NODE *ObjectNode; | |
| DataNode = NULL; | |
| IntNode = NULL; | |
| ObjectNode = 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 = AmlCodeGenInteger (Integer, &IntNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto exit_handler; | |
| } | |
| Status = AmlCreateDataNode ( | |
| EAmlNodeDataTypeNameString, | |
| (UINT8 *)AmlNameString, | |
| AmlNameStringSize, | |
| &DataNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto exit_handler1; | |
| } | |
| // AmlCodeGenReturn() deletes DataNode if error. | |
| Status = AmlCodeGenReturn ( | |
| (AML_NODE_HEADER *)DataNode, | |
| ParentNode, | |
| &ObjectNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto exit_handler1; | |
| } | |
| Status = AmlVarListAddTail ( | |
| (AML_NODE_HANDLE)ObjectNode, | |
| (AML_NODE_HANDLE)IntNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| // ObjectNode is already attached to ParentNode in AmlCodeGenReturn(), | |
| // so no need to free it here, it will be deleted when deleting the | |
| // ParentNode tree | |
| ASSERT (0); | |
| goto exit_handler1; | |
| } | |
| if (NewObjectNode != 0) { | |
| *NewObjectNode = ObjectNode; | |
| } | |
| goto exit_handler; | |
| exit_handler1: | |
| if (IntNode != NULL) { | |
| AmlDeleteTree ((AML_NODE_HANDLE)IntNode); | |
| } | |
| exit_handler: | |
| if (AmlNameString != NULL) { | |
| FreePool (AmlNameString); | |
| } | |
| 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 a NameString that takes an | |
| integer argument. | |
| AmlCodeGenMethodRetNameStringIntegerArgument ( | |
| "MET0", "MET1", 1, TRUE, 3, 5, ParentNode, NewObjectNode | |
| ); | |
| is equivalent of the following ASL code: | |
| Method(MET0, 1, Serialized, 3) { | |
| Return (MET1 (5)) | |
| } | |
| 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] IntegerArgument Argument to pass 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 | |
| AmlCodeGenMethodRetNameStringIntegerArgument ( | |
| IN CONST CHAR8 *MethodNameString, | |
| IN CONST CHAR8 *ReturnedNameString OPTIONAL, | |
| IN UINT8 NumArgs, | |
| IN BOOLEAN IsSerialized, | |
| IN UINT8 SyncLevel, | |
| IN UINT64 IntegerArgument, | |
| 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 = AmlCodeGenReturnNameStringIntegerArgument ( | |
| ReturnedNameString, | |
| IntegerArgument, | |
| (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 == EFI_ACPI_6_5_AML_CPC_REVISION) { | |
| // NumEntries 23 per ACPI 6.4 specification | |
| NumberOfEntries = 23; | |
| } else { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| /// The following fields are theoretically mandatory, but not supported | |
| /// by some platforms. | |
| /// - PerformanceLimitedRegister | |
| /// - ReferencePerformanceCounterRegister | |
| /// - DeliveredPerformanceCounterRegister | |
| /// Warn if BIT0 in PcdDevelopmentPlatformRelaxations is set, otherwise | |
| /// return an error. | |
| if (IsNullGenericAddress (&CpcInfo->PerformanceLimitedRegister) || | |
| IsNullGenericAddress (&CpcInfo->ReferencePerformanceCounterRegister) || | |
| IsNullGenericAddress (&CpcInfo->DeliveredPerformanceCounterRegister)) | |
| { | |
| if ((PcdGet64 (PcdDevelopmentPlatformRelaxations) & BIT0) != 0) { | |
| DEBUG (( | |
| DEBUG_WARN, | |
| "Missing PerformanceLimited|ReferencePerformanceCounter|" | |
| "DeliveredPerformanceCounter field in _CPC object\n" | |
| )); | |
| } 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)) | |
| { | |
| 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; | |
| } | |
| /** AML code generation to add a NameString to the package in a named node. | |
| @param [in] NameString NameString to add | |
| @param [in] NamedNode Node to add the string to the included package. | |
| @retval EFI_SUCCESS Success. | |
| @retval EFI_INVALID_PARAMETER Invalid parameter. | |
| @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| AmlAddNameStringToNamedPackage ( | |
| IN CHAR8 *NameString, | |
| IN AML_OBJECT_NODE_HANDLE NamedNode | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| AML_DATA_NODE *DataNode; | |
| CHAR8 *AmlNameString; | |
| UINT32 AmlNameStringSize; | |
| AML_OBJECT_NODE_HANDLE PackageNode; | |
| DataNode = NULL; | |
| if ((NamedNode == NULL) || | |
| (AmlGetNodeType ((AML_NODE_HANDLE)NamedNode) != EAmlNodeObject) || | |
| (!AmlNodeHasOpCode (NamedNode, AML_NAME_OP, 0))) | |
| { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| PackageNode = (AML_OBJECT_NODE_HANDLE)AmlGetFixedArgument ( | |
| NamedNode, | |
| EAmlParseIndexTerm1 | |
| ); | |
| if ((PackageNode == NULL) || | |
| (AmlGetNodeType ((AML_NODE_HANDLE)PackageNode) != EAmlNodeObject) || | |
| (!AmlNodeHasOpCode (PackageNode, AML_PACKAGE_OP, 0))) | |
| { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| 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; | |
| } | |
| Status = AmlVarListAddTail ( | |
| (AML_NODE_HANDLE)PackageNode, | |
| (AML_NODE_HANDLE)DataNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| AmlDeleteTree ((AML_NODE_HANDLE)DataNode); | |
| } | |
| exit_handler: | |
| if (AmlNameString != NULL) { | |
| FreePool (AmlNameString); | |
| } | |
| return Status; | |
| } | |
| /** Add an integer value to the named package node. | |
| AmlCodeGenNamePackage ("_CID", NULL, &PackageNode); | |
| AmlGetEisaIdFromString ("PNP0A03", &EisaId); | |
| AmlAddIntegerToNamedPackage (EisaId, NameNode); | |
| AmlGetEisaIdFromString ("PNP0A08", &EisaId); | |
| AmlAddIntegerToNamedPackage (EisaId, NameNode); | |
| equivalent of the following ASL code: | |
| Name (_CID, Package (0x02) // _CID: Compatible ID | |
| { | |
| EisaId ("PNP0A03"), | |
| EisaId ("PNP0A08") | |
| }) | |
| The package is added at the tail of the list of the input package node | |
| name: | |
| Name ("NamePackageNode", Package () { | |
| [Pre-existing package entries], | |
| [Newly created integer entry] | |
| }) | |
| @ingroup CodeGenApis | |
| @param [in] Integer Integer value that need to be added to package node. | |
| @param [in, out] NameNode Package named node to add the object to. | |
| @retval EFI_SUCCESS Success. | |
| @retval EFI_INVALID_PARAMETER Invalid parameter. | |
| @retval Others Error occurred during the operation. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| AmlAddIntegerToNamedPackage ( | |
| IN UINT32 Integer, | |
| IN OUT AML_OBJECT_NODE_HANDLE NameNode | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| AML_OBJECT_NODE *PackageNode; | |
| if (NameNode == NULL) { | |
| ASSERT_EFI_ERROR (FALSE); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| PackageNode = (AML_OBJECT_NODE_HANDLE)AmlGetFixedArgument ( | |
| NameNode, | |
| EAmlParseIndexTerm1 | |
| ); | |
| if ((PackageNode == NULL) || | |
| (AmlGetNodeType ((AML_NODE_HANDLE)PackageNode) != EAmlNodeObject) || | |
| (!AmlNodeHasOpCode (PackageNode, AML_PACKAGE_OP, 0))) | |
| { | |
| ASSERT_EFI_ERROR (FALSE); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Status = AmlAddRegisterOrIntegerToPackage (NULL, Integer, PackageNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| } | |
| return Status; | |
| } | |
| /** AML code generation to invoke/call another method. | |
| This method is a subset implementation of MethodInvocation | |
| defined in the ACPI specification 6.5, | |
| section 20.2.5 "Term Objects Encoding". | |
| Added integer, string, ArgObj and LocalObj support. | |
| Example 1: | |
| AmlCodeGenInvokeMethod ("MET0", 0, NULL, ParentNode); | |
| is equivalent to the following ASL code: | |
| MET0 (); | |
| Example 2: | |
| AML_METHOD_PARAM Param[4]; | |
| Param[0].Data.Integer = 0x100; | |
| Param[0].Type = AmlMethodParamTypeInteger; | |
| Param[1].Data.Buffer = "TEST"; | |
| Param[1].Type = AmlMethodParamTypeString; | |
| Param[2].Data.Arg = 0; | |
| Param[2].Type = AmlMethodParamTypeArg; | |
| Param[3].Data.Local = 2; | |
| Param[3].Type = AmlMethodParamTypeLocal; | |
| AmlCodeGenInvokeMethod ("MET0", 4, Param, ParentNode); | |
| is equivalent to the following ASL code: | |
| MET0 (0x100, "TEST", Arg0, Local2); | |
| Example 3: | |
| AML_METHOD_PARAM Param[2]; | |
| Param[0].Data.Arg = 0; | |
| Param[0].Type = AmlMethodParamTypeArg; | |
| Param[1].Data.Integer = 0x100; | |
| Param[1].Type = AmlMethodParamTypeInteger; | |
| AmlCodeGenMethodRetNameString ("MET2", NULL, 2, TRUE, 0, | |
| ParentNode, &MethodNode); | |
| AmlCodeGenInvokeMethod ("MET3", 2, Param, MethodNode); | |
| is equivalent to the following ASL code: | |
| Method (MET2, 2, Serialized) | |
| { | |
| MET3 (Arg0, 0x0100) | |
| } | |
| @param [in] MethodNameString The method name to be called or invoked. | |
| @param [in] NumArgs Number of arguments to be passed, | |
| 0 to 7 are permissible values. | |
| @param [in] Parameters Contains the parameter data. | |
| @param [in] ParentNode The parent node to which the method invocation | |
| nodes are attached. | |
| @retval EFI_SUCCESS Success. | |
| @retval EFI_INVALID_PARAMETER Invalid parameter. | |
| @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| AmlCodeGenInvokeMethod ( | |
| IN CONST CHAR8 *MethodNameString, | |
| IN UINT8 NumArgs, | |
| IN AML_METHOD_PARAM *Parameters OPTIONAL, | |
| IN AML_NODE_HANDLE ParentNode | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| UINT8 Index; | |
| CHAR8 *AmlNameString; | |
| UINT32 AmlNameStringSize; | |
| AML_DATA_NODE *DataNode; | |
| AML_OBJECT_NODE *ObjectNode; | |
| AML_NODE_HANDLE *NodeStream; | |
| if ((MethodNameString == NULL) || (ParentNode == NULL)) { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if ((NumArgs > 7) || | |
| ((Parameters == NULL) && (NumArgs > 0))) | |
| { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| /// Allocate space to store methodname, object, data node pointers | |
| NodeStream = AllocateZeroPool (sizeof (AML_NODE_HANDLE) * (NumArgs + 1)); | |
| if (NodeStream == NULL) { | |
| ASSERT (0); | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| /// Create a called or invoked method name string. | |
| Status = ConvertAslNameToAmlName (MethodNameString, &AmlNameString); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto exit_handler; | |
| } | |
| Status = AmlGetNameStringSize (AmlNameString, &AmlNameStringSize); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| FreePool (AmlNameString); | |
| goto exit_handler; | |
| } | |
| DataNode = NULL; | |
| Status = AmlCreateDataNode ( | |
| EAmlNodeDataTypeNameString, | |
| (UINT8 *)AmlNameString, | |
| AmlNameStringSize, | |
| &DataNode | |
| ); | |
| FreePool (AmlNameString); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto exit_handler; | |
| } | |
| NodeStream[0] = (AML_NODE_HANDLE)DataNode; | |
| if (Parameters != NULL) { | |
| /// Validate and convert the Parameters to the stream of nodes. | |
| for (Index = 0; Index < NumArgs; Index++) { | |
| ObjectNode = NULL; | |
| switch (Parameters[Index].Type) { | |
| case AmlMethodParamTypeInteger: | |
| Status = AmlCodeGenInteger ( | |
| Parameters[Index].Data.Integer, | |
| &ObjectNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto exit_handler; | |
| } | |
| break; | |
| case AmlMethodParamTypeString: | |
| if (Parameters[Index].Data.Buffer == NULL) { | |
| ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER); | |
| Status = EFI_INVALID_PARAMETER; | |
| goto exit_handler; | |
| } | |
| Status = AmlCodeGenString ( | |
| Parameters[Index].Data.Buffer, | |
| &ObjectNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto exit_handler; | |
| } | |
| break; | |
| case AmlMethodParamTypeArg: | |
| if (Parameters[Index].Data.Arg > (UINT8)(AML_ARG6 - AML_ARG0)) { | |
| ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER); | |
| Status = EFI_INVALID_PARAMETER; | |
| goto exit_handler; | |
| } | |
| Status = AmlCreateObjectNode ( | |
| AmlGetByteEncodingByOpCode ( | |
| AML_ARG0 + Parameters[Index].Data.Arg, | |
| 0 | |
| ), | |
| 0, | |
| &ObjectNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto exit_handler; | |
| } | |
| break; | |
| case AmlMethodParamTypeLocal: | |
| if (Parameters[Index].Data.Local > (UINT8)(AML_LOCAL7 - AML_LOCAL0)) { | |
| ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER); | |
| Status = EFI_INVALID_PARAMETER; | |
| goto exit_handler; | |
| } | |
| Status = AmlCreateObjectNode ( | |
| AmlGetByteEncodingByOpCode ( | |
| AML_LOCAL0 + Parameters[Index].Data.Local, | |
| 0 | |
| ), | |
| 0, | |
| &ObjectNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto exit_handler; | |
| } | |
| break; | |
| default: | |
| ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER); | |
| Status = EFI_INVALID_PARAMETER; | |
| goto exit_handler; | |
| } // switch | |
| // Link the Object Node in the Node Stream. | |
| NodeStream[Index + 1] = (AML_NODE_HANDLE)ObjectNode; | |
| } // for | |
| } | |
| /// Index <= NumArgs, because an additional method name was added. | |
| for (Index = 0; Index <= NumArgs; Index++) { | |
| Status = AmlVarListAddTail ( | |
| (AML_NODE_HANDLE)ParentNode, | |
| (AML_NODE_HANDLE)NodeStream[Index] | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto exit_handler_detach; | |
| } | |
| } | |
| FreePool (NodeStream); | |
| return Status; | |
| exit_handler_detach: | |
| /// The index contains the last successful node attached. | |
| for ( ; Index > 0; Index--) { | |
| /// Index contains the node number that is failed for AmlVarListAddTail(). | |
| /// Hence, start detaching from the last successful | |
| AmlDetachNode (NodeStream[Index-1]); | |
| } | |
| exit_handler: | |
| /// Index <= NumArgs, because an additional method name was added. | |
| for (Index = 0; Index <= NumArgs; Index++) { | |
| if (NodeStream[Index] != 0) { | |
| AmlDeleteTree (NodeStream[Index]); | |
| } | |
| } | |
| FreePool (NodeStream); | |
| return Status; | |
| } | |
| /** Create a _PSD node. | |
| Creates and optionally adds the following node | |
| Name(_PSD, Package() | |
| { | |
| NumEntries, // Integer | |
| Revision, // Integer | |
| Domain, // Integer | |
| CoordType, // Integer | |
| NumProc, // Integer | |
| }) | |
| Cf. ACPI 6.5, s8.4.5.5 _PSD (P-State Dependency) | |
| @ingroup CodeGenApis | |
| @param [in] PsdInfo PsdInfo object | |
| @param [in] ParentNode If provided, set ParentNode as the parent | |
| of the node created. | |
| @param [out] NewPsdNode 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 | |
| AmlCreatePsdNode ( | |
| IN AML_PSD_INFO *PsdInfo, | |
| IN AML_NODE_HANDLE ParentNode OPTIONAL, | |
| OUT AML_OBJECT_NODE_HANDLE *NewPsdNode OPTIONAL | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| AML_OBJECT_NODE_HANDLE PsdNode; | |
| AML_OBJECT_NODE_HANDLE PsdPackage; | |
| AML_OBJECT_NODE_HANDLE IntegerNode; | |
| UINT32 NumberOfEntries; | |
| if ((PsdInfo == NULL) || | |
| ((ParentNode == NULL) && (NewPsdNode == NULL))) | |
| { | |
| Status = EFI_INVALID_PARAMETER; | |
| ASSERT_EFI_ERROR (Status); | |
| return Status; | |
| } | |
| // Revision 3 per ACPI 6.5 specification | |
| if (PsdInfo->Revision == EFI_ACPI_6_5_AML_PSD_REVISION) { | |
| // NumEntries 5 per ACPI 6.5 specification | |
| NumberOfEntries = 5; | |
| } else { | |
| Status = EFI_INVALID_PARAMETER; | |
| ASSERT_EFI_ERROR (Status); | |
| return Status; | |
| } | |
| if (((PsdInfo->CoordType != ACPI_AML_COORD_TYPE_SW_ALL) && | |
| (PsdInfo->CoordType != ACPI_AML_COORD_TYPE_SW_ANY) && | |
| (PsdInfo->CoordType != ACPI_AML_COORD_TYPE_HW_ALL)) || | |
| (PsdInfo->NumProc == 0)) | |
| { | |
| Status = EFI_INVALID_PARAMETER; | |
| ASSERT_EFI_ERROR (Status); | |
| return Status; | |
| } | |
| Status = AmlCodeGenNamePackage ("_PSD", NULL, &PsdNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| return Status; | |
| } | |
| // Get the Package object node of the _PSD node, | |
| // which is the 2nd fixed argument (i.e. index 1). | |
| PsdPackage = (AML_OBJECT_NODE_HANDLE)AmlGetFixedArgument ( | |
| PsdNode, | |
| EAmlParseIndexTerm1 | |
| ); | |
| if ((PsdPackage == NULL) || | |
| (AmlGetNodeType ((AML_NODE_HANDLE)PsdPackage) != EAmlNodeObject) || | |
| (!AmlNodeHasOpCode (PsdPackage, AML_PACKAGE_OP, 0))) | |
| { | |
| Status = EFI_INVALID_PARAMETER; | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| // NumEntries | |
| Status = AmlCodeGenInteger (NumberOfEntries, &IntegerNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| Status = AmlVarListAddTail ( | |
| (AML_NODE_HANDLE)PsdPackage, | |
| (AML_NODE_HANDLE)IntegerNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| FreePool (IntegerNode); | |
| goto error_handler; | |
| } | |
| // Revision | |
| Status = AmlCodeGenInteger (PsdInfo->Revision, &IntegerNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| Status = AmlVarListAddTail ( | |
| (AML_NODE_HANDLE)PsdPackage, | |
| (AML_NODE_HANDLE)IntegerNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| FreePool (IntegerNode); | |
| goto error_handler; | |
| } | |
| // Domain | |
| Status = AmlCodeGenInteger (PsdInfo->Domain, &IntegerNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| Status = AmlVarListAddTail ( | |
| (AML_NODE_HANDLE)PsdPackage, | |
| (AML_NODE_HANDLE)IntegerNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| FreePool (IntegerNode); | |
| goto error_handler; | |
| } | |
| // CoordType | |
| Status = AmlCodeGenInteger (PsdInfo->CoordType, &IntegerNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| Status = AmlVarListAddTail ( | |
| (AML_NODE_HANDLE)PsdPackage, | |
| (AML_NODE_HANDLE)IntegerNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| FreePool (IntegerNode); | |
| goto error_handler; | |
| } | |
| // Num Processors | |
| Status = AmlCodeGenInteger (PsdInfo->NumProc, &IntegerNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| Status = AmlVarListAddTail ( | |
| (AML_NODE_HANDLE)PsdPackage, | |
| (AML_NODE_HANDLE)IntegerNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| FreePool (IntegerNode); | |
| goto error_handler; | |
| } | |
| Status = LinkNode (PsdNode, ParentNode, NewPsdNode); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| goto error_handler; | |
| } | |
| return Status; | |
| error_handler: | |
| AmlDeleteTree ((AML_NODE_HANDLE)PsdNode); | |
| return Status; | |
| } |