MdeModulePkg/ACPI: Install ACPI table from HOB.

If HOB contains APCI table information, entry point of AcpiTableDxe.inf
should parse the APCI table from HOB, and install these tables.
We assume the whole ACPI table
(starting with EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER)
is contained by a single gEfiAcpiTableGuid HOB.

If error happens when installing ACPI table, stop installing and removing
all the tables that are already added.

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Hao A Wu <hao.a.wu@intel.com>
Cc: Dandan Bi <dandan.bi@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Ray Ni <ray.ni@intel.com>
Reviewed-by: Hao A Wu <hao.a.wu@intel.com>
Tested-by: Patrick Rudolph <patrick.rudolph@9elements.com>
Signed-off-by: Zhiguang Liu <zhiguang.liu@intel.com>
This commit is contained in:
Zhiguang Liu
2021-04-30 14:17:56 +08:00
committed by mergify[bot]
parent 75293330ea
commit 761329ee27
4 changed files with 271 additions and 38 deletions

View File

@@ -1,7 +1,7 @@
/** @file
ACPI Table Protocol Implementation
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
@@ -30,6 +30,7 @@ STATIC EFI_ALLOCATE_TYPE mAcpiTableAllocType;
@param Table Table to add.
@param Checksum Does the table require checksumming.
@param Version The version of the list to add the table to.
@param IsFromHob True, if add Apci Table from Hob List.
@param Handle Pointer for returning the handle.
@return EFI_SUCCESS The function completed successfully.
@@ -44,6 +45,7 @@ AddTableToList (
IN VOID *Table,
IN BOOLEAN Checksum,
IN EFI_ACPI_TABLE_VERSION Version,
IN BOOLEAN IsFromHob,
OUT UINTN *Handle
);
@@ -238,6 +240,7 @@ InstallAcpiTable (
AcpiTableBufferConst,
TRUE,
Version,
FALSE,
TableKey
);
if (!EFI_ERROR (Status)) {
@@ -472,6 +475,7 @@ FreeTableMemory (
@param Table Table to add.
@param Checksum Does the table require checksumming.
@param Version The version of the list to add the table to.
@param IsFromHob True, if add Apci Table from Hob List.
@param Handle Pointer for returning the handle.
@return EFI_SUCCESS The function completed successfully.
@@ -487,6 +491,7 @@ AddTableToList (
IN VOID *Table,
IN BOOLEAN Checksum,
IN EFI_ACPI_TABLE_VERSION Version,
IN BOOLEAN IsFromHob,
OUT UINTN *Handle
)
{
@@ -553,12 +558,17 @@ AddTableToList (
// SMM communication ACPI table.
//
ASSERT ((EFI_PAGE_SIZE % 64) == 0);
Status = gBS->AllocatePages (
AllocateMaxAddress,
EfiACPIMemoryNVS,
EFI_SIZE_TO_PAGES (CurrentTableList->TableSize),
&AllocPhysAddress
);
if (IsFromHob){
AllocPhysAddress = (UINTN)Table;
Status = EFI_SUCCESS;
} else {
Status = gBS->AllocatePages (
AllocateMaxAddress,
EfiACPIMemoryNVS,
EFI_SIZE_TO_PAGES (CurrentTableList->TableSize),
&AllocPhysAddress
);
}
} else if (mAcpiTableAllocType == AllocateAnyPages) {
//
// If there is no allocation limit, there is also no need to use page
@@ -1689,6 +1699,151 @@ ChecksumCommonTables (
return EFI_SUCCESS;
}
/**
This function will find gUniversalPayloadAcpiTableGuid Guid Hob, and install Acpi table from it.
@param AcpiTableInstance Protocol instance private data.
@return EFI_SUCCESS The function completed successfully.
@return EFI_NOT_FOUND The function doesn't find the gEfiAcpiTableGuid Guid Hob.
@return EFI_ABORTED The function could not complete successfully.
**/
EFI_STATUS
InstallAcpiTableFromHob (
EFI_ACPI_TABLE_INSTANCE *AcpiTableInstance
)
{
EFI_HOB_GUID_TYPE *GuidHob;
EFI_ACPI_TABLE_VERSION Version;
EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp;
EFI_ACPI_DESCRIPTION_HEADER *Rsdt;
EFI_ACPI_DESCRIPTION_HEADER *ChildTable;
UINT64 ChildTableAddress;
UINTN Count;
UINTN Index;
UINTN TableKey;
EFI_STATUS Status;
UINTN EntrySize;
UNIVERSAL_PAYLOAD_ACPI_TABLE *AcpiTableAdress;
VOID *TableToInstall;
EFI_ACPI_SDT_HEADER *Table;
UNIVERSAL_PAYLOAD_GENERIC_HEADER *GenericHeader;
TableKey = 0;
Version = PcdGet32 (PcdAcpiExposedTableVersions);
Status = EFI_SUCCESS;
//
// HOB only contains the ACPI table in 2.0+ format.
//
GuidHob = GetFirstGuidHob (&gUniversalPayloadAcpiTableGuid);
if (GuidHob == NULL) {
return EFI_NOT_FOUND;
}
GenericHeader = (UNIVERSAL_PAYLOAD_GENERIC_HEADER *) GET_GUID_HOB_DATA (GuidHob);
if ((sizeof (UNIVERSAL_PAYLOAD_GENERIC_HEADER) > GET_GUID_HOB_DATA_SIZE (GuidHob)) || (GenericHeader->Length > GET_GUID_HOB_DATA_SIZE (GuidHob))) {
return EFI_NOT_FOUND;
}
if (GenericHeader->Revision == UNIVERSAL_PAYLOAD_ACPI_TABLE_REVISION) {
//
// UNIVERSAL_PAYLOAD_ACPI_TABLE structure is used when Revision equals to UNIVERSAL_PAYLOAD_ACPI_TABLE_REVISION
//
AcpiTableAdress = (UNIVERSAL_PAYLOAD_ACPI_TABLE *) GET_GUID_HOB_DATA (GuidHob);
if (AcpiTableAdress->Header.Length < UNIVERSAL_PAYLOAD_SIZEOF_THROUGH_FIELD (UNIVERSAL_PAYLOAD_ACPI_TABLE, Rsdp)) {
//
// Retrun if can't find the ACPI Info Hob with enough length
//
return EFI_NOT_FOUND;
}
Rsdp = (EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER *) (UINTN) (AcpiTableAdress->Rsdp);
//
// An ACPI-compatible OS must use the XSDT if present.
// It shouldn't happen that XsdtAddress points beyond 4G range in 32-bit environment.
//
ASSERT ((UINTN) Rsdp->XsdtAddress == Rsdp->XsdtAddress);
EntrySize = sizeof (UINT64);
Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN) Rsdp->XsdtAddress;
if (Rsdt == NULL) {
//
// XsdtAddress is zero, then we use Rsdt which has 32 bit entry
//
Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN) Rsdp->RsdtAddress;
EntrySize = sizeof (UINT32);
}
if (Rsdt->Length <= sizeof (EFI_ACPI_DESCRIPTION_HEADER)) {
return EFI_ABORTED;
}
Count = (Rsdt->Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / EntrySize;
for (Index = 0; Index < Count; Index++){
ChildTableAddress = 0;
CopyMem (&ChildTableAddress, (UINT8 *) (Rsdt + 1) + EntrySize * Index, EntrySize);
//
// If the address is of UINT64 while this module runs at 32 bits,
// make sure the upper bits are all-zeros.
//
ASSERT (ChildTableAddress == (UINTN) ChildTableAddress);
if (ChildTableAddress != (UINTN) ChildTableAddress) {
Status = EFI_ABORTED;
break;
}
ChildTable = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN) ChildTableAddress;
Status = AddTableToList (AcpiTableInstance, ChildTable, TRUE, Version, TRUE, &TableKey);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "InstallAcpiTableFromHob: Fail to add ACPI table at 0x%p\n", ChildTable));
ASSERT_EFI_ERROR (Status);
break;
}
if (ChildTable->Signature == EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE){
//
// Add the FACS and DSDT tables if it is not NULL.
//
if (((EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *) ChildTable)->FirmwareCtrl != 0) {
TableToInstall = (VOID *) (UINTN) ((EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *) ChildTable)->FirmwareCtrl;
Status = AddTableToList (AcpiTableInstance, TableToInstall, TRUE, Version, TRUE, &TableKey);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "InstallAcpiTableFromHob: Fail to add ACPI table FACS\n"));
ASSERT_EFI_ERROR (Status);
break;
}
}
if (((EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *) ChildTable)->Dsdt != 0) {
TableToInstall = (VOID *) (UINTN) ((EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *) ChildTable)->Dsdt;
Status = AddTableToList (AcpiTableInstance, TableToInstall, TRUE, Version, TRUE, &TableKey);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "InstallAcpiTableFromHob: Fail to add ACPI table DSDT\n"));
ASSERT_EFI_ERROR (Status);
break;
}
}
}
}
} else {
return EFI_NOT_FOUND;
}
if (EFI_ERROR (Status)) {
//
// Error happens when trying to add ACPI table to the list.
// Remove all of them from list because at this time, no other tables except from HOB are in the list
//
while (SdtGetAcpiTable (AcpiTableInstance, 0, &Table, &Version, &TableKey) == EFI_SUCCESS) {
RemoveTableFromList (AcpiTableInstance, Version, TableKey);
}
} else {
Status = PublishTables (AcpiTableInstance, Version);
}
ASSERT_EFI_ERROR (Status);
return Status;
}
/**
Constructor for the ACPI table protocol. Initializes instance
@@ -1918,6 +2073,8 @@ AcpiTableAcpiTableConstructor (
ChecksumCommonTables (AcpiTableInstance);
InstallAcpiTableFromHob (AcpiTableInstance);
//
// Completed successfully
//