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:
Pierre Gondois
2020-08-05 15:43:33 +01:00
committed by mergify[bot]
parent 3196253710
commit c85ac5245c
5 changed files with 1645 additions and 0 deletions

View File

@@ -0,0 +1,382 @@
/** @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;
}

View File

@@ -0,0 +1,219 @@
/** @file
AML Helper.
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 <Api/AmlApiHelper.h>
#include <AmlCoreInterface.h>
#include <AmlInclude.h>
#include <String/AmlString.h>
/** Compare the NameString defined by the "Name ()" ASL function,
and stored in the NameOpNode, with the input NameString.
An ASL NameString is expected to be NULL terminated, and can be composed
of NameSegs that have less that 4 chars, like "DEV". "DEV" will be expanded
as "DEV_".
An AML NameString is not NULL terminated and is is only composed of
4 chars long NameSegs.
@param [in] NameOpNode NameOp object node defining a variable.
Must have an AML_NAME_OP/0 OpCode/SubOpCode.
NameOp object nodes are defined in ASL
using the "Name ()" function.
@param [in] AslName ASL NameString to compare the NameOp's name with.
Must be NULL terminated.
@retval TRUE If the AslName and the AmlName defined by the NameOp node
are similar.
@retval FALSE Otherwise.
**/
BOOLEAN
EFIAPI
AmlNameOpCompareName (
IN AML_OBJECT_NODE_HANDLE NameOpNode,
IN CHAR8 * AslName
)
{
EFI_STATUS Status;
AML_DATA_NODE_HANDLE NameDataNode;
CHAR8 * AmlName;
UINT32 AmlNameSize;
BOOLEAN RetVal;
if ((NameOpNode == NULL) ||
(AmlGetNodeType ((AML_NODE_HANDLE)NameOpNode) != EAmlNodeObject) ||
(!AmlNodeHasOpCode (NameOpNode, AML_NAME_OP, 0)) ||
(AslName == NULL)) {
ASSERT (0);
return FALSE;
}
// Get the NameOp name, being in a data node
// which is the first fixed argument (i.e. index 0).
NameDataNode = (AML_DATA_NODE_HANDLE)AmlGetFixedArgument (
NameOpNode,
EAmlParseIndexTerm0
);
if ((NameDataNode == NULL) ||
(AmlGetNodeType ((AML_NODE_HANDLE)NameDataNode) != EAmlNodeData) ||
(!AmlNodeHasDataType (NameDataNode, EAmlNodeDataTypeNameString))) {
ASSERT (0);
return FALSE;
}
// Get the size of the name.
Status = AmlGetDataNodeBuffer (NameDataNode, NULL, &AmlNameSize);
if (EFI_ERROR (Status)) {
ASSERT (0);
return FALSE;
}
// Allocate memory to fetch the name.
AmlName = AllocateZeroPool (AmlNameSize);
if (AmlName == NULL) {
ASSERT (0);
return FALSE;
}
// Fetch the name.
Status = AmlGetDataNodeBuffer (NameDataNode, (UINT8*)AmlName, &AmlNameSize);
if (EFI_ERROR (Status)) {
FreePool (AmlName);
ASSERT (0);
return FALSE;
}
// Compare the input AslName and the AmlName stored in the NameOp node.
RetVal = CompareAmlWithAslNameString (AmlName, AslName);
// Free the string buffer.
FreePool (AmlName);
return RetVal;
}
/** Check whether ObjectNode has the input OpCode/SubOpcode couple.
@param [in] ObjectNode Pointer to an object node.
@param [in] OpCode OpCode to check
@param [in] SubOpCode SubOpCode to check
@retval TRUE The node is an object node and
the Opcode and SubOpCode match.
@retval FALSE Otherwise.
**/
BOOLEAN
EFIAPI
AmlNodeHasOpCode (
IN AML_OBJECT_NODE_HANDLE ObjectNode,
IN UINT8 OpCode,
IN UINT8 SubOpCode
)
{
EFI_STATUS Status;
UINT8 NodeOpCode;
UINT8 NodeSubOpCode;
// Get the Node information.
Status = AmlGetObjectNodeInfo (
ObjectNode,
&NodeOpCode,
&NodeSubOpCode,
NULL,
NULL
);
if (EFI_ERROR (Status)) {
ASSERT (0);
return FALSE;
}
// Check the OpCode and SubOpCode.
if ((OpCode != NodeOpCode) ||
(SubOpCode != NodeSubOpCode)) {
return FALSE;
}
return TRUE;
}
/** Check whether DataNode has the input DataType.
@param [in] DataNode Pointer to a data node.
@param [in] DataType DataType to check.
@retval TRUE The node is a data node and
the DataType match.
@retval FALSE Otherwise.
**/
BOOLEAN
EFIAPI
AmlNodeHasDataType (
IN AML_DATA_NODE_HANDLE DataNode,
IN EAML_NODE_DATA_TYPE DataType
)
{
EFI_STATUS Status;
EAML_NODE_DATA_TYPE NodeDataType;
// Get the data type.
Status = AmlGetNodeDataType (DataNode, &NodeDataType);
if (EFI_ERROR (Status)) {
ASSERT (0);
return FALSE;
}
// Check the data type.
if (NodeDataType != DataType) {
return FALSE;
}
return TRUE;
}
/** Check whether RdNode has the input RdDataType.
@param [in] RdNode Pointer to a data node.
@param [in] RdDataType DataType to check.
@retval TRUE The node is a Resource Data node and
the RdDataType match.
@retval FALSE Otherwise.
**/
BOOLEAN
EFIAPI
AmlNodeHasRdDataType (
IN AML_DATA_NODE_HANDLE RdNode,
IN AML_RD_HEADER RdDataType
)
{
EFI_STATUS Status;
AML_RD_HEADER NodeRdDataType;
// Get the resource data type.
Status = AmlGetResourceDataType (
RdNode,
&NodeRdDataType
);
if (EFI_ERROR (Status)) {
ASSERT (0);
return FALSE;
}
// Check the RdDataType.
return AmlRdCompareDescId (&NodeRdDataType, RdDataType);
}

