mirror of
https://github.com/tianocore/edk2.git
synced 2025-08-29 01:47:04 +00:00

- This patch is intended to fix the debug macro issue reported from the Debug Macro Checking. - Remove the redundant comma between two debug message string. Signed-off-by: Jason1 Lin <jason1.lin@intel.com>
466 lines
14 KiB
C
466 lines
14 KiB
C
/** @file
|
|
|
|
Generate ACPI FACS table for AMD platforms.
|
|
|
|
Copyright (C) 2025 Advanced Micro Devices, Inc. All rights reserved.
|
|
|
|
SPDX-License-Identifier BSD-2-Clause-Patent
|
|
**/
|
|
|
|
#include <AcpiTableGenerator.h>
|
|
#include <ConfigurationManagerHelper.h>
|
|
#include <ConfigurationManagerObject.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/TableHelperLib.h>
|
|
#include <Protocol/AcpiTable.h>
|
|
#include <Protocol/ConfigurationManagerProtocol.h>
|
|
#include <X64NameSpaceObjects.h>
|
|
#include <Library/UefiBootServicesTableLib.h>
|
|
#include <Library/UefiLib.h>
|
|
#include <Library/BaseMemoryLib.h>
|
|
|
|
/** This macro expands to a function that retrieves the
|
|
FACS information from the Configuration Manager.
|
|
*/
|
|
GET_OBJECT_LIST (
|
|
EObjNameSpaceX64,
|
|
EX64ObjFacsInfo,
|
|
CM_X64_FACS_INFO
|
|
);
|
|
|
|
/** The ACPI FACS Table.
|
|
*/
|
|
STATIC
|
|
EFI_ACPI_6_5_FIRMWARE_ACPI_CONTROL_STRUCTURE AcpiFacs = {
|
|
EFI_ACPI_6_5_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE,
|
|
// Length
|
|
sizeof (EFI_ACPI_6_5_FIRMWARE_ACPI_CONTROL_STRUCTURE),
|
|
// Hardware Signature
|
|
0,
|
|
// Firmware Waking Vector
|
|
0,
|
|
// Global Lock
|
|
0,
|
|
// Flags
|
|
0,
|
|
// XFirmware Waking Vector
|
|
0,
|
|
// Version
|
|
0,
|
|
// Reserved0
|
|
{ 0, 0, 0 },
|
|
// OSPM Flags
|
|
0,
|
|
// Reserved1
|
|
{
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0
|
|
}
|
|
};
|
|
|
|
/**
|
|
Update the hardware signature in the FACS table.
|
|
**/
|
|
VOID
|
|
AcpiFacsUpdateHardwareSignature (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_ACPI_6_5_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs;
|
|
EFI_ACPI_6_5_FIXED_ACPI_DESCRIPTION_TABLE *Fadt;
|
|
EFI_ACPI_6_5_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp;
|
|
EFI_ACPI_DESCRIPTION_HEADER *Table;
|
|
EFI_ACPI_DESCRIPTION_HEADER *Xsdt;
|
|
EFI_ACPI_DESCRIPTION_HEADER *Dsdt;
|
|
EFI_STATUS Status;
|
|
UINT32 CollectedCrc[2];
|
|
UINT32 ComputedCrc;
|
|
UINT32 TableCount;
|
|
UINT64 XsdtTablePtr;
|
|
UINTN Index;
|
|
UINTN XsdtPtr;
|
|
|
|
DEBUG ((DEBUG_INFO, "Updating hardware signature in FACS Table.\n"));
|
|
|
|
Facs = NULL;
|
|
Fadt = NULL;
|
|
Dsdt = NULL;
|
|
Status = EfiGetSystemConfigurationTable (&gEfiAcpiTableGuid, (VOID **)&Rsdp);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "Failed to get RSDP. Status(%r)\n", Status));
|
|
ASSERT_EFI_ERROR (Status);
|
|
return;
|
|
}
|
|
|
|
if ( (Rsdp->Revision >= EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION)
|
|
&& (Rsdp->XsdtAddress != 0))
|
|
{
|
|
CollectedCrc[0] = Rsdp->ExtendedChecksum;
|
|
Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)Rsdp->XsdtAddress;
|
|
CollectedCrc[1] = Xsdt->Checksum;
|
|
gBS->CalculateCrc32 (
|
|
(UINT8 *)CollectedCrc,
|
|
ARRAY_SIZE (CollectedCrc),
|
|
&ComputedCrc
|
|
);
|
|
CollectedCrc[0] = ComputedCrc;
|
|
|
|
TableCount = (Xsdt->Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof (UINT64);
|
|
XsdtPtr = (UINTN)(Xsdt + 1);
|
|
for (Index = 0; Index < TableCount; Index++) {
|
|
CopyMem (
|
|
&XsdtTablePtr,
|
|
(VOID *)(XsdtPtr + Index * sizeof (UINT64)),
|
|
sizeof (UINT64)
|
|
);
|
|
Table = (EFI_ACPI_DESCRIPTION_HEADER *)((UINTN)(XsdtTablePtr));
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"FACS: Collecting CRC of %c%c%c%c\n",
|
|
Table->Signature & 0xFF,
|
|
(Table->Signature >> 8) & 0xFF,
|
|
(Table->Signature >> 16) & 0xFF,
|
|
(Table->Signature >> 24) & 0xFF
|
|
));
|
|
CollectedCrc[1] = Table->Checksum;
|
|
gBS->CalculateCrc32 (
|
|
(UINT8 *)CollectedCrc,
|
|
ARRAY_SIZE (CollectedCrc),
|
|
&ComputedCrc
|
|
);
|
|
CollectedCrc[0] = ComputedCrc;
|
|
/// check if Table is FADT
|
|
if (Table->Signature == EFI_ACPI_6_5_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE) {
|
|
Dsdt = NULL;
|
|
Fadt = (EFI_ACPI_6_5_FIXED_ACPI_DESCRIPTION_TABLE *)Table;
|
|
if (Fadt->XDsdt != 0) {
|
|
Dsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)(Fadt->XDsdt);
|
|
} else {
|
|
Dsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)(Fadt->Dsdt);
|
|
}
|
|
|
|
if (Dsdt != NULL) {
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"FACS: Collecting CRC of %c%c%c%c\n",
|
|
Dsdt->Signature & 0xFF,
|
|
(Dsdt->Signature >> 8) & 0xFF,
|
|
(Dsdt->Signature >> 16) & 0xFF,
|
|
(Dsdt->Signature >> 24) & 0xFF
|
|
));
|
|
CollectedCrc[1] = Dsdt->Checksum;
|
|
gBS->CalculateCrc32 (
|
|
(UINT8 *)CollectedCrc,
|
|
ARRAY_SIZE (CollectedCrc),
|
|
&ComputedCrc
|
|
);
|
|
CollectedCrc[0] = ComputedCrc;
|
|
}
|
|
|
|
Facs = NULL;
|
|
if (Fadt->XFirmwareCtrl != 0) {
|
|
Facs = (EFI_ACPI_6_5_FIRMWARE_ACPI_CONTROL_STRUCTURE *)(UINTN)(Fadt->XFirmwareCtrl);
|
|
} else {
|
|
Facs = (EFI_ACPI_6_5_FIRMWARE_ACPI_CONTROL_STRUCTURE *)(UINTN)(Fadt->FirmwareCtrl);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
DEBUG ((DEBUG_ERROR, "ERROR: FACS Generator do not support RSDT table.\n"));
|
|
return;
|
|
}
|
|
|
|
if (Facs != NULL) {
|
|
/// Update FACS signature
|
|
Facs->HardwareSignature = ComputedCrc;
|
|
} else {
|
|
DEBUG ((DEBUG_ERROR, "ERROR: FACS Table not found.\n"));
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/**
|
|
Event notification function for AcpiFacsLib.
|
|
|
|
@param[in] Event Event whose notification function is being invoked.
|
|
@param[in] Context Pointer to the notification function's context, which is
|
|
implementation-dependent.
|
|
**/
|
|
STATIC
|
|
VOID
|
|
EFIAPI
|
|
AcpiFacsLibEvent (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
/// Close the Event
|
|
gBS->CloseEvent (Event);
|
|
|
|
/// Update the FACS Table
|
|
AcpiFacsUpdateHardwareSignature ();
|
|
}
|
|
|
|
/** Update FACS table information.
|
|
|
|
@param [in] CfgMgrProtocol Pointer to the Configuration Manager
|
|
Protocol Interface.
|
|
|
|
@retval EFI_SUCCESS Success.
|
|
@retval EFI_INVALID_PARAMETER A parameter is invalid.
|
|
@retval EFI_NOT_FOUND The required object was not found or
|
|
the FACS is not enabled.
|
|
@retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration
|
|
Manager is less than the Object size for the
|
|
requested object.
|
|
@retval EFI_UNSUPPORTED If invalid protection and oem flags provided.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
FacsUpdateTableInfo (
|
|
IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol
|
|
)
|
|
{
|
|
CM_X64_FACS_INFO *FacsInfo;
|
|
EFI_STATUS Status;
|
|
|
|
ASSERT (CfgMgrProtocol != NULL);
|
|
|
|
// Get the FACS information from the Platform Configuration Manager
|
|
Status = GetEX64ObjFacsInfo (
|
|
CfgMgrProtocol,
|
|
CM_NULL_TOKEN,
|
|
&FacsInfo,
|
|
NULL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((
|
|
DEBUG_ERROR,
|
|
"ERROR: FACS: Failed to get FACS information." \
|
|
" Status = %r\n",
|
|
Status
|
|
));
|
|
return Status;
|
|
}
|
|
|
|
if ((FacsInfo->Flags & ~(EFI_ACPI_6_5_S4BIOS_F|EFI_ACPI_6_5_64BIT_WAKE_SUPPORTED_F)) != 0) {
|
|
DEBUG ((
|
|
DEBUG_ERROR,
|
|
"ERROR: FACS: Invalid Flags. Flags = 0x%x\n",
|
|
FacsInfo->Flags
|
|
));
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
if ((FacsInfo->OspmFlags & ~(EFI_ACPI_6_5_OSPM_64BIT_WAKE_F)) != 0) {
|
|
DEBUG ((
|
|
DEBUG_ERROR,
|
|
"ERROR: FACS: Invalid OSPM Flags. Flags = 0x%x\n",
|
|
FacsInfo->OspmFlags
|
|
));
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
if ((FacsInfo->OspmFlags & EFI_ACPI_6_5_OSPM_64BIT_WAKE_F) &&
|
|
!(FacsInfo->Flags & EFI_ACPI_6_5_64BIT_WAKE_SUPPORTED_F))
|
|
{
|
|
DEBUG ((
|
|
DEBUG_ERROR,
|
|
"ERROR: FACS: Invalid Flags. Flags = 0x%x, OSPM Flags = 0x%x.\n"
|
|
" 64-bit wake is not supported but 64-bit wake flag is set.\n",
|
|
FacsInfo->Flags,
|
|
FacsInfo->OspmFlags
|
|
));
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
// Update the FACS table
|
|
AcpiFacs.HardwareSignature = 0;
|
|
AcpiFacs.FirmwareWakingVector = FacsInfo->FirmwareWakingVector;
|
|
AcpiFacs.Flags = FacsInfo->Flags;
|
|
AcpiFacs.XFirmwareWakingVector = FacsInfo->XFirmwareWakingVector;
|
|
AcpiFacs.Version = EFI_ACPI_6_5_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION;
|
|
AcpiFacs.OspmFlags = FacsInfo->OspmFlags;
|
|
|
|
return Status;
|
|
}
|
|
|
|
/** Construct the FACS table.
|
|
|
|
This function invokes the Configuration Manager protocol interface
|
|
to get the required information for generating the ACPI table.
|
|
|
|
If this function allocates any resources then they must be freed
|
|
in the FreeXXXXTableResources function.
|
|
|
|
@param [in] This Pointer to the table generator.
|
|
@param [in] AcpiTableInfo Pointer to the ACPI Table Info.
|
|
@param [in] CfgMgrProtocol Pointer to the Configuration Manager
|
|
Protocol Interface.
|
|
@param [out] Table Pointer to the constructed ACPI Table.
|
|
|
|
@retval EFI_SUCCESS Table generated successfully.
|
|
@retval EFI_INVALID_PARAMETER A parameter is invalid.
|
|
@retval EFI_NOT_FOUND The required object was not found.
|
|
@retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration
|
|
Manager is less than the Object size for the
|
|
requested object.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BuildFacsTable (
|
|
IN CONST ACPI_TABLE_GENERATOR *CONST This,
|
|
IN CONST CM_STD_OBJ_ACPI_TABLE_INFO *CONST AcpiTableInfo,
|
|
IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
|
|
OUT EFI_ACPI_DESCRIPTION_HEADER **CONST Table
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_EVENT Event;
|
|
|
|
ASSERT (This != NULL);
|
|
ASSERT (AcpiTableInfo != NULL);
|
|
ASSERT (CfgMgrProtocol != NULL);
|
|
ASSERT (Table != NULL);
|
|
ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
|
|
ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
|
|
|
|
if ((AcpiTableInfo->AcpiTableRevision < This->MinAcpiTableRevision) ||
|
|
(AcpiTableInfo->AcpiTableRevision > This->AcpiTableRevision))
|
|
{
|
|
DEBUG ((
|
|
DEBUG_ERROR,
|
|
"ERROR: FACS: Requested table revision = %d, is not supported."
|
|
"Supported table revision: Minimum = %d, Maximum = %d\n",
|
|
AcpiTableInfo->AcpiTableRevision,
|
|
This->MinAcpiTableRevision,
|
|
This->AcpiTableRevision
|
|
));
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
*Table = NULL;
|
|
|
|
// Update FACS table info
|
|
Status = FacsUpdateTableInfo (CfgMgrProtocol);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((
|
|
DEBUG_ERROR,
|
|
"ERROR: FACS: Failed to update table info. Status = %r\n",
|
|
Status
|
|
));
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Register notify function
|
|
//
|
|
Status = gBS->CreateEventEx (
|
|
EVT_NOTIFY_SIGNAL,
|
|
TPL_CALLBACK,
|
|
AcpiFacsLibEvent,
|
|
NULL,
|
|
&gEfiEventReadyToBootGuid,
|
|
&Event
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((
|
|
DEBUG_ERROR,
|
|
"ERROR: FACS: Failed to create event. Status = %r\n",
|
|
Status
|
|
));
|
|
return Status;
|
|
}
|
|
|
|
*Table = (EFI_ACPI_DESCRIPTION_HEADER *)&AcpiFacs;
|
|
return Status;
|
|
}
|
|
|
|
/** This macro defines the FACS Table Generator revision.
|
|
*/
|
|
#define FACS_GENERATOR_REVISION CREATE_REVISION (1, 0)
|
|
|
|
/** The interface for the FACS Table Generator.
|
|
*/
|
|
STATIC
|
|
CONST
|
|
ACPI_TABLE_GENERATOR FacsGenerator = {
|
|
// Generator ID
|
|
CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdFacs),
|
|
// Generator Description
|
|
L"ACPI.STD.FACS.GENERATOR",
|
|
// ACPI Table Signature
|
|
EFI_ACPI_6_5_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE,
|
|
// ACPI Table Revision supported by this Generator
|
|
EFI_ACPI_6_5_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION,
|
|
// Minimum supported ACPI Table Revision
|
|
EFI_ACPI_6_5_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION,
|
|
// Creator ID
|
|
TABLE_GENERATOR_CREATOR_ID,
|
|
// Creator Revision
|
|
FACS_GENERATOR_REVISION,
|
|
// Build Table function
|
|
BuildFacsTable,
|
|
// No additional resources are allocated by the generator.
|
|
// Hence the Free Resource function is not required.
|
|
NULL,
|
|
// Extended build function not needed
|
|
NULL,
|
|
// Extended build function not implemented by the generator.
|
|
// Hence extended free resource function is not required.
|
|
NULL
|
|
};
|
|
|
|
/** Register the Generator with the ACPI Table Factory.
|
|
|
|
@param [in] ImageHandle The handle to the image.
|
|
@param [in] SystemTable Pointer to the System Table.
|
|
|
|
@retval EFI_SUCCESS The Generator is registered.
|
|
@retval EFI_INVALID_PARAMETER A parameter is invalid.
|
|
@retval EFI_ALREADY_STARTED The Generator for the Table ID
|
|
is already registered.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
AcpiFacsLibConstructor (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
Status = RegisterAcpiTableGenerator (&FacsGenerator);
|
|
DEBUG ((DEBUG_INFO, "FACS: Register Generator. Status = %r\n", Status));
|
|
ASSERT_EFI_ERROR (Status);
|
|
return Status;
|
|
}
|
|
|
|
/** Deregister the Generator from the ACPI Table Factory.
|
|
|
|
@param [in] ImageHandle The handle to the image.
|
|
@param [in] SystemTable Pointer to the System Table.
|
|
|
|
@retval EFI_SUCCESS The Generator is deregistered.
|
|
@retval EFI_INVALID_PARAMETER A parameter is invalid.
|
|
@retval EFI_NOT_FOUND The Generator is not registered.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
AcpiFacsLibDestructor (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
Status = DeregisterAcpiTableGenerator (&FacsGenerator);
|
|
DEBUG ((DEBUG_INFO, "FACS: Deregister Generator. Status = %r\n", Status));
|
|
ASSERT_EFI_ERROR (Status);
|
|
return Status;
|
|
}
|