summaryrefslogtreecommitdiffstats
path: root/DynamicTablesPkg/Library/Common/AmlLib/Api/AmlApi.c
diff options
context:
space:
mode:
Diffstat (limited to 'DynamicTablesPkg/Library/Common/AmlLib/Api/AmlApi.c')
-rw-r--r--DynamicTablesPkg/Library/Common/AmlLib/Api/AmlApi.c382
1 files changed, 382 insertions, 0 deletions
diff --git a/DynamicTablesPkg/Library/Common/AmlLib/Api/AmlApi.c b/DynamicTablesPkg/Library/Common/AmlLib/Api/AmlApi.c
new file mode 100644
index 0000000000..fdf04acc62
--- /dev/null
+++ b/DynamicTablesPkg/Library/Common/AmlLib/Api/AmlApi.c
@@ -0,0 +1,382 @@
+/** @file
+ AML Api.
+
+ Copyright (c) 2020, 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 "_CRS" 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:
+ - The "_CRS" object must be declared using ASL "Name (Declare Named Object)".
+ - "_CRS" declared using ASL "Method (Declare Control Method)" is not
+ supported.
+
+ @param [in] NameOpCrsNode NameOp object node defining a "_CRS" 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 "_CRS" 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
+AmlNameOpCrsGetFirstRdNode (
+ IN AML_OBJECT_NODE_HANDLE NameOpCrsNode,
+ OUT AML_DATA_NODE_HANDLE * OutRdNode
+ )
+{
+ AML_OBJECT_NODE_HANDLE BufferOpNode;
+ AML_DATA_NODE_HANDLE FirstRdNode;
+
+ if ((NameOpCrsNode == NULL) ||
+ (AmlGetNodeType ((AML_NODE_HANDLE)NameOpCrsNode) != EAmlNodeObject) ||
+ (!AmlNodeHasOpCode (NameOpCrsNode, AML_NAME_OP, 0)) ||
+ (!AmlNameOpCompareName (NameOpCrsNode, "_CRS")) ||
+ (OutRdNode == NULL)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *OutRdNode = NULL;
+
+ // Get the _CRS value which is represented as a BufferOp object node
+ // which is the 2nd fixed argument (i.e. index 1).
+ BufferOpNode = (AML_OBJECT_NODE_HANDLE)AmlGetFixedArgument (
+ NameOpCrsNode,
+ 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 (...) {...}
+ }
+ )
+
+ The CurrRdNode Resource Data node must be defined in an object named "_CRS"
+ and defined by a "Name ()" ASL function.
+
+ @param [in] CurrRdNode Pointer to the current Resource Data element of
+ the "_CRS" 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
+AmlNameOpCrsGetNextRdNode (
+ IN AML_DATA_NODE_HANDLE CurrRdNode,
+ OUT AML_DATA_NODE_HANDLE * OutRdNode
+ )
+{
+ AML_OBJECT_NODE_HANDLE NameOpCrsNode;
+ 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.
+ NameOpCrsNode = (AML_OBJECT_NODE_HANDLE)AmlGetParent (
+ (AML_NODE_HANDLE)BufferOpNode
+ );
+ if ((NameOpCrsNode == NULL) ||
+ (!AmlNodeHasOpCode (NameOpCrsNode, AML_NAME_OP, 0)) ||
+ (!AmlNameOpCompareName (NameOpCrsNode, "_CRS"))) {
+ 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;
+}