]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiSdt.c
MdeModulePkg:
[mirror_edk2.git] / MdeModulePkg / Universal / Acpi / AcpiTableDxe / AcpiSdt.c
diff --git a/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiSdt.c b/MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiSdt.c
new file mode 100644 (file)
index 0000000..5aad7cc
--- /dev/null
@@ -0,0 +1,1112 @@
+/** @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
+//\r
+// Includes\r
+//\r
+#include "AcpiTable.h"\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED\r
+EFI_ACPI_SDT_PROTOCOL  mAcpiSdtProtocolTemplate = {\r
+  EFI_ACPI_TABLE_VERSION_NONE | EFI_ACPI_TABLE_VERSION_1_0B | EFI_ACPI_TABLE_VERSION_2_0 | EFI_ACPI_TABLE_VERSION_3_0 | EFI_ACPI_TABLE_VERSION_4_0,\r
+  GetAcpiTable2,\r
+  RegisterNotify,\r
+  Open,\r
+  OpenSdt,\r
+  Close,\r
+  GetChild,\r
+  GetOption,\r
+  SetOption,\r
+  FindPath\r
+};\r
+\r
+/**\r
+  This function returns ACPI Table instance.\r
+\r
+  @return AcpiTableInstance\r
+**/\r
+EFI_ACPI_TABLE_INSTANCE *\r
+SdtGetAcpiTableInstance (\r
+  VOID\r
+  )\r
+{\r
+  return mPrivateData;\r
+}\r
+\r
+/**\r
+  This function finds the table specified by the buffer.\r
+\r
+  @param[in]  Buffer      Table buffer to find.\r
+\r
+  @return ACPI table list.\r
+**/\r
+EFI_ACPI_TABLE_LIST *\r
+FindTableByBuffer (\r
+  IN VOID  *Buffer\r
+  )\r
+{\r
+  EFI_ACPI_TABLE_INSTANCE   *AcpiTableInstance;\r
+  LIST_ENTRY                *CurrentLink;\r
+  EFI_ACPI_TABLE_LIST       *CurrentTableList;\r
+  LIST_ENTRY                *StartLink;\r
+\r
+  //\r
+  // Get the instance of the ACPI Table\r
+  //\r
+  AcpiTableInstance = SdtGetAcpiTableInstance ();\r
+\r
+  //\r
+  // Find the notify\r
+  //\r
+  StartLink   = &AcpiTableInstance->TableList;\r
+  CurrentLink = StartLink->ForwardLink;\r
+\r
+  while (CurrentLink != StartLink) {\r
+    CurrentTableList = EFI_ACPI_TABLE_LIST_FROM_LINK (CurrentLink);\r
+    if (((UINTN)CurrentTableList->PageAddress <= (UINTN)Buffer) &&\r
+        ((UINTN)CurrentTableList->PageAddress + EFI_PAGES_TO_SIZE(CurrentTableList->NumberOfPages) > (UINTN)Buffer)) {\r
+      //\r
+      // Good! Found Table.\r
+      //\r
+      return CurrentTableList;\r
+    }\r
+\r
+    CurrentLink = CurrentLink->ForwardLink;\r
+  }\r
+\r
+  return NULL;\r
+}\r
+\r
+/**\r
+  This function updates AML table checksum.\r
+  It will search the ACPI table installed by ACPI_TABLE protocol.\r
+\r
+  @param[in]  Buffer        A piece of AML code buffer pointer.\r
+\r
+  @retval EFI_SUCCESS       The table holds the AML buffer is found, and checksum is updated.\r
+  @retval EFI_NOT_FOUND     The table holds the AML buffer is not found.\r
+**/\r
+EFI_STATUS\r
+SdtUpdateAmlChecksum (\r
+  IN VOID  *Buffer\r
+  )\r
+{\r
+  EFI_ACPI_TABLE_LIST       *CurrentTableList;\r
+\r
+  CurrentTableList = FindTableByBuffer (Buffer);\r
+  if (CurrentTableList == NULL) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  AcpiPlatformChecksum (\r
+    (VOID *)CurrentTableList->Table,\r
+    CurrentTableList->Table->Length,\r
+    OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER, Checksum)\r
+    );\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  This function finds MAX AML buffer size.\r
+  It will search the ACPI table installed by ACPI_TABLE protocol.\r
+\r
+  @param[in]  Buffer        A piece of AML code buffer pointer.\r
+  @param[out] MaxSize       On return it holds the MAX size of buffer.\r
+\r
+  @retval EFI_SUCCESS       The table holds the AML buffer is found, and MAX size if returned.\r
+  @retval EFI_NOT_FOUND     The table holds the AML buffer is not found.\r
+**/\r
+EFI_STATUS\r
+SdtGetMaxAmlBufferSize (\r
+  IN  VOID  *Buffer,\r
+  OUT UINTN *MaxSize\r
+  )\r
+{\r
+  EFI_ACPI_TABLE_LIST       *CurrentTableList;\r
+\r
+  CurrentTableList = FindTableByBuffer (Buffer);\r
+  if (CurrentTableList == NULL) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  *MaxSize = (UINTN)CurrentTableList->Table + CurrentTableList->Table->Length - (UINTN)Buffer;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  This function invokes ACPI notification.\r
+\r
+  @param[in]  AcpiTableInstance          Instance to AcpiTable\r
+  @param[in]  Version                    Version(s) to set.\r
+  @param[in]  Handle                     Handle of the table.\r
+**/\r
+VOID\r
+SdtNotifyAcpiList (\r
+  IN EFI_ACPI_TABLE_INSTANCE   *AcpiTableInstance,\r
+  IN EFI_ACPI_TABLE_VERSION    Version,\r
+  IN UINTN                     Handle\r
+  )\r
+{\r
+  EFI_ACPI_NOTIFY_LIST      *CurrentNotifyList;\r
+  LIST_ENTRY                *CurrentLink;\r
+  LIST_ENTRY                *StartLink;\r
+  EFI_ACPI_TABLE_LIST       *Table;\r
+  EFI_STATUS                Status;\r
+\r
+  //\r
+  // We should not use Table buffer, because it is user input buffer.\r
+  //\r
+  Status = FindTableByHandle (\r
+             Handle,\r
+             &AcpiTableInstance->TableList,\r
+             &Table\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Find the notify\r
+  //\r
+  StartLink   = &AcpiTableInstance->NotifyList;\r
+  CurrentLink = StartLink->ForwardLink;\r
+\r
+  while (CurrentLink != StartLink) {\r
+    CurrentNotifyList = EFI_ACPI_NOTIFY_LIST_FROM_LINK (CurrentLink);\r
+\r
+    //\r
+    // Inovke notification\r
+    //\r
+    CurrentNotifyList->Notification ((EFI_ACPI_SDT_HEADER *)Table->Table, Version, Handle);\r
+\r
+    CurrentLink = CurrentLink->ForwardLink;\r
+  }\r
+\r
+  return ;\r
+}\r
+\r
+/**\r
+  Returns a requested ACPI table.\r
+  \r
+  The GetAcpiTable() function returns a pointer to a buffer containing the ACPI table associated\r
+  with the Index that was input. The following structures are not considered elements in the list of\r
+  ACPI tables:\r
+  - Root System Description Pointer (RSD_PTR)\r
+  - Root System Description Table (RSDT)\r
+  - Extended System Description Table (XSDT)\r
+  Version is updated with a bit map containing all the versions of ACPI of which the table is a\r
+  member.\r
+  \r
+  @param[in]    Index       The zero-based index of the table to retrieve.\r
+  @param[out]   Table       Pointer for returning the table buffer.\r
+  @param[out]   Version     On return, updated with the ACPI versions to which this table belongs. Type\r
+                            EFI_ACPI_TABLE_VERSION is defined in "Related Definitions" in the\r
+                            EFI_ACPI_SDT_PROTOCOL.    \r
+  @param[out]   TableKey    On return, points to the table key for the specified ACPI system definition table. This\r
+                            is identical to the table key used in the EFI_ACPI_TABLE_PROTOCOL.  \r
+                            \r
+  @retval EFI_SUCCESS       The function completed successfully.\r
+  @retval EFI_NOT_FOUND     The requested index is too large and a table was not found.                                  \r
+**/  \r
+EFI_STATUS\r
+EFIAPI\r
+GetAcpiTable2 (\r
+  IN  UINTN                               Index,\r
+  OUT EFI_ACPI_SDT_HEADER                 **Table,\r
+  OUT EFI_ACPI_TABLE_VERSION              *Version,\r
+  OUT UINTN                               *TableKey\r
+  )\r
+{\r
+  EFI_ACPI_TABLE_INSTANCE   *AcpiTableInstance;\r
+  UINTN                     TableIndex;\r
+  LIST_ENTRY                *CurrentLink;\r
+  LIST_ENTRY                *StartLink;\r
+  EFI_ACPI_TABLE_LIST       *CurrentTable;\r
+\r
+  ASSERT (Table != NULL);\r
+  ASSERT (Version != NULL);\r
+  ASSERT (TableKey != NULL);\r
+\r
+  //\r
+  // Get the instance of the ACPI Table\r
+  //\r
+  AcpiTableInstance = SdtGetAcpiTableInstance ();\r
+\r
+  //\r
+  // Find the table\r
+  //\r
+  StartLink   = &AcpiTableInstance->TableList;\r
+  CurrentLink = StartLink->ForwardLink;\r
+  TableIndex = 0;\r
+\r
+  while (CurrentLink != StartLink) {\r
+    if (TableIndex == Index) {\r
+      break;\r
+    }\r
+    //\r
+    // Next one\r
+    //\r
+    CurrentLink = CurrentLink->ForwardLink;\r
+    TableIndex ++;\r
+  }\r
+\r
+  if ((TableIndex != Index) || (CurrentLink == StartLink)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  //\r
+  // Get handle and version\r
+  //\r
+  CurrentTable  = EFI_ACPI_TABLE_LIST_FROM_LINK (CurrentLink);\r
+  *TableKey     = CurrentTable->Handle;\r
+  *Version      = CurrentTable->Version;\r
+  *Table        = (EFI_ACPI_SDT_HEADER *)CurrentTable->Table;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Register a callback when an ACPI table is installed.\r
+  \r
+  This function registers a function which will be called whenever a new ACPI table is installed.\r
+  \r
+  @param[in]  Notification               Points to the callback function to be registered\r
+**/\r
+VOID\r
+SdtRegisterNotify (\r
+  IN EFI_ACPI_NOTIFICATION_FN   Notification\r
+  )\r
+{\r
+  EFI_ACPI_TABLE_INSTANCE   *AcpiTableInstance;\r
+  EFI_ACPI_NOTIFY_LIST      *CurrentNotifyList;\r
+\r
+  //\r
+  // Get the instance of the ACPI Table\r
+  //\r
+  AcpiTableInstance = SdtGetAcpiTableInstance ();\r
+\r
+  //\r
+  // Create a new list entry\r
+  //\r
+  CurrentNotifyList = AllocatePool (sizeof (EFI_ACPI_NOTIFY_LIST));\r
+  ASSERT (CurrentNotifyList != NULL);\r
+\r
+  //\r
+  // Initialize the table contents\r
+  //\r
+  CurrentNotifyList->Signature    = EFI_ACPI_NOTIFY_LIST_SIGNATURE;\r
+  CurrentNotifyList->Notification = Notification;\r
+\r
+  //\r
+  // Add the table to the current list of tables\r
+  //\r
+  InsertTailList (&AcpiTableInstance->NotifyList, &CurrentNotifyList->Link);\r
+\r
+  return ;\r
+}\r
+\r
+/**\r
+  Unregister a callback when an ACPI table is installed.\r
+  \r
+  This function unregisters a function which will be called whenever a new ACPI table is installed.\r
+  \r
+  @param[in]  Notification               Points to the callback function to be unregistered.\r
+  \r
+  @retval EFI_SUCCESS           Callback successfully unregistered.\r
+  @retval EFI_INVALID_PARAMETER Notification does not match a known registration function.                        \r
+**/\r
+EFI_STATUS\r
+SdtUnregisterNotify (\r
+  IN EFI_ACPI_NOTIFICATION_FN   Notification\r
+  )\r
+{\r
+  EFI_ACPI_TABLE_INSTANCE   *AcpiTableInstance;\r
+  EFI_ACPI_NOTIFY_LIST      *CurrentNotifyList;\r
+  LIST_ENTRY                *CurrentLink;\r
+  LIST_ENTRY                *StartLink;\r
+\r
+  //\r
+  // Get the instance of the ACPI Table\r
+  //\r
+  AcpiTableInstance = SdtGetAcpiTableInstance ();\r
+\r
+  //\r
+  // Find the notify\r
+  //\r
+  StartLink   = &AcpiTableInstance->NotifyList;\r
+  CurrentLink = StartLink->ForwardLink;\r
+\r
+  while (CurrentLink != StartLink) {\r
+    CurrentNotifyList = EFI_ACPI_NOTIFY_LIST_FROM_LINK (CurrentLink);\r
+    if (CurrentNotifyList->Notification == Notification) {\r
+      //\r
+      // Good! Found notification.\r
+      //\r
+      // Remove it from list and free the node.\r
+      //\r
+      RemoveEntryList (&(CurrentNotifyList->Link));\r
+      FreePool (CurrentNotifyList);\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    CurrentLink = CurrentLink->ForwardLink;\r
+  }\r
+\r
+  //\r
+  // Not found!\r
+  //\r
+  return EFI_INVALID_PARAMETER;\r
+}\r
+\r
+/**\r
+  Register or unregister a callback when an ACPI table is installed.\r
+  \r
+  This function registers or unregisters a function which will be called whenever a new ACPI table is\r
+  installed.\r
+  \r
+  @param[in]    Register        If TRUE, then the specified function will be registered. If FALSE, then the specified\r
+                                function will be unregistered.\r
+  @param[in]    Notification    Points to the callback function to be registered or unregistered.\r
+  \r
+  @retval EFI_SUCCESS           Callback successfully registered or unregistered.\r
+  @retval EFI_INVALID_PARAMETER Notification is NULL\r
+  @retval EFI_INVALID_PARAMETER Register is FALSE and Notification does not match a known registration function.                        \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RegisterNotify (\r
+  IN BOOLEAN                    Register,\r
+  IN EFI_ACPI_NOTIFICATION_FN   Notification\r
+  )\r
+{\r
+  //\r
+  // Check for invalid input parameters\r
+  //\r
+  if (Notification == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (Register) {\r
+    //\r
+    // Register a new notify\r
+    //\r
+    SdtRegisterNotify (Notification);\r
+    return EFI_SUCCESS;\r
+  } else {\r
+    //\r
+    // Unregister an old notify\r
+    //\r
+    return SdtUnregisterNotify (Notification);\r
+  }\r
+}\r
+\r
+/**\r
+  Create a handle for the first ACPI opcode in an ACPI system description table.\r
+  \r
+  @param[in]    TableKey    The table key for the ACPI table, as returned by GetTable().\r
+  @param[out]   Handle      On return, points to the newly created ACPI handle.\r
+\r
+  @retval EFI_SUCCESS       Handle created successfully.\r
+  @retval EFI_NOT_FOUND     TableKey does not refer to a valid ACPI table.  \r
+**/\r
+EFI_STATUS\r
+SdtOpenSdtTable (\r
+  IN    UINTN           TableKey,\r
+  OUT   EFI_ACPI_HANDLE *Handle\r
+  )\r
+{\r
+  EFI_ACPI_TABLE_INSTANCE   *AcpiTableInstance;\r
+  EFI_STATUS                Status;\r
+  EFI_ACPI_TABLE_LIST       *Table;\r
+  EFI_AML_HANDLE            *AmlHandle;\r
+\r
+  //\r
+  // Get the instance of the ACPI Table\r
+  //\r
+  AcpiTableInstance = SdtGetAcpiTableInstance ();\r
+\r
+  //\r
+  // Find the table\r
+  //\r
+  Status = FindTableByHandle (\r
+             TableKey,\r
+             &AcpiTableInstance->TableList,\r
+             &Table\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  AmlHandle = AllocatePool (sizeof(*AmlHandle));\r
+  ASSERT (AmlHandle != NULL);\r
+  AmlHandle->Signature       = EFI_AML_ROOT_HANDLE_SIGNATURE;\r
+  AmlHandle->Buffer          = (VOID *)((UINTN)Table->Table + sizeof(EFI_ACPI_SDT_HEADER));\r
+  AmlHandle->Size            = Table->Table->Length - sizeof(EFI_ACPI_SDT_HEADER);\r
+  AmlHandle->AmlByteEncoding = NULL;\r
+  AmlHandle->Modified        = FALSE;\r
+\r
+  //\r
+  // return the ACPI handle\r
+  //\r
+  *Handle = (EFI_ACPI_HANDLE)AmlHandle;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Create a handle for the first ACPI opcode in an ACPI system description table.\r
+  \r
+  @param[in]    TableKey    The table key for the ACPI table, as returned by GetTable().\r
+  @param[out]   Handle      On return, points to the newly created ACPI handle.\r
+\r
+  @retval EFI_SUCCESS       Handle created successfully.\r
+  @retval EFI_NOT_FOUND     TableKey does not refer to a valid ACPI table.  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OpenSdt (\r
+  IN    UINTN           TableKey,\r
+  OUT   EFI_ACPI_HANDLE *Handle\r
+  )\r
+{\r
+  if (Handle == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  return SdtOpenSdtTable (TableKey, Handle);\r
+}\r
+\r
+/**\r
+  Create a handle from an ACPI opcode\r
+  \r
+  @param[in]  Buffer                 Points to the ACPI opcode.\r
+  @param[in]  BufferSize             Max buffer size.\r
+  @param[out] Handle                 Upon return, holds the handle.\r
+  \r
+  @retval   EFI_SUCCESS             Success\r
+  @retval   EFI_INVALID_PARAMETER   Buffer is NULL or Handle is NULL or Buffer points to an\r
+                                    invalid opcode.\r
+  \r
+**/\r
+EFI_STATUS\r
+SdtOpenEx (\r
+  IN    VOID            *Buffer,\r
+  IN    UINTN           BufferSize,\r
+  OUT   EFI_ACPI_HANDLE *Handle \r
+  )\r
+{\r
+  AML_BYTE_ENCODING   *AmlByteEncoding;\r
+  EFI_AML_HANDLE      *AmlHandle;\r
+\r
+  AmlByteEncoding = AmlSearchByOpByte (Buffer);\r
+  if (AmlByteEncoding == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Do not open NameString as handle\r
+  //\r
+  if ((AmlByteEncoding->Attribute & AML_IS_NAME_CHAR) != 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Good, find it\r
+  //\r
+  AmlHandle = AllocatePool (sizeof(*AmlHandle));\r
+  ASSERT (AmlHandle != NULL);\r
+  \r
+  AmlHandle->Signature       = EFI_AML_HANDLE_SIGNATURE;\r
+  AmlHandle->Buffer          = Buffer;\r
+  AmlHandle->AmlByteEncoding = AmlByteEncoding;\r
+  AmlHandle->Modified        = FALSE;\r
+\r
+  AmlHandle->Size = AmlGetObjectSize (AmlByteEncoding, Buffer, BufferSize);\r
+  if (AmlHandle->Size == 0) {\r
+    FreePool (AmlHandle);\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  *Handle = (EFI_ACPI_HANDLE)AmlHandle;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Create a handle from an ACPI opcode\r
+  \r
+  @param[in]  Buffer                 Points to the ACPI opcode.\r
+  @param[out] Handle                 Upon return, holds the handle.\r
+  \r
+  @retval   EFI_SUCCESS             Success\r
+  @retval   EFI_INVALID_PARAMETER   Buffer is NULL or Handle is NULL or Buffer points to an\r
+                                    invalid opcode.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Open (\r
+  IN    VOID            *Buffer,\r
+  OUT   EFI_ACPI_HANDLE *Handle \r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  UINTN               MaxSize;\r
+\r
+  //\r
+  // Check for invalid input parameters\r
+  //\r
+  if (Buffer == NULL || Handle == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status = SdtGetMaxAmlBufferSize (Buffer, &MaxSize);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  return SdtOpenEx (Buffer, MaxSize, Handle);\r
+}\r
+\r
+/**\r
+  Close an ACPI handle.\r
+  \r
+  @param[in] Handle Returns the handle.\r
+  \r
+  @retval EFI_SUCCESS           Success\r
+  @retval EFI_INVALID_PARAMETER Handle is NULL or does not refer to a valid ACPI object.  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Close (\r
+  IN EFI_ACPI_HANDLE Handle\r
+  )\r
+{\r
+  EFI_AML_HANDLE      *AmlHandle;\r
+  EFI_STATUS          Status;\r
+\r
+  //\r
+  // Check for invalid input parameters\r
+  //\r
+  if (Handle == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  AmlHandle = (EFI_AML_HANDLE *)Handle;\r
+  if ((AmlHandle->Signature != EFI_AML_ROOT_HANDLE_SIGNATURE) &&\r
+      (AmlHandle->Signature != EFI_AML_HANDLE_SIGNATURE)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Update Checksum only if modified\r
+  //\r
+  if (AmlHandle->Modified) {\r
+    Status = SdtUpdateAmlChecksum (AmlHandle->Buffer);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  }\r
+\r
+  FreePool (AmlHandle);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Retrieve information about an ACPI object.\r
+  \r
+  @param[in]    Handle      ACPI object handle.\r
+  @param[in]    Index       Index of the data to retrieve from the object. In general, indexes read from left-to-right\r
+                            in the ACPI encoding, with index 0 always being the ACPI opcode.\r
+  @param[out]   DataType    Points to the returned data type or EFI_ACPI_DATA_TYPE_NONE if no data exists\r
+                            for the specified index.\r
+  @param[out]   Data        Upon return, points to the pointer to the data.\r
+  @param[out]   DataSize    Upon return, points to the size of Data.\r
+  \r
+  @retval       EFI_SUCCESS           Success.\r
+  @retval       EFI_INVALID_PARAMETER Handle is NULL or does not refer to a valid ACPI object.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetOption (\r
+  IN        EFI_ACPI_HANDLE     Handle,\r
+  IN        UINTN               Index,\r
+  OUT       EFI_ACPI_DATA_TYPE  *DataType,\r
+  OUT CONST VOID                **Data,\r
+  OUT       UINTN               *DataSize\r
+  )\r
+{\r
+  EFI_AML_HANDLE      *AmlHandle;\r
+  AML_BYTE_ENCODING   *AmlByteEncoding;\r
+  EFI_STATUS          Status;\r
+\r
+  ASSERT (DataType != NULL);\r
+  ASSERT (Data != NULL);\r
+  ASSERT (DataSize != NULL);\r
+\r
+  //\r
+  // Check for invalid input parameters\r
+  //\r
+  if (Handle == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  AmlHandle = (EFI_AML_HANDLE *)Handle;\r
+  //\r
+  // Do not check EFI_AML_ROOT_HANDLE_SIGNATURE because there is no option for Root handle\r
+  //\r
+  if (AmlHandle->Signature != EFI_AML_HANDLE_SIGNATURE) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  AmlByteEncoding = AmlHandle->AmlByteEncoding;\r
+  if (Index > AmlByteEncoding->MaxIndex) {\r
+    *DataType = EFI_ACPI_DATA_TYPE_NONE;\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Parse option\r
+  //\r
+  Status = AmlParseOptionHandleCommon (AmlHandle, (AML_OP_PARSE_INDEX)Index, DataType, (VOID **)Data, DataSize);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Change information about an ACPI object.\r
+  \r
+  @param[in]  Handle    ACPI object handle.\r
+  @param[in]  Index     Index of the data to retrieve from the object. In general, indexes read from left-to-right\r
+                        in the ACPI encoding, with index 0 always being the ACPI opcode.\r
+  @param[in]  Data      Points to the data.\r
+  @param[in]  DataSize  The size of the Data.\r
+\r
+  @retval EFI_SUCCESS           Success\r
+  @retval EFI_INVALID_PARAMETER Handle is NULL or does not refer to a valid ACPI object.\r
+  @retval EFI_BAD_BUFFER_SIZE   Data cannot be accommodated in the space occupied by\r
+                                the option.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SetOption (\r
+  IN        EFI_ACPI_HANDLE Handle,\r
+  IN        UINTN           Index,\r
+  IN CONST  VOID            *Data,\r
+  IN        UINTN           DataSize\r
+  )\r
+{\r
+  EFI_AML_HANDLE      *AmlHandle;\r
+  AML_BYTE_ENCODING   *AmlByteEncoding;\r
+  EFI_STATUS          Status;\r
+  EFI_ACPI_DATA_TYPE  DataType;\r
+  VOID                *OrgData;\r
+  UINTN               OrgDataSize;\r
+\r
+  ASSERT (Data != NULL);\r
+\r
+  //\r
+  // Check for invalid input parameters\r
+  //\r
+  if (Handle == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  AmlHandle = (EFI_AML_HANDLE *)Handle;\r
+  //\r
+  // Do not check EFI_AML_ROOT_HANDLE_SIGNATURE because there is no option for Root handle\r
+  //\r
+  if (AmlHandle->Signature != EFI_AML_HANDLE_SIGNATURE) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  AmlByteEncoding = AmlHandle->AmlByteEncoding;\r
+\r
+  if (Index > AmlByteEncoding->MaxIndex) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Parse option\r
+  //\r
+  Status = AmlParseOptionHandleCommon (AmlHandle, (AML_OP_PARSE_INDEX)Index, &DataType, &OrgData, &OrgDataSize);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  if (DataType == EFI_ACPI_DATA_TYPE_NONE) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (DataSize > OrgDataSize) {\r
+    return EFI_BAD_BUFFER_SIZE;\r
+  }\r
+\r
+  //\r
+  // Update\r
+  //\r
+  CopyMem (OrgData, Data, DataSize);\r
+  AmlHandle->Modified = TRUE;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Return the child ACPI objects.\r
+  \r
+  @param[in]        ParentHandle    Parent handle.\r
+  @param[in, out]   Handle          On entry, points to the previously returned handle or NULL to start with the first\r
+                                    handle. On return, points to the next returned ACPI handle or NULL if there are no\r
+                                    child objects.\r
+\r
+  @retval EFI_SUCCESS               Success\r
+  @retval EFI_INVALID_PARAMETER     ParentHandle is NULL or does not refer to a valid ACPI object.                                \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetChild (\r
+  IN EFI_ACPI_HANDLE        ParentHandle,\r
+  IN OUT EFI_ACPI_HANDLE    *Handle\r
+  )\r
+{\r
+  EFI_AML_HANDLE      *AmlParentHandle;\r
+  EFI_AML_HANDLE      *AmlHandle;\r
+  VOID                *Buffer;\r
+  EFI_STATUS          Status;\r
+\r
+  ASSERT (Handle != NULL);\r
+\r
+  //\r
+  // Check for invalid input parameters\r
+  //\r
+  if (ParentHandle == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  AmlHandle       = *Handle;\r
+  if ((AmlHandle != NULL) && (AmlHandle->Signature != EFI_AML_HANDLE_SIGNATURE)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  AmlParentHandle = (EFI_AML_HANDLE *)ParentHandle;\r
+  if (AmlParentHandle->Signature == EFI_AML_ROOT_HANDLE_SIGNATURE) {\r
+    //\r
+    // Root handle\r
+    //\r
+    Status = AmlGetChildFromRoot (AmlParentHandle, AmlHandle, &Buffer);\r
+  } else if (AmlParentHandle->Signature == EFI_AML_HANDLE_SIGNATURE) {\r
+    //\r
+    // Non-root handle\r
+    //\r
+    Status = AmlGetChildFromNonRoot (AmlParentHandle, AmlHandle, &Buffer);\r
+  } else {\r
+    //\r
+    // Invalid\r
+    //\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  if (Buffer == NULL) {\r
+    *Handle = NULL;\r
+    return EFI_SUCCESS;\r
+  }\r
+  return SdtOpenEx (Buffer, (UINTN)AmlParentHandle->Buffer + AmlParentHandle->Size - (UINTN)Buffer, Handle);\r
+}\r
+\r
+/**\r
+  Returns the handle of the ACPI object representing the specified ACPI path\r
+  \r
+  @param[in]    HandleIn    Points to the handle of the object representing the starting point for the path search.\r
+  @param[in]    AmlPath     Points to the AML path.\r
+  @param[out]   HandleOut   On return, points to the ACPI object which represents AcpiPath, relative to\r
+                            HandleIn.\r
+                            \r
+  @retval EFI_SUCCESS           Success\r
+  @retval EFI_INVALID_PARAMETER HandleIn is NULL or does not refer to a valid ACPI object.                            \r
+**/\r
+EFI_STATUS\r
+SdtFindPathFromNonRoot (\r
+  IN    EFI_ACPI_HANDLE HandleIn,\r
+  IN    UINT8           *AmlPath,\r
+  OUT   EFI_ACPI_HANDLE *HandleOut\r
+  )\r
+{\r
+  EFI_AML_HANDLE      *AmlHandle;\r
+  VOID                *Buffer;\r
+  EFI_STATUS          Status;\r
+\r
+  AmlHandle = (EFI_AML_HANDLE *)HandleIn;\r
+\r
+  //\r
+  // For non-root handle, we need search from THIS node instead of ROOT.\r
+  //\r
+  Status = AmlFindPath (AmlHandle, AmlPath, &Buffer, FALSE);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  if (Buffer == NULL) {\r
+    *HandleOut = NULL;\r
+    return EFI_SUCCESS;\r
+  }\r
+  return SdtOpenEx (Buffer, (UINTN)AmlHandle->Buffer + AmlHandle->Size - (UINTN)Buffer, HandleOut);\r
+}\r
+\r
+/**\r
+  Duplicate AML handle.\r
+  \r
+  @param[in]    AmlHandle   Handle to be duplicated.\r
+                            \r
+  @return Duplicated AML handle.\r
+**/\r
+EFI_AML_HANDLE *\r
+SdtDuplicateHandle (\r
+  IN EFI_AML_HANDLE      *AmlHandle\r
+  )\r
+{\r
+  EFI_AML_HANDLE  *DstAmlHandle;\r
+\r
+  DstAmlHandle = AllocatePool (sizeof(*DstAmlHandle));\r
+  ASSERT (DstAmlHandle != NULL);\r
+  CopyMem (DstAmlHandle, (VOID *)AmlHandle, sizeof(*DstAmlHandle));\r
+\r
+  return DstAmlHandle;\r
+}\r
+\r
+/**\r
+  Returns the handle of the ACPI object representing the specified ACPI path\r
+  \r
+  @param[in]    HandleIn    Points to the handle of the object representing the starting point for the path search.\r
+  @param[in]    AmlPath     Points to the AML path.\r
+  @param[out]   HandleOut   On return, points to the ACPI object which represents AcpiPath, relative to\r
+                            HandleIn.\r
+                            \r
+  @retval EFI_SUCCESS           Success\r
+  @retval EFI_INVALID_PARAMETER HandleIn is NULL or does not refer to a valid ACPI object.                            \r
+**/\r
+EFI_STATUS\r
+SdtFindPathFromRoot (\r
+  IN    EFI_ACPI_HANDLE HandleIn,\r
+  IN    UINT8           *AmlPath,\r
+  OUT   EFI_ACPI_HANDLE *HandleOut\r
+  )\r
+{\r
+  EFI_ACPI_HANDLE     ChildHandle;\r
+  EFI_AML_HANDLE      *AmlHandle;\r
+  EFI_STATUS          Status;\r
+  VOID                *Buffer;\r
+\r
+  AmlHandle = (EFI_AML_HANDLE *)HandleIn;\r
+\r
+  //\r
+  // Handle case that AcpiPath is Root\r
+  //\r
+  if (AmlIsRootPath (AmlPath)) {\r
+    //\r
+    // Duplicate RootHandle\r
+    //\r
+    *HandleOut = (EFI_ACPI_HANDLE)SdtDuplicateHandle (AmlHandle);\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Let children find it.\r
+  //\r
+  ChildHandle = NULL;\r
+  while (TRUE) {\r
+    Status = GetChild (HandleIn, &ChildHandle);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    if (ChildHandle == NULL) {\r
+      //\r
+      // Not found\r
+      //\r
+      *HandleOut = NULL;\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    //\r
+    // More child\r
+    //\r
+    AmlHandle = (EFI_AML_HANDLE *)ChildHandle;\r
+    Status = AmlFindPath (AmlHandle, AmlPath, &Buffer, TRUE);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    if (Buffer != NULL) {\r
+      //\r
+      // Great! Find it, open\r
+      //\r
+      Status = SdtOpenEx (Buffer, (UINTN)AmlHandle->Buffer + AmlHandle->Size - (UINTN)Buffer, HandleOut);\r
+      if (!EFI_ERROR (Status))  {\r
+        return EFI_SUCCESS;\r
+      }\r
+      //\r
+      // Not success, try next one\r
+      //\r
+    }\r
+  }\r
+\r
+  //\r
+  // Should not run here\r
+  //\r
+}\r
+\r
+/**\r
+  Returns the handle of the ACPI object representing the specified ACPI path\r
+  \r
+  @param[in]    HandleIn    Points to the handle of the object representing the starting point for the path search.\r
+  @param[in]    AcpiPath    Points to the ACPI path, which conforms to the ACPI encoded path format.\r
+  @param[out]   HandleOut   On return, points to the ACPI object which represents AcpiPath, relative to\r
+                            HandleIn.\r
+                            \r
+  @retval EFI_SUCCESS           Success\r
+  @retval EFI_INVALID_PARAMETER HandleIn is NULL or does not refer to a valid ACPI object.                            \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FindPath (\r
+  IN    EFI_ACPI_HANDLE HandleIn,\r
+  IN    VOID            *AcpiPath,\r
+  OUT   EFI_ACPI_HANDLE *HandleOut\r
+  )\r
+{\r
+  EFI_AML_HANDLE      *AmlHandle;\r
+  EFI_STATUS          Status;\r
+  UINT8               *AmlPath;\r
+\r
+  //\r
+  // Check for invalid input parameters\r
+  //\r
+  if (HandleIn == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  AmlHandle = (EFI_AML_HANDLE *)HandleIn;\r
+  \r
+  //\r
+  // Convert ASL path to AML path\r
+  //\r
+  AmlPath = AmlNameFromAslName (AcpiPath);\r
+  if (AmlPath == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  DEBUG_CODE_BEGIN ();\r
+  DEBUG ((EFI_D_ERROR, "AcpiSdt: FindPath - "));\r
+  AmlPrintNameString (AmlPath);\r
+  DEBUG ((EFI_D_ERROR, "\n"));\r
+  DEBUG_CODE_END ();\r
+\r
+  if (AmlHandle->Signature == EFI_AML_ROOT_HANDLE_SIGNATURE) {\r
+    //\r
+    // Root Handle\r
+    //\r
+    Status = SdtFindPathFromRoot (HandleIn, AmlPath, HandleOut);\r
+  } else if (AmlHandle->Signature == EFI_AML_HANDLE_SIGNATURE) {\r
+    //\r
+    // Non-Root handle\r
+    //\r
+    Status = SdtFindPathFromNonRoot (HandleIn, AmlPath, HandleOut);\r
+  } else {\r
+    Status = EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  FreePool (AmlPath);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  ExitPmAuth Protocol notification event handler.\r
+\r
+  @param[in] Event    Event whose notification function is being invoked.\r
+  @param[in] Context  Pointer to the notification function's context.\r
+**/\r
+VOID\r
+EFIAPI\r
+ExitPmAuthNotification (\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *Context\r
+  )\r
+{\r
+  EFI_STATUS Status;\r
+  VOID       *DxeSmmReadyToLock;\r
+\r
+  //\r
+  // Add more check to locate protocol after got event, because\r
+  // the library will signal this event immediately once it is register\r
+  // just in case it is already installed.\r
+  //\r
+  Status = gBS->LocateProtocol (\r
+                  &gEfiDxeSmmReadyToLockProtocolGuid,\r
+                  NULL,\r
+                  &DxeSmmReadyToLock\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return ;\r
+  }\r
+\r
+  //\r
+  // Uninstall ACPI SDT protocol, so that we can make sure no one update ACPI table from API level.\r
+  //\r
+  Status = gBS->UninstallProtocolInterface (\r
+                  mHandle,\r
+                  &gEfiAcpiSdtProtocolGuid,\r
+                  &mPrivateData->AcpiSdtProtocol\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Close event, so it will not be invoked again.\r
+  //\r
+  gBS->CloseEvent (Event);\r
+\r
+  return ;\r
+}\r
+\r
+/**\r
+  This function initializes AcpiSdt protocol in ACPI table instance.\r
+\r
+  @param[in]  AcpiTableInstance       Instance to construct\r
+**/\r
+VOID\r
+SdtAcpiTableAcpiSdtConstructor (\r
+  IN EFI_ACPI_TABLE_INSTANCE   *AcpiTableInstance\r
+  )\r
+{\r
+  VOID *Registration;\r
+\r
+  InitializeListHead (&AcpiTableInstance->NotifyList);\r
+  CopyMem (&AcpiTableInstance->AcpiSdtProtocol, &mAcpiSdtProtocolTemplate, sizeof(mAcpiSdtProtocolTemplate));\r
+\r
+  //\r
+  // Register event for ExitPmAuth, so that we can uninstall ACPI SDT protocol after ExitPmAuth.\r
+  //\r
+  EfiCreateProtocolNotifyEvent (\r
+    &gEfiDxeSmmReadyToLockProtocolGuid,\r
+    TPL_CALLBACK,\r
+    ExitPmAuthNotification,\r
+    NULL,\r
+    &Registration\r
+    );\r
+\r
+  return ;\r
+}\r