/** @file
Boot service DXE ASL update library implementation.
These functions in this file can be called during DXE and cannot be called during runtime
or in SMM which should use a RT or SMM library.
This library uses the ACPI Support protocol.
Copyright (c) 2017 - 2020, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include
#include
#include
#include
#include
#include
#include
#include
#include
//
// Function implementations
//
static EFI_ACPI_SDT_PROTOCOL *mAcpiSdt = NULL;
static EFI_ACPI_TABLE_PROTOCOL *mAcpiTable = NULL;
/**
Initialize the ASL update library state.
This must be called at the beginning of the function calls in this library.
@retval EFI_SUCCESS - The function completed successfully.
**/
EFI_STATUS
InitializeAslUpdateLib (
VOID
)
{
EFI_STATUS Status;
///
/// Locate ACPI tables
///
Status = gBS->LocateProtocol (&gEfiAcpiSdtProtocolGuid, NULL, (VOID **) &mAcpiSdt);
ASSERT_EFI_ERROR (Status);
Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &mAcpiTable);
ASSERT_EFI_ERROR (Status);
return Status;
}
/**
This function uses the ACPI SDT protocol to locate an ACPI SSDT table.
@param[in] TableId - Pointer to an ASCII string containing the OEM Table ID from the ACPI table header
@param[in] TableIdSize - Length of the TableId to match. Table ID are 8 bytes long, this function
will consider it a match if the first TableIdSize bytes match
@param[in, out] Table - Updated with a pointer to the table
@param[in, out] Handle - AcpiSupport protocol table handle for the table found
@retval EFI_SUCCESS - The function completed successfully.
@retval EFI_NOT_FOUND - Failed to locate AcpiTable.
@retval EFI_NOT_READY - Not ready to locate AcpiTable.
**/
EFI_STATUS
LocateAcpiTableByOemTableId (
IN UINT8 *TableId,
IN UINT8 TableIdSize,
IN OUT EFI_ACPI_DESCRIPTION_HEADER **Table,
IN OUT UINTN *Handle
)
{
EFI_STATUS Status;
INTN Index;
EFI_ACPI_TABLE_VERSION Version;
EFI_ACPI_DESCRIPTION_HEADER *OrgTable;
if (mAcpiSdt == NULL) {
InitializeAslUpdateLib ();
if (mAcpiSdt == NULL) {
return EFI_NOT_READY;
}
}
///
/// Locate table with matching ID
///
Version = 0;
Index = 0;
do {
Status = mAcpiSdt->GetAcpiTable (Index, (EFI_ACPI_SDT_HEADER **)&OrgTable, &Version, Handle);
if (Status == EFI_NOT_FOUND) {
break;
}
ASSERT_EFI_ERROR (Status);
Index++;
} while (CompareMem (&(OrgTable->OemTableId), TableId, TableIdSize));
if (Status != EFI_NOT_FOUND) {
*Table = AllocateCopyPool (OrgTable->Length, OrgTable);
ASSERT (*Table);
}
///
/// If we found the table, there will be no error.
///
return Status;
}
/**
This procedure will update immediate value assigned to a Name.
@param[in] AslSignature - The signature of Operation Region that we want to update.
@param[in] Buffer - source of data to be written over original aml
@param[in] Length - length of data to be overwritten
@retval EFI_SUCCESS - The function completed successfully.
@retval EFI_NOT_FOUND - Failed to locate AcpiTable.
@retval EFI_NOT_READY - Not ready to locate AcpiTable.
**/
EFI_STATUS
EFIAPI
UpdateNameAslCode (
IN UINT32 AslSignature,
IN VOID *Buffer,
IN UINTN Length
)
{
EFI_STATUS Status;
EFI_ACPI_DESCRIPTION_HEADER *Table;
UINT8 *CurrPtr;
UINT32 *Signature;
UINT8 *DsdtPointer;
UINT8 *EndPointer;
UINTN Handle;
UINT8 DataSize;
if (mAcpiTable == NULL) {
InitializeAslUpdateLib ();
if (mAcpiTable == NULL) {
return EFI_NOT_READY;
}
}
///
/// Locate table with matching ID
///
Handle = 0;
Status = LocateAcpiTableBySignature (
EFI_ACPI_3_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE,
(EFI_ACPI_DESCRIPTION_HEADER **) &Table,
&Handle
);
if (EFI_ERROR (Status)) {
return Status;
}
///
/// Point to the beginning of the DSDT table
///
CurrPtr = (UINT8 *) Table;
if (CurrPtr == NULL) {
return EFI_NOT_FOUND;
}
///
/// Loop through the ASL looking for values that we must fix up.
///
EndPointer = CurrPtr + ((EFI_ACPI_COMMON_HEADER *) CurrPtr)->Length;
for (DsdtPointer = CurrPtr; DsdtPointer < EndPointer; DsdtPointer++) {
///
/// Get a pointer to compare for signature
///
Signature = (UINT32 *) DsdtPointer;
///
/// Check if this is the Device Object signature we are looking for
///
if ((*Signature) == AslSignature) {
///
/// Look for Name Encoding
///
if (*(DsdtPointer-1) == AML_NAME_OP) {
///
/// Check if size of new and old data is the same
///
DataSize = *(DsdtPointer+4);
if ((Length == 1 && DataSize == 0xA) ||
(Length == 2 && DataSize == 0xB) ||
(Length == 4 && DataSize == 0xC)) {
CopyMem (DsdtPointer+5, Buffer, Length);
} else if (Length == 1 && ((*(UINT8*) Buffer) == 0 || (*(UINT8*) Buffer) == 1) && (DataSize == 0 || DataSize == 1)) {
CopyMem (DsdtPointer+4, Buffer, Length);
} else {
FreePool (Table);
return EFI_BAD_BUFFER_SIZE;
}
Status = mAcpiTable->UninstallAcpiTable (
mAcpiTable,
Handle
);
Handle = 0;
Status = mAcpiTable->InstallAcpiTable (
mAcpiTable,
Table,
Table->Length,
&Handle
);
FreePool (Table);
return Status;
}
}
}
return EFI_NOT_FOUND;
}
/**
This procedure will update immediate value assigned to a Name in SSDT table.
@param[in] TableId - Pointer to an ASCII string containing the OEM Table ID from the ACPI table header
@param[in] TableIdSize - Length of the TableId to match. Table ID are 8 bytes long, this function
@param[in] AslSignature - The signature of Operation Region that we want to update.
@param[in] Buffer - source of data to be written over original aml
@param[in] Length - length of data to be overwritten
@retval EFI_UNSUPPORTED The function is not supported in this library.
**/
EFI_STATUS
EFIAPI
UpdateSsdtNameAslCode (
IN UINT8 *TableId,
IN UINT8 TableIdSize,
IN UINT32 AslSignature,
IN VOID *Buffer,
IN UINTN Length
)
{
return EFI_UNSUPPORTED;
}
/**
This procedure will update the name of ASL Method.
@param[in] AslSignature - The signature of Operation Region that we want to update.
@param[in] Buffer - source of data to be written over original aml
@param[in] Length - length of data to be overwritten
@retval EFI_UNSUPPORTED The function is not supported in this library.
**/
EFI_STATUS
EFIAPI
UpdateMethodAslCode (
IN UINT32 AslSignature,
IN VOID *Buffer,
IN UINTN Length
)
{
return EFI_UNSUPPORTED;
}
/**
This function uses the ACPI SDT protocol to locate an ACPI table.
It is really only useful for finding tables that only have a single instance,
e.g. FADT, FACS, MADT, etc. It is not good for locating SSDT, etc.
Matches are determined by finding the table with ACPI table that has
a matching signature.
@param[in] Signature - Pointer to an ASCII string containing the OEM Table ID from the ACPI table header
@param[in, out] Table - Updated with a pointer to the table
@param[in, out] Handle - AcpiSupport protocol table handle for the table found
@retval EFI_SUCCESS - The function completed successfully.
@retval EFI_NOT_FOUND - Failed to locate AcpiTable.
@retval EFI_NOT_READY - Not ready to locate AcpiTable.
**/
EFI_STATUS
EFIAPI
LocateAcpiTableBySignature (
IN UINT32 Signature,
IN OUT EFI_ACPI_DESCRIPTION_HEADER **Table,
IN OUT UINTN *Handle
)
{
EFI_STATUS Status;
INTN Index;
EFI_ACPI_TABLE_VERSION Version;
EFI_ACPI_DESCRIPTION_HEADER *OrgTable;
if (mAcpiSdt == NULL) {
InitializeAslUpdateLib ();
if (mAcpiSdt == NULL) {
return EFI_NOT_READY;
}
}
///
/// Locate table with matching ID
///
Version = 0;
Index = 0;
do {
Status = mAcpiSdt->GetAcpiTable (Index, (EFI_ACPI_SDT_HEADER **)&OrgTable, &Version, Handle);
if (Status == EFI_NOT_FOUND) {
break;
}
ASSERT_EFI_ERROR (Status);
Index++;
} while (OrgTable->Signature != Signature);
if (Status != EFI_NOT_FOUND) {
*Table = AllocateCopyPool (OrgTable->Length, OrgTable);
ASSERT (*Table);
}
///
/// If we found the table, there will be no error.
///
return Status;
}