/** @file
This is an implementation of the AcpiVariable platform field for ECP platform.
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
==
typedef struct {
EFI_PHYSICAL_ADDRESS AcpiReservedMemoryBase; <<===
UINT32 AcpiReservedMemorySize; <<===
EFI_PHYSICAL_ADDRESS S3ReservedLowMemoryBase;
EFI_PHYSICAL_ADDRESS AcpiBootScriptTable;
EFI_PHYSICAL_ADDRESS RuntimeScriptTableBase;
EFI_PHYSICAL_ADDRESS AcpiFacsTable;
UINT64 SystemMemoryLength; <<===
ACPI_CPU_DATA_COMPATIBILITY AcpiCpuData;
EFI_PHYSICAL_ADDRESS VideoOpromAddress;
UINT32 VideoOpromSize;
EFI_PHYSICAL_ADDRESS S3DebugBufferAddress;
EFI_PHYSICAL_ADDRESS S3ResumeNvsEntryPoint;
} ACPI_VARIABLE_SET_COMPATIBILITY;
**/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
GLOBAL_REMOVE_IF_UNREFERENCED
ACPI_VARIABLE_SET_COMPATIBILITY *mAcpiVariableSetCompatibility = NULL;
/**
Allocate memory below 4G memory address.
This function allocates memory below 4G memory address.
@param MemoryType Memory type of memory to allocate.
@param Size Size of memory to allocate.
@return Allocated address for output.
**/
VOID*
AllocateMemoryBelow4G (
IN EFI_MEMORY_TYPE MemoryType,
IN UINTN Size
);
/**
Hook point for AcpiVariableThunkPlatform for S3Ready.
**/
VOID
S3ReadyThunkPlatform (
VOID
)
{
EFI_PHYSICAL_ADDRESS AcpiMemoryBase;
UINT32 AcpiMemorySize;
EFI_PEI_HOB_POINTERS Hob;
UINT64 MemoryLength;
DEBUG ((EFI_D_INFO, "S3ReadyThunkPlatform\n"));
if (mAcpiVariableSetCompatibility == NULL) {
return;
}
//
// Allocate ACPI reserved memory under 4G
//
AcpiMemoryBase = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateMemoryBelow4G (EfiReservedMemoryType, PcdGet32 (PcdS3AcpiReservedMemorySize));
ASSERT (AcpiMemoryBase != 0);
AcpiMemorySize = PcdGet32 (PcdS3AcpiReservedMemorySize);
//
// Calculate the system memory length by memory hobs
//
MemoryLength = 0x100000;
Hob.Raw = GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR);
ASSERT (Hob.Raw != NULL);
while ((Hob.Raw != NULL) && (!END_OF_HOB_LIST (Hob))) {
if (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) {
//
// Skip the memory region below 1MB
//
if (Hob.ResourceDescriptor->PhysicalStart >= 0x100000) {
MemoryLength += Hob.ResourceDescriptor->ResourceLength;
}
}
Hob.Raw = GET_NEXT_HOB (Hob);
Hob.Raw = GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, Hob.Raw);
}
mAcpiVariableSetCompatibility->AcpiReservedMemoryBase = AcpiMemoryBase;
mAcpiVariableSetCompatibility->AcpiReservedMemorySize = AcpiMemorySize;
mAcpiVariableSetCompatibility->SystemMemoryLength = MemoryLength;
DEBUG((EFI_D_INFO, "AcpiVariableThunkPlatform: AcpiMemoryBase is 0x%8x\n", mAcpiVariableSetCompatibility->AcpiReservedMemoryBase));
DEBUG((EFI_D_INFO, "AcpiVariableThunkPlatform: AcpiMemorySize is 0x%8x\n", mAcpiVariableSetCompatibility->AcpiReservedMemorySize));
DEBUG((EFI_D_INFO, "AcpiVariableThunkPlatform: SystemMemoryLength is 0x%8x\n", mAcpiVariableSetCompatibility->SystemMemoryLength));
return ;
}
/**
Register callback function upon VariableLockProtocol
to lock ACPI_GLOBAL_VARIABLE variable to avoid malicious code to update it.
@param[in] Event Event whose notification function is being invoked.
@param[in] Context Pointer to the notification function's context.
**/
VOID
EFIAPI
VariableLockAcpiGlobalVariable (
IN EFI_EVENT Event,
IN VOID *Context
)
{
EFI_STATUS Status;
EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;
//
// Mark ACPI_GLOBAL_VARIABLE variable to read-only if the Variable Lock protocol exists
//
Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock);
if (!EFI_ERROR (Status)) {
Status = VariableLock->RequestToLock (VariableLock, ACPI_GLOBAL_VARIABLE, &gEfiAcpiVariableCompatiblityGuid);
ASSERT_EFI_ERROR (Status);
}
}
/**
Hook point for AcpiVariableThunkPlatform for InstallAcpiS3Save.
**/
VOID
InstallAcpiS3SaveThunk (
VOID
)
{
EFI_STATUS Status;
FRAMEWORK_EFI_MP_SERVICES_PROTOCOL *FrameworkMpService;
UINTN VarSize;
VOID *Registration;
Status = gBS->LocateProtocol (
&gFrameworkEfiMpServiceProtocolGuid,
NULL,
(VOID**) &FrameworkMpService
);
if (!EFI_ERROR (Status)) {
//
// On ECP platform, if framework CPU drivers are in use, The compatible version of ACPI variable set
// should be produced by CPU driver.
//
VarSize = sizeof (mAcpiVariableSetCompatibility);
Status = gRT->GetVariable (
ACPI_GLOBAL_VARIABLE,
&gEfiAcpiVariableCompatiblityGuid,
NULL,
&VarSize,
&mAcpiVariableSetCompatibility
);
if (EFI_ERROR (Status) || (VarSize != sizeof (mAcpiVariableSetCompatibility))) {
DEBUG ((EFI_D_ERROR, "FATAL ERROR: AcpiVariableSetCompatibility was not saved by CPU driver correctly. OS S3 may fail!\n"));
mAcpiVariableSetCompatibility = NULL;
}
} else {
//
// Allocate/initialize the compatible version of Acpi Variable Set since Framework chipset/platform
// driver need this variable. ACPI_GLOBAL_VARIABLE variable is not used in runtime phase,
// so RT attribute is not needed for it.
//
mAcpiVariableSetCompatibility = AllocateMemoryBelow4G (EfiACPIMemoryNVS, sizeof(ACPI_VARIABLE_SET_COMPATIBILITY));
Status = gRT->SetVariable (
ACPI_GLOBAL_VARIABLE,
&gEfiAcpiVariableCompatiblityGuid,
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
sizeof(mAcpiVariableSetCompatibility),
&mAcpiVariableSetCompatibility
);
if (!EFI_ERROR (Status)) {
//
// Register callback function upon VariableLockProtocol
// to lock ACPI_GLOBAL_VARIABLE variable to avoid malicious code to update it.
//
EfiCreateProtocolNotifyEvent (
&gEdkiiVariableLockProtocolGuid,
TPL_CALLBACK,
VariableLockAcpiGlobalVariable,
NULL,
&Registration
);
} else {
DEBUG ((EFI_D_ERROR, "FATAL ERROR: AcpiVariableSetCompatibility cannot be saved: %r. OS S3 may fail!\n", Status));
gBS->FreePages (
(EFI_PHYSICAL_ADDRESS) (UINTN) mAcpiVariableSetCompatibility,
EFI_SIZE_TO_PAGES (sizeof (ACPI_VARIABLE_SET_COMPATIBILITY))
);
mAcpiVariableSetCompatibility = NULL;
}
}
DEBUG((EFI_D_INFO, "AcpiVariableSetCompatibility is 0x%8x\n", mAcpiVariableSetCompatibility));
}