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