| /** @file | |
| ACPI Sdt Protocol Driver | |
| Copyright (c) 2010 - 2021, Intel Corporation. All rights reserved. <BR> | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| // | |
| // Includes | |
| // | |
| #include "AcpiTable.h" | |
| GLOBAL_REMOVE_IF_UNREFERENCED | |
| EFI_ACPI_SDT_PROTOCOL mAcpiSdtProtocolTemplate = { | |
| EFI_ACPI_TABLE_VERSION_NONE, | |
| GetAcpiTable2, | |
| RegisterNotify, | |
| Open, | |
| OpenSdt, | |
| Close, | |
| GetChild, | |
| GetOption, | |
| SetOption, | |
| FindPath | |
| }; | |
| /** | |
| This function returns ACPI Table instance. | |
| @return AcpiTableInstance | |
| **/ | |
| EFI_ACPI_TABLE_INSTANCE * | |
| SdtGetAcpiTableInstance ( | |
| VOID | |
| ) | |
| { | |
| return mPrivateData; | |
| } | |
| /** | |
| This function finds the table specified by the buffer. | |
| @param[in] Buffer Table buffer to find. | |
| @return ACPI table list. | |
| **/ | |
| EFI_ACPI_TABLE_LIST * | |
| FindTableByBuffer ( | |
| IN VOID *Buffer | |
| ) | |
| { | |
| EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance; | |
| LIST_ENTRY *CurrentLink; | |
| EFI_ACPI_TABLE_LIST *CurrentTableList; | |
| LIST_ENTRY *StartLink; | |
| // | |
| // Get the instance of the ACPI Table | |
| // | |
| AcpiTableInstance = SdtGetAcpiTableInstance (); | |
| // | |
| // Find the notify | |
| // | |
| StartLink = &AcpiTableInstance->TableList; | |
| CurrentLink = StartLink->ForwardLink; | |
| while (CurrentLink != StartLink) { | |
| CurrentTableList = EFI_ACPI_TABLE_LIST_FROM_LINK (CurrentLink); | |
| if (((UINTN)CurrentTableList->Table <= (UINTN)Buffer) && | |
| ((UINTN)CurrentTableList->Table + CurrentTableList->TableSize > (UINTN)Buffer)) | |
| { | |
| // | |
| // Good! Found Table. | |
| // | |
| return CurrentTableList; | |
| } | |
| CurrentLink = CurrentLink->ForwardLink; | |
| } | |
| return NULL; | |
| } | |
| /** | |
| This function updates AML table checksum. | |
| It will search the ACPI table installed by ACPI_TABLE protocol. | |
| @param[in] Buffer A piece of AML code buffer pointer. | |
| @retval EFI_SUCCESS The table holds the AML buffer is found, and checksum is updated. | |
| @retval EFI_NOT_FOUND The table holds the AML buffer is not found. | |
| **/ | |
| EFI_STATUS | |
| SdtUpdateAmlChecksum ( | |
| IN VOID *Buffer | |
| ) | |
| { | |
| EFI_ACPI_TABLE_LIST *CurrentTableList; | |
| CurrentTableList = FindTableByBuffer (Buffer); | |
| if (CurrentTableList == NULL) { | |
| return EFI_NOT_FOUND; | |
| } | |
| AcpiPlatformChecksum ( | |
| (VOID *)CurrentTableList->Table, | |
| CurrentTableList->Table->Length, | |
| OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER, Checksum) | |
| ); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| This function finds MAX AML buffer size. | |
| It will search the ACPI table installed by ACPI_TABLE protocol. | |
| @param[in] Buffer A piece of AML code buffer pointer. | |
| @param[out] MaxSize On return it holds the MAX size of buffer. | |
| @retval EFI_SUCCESS The table holds the AML buffer is found, and MAX size if returned. | |
| @retval EFI_NOT_FOUND The table holds the AML buffer is not found. | |
| **/ | |
| EFI_STATUS | |
| SdtGetMaxAmlBufferSize ( | |
| IN VOID *Buffer, | |
| OUT UINTN *MaxSize | |
| ) | |
| { | |
| EFI_ACPI_TABLE_LIST *CurrentTableList; | |
| CurrentTableList = FindTableByBuffer (Buffer); | |
| if (CurrentTableList == NULL) { | |
| return EFI_NOT_FOUND; | |
| } | |
| *MaxSize = (UINTN)CurrentTableList->Table + CurrentTableList->Table->Length - (UINTN)Buffer; | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| This function invokes ACPI notification. | |
| @param[in] AcpiTableInstance Instance to AcpiTable | |
| @param[in] Version Version(s) to set. | |
| @param[in] Handle Handle of the table. | |
| **/ | |
| VOID | |
| SdtNotifyAcpiList ( | |
| IN EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance, | |
| IN EFI_ACPI_TABLE_VERSION Version, | |
| IN UINTN Handle | |
| ) | |
| { | |
| EFI_ACPI_NOTIFY_LIST *CurrentNotifyList; | |
| LIST_ENTRY *CurrentLink; | |
| LIST_ENTRY *StartLink; | |
| EFI_ACPI_TABLE_LIST *Table; | |
| EFI_STATUS Status; | |
| // | |
| // We should not use Table buffer, because it is user input buffer. | |
| // | |
| Status = FindTableByHandle ( | |
| Handle, | |
| &AcpiTableInstance->TableList, | |
| &Table | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| // | |
| // Find the notify | |
| // | |
| StartLink = &AcpiTableInstance->NotifyList; | |
| CurrentLink = StartLink->ForwardLink; | |
| while (CurrentLink != StartLink) { | |
| CurrentNotifyList = EFI_ACPI_NOTIFY_LIST_FROM_LINK (CurrentLink); | |
| // | |
| // Inovke notification | |
| // | |
| CurrentNotifyList->Notification ((EFI_ACPI_SDT_HEADER *)Table->Table, Version, Handle); | |
| CurrentLink = CurrentLink->ForwardLink; | |
| } | |
| return; | |
| } | |
| /** | |
| Returns a requested ACPI table. | |
| The following structures are not considered elements in the list of | |
| ACPI tables: | |
| - Root System Description Pointer (RSD_PTR) | |
| - Root System Description Table (RSDT) | |
| - Extended System Description Table (XSDT) | |
| Version is updated with a bit map containing all the versions of ACPI of which the table is a | |
| member. For tables installed via the EFI_ACPI_TABLE_PROTOCOL.InstallAcpiTable() interface, | |
| the function returns the value of EFI_ACPI_STD_PROTOCOL.AcpiVersion. | |
| @param[in] AcpiTableInstance ACPI table Instance. | |
| @param[in] Index The zero-based index of the table to retrieve. | |
| @param[out] Table Pointer for returning the table buffer. | |
| @param[out] Version On return, updated with the ACPI versions to which this table belongs. Type | |
| EFI_ACPI_TABLE_VERSION is defined in "Related Definitions" in the | |
| EFI_ACPI_SDT_PROTOCOL. | |
| @param[out] TableKey On return, points to the table key for the specified ACPI system definition table. | |
| This is identical to the table key used in the EFI_ACPI_TABLE_PROTOCOL. | |
| The TableKey can be passed to EFI_ACPI_TABLE_PROTOCOL.UninstallAcpiTable() | |
| to uninstall the table. | |
| @retval EFI_SUCCESS The function completed successfully. | |
| @retval EFI_NOT_FOUND The requested index is too large and a table was not found. | |
| **/ | |
| EFI_STATUS | |
| SdtGetAcpiTable ( | |
| IN EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance, | |
| IN UINTN Index, | |
| OUT EFI_ACPI_SDT_HEADER **Table, | |
| OUT EFI_ACPI_TABLE_VERSION *Version, | |
| OUT UINTN *TableKey | |
| ) | |
| { | |
| UINTN TableIndex; | |
| LIST_ENTRY *CurrentLink; | |
| LIST_ENTRY *StartLink; | |
| EFI_ACPI_TABLE_LIST *CurrentTable; | |
| // | |
| // Find the table | |
| // | |
| StartLink = &AcpiTableInstance->TableList; | |
| CurrentLink = StartLink->ForwardLink; | |
| TableIndex = 0; | |
| while (CurrentLink != StartLink) { | |
| if (TableIndex == Index) { | |
| break; | |
| } | |
| // | |
| // Next one | |
| // | |
| CurrentLink = CurrentLink->ForwardLink; | |
| TableIndex++; | |
| } | |
| if ((TableIndex != Index) || (CurrentLink == StartLink)) { | |
| return EFI_NOT_FOUND; | |
| } | |
| // | |
| // Get handle and version | |
| // | |
| CurrentTable = EFI_ACPI_TABLE_LIST_FROM_LINK (CurrentLink); | |
| *TableKey = CurrentTable->Handle; | |
| *Version = CurrentTable->Version; | |
| *Table = (EFI_ACPI_SDT_HEADER *)CurrentTable->Table; | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Returns a requested ACPI table. | |
| The GetAcpiTable() function returns a pointer to a buffer containing the ACPI table associated | |
| with the Index that was input. The following structures are not considered elements in the list of | |
| ACPI tables: | |
| - Root System Description Pointer (RSD_PTR) | |
| - Root System Description Table (RSDT) | |
| - Extended System Description Table (XSDT) | |
| Version is updated with a bit map containing all the versions of ACPI of which the table is a | |
| member. For tables installed via the EFI_ACPI_TABLE_PROTOCOL.InstallAcpiTable() interface, | |
| the function returns the value of EFI_ACPI_STD_PROTOCOL.AcpiVersion. | |
| @param[in] Index The zero-based index of the table to retrieve. | |
| @param[out] Table Pointer for returning the table buffer. | |
| @param[out] Version On return, updated with the ACPI versions to which this table belongs. Type | |
| EFI_ACPI_TABLE_VERSION is defined in "Related Definitions" in the | |
| EFI_ACPI_SDT_PROTOCOL. | |
| @param[out] TableKey On return, points to the table key for the specified ACPI system definition table. | |
| This is identical to the table key used in the EFI_ACPI_TABLE_PROTOCOL. | |
| The TableKey can be passed to EFI_ACPI_TABLE_PROTOCOL.UninstallAcpiTable() | |
| to uninstall the table. | |
| @retval EFI_SUCCESS The function completed successfully. | |
| @retval EFI_NOT_FOUND The requested index is too large and a table was not found. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| GetAcpiTable2 ( | |
| IN UINTN Index, | |
| OUT EFI_ACPI_SDT_HEADER **Table, | |
| OUT EFI_ACPI_TABLE_VERSION *Version, | |
| OUT UINTN *TableKey | |
| ) | |
| { | |
| EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance; | |
| ASSERT (Table != NULL); | |
| ASSERT (Version != NULL); | |
| ASSERT (TableKey != NULL); | |
| // | |
| // Get the instance of the ACPI Table | |
| // | |
| AcpiTableInstance = SdtGetAcpiTableInstance (); | |
| return SdtGetAcpiTable (AcpiTableInstance, Index, Table, Version, TableKey); | |
| } | |
| /** | |
| Register a callback when an ACPI table is installed. | |
| This function registers a function which will be called whenever a new ACPI table is installed. | |
| @param[in] Notification Points to the callback function to be registered | |
| **/ | |
| VOID | |
| SdtRegisterNotify ( | |
| IN EFI_ACPI_NOTIFICATION_FN Notification | |
| ) | |
| { | |
| EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance; | |
| EFI_ACPI_NOTIFY_LIST *CurrentNotifyList; | |
| // | |
| // Get the instance of the ACPI Table | |
| // | |
| AcpiTableInstance = SdtGetAcpiTableInstance (); | |
| // | |
| // Create a new list entry | |
| // | |
| CurrentNotifyList = AllocatePool (sizeof (EFI_ACPI_NOTIFY_LIST)); | |
| ASSERT (CurrentNotifyList != NULL); | |
| // | |
| // Initialize the table contents | |
| // | |
| CurrentNotifyList->Signature = EFI_ACPI_NOTIFY_LIST_SIGNATURE; | |
| CurrentNotifyList->Notification = Notification; | |
| // | |
| // Add the table to the current list of tables | |
| // | |
| InsertTailList (&AcpiTableInstance->NotifyList, &CurrentNotifyList->Link); | |
| return; | |
| } | |
| /** | |
| Unregister a callback when an ACPI table is installed. | |
| This function unregisters a function which will be called whenever a new ACPI table is installed. | |
| @param[in] Notification Points to the callback function to be unregistered. | |
| @retval EFI_SUCCESS Callback successfully unregistered. | |
| @retval EFI_INVALID_PARAMETER Notification does not match a known registration function. | |
| **/ | |
| EFI_STATUS | |
| SdtUnregisterNotify ( | |
| IN EFI_ACPI_NOTIFICATION_FN Notification | |
| ) | |
| { | |
| EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance; | |
| EFI_ACPI_NOTIFY_LIST *CurrentNotifyList; | |
| LIST_ENTRY *CurrentLink; | |
| LIST_ENTRY *StartLink; | |
| // | |
| // Get the instance of the ACPI Table | |
| // | |
| AcpiTableInstance = SdtGetAcpiTableInstance (); | |
| // | |
| // Find the notify | |
| // | |
| StartLink = &AcpiTableInstance->NotifyList; | |
| CurrentLink = StartLink->ForwardLink; | |
| while (CurrentLink != StartLink) { | |
| CurrentNotifyList = EFI_ACPI_NOTIFY_LIST_FROM_LINK (CurrentLink); | |
| if (CurrentNotifyList->Notification == Notification) { | |
| // | |
| // Good! Found notification. | |
| // | |
| // Remove it from list and free the node. | |
| // | |
| RemoveEntryList (&(CurrentNotifyList->Link)); | |
| FreePool (CurrentNotifyList); | |
| return EFI_SUCCESS; | |
| } | |
| CurrentLink = CurrentLink->ForwardLink; | |
| } | |
| // | |
| // Not found! | |
| // | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| /** | |
| Register or unregister a callback when an ACPI table is installed. | |
| This function registers or unregisters a function which will be called whenever a new ACPI table is | |
| installed. | |
| @param[in] Register If TRUE, then the specified function will be registered. If FALSE, then the specified | |
| function will be unregistered. | |
| @param[in] Notification Points to the callback function to be registered or unregistered. | |
| @retval EFI_SUCCESS Callback successfully registered or unregistered. | |
| @retval EFI_INVALID_PARAMETER Notification is NULL | |
| @retval EFI_INVALID_PARAMETER Register is FALSE and Notification does not match a known registration function. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| RegisterNotify ( | |
| IN BOOLEAN Register, | |
| IN EFI_ACPI_NOTIFICATION_FN Notification | |
| ) | |
| { | |
| // | |
| // Check for invalid input parameters | |
| // | |
| if (Notification == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (Register) { | |
| // | |
| // Register a new notify | |
| // | |
| SdtRegisterNotify (Notification); | |
| return EFI_SUCCESS; | |
| } else { | |
| // | |
| // Unregister an old notify | |
| // | |
| return SdtUnregisterNotify (Notification); | |
| } | |
| } | |
| /** | |
| Create a handle for the first ACPI opcode in an ACPI system description table. | |
| @param[in] TableKey The table key for the ACPI table, as returned by GetTable(). | |
| @param[out] Handle On return, points to the newly created ACPI handle. | |
| @retval EFI_SUCCESS Handle created successfully. | |
| @retval EFI_NOT_FOUND TableKey does not refer to a valid ACPI table. | |
| **/ | |
| EFI_STATUS | |
| SdtOpenSdtTable ( | |
| IN UINTN TableKey, | |
| OUT EFI_ACPI_HANDLE *Handle | |
| ) | |
| { | |
| EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance; | |
| EFI_STATUS Status; | |
| EFI_ACPI_TABLE_LIST *Table; | |
| EFI_AML_HANDLE *AmlHandle; | |
| // | |
| // Get the instance of the ACPI Table | |
| // | |
| AcpiTableInstance = SdtGetAcpiTableInstance (); | |
| // | |
| // Find the table | |
| // | |
| Status = FindTableByHandle ( | |
| TableKey, | |
| &AcpiTableInstance->TableList, | |
| &Table | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return EFI_NOT_FOUND; | |
| } | |
| AmlHandle = AllocatePool (sizeof (*AmlHandle)); | |
| ASSERT (AmlHandle != NULL); | |
| AmlHandle->Signature = EFI_AML_ROOT_HANDLE_SIGNATURE; | |
| AmlHandle->Buffer = (VOID *)((UINTN)Table->Table + sizeof (EFI_ACPI_SDT_HEADER)); | |
| AmlHandle->Size = Table->Table->Length - sizeof (EFI_ACPI_SDT_HEADER); | |
| AmlHandle->AmlByteEncoding = NULL; | |
| AmlHandle->Modified = FALSE; | |
| // | |
| // return the ACPI handle | |
| // | |
| *Handle = (EFI_ACPI_HANDLE)AmlHandle; | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Create a handle for the first ACPI opcode in an ACPI system description table. | |
| @param[in] TableKey The table key for the ACPI table, as returned by GetTable(). | |
| @param[out] Handle On return, points to the newly created ACPI handle. | |
| @retval EFI_SUCCESS Handle created successfully. | |
| @retval EFI_NOT_FOUND TableKey does not refer to a valid ACPI table. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| OpenSdt ( | |
| IN UINTN TableKey, | |
| OUT EFI_ACPI_HANDLE *Handle | |
| ) | |
| { | |
| if (Handle == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| return SdtOpenSdtTable (TableKey, Handle); | |
| } | |
| /** | |
| Create a handle from an ACPI opcode | |
| @param[in] Buffer Points to the ACPI opcode. | |
| @param[in] BufferSize Max buffer size. | |
| @param[out] Handle Upon return, holds the handle. | |
| @retval EFI_SUCCESS Success | |
| @retval EFI_INVALID_PARAMETER Buffer is NULL or Handle is NULL or Buffer points to an | |
| invalid opcode. | |
| **/ | |
| EFI_STATUS | |
| SdtOpenEx ( | |
| IN VOID *Buffer, | |
| IN UINTN BufferSize, | |
| OUT EFI_ACPI_HANDLE *Handle | |
| ) | |
| { | |
| AML_BYTE_ENCODING *AmlByteEncoding; | |
| EFI_AML_HANDLE *AmlHandle; | |
| AmlByteEncoding = AmlSearchByOpByte (Buffer); | |
| if (AmlByteEncoding == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // Do not open NameString as handle | |
| // | |
| if ((AmlByteEncoding->Attribute & AML_IS_NAME_CHAR) != 0) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // Good, find it | |
| // | |
| AmlHandle = AllocatePool (sizeof (*AmlHandle)); | |
| ASSERT (AmlHandle != NULL); | |
| AmlHandle->Signature = EFI_AML_HANDLE_SIGNATURE; | |
| AmlHandle->Buffer = Buffer; | |
| AmlHandle->AmlByteEncoding = AmlByteEncoding; | |
| AmlHandle->Modified = FALSE; | |
| AmlHandle->Size = AmlGetObjectSize (AmlByteEncoding, Buffer, BufferSize); | |
| if (AmlHandle->Size == 0) { | |
| FreePool (AmlHandle); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| *Handle = (EFI_ACPI_HANDLE)AmlHandle; | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Create a handle from an ACPI opcode | |
| @param[in] Buffer Points to the ACPI opcode. | |
| @param[out] Handle Upon return, holds the handle. | |
| @retval EFI_SUCCESS Success | |
| @retval EFI_INVALID_PARAMETER Buffer is NULL or Handle is NULL or Buffer points to an | |
| invalid opcode. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| Open ( | |
| IN VOID *Buffer, | |
| OUT EFI_ACPI_HANDLE *Handle | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| UINTN MaxSize; | |
| MaxSize = 0; | |
| // | |
| // Check for invalid input parameters | |
| // | |
| if ((Buffer == NULL) || (Handle == NULL)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Status = SdtGetMaxAmlBufferSize (Buffer, &MaxSize); | |
| if (EFI_ERROR (Status)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| return SdtOpenEx (Buffer, MaxSize, Handle); | |
| } | |
| /** | |
| Close an ACPI handle. | |
| @param[in] Handle Returns the handle. | |
| @retval EFI_SUCCESS Success | |
| @retval EFI_INVALID_PARAMETER Handle is NULL or does not refer to a valid ACPI object. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| Close ( | |
| IN EFI_ACPI_HANDLE Handle | |
| ) | |
| { | |
| EFI_AML_HANDLE *AmlHandle; | |
| EFI_STATUS Status; | |
| // | |
| // Check for invalid input parameters | |
| // | |
| if (Handle == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| AmlHandle = (EFI_AML_HANDLE *)Handle; | |
| if ((AmlHandle->Signature != EFI_AML_ROOT_HANDLE_SIGNATURE) && | |
| (AmlHandle->Signature != EFI_AML_HANDLE_SIGNATURE)) | |
| { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // Update Checksum only if modified | |
| // | |
| if (AmlHandle->Modified) { | |
| Status = SdtUpdateAmlChecksum (AmlHandle->Buffer); | |
| if (EFI_ERROR (Status)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| } | |
| FreePool (AmlHandle); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Retrieve information about an ACPI object. | |
| @param[in] Handle ACPI object handle. | |
| @param[in] Index Index of the data to retrieve from the object. In general, indexes read from left-to-right | |
| in the ACPI encoding, with index 0 always being the ACPI opcode. | |
| @param[out] DataType Points to the returned data type or EFI_ACPI_DATA_TYPE_NONE if no data exists | |
| for the specified index. | |
| @param[out] Data Upon return, points to the pointer to the data. | |
| @param[out] DataSize Upon return, points to the size of Data. | |
| @retval EFI_SUCCESS Success. | |
| @retval EFI_INVALID_PARAMETER Handle is NULL or does not refer to a valid ACPI object. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| GetOption ( | |
| IN EFI_ACPI_HANDLE Handle, | |
| IN UINTN Index, | |
| OUT EFI_ACPI_DATA_TYPE *DataType, | |
| OUT CONST VOID **Data, | |
| OUT UINTN *DataSize | |
| ) | |
| { | |
| EFI_AML_HANDLE *AmlHandle; | |
| AML_BYTE_ENCODING *AmlByteEncoding; | |
| EFI_STATUS Status; | |
| ASSERT (DataType != NULL); | |
| ASSERT (Data != NULL); | |
| ASSERT (DataSize != NULL); | |
| // | |
| // Check for invalid input parameters | |
| // | |
| if (Handle == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| AmlHandle = (EFI_AML_HANDLE *)Handle; | |
| // | |
| // Do not check EFI_AML_ROOT_HANDLE_SIGNATURE because there is no option for Root handle | |
| // | |
| if (AmlHandle->Signature != EFI_AML_HANDLE_SIGNATURE) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| AmlByteEncoding = AmlHandle->AmlByteEncoding; | |
| if (Index > AmlByteEncoding->MaxIndex) { | |
| *DataType = EFI_ACPI_DATA_TYPE_NONE; | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // Parse option | |
| // | |
| Status = AmlParseOptionHandleCommon (AmlHandle, (AML_OP_PARSE_INDEX)Index, DataType, (VOID **)Data, DataSize); | |
| if (EFI_ERROR (Status)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Change information about an ACPI object. | |
| @param[in] Handle ACPI object handle. | |
| @param[in] Index Index of the data to retrieve from the object. In general, indexes read from left-to-right | |
| in the ACPI encoding, with index 0 always being the ACPI opcode. | |
| @param[in] Data Points to the data. | |
| @param[in] DataSize The size of the Data. | |
| @retval EFI_SUCCESS Success | |
| @retval EFI_INVALID_PARAMETER Handle is NULL or does not refer to a valid ACPI object. | |
| @retval EFI_BAD_BUFFER_SIZE Data cannot be accommodated in the space occupied by | |
| the option. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| SetOption ( | |
| IN EFI_ACPI_HANDLE Handle, | |
| IN UINTN Index, | |
| IN CONST VOID *Data, | |
| IN UINTN DataSize | |
| ) | |
| { | |
| EFI_AML_HANDLE *AmlHandle; | |
| AML_BYTE_ENCODING *AmlByteEncoding; | |
| EFI_STATUS Status; | |
| EFI_ACPI_DATA_TYPE DataType; | |
| VOID *OrgData; | |
| UINTN OrgDataSize; | |
| ASSERT (Data != NULL); | |
| // | |
| // Check for invalid input parameters | |
| // | |
| if (Handle == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| AmlHandle = (EFI_AML_HANDLE *)Handle; | |
| // | |
| // Do not check EFI_AML_ROOT_HANDLE_SIGNATURE because there is no option for Root handle | |
| // | |
| if (AmlHandle->Signature != EFI_AML_HANDLE_SIGNATURE) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| AmlByteEncoding = AmlHandle->AmlByteEncoding; | |
| if (Index > AmlByteEncoding->MaxIndex) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // Parse option | |
| // | |
| Status = AmlParseOptionHandleCommon (AmlHandle, (AML_OP_PARSE_INDEX)Index, &DataType, &OrgData, &OrgDataSize); | |
| if (EFI_ERROR (Status)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (DataType == EFI_ACPI_DATA_TYPE_NONE) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (DataSize > OrgDataSize) { | |
| return EFI_BAD_BUFFER_SIZE; | |
| } | |
| // | |
| // Update | |
| // | |
| CopyMem (OrgData, Data, DataSize); | |
| AmlHandle->Modified = TRUE; | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Return the child ACPI objects. | |
| @param[in] ParentHandle Parent handle. | |
| @param[in, out] Handle On entry, points to the previously returned handle or NULL to start with the first | |
| handle. On return, points to the next returned ACPI handle or NULL if there are no | |
| child objects. | |
| @retval EFI_SUCCESS Success | |
| @retval EFI_INVALID_PARAMETER ParentHandle is NULL or does not refer to a valid ACPI object. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| GetChild ( | |
| IN EFI_ACPI_HANDLE ParentHandle, | |
| IN OUT EFI_ACPI_HANDLE *Handle | |
| ) | |
| { | |
| EFI_AML_HANDLE *AmlParentHandle; | |
| EFI_AML_HANDLE *AmlHandle; | |
| VOID *Buffer; | |
| EFI_STATUS Status; | |
| ASSERT (Handle != NULL); | |
| // | |
| // Check for invalid input parameters | |
| // | |
| if (ParentHandle == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| AmlHandle = *Handle; | |
| if ((AmlHandle != NULL) && (AmlHandle->Signature != EFI_AML_HANDLE_SIGNATURE)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| AmlParentHandle = (EFI_AML_HANDLE *)ParentHandle; | |
| if (AmlParentHandle->Signature == EFI_AML_ROOT_HANDLE_SIGNATURE) { | |
| // | |
| // Root handle | |
| // | |
| Status = AmlGetChildFromRoot (AmlParentHandle, AmlHandle, &Buffer); | |
| } else if (AmlParentHandle->Signature == EFI_AML_HANDLE_SIGNATURE) { | |
| // | |
| // Non-root handle | |
| // | |
| Status = AmlGetChildFromNonRoot (AmlParentHandle, AmlHandle, &Buffer); | |
| } else { | |
| // | |
| // Invalid | |
| // | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (EFI_ERROR (Status)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (Buffer == NULL) { | |
| *Handle = NULL; | |
| return EFI_SUCCESS; | |
| } | |
| return SdtOpenEx (Buffer, (UINTN)AmlParentHandle->Buffer + AmlParentHandle->Size - (UINTN)Buffer, Handle); | |
| } | |
| /** | |
| Returns the handle of the ACPI object representing the specified ACPI path | |
| @param[in] HandleIn Points to the handle of the object representing the starting point for the path search. | |
| @param[in] AmlPath Points to the AML path. | |
| @param[out] HandleOut On return, points to the ACPI object which represents AcpiPath, relative to | |
| HandleIn. | |
| @retval EFI_SUCCESS Success | |
| @retval EFI_INVALID_PARAMETER HandleIn is NULL or does not refer to a valid ACPI object. | |
| **/ | |
| EFI_STATUS | |
| SdtFindPathFromNonRoot ( | |
| IN EFI_ACPI_HANDLE HandleIn, | |
| IN UINT8 *AmlPath, | |
| OUT EFI_ACPI_HANDLE *HandleOut | |
| ) | |
| { | |
| EFI_AML_HANDLE *AmlHandle; | |
| VOID *Buffer; | |
| EFI_STATUS Status; | |
| Buffer = NULL; | |
| AmlHandle = (EFI_AML_HANDLE *)HandleIn; | |
| // | |
| // For non-root handle, we need search from THIS node instead of ROOT. | |
| // | |
| Status = AmlFindPath (AmlHandle, AmlPath, &Buffer, FALSE); | |
| if (EFI_ERROR (Status)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (Buffer == NULL) { | |
| *HandleOut = NULL; | |
| return EFI_SUCCESS; | |
| } | |
| return SdtOpenEx (Buffer, (UINTN)AmlHandle->Buffer + AmlHandle->Size - (UINTN)Buffer, HandleOut); | |
| } | |
| /** | |
| Duplicate AML handle. | |
| @param[in] AmlHandle Handle to be duplicated. | |
| @return Duplicated AML handle. | |
| **/ | |
| EFI_AML_HANDLE * | |
| SdtDuplicateHandle ( | |
| IN EFI_AML_HANDLE *AmlHandle | |
| ) | |
| { | |
| EFI_AML_HANDLE *DstAmlHandle; | |
| DstAmlHandle = AllocatePool (sizeof (*DstAmlHandle)); | |
| ASSERT (DstAmlHandle != NULL); | |
| CopyMem (DstAmlHandle, (VOID *)AmlHandle, sizeof (*DstAmlHandle)); | |
| return DstAmlHandle; | |
| } | |
| /** | |
| Returns the handle of the ACPI object representing the specified ACPI path | |
| @param[in] HandleIn Points to the handle of the object representing the starting point for the path search. | |
| @param[in] AmlPath Points to the AML path. | |
| @param[out] HandleOut On return, points to the ACPI object which represents AcpiPath, relative to | |
| HandleIn. | |
| @retval EFI_SUCCESS Success | |
| @retval EFI_INVALID_PARAMETER HandleIn is NULL or does not refer to a valid ACPI object. | |
| **/ | |
| EFI_STATUS | |
| SdtFindPathFromRoot ( | |
| IN EFI_ACPI_HANDLE HandleIn, | |
| IN UINT8 *AmlPath, | |
| OUT EFI_ACPI_HANDLE *HandleOut | |
| ) | |
| { | |
| EFI_ACPI_HANDLE ChildHandle; | |
| EFI_AML_HANDLE *AmlHandle; | |
| EFI_STATUS Status; | |
| VOID *Buffer; | |
| Buffer = NULL; | |
| AmlHandle = (EFI_AML_HANDLE *)HandleIn; | |
| // | |
| // Handle case that AcpiPath is Root | |
| // | |
| if (AmlIsRootPath (AmlPath)) { | |
| // | |
| // Duplicate RootHandle | |
| // | |
| *HandleOut = (EFI_ACPI_HANDLE)SdtDuplicateHandle (AmlHandle); | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // Let children find it. | |
| // | |
| ChildHandle = NULL; | |
| while (TRUE) { | |
| Status = GetChild (HandleIn, &ChildHandle); | |
| if (EFI_ERROR (Status)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (ChildHandle == NULL) { | |
| // | |
| // Not found | |
| // | |
| *HandleOut = NULL; | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // More child | |
| // | |
| AmlHandle = (EFI_AML_HANDLE *)ChildHandle; | |
| Status = AmlFindPath (AmlHandle, AmlPath, &Buffer, TRUE); | |
| if (EFI_ERROR (Status)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (Buffer != NULL) { | |
| // | |
| // Great! Find it, open | |
| // | |
| Status = SdtOpenEx (Buffer, (UINTN)AmlHandle->Buffer + AmlHandle->Size - (UINTN)Buffer, HandleOut); | |
| if (!EFI_ERROR (Status)) { | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // Not success, try next one | |
| // | |
| } | |
| } | |
| // | |
| // Should not run here | |
| // | |
| } | |
| /** | |
| Returns the handle of the ACPI object representing the specified ACPI path | |
| @param[in] HandleIn Points to the handle of the object representing the starting point for the path search. | |
| @param[in] AcpiPath Points to the ACPI path, which conforms to the ACPI encoded path format. | |
| @param[out] HandleOut On return, points to the ACPI object which represents AcpiPath, relative to | |
| HandleIn. | |
| @retval EFI_SUCCESS Success | |
| @retval EFI_INVALID_PARAMETER HandleIn is NULL or does not refer to a valid ACPI object. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| FindPath ( | |
| IN EFI_ACPI_HANDLE HandleIn, | |
| IN VOID *AcpiPath, | |
| OUT EFI_ACPI_HANDLE *HandleOut | |
| ) | |
| { | |
| EFI_AML_HANDLE *AmlHandle; | |
| EFI_STATUS Status; | |
| UINT8 *AmlPath; | |
| // | |
| // Check for invalid input parameters | |
| // | |
| if (HandleIn == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| AmlHandle = (EFI_AML_HANDLE *)HandleIn; | |
| // | |
| // Convert ASL path to AML path | |
| // | |
| AmlPath = AmlNameFromAslName (AcpiPath); | |
| if (AmlPath == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| DEBUG_CODE_BEGIN (); | |
| DEBUG ((DEBUG_ERROR, "AcpiSdt: FindPath - ")); | |
| AmlPrintNameString (AmlPath); | |
| DEBUG ((DEBUG_ERROR, "\n")); | |
| DEBUG_CODE_END (); | |
| if (AmlHandle->Signature == EFI_AML_ROOT_HANDLE_SIGNATURE) { | |
| // | |
| // Root Handle | |
| // | |
| Status = SdtFindPathFromRoot (HandleIn, AmlPath, HandleOut); | |
| } else if (AmlHandle->Signature == EFI_AML_HANDLE_SIGNATURE) { | |
| // | |
| // Non-Root handle | |
| // | |
| Status = SdtFindPathFromNonRoot (HandleIn, AmlPath, HandleOut); | |
| } else { | |
| Status = EFI_INVALID_PARAMETER; | |
| } | |
| FreePool (AmlPath); | |
| return Status; | |
| } | |
| /** | |
| This function initializes AcpiSdt protocol in ACPI table instance. | |
| @param[in] AcpiTableInstance Instance to construct | |
| **/ | |
| VOID | |
| SdtAcpiTableAcpiSdtConstructor ( | |
| IN EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance | |
| ) | |
| { | |
| InitializeListHead (&AcpiTableInstance->NotifyList); | |
| CopyMem (&AcpiTableInstance->AcpiSdtProtocol, &mAcpiSdtProtocolTemplate, sizeof (mAcpiSdtProtocolTemplate)); | |
| AcpiTableInstance->AcpiSdtProtocol.AcpiVersion = (EFI_ACPI_TABLE_VERSION)PcdGet32 (PcdAcpiExposedTableVersions); | |
| return; | |
| } |