diff options
author | raywu <raywu0301@gmail.com> | 2018-06-15 00:00:50 +0800 |
---|---|---|
committer | raywu <raywu0301@gmail.com> | 2018-06-15 00:00:50 +0800 |
commit | b7c51c9cf4864df6aabb99a1ae843becd577237c (patch) | |
tree | eebe9b0d0ca03062955223097e57da84dd618b9a /Core/EM/ACPI/AmlNamespace.c | |
download | zprj-master.tar.xz |
Diffstat (limited to 'Core/EM/ACPI/AmlNamespace.c')
-rw-r--r-- | Core/EM/ACPI/AmlNamespace.c | 659 |
1 files changed, 659 insertions, 0 deletions
diff --git a/Core/EM/ACPI/AmlNamespace.c b/Core/EM/ACPI/AmlNamespace.c new file mode 100644 index 0000000..2c72400 --- /dev/null +++ b/Core/EM/ACPI/AmlNamespace.c @@ -0,0 +1,659 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2011, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** + +//********************************************************************** +// $Header: /Alaska/BIN/Modules/ACPI/Template/Core/AmlNamespace.c 2 5/14/11 2:11p Yakovlevs $ +// +// $Revision: 2 $ +// +// $Date: 5/14/11 2:11p $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/BIN/Modules/ACPI/Template/Core/AmlNamespace.c $ +// +// 2 5/14/11 2:11p Yakovlevs +// [TAG] EIP 56526 +// [Category] New Feature +// [Description] ACPI Manipulation Protocol. PI 1.2 Spec Vol 5 Section +// 9. Initial checkin. +// [Files] AcpiCore.c; AcpiCore.h; AcpiSdtPrivate.h; Aml.c; AmlChild.c; +// AmlNamespace.c; AmlOption.c; AmlString.c AcpiSdt.c; +// Protocol\AcpiSdt.h. +// +//********************************************************************** + + +//********************************************************************** +//<AMI_FHDR_START> +// +// Name: AmlNamespace.c +// +// Description: +// ACPI AML Name space parsing/manipulation functions for ACPI SDT. +// +//<AMI_FHDR_END> +//********************************************************************** + +#include "AcpiCore.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 = Malloc(sizeof(*AmlNodeList)); + ASSERT (AmlNodeList != NULL); + + AmlNodeList->Signature = EFI_AML_NODE_LIST_SIGNATURE; + pBS->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 (MemCmp (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. + // + TRACE ((-1, "AML: Override Happen - %a!\n", NameString)); + TRACE ((-1, "AML: Existing Node - %x\n", AmlNodeList->Buffer)); + TRACE ((-1, "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; + + 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. + // + pBS->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) { + TRACE ((-1, "\\")); + } else { + for (Index = 0; Index < Level; Index++) { + TRACE ((-1, " ")); + } + AmlPrintNameSeg (AmlParentNodeList->Name); + } + TRACE ((-1, "\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; + } + +#if EFI_DEBUG + TRACE ((-1, "AcpiSdt: NameSpace:\n")); + AmlDumpNodeInfo (AmlRootNodeList, 0); +#endif + // + // 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) { +#if EFI_DEBUG + TRACE ((-1, "AcpiSdt: Search from: \\")); + AmlPrintNameSeg (CurrentAmlNodeList->Name); + TRACE ((-1, "\n")); +#endif + 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; +} + +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2011, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** |