mirror of https://github.com/acidanthera/audk.git
395 lines
12 KiB
C
395 lines
12 KiB
C
/** @file
|
|
*
|
|
* Copyright (c) 2014-2015, ARM Limited. All rights reserved.
|
|
* Copyright (c) 2021, Ampere Computing LLC. All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
*
|
|
**/
|
|
|
|
#include <Uefi.h>
|
|
|
|
#include <Library/AcpiLib.h>
|
|
#include <Library/BaseLib.h>
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/UefiBootServicesTableLib.h>
|
|
|
|
#include <Protocol/AcpiSystemDescriptionTable.h>
|
|
#include <Protocol/AcpiTable.h>
|
|
#include <Protocol/FirmwareVolume2.h>
|
|
|
|
#include <IndustryStandard/Acpi.h>
|
|
|
|
/**
|
|
Locate and Install the ACPI tables from the Firmware Volume if it verifies
|
|
the function condition.
|
|
|
|
@param AcpiFile Guid of the ACPI file into the Firmware Volume
|
|
@param CheckAcpiTableFunction Function that checks if the ACPI table should be installed
|
|
|
|
@return EFI_SUCCESS The function completed successfully.
|
|
@return EFI_NOT_FOUND The protocol could not be located.
|
|
@return EFI_OUT_OF_RESOURCES There are not enough resources to find the protocol.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
LocateAndInstallAcpiFromFvConditional (
|
|
IN CONST EFI_GUID *AcpiFile,
|
|
IN EFI_LOCATE_ACPI_CHECK CheckAcpiTableFunction
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol;
|
|
EFI_HANDLE *HandleBuffer;
|
|
UINTN NumberOfHandles;
|
|
UINT32 FvStatus;
|
|
UINTN Index;
|
|
EFI_FIRMWARE_VOLUME2_PROTOCOL *FvInstance;
|
|
INTN SectionInstance;
|
|
UINTN SectionSize;
|
|
EFI_ACPI_COMMON_HEADER *AcpiTable;
|
|
UINTN AcpiTableSize;
|
|
UINTN AcpiTableKey;
|
|
BOOLEAN Valid;
|
|
|
|
// Ensure the ACPI Table is present
|
|
Status = gBS->LocateProtocol (
|
|
&gEfiAcpiTableProtocolGuid,
|
|
NULL,
|
|
(VOID **)&AcpiProtocol
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
FvStatus = 0;
|
|
SectionInstance = 0;
|
|
|
|
// Locate all the Firmware Volume protocols.
|
|
Status = gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiFirmwareVolume2ProtocolGuid,
|
|
NULL,
|
|
&NumberOfHandles,
|
|
&HandleBuffer
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
// Looking for FV with ACPI storage file
|
|
for (Index = 0; Index < NumberOfHandles; Index++) {
|
|
//
|
|
// Get the protocol on this handle
|
|
// This should not fail because of LocateHandleBuffer
|
|
//
|
|
Status = gBS->HandleProtocol (
|
|
HandleBuffer[Index],
|
|
&gEfiFirmwareVolume2ProtocolGuid,
|
|
(VOID **)&FvInstance
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto FREE_HANDLE_BUFFER;
|
|
}
|
|
|
|
while (Status == EFI_SUCCESS) {
|
|
// AcpiTable must be allocated by ReadSection (ie: AcpiTable == NULL)
|
|
AcpiTable = NULL;
|
|
|
|
// See if it has the ACPI storage file
|
|
Status = FvInstance->ReadSection (
|
|
FvInstance,
|
|
AcpiFile,
|
|
EFI_SECTION_RAW,
|
|
SectionInstance,
|
|
(VOID **)&AcpiTable,
|
|
&SectionSize,
|
|
&FvStatus
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
AcpiTableKey = 0;
|
|
AcpiTableSize = ((EFI_ACPI_DESCRIPTION_HEADER *)AcpiTable)->Length;
|
|
ASSERT (SectionSize >= AcpiTableSize);
|
|
|
|
DEBUG ((
|
|
DEBUG_ERROR,
|
|
"- Found '%c%c%c%c' ACPI Table\n",
|
|
(((EFI_ACPI_DESCRIPTION_HEADER *)AcpiTable)->Signature & 0xFF),
|
|
((((EFI_ACPI_DESCRIPTION_HEADER *)AcpiTable)->Signature >> 8) & 0xFF),
|
|
((((EFI_ACPI_DESCRIPTION_HEADER *)AcpiTable)->Signature >> 16) & 0xFF),
|
|
((((EFI_ACPI_DESCRIPTION_HEADER *)AcpiTable)->Signature >> 24) & 0xFF)
|
|
));
|
|
|
|
// Is the ACPI table valid?
|
|
if (CheckAcpiTableFunction) {
|
|
Valid = CheckAcpiTableFunction ((EFI_ACPI_DESCRIPTION_HEADER *)AcpiTable);
|
|
} else {
|
|
Valid = TRUE;
|
|
}
|
|
|
|
// Install the ACPI Table
|
|
if (Valid) {
|
|
Status = AcpiProtocol->InstallAcpiTable (
|
|
AcpiProtocol,
|
|
AcpiTable,
|
|
AcpiTableSize,
|
|
&AcpiTableKey
|
|
);
|
|
}
|
|
|
|
// Free memory allocated by ReadSection
|
|
gBS->FreePool (AcpiTable);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
break;
|
|
}
|
|
|
|
// Increment the section instance
|
|
SectionInstance++;
|
|
}
|
|
}
|
|
}
|
|
|
|
FREE_HANDLE_BUFFER:
|
|
//
|
|
// Free any allocated buffers
|
|
//
|
|
gBS->FreePool (HandleBuffer);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Locate and Install the ACPI tables from the Firmware Volume
|
|
|
|
@param AcpiFile Guid of the ACPI file into the Firmware Volume
|
|
|
|
@return EFI_SUCCESS The function completed successfully.
|
|
@return EFI_NOT_FOUND The protocol could not be located.
|
|
@return EFI_OUT_OF_RESOURCES There are not enough resources to find the protocol.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
LocateAndInstallAcpiFromFv (
|
|
IN CONST EFI_GUID *AcpiFile
|
|
)
|
|
{
|
|
return LocateAndInstallAcpiFromFvConditional (AcpiFile, NULL);
|
|
}
|
|
|
|
/**
|
|
This function calculates and updates a UINT8 checksum
|
|
in an ACPI description table header.
|
|
|
|
@param Buffer Pointer to buffer to checksum
|
|
@param Size Number of bytes to checksum
|
|
|
|
@retval EFI_SUCCESS The function completed successfully.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
AcpiUpdateChecksum (
|
|
IN OUT UINT8 *Buffer,
|
|
IN UINTN Size
|
|
)
|
|
{
|
|
UINTN ChecksumOffset;
|
|
|
|
if ((Buffer == NULL) || (Size == 0)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
ChecksumOffset = OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER, Checksum);
|
|
|
|
//
|
|
// Set checksum to 0 first
|
|
//
|
|
Buffer[ChecksumOffset] = 0;
|
|
|
|
//
|
|
// Update checksum value
|
|
//
|
|
Buffer[ChecksumOffset] = CalculateCheckSum8 (Buffer, Size);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
This function uses the ACPI SDT protocol to search an ACPI table
|
|
with a given signature.
|
|
|
|
@param AcpiTableSdtProtocol Pointer to ACPI SDT protocol.
|
|
@param TableSignature ACPI table signature.
|
|
@param Index The zero-based index of the table where to search the table.
|
|
The index will be updated to the next instance if the table
|
|
is found with the matched TableSignature.
|
|
@param Table Pointer to the table.
|
|
@param TableKey Pointer to the table key.
|
|
|
|
@return EFI_SUCCESS The function completed successfully.
|
|
@return EFI_INVALID_PARAMETER At least one of parameters is invalid.
|
|
@retval EFI_NOT_FOUND The requested index is too large and a table was not found.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
AcpiLocateTableBySignature (
|
|
IN EFI_ACPI_SDT_PROTOCOL *AcpiSdtProtocol,
|
|
IN UINT32 TableSignature,
|
|
IN OUT UINTN *Index,
|
|
OUT EFI_ACPI_DESCRIPTION_HEADER **Table,
|
|
OUT UINTN *TableKey
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_ACPI_SDT_HEADER *TempTable;
|
|
EFI_ACPI_TABLE_VERSION TableVersion;
|
|
UINTN TableIndex;
|
|
|
|
if ( (AcpiSdtProtocol == NULL)
|
|
|| (Table == NULL)
|
|
|| (TableKey == NULL))
|
|
{
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
//
|
|
// Search for ACPI Table with matching signature
|
|
//
|
|
TableVersion = 0;
|
|
TableIndex = *Index;
|
|
while (!EFI_ERROR (Status)) {
|
|
Status = AcpiSdtProtocol->GetAcpiTable (
|
|
TableIndex,
|
|
&TempTable,
|
|
&TableVersion,
|
|
TableKey
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
TableIndex++;
|
|
|
|
if (((EFI_ACPI_DESCRIPTION_HEADER *)TempTable)->Signature == TableSignature) {
|
|
*Table = (EFI_ACPI_DESCRIPTION_HEADER *)TempTable;
|
|
*Index = TableIndex;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
This function updates the integer value of an AML Object.
|
|
|
|
@param AcpiTableSdtProtocol Pointer to ACPI SDT protocol.
|
|
@param TableHandle Points to the table representing the starting point
|
|
for the object path search.
|
|
@param AsciiObjectPath Pointer to the ACPI path of the object being updated.
|
|
@param Value New value to write to the object.
|
|
|
|
@return EFI_SUCCESS The function completed successfully.
|
|
@return EFI_INVALID_PARAMETER At least one of parameters is invalid or the data type
|
|
of the ACPI object is not an integer value.
|
|
@retval EFI_NOT_FOUND The object is not found with the given path.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
AcpiAmlObjectUpdateInteger (
|
|
IN EFI_ACPI_SDT_PROTOCOL *AcpiSdtProtocol,
|
|
IN EFI_ACPI_HANDLE TableHandle,
|
|
IN CHAR8 *AsciiObjectPath,
|
|
IN UINTN Value
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_ACPI_HANDLE ObjectHandle;
|
|
EFI_ACPI_HANDLE DataHandle;
|
|
EFI_ACPI_DATA_TYPE DataType;
|
|
UINT8 *Buffer;
|
|
UINTN BufferSize;
|
|
UINTN DataSize;
|
|
|
|
if ((AcpiSdtProtocol == NULL) || (AsciiObjectPath == NULL)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
ObjectHandle = NULL;
|
|
DataHandle = NULL;
|
|
|
|
Status = AcpiSdtProtocol->FindPath (TableHandle, AsciiObjectPath, &ObjectHandle);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = AcpiSdtProtocol->GetOption (ObjectHandle, 0, &DataType, (VOID *)&Buffer, &BufferSize);
|
|
if (EFI_ERROR (Status)) {
|
|
Status = EFI_NOT_FOUND;
|
|
goto Exit;
|
|
}
|
|
|
|
ASSERT (DataType == EFI_ACPI_DATA_TYPE_OPCODE);
|
|
ASSERT (Buffer != NULL);
|
|
|
|
if (Buffer[0] != AML_NAME_OP) {
|
|
Status = EFI_NOT_FOUND;
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Get handle of data object
|
|
//
|
|
Status = AcpiSdtProtocol->GetChild (ObjectHandle, &DataHandle);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
Status = AcpiSdtProtocol->GetOption (DataHandle, 0, &DataType, (VOID *)&Buffer, &BufferSize);
|
|
ASSERT (DataType == EFI_ACPI_DATA_TYPE_OPCODE);
|
|
ASSERT (Buffer != NULL);
|
|
|
|
if ((Buffer[0] == AML_ZERO_OP) || (Buffer[0] == AML_ONE_OP)) {
|
|
Status = AcpiSdtProtocol->SetOption (DataHandle, 0, (VOID *)&Value, sizeof (UINT8));
|
|
ASSERT_EFI_ERROR (Status);
|
|
} else {
|
|
//
|
|
// Check the size of data object
|
|
//
|
|
switch (Buffer[0]) {
|
|
case AML_BYTE_PREFIX:
|
|
DataSize = sizeof (UINT8);
|
|
break;
|
|
|
|
case AML_WORD_PREFIX:
|
|
DataSize = sizeof (UINT16);
|
|
break;
|
|
|
|
case AML_DWORD_PREFIX:
|
|
DataSize = sizeof (UINT32);
|
|
break;
|
|
|
|
case AML_QWORD_PREFIX:
|
|
DataSize = sizeof (UINT64);
|
|
break;
|
|
|
|
default:
|
|
// The data type of the ACPI object is not an integer
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
Status = AcpiSdtProtocol->SetOption (DataHandle, 1, (VOID *)&Value, DataSize);
|
|
ASSERT_EFI_ERROR (Status);
|
|
}
|
|
|
|
Exit:
|
|
AcpiSdtProtocol->Close (DataHandle);
|
|
AcpiSdtProtocol->Close (ObjectHandle);
|
|
|
|
return Status;
|
|
}
|