mirror of https://github.com/acidanthera/audk.git
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:
parent
3196253710
commit
c85ac5245c
|
@ -0,0 +1,631 @@
|
|||
/** @file
|
||||
AML Lib.
|
||||
|
||||
Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>
|
||||
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
**/
|
||||
|
||||
#ifndef AML_LIB_H_
|
||||
#define AML_LIB_H_
|
||||
|
||||
/**
|
||||
@mainpage Dynamic AML Generation
|
||||
@{
|
||||
@par Summary
|
||||
@{
|
||||
ACPI tables are categorized as data tables and definition block
|
||||
tables. Dynamic Tables Framework currently supports generation of ACPI
|
||||
data tables. Generation of definition block tables is difficult as these
|
||||
tables are encoded in ACPI Machine Language (AML), which has a complex
|
||||
grammar.
|
||||
|
||||
Dynamic AML Generation is an extension to the Dynamic tables Framework.
|
||||
One of the techniques used to simplify definition block generation is to
|
||||
fixup a template SSDT table.
|
||||
|
||||
Dynamic AML aims to provide a framework that allows fixing up of an ACPI
|
||||
SSDT template with appropriate information about the hardware.
|
||||
|
||||
This framework consists of an:
|
||||
- AMLLib core that implements a rich set of interfaces to parse, traverse
|
||||
and update AML data.
|
||||
- AMLLib library APIs that provides interfaces to search and updates nodes
|
||||
in the AML namespace.
|
||||
@}
|
||||
@}
|
||||
*/
|
||||
|
||||
#include <IndustryStandard/Acpi.h>
|
||||
|
||||
#ifndef AML_HANDLE
|
||||
|
||||
/** Node handle.
|
||||
*/
|
||||
typedef void* AML_NODE_HANDLE;
|
||||
|
||||
/** Root Node handle.
|
||||
*/
|
||||
typedef void* AML_ROOT_NODE_HANDLE;
|
||||
|
||||
/** Object Node handle.
|
||||
*/
|
||||
typedef void* AML_OBJECT_NODE_HANDLE;
|
||||
|
||||
/** Data Node handle.
|
||||
*/
|
||||
typedef void* AML_DATA_NODE_HANDLE;
|
||||
|
||||
#endif // AML_HANDLE
|
||||
|
||||
/** Parse the definition block.
|
||||
|
||||
The function parses the whole AML blob. It starts with the ACPI DSDT/SSDT
|
||||
header and then parses the AML bytestream.
|
||||
A tree structure is returned via the RootPtr.
|
||||
The tree must be deleted with the AmlDeleteTree function.
|
||||
|
||||
@ingroup UserApis
|
||||
|
||||
@param [in] DefinitionBlock Pointer to the definition block.
|
||||
@param [out] RootPtr Pointer to the root node of the AML tree.
|
||||
|
||||
@retval EFI_SUCCESS The function completed successfully.
|
||||
@retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
|
||||
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
||||
@retval EFI_OUT_OF_RESOURCES Could not allocate memory.
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
AmlParseDefinitionBlock (
|
||||
IN CONST EFI_ACPI_DESCRIPTION_HEADER * DefinitionBlock,
|
||||
OUT AML_ROOT_NODE_HANDLE * RootPtr
|
||||
);
|
||||
|
||||
/** Serialize an AML definition block.
|
||||
|
||||
This functions allocates memory with the "AllocateZeroPool ()"
|
||||
function. This memory is used to serialize the AML tree and is
|
||||
returned in the Table.
|
||||
|
||||
@ingroup UserApis
|
||||
|
||||
@param [in] RootNode Root node of the tree.
|
||||
@param [out] Table On return, hold the serialized
|
||||
definition block.
|
||||
|
||||
@retval EFI_SUCCESS The function completed successfully.
|
||||
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
||||
@retval EFI_OUT_OF_RESOURCES Could not allocate memory.
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
AmlSerializeDefinitionBlock (
|
||||
IN AML_ROOT_NODE_HANDLE RootNode,
|
||||
OUT EFI_ACPI_DESCRIPTION_HEADER ** Table
|
||||
);
|
||||
|
||||
/** Clone a node and its children (clone a tree branch).
|
||||
|
||||
The cloned branch returned is not attached to any tree.
|
||||
|
||||
@ingroup UserApis
|
||||
|
||||
@param [in] Node Pointer to a node.
|
||||
Node is the head of the branch to clone.
|
||||
@param [out] ClonedNode Pointer holding the head of the created cloned
|
||||
branch.
|
||||
|
||||
@retval EFI_SUCCESS The function completed successfully.
|
||||
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
||||
@retval EFI_OUT_OF_RESOURCES Could not allocate memory.
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
AmlCloneTree (
|
||||
IN AML_NODE_HANDLE Node,
|
||||
OUT AML_NODE_HANDLE * ClonedNode
|
||||
);
|
||||
|
||||
/** Delete a Node and its children.
|
||||
|
||||
The Node must be removed from the tree first,
|
||||
or must be the root node.
|
||||
|
||||
@ingroup UserApis
|
||||
|
||||
@param [in] Node Pointer to the node to delete.
|
||||
|
||||
@retval EFI_SUCCESS The function completed successfully.
|
||||
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
AmlDeleteTree (
|
||||
IN AML_NODE_HANDLE Node
|
||||
);
|
||||
|
||||
/** Detach the Node from the tree.
|
||||
|
||||
The function will fail if the Node is in its parent's fixed
|
||||
argument list.
|
||||
The Node is not deleted. The deletion is done separately
|
||||
from the removal.
|
||||
|
||||
@ingroup UserApis
|
||||
|
||||
@param [in] Node Pointer to a Node.
|
||||
Must be a data node or an object node.
|
||||
|
||||
@retval EFI_SUCCESS The function completed successfully.
|
||||
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
AmlDetachNode (
|
||||
IN AML_NODE_HANDLE Node
|
||||
);
|
||||
|
||||
/** Find a node in the AML namespace, given an ASL path and a reference Node.
|
||||
|
||||
- The AslPath can be an absolute path, or a relative path from the
|
||||
reference Node;
|
||||
- Node must be a root node or a namespace node;
|
||||
- A root node is expected to be at the top of the tree.
|
||||
|
||||
E.g.:
|
||||
For the following AML namespace, with the ReferenceNode being the node with
|
||||
the name "AAAA":
|
||||
- the node with the name "BBBB" can be found by looking for the ASL
|
||||
path "BBBB";
|
||||
- the root node can be found by looking for the ASL relative path "^",
|
||||
or the absolute path "\\".
|
||||
|
||||
AML namespace:
|
||||
\
|
||||
\-AAAA <- ReferenceNode
|
||||
\-BBBB
|
||||
|
||||
@ingroup NameSpaceApis
|
||||
|
||||
@param [in] ReferenceNode Reference node.
|
||||
If a relative path is given, the
|
||||
search is done from this node. If
|
||||
an absolute path is given, the
|
||||
search is done from the root node.
|
||||
Must be a root node or an object
|
||||
node which is part of the
|
||||
namespace.
|
||||
@param [in] AslPath ASL path to the searched node in
|
||||
the namespace. An ASL path name is
|
||||
NULL terminated. Can be a relative
|
||||
or absolute path.
|
||||
E.g.: "\\_SB.CLU0.CPU0" or "^CPU0"
|
||||
@param [out] OutNode Pointer to the found node.
|
||||
Contains NULL if not found.
|
||||
|
||||
@retval EFI_SUCCESS The function completed successfully.
|
||||
@retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
|
||||
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
||||
@retval EFI_OUT_OF_RESOURCES Out of memory.
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
AmlFindNode (
|
||||
IN AML_NODE_HANDLE ReferenceNode,
|
||||
IN CHAR8 * AslPath,
|
||||
OUT AML_NODE_HANDLE * OutNode
|
||||
);
|
||||
|
||||
/**
|
||||
@defgroup UserApis User APIs
|
||||
@{
|
||||
User APIs are implemented to ease most common actions that might be done
|
||||
using the AmlLib. They allow to find specific objects like "_UID" or
|
||||
"_CRS" and to update their value. It also shows what can be done using
|
||||
AmlLib functions.
|
||||
@}
|
||||
*/
|
||||
|
||||
/** Update the name of a DeviceOp object node.
|
||||
|
||||
@ingroup UserApis
|
||||
|
||||
@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
|
||||
);
|
||||
|
||||
/** Update an integer value defined by a NameOp object node.
|
||||
|
||||
For compatibility reasons, the NameOpNode must initially
|
||||
contain an integer.
|
||||
|
||||
@ingroup UserApis
|
||||
|
||||
@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
|
||||
);
|
||||
|
||||
/** 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.
|
||||
|
||||
@ingroup UserApis
|
||||
|
||||
@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
|
||||
);
|
||||
|
||||
/** 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.
|
||||
|
||||
@ingroup UserApis
|
||||
|
||||
@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
|
||||
);
|
||||
|
||||
/** 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.
|
||||
|
||||
@ingroup UserApis
|
||||
|
||||
@param [in] CurrRdNode Pointer to the current Resource Data element of
|
||||
the "_CRS" variable.
|
||||
@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
|
||||
);
|
||||
|
||||
/** 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.
|
||||
|
||||
@ingroup UserApis
|
||||
|
||||
@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
|
||||
);
|
||||
|
||||
/** Update the base address and length of a QWord resource data node.
|
||||
|
||||
@ingroup UserApis
|
||||
|
||||
@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
|
||||
);
|
||||
|
||||
/** Add an Interrupt Resource Data node.
|
||||
|
||||
This function creates a Resource Data element corresponding to the
|
||||
"Interrupt ()" ASL function, stores it in an AML Data Node.
|
||||
|
||||
It then adds it after the input CurrRdNode in the list of resource data
|
||||
element.
|
||||
|
||||
The Resource Data effectively created 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.
|
||||
|
||||
The Extended Interrupt contains one single interrupt.
|
||||
|
||||
This function allocates memory to create a data node. It is the caller's
|
||||
responsibility to either:
|
||||
- attach this node to an AML tree;
|
||||
- delete this node.
|
||||
|
||||
Note: The _CRS node must be defined using the ASL Name () function.
|
||||
e.g. Name (_CRS, ResourceTemplate () {
|
||||
...
|
||||
}
|
||||
|
||||
@ingroup UserApis
|
||||
|
||||
@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 [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 Could not allocate memory.
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
AmlCodeGenCrsAddRdInterrupt (
|
||||
IN AML_OBJECT_NODE_HANDLE NameOpCrsNode,
|
||||
IN BOOLEAN ResourceConsumer,
|
||||
IN BOOLEAN EdgeTriggered,
|
||||
IN BOOLEAN ActiveLow,
|
||||
IN BOOLEAN Shared,
|
||||
IN UINT32 * IrqList,
|
||||
IN UINT8 IrqCount
|
||||
);
|
||||
|
||||
/** AML code generation for DefinitionBlock.
|
||||
|
||||
Create a Root Node handle.
|
||||
It is the caller's responsibility to free the allocated memory
|
||||
with the AmlDeleteTree function.
|
||||
|
||||
AmlCodeGenDefinitionBlock (TableSignature, OemId, TableID, OEMRevision) is
|
||||
equivalent to the following ASL code:
|
||||
DefinitionBlock (AMLFileName, TableSignature, ComplianceRevision,
|
||||
OemId, TableID, OEMRevision) {}
|
||||
with the ComplianceRevision set to 2 and the AMLFileName is ignored.
|
||||
|
||||
@ingroup CodeGenApis
|
||||
|
||||
@param[in] TableSignature 4-character ACPI signature.
|
||||
Must be 'DSDT' or 'SSDT'.
|
||||
@param[in] OemId 6-character string OEM identifier.
|
||||
@param[in] OemTableId 8-character string OEM table identifier.
|
||||
@param[in] OemRevision OEM revision number.
|
||||
@param[out] DefinitionBlockTerm The ASL Term handle representing a
|
||||
Definition Block.
|
||||
|
||||
@retval EFI_SUCCESS Success.
|
||||
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
||||
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
AmlCodeGenDefinitionBlock (
|
||||
IN CONST CHAR8 * TableSignature,
|
||||
IN CONST CHAR8 * OemId,
|
||||
IN CONST CHAR8 * OemTableId,
|
||||
IN UINT32 OemRevision,
|
||||
OUT AML_ROOT_NODE_HANDLE * NewRootNode
|
||||
);
|
||||
|
||||
/** AML code generation for a Name object node, containing a String.
|
||||
|
||||
AmlCodeGenNameString ("_HID", "HID0000", ParentNode, NewObjectNode) is
|
||||
equivalent of the following ASL code:
|
||||
Name(_HID, "HID0000")
|
||||
|
||||
@ingroup CodeGenApis
|
||||
|
||||
@param [in] NameString The new variable name.
|
||||
Must be a NULL-terminated ASL NameString
|
||||
e.g.: "DEV0", "DV15.DEV0", etc.
|
||||
The input string is copied.
|
||||
@param [in] String NULL terminated String to associate to the
|
||||
NameString.
|
||||
@param [in] ParentNode If provided, set ParentNode as the parent
|
||||
of the node created.
|
||||
@param [out] NewObjectNode If success, contains the created node.
|
||||
|
||||
@retval EFI_SUCCESS Success.
|
||||
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
||||
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
AmlCodeGenNameString (
|
||||
IN CONST CHAR8 * NameString,
|
||||
IN CHAR8 * String,
|
||||
IN AML_NODE_HANDLE ParentNode, OPTIONAL
|
||||
OUT AML_OBJECT_NODE_HANDLE * NewObjectNode OPTIONAL
|
||||
);
|
||||
|
||||
/** AML code generation for a Name object node, containing an Integer.
|
||||
|
||||
AmlCodeGenNameInteger ("_UID", 1, ParentNode, NewObjectNode) is
|
||||
equivalent of the following ASL code:
|
||||
Name(_UID, One)
|
||||
|
||||
@ingroup CodeGenApis
|
||||
|
||||
@param [in] NameString The new variable name.
|
||||
Must be a NULL-terminated ASL NameString
|
||||
e.g.: "DEV0", "DV15.DEV0", etc.
|
||||
The input string is copied.
|
||||
@param [in] Integer Integer to associate to the NameString.
|
||||
@param [in] ParentNode If provided, set ParentNode as the parent
|
||||
of the node created.
|
||||
@param [out] NewObjectNode If success, contains the created node.
|
||||
|
||||
@retval EFI_SUCCESS Success.
|
||||
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
||||
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
AmlCodeGenNameInteger (
|
||||
IN CONST CHAR8 * NameString,
|
||||
IN UINT64 Integer,
|
||||
IN AML_NODE_HANDLE ParentNode, OPTIONAL
|
||||
OUT AML_OBJECT_NODE_HANDLE * NewObjectNode OPTIONAL
|
||||
);
|
||||
|
||||
/** AML code generation for a Device object node.
|
||||
|
||||
AmlCodeGenDevice ("COM0", ParentNode, NewObjectNode) is
|
||||
equivalent of the following ASL code:
|
||||
Device(COM0) {}
|
||||
|
||||
@ingroup CodeGenApis
|
||||
|
||||
@param [in] NameString The new Device's name.
|
||||
Must be a NULL-terminated ASL NameString
|
||||
e.g.: "DEV0", "DV15.DEV0", etc.
|
||||
The input string is copied.
|
||||
@param [in] ParentNode If provided, set ParentNode as the parent
|
||||
of the node created.
|
||||
@param [out] NewObjectNode If success, contains the created node.
|
||||
|
||||
@retval EFI_SUCCESS Success.
|
||||
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
||||
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
AmlCodeGenDevice (
|
||||
IN CONST CHAR8 * NameString,
|
||||
IN AML_NODE_HANDLE ParentNode, OPTIONAL
|
||||
OUT AML_OBJECT_NODE_HANDLE * NewObjectNode OPTIONAL
|
||||
);
|
||||
|
||||
/** AML code generation for a Scope object node.
|
||||
|
||||
AmlCodeGenScope ("_SB", ParentNode, NewObjectNode) is
|
||||
equivalent of the following ASL code:
|
||||
Scope(_SB) {}
|
||||
|
||||
@ingroup CodeGenApis
|
||||
|
||||
@param [in] NameString The new Scope's name.
|
||||
Must be a NULL-terminated ASL NameString
|
||||
e.g.: "DEV0", "DV15.DEV0", etc.
|
||||
The input string is copied.
|
||||
@param [in] ParentNode If provided, set ParentNode as the parent
|
||||
of the node created.
|
||||
@param [out] NewObjectNode If success, contains the created node.
|
||||
|
||||
@retval EFI_SUCCESS Success.
|
||||
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
||||
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
AmlCodeGenScope (
|
||||
IN CONST CHAR8 * NameString,
|
||||
IN AML_NODE_HANDLE ParentNode, OPTIONAL
|
||||
OUT AML_OBJECT_NODE_HANDLE * NewObjectNode OPTIONAL
|
||||
);
|
||||
|
||||
#endif // AML_LIB_H_
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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_
|
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue