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>
		
			
				
	
	
		
			321 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			321 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  AML Update Resource Data.
 | 
						|
 | 
						|
  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 <CodeGen/AmlResourceDataCodeGen.h>
 | 
						|
 | 
						|
/** Update the first interrupt of an Interrupt resource data node.
 | 
						|
 | 
						|
  The flags of the Interrupt resource data are left unchanged.
 | 
						|
 | 
						|
  The InterruptRdNode corresponds to the Resource Data created by the
 | 
						|
  "Interrupt ()" ASL macro. It is an Extended Interrupt Resource Data.
 | 
						|
  See ACPI 6.3 specification, s6.4.3.6 "Extended Interrupt Descriptor"
 | 
						|
  for more information about Extended Interrupt Resource Data.
 | 
						|
 | 
						|
  @param  [in]  InterruptRdNode   Pointer to the an extended interrupt
 | 
						|
                                  resource data node.
 | 
						|
  @param  [in]  Irq               Interrupt value to update.
 | 
						|
 | 
						|
  @retval  EFI_SUCCESS            The function completed successfully.
 | 
						|
  @retval  EFI_INVALID_PARAMETER  Invalid parameter.
 | 
						|
  @retval  EFI_OUT_OF_RESOURCES   Out of resources.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
AmlUpdateRdInterrupt (
 | 
						|
  IN  AML_DATA_NODE_HANDLE    InterruptRdNode,
 | 
						|
  IN  UINT32                  Irq
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                    Status;
 | 
						|
  UINT32                      * FirstInterrupt;
 | 
						|
  UINT8                       * QueryBuffer;
 | 
						|
  UINT32                        QueryBufferSize;
 | 
						|
 | 
						|
  if ((InterruptRdNode == NULL)                                           ||
 | 
						|
      (AmlGetNodeType ((AML_NODE_HANDLE)InterruptRdNode) != EAmlNodeData) ||
 | 
						|
      (!AmlNodeHasDataType (
 | 
						|
          InterruptRdNode,
 | 
						|
          EAmlNodeDataTypeResourceData))                                  ||
 | 
						|
      (!AmlNodeHasRdDataType (
 | 
						|
          InterruptRdNode,
 | 
						|
          AML_RD_BUILD_LARGE_DESC_ID (
 | 
						|
            ACPI_LARGE_EXTENDED_IRQ_DESCRIPTOR_NAME)))) {
 | 
						|
    ASSERT (0);
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  QueryBuffer = NULL;
 | 
						|
 | 
						|
  // Get the size of the InterruptRdNode buffer.
 | 
						|
  Status = AmlGetDataNodeBuffer (
 | 
						|
             InterruptRdNode,
 | 
						|
             NULL,
 | 
						|
             &QueryBufferSize
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    ASSERT (0);
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  // Check the Buffer is large enough.
 | 
						|
  if (QueryBufferSize < sizeof (EFI_ACPI_EXTENDED_INTERRUPT_DESCRIPTOR)) {
 | 
						|
    ASSERT (0);
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  // Allocate a buffer to fetch the data.
 | 
						|
  QueryBuffer = AllocatePool (QueryBufferSize);
 | 
						|
  if (QueryBuffer == NULL) {
 | 
						|
    ASSERT (0);
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  // Get the data.
 | 
						|
  Status = AmlGetDataNodeBuffer (
 | 
						|
             InterruptRdNode,
 | 
						|
             QueryBuffer,
 | 
						|
             &QueryBufferSize
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    ASSERT (0);
 | 
						|
    goto error_handler;
 | 
						|
  }
 | 
						|
 | 
						|
  // Get the address of the first interrupt field.
 | 
						|
  FirstInterrupt =
 | 
						|
    ((EFI_ACPI_EXTENDED_INTERRUPT_DESCRIPTOR*)QueryBuffer)->InterruptNumber;
 | 
						|
 | 
						|
  *FirstInterrupt = Irq;
 | 
						|
 | 
						|
  // Update the InterruptRdNode buffer.
 | 
						|
  Status = AmlUpdateDataNode (
 | 
						|
             InterruptRdNode,
 | 
						|
             EAmlNodeDataTypeResourceData,
 | 
						|
             QueryBuffer,
 | 
						|
             QueryBufferSize
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    ASSERT (0);
 | 
						|
  }
 | 
						|
 | 
						|
error_handler:
 | 
						|
  if (QueryBuffer != NULL) {
 | 
						|
    FreePool (QueryBuffer);
 | 
						|
  }
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/** Update the interrupt list of an interrupt resource data node.
 | 
						|
 | 
						|
  The InterruptRdNode corresponds to the Resource Data created by the
 | 
						|
  "Interrupt ()" ASL function. It is an Extended Interrupt Resource Data.
 | 
						|
  See ACPI 6.3 specification, s6.4.3.6 "Extended Interrupt Descriptor"
 | 
						|
  for more information about Extended Interrupt Resource Data.
 | 
						|
 | 
						|
  @param  [in]  InterruptRdNode   Pointer to the an extended interrupt
 | 
						|
                                  resource data node.
 | 
						|
  @param  [in]  ResourceConsumer    The device consumes the specified interrupt
 | 
						|
                                    or produces it for use by a child device.
 | 
						|
  @param  [in]  EdgeTriggered       The interrupt is edge triggered or
 | 
						|
                                    level triggered.
 | 
						|
  @param  [in]  ActiveLow           The interrupt is active-high or active-low.
 | 
						|
  @param  [in]  Shared              The interrupt can be shared with other
 | 
						|
                                    devices or not (Exclusive).
 | 
						|
  @param  [in]  IrqList           Interrupt list. Must be non-NULL.
 | 
						|
  @param  [in]  IrqCount          Interrupt count. Must be non-zero.
 | 
						|
 | 
						|
 | 
						|
  @retval  EFI_SUCCESS            The function completed successfully.
 | 
						|
  @retval  EFI_INVALID_PARAMETER  Invalid parameter.
 | 
						|
  @retval  EFI_OUT_OF_RESOURCES   Out of resources.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
AmlUpdateRdInterruptEx (
 | 
						|
  IN  AML_DATA_NODE_HANDLE    InterruptRdNode,
 | 
						|
  IN  BOOLEAN                 ResourceConsumer,
 | 
						|
  IN  BOOLEAN                 EdgeTriggered,
 | 
						|
  IN  BOOLEAN                 ActiveLow,
 | 
						|
  IN  BOOLEAN                 Shared,
 | 
						|
  IN  UINT32                * IrqList,
 | 
						|
  IN  UINT8                   IrqCount
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                                 Status;
 | 
						|
 | 
						|
  EFI_ACPI_EXTENDED_INTERRUPT_DESCRIPTOR   * RdInterrupt;
 | 
						|
  UINT32                                   * FirstInterrupt;
 | 
						|
  UINT8                                    * UpdateBuffer;
 | 
						|
  UINT16                                     UpdateBufferSize;
 | 
						|
 | 
						|
  if ((InterruptRdNode == NULL)                                              ||
 | 
						|
      (AmlGetNodeType ((AML_NODE_HANDLE)InterruptRdNode) != EAmlNodeData)    ||
 | 
						|
      (!AmlNodeHasDataType (
 | 
						|
          InterruptRdNode,
 | 
						|
          EAmlNodeDataTypeResourceData))                                     ||
 | 
						|
      (!AmlNodeHasRdDataType (
 | 
						|
          InterruptRdNode,
 | 
						|
          AML_RD_BUILD_LARGE_DESC_ID (
 | 
						|
            ACPI_LARGE_EXTENDED_IRQ_DESCRIPTOR_NAME)))                       ||
 | 
						|
      (IrqList == NULL)                                                      ||
 | 
						|
      (IrqCount == 0)) {
 | 
						|
    ASSERT (0);
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  UpdateBuffer = NULL;
 | 
						|
  UpdateBufferSize = sizeof (EFI_ACPI_EXTENDED_INTERRUPT_DESCRIPTOR) +
 | 
						|
                       ((IrqCount - 1) * sizeof (UINT32));
 | 
						|
 | 
						|
  // Allocate a buffer to update the data.
 | 
						|
  UpdateBuffer = AllocatePool (UpdateBufferSize);
 | 
						|
  if (UpdateBuffer == NULL) {
 | 
						|
    ASSERT (0);
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  // Update the Resource Data information (structure size, interrupt count).
 | 
						|
  RdInterrupt = (EFI_ACPI_EXTENDED_INTERRUPT_DESCRIPTOR*)UpdateBuffer;
 | 
						|
  RdInterrupt->Header.Header.Byte =
 | 
						|
     AML_RD_BUILD_LARGE_DESC_ID (ACPI_LARGE_EXTENDED_IRQ_DESCRIPTOR_NAME);
 | 
						|
  RdInterrupt->Header.Length =
 | 
						|
    UpdateBufferSize - sizeof (ACPI_LARGE_RESOURCE_HEADER);
 | 
						|
  RdInterrupt->InterruptTableLength = IrqCount;
 | 
						|
  RdInterrupt->InterruptVectorFlags = (ResourceConsumer ? BIT0 : 0) |
 | 
						|
                                      (EdgeTriggered ? BIT1 : 0)    |
 | 
						|
                                      (ActiveLow ? BIT2 : 0)        |
 | 
						|
                                      (Shared ? BIT3 : 0);
 | 
						|
 | 
						|
  // Get the address of the first interrupt field.
 | 
						|
  FirstInterrupt =
 | 
						|
    ((EFI_ACPI_EXTENDED_INTERRUPT_DESCRIPTOR*)UpdateBuffer)->InterruptNumber;
 | 
						|
 | 
						|
  // Copy the input list of interrupts.
 | 
						|
  CopyMem (FirstInterrupt, IrqList, (sizeof (UINT32) * IrqCount));
 | 
						|
 | 
						|
  // Update the InterruptRdNode buffer.
 | 
						|
  Status = AmlUpdateDataNode (
 | 
						|
             InterruptRdNode,
 | 
						|
             EAmlNodeDataTypeResourceData,
 | 
						|
             UpdateBuffer,
 | 
						|
             UpdateBufferSize
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    ASSERT (0);
 | 
						|
  }
 | 
						|
 | 
						|
  // Cleanup
 | 
						|
  FreePool (UpdateBuffer);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/** Update the base address and length of a QWord resource data node.
 | 
						|
 | 
						|
  @param  [in] QWordRdNode         Pointer a QWord resource data
 | 
						|
                                   node.
 | 
						|
  @param  [in] BaseAddress         Base address.
 | 
						|
  @param  [in] BaseAddressLength   Base address length.
 | 
						|
 | 
						|
  @retval  EFI_SUCCESS            The function completed successfully.
 | 
						|
  @retval  EFI_INVALID_PARAMETER  Invalid parameter.
 | 
						|
  @retval  EFI_OUT_OF_RESOURCES   Out of resources.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
AmlUpdateRdQWord (
 | 
						|
  IN  AML_DATA_NODE_HANDLE  QWordRdNode,
 | 
						|
  IN  UINT64                BaseAddress,
 | 
						|
  IN  UINT64                BaseAddressLength
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                                 Status;
 | 
						|
  EFI_ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR  * RdQWord;
 | 
						|
 | 
						|
  UINT8                                    * QueryBuffer;
 | 
						|
  UINT32                                     QueryBufferSize;
 | 
						|
 | 
						|
  if ((QWordRdNode == NULL)                                             ||
 | 
						|
      (AmlGetNodeType ((AML_NODE_HANDLE)QWordRdNode) != EAmlNodeData)   ||
 | 
						|
      (!AmlNodeHasDataType (QWordRdNode, EAmlNodeDataTypeResourceData)) ||
 | 
						|
      (!AmlNodeHasRdDataType (
 | 
						|
          QWordRdNode,
 | 
						|
          AML_RD_BUILD_LARGE_DESC_ID (
 | 
						|
            ACPI_LARGE_QWORD_ADDRESS_SPACE_DESCRIPTOR_NAME)))) {
 | 
						|
    ASSERT (0);
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  // Get the size of the QWordRdNode's buffer.
 | 
						|
  Status = AmlGetDataNodeBuffer (
 | 
						|
             QWordRdNode,
 | 
						|
             NULL,
 | 
						|
             &QueryBufferSize
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    ASSERT (0);
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  // Allocate a buffer to fetch the data.
 | 
						|
  QueryBuffer = AllocatePool (QueryBufferSize);
 | 
						|
  if (QueryBuffer == NULL) {
 | 
						|
    ASSERT (0);
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  // Get the data.
 | 
						|
  Status = AmlGetDataNodeBuffer (
 | 
						|
             QWordRdNode,
 | 
						|
             QueryBuffer,
 | 
						|
             &QueryBufferSize
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    ASSERT (0);
 | 
						|
    goto error_handler;
 | 
						|
  }
 | 
						|
 | 
						|
  RdQWord = (EFI_ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR*)QueryBuffer;
 | 
						|
 | 
						|
  // Update the Base Address and Length.
 | 
						|
  RdQWord->AddrRangeMin = BaseAddress;
 | 
						|
  RdQWord->AddrRangeMax = BaseAddress + BaseAddressLength - 1;
 | 
						|
  RdQWord->AddrLen = BaseAddressLength;
 | 
						|
 | 
						|
  // Update Base Address Resource Data node.
 | 
						|
  Status = AmlUpdateDataNode (
 | 
						|
             QWordRdNode,
 | 
						|
             EAmlNodeDataTypeResourceData,
 | 
						|
             QueryBuffer,
 | 
						|
             QueryBufferSize
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    ASSERT (0);
 | 
						|
  }
 | 
						|
 | 
						|
error_handler:
 | 
						|
  if (QueryBuffer != NULL) {
 | 
						|
    FreePool (QueryBuffer);
 | 
						|
  }
 | 
						|
  return Status;
 | 
						|
}
 |