mirror of https://github.com/acidanthera/audk.git
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;
|
|
}
|