--- /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
+//\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