View File

@@ -0,0 +1,93 @@
/** @file
AML Helper.
Copyright (c) 2020, Arm Limited. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#ifndef AML_HELPER_H_
#define AML_HELPER_H_
#include <AmlNodeDefines.h>
#include <ResourceData/AmlResourceData.h>
/** Compare the NameString defined by the "Name ()" ASL function,
and stored in the NameOpNode, with the input NameString.
An ASL NameString is expected to be NULL terminated, and can be composed
of NameSegs that have less that 4 chars, like "DEV". "DEV" will be expanded
as "DEV_".
An AML NameString is not NULL terminated and is is only composed of
4 chars long NameSegs.
@param [in] NameOpNode NameOp object node defining a variable.
Must have an AML_NAME_OP/0 OpCode/SubOpCode.
NameOp object nodes are defined in ASL
using the "Name ()" function.
@param [in] AslName ASL NameString to compare the NameOp's name with.
Must be NULL terminated.
@retval TRUE If the AslName and the AmlName defined by the NameOp node
are similar.
@retval FALSE Otherwise.
**/
BOOLEAN
EFIAPI
AmlNameOpCompareName (
IN AML_OBJECT_NODE_HANDLE NameOpNode,
IN CHAR8 * AslName
);
/** Check whether ObjectNode has the input OpCode/SubOpcode couple.
@param [in] ObjectNode Pointer to an object node.
@param [in] OpCode OpCode to check
@param [in] SubOpCode SubOpCode to check
@retval TRUE The node is an object node and
the Opcode and SubOpCode match.
@retval FALSE Otherwise.
**/
BOOLEAN
EFIAPI
AmlNodeHasOpCode (
IN AML_OBJECT_NODE_HANDLE ObjectNode,
IN UINT8 OpCode,
IN UINT8 SubOpCode
);
/** Check whether DataNode has the input DataType.
@param [in] DataNode Pointer to a data node.
@param [in] DataType DataType to check.
@retval TRUE The node is a data node and
the DataType match.
@retval FALSE Otherwise.
**/
BOOLEAN
EFIAPI
AmlNodeHasDataType (
IN AML_DATA_NODE_HANDLE DataNode,
IN EAML_NODE_DATA_TYPE DataType
);
/** Check whether RdNode has the input RdDataType.
@param [in] RdNode Pointer to a data node.
@param [in] RdDataType DataType to check.
@retval TRUE The node is a Resource Data node and
the RdDataType match.
@retval FALSE Otherwise.
**/
BOOLEAN
EFIAPI
AmlNodeHasRdDataType (
IN AML_DATA_NODE_HANDLE RdNode,
IN AML_RD_HEADER RdDataType
);
#endif // AML_HELPER_H_

View 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;
}