mirror of https://github.com/acidanthera/audk.git
1497 lines
48 KiB
C
1497 lines
48 KiB
C
/** @file
|
|
AML NameSpace.
|
|
|
|
Copyright (c) 2019 - 2021, Arm Limited. All rights reserved.<BR>
|
|
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
**/
|
|
|
|
/* Lexicon:
|
|
|
|
NameSeg:
|
|
- An ASL NameSeg is a name made of at most 4 chars.
|
|
Cf. ACPI 6.3 specification, s19.2.2 'Name and Pathname Terms'.
|
|
- An AML NameSeg is a name made of 4 chars.
|
|
Cf. ACPI 6.3 specification, s20.2.2 'Name Objects Encoding'.
|
|
|
|
NameString:
|
|
A NameString is analogous to a pathname. It is made of 0 to 255 NameSegs.
|
|
A NameString can be prefixed by a root char ('\') or 0 to 255 carets ('^').
|
|
|
|
A NameString can be ASL or AML encoded.
|
|
AML NameStrings can have a NameString prefix (dual or multi-name prefix)
|
|
between the root/carets and the list of NameSegs. If the prefix is the
|
|
multi-name prefix, then the number of NameSegs is encoded on one single byte.
|
|
Cf. ACPI 6.3 specification, s19.2.2 'Name and Pathname Terms'.
|
|
Cf. ACPI 6.3 specification, s20.2.2 'Name Objects Encoding'.
|
|
|
|
Namespace level:
|
|
One level in the AML Namespace level corresponds to one NameSeg. In ASL,
|
|
objects names are NameStrings. This means a device can have a name which
|
|
spans multiple levels.
|
|
E.g.: The ASL code: Device (CLU0.CPU0) corresponds to 2 levels.
|
|
|
|
Namespace node:
|
|
A namespace node is an object node which has an associated name, and which
|
|
changes the current scope.
|
|
E.g.:
|
|
1. The "Device ()" ASL statement adds a name to the AML namespace and
|
|
changes the current scope to the device scope, this is a namespace node.
|
|
2. The "Scope ()" ASL statement changes the current scope, this is a
|
|
namespace node.
|
|
3. A method invocation has a name, but does not add nor change the current
|
|
AML scope. This is not a namespace node.
|
|
|
|
- Object nodes with the AML_IN_NAMESPACE attribute are namespace nodes.
|
|
Buffers (), Packages (), etc. are not part of the namespace. It is however
|
|
possible to associate them with a name with the Name () ASL statement.
|
|
- The root node is considered as being part of the namespace.
|
|
- Some resource data elements can have a name when defining them in
|
|
an ASL statement. However, this name is stripped by the ASL compiler.
|
|
Thus, they don't have a name in the AML bytestream, and are therefore
|
|
not part of the AML namespace.
|
|
- Field list elements are part of the namespace.
|
|
Fields created by an CreateXXXField () ASL statement are part of the
|
|
namespace. The name of these node can be found in the third or fourth
|
|
fixed argument. The exact index of the name can be found in the NameIndex
|
|
field of the AML_BYTE_ENCODING array.
|
|
Field are at the same level as their ASL statement in the namespace.
|
|
E.g:
|
|
Scope (\) {
|
|
OperationRegion (REG0, SystemIO, 0x100, 0x100)
|
|
Field (REG0, ByteAcc, NoLock, Preserve) {
|
|
FIE0, 1,
|
|
FIE1, 5
|
|
}
|
|
|
|
Name (BUF0, Buffer (100) {})
|
|
CreateField (BUF0, 5, 2, MEM0)
|
|
}
|
|
|
|
produces this namespace:
|
|
\ (Root)
|
|
\-REG0
|
|
\-FIE0
|
|
\-FIE1
|
|
\-BUF0
|
|
\-MEM0
|
|
|
|
Raw AML pathname or Raw AML NameString:
|
|
In order to easily manipulate AML NameStrings, the non-NameSegs chars are
|
|
removed in raw pathnames/NameStrings. Non-NameSegs chars are the
|
|
root char ('\'), carets ('^') and NameString prefixes (Dual/Multi name char).
|
|
E.g. The following terminology is defined in this AML Library.
|
|
ASL absolute path: "[RootChar]AAAA.BBBB.CCCC\0"
|
|
AML absolute path: "[RootChar][MultiNamePrefix][3(NameSegs)]AAAABBBBCCCC"
|
|
Raw absolute path: "AAAABBBBCCCC"
|
|
|
|
Multi-name:
|
|
A NameString with at least 2 NameSegs. A node can have a name which spans
|
|
multiple namespace levels.
|
|
*/
|
|
|
|
#include <NameSpace/AmlNameSpace.h>
|
|
|
|
#include <AmlCoreInterface.h>
|
|
#include <AmlDbgPrint/AmlDbgPrint.h>
|
|
#include <String/AmlString.h>
|
|
#include <Tree/AmlNode.h>
|
|
#include <Tree/AmlTree.h>
|
|
#include <Tree/AmlTreeTraversal.h>
|
|
|
|
/** Context of the path search callback function.
|
|
|
|
The function finding a node from a path and a reference node enumerates
|
|
the namespace nodes in the tree and compares their absolute path with the
|
|
searched path. The enumeration function uses a callback function that can
|
|
receive a context.
|
|
This structure is used to store the context information required in the
|
|
callback function.
|
|
*/
|
|
typedef struct AmlPathSearchContext {
|
|
/// Backward stream holding the raw AML absolute searched path.
|
|
AML_STREAM * SearchPathBStream;
|
|
|
|
/// An empty backward stream holding a pre-allocated buffer. This prevents
|
|
/// from having to do multiple allocations during the search.
|
|
/// This stream is used to query the raw AML absolute path of the node
|
|
/// currently being probed.
|
|
AML_STREAM * CurrNodePathBStream;
|
|
|
|
/// If the node being visited is the node being searched,
|
|
/// i.e. its path and the searched path match,
|
|
/// save its reference in this pointer.
|
|
AML_NODE_HEADER * OutNode;
|
|
} AML_PATH_SEARCH_CONTEXT;
|
|
|
|
/** Return the first AML namespace node up in the parent hierarchy.
|
|
|
|
Return the root node if no namespace node is found is the hierarchy.
|
|
|
|
@param [in] Node Node to look at the parents from.
|
|
If Node is the root node, OutNode is NULL.
|
|
@param [out] OutNode If a namespace node is found, pointer to the
|
|
first namespace node of Node's parents.
|
|
Stop at the root node otherwise.
|
|
|
|
@retval EFI_SUCCESS The function completed successfully.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
AmlGetFirstAncestorNameSpaceNode (
|
|
IN CONST AML_NODE_HEADER * Node,
|
|
OUT AML_NODE_HEADER ** OutNode
|
|
)
|
|
{
|
|
if (!IS_AML_NODE_VALID (Node) ||
|
|
(OutNode == NULL)) {
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
// If Node is the root node, return NULL.
|
|
if (IS_AML_ROOT_NODE (Node)) {
|
|
*OutNode = NULL;
|
|
return EFI_SUCCESS;
|
|
} else {
|
|
// Else, get the parent node.
|
|
Node = AmlGetParent ((AML_NODE_HEADER*)Node);
|
|
if (!IS_AML_NODE_VALID (Node)) {
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
// Continue getting the parent node while no namespace node is encountered.
|
|
while (TRUE) {
|
|
if (IS_AML_ROOT_NODE (Node)) {
|
|
break;
|
|
} else if (AmlNodeHasAttribute (
|
|
(CONST AML_OBJECT_NODE*)Node,
|
|
AML_IN_NAMESPACE
|
|
)) {
|
|
break;
|
|
} else {
|
|
Node = AmlGetParent ((AML_NODE_HEADER*)Node);
|
|
if (!IS_AML_NODE_VALID (Node)) {
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
} // while
|
|
|
|
*OutNode = (AML_NODE_HEADER*)Node;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/** Climb up the AML namespace hierarchy.
|
|
|
|
This function get the ancestor namespace node in the AML namespace.
|
|
If Levels is not zero, skip Levels namespace nodes in the AML namespace.
|
|
If Levels is zero, return the first ancestor namespace node.
|
|
I.e. if Levels = n, this function returns the (n + 1) ancestor.
|
|
|
|
@param [in] Node Pointer to an object node.
|
|
@param [in, out] Levels Pointer holding a number of AML namespace levels:
|
|
- At entry, the number of levels to go up in
|
|
the AML namespace;
|
|
- At exit, the number of levels that still need
|
|
to be climbed in case of a multi-named node.
|
|
Indeed, if a node with a multi-name is found,
|
|
and Levels is less than the number of NameSegs
|
|
in this name, then the function returns with
|
|
the number of levels that still need to be
|
|
climbed.
|
|
E.g.: If the first ancestor node's name is
|
|
"AAAA.BBBB.CCCC" and
|
|
Levels = 2 -> i.e go up 3 levels
|
|
\
|
|
...
|
|
\-"AAAA.BBBB.CCCC" <----- OutNode
|
|
\-"DDDD" <----- Node (Input)
|
|
|
|
The function should ideally return a node
|
|
with the name "AAAA". However, it is not
|
|
possible to split the node name
|
|
"AAAA.BBBB.CCCC" to "AAAA".
|
|
Thus, OutNode is set to the input node,
|
|
and Levels = 2.
|
|
In most cases the number of levels to climb
|
|
correspond to non multi-name node, and therefore
|
|
Levels = 0 at exit.
|
|
@param [out] HasRoot The returned node in OutNode has an AML absolute
|
|
name, starting with a root char ('\'), or if OutNode
|
|
is the root node.
|
|
@param [out] OutNode The Levels+1 namespace ancestor of the input node in
|
|
the AML namespace. Must be the root node or a
|
|
namespace node.
|
|
|
|
@retval EFI_SUCCESS The function completed successfully.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
AmlGetAncestorNameSpaceNode (
|
|
IN CONST AML_OBJECT_NODE * Node,
|
|
IN OUT UINT32 * Levels,
|
|
OUT UINT32 * HasRoot,
|
|
OUT CONST AML_NODE_HEADER ** OutNode
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
CONST AML_NODE_HEADER * NameSpaceNode;
|
|
CHAR8 * NodeName;
|
|
UINT32 ParentCnt;
|
|
|
|
UINT32 Root;
|
|
UINT32 ParentPrefix;
|
|
UINT32 SegCount;
|
|
|
|
if (!IS_AML_OBJECT_NODE (Node) ||
|
|
(Levels == NULL) ||
|
|
(HasRoot == NULL) ||
|
|
(OutNode == NULL)) {
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
ParentCnt = *Levels;
|
|
*HasRoot = 0;
|
|
|
|
// ParentCnt namespace levels need to be climbed.
|
|
do {
|
|
// Get the next namespace node in the hierarchy.
|
|
Status = AmlGetFirstAncestorNameSpaceNode (
|
|
(CONST AML_NODE_HEADER*)Node,
|
|
(AML_NODE_HEADER**)&NameSpaceNode
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
Node = (CONST AML_OBJECT_NODE*)NameSpaceNode;
|
|
|
|
if (IS_AML_ROOT_NODE (Node)) {
|
|
// Node is the root node. It is not possible to go beyond.
|
|
if (ParentCnt != 0) {
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
*HasRoot = 1;
|
|
break;
|
|
}
|
|
|
|
NodeName = AmlNodeGetName ((CONST AML_OBJECT_NODE*)Node);
|
|
if (NodeName == NULL) {
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
// Analyze the node name.
|
|
Status = AmlParseNameStringInfo (
|
|
NodeName,
|
|
&Root,
|
|
&ParentPrefix,
|
|
&SegCount
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
if (Root != 0) {
|
|
// NodeName is an absolute pathname.
|
|
*HasRoot = Root;
|
|
|
|
// If the node has Root then it cannot have ParentPrefixes (Carets).
|
|
if (ParentPrefix != 0) {
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (SegCount == ParentCnt) {
|
|
// There are exactly enough AML namespace levels to consume.
|
|
// This means the root node was the searched node.
|
|
Node = (CONST AML_OBJECT_NODE*)AmlGetRootNode (
|
|
(CONST AML_NODE_HEADER*)Node
|
|
);
|
|
if (!IS_AML_ROOT_NODE (Node)) {
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
ParentCnt = 0;
|
|
break;
|
|
} else if (ParentCnt < SegCount) {
|
|
// There are too many AML namespace levels in this name.
|
|
// ParentCnt has the right value, just return.
|
|
break;
|
|
} else {
|
|
// ParentCnt > SegCount
|
|
// Return error as there must be at least ParentCnt AML namespace
|
|
// levels left in the absolute path.
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
} else {
|
|
// Root is 0.
|
|
if (ParentCnt < SegCount) {
|
|
// NodeName is a relative path.
|
|
// NodeName has enough levels to consume all the ParentCnt.
|
|
// Exit.
|
|
break;
|
|
} else if (SegCount == ParentCnt) {
|
|
// There are exactly enough AML namespace levels to consume.
|
|
if (ParentPrefix == 0) {
|
|
// The node name doesn't have any carets. Get the next namespace
|
|
// node and return.
|
|
Status = AmlGetFirstAncestorNameSpaceNode (
|
|
(CONST AML_NODE_HEADER*)Node,
|
|
(AML_NODE_HEADER**)&NameSpaceNode
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
Node = (CONST AML_OBJECT_NODE*)NameSpaceNode;
|
|
ParentCnt = 0;
|
|
break;
|
|
} else {
|
|
// The node name has carets. Need to continue climbing the
|
|
// AML namespace.
|
|
ParentCnt = ParentPrefix;
|
|
}
|
|
} else {
|
|
// ParentCnt > SegCount
|
|
// NodeName doesn't have enough levels to consume all the ParentCnt.
|
|
// Update ParentCnt: Consume SegCount levels and add ParentPrefix
|
|
// levels. Continue climbing the tree.
|
|
ParentCnt = ParentCnt + ParentPrefix - SegCount;
|
|
}
|
|
}
|
|
} while (ParentCnt != 0);
|
|
|
|
*OutNode = (CONST AML_NODE_HEADER*)Node;
|
|
*Levels = ParentCnt;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/** Build the raw absolute AML pathname to Node and write it to a stream.
|
|
|
|
A raw AML pathname is an AML pathname where the root char ('\'),
|
|
prefix chars ('^') and NameString prefix byte (e.g.: DualNamePrefix)
|
|
have been removed. A raw AML pathname is a list of concatenated
|
|
NameSegs.
|
|
|
|
E.g.:
|
|
ASL absolute path: "[RootChar]AAAA.BBBB.CCCC\0"
|
|
AML absolute path: "[RootChar][MultiNamePrefix][3(NameSegs)]AAAABBBBCCCC"
|
|
Raw absolute path: "AAAABBBBCCCC"
|
|
|
|
@param [in] Node Node to build the raw absolute path to
|
|
Must be a root node, or a namespace node.
|
|
@param [in] InputParent Skip InputParent AML namespace levels before
|
|
starting building the raw absolute pathname.
|
|
E.g.: - Node's name being "^AAAA.BBBB.CCCC";
|
|
- InputParent = 2;
|
|
"BBBB.CCCC" will be skipped (2
|
|
levels), and "^AAAA" will remain. The
|
|
first caret is not related to InputParent.
|
|
@param [out] RawAbsPathBStream Backward stream to write the raw
|
|
pathname to.
|
|
If Node is the root node, the Stream data
|
|
Buffer will stay empty.
|
|
The stream must not be at its end.
|
|
|
|
@retval EFI_SUCCESS The function completed successfully.
|
|
@retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
AmlGetRawNameSpacePath (
|
|
IN CONST AML_NODE_HEADER * Node,
|
|
IN UINT32 InputParent,
|
|
OUT AML_STREAM * RawAbsPathBStream
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
AML_NODE_HEADER * ParentNode;
|
|
CHAR8 * NodeName;
|
|
|
|
UINT32 Root;
|
|
UINT32 ParentPrefix;
|
|
UINT32 SegCount;
|
|
CONST CHAR8 * NameSeg;
|
|
|
|
if ((!IS_AML_ROOT_NODE (Node) &&
|
|
!AmlNodeHasAttribute (
|
|
(CONST AML_OBJECT_NODE*)Node,
|
|
AML_IN_NAMESPACE)) ||
|
|
!IS_STREAM (RawAbsPathBStream) ||
|
|
IS_END_OF_STREAM (RawAbsPathBStream) ||
|
|
!IS_STREAM_BACKWARD (RawAbsPathBStream) ||
|
|
(InputParent > MAX_UINT8)) {
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
while (1) {
|
|
if (IS_AML_ROOT_NODE (Node)) {
|
|
break;
|
|
}
|
|
|
|
NodeName = AmlNodeGetName ((CONST AML_OBJECT_NODE*)Node);
|
|
if (NodeName == NULL) {
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = AmlParseNameStringInfo (
|
|
NodeName,
|
|
&Root,
|
|
&ParentPrefix,
|
|
&SegCount
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
if (SegCount > InputParent) {
|
|
// 1.1. If the Node's name has enough levels to consume all the
|
|
// InputParent carets, write the levels that are left.
|
|
NameSeg = AmlGetFirstNameSeg (NodeName, Root, ParentPrefix);
|
|
Status = AmlStreamWrite (
|
|
RawAbsPathBStream,
|
|
(CONST UINT8*)NameSeg,
|
|
(SegCount - InputParent) * AML_NAME_SEG_SIZE
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
InputParent = 0;
|
|
} else {
|
|
// (SegCount <= InputParent)
|
|
// 1.2. Else save the InputParent in TotalParent to climb
|
|
// them later.
|
|
InputParent -= SegCount;
|
|
}
|
|
|
|
InputParent += ParentPrefix;
|
|
|
|
if (Root != 0) {
|
|
// 2. The Node's name is an absolute path.
|
|
// Exit, the root has been reached.
|
|
if (InputParent != 0) {
|
|
ASSERT (0);
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
break;
|
|
}
|
|
|
|
Status = AmlGetAncestorNameSpaceNode (
|
|
(CONST AML_OBJECT_NODE*)Node,
|
|
&InputParent,
|
|
&Root,
|
|
(CONST AML_NODE_HEADER**)&ParentNode
|
|
);
|
|
if (EFI_ERROR (Status) ||
|
|
(!IS_AML_NODE_VALID (ParentNode))) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
Node = ParentNode;
|
|
|
|
if (IS_AML_ROOT_NODE (Node)) {
|
|
// 3.1. If the root node has been found while climbing,
|
|
// no need to write NameSegs.
|
|
// Exit.
|
|
break;
|
|
} else if (Root != 0) {
|
|
// 3.2. An absolute path has been found while climbing the tree.
|
|
// If (InputParent != 0), the raw pathname is not the root.
|
|
// Write the first [SegCount - InputParent] NameSegs of this
|
|
// absolute path.
|
|
// Then exit.
|
|
if (InputParent != 0) {
|
|
// Get the absolute pathname.
|
|
NodeName = AmlNodeGetName ((CONST AML_OBJECT_NODE*)Node);
|
|
if (NodeName == NULL) {
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
// Analyze the absolute pathname.
|
|
Status = AmlParseNameStringInfo (
|
|
NodeName,
|
|
&Root,
|
|
&ParentPrefix,
|
|
&SegCount
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
// Writing the n first NameSegs.
|
|
// n = SegCount - InputParent
|
|
NameSeg = AmlGetFirstNameSeg (NodeName, Root, ParentPrefix);
|
|
Status = AmlStreamWrite (
|
|
RawAbsPathBStream,
|
|
(CONST UINT8*)NameSeg,
|
|
(SegCount - InputParent) * AML_NAME_SEG_SIZE
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
break;
|
|
} // (InputParent != 0)
|
|
|
|
}
|
|
} // while
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/** Add the RootChar and prefix byte to the raw AML NameString in the
|
|
input Stream to create a valid absolute path.
|
|
|
|
The prefix byte can be AML_DUAL_NAME_PREFIX, AML_MULTI_NAME_PREFIX
|
|
or nothing.
|
|
|
|
@param [in, out] AmlPathBStream The Stream initially contains a raw
|
|
NameString (i.e. a list of NameSegs).
|
|
The Stream can be empty (e.g.: for the
|
|
root path).
|
|
The stream must not be at its end.
|
|
|
|
@retval EFI_SUCCESS The function completed successfully.
|
|
@retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
AmlAddPrefix (
|
|
IN OUT AML_STREAM * AmlPathBStream
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 NameSegCount;
|
|
UINT32 NameSegSize;
|
|
|
|
// At most 3 bytes are needed for: RootChar + MultiNamePrefix + SegCount.
|
|
CHAR8 Prefix[3];
|
|
UINT32 PrefixSize;
|
|
|
|
// The Stream contains concatenated NameSegs.
|
|
if (!IS_STREAM (AmlPathBStream) ||
|
|
IS_END_OF_STREAM (AmlPathBStream) ||
|
|
!IS_STREAM_BACKWARD (AmlPathBStream)) {
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
// Its size should be a multiple of AML_NAME_SEG_SIZE.
|
|
// AML_NAME_SEG_SIZE = 4. Check the 2 lowest bits.
|
|
NameSegSize = AmlStreamGetIndex (AmlPathBStream);
|
|
if ((NameSegSize & (AML_NAME_SEG_SIZE - 1)) != 0) {
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
// Each NameSeg is 4 bytes so divide the NameSegSize by 4.
|
|
NameSegCount = NameSegSize >> 2;
|
|
if (NameSegCount > MAX_UINT8) {
|
|
// There can be at most 255 NameSegs.
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Prefix[0] = AML_ROOT_CHAR;
|
|
|
|
switch (NameSegCount) {
|
|
case 0:
|
|
{
|
|
// Root and parents only NameString (no NameSeg(s)) end with '\0'.
|
|
Prefix[1] = AML_ZERO_OP;
|
|
PrefixSize = 2;
|
|
break;
|
|
}
|
|
case 1:
|
|
{
|
|
PrefixSize = 1;
|
|
break;
|
|
}
|
|
case 2:
|
|
{
|
|
Prefix[1] = AML_DUAL_NAME_PREFIX;
|
|
PrefixSize = 2;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
Prefix[1] = AML_MULTI_NAME_PREFIX;
|
|
Prefix[2] = (UINT8)NameSegCount;
|
|
PrefixSize = 3;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Add the RootChar + prefix (if needed) at the beginning of the pathname.
|
|
Status = AmlStreamWrite (AmlPathBStream, (CONST UINT8*)Prefix, PrefixSize);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/** Remove the prefix bytes of an AML NameString stored in a backward stream
|
|
to get a raw NameString.
|
|
|
|
The AML encoding for '\', '^', Dual name or multi-name prefix are
|
|
stripped off.
|
|
E.g: If the ASL path was "\AAAA.BBBB", the AML equivalent would be
|
|
"{RootChar}{DualNamePrefix}AAAABBBB". So resultant raw NameString
|
|
is "AAAABBBB".
|
|
|
|
@param [in, out] AmlPathBStream Backward stream containing an AML
|
|
NameString.
|
|
The stream must not be at its end.
|
|
|
|
@retval EFI_SUCCESS The function completed successfully.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
AmlRemovePrefix (
|
|
IN OUT AML_STREAM * AmlPathBStream
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
UINT32 TotalSize;
|
|
UINT32 RewindSize;
|
|
|
|
UINT32 Root;
|
|
UINT32 ParentPrefix;
|
|
UINT32 SegCount;
|
|
|
|
if (!IS_STREAM (AmlPathBStream) ||
|
|
IS_END_OF_STREAM (AmlPathBStream) ||
|
|
!IS_STREAM_BACKWARD (AmlPathBStream)) {
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = AmlParseNameStringInfo (
|
|
(CHAR8*)AmlStreamGetCurrPos (AmlPathBStream),
|
|
&Root,
|
|
&ParentPrefix,
|
|
&SegCount
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
TotalSize = AmlComputeNameStringSize (Root, ParentPrefix, SegCount);
|
|
if (TotalSize == 0) {
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
// Rewind the stream of all the bytes that are not SegCounts
|
|
// to drop the prefix.
|
|
RewindSize = TotalSize - (SegCount * AML_NAME_SEG_SIZE);
|
|
if (RewindSize != 0) {
|
|
Status = AmlStreamRewind (AmlPathBStream, RewindSize);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/** Build the absolute ASL pathname to Node.
|
|
|
|
BufferSize is always updated to the size of the pathname.
|
|
|
|
If:
|
|
- the content of BufferSize is >= to the size of the pathname AND;
|
|
- Buffer is not NULL.
|
|
then copy the pathname in the Buffer. A buffer of the size
|
|
MAX_ASL_NAMESTRING_SIZE is big enough to receive any ASL pathname.
|
|
|
|
@param [in] Node Node to build the absolute path to.
|
|
Must be a root node, or a namespace node.
|
|
@param [out] Buffer Buffer to write the path to.
|
|
If NULL, only update *BufferSize.
|
|
@param [in, out] BufferSize Pointer holding:
|
|
- At entry, the size of the Buffer;
|
|
- At exit, the size of the pathname.
|
|
|
|
@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
|
|
AmlGetAslPathName (
|
|
IN AML_NODE_HEADER * Node,
|
|
OUT CHAR8 * Buffer,
|
|
IN OUT UINT32 * BufferSize
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
// Backward stream used to build the raw AML absolute path to the node.
|
|
AML_STREAM RawAmlAbsPathBStream;
|
|
CHAR8 * RawAmlAbsPathBuffer;
|
|
UINT32 RawAmlAbsPathBufferSize;
|
|
|
|
CHAR8 * AmlPathName;
|
|
CHAR8 * AslPathName;
|
|
UINT32 AslPathNameSize;
|
|
|
|
UINT32 Root;
|
|
UINT32 ParentPrefix;
|
|
UINT32 SegCount;
|
|
|
|
if ((!IS_AML_ROOT_NODE (Node) &&
|
|
!AmlNodeHasAttribute (
|
|
(CONST AML_OBJECT_NODE*)Node,
|
|
AML_IN_NAMESPACE)) ||
|
|
(BufferSize == NULL)) {
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
AslPathName = NULL;
|
|
|
|
// Allocate a Stream to get the raw AML absolute pathname.
|
|
RawAmlAbsPathBufferSize = MAX_AML_NAMESTRING_SIZE;
|
|
RawAmlAbsPathBuffer = AllocateZeroPool (RawAmlAbsPathBufferSize);
|
|
if (RawAmlAbsPathBuffer == NULL) {
|
|
ASSERT (0);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
Status = AmlStreamInit (
|
|
&RawAmlAbsPathBStream,
|
|
(UINT8*)RawAmlAbsPathBuffer,
|
|
RawAmlAbsPathBufferSize,
|
|
EAmlStreamDirectionBackward
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
goto exit_handler;
|
|
}
|
|
|
|
// Get the raw pathname of the Node. The raw pathname being an
|
|
// AML NameString without the RootChar and prefix byte.
|
|
// It is a list of concatenated NameSegs.
|
|
Status = AmlGetRawNameSpacePath (Node, 0, &RawAmlAbsPathBStream);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
goto exit_handler;
|
|
}
|
|
|
|
// Add the RootChar and prefix byte.
|
|
Status = AmlAddPrefix (&RawAmlAbsPathBStream);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
goto exit_handler;
|
|
}
|
|
|
|
AmlPathName = (CHAR8*)AmlStreamGetCurrPos (&RawAmlAbsPathBStream);
|
|
|
|
// Analyze the NameString.
|
|
Status = AmlParseNameStringInfo (
|
|
(CONST CHAR8*)AmlPathName,
|
|
&Root,
|
|
&ParentPrefix,
|
|
&SegCount
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
goto exit_handler;
|
|
}
|
|
|
|
// Compute the size the ASL pathname will take.
|
|
AslPathNameSize = AslComputeNameStringSize (Root, ParentPrefix, SegCount);
|
|
if (AslPathNameSize == 0) {
|
|
ASSERT (0);
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto exit_handler;
|
|
}
|
|
|
|
// Input Buffer is large enough. Copy the pathname if the Buffer is valid.
|
|
if ((Buffer != NULL) && (AslPathNameSize <= *BufferSize)) {
|
|
Status = ConvertAmlNameToAslName (AmlPathName, &AslPathName);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto exit_handler;
|
|
}
|
|
|
|
CopyMem (Buffer, AslPathName, AslPathNameSize);
|
|
}
|
|
|
|
*BufferSize = AslPathNameSize;
|
|
|
|
exit_handler:
|
|
// Free allocated memory.
|
|
FreePool (RawAmlAbsPathBuffer);
|
|
if (AslPathName != NULL) {
|
|
FreePool (AslPathName);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
#if !defined (MDEPKG_NDEBUG)
|
|
|
|
/** Recursively print the pathnames in the AML namespace in Node's branch.
|
|
|
|
@param [in] Node Pointer to a node.
|
|
@param [in] Context An empty forward stream holding a pre-allocated
|
|
buffer. This prevents from having to do multiple
|
|
allocations during the enumeration.
|
|
@param [in, out] Status At entry, contains the status returned by the
|
|
last call to this exact function during the
|
|
enumeration.
|
|
As exit, contains the returned status of the
|
|
call to this function.
|
|
Optional, can be NULL.
|
|
|
|
@retval TRUE if the enumeration can continue or has finished without
|
|
interruption.
|
|
@retval FALSE if the enumeration needs to stopped or has stopped.
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
EFIAPI
|
|
AmlDbgPrintNameSpaceCallback (
|
|
IN AML_NODE_HEADER * Node,
|
|
IN VOID * Context,
|
|
IN OUT EFI_STATUS * Status OPTIONAL
|
|
)
|
|
{
|
|
BOOLEAN ContinueEnum;
|
|
EFI_STATUS Status1;
|
|
|
|
AML_STREAM * CurrNodePathFStream;
|
|
CHAR8 * CurrNodePathBuffer;
|
|
UINT32 CurrNodePathBufferSize;
|
|
|
|
ContinueEnum = TRUE;
|
|
Status1 = EFI_SUCCESS;
|
|
|
|
if (!IS_AML_NODE_VALID (Node) ||
|
|
(Context == NULL)) {
|
|
ASSERT (0);
|
|
Status1 = EFI_INVALID_PARAMETER;
|
|
ContinueEnum = FALSE;
|
|
goto exit_handler;
|
|
}
|
|
|
|
if (!IS_AML_ROOT_NODE (Node) &&
|
|
!AmlNodeHasAttribute (
|
|
(CONST AML_OBJECT_NODE*)Node,
|
|
AML_IN_NAMESPACE)) {
|
|
// Skip this node and continue enumeration.
|
|
goto exit_handler;
|
|
}
|
|
|
|
if (IS_AML_ROOT_NODE (Node)) {
|
|
DEBUG ((DEBUG_INFO, "\\\n"));
|
|
} else if (AmlNodeHasAttribute (
|
|
(CONST AML_OBJECT_NODE*)Node,
|
|
AML_IN_NAMESPACE)) {
|
|
|
|
CurrNodePathFStream = (AML_STREAM*)Context;
|
|
|
|
// Check the Context's content.
|
|
if (!IS_STREAM (CurrNodePathFStream) ||
|
|
IS_END_OF_STREAM (CurrNodePathFStream) ||
|
|
!IS_STREAM_FORWARD (CurrNodePathFStream)) {
|
|
ASSERT (0);
|
|
Status1 = EFI_INVALID_PARAMETER;
|
|
ContinueEnum = FALSE;
|
|
goto exit_handler;
|
|
}
|
|
|
|
CurrNodePathBuffer = (CHAR8*)AmlStreamGetBuffer (CurrNodePathFStream);
|
|
CurrNodePathBufferSize = AmlStreamGetMaxBufferSize (CurrNodePathFStream);
|
|
|
|
Status1 = AmlGetAslPathName (
|
|
(AML_NODE_HEADER*)Node,
|
|
CurrNodePathBuffer,
|
|
&CurrNodePathBufferSize
|
|
);
|
|
if (EFI_ERROR (Status1)) {
|
|
ASSERT (0);
|
|
ContinueEnum = FALSE;
|
|
goto exit_handler;
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "%a\n", CurrNodePathBuffer));
|
|
|
|
} else {
|
|
ASSERT (0);
|
|
Status1 = EFI_INVALID_PARAMETER;
|
|
ContinueEnum = FALSE;
|
|
}
|
|
|
|
exit_handler:
|
|
if (Status != NULL) {
|
|
*Status = Status1;
|
|
}
|
|
|
|
return ContinueEnum;
|
|
}
|
|
|
|
/** Print the absolute pathnames in the AML namespace of
|
|
all the nodes in the tree starting from the Root node.
|
|
|
|
@param [in] RootNode Pointer to a root node.
|
|
|
|
@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
|
|
AmlDbgPrintNameSpace (
|
|
IN AML_ROOT_NODE * RootNode
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
AML_STREAM CurrNodePathFStream;
|
|
CHAR8 * CurrNodePathBuffer;
|
|
UINT32 CurrNodePathBufferSize;
|
|
|
|
if (!IS_AML_ROOT_NODE (RootNode)) {
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "AmlNameSpace: AML namespace:\n"));
|
|
|
|
// Allocate memory to build the absolute ASL path to each node.
|
|
CurrNodePathBufferSize = MAX_AML_NAMESTRING_SIZE;
|
|
CurrNodePathBuffer = AllocateZeroPool (CurrNodePathBufferSize);
|
|
if (CurrNodePathBuffer == NULL) {
|
|
ASSERT (0);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
// An empty forward stream holding a pre-allocated buffer is used
|
|
// to avoid multiple allocations during the enumeration.
|
|
Status = AmlStreamInit (
|
|
&CurrNodePathFStream,
|
|
(UINT8*)CurrNodePathBuffer,
|
|
CurrNodePathBufferSize,
|
|
EAmlStreamDirectionForward
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
goto exit_handler;
|
|
}
|
|
|
|
AmlEnumTree (
|
|
(AML_NODE_HEADER*)RootNode,
|
|
AmlDbgPrintNameSpaceCallback,
|
|
(VOID*)&CurrNodePathFStream,
|
|
&Status
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
exit_handler:
|
|
FreePool (CurrNodePathBuffer);
|
|
|
|
return Status;
|
|
}
|
|
|
|
#endif // MDEPKG_NDEBUG
|
|
|
|
/** Callback function to find the node corresponding to an absolute pathname.
|
|
|
|
For each namespace node, build its raw AML absolute path. Then compare this
|
|
path with the raw AML absolute path of the search node available in the
|
|
Context.
|
|
|
|
@param [in] Node Pointer to the node to whose pathname is being
|
|
tested.
|
|
@param [in, out] Context A pointer to AML_PATH_SEARCH_CONTEXT that has:
|
|
- The searched path stored in a stream;
|
|
- An empty stream to query the pathname of the
|
|
probed node;
|
|
- A node pointer to store the searched node
|
|
if found.
|
|
@param [in, out] Status At entry, contains the status returned by the
|
|
last call to this exact function during the
|
|
enumeration.
|
|
As exit, contains the returned status of the
|
|
call to this function.
|
|
Optional, can be NULL.
|
|
|
|
@retval TRUE if the enumeration can continue or has finished without
|
|
interruption.
|
|
@retval FALSE if the enumeration needs to stopped or has stopped.
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
EFIAPI
|
|
AmlEnumeratePathCallback (
|
|
IN AML_NODE_HEADER * Node,
|
|
IN OUT VOID * Context,
|
|
IN OUT EFI_STATUS * Status OPTIONAL
|
|
)
|
|
{
|
|
BOOLEAN ContinueEnum;
|
|
EFI_STATUS Status1;
|
|
|
|
AML_PATH_SEARCH_CONTEXT * PathSearchContext;
|
|
|
|
AML_STREAM * SearchPathBStream;
|
|
|
|
AML_STREAM * CurrNodePathBStream;
|
|
UINT32 CurrNodePathSize;
|
|
|
|
ContinueEnum = TRUE;
|
|
Status1 = EFI_SUCCESS;
|
|
|
|
if (!IS_AML_NODE_VALID (Node) ||
|
|
(Context == NULL)) {
|
|
ASSERT (0);
|
|
Status1 = EFI_INVALID_PARAMETER;
|
|
ContinueEnum = FALSE;
|
|
goto exit_handler;
|
|
}
|
|
|
|
if (!AmlNodeHasAttribute (
|
|
(CONST AML_OBJECT_NODE*)Node,
|
|
AML_IN_NAMESPACE)) {
|
|
goto exit_handler;
|
|
}
|
|
|
|
PathSearchContext = (AML_PATH_SEARCH_CONTEXT*)Context;
|
|
SearchPathBStream = PathSearchContext->SearchPathBStream;
|
|
CurrNodePathBStream = PathSearchContext->CurrNodePathBStream;
|
|
|
|
// Check the Context's content.
|
|
if (!IS_STREAM (SearchPathBStream) ||
|
|
IS_END_OF_STREAM (SearchPathBStream) ||
|
|
!IS_STREAM_BACKWARD (SearchPathBStream) ||
|
|
!IS_STREAM (CurrNodePathBStream) ||
|
|
IS_END_OF_STREAM (CurrNodePathBStream) ||
|
|
!IS_STREAM_BACKWARD (CurrNodePathBStream)) {
|
|
ASSERT (0);
|
|
Status1 = EFI_INVALID_PARAMETER;
|
|
ContinueEnum = FALSE;
|
|
goto exit_handler;
|
|
}
|
|
|
|
CurrNodePathSize = AmlStreamGetMaxBufferSize (CurrNodePathBStream);
|
|
if (CurrNodePathSize == 0) {
|
|
ASSERT (0);
|
|
Status1 = EFI_INVALID_PARAMETER;
|
|
ContinueEnum = FALSE;
|
|
goto exit_handler;
|
|
}
|
|
|
|
// Get the raw AML absolute pathname of the current node.
|
|
Status1 = AmlGetRawNameSpacePath (Node, 0, CurrNodePathBStream);
|
|
if (EFI_ERROR (Status1)) {
|
|
ASSERT (0);
|
|
ContinueEnum = FALSE;
|
|
goto exit_handler;
|
|
}
|
|
|
|
DEBUG ((
|
|
DEBUG_VERBOSE,
|
|
"AmlNameSpace: "
|
|
"Comparing search path with current node path.\n"
|
|
));
|
|
DEBUG ((DEBUG_VERBOSE, "Search path:"));
|
|
AMLDBG_PRINT_CHARS (
|
|
DEBUG_VERBOSE,
|
|
(CHAR8*)AmlStreamGetCurrPos (SearchPathBStream),
|
|
AmlStreamGetIndex (SearchPathBStream)
|
|
);
|
|
DEBUG ((DEBUG_VERBOSE, "\nPath of the current node: "));
|
|
AMLDBG_PRINT_CHARS (
|
|
DEBUG_VERBOSE,
|
|
(CHAR8*)AmlStreamGetCurrPos (CurrNodePathBStream),
|
|
AmlStreamGetIndex (CurrNodePathBStream)
|
|
);
|
|
DEBUG ((DEBUG_VERBOSE, "\n"));
|
|
|
|
// Compare the searched path and Node's path.
|
|
if ((AmlStreamGetIndex (CurrNodePathBStream) ==
|
|
AmlStreamGetIndex (SearchPathBStream)) &&
|
|
(CompareMem (
|
|
AmlStreamGetCurrPos (CurrNodePathBStream),
|
|
AmlStreamGetCurrPos (SearchPathBStream),
|
|
AmlStreamGetIndex (SearchPathBStream)) == 0)) {
|
|
Status1 = EFI_SUCCESS;
|
|
ContinueEnum = FALSE;
|
|
PathSearchContext->OutNode = Node;
|
|
} else {
|
|
// If the paths don't match, reset the CurrNodePathStream's content.
|
|
Status1 = AmlStreamReset (CurrNodePathBStream);
|
|
if (EFI_ERROR (Status1)) {
|
|
ASSERT (0);
|
|
ContinueEnum = FALSE;
|
|
}
|
|
}
|
|
|
|
exit_handler:
|
|
if (Status != NULL) {
|
|
*Status = Status1;
|
|
}
|
|
|
|
return ContinueEnum;
|
|
}
|
|
|
|
/** Build a raw AML absolute path from a reference node and a relative
|
|
ASL path.
|
|
|
|
The AslPath can be a relative path or an absolute path.
|
|
Node must be a root node or a namespace node.
|
|
A root node is expected to be at the top of the tree.
|
|
|
|
@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".
|
|
@param [in, out] RawAmlAbsSearchPathBStream Backward stream to write the
|
|
raw absolute AML path of the
|
|
searched node.
|
|
The stream must not be at
|
|
its end.
|
|
|
|
@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.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
AmlBuildAbsoluteAmlPath (
|
|
IN AML_NODE_HEADER * ReferenceNode,
|
|
IN CHAR8 * AslPath,
|
|
IN OUT AML_STREAM * RawAmlAbsSearchPathBStream
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
CHAR8 * AmlPath;
|
|
|
|
UINT32 AmlNameStringSize;
|
|
UINT32 Root;
|
|
UINT32 ParentPrefix;
|
|
UINT32 SegCount;
|
|
|
|
if ((!IS_AML_ROOT_NODE (ReferenceNode) &&
|
|
!AmlNodeHasAttribute (
|
|
(CONST AML_OBJECT_NODE*)ReferenceNode,
|
|
AML_IN_NAMESPACE)) ||
|
|
(AslPath == NULL) ||
|
|
!IS_STREAM (RawAmlAbsSearchPathBStream) ||
|
|
IS_END_OF_STREAM (RawAmlAbsSearchPathBStream) ||
|
|
!IS_STREAM_BACKWARD (RawAmlAbsSearchPathBStream)) {
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
// 1. Validate, analyze and convert the AslPath to an AmlPath.
|
|
Status = ConvertAslNameToAmlName (AslPath, &AmlPath);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
return Status;
|
|
}
|
|
|
|
Status = AmlParseNameStringInfo (AmlPath, &Root, &ParentPrefix, &SegCount);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
goto exit_handler;
|
|
}
|
|
|
|
// Not possible to go beyond the root.
|
|
if (IS_AML_ROOT_NODE (ReferenceNode) && (ParentPrefix != 0)) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
ASSERT (0);
|
|
goto exit_handler;
|
|
}
|
|
|
|
AmlNameStringSize = AmlComputeNameStringSize (Root, ParentPrefix, SegCount);
|
|
if (AmlNameStringSize == 0) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
ASSERT (0);
|
|
goto exit_handler;
|
|
}
|
|
|
|
// 2.1. Write the AML path to the stream.
|
|
Status = AmlStreamWrite (
|
|
RawAmlAbsSearchPathBStream,
|
|
(CONST UINT8*)AmlPath,
|
|
AmlNameStringSize
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
goto exit_handler;
|
|
}
|
|
|
|
// 2.2. Then remove the AML prefix (root char, parent prefix, etc.)
|
|
// to obtain a raw AML NameString. Raw AML NameString are easier
|
|
// to manipulate.
|
|
Status = AmlRemovePrefix (RawAmlAbsSearchPathBStream);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
goto exit_handler;
|
|
}
|
|
|
|
// 3. If AslPath is a relative path and the reference Node is not
|
|
// the root node, fill the Stream with the absolute path to the
|
|
// reference node.
|
|
if ((Root == 0) && !IS_AML_ROOT_NODE (ReferenceNode)) {
|
|
Status = AmlGetRawNameSpacePath (
|
|
ReferenceNode,
|
|
ParentPrefix,
|
|
RawAmlAbsSearchPathBStream
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
}
|
|
}
|
|
|
|
exit_handler:
|
|
// Free allocated memory.
|
|
FreePool (AmlPath);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/** 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
|
|
|
|
@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_HEADER * ReferenceNode,
|
|
IN CHAR8 * AslPath,
|
|
OUT AML_NODE_HEADER ** OutNode
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
AML_PATH_SEARCH_CONTEXT PathSearchContext;
|
|
AML_ROOT_NODE * RootNode;
|
|
|
|
// Backward stream used to build the raw AML absolute path to the searched
|
|
// node.
|
|
AML_STREAM RawAmlAbsSearchPathBStream;
|
|
CHAR8 * RawAmlAbsSearchPathBuffer;
|
|
UINT32 RawAmlAbsSearchPathBufferSize;
|
|
|
|
// Backward stream used to store the raw AML absolute path of the node
|
|
// currently enumerated in the tree. This path can then be compared to the
|
|
// RawAmlAbsSearchPath.
|
|
AML_STREAM RawAmlAbsCurrNodePathBStream;
|
|
CHAR8 * RawAmlAbsCurrNodePathBuffer;
|
|
UINT32 RawAmlAbsCurrNodePathBufferSize;
|
|
|
|
if ((!IS_AML_ROOT_NODE (ReferenceNode) &&
|
|
!AmlNodeHasAttribute (
|
|
(CONST AML_OBJECT_NODE*)ReferenceNode,
|
|
AML_IN_NAMESPACE)) ||
|
|
(AslPath == NULL) ||
|
|
(OutNode == NULL)) {
|
|
ASSERT (0);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
*OutNode = NULL;
|
|
RawAmlAbsCurrNodePathBuffer = NULL;
|
|
|
|
// 1. Build a raw absolute AML path from the reference node and the ASL
|
|
// path. For this:
|
|
// 1.1. First initialize a backward stream.
|
|
RawAmlAbsSearchPathBufferSize = MAX_AML_NAMESTRING_SIZE;
|
|
RawAmlAbsSearchPathBuffer = AllocateZeroPool (RawAmlAbsSearchPathBufferSize);
|
|
if (RawAmlAbsSearchPathBuffer == NULL) {
|
|
ASSERT (0);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
Status = AmlStreamInit (
|
|
&RawAmlAbsSearchPathBStream,
|
|
(UINT8*)RawAmlAbsSearchPathBuffer,
|
|
RawAmlAbsSearchPathBufferSize,
|
|
EAmlStreamDirectionBackward
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
goto exit_handler;
|
|
}
|
|
|
|
// 1.2. Then build the raw AML absolute path.
|
|
Status = AmlBuildAbsoluteAmlPath (
|
|
ReferenceNode,
|
|
AslPath,
|
|
&RawAmlAbsSearchPathBStream
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
goto exit_handler;
|
|
}
|
|
|
|
// 2. Find the root node by climbing up the tree from the reference node.
|
|
RootNode = AmlGetRootNode (ReferenceNode);
|
|
if (RootNode == NULL) {
|
|
ASSERT (0);
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto exit_handler;
|
|
}
|
|
|
|
// 3. If the searched node is the root node, return.
|
|
// For the Root Node there is no NameSegs so the length of
|
|
// the stream will be zero.
|
|
if (AmlStreamGetIndex (&RawAmlAbsSearchPathBStream) == 0) {
|
|
*OutNode = (AML_NODE_HEADER*)RootNode;
|
|
Status = EFI_SUCCESS;
|
|
goto exit_handler;
|
|
}
|
|
|
|
// 4. Create a backward stream large enough to hold the current node path
|
|
// during enumeration. This prevents from doing multiple allocation/free
|
|
// operations.
|
|
RawAmlAbsCurrNodePathBufferSize = MAX_ASL_NAMESTRING_SIZE;
|
|
RawAmlAbsCurrNodePathBuffer = AllocateZeroPool (
|
|
RawAmlAbsCurrNodePathBufferSize
|
|
);
|
|
if (RawAmlAbsCurrNodePathBuffer == NULL) {
|
|
ASSERT (0);
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto exit_handler;
|
|
}
|
|
|
|
Status = AmlStreamInit (
|
|
&RawAmlAbsCurrNodePathBStream,
|
|
(UINT8*)RawAmlAbsCurrNodePathBuffer,
|
|
RawAmlAbsCurrNodePathBufferSize,
|
|
EAmlStreamDirectionBackward
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
goto exit_handler;
|
|
}
|
|
|
|
// 5. Fill a path search context structure with:
|
|
// - SearchPathStream: backward stream containing the raw absolute AML
|
|
// path to the searched node;
|
|
// - CurrNodePathStream: backward stream containing the raw absolute AML
|
|
// of the node currently being enumerated;
|
|
// - OutNode: node pointer to the store the potentially found node.
|
|
PathSearchContext.SearchPathBStream = &RawAmlAbsSearchPathBStream;
|
|
PathSearchContext.CurrNodePathBStream = &RawAmlAbsCurrNodePathBStream;
|
|
PathSearchContext.OutNode = NULL;
|
|
|
|
// 6. Iterate through the namespace nodes of the tree.
|
|
// For each namespace node, build its raw AML absolute path. Then compare
|
|
// it with the search path.
|
|
AmlEnumTree (
|
|
(AML_NODE_HEADER*)RootNode,
|
|
AmlEnumeratePathCallback,
|
|
(VOID*)&PathSearchContext,
|
|
&Status
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT (0);
|
|
goto exit_handler;
|
|
}
|
|
|
|
*OutNode = PathSearchContext.OutNode;
|
|
if (*OutNode == NULL) {
|
|
Status = EFI_NOT_FOUND;
|
|
}
|
|
|
|
exit_handler:
|
|
// Free allocated memory.
|
|
FreePool (RawAmlAbsSearchPathBuffer);
|
|
if (RawAmlAbsCurrNodePathBuffer != NULL) {
|
|
FreePool (RawAmlAbsCurrNodePathBuffer);
|
|
}
|
|
|
|
return Status;
|
|
}
|