DynamicTablesPkg: AmlLib APIs
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>
This commit is contained in:
committed by
mergify[bot]
parent
3196253710
commit
c85ac5245c
320
DynamicTablesPkg/Library/Common/AmlLib/Api/AmlResourceDataApi.c
Normal file
320
DynamicTablesPkg/Library/Common/AmlLib/Api/AmlResourceDataApi.c
Normal file
@@ -0,0 +1,320 @@
|
||||
/** @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;
|
||||
}
|
Reference in New Issue
Block a user