]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Acpi/AcpiTableDxe/AmlNamespace.c
MdeModulePkg:
[mirror_edk2.git] / MdeModulePkg / Universal / Acpi / AcpiTableDxe / AmlNamespace.c
diff --git a/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AmlNamespace.c b/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AmlNamespace.c
new file mode 100644 (file)
index 0000000..b62256e
--- /dev/null
@@ -0,0 +1,612 @@
+/** @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