summaryrefslogtreecommitdiffstats
path: root/DynamicTablesPkg/Library/Common/AmlLib/Api/AmlResourceDataApi.c
diff options
context:
space:
mode:
authorPierre Gondois <pierre.gondois@arm.com>2020-08-05 15:43:33 +0100
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>2020-08-13 18:00:06 +0000
commitc85ac5245c0c47836fb9b599caff0b949066a412 (patch)
tree471c141145185ee96e7037838e214b408d3d7fd7 /DynamicTablesPkg/Library/Common/AmlLib/Api/AmlResourceDataApi.c
parent3196253710a1ed56b4dc04a728d33961ec7542c8 (diff)
downloadedk2-c85ac5245c0c47836fb9b599caff0b949066a412.tar.gz
edk2-c85ac5245c0c47836fb9b599caff0b949066a412.tar.bz2
edk2-c85ac5245c0c47836fb9b599caff0b949066a412.zip
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>
Diffstat (limited to 'DynamicTablesPkg/Library/Common/AmlLib/Api/AmlResourceDataApi.c')
-rw-r--r--DynamicTablesPkg/Library/Common/AmlLib/Api/AmlResourceDataApi.c320
1 files changed, 320 insertions, 0 deletions
diff --git a/DynamicTablesPkg/Library/Common/AmlLib/Api/AmlResourceDataApi.c b/DynamicTablesPkg/Library/Common/AmlLib/Api/AmlResourceDataApi.c
new file mode 100644
index 0000000000..913c8dcdb0
--- /dev/null
+++ b/DynamicTablesPkg/Library/Common/AmlLib/Api/AmlResourceDataApi.c
@@ -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;
+}