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