/** @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; | |
} |