summaryrefslogtreecommitdiffstats
path: root/DynamicTablesPkg/Library/Acpi/X64/AcpiFacsLib/FacsGenerator.c
diff options
context:
space:
mode:
Diffstat (limited to 'DynamicTablesPkg/Library/Acpi/X64/AcpiFacsLib/FacsGenerator.c')
-rw-r--r--DynamicTablesPkg/Library/Acpi/X64/AcpiFacsLib/FacsGenerator.c465
1 files changed, 465 insertions, 0 deletions
diff --git a/DynamicTablesPkg/Library/Acpi/X64/AcpiFacsLib/FacsGenerator.c b/DynamicTablesPkg/Library/Acpi/X64/AcpiFacsLib/FacsGenerator.c
new file mode 100644
index 0000000000..5e5cccedb9
--- /dev/null
+++ b/DynamicTablesPkg/Library/Acpi/X64/AcpiFacsLib/FacsGenerator.c
@@ -0,0 +1,465 @@
+/** @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;
+}