/** @file
Source code file for Platform Init Pre-Memory PEI module
Copyright (c) 2017 - 2020, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
EFI_STATUS
EFIAPI
MemoryDiscoveredPpiNotifyCallback (
IN CONST EFI_PEI_SERVICES **PeiServices,
IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
IN VOID *Ppi
);
EFI_STATUS
EFIAPI
GetPlatformMemorySize (
IN EFI_PEI_SERVICES **PeiServices,
IN PEI_PLATFORM_MEMORY_SIZE_PPI *This,
IN OUT UINT64 *MemorySize
);
/**
This function checks the memory range in PEI.
@param PeiServices Pointer to PEI Services.
@param This Pei memory test PPI pointer.
@param BeginAddress Beginning of the memory address to be checked.
@param MemoryLength Bytes of memory range to be checked.
@param Operation Type of memory check operation to be performed.
@param ErrorAddress Return the address of the error memory address.
@retval EFI_SUCCESS The operation completed successfully.
@retval EFI_DEVICE_ERROR Memory test failed. It's not safe to use this range of memory.
**/
EFI_STATUS
EFIAPI
BaseMemoryTest (
IN EFI_PEI_SERVICES **PeiServices,
IN PEI_BASE_MEMORY_TEST_PPI *This,
IN EFI_PHYSICAL_ADDRESS BeginAddress,
IN UINT64 MemoryLength,
IN PEI_MEMORY_TEST_OP Operation,
OUT EFI_PHYSICAL_ADDRESS *ErrorAddress
);
/**
A hook for platform-specific initialization prior to disabling temporary RAM.
@retval EFI_SUCCESS The platform initialization was successful.
@retval EFI_NOT_READY The platform has not been detected yet.
**/
EFI_STATUS
EFIAPI
PlatformInitBeforeTempRamExit (
VOID
);
/**
A hook for platform-specific initialization after disabling temporary RAM.
@retval EFI_SUCCESS The platform initialization was successful.
@retval EFI_NOT_READY The platform has not been detected yet.
**/
EFI_STATUS
EFIAPI
PlatformInitAfterTempRamExit (
VOID
);
GLOBAL_REMOVE_IF_UNREFERENCED EFI_PEI_NOTIFY_DESCRIPTOR mMemDiscoveredNotifyList = {
(EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
&gEfiPeiMemoryDiscoveredPpiGuid,
(EFI_PEIM_NOTIFY_ENTRY_POINT) MemoryDiscoveredPpiNotifyCallback
};
GLOBAL_REMOVE_IF_UNREFERENCED EFI_PEI_PPI_DESCRIPTOR mPpiListRecoveryBootMode = {
(EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
&gEfiPeiBootInRecoveryModePpiGuid,
NULL
};
GLOBAL_REMOVE_IF_UNREFERENCED EFI_PEI_PPI_DESCRIPTOR mPpiBootMode = {
(EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
&gEfiPeiMasterBootModePpiGuid,
NULL
};
GLOBAL_REMOVE_IF_UNREFERENCED PEI_BASE_MEMORY_TEST_PPI mPeiBaseMemoryTestPpi = { BaseMemoryTest };
GLOBAL_REMOVE_IF_UNREFERENCED PEI_PLATFORM_MEMORY_SIZE_PPI mMemoryMemorySizePpi = { GetPlatformMemorySize };
GLOBAL_REMOVE_IF_UNREFERENCED EFI_PEI_PPI_DESCRIPTOR mMemPpiList[] = {
{
EFI_PEI_PPI_DESCRIPTOR_PPI,
&gPeiBaseMemoryTestPpiGuid,
&mPeiBaseMemoryTestPpi
},
{
(EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
&gPeiPlatformMemorySizePpiGuid,
&mMemoryMemorySizePpi
},
};
GLOBAL_REMOVE_IF_UNREFERENCED PLATFORM_INIT_TEMP_RAM_EXIT_PPI mPlatformInitTempRamExitPpi = {
PlatformInitBeforeTempRamExit,
PlatformInitAfterTempRamExit
};
GLOBAL_REMOVE_IF_UNREFERENCED EFI_PEI_PPI_DESCRIPTOR mPlatformInitTempRamExitPpiDesc = {
(EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
&gPlatformInitTempRamExitPpiGuid,
&mPlatformInitTempRamExitPpi
};
///
/// Memory Reserved should be between 125% to 150% of the Current required memory
/// otherwise BdsMisc.c would do a reset to make it 125% to avoid s4 resume issues.
///
GLOBAL_REMOVE_IF_UNREFERENCED EFI_MEMORY_TYPE_INFORMATION mDefaultMemoryTypeInformation[] = {
{ EfiACPIReclaimMemory, FixedPcdGet32 (PcdPlatformEfiAcpiReclaimMemorySize) }, // ASL
{ EfiACPIMemoryNVS, FixedPcdGet32 (PcdPlatformEfiAcpiNvsMemorySize) }, // ACPI NVS (including S3 related)
{ EfiReservedMemoryType, FixedPcdGet32 (PcdPlatformEfiReservedMemorySize) }, // BIOS Reserved (including S3 related)
{ EfiRuntimeServicesData, FixedPcdGet32 (PcdPlatformEfiRtDataMemorySize) }, // Runtime Service Data
{ EfiRuntimeServicesCode, FixedPcdGet32 (PcdPlatformEfiRtCodeMemorySize) }, // Runtime Service Code
{ EfiMaxMemoryType, 0 }
};
VOID
BuildMemoryTypeInformation (
VOID
)
{
EFI_STATUS Status;
EFI_PEI_READ_ONLY_VARIABLE2_PPI *VariableServices;
UINTN DataSize;
EFI_MEMORY_TYPE_INFORMATION MemoryData[EfiMaxMemoryType + 1];
//
// Locate system configuration variable
//
Status = PeiServicesLocatePpi(
&gEfiPeiReadOnlyVariable2PpiGuid, // GUID
0, // INSTANCE
NULL, // EFI_PEI_PPI_DESCRIPTOR
(VOID **) &VariableServices // PPI
);
ASSERT_EFI_ERROR(Status);
DataSize = sizeof (MemoryData);
Status = VariableServices->GetVariable (
VariableServices,
EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME,
&gEfiMemoryTypeInformationGuid,
NULL,
&DataSize,
&MemoryData
);
if (EFI_ERROR(Status)) {
DataSize = sizeof (mDefaultMemoryTypeInformation);
CopyMem(MemoryData, mDefaultMemoryTypeInformation, DataSize);
}
///
/// Build the GUID'd HOB for DXE
///
BuildGuidDataHob (
&gEfiMemoryTypeInformationGuid,
MemoryData,
DataSize
);
}
EFI_STATUS
EFIAPI
GetPlatformMemorySize (
IN EFI_PEI_SERVICES **PeiServices,
IN PEI_PLATFORM_MEMORY_SIZE_PPI *This,
IN OUT UINT64 *MemorySize
)
{
EFI_STATUS Status;
EFI_PEI_READ_ONLY_VARIABLE2_PPI *Variable;
UINTN DataSize;
EFI_MEMORY_TYPE_INFORMATION MemoryData[EfiMaxMemoryType + 1];
UINTN Index;
EFI_BOOT_MODE BootMode;
UINTN IndexNumber;
#define PEI_MIN_MEMORY_SIZE (EFI_PHYSICAL_ADDRESS) ((320 * 0x100000))
*MemorySize = PEI_MIN_MEMORY_SIZE;
Status = PeiServicesLocatePpi (
&gEfiPeiReadOnlyVariable2PpiGuid,
0,
NULL,
(VOID **)&Variable
);
ASSERT_EFI_ERROR (Status);
Status = PeiServicesGetBootMode (&BootMode);
ASSERT_EFI_ERROR (Status);
DataSize = sizeof (MemoryData);
Status = Variable->GetVariable (
Variable,
EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME,
&gEfiMemoryTypeInformationGuid,
NULL,
&DataSize,
&MemoryData
);
IndexNumber = sizeof (mDefaultMemoryTypeInformation) / sizeof (EFI_MEMORY_TYPE_INFORMATION);
//
// Accumulate maximum amount of memory needed
//
DEBUG((EFI_D_ERROR, "PEI_MIN_MEMORY_SIZE:%dKB \n", DivU64x32(*MemorySize,1024)));
DEBUG((EFI_D_ERROR, "IndexNumber:%d MemoryDataNumber%d \n", IndexNumber,DataSize/ sizeof (EFI_MEMORY_TYPE_INFORMATION)));
if (EFI_ERROR (Status)) {
//
// Start with minimum memory
//
for (Index = 0; Index < IndexNumber; Index++) {
DEBUG((EFI_D_ERROR, "Index[%d].Type = %d .NumberOfPages=0x%x\n", Index,mDefaultMemoryTypeInformation[Index].Type,mDefaultMemoryTypeInformation[Index].NumberOfPages));
*MemorySize += mDefaultMemoryTypeInformation[Index].NumberOfPages * EFI_PAGE_SIZE;
}
DEBUG((EFI_D_ERROR, "No memory type, Total platform memory:%dKB \n", DivU64x32(*MemorySize,1024)));
} else {
//
// Start with at least 0x200 pages of memory for the DXE Core and the DXE Stack
//
for (Index = 0; Index < IndexNumber; Index++) {
DEBUG((EFI_D_ERROR, "Index[%d].Type = %d .NumberOfPages=0x%x\n", Index,MemoryData[Index].Type,MemoryData[Index].NumberOfPages));
*MemorySize += MemoryData[Index].NumberOfPages * EFI_PAGE_SIZE;
}
DEBUG((EFI_D_ERROR, "has memory type, Total platform memory:%dKB \n", DivU64x32(*MemorySize,1024)));
}
return EFI_SUCCESS;
}
/**
This function checks the memory range in PEI.
@param PeiServices Pointer to PEI Services.
@param This Pei memory test PPI pointer.
@param BeginAddress Beginning of the memory address to be checked.
@param MemoryLength Bytes of memory range to be checked.
@param Operation Type of memory check operation to be performed.
@param ErrorAddress Return the address of the error memory address.
@retval EFI_SUCCESS The operation completed successfully.
@retval EFI_DEVICE_ERROR Memory test failed. It's not safe to use this range of memory.
**/
EFI_STATUS
EFIAPI
BaseMemoryTest (
IN EFI_PEI_SERVICES **PeiServices,
IN PEI_BASE_MEMORY_TEST_PPI *This,
IN EFI_PHYSICAL_ADDRESS BeginAddress,
IN UINT64 MemoryLength,
IN PEI_MEMORY_TEST_OP Operation,
OUT EFI_PHYSICAL_ADDRESS *ErrorAddress
)
{
UINT32 TestPattern;
UINT32 SpanSize;
EFI_PHYSICAL_ADDRESS TempAddress;
#define MEMORY_TEST_PATTERN 0x5A5A5A5A
#define MEMORY_TEST_COVER_SPAN 0x40000
TestPattern = MEMORY_TEST_PATTERN;
SpanSize = 0;
//
// Make sure we don't try and test anything above the max physical address range
//
ASSERT (BeginAddress + MemoryLength < MAX_ADDRESS);
switch (Operation) {
case Extensive:
SpanSize = 0x4;
break;
case Sparse:
case Quick:
SpanSize = MEMORY_TEST_COVER_SPAN;
break;
case Ignore:
goto Done;
break;
}
//
// Write the test pattern into memory range
//
TempAddress = BeginAddress;
while (TempAddress < BeginAddress + MemoryLength) {
(*(UINT32 *) (UINTN) TempAddress) = TestPattern;
TempAddress += SpanSize;
}
//
// Read pattern from memory and compare it
//
TempAddress = BeginAddress;
while (TempAddress < BeginAddress + MemoryLength) {
if ((*(UINT32 *) (UINTN) TempAddress) != TestPattern) {
*ErrorAddress = TempAddress;
return EFI_DEVICE_ERROR;
}
TempAddress += SpanSize;
}
Done:
return EFI_SUCCESS;
}
/**
Install Firmware Volume Hob's once there is main memory
@param[in] PeiServices General purpose services available to every PEIM.
@param[in] NotifyDescriptor Notify that this module published.
@param[in] Ppi PPI that was installed.
@retval EFI_SUCCESS The function completed successfully.
**/
EFI_STATUS
EFIAPI
MemoryDiscoveredPpiNotifyCallback (
IN CONST EFI_PEI_SERVICES **PeiServices,
IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
IN VOID *Ppi
)
{
EFI_STATUS Status;
EFI_BOOT_MODE BootMode;
Status = BoardInitAfterMemoryInit ();
ASSERT_EFI_ERROR (Status);
Status = PeiServicesGetBootMode (&BootMode);
ASSERT_EFI_ERROR (Status);
SetCacheMtrr ();
ReportCpuHob ();
TestPointMemoryDiscoveredMtrrFunctional ();
TestPointMemoryDiscoveredMemoryResourceFunctional ();
///
/// If S3 resume, then we are done
///
if (BootMode == BOOT_ON_S3_RESUME) {
return EFI_SUCCESS;
}
TestPointMemoryDiscoveredDmaProtectionEnabled ();
if (PcdGetBool (PcdStopAfterMemInit)) {
CpuDeadLoop ();
}
return Status;
}
/**
A hook for platform-specific initialization prior to disabling temporary RAM.
@retval EFI_SUCCESS The platform initialization was successful.
@retval EFI_NOT_READY The platform has not been detected yet.
**/
EFI_STATUS
EFIAPI
PlatformInitBeforeTempRamExit (
VOID
)
{
return BoardInitBeforeTempRamExit ();
}
/**
A hook for platform-specific initialization after disabling temporary RAM.
@retval EFI_SUCCESS The platform initialization was successful.
@retval EFI_NOT_READY The platform has not been detected yet.
**/
EFI_STATUS
EFIAPI
PlatformInitAfterTempRamExit (
VOID
)
{
return BoardInitAfterTempRamExit ();
}
/**
This function handles PlatformInit task after PeiReadOnlyVariable2 PPI produced
@param[in] PeiServices Pointer to PEI Services Table.
@retval EFI_SUCCESS The function completes successfully
@retval others
**/
EFI_STATUS
EFIAPI
PlatformInitPreMem (
IN CONST EFI_PEI_SERVICES **PeiServices
)
{
EFI_STATUS Status;
EFI_BOOT_MODE BootMode;
//
// Start board detection
//
BoardDetect ();
BoardDebugInit ();
TestPointDebugInitDone ();
if (PcdGetBool (PcdStopAfterDebugInit)) {
CpuDeadLoop ();
}
BootMode = BoardBootModeDetect ();
Status = PeiServicesSetBootMode (BootMode);
ASSERT_EFI_ERROR (Status);
if (BootMode == BOOT_IN_RECOVERY_MODE) {
Status = PeiServicesInstallPpi (&mPpiListRecoveryBootMode);
}
///
/// Signal possible dependent modules that there has been a
/// final boot mode determination, it is used to build BIST
/// Hob for Dxe use.
///
Status = PeiServicesInstallPpi (&mPpiBootMode);
ASSERT_EFI_ERROR (Status);
BuildMemoryTypeInformation ();
if (!PcdGetBool(PcdFspWrapperBootMode)) {
Status = PeiServicesInstallPpi (mMemPpiList);
ASSERT_EFI_ERROR (Status);
}
Status = BoardInitBeforeMemoryInit ();
ASSERT_EFI_ERROR (Status);
Status = PeiServicesInstallPpi (&mPlatformInitTempRamExitPpiDesc);
ASSERT_EFI_ERROR (Status);
return Status;
}
/**
Platform Init before memory PEI module entry point
@param[in] FileHandle Not used.
@param[in] PeiServices General purpose services available to every PEIM.
@retval EFI_SUCCESS The function completes successfully
@retval EFI_OUT_OF_RESOURCES Insufficient resources to create database
**/
EFI_STATUS
EFIAPI
PlatformInitPreMemEntryPoint (
IN EFI_PEI_FILE_HANDLE FileHandle,
IN CONST EFI_PEI_SERVICES **PeiServices
)
{
EFI_STATUS Status;
Status = PlatformInitPreMem (PeiServices);
///
/// After code reorangized, memorycallback will run because the PPI is already
/// installed when code run to here, it is supposed that the InstallEfiMemory is
/// done before.
///
Status = PeiServicesNotifyPpi (&mMemDiscoveredNotifyList);
return Status;
}