/** @file | |
AML Api. | |
Copyright (c) 2020 - 2021, Arm Limited. All rights reserved.<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
/* Even though this file has access to the internal Node definition, | |
i.e. AML_ROOT_NODE, AML_OBJECT_NODE, etc. Only the external node | |
handle types should be used, i.e. AML_NODE_HANDLE, AML_ROOT_NODE_HANDLE, | |
etc. | |
Indeed, the functions in the "Api" folder should be implemented only | |
using the "safe" functions available in the "Include" folder. This | |
makes the functions available in the "Api" folder easy to export. | |
*/ | |
#include <AmlNodeDefines.h> | |
#include <AmlCoreInterface.h> | |
#include <AmlInclude.h> | |
#include <Api/AmlApiHelper.h> | |
#include <String/AmlString.h> | |
/** Update the name of a DeviceOp object node. | |
@param [in] DeviceOpNode Object node representing a Device. | |
Must have an OpCode=AML_NAME_OP, SubOpCode=0. | |
OpCode/SubOpCode. | |
DeviceOp object nodes are defined in ASL | |
using the "Device ()" function. | |
@param [in] NewNameString The new Device's name. | |
Must be a NULL-terminated ASL NameString | |
e.g.: "DEV0", "DV15.DEV0", etc. | |
The input string is copied. | |
@retval EFI_SUCCESS The function completed successfully. | |
@retval EFI_INVALID_PARAMETER Invalid parameter. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
AmlDeviceOpUpdateName ( | |
IN AML_OBJECT_NODE_HANDLE DeviceOpNode, | |
IN CHAR8 *NewNameString | |
) | |
{ | |
EFI_STATUS Status; | |
AML_DATA_NODE_HANDLE DeviceNameDataNode; | |
CHAR8 *NewAmlNameString; | |
UINT32 NewAmlNameStringSize; | |
// Check the input node is an object node. | |
if ((DeviceOpNode == NULL) || | |
(AmlGetNodeType ((AML_NODE_HANDLE)DeviceOpNode) != EAmlNodeObject) || | |
(!AmlNodeHasOpCode (DeviceOpNode, AML_EXT_OP, AML_EXT_DEVICE_OP)) || | |
(NewNameString == NULL)) | |
{ | |
ASSERT (0); | |
return EFI_INVALID_PARAMETER; | |
} | |
// Get the Device's name, being a data node | |
// which is the 1st fixed argument (i.e. index 0). | |
DeviceNameDataNode = (AML_DATA_NODE_HANDLE)AmlGetFixedArgument ( | |
DeviceOpNode, | |
EAmlParseIndexTerm0 | |
); | |
if ((DeviceNameDataNode == NULL) || | |
(AmlGetNodeType ((AML_NODE_HANDLE)DeviceNameDataNode) != EAmlNodeData) || | |
(!AmlNodeHasDataType (DeviceNameDataNode, EAmlNodeDataTypeNameString))) | |
{ | |
ASSERT (0); | |
return EFI_INVALID_PARAMETER; | |
} | |
Status = ConvertAslNameToAmlName (NewNameString, &NewAmlNameString); | |
if (EFI_ERROR (Status)) { | |
ASSERT (0); | |
return Status; | |
} | |
Status = AmlGetNameStringSize (NewAmlNameString, &NewAmlNameStringSize); | |
if (EFI_ERROR (Status)) { | |
ASSERT (0); | |
goto exit_handler; | |
} | |
// Update the Device's name node. | |
Status = AmlUpdateDataNode ( | |
DeviceNameDataNode, | |
EAmlNodeDataTypeNameString, | |
(UINT8 *)NewAmlNameString, | |
NewAmlNameStringSize | |
); | |
ASSERT_EFI_ERROR (Status); | |
exit_handler: | |
FreePool (NewAmlNameString); | |
return Status; | |
} | |
/** Update an integer value defined by a NameOp object node. | |
For compatibility reasons, the NameOpNode must initially | |
contain an integer. | |
@param [in] NameOpNode NameOp object node. | |
Must have an OpCode=AML_NAME_OP, SubOpCode=0. | |
NameOp object nodes are defined in ASL | |
using the "Name ()" function. | |
@param [in] NewInt New Integer value to assign. | |
Must be a UINT64. | |
@retval EFI_SUCCESS The function completed successfully. | |
@retval EFI_INVALID_PARAMETER Invalid parameter. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
AmlNameOpUpdateInteger ( | |
IN AML_OBJECT_NODE_HANDLE NameOpNode, | |
IN UINT64 NewInt | |
) | |
{ | |
EFI_STATUS Status; | |
AML_OBJECT_NODE_HANDLE IntegerOpNode; | |
if ((NameOpNode == NULL) || | |
(AmlGetNodeType ((AML_NODE_HANDLE)NameOpNode) != EAmlNodeObject) || | |
(!AmlNodeHasOpCode (NameOpNode, AML_NAME_OP, 0))) | |
{ | |
ASSERT (0); | |
return EFI_INVALID_PARAMETER; | |
} | |
// Get the Integer object node defined by the "Name ()" function: | |
// it must have an Integer OpCode (Byte/Word/DWord/QWord). | |
// It is the 2nd fixed argument (i.e. index 1) of the NameOp node. | |
// This can also be a ZeroOp or OneOp node. | |
IntegerOpNode = (AML_OBJECT_NODE_HANDLE)AmlGetFixedArgument ( | |
NameOpNode, | |
EAmlParseIndexTerm1 | |
); | |
if ((IntegerOpNode == NULL) || | |
(AmlGetNodeType ((AML_NODE_HANDLE)IntegerOpNode) != EAmlNodeObject)) | |
{ | |
ASSERT (0); | |
return EFI_INVALID_PARAMETER; | |
} | |
// Update the Integer value. | |
Status = AmlUpdateInteger (IntegerOpNode, NewInt); | |
ASSERT_EFI_ERROR (Status); | |
return Status; | |
} | |
/** Update a string value defined by a NameOp object node. | |
The NameOpNode must initially contain a string. | |
The EISAID ASL macro converts a string to an integer. This, it is | |
not accepted. | |
@param [in] NameOpNode NameOp object node. | |
Must have an OpCode=AML_NAME_OP, SubOpCode=0. | |
NameOp object nodes are defined in ASL | |
using the "Name ()" function. | |
@param [in] NewName New NULL terminated string to assign to | |
the NameOpNode. | |
The input string is copied. | |
@retval EFI_SUCCESS The function completed successfully. | |
@retval EFI_INVALID_PARAMETER Invalid parameter. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
AmlNameOpUpdateString ( | |
IN AML_OBJECT_NODE_HANDLE NameOpNode, | |
IN CONST CHAR8 *NewName | |
) | |
{ | |
EFI_STATUS Status; | |
AML_OBJECT_NODE_HANDLE StringOpNode; | |
AML_DATA_NODE_HANDLE StringDataNode; | |
if ((NameOpNode == NULL) || | |
(AmlGetNodeType ((AML_NODE_HANDLE)NameOpNode) != EAmlNodeObject) || | |
(!AmlNodeHasOpCode (NameOpNode, AML_NAME_OP, 0))) | |
{ | |
ASSERT (0); | |
return EFI_INVALID_PARAMETER; | |
} | |
// Get the String object node defined by the "Name ()" function: | |
// it must have a string OpCode. | |
// It is the 2nd fixed argument (i.e. index 1) of the NameOp node. | |
StringOpNode = (AML_OBJECT_NODE_HANDLE)AmlGetFixedArgument ( | |
NameOpNode, | |
EAmlParseIndexTerm1 | |
); | |
if ((StringOpNode == NULL) || | |
(AmlGetNodeType ((AML_NODE_HANDLE)StringOpNode) != EAmlNodeObject)) | |
{ | |
ASSERT (0); | |
return EFI_INVALID_PARAMETER; | |
} | |
// Get the string data node. | |
// It is the 1st fixed argument (i.e. index 0) of the StringOpNode node. | |
StringDataNode = (AML_DATA_NODE_HANDLE)AmlGetFixedArgument ( | |
StringOpNode, | |
EAmlParseIndexTerm0 | |
); | |
if ((StringDataNode == NULL) || | |
(AmlGetNodeType ((AML_NODE_HANDLE)StringDataNode) != EAmlNodeData)) | |
{ | |
ASSERT (0); | |
return EFI_INVALID_PARAMETER; | |
} | |
// Update the string value. | |
Status = AmlUpdateDataNode ( | |
StringDataNode, | |
EAmlNodeDataTypeString, | |
(UINT8 *)NewName, | |
(UINT32)AsciiStrLen (NewName) + 1 | |
); | |
ASSERT_EFI_ERROR (Status); | |
return Status; | |
} | |
/** Get the first Resource Data element contained in a named object. | |
In the following ASL code, the function will return the Resource Data | |
node corresponding to the "QWordMemory ()" ASL macro. | |
Name (_CRS, ResourceTemplate() { | |
QWordMemory (...) {...}, | |
Interrupt (...) {...} | |
} | |
) | |
Note: | |
"_CRS" names defined as methods are not handled by this function. | |
They must be defined as names, using the "Name ()" statement. | |
@param [in] NameOpNode NameOp object node defining a named object. | |
Must have an OpCode=AML_NAME_OP, SubOpCode=0. | |
NameOp object nodes are defined in ASL | |
using the "Name ()" function. | |
@param [out] OutRdNode Pointer to the first Resource Data element of | |
the named object. A Resource Data element | |
is stored in a data node. | |
@retval EFI_SUCCESS The function completed successfully. | |
@retval EFI_INVALID_PARAMETER Invalid parameter. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
AmlNameOpGetFirstRdNode ( | |
IN AML_OBJECT_NODE_HANDLE NameOpNode, | |
OUT AML_DATA_NODE_HANDLE *OutRdNode | |
) | |
{ | |
AML_OBJECT_NODE_HANDLE BufferOpNode; | |
AML_DATA_NODE_HANDLE FirstRdNode; | |
if ((NameOpNode == NULL) || | |
(AmlGetNodeType ((AML_NODE_HANDLE)NameOpNode) != EAmlNodeObject) || | |
(!AmlNodeHasOpCode (NameOpNode, AML_NAME_OP, 0)) || | |
(OutRdNode == NULL)) | |
{ | |
ASSERT (0); | |
return EFI_INVALID_PARAMETER; | |
} | |
*OutRdNode = NULL; | |
// Get the value of the variable which is represented as a BufferOp object | |
// node which is the 2nd fixed argument (i.e. index 1). | |
BufferOpNode = (AML_OBJECT_NODE_HANDLE)AmlGetFixedArgument ( | |
NameOpNode, | |
EAmlParseIndexTerm1 | |
); | |
if ((BufferOpNode == NULL) || | |
(AmlGetNodeType ((AML_NODE_HANDLE)BufferOpNode) != EAmlNodeObject) || | |
(!AmlNodeHasOpCode (BufferOpNode, AML_BUFFER_OP, 0))) | |
{ | |
ASSERT (0); | |
return EFI_INVALID_PARAMETER; | |
} | |
// Get the first Resource data node in the variable list of | |
// argument of the BufferOp node. | |
FirstRdNode = (AML_DATA_NODE_HANDLE)AmlGetNextVariableArgument ( | |
(AML_NODE_HANDLE)BufferOpNode, | |
NULL | |
); | |
if ((FirstRdNode == NULL) || | |
(AmlGetNodeType ((AML_NODE_HANDLE)FirstRdNode) != EAmlNodeData) || | |
(!AmlNodeHasDataType (FirstRdNode, EAmlNodeDataTypeResourceData))) | |
{ | |
ASSERT (0); | |
return EFI_INVALID_PARAMETER; | |
} | |
*OutRdNode = FirstRdNode; | |
return EFI_SUCCESS; | |
} | |
/** Get the Resource Data element following the CurrRdNode Resource Data. | |
In the following ASL code, if CurrRdNode corresponds to the first | |
"QWordMemory ()" ASL macro, the function will return the Resource Data | |
node corresponding to the "Interrupt ()" ASL macro. | |
Name (_CRS, ResourceTemplate() { | |
QwordMemory (...) {...}, | |
Interrupt (...) {...} | |
} | |
) | |
Note: | |
"_CRS" names defined as methods are not handled by this function. | |
They must be defined as names, using the "Name ()" statement. | |
@param [in] CurrRdNode Pointer to the current Resource Data element of | |
the named object. | |
@param [out] OutRdNode Pointer to the Resource Data element following | |
the CurrRdNode. | |
Contain a NULL pointer if CurrRdNode is the | |
last Resource Data element in the list. | |
The "End Tag" is not considered as a resource | |
data element and is not returned. | |
@retval EFI_SUCCESS The function completed successfully. | |
@retval EFI_INVALID_PARAMETER Invalid parameter. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
AmlNameOpGetNextRdNode ( | |
IN AML_DATA_NODE_HANDLE CurrRdNode, | |
OUT AML_DATA_NODE_HANDLE *OutRdNode | |
) | |
{ | |
AML_OBJECT_NODE_HANDLE NameOpNode; | |
AML_OBJECT_NODE_HANDLE BufferOpNode; | |
if ((CurrRdNode == NULL) || | |
(AmlGetNodeType ((AML_NODE_HANDLE)CurrRdNode) != EAmlNodeData) || | |
(!AmlNodeHasDataType (CurrRdNode, EAmlNodeDataTypeResourceData)) || | |
(OutRdNode == NULL)) | |
{ | |
ASSERT (0); | |
return EFI_INVALID_PARAMETER; | |
} | |
*OutRdNode = NULL; | |
// The parent of the CurrRdNode must be a BufferOp node. | |
BufferOpNode = (AML_OBJECT_NODE_HANDLE)AmlGetParent ( | |
(AML_NODE_HANDLE)CurrRdNode | |
); | |
if ((BufferOpNode == NULL) || | |
(!AmlNodeHasOpCode (BufferOpNode, AML_BUFFER_OP, 0))) | |
{ | |
ASSERT (0); | |
return EFI_INVALID_PARAMETER; | |
} | |
// The parent of the BufferOpNode must be a NameOp node. | |
NameOpNode = (AML_OBJECT_NODE_HANDLE)AmlGetParent ( | |
(AML_NODE_HANDLE)BufferOpNode | |
); | |
if ((NameOpNode == NULL) || | |
(!AmlNodeHasOpCode (NameOpNode, AML_NAME_OP, 0))) | |
{ | |
ASSERT (0); | |
return EFI_INVALID_PARAMETER; | |
} | |
*OutRdNode = (AML_DATA_NODE_HANDLE)AmlGetNextVariableArgument ( | |
(AML_NODE_HANDLE)BufferOpNode, | |
(AML_NODE_HANDLE)CurrRdNode | |
); | |
// If the Resource Data is an End Tag, return NULL. | |
if (AmlNodeHasRdDataType ( | |
*OutRdNode, | |
AML_RD_BUILD_SMALL_DESC_ID (ACPI_SMALL_END_TAG_DESCRIPTOR_NAME) | |
)) | |
{ | |
*OutRdNode = NULL; | |
} | |
return EFI_SUCCESS; | |
} | |
/** Attach a node in an AML tree. | |
The node will be added as the last statement of the ParentNode. | |
E.g.: | |
ASL code corresponding to NewNode: | |
Name (_UID, 0) | |
ASL code corresponding to ParentNode: | |
Device (PCI0) { | |
Name(_HID, EISAID("PNP0A08")) | |
} | |
"AmlAttachNode (ParentNode, NewNode)" will result in: | |
ASL code: | |
Device (PCI0) { | |
Name(_HID, EISAID("PNP0A08")) | |
Name (_UID, 0) | |
} | |
@param [in] ParentNode Pointer to the parent node. | |
Must be a root or an object node. | |
@param [in] NewNode Pointer to the node to add. | |
@retval EFI_SUCCESS The function completed successfully. | |
@retval EFI_INVALID_PARAMETER Invalid parameter. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
AmlAttachNode ( | |
IN AML_NODE_HANDLE ParentNode, | |
IN AML_NODE_HANDLE NewNode | |
) | |
{ | |
return AmlVarListAddTail (ParentNode, NewNode); | |
} |