AmlLib library implements an AML parser, AML tree interface, serialiser, code generator and other interfaces to generate Definition Block tables. The AmlLib APIs are a collection of interfaces that enable parsing, iterating, modifying, adding, and serialising AML data to generate a Definition Block table. The AmlLib APIs are declared in Include\AmlLib\AmlLib.h Signed-off-by: Pierre Gondois <pierre.gondois@arm.com> Signed-off-by: Sami Mujawar <sami.mujawar@arm.com> Reviewed-by: Alexei Fedorov <Alexei.Fedorov@arm.com>
		
			
				
	
	
		
			383 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			383 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @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;
 | 
						|
}
 |