mirror of https://github.com/acidanthera/audk.git
615 lines
16 KiB
C
615 lines
16 KiB
C
/** @file
|
|
ACPI Sdt Protocol Driver
|
|
|
|
Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved. <BR>
|
|
This program and the accompanying materials
|
|
are licensed and made available under the terms and conditions of the BSD License
|
|
which accompanies this distribution. The full text of the license may be found at
|
|
http://opensource.org/licenses/bsd-license.php
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
|
**/
|
|
|
|
#include "AcpiTable.h"
|
|
|
|
/**
|
|
Construct node list according to the AML handle.
|
|
|
|
@param[in] AmlHandle AML handle.
|
|
@param[in] AmlRootNodeList AML root node list.
|
|
@param[in] AmlParentNodeList AML parent node list.
|
|
|
|
@retval EFI_SUCCESS Success.
|
|
@retval EFI_INVALID_PARAMETER AML handle does not refer to a valid ACPI object.
|
|
**/
|
|
EFI_STATUS
|
|
AmlConstructNodeList (
|
|
IN EFI_AML_HANDLE *AmlHandle,
|
|
IN EFI_AML_NODE_LIST *AmlRootNodeList,
|
|
IN EFI_AML_NODE_LIST *AmlParentNodeList
|
|
);
|
|
|
|
/**
|
|
Create AML Node.
|
|
|
|
@param[in] NameSeg AML NameSeg.
|
|
@param[in] Parent AML parent node list.
|
|
@param[in] AmlByteEncoding AML Byte Encoding.
|
|
|
|
@return AML Node.
|
|
**/
|
|
EFI_AML_NODE_LIST *
|
|
AmlCreateNode (
|
|
IN UINT8 *NameSeg,
|
|
IN EFI_AML_NODE_LIST *Parent,
|
|
IN AML_BYTE_ENCODING *AmlByteEncoding
|
|
)
|
|
{
|
|
EFI_AML_NODE_LIST *AmlNodeList;
|
|
|
|
AmlNodeList = AllocatePool (sizeof(*AmlNodeList));
|
|
ASSERT (AmlNodeList != NULL);
|
|
|
|
AmlNodeList->Signature = EFI_AML_NODE_LIST_SIGNATURE;
|
|
CopyMem (AmlNodeList->Name, NameSeg, AML_NAME_SEG_SIZE);
|
|
AmlNodeList->Buffer = NULL;
|
|
AmlNodeList->Size = 0;
|
|
InitializeListHead (&AmlNodeList->Link);
|
|
InitializeListHead (&AmlNodeList->Children);
|
|
AmlNodeList->Parent = Parent;
|
|
AmlNodeList->AmlByteEncoding = AmlByteEncoding;
|
|
|
|
return AmlNodeList;
|
|
}
|
|
|
|
/**
|
|
Find the AML NameSeg in the children of AmlParentNodeList.
|
|
|
|
@param[in] NameSeg AML NameSeg.
|
|
@param[in] AmlParentNodeList AML parent node list.
|
|
@param[in] Create TRUE means to create node if not found.
|
|
|
|
@return AmlChildNode whoes name is same as NameSeg.
|
|
**/
|
|
EFI_AML_NODE_LIST *
|
|
AmlFindNodeInThis (
|
|
IN UINT8 *NameSeg,
|
|
IN EFI_AML_NODE_LIST *AmlParentNodeList,
|
|
IN BOOLEAN Create
|
|
)
|
|
{
|
|
EFI_AML_NODE_LIST *CurrentAmlNodeList;
|
|
LIST_ENTRY *CurrentLink;
|
|
LIST_ENTRY *StartLink;
|
|
EFI_AML_NODE_LIST *AmlNodeList;
|
|
|
|
StartLink = &AmlParentNodeList->Children;
|
|
CurrentLink = StartLink->ForwardLink;
|
|
|
|
while (CurrentLink != StartLink) {
|
|
CurrentAmlNodeList = EFI_AML_NODE_LIST_FROM_LINK (CurrentLink);
|
|
//
|
|
// AML name is same as the one stored
|
|
//
|
|
if (CompareMem (CurrentAmlNodeList->Name, NameSeg, AML_NAME_SEG_SIZE) == 0) {
|
|
//
|
|
// Good! Found it
|
|
//
|
|
return CurrentAmlNodeList;
|
|
}
|
|
CurrentLink = CurrentLink->ForwardLink;
|
|
}
|
|
|
|
//
|
|
// Not found
|
|
//
|
|
if (!Create) {
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Create new node with NULL buffer - it means namespace not be returned.
|
|
//
|
|
AmlNodeList = AmlCreateNode (NameSeg, AmlParentNodeList, NULL);
|
|
InsertTailList (&AmlParentNodeList->Children, &AmlNodeList->Link);
|
|
|
|
return AmlNodeList;
|
|
}
|
|
|
|
/**
|
|
Find the AML NameString in the children of AmlParentNodeList or AmlRootNodeList.
|
|
|
|
@param[in] NameString AML NameString.
|
|
@param[in] AmlRootNodeList AML root node list.
|
|
@param[in] AmlParentNodeList AML parent node list.
|
|
@param[in] Create TRUE means to create node if not found.
|
|
|
|
@return AmlChildNode whoes name is same as NameSeg.
|
|
**/
|
|
EFI_AML_NODE_LIST *
|
|
AmlFindNodeInTheTree (
|
|
IN UINT8 *NameString,
|
|
IN EFI_AML_NODE_LIST *AmlRootNodeList,
|
|
IN EFI_AML_NODE_LIST *AmlParentNodeList,
|
|
IN BOOLEAN Create
|
|
)
|
|
{
|
|
UINT8 *Buffer;
|
|
EFI_AML_NODE_LIST *AmlNodeList;
|
|
EFI_AML_NODE_LIST *AmlCurrentNodeList;
|
|
UINT8 Index;
|
|
UINT8 SegCount;
|
|
|
|
Buffer = NameString;
|
|
|
|
//
|
|
// Handle root or parent prefix
|
|
//
|
|
if (*Buffer == AML_ROOT_CHAR) {
|
|
AmlCurrentNodeList = AmlRootNodeList;
|
|
Buffer += 1;
|
|
} else if (*Buffer == AML_PARENT_PREFIX_CHAR) {
|
|
AmlCurrentNodeList = AmlParentNodeList;
|
|
do {
|
|
if (AmlCurrentNodeList->Parent != NULL) {
|
|
AmlCurrentNodeList = AmlCurrentNodeList->Parent;
|
|
} else {
|
|
//
|
|
// Only root has no parent
|
|
//
|
|
ASSERT (AmlCurrentNodeList == AmlRootNodeList);
|
|
}
|
|
Buffer += 1;
|
|
} while (*Buffer == AML_PARENT_PREFIX_CHAR);
|
|
} else {
|
|
AmlCurrentNodeList = AmlParentNodeList;
|
|
}
|
|
|
|
//
|
|
// Handle name segment
|
|
//
|
|
if (*Buffer == AML_DUAL_NAME_PREFIX) {
|
|
Buffer += 1;
|
|
SegCount = 2;
|
|
} else if (*Buffer == AML_MULTI_NAME_PREFIX) {
|
|
Buffer += 1;
|
|
SegCount = *Buffer;
|
|
Buffer += 1;
|
|
} else if (*Buffer == 0) {
|
|
//
|
|
// NULL name, only for Root
|
|
//
|
|
ASSERT (AmlCurrentNodeList == AmlRootNodeList);
|
|
return AmlCurrentNodeList;
|
|
} else {
|
|
SegCount = 1;
|
|
}
|
|
|
|
//
|
|
// Handle NamePath
|
|
//
|
|
Index = 0;
|
|
do {
|
|
AmlNodeList = AmlFindNodeInThis (Buffer, AmlCurrentNodeList, Create);
|
|
if (AmlNodeList == NULL) {
|
|
return NULL;
|
|
}
|
|
AmlCurrentNodeList = AmlNodeList;
|
|
Buffer += AML_NAME_SEG_SIZE;
|
|
Index ++;
|
|
} while (Index < SegCount);
|
|
|
|
return AmlNodeList;
|
|
}
|
|
|
|
/**
|
|
Insert the NameString to the AmlNodeList.
|
|
|
|
@param[in] NameString AML NameString.
|
|
@param[in] Buffer Buffer for the Node.
|
|
@param[in] Size Size for the Node.
|
|
@param[in] AmlRootNodeList AML root node list.
|
|
@param[in] AmlParentNodeList AML parent node list.
|
|
|
|
@return AmlChildNode whoes name is NameString.
|
|
**/
|
|
EFI_AML_NODE_LIST *
|
|
AmlInsertNodeToTree (
|
|
IN UINT8 *NameString,
|
|
IN VOID *Buffer,
|
|
IN UINTN Size,
|
|
IN EFI_AML_NODE_LIST *AmlRootNodeList,
|
|
IN EFI_AML_NODE_LIST *AmlParentNodeList
|
|
)
|
|
{
|
|
EFI_AML_NODE_LIST *AmlNodeList;
|
|
|
|
AmlNodeList = AmlFindNodeInTheTree (
|
|
NameString,
|
|
AmlRootNodeList,
|
|
AmlParentNodeList,
|
|
TRUE // Find and Create
|
|
);
|
|
ASSERT (AmlNodeList != NULL);
|
|
if (AmlNodeList == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Check buffer
|
|
//
|
|
if (AmlNodeList->Buffer == NULL) {
|
|
//
|
|
// NULL means new added one or SCOPE_OP
|
|
//
|
|
if (*(UINT8 *)Buffer != AML_SCOPE_OP) {
|
|
//
|
|
// We need check if new one is SCOPE_OP, because SCOPE_OP just means namespace, not a real device.
|
|
// We should not return SCOPE_OP.
|
|
//
|
|
AmlNodeList->Buffer = Buffer;
|
|
AmlNodeList->Size = Size;
|
|
AmlNodeList->AmlByteEncoding = AmlSearchByOpByte (Buffer);
|
|
}
|
|
return AmlNodeList;
|
|
}
|
|
|
|
//
|
|
// Already added
|
|
//
|
|
if (*(UINT8 *)Buffer == AML_SCOPE_OP) {
|
|
//
|
|
// The new one is SCOPE_OP, OK just return;
|
|
//
|
|
return AmlNodeList;
|
|
}
|
|
|
|
//
|
|
// Oops!!!, There must be something wrong.
|
|
//
|
|
DEBUG ((EFI_D_ERROR, "AML: Override Happen - %a!\n", NameString));
|
|
DEBUG ((EFI_D_ERROR, "AML: Existing Node - %x\n", AmlNodeList->Buffer));
|
|
DEBUG ((EFI_D_ERROR, "AML: New Buffer - %x\n", Buffer));
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
Construct child node list according to the AML handle.
|
|
|
|
@param[in] AmlHandle AML handle.
|
|
@param[in] AmlRootNodeList AML root node list.
|
|
@param[in] AmlParentNodeList AML parent node list.
|
|
|
|
@retval EFI_SUCCESS Success.
|
|
@retval EFI_INVALID_PARAMETER AML handle does not refer to a valid ACPI object.
|
|
**/
|
|
EFI_STATUS
|
|
AmlConstructNodeListForChild (
|
|
IN EFI_AML_HANDLE *AmlHandle,
|
|
IN EFI_AML_NODE_LIST *AmlRootNodeList,
|
|
IN EFI_AML_NODE_LIST *AmlParentNodeList
|
|
)
|
|
{
|
|
AML_BYTE_ENCODING *AmlByteEncoding;
|
|
UINT8 *Buffer;
|
|
UINTN BufferSize;
|
|
UINT8 *CurrentBuffer;
|
|
EFI_AML_HANDLE *AmlChildHandle;
|
|
EFI_STATUS Status;
|
|
|
|
CurrentBuffer = NULL;
|
|
AmlChildHandle = NULL;
|
|
AmlByteEncoding = AmlHandle->AmlByteEncoding;
|
|
Buffer = AmlHandle->Buffer;
|
|
BufferSize = AmlHandle->Size;
|
|
|
|
//
|
|
// Check if we need recursively add node
|
|
//
|
|
if ((AmlByteEncoding->Attribute & AML_HAS_CHILD_OBJ) == 0) {
|
|
//
|
|
// No more node need to be added
|
|
//
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Do we need add node within METHOD?
|
|
// Yes, just add Object is OK. But we need filter NameString for METHOD invoke.
|
|
//
|
|
|
|
//
|
|
// Now, we get the last node.
|
|
//
|
|
Status = AmlGetOffsetAfterLastOption (AmlHandle, &CurrentBuffer);
|
|
if (EFI_ERROR (Status)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Go through all the reset buffer.
|
|
//
|
|
while ((UINTN)CurrentBuffer < (UINTN)Buffer + BufferSize) {
|
|
//
|
|
// Find the child node.
|
|
//
|
|
Status = SdtOpenEx (CurrentBuffer, (UINTN)Buffer + BufferSize - (UINTN)CurrentBuffer, (EFI_ACPI_HANDLE *)&AmlChildHandle);
|
|
if (EFI_ERROR (Status)) {
|
|
//
|
|
// No child found, break now.
|
|
//
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Good, find the child. Construct node recursively
|
|
//
|
|
Status = AmlConstructNodeList (
|
|
AmlChildHandle,
|
|
AmlRootNodeList,
|
|
AmlParentNodeList
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Parse next one
|
|
//
|
|
CurrentBuffer += AmlChildHandle->Size;
|
|
|
|
Close ((EFI_ACPI_HANDLE)AmlChildHandle);
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Construct node list according to the AML handle.
|
|
|
|
@param[in] AmlHandle AML handle.
|
|
@param[in] AmlRootNodeList AML root node list.
|
|
@param[in] AmlParentNodeList AML parent node list.
|
|
|
|
@retval EFI_SUCCESS Success.
|
|
@retval EFI_INVALID_PARAMETER AML handle does not refer to a valid ACPI object.
|
|
**/
|
|
EFI_STATUS
|
|
AmlConstructNodeList (
|
|
IN EFI_AML_HANDLE *AmlHandle,
|
|
IN EFI_AML_NODE_LIST *AmlRootNodeList,
|
|
IN EFI_AML_NODE_LIST *AmlParentNodeList
|
|
)
|
|
{
|
|
VOID *NameString;
|
|
EFI_AML_NODE_LIST *AmlNodeList;
|
|
|
|
//
|
|
// 1. Check if there is need to construct node for this OpCode.
|
|
//
|
|
if ((AmlHandle->AmlByteEncoding->Attribute & AML_IN_NAMESPACE) == 0) {
|
|
//
|
|
// No need to construct node, so we just skip this OpCode.
|
|
//
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// 2. Now, we need construct node for this OpCode.
|
|
//
|
|
NameString = AmlGetObjectName (AmlHandle);
|
|
if (NameString == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Now, we need to insert node to the node list.
|
|
// NOTE: The name here could be AML NameString. So the callee need parse it.
|
|
//
|
|
AmlNodeList = AmlInsertNodeToTree (NameString, AmlHandle->Buffer, AmlHandle->Size, AmlRootNodeList, AmlParentNodeList);
|
|
ASSERT (AmlNodeList != NULL);
|
|
|
|
//
|
|
// 3. Ok, we need to parse the object list to see if there are more node to be added.
|
|
//
|
|
return AmlConstructNodeListForChild (AmlHandle, AmlRootNodeList, AmlNodeList);
|
|
}
|
|
|
|
/**
|
|
Destruct node list
|
|
|
|
@param[in] AmlParentNodeList AML parent node list.
|
|
**/
|
|
VOID
|
|
AmlDestructNodeList (
|
|
IN EFI_AML_NODE_LIST *AmlParentNodeList
|
|
)
|
|
{
|
|
EFI_AML_NODE_LIST *CurrentAmlNodeList;
|
|
LIST_ENTRY *CurrentLink;
|
|
LIST_ENTRY *StartLink;
|
|
|
|
//
|
|
// Get the children link
|
|
//
|
|
StartLink = &AmlParentNodeList->Children;
|
|
CurrentLink = StartLink->ForwardLink;
|
|
|
|
//
|
|
// Go through all the children
|
|
//
|
|
while (CurrentLink != StartLink) {
|
|
//
|
|
// Destruct the child's list recursively
|
|
//
|
|
CurrentAmlNodeList = EFI_AML_NODE_LIST_FROM_LINK (CurrentLink);
|
|
CurrentLink = CurrentLink->ForwardLink;
|
|
|
|
//
|
|
// Remove this child from list and free the node
|
|
//
|
|
RemoveEntryList (&(CurrentAmlNodeList->Link));
|
|
|
|
AmlDestructNodeList (CurrentAmlNodeList);
|
|
}
|
|
|
|
//
|
|
// Done.
|
|
//
|
|
FreePool (AmlParentNodeList);
|
|
return ;
|
|
}
|
|
|
|
/**
|
|
Dump node list
|
|
|
|
@param[in] AmlParentNodeList AML parent node list.
|
|
@param[in] Level Output debug level.
|
|
**/
|
|
VOID
|
|
AmlDumpNodeInfo (
|
|
IN EFI_AML_NODE_LIST *AmlParentNodeList,
|
|
IN UINTN Level
|
|
)
|
|
{
|
|
EFI_AML_NODE_LIST *CurrentAmlNodeList;
|
|
volatile LIST_ENTRY *CurrentLink;
|
|
UINTN Index;
|
|
|
|
CurrentLink = AmlParentNodeList->Children.ForwardLink;
|
|
|
|
if (Level == 0) {
|
|
DEBUG ((EFI_D_ERROR, "\\"));
|
|
} else {
|
|
for (Index = 0; Index < Level; Index++) {
|
|
DEBUG ((EFI_D_ERROR, " "));
|
|
}
|
|
AmlPrintNameSeg (AmlParentNodeList->Name);
|
|
}
|
|
DEBUG ((EFI_D_ERROR, "\n"));
|
|
|
|
while (CurrentLink != &AmlParentNodeList->Children) {
|
|
CurrentAmlNodeList = EFI_AML_NODE_LIST_FROM_LINK (CurrentLink);
|
|
AmlDumpNodeInfo (CurrentAmlNodeList, Level + 1);
|
|
CurrentLink = CurrentLink->ForwardLink;
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
/**
|
|
Returns the handle of the ACPI object representing the specified ACPI AML path
|
|
|
|
@param[in] AmlHandle Points to the handle of the object representing the starting point for the path search.
|
|
@param[in] AmlPath Points to the ACPI AML path.
|
|
@param[out] Buffer On return, points to the ACPI object which represents AcpiPath, relative to
|
|
HandleIn.
|
|
@param[in] FromRoot TRUE means to find AML path from \ (Root) Node.
|
|
FALSE means to find AML path from this Node (The HandleIn).
|
|
|
|
@retval EFI_SUCCESS Success
|
|
@retval EFI_INVALID_PARAMETER HandleIn does not refer to a valid ACPI object.
|
|
**/
|
|
EFI_STATUS
|
|
AmlFindPath (
|
|
IN EFI_AML_HANDLE *AmlHandle,
|
|
IN UINT8 *AmlPath,
|
|
OUT VOID **Buffer,
|
|
IN BOOLEAN FromRoot
|
|
)
|
|
{
|
|
EFI_AML_NODE_LIST *AmlRootNodeList;
|
|
EFI_STATUS Status;
|
|
EFI_AML_NODE_LIST *AmlNodeList;
|
|
UINT8 RootNameSeg[AML_NAME_SEG_SIZE];
|
|
EFI_AML_NODE_LIST *CurrentAmlNodeList;
|
|
LIST_ENTRY *CurrentLink;
|
|
|
|
//
|
|
// 1. create tree
|
|
//
|
|
|
|
//
|
|
// Create root handle
|
|
//
|
|
RootNameSeg[0] = AML_ROOT_CHAR;
|
|
RootNameSeg[1] = 0;
|
|
AmlRootNodeList = AmlCreateNode (RootNameSeg, NULL, AmlHandle->AmlByteEncoding);
|
|
|
|
Status = AmlConstructNodeList (
|
|
AmlHandle,
|
|
AmlRootNodeList, // Root
|
|
AmlRootNodeList // Parent
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
DEBUG_CODE_BEGIN ();
|
|
DEBUG ((EFI_D_ERROR, "AcpiSdt: NameSpace:\n"));
|
|
AmlDumpNodeInfo (AmlRootNodeList, 0);
|
|
DEBUG_CODE_END ();
|
|
|
|
//
|
|
// 2. Search the node in the tree
|
|
//
|
|
if (FromRoot) {
|
|
//
|
|
// Search from Root
|
|
//
|
|
CurrentAmlNodeList = AmlRootNodeList;
|
|
} else {
|
|
//
|
|
// Search from this node, NOT ROOT.
|
|
// Since we insert node to ROOT one by one, we just get the first node and search from it.
|
|
//
|
|
CurrentLink = AmlRootNodeList->Children.ForwardLink;
|
|
if (CurrentLink != &AmlRootNodeList->Children) {
|
|
//
|
|
// First node
|
|
//
|
|
CurrentAmlNodeList = EFI_AML_NODE_LIST_FROM_LINK (CurrentLink);
|
|
} else {
|
|
//
|
|
// No child
|
|
//
|
|
CurrentAmlNodeList = NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Search
|
|
//
|
|
if (CurrentAmlNodeList != NULL) {
|
|
DEBUG_CODE_BEGIN ();
|
|
DEBUG ((EFI_D_ERROR, "AcpiSdt: Search from: \\"));
|
|
AmlPrintNameSeg (CurrentAmlNodeList->Name);
|
|
DEBUG ((EFI_D_ERROR, "\n"));
|
|
DEBUG_CODE_END ();
|
|
AmlNodeList = AmlFindNodeInTheTree (
|
|
AmlPath,
|
|
AmlRootNodeList, // Root
|
|
CurrentAmlNodeList, // Parent
|
|
FALSE
|
|
);
|
|
} else {
|
|
AmlNodeList = NULL;
|
|
}
|
|
|
|
*Buffer = NULL;
|
|
Status = EFI_SUCCESS;
|
|
if (AmlNodeList != NULL && AmlNodeList->Buffer != NULL) {
|
|
*Buffer = AmlNodeList->Buffer;
|
|
}
|
|
|
|
//
|
|
// 3. free the tree
|
|
//
|
|
AmlDestructNodeList (AmlRootNodeList);
|
|
|
|
return Status;
|
|
}
|