/** @file
This is the driver that initializes the Intel System Agent.
Copyright (c) 2019 Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "SaInitDxe.h"
#include "SaInit.h"
#include
#include
#include
///
/// Global Variables
///
GLOBAL_REMOVE_IF_UNREFERENCED SYSTEM_AGENT_NVS_AREA_PROTOCOL mSaNvsAreaProtocol;
GLOBAL_REMOVE_IF_UNREFERENCED SA_POLICY_PROTOCOL *mSaPolicy;
extern SA_CONFIG_HOB *mSaConfigHob;
/**
Initialize System Agent SSDT ACPI tables
@retval EFI_SUCCESS ACPI tables are initialized successfully
@retval EFI_NOT_FOUND ACPI tables not found
**/
EFI_STATUS
InitializeSaSsdtAcpiTables (
VOID
)
{
EFI_STATUS Status;
EFI_HANDLE *HandleBuffer;
UINTN NumberOfHandles;
EFI_FV_FILETYPE FileType;
UINT32 FvStatus;
EFI_FV_FILE_ATTRIBUTES Attributes;
UINTN Size;
UINTN i;
EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVol;
INTN Instance;
EFI_ACPI_COMMON_HEADER *CurrentTable;
UINTN AcpiTableKey;
UINT8 *CurrPtr;
UINT8 *EndPtr;
UINT32 *Signature;
EFI_ACPI_DESCRIPTION_HEADER *SaAcpiTable;
EFI_ACPI_TABLE_PROTOCOL *AcpiTable;
FwVol = NULL;
SaAcpiTable = NULL;
///
/// Locate ACPI Table protocol
///
DEBUG ((DEBUG_INFO, "Init SA SSDT table\n"));
Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable);
if (Status != EFI_SUCCESS) {
DEBUG ((DEBUG_WARN, "Fail to locate EfiAcpiTableProtocol.\n"));
return EFI_NOT_FOUND;
}
///
/// Locate protocol.
/// There is little chance we can't find an FV protocol
///
Status = gBS->LocateHandleBuffer (
ByProtocol,
&gEfiFirmwareVolume2ProtocolGuid,
NULL,
&NumberOfHandles,
&HandleBuffer
);
ASSERT_EFI_ERROR (Status);
///
/// Looking for FV with ACPI storage file
///
for (i = 0; i < NumberOfHandles; i++) {
///
/// Get the protocol on this handle
/// This should not fail because of LocateHandleBuffer
///
Status = gBS->HandleProtocol (
HandleBuffer[i],
&gEfiFirmwareVolume2ProtocolGuid,
(VOID **) &FwVol
);
ASSERT_EFI_ERROR (Status);
///
/// See if it has the ACPI storage file
///
Size = 0;
FvStatus = 0;
Status = FwVol->ReadFile (
FwVol,
&gSaSsdtAcpiTableStorageGuid,
NULL,
&Size,
&FileType,
&Attributes,
&FvStatus
);
///
/// If we found it, then we are done
///
if (Status == EFI_SUCCESS) {
break;
}
}
///
/// Free any allocated buffers
///
FreePool (HandleBuffer);
///
/// Sanity check that we found our data file
///
ASSERT (FwVol != NULL);
if (FwVol == NULL) {
DEBUG ((DEBUG_INFO, "SA Global NVS table not found\n"));
return EFI_NOT_FOUND;
}
///
/// Our exit status is determined by the success of the previous operations
/// If the protocol was found, Instance already points to it.
/// Read tables from the storage file.
///
Instance = 0;
CurrentTable = NULL;
while (Status == EFI_SUCCESS) {
Status = FwVol->ReadSection (
FwVol,
&gSaSsdtAcpiTableStorageGuid,
EFI_SECTION_RAW,
Instance,
(VOID **) &CurrentTable,
&Size,
&FvStatus
);
if (!EFI_ERROR (Status)) {
///
/// Check the table ID to modify the table
///
if (((EFI_ACPI_DESCRIPTION_HEADER *) CurrentTable)->OemTableId == SIGNATURE_64 ('S', 'a', 'S', 's', 'd', 't', ' ', 0)) {
SaAcpiTable = (EFI_ACPI_DESCRIPTION_HEADER *) CurrentTable;
///
/// Locate the SSDT package
///
CurrPtr = (UINT8 *) SaAcpiTable;
EndPtr = CurrPtr + SaAcpiTable->Length;
for (; CurrPtr <= EndPtr; CurrPtr++) {
Signature = (UINT32 *) (CurrPtr + 3);
if (*Signature == SIGNATURE_32 ('S', 'A', 'N', 'V')) {
ASSERT (*(UINT32 *) (CurrPtr + 3 + sizeof (*Signature) + 2) == 0xFFFF0000);
ASSERT (*(UINT16 *) (CurrPtr + 3 + sizeof (*Signature) + 2 + sizeof (UINT32) + 1) == 0xAA55);
///
/// SA Global NVS Area address
///
*(UINT32 *) (CurrPtr + 3 + sizeof (*Signature) + 2) = (UINT32) (UINTN) mSaNvsAreaProtocol.Area;
///
/// SA Global NVS Area size
///
*(UINT16 *) (CurrPtr + 3 + sizeof (*Signature) + 2 + sizeof (UINT32) + 1) =
sizeof (SYSTEM_AGENT_NVS_AREA);
AcpiTableKey = 0;
Status = AcpiTable->InstallAcpiTable (
AcpiTable,
SaAcpiTable,
SaAcpiTable->Length,
&AcpiTableKey
);
ASSERT_EFI_ERROR (Status);
return EFI_SUCCESS;
}
}
}
///
/// Increment the instance
///
Instance++;
CurrentTable = NULL;
}
}
return Status;
}
/**
Install SSDT Table
@retval EFI_SUCCESS - SSDT Table load successful.
**/
EFI_STATUS
InstallSsdtAcpiTable (
IN GUID SsdtTableGuid,
IN UINT64 Signature
)
{
EFI_STATUS Status;
EFI_HANDLE *HandleBuffer;
BOOLEAN LoadTable;
UINTN NumberOfHandles;
UINTN Index;
INTN Instance;
UINTN Size;
UINT32 FvStatus;
UINTN TableHandle;
EFI_FV_FILETYPE FileType;
EFI_FV_FILE_ATTRIBUTES Attributes;
EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVol;
EFI_ACPI_TABLE_PROTOCOL *AcpiTable;
EFI_ACPI_DESCRIPTION_HEADER *TableHeader;
EFI_ACPI_COMMON_HEADER *Table;
FwVol = NULL;
Table = NULL;
DEBUG ((DEBUG_INFO, "Loading SSDT Table GUID: %g\n", SsdtTableGuid));
///
/// Locate FV protocol.
///
Status = gBS->LocateHandleBuffer (
ByProtocol,
&gEfiFirmwareVolume2ProtocolGuid,
NULL,
&NumberOfHandles,
&HandleBuffer
);
ASSERT_EFI_ERROR (Status);
///
/// Look 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 **) &FwVol
);
ASSERT_EFI_ERROR (Status);
if (FwVol == NULL) {
return EFI_NOT_FOUND;
}
///
/// See if it has the ACPI storage file
///
Size = 0;
FvStatus = 0;
Status = FwVol->ReadFile (
FwVol,
&SsdtTableGuid,
NULL,
&Size,
&FileType,
&Attributes,
&FvStatus
);
///
/// If we found it, then we are done
///
if (!EFI_ERROR (Status)) {
break;
}
}
///
/// Our exit status is determined by the success of the previous operations
/// If the protocol was found, Instance already points to it.
///
///
/// Free any allocated buffers
///
FreePool (HandleBuffer);
///
/// Sanity check that we found our data file
///
ASSERT (FwVol);
///
/// Locate ACPI tables
///
Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable);
///
/// Read tables from the storage file.
///
if (FwVol == NULL) {
ASSERT_EFI_ERROR (EFI_NOT_FOUND);
return EFI_NOT_FOUND;
}
Instance = 0;
while (Status == EFI_SUCCESS) {
///
/// Read the ACPI tables
///
Status = FwVol->ReadSection (
FwVol,
&SsdtTableGuid,
EFI_SECTION_RAW,
Instance,
(VOID **) &Table,
&Size,
&FvStatus
);
if (!EFI_ERROR (Status)) {
///
/// check and load SwitchableGraphics SSDT table
///
LoadTable = FALSE;
TableHeader = (EFI_ACPI_DESCRIPTION_HEADER *) Table;
if (((EFI_ACPI_DESCRIPTION_HEADER *) TableHeader)->OemTableId == Signature) {
///
/// This is the SSDT table that match the Signature
///
DEBUG ((DEBUG_INFO, "Found out SSDT Table GUID: %g\n", SsdtTableGuid));
LoadTable = TRUE;
}
///
/// Add the table
///
if (LoadTable) {
TableHandle = 0;
Status = AcpiTable->InstallAcpiTable (
AcpiTable,
TableHeader,
TableHeader->Length,
&TableHandle
);
}
///
/// Increment the instance
///
Instance++;
Table = NULL;
}
}
return EFI_SUCCESS;
}
/**
This function gets registered as a callback to perform Dmar Igd
@param[in] Event - A pointer to the Event that triggered the callback.
@param[in] Context - A pointer to private data registered with the callback function.
**/
VOID
EFIAPI
SaAcpiEndOfDxeCallback (
IN EFI_EVENT Event,
IN VOID *Context
)
{
EFI_STATUS Status;
if (PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS (SA_SEG_NUM, SA_MC_BUS, 2, 0, R_SA_IGD_VID)) != 0xFFFF) {
Status = PostPmInitEndOfDxe ();
if (EFI_SUCCESS != Status) {
DEBUG ((DEBUG_WARN, "[SA] EndOfDxe GraphicsInit Error, Status = %r \n", Status));
ASSERT_EFI_ERROR (Status);
}
}
if (PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS (SA_SEG_NUM, SA_MC_BUS, 2, 0, R_SA_IGD_VID)) != 0xFFFF) {
Status = GetVBiosVbtEndOfDxe ();
if (EFI_SUCCESS != Status) {
DEBUG ((DEBUG_WARN, "[SA] EndOfDxe Op Region Error, Status = %r \n", Status));
}
Status = UpdateIgdOpRegionEndOfDxe ();
if (EFI_SUCCESS != Status) {
DEBUG ((DEBUG_WARN, "[SA] EndOfDxe Update Op Region Error, Status = %r \n", Status));
}
}
return;
}
/**
SystemAgent Acpi Initialization.
@param[in] ImageHandle Handle for the image of this driver
@retval EFI_SUCCESS The function completed successfully
@retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
**/
EFI_STATUS
EFIAPI
SaAcpiInit (
IN EFI_HANDLE ImageHandle
)
{
EFI_STATUS Status;
EFI_CPUID_REGISTER CpuidRegs;
CPU_FAMILY CpuFamilyId;
EFI_EVENT EndOfDxeEvent;
CpuFamilyId = GetCpuFamily();
AsmCpuid (1, &CpuidRegs.RegEax, 0, 0, 0);
///
/// Get the platform setup policy.
///
Status = gBS->LocateProtocol (&gSaPolicyProtocolGuid, NULL, (VOID **) &mSaPolicy);
ASSERT_EFI_ERROR (Status);
///
/// Install System Agent Global NVS protocol
///
DEBUG ((DEBUG_INFO, "Install SA GNVS protocol\n"));
Status = (gBS->AllocatePool) (EfiACPIMemoryNVS, sizeof (SYSTEM_AGENT_NVS_AREA), (VOID **) &mSaNvsAreaProtocol.Area);
ASSERT_EFI_ERROR (Status);
ZeroMem ((VOID *) mSaNvsAreaProtocol.Area, sizeof (SYSTEM_AGENT_NVS_AREA));
mSaNvsAreaProtocol.Area->XPcieCfgBaseAddress = (UINT32) (PcdGet64 (PcdPciExpressBaseAddress));
mSaNvsAreaProtocol.Area->CpuIdInfo = CpuidRegs.RegEax;
if (mSaConfigHob != NULL) {
mSaNvsAreaProtocol.Area->IpuAcpiMode = mSaConfigHob->IpuAcpiMode;
}
Status = gBS->InstallMultipleProtocolInterfaces (
&ImageHandle,
&gSaNvsAreaProtocolGuid,
&mSaNvsAreaProtocol,
NULL
);
ASSERT_EFI_ERROR (Status);
///
/// PciExpress Dxe Initialization
///
DEBUG ((DEBUG_INFO, "Initializing PciExpress (Dxe)\n"));
PciExpressInit (mSaPolicy);
///
/// GtPostInit Initialization
///
DEBUG ((DEBUG_INFO, "Initializing GT ACPI tables\n"));
GraphicsInit (ImageHandle, mSaPolicy);
/// Vtd Initialization
///
DEBUG ((DEBUG_INFO, "Initializing VT-d ACPI tables\n"));
VtdInit (mSaPolicy);
///
/// IgdOpRegion Install Initialization
///
DEBUG ((DEBUG_INFO, "Initializing IGD OpRegion\n"));
IgdOpRegionInit ();
///
/// Register an end of DXE event for SA ACPI to do tasks before invoking any UEFI drivers,
/// applications, or connecting consoles,...
///
Status = gBS->CreateEventEx (
EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
SaAcpiEndOfDxeCallback,
NULL,
&gEfiEndOfDxeEventGroupGuid,
&EndOfDxeEvent
);
///
/// Install System Agent Global NVS ACPI table
///
Status = InitializeSaSsdtAcpiTables ();
///
/// Install PEG SSDT table only if PEG port is present
///
if (IsPchLinkDmi (CpuFamilyId)) {
if (PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS (SA_SEG_NUM, SA_PEG_BUS_NUM, SA_PEG_DEV_NUM, SA_PEG0_FUN_NUM, R_SA_PEG_DID_OFFSET)) != V_SA_DEVICE_ID_INVALID) {
Status = InstallSsdtAcpiTable (gPegSsdtAcpiTableStorageGuid, SIGNATURE_64 ('P','e','g','S','s','d','t',0));
ASSERT_EFI_ERROR (Status);
}
}
return EFI_SUCCESS;
}