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