/** @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.<BR>
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
**/
|
#include <Base.h>
|
#include <Uefi/UefiBaseType.h>
|
#include <Uefi/UefiSpec.h>
|
#include <Library/UefiBootServicesTableLib.h>
|
#include <Library/DebugLib.h>
|
#include <Library/UefiLib.h>
|
#include <Library/BaseMemoryLib.h>
|
#include <Library/MemoryAllocationLib.h>
|
|
#include <Library/AslUpdateLib.h>
|
|
//
|
// 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;
|
}
|
|