KabyLake/KabylakeFspPkg/FspInit/Pei/FspInitPreMem.c
2019-11-19 16:10:28 +08:00

635 lines
18 KiB
C

/** @file
Source code file for FSP Init Pre-Memory PEI module
@copyright
INTEL CONFIDENTIAL
Copyright 2012 - 2017 Intel Corporation.
The source code contained or described herein and all documents related to the
source code ("Material") are owned by Intel Corporation or its suppliers or
licensors. Title to the Material remains with Intel Corporation or its suppliers
and licensors. The Material may contain trade secrets and proprietary and
confidential information of Intel Corporation and its suppliers and licensors,
and is protected by worldwide copyright and trade secret laws and treaty
provisions. No part of the Material may be used, copied, reproduced, modified,
published, uploaded, posted, transmitted, distributed, or disclosed in any way
without Intel's prior express written permission.
No license under any patent, copyright, trade secret or other intellectual
property right is granted to or conferred upon you by disclosure or delivery
of the Materials, either expressly, by implication, inducement, estoppel or
otherwise. Any license under such intellectual property rights must be
express and approved by Intel in writing.
Unless otherwise agreed by Intel in writing, you may not remove or alter
this notice or any other notice embedded in Materials by Intel or
Intel's suppliers or licensors in any way.
This file contains an 'Intel Peripheral Driver' and is uniquely identified as
"Intel Reference Module" and is licensed for Intel CPUs and chipsets under
the terms of your license agreement with Intel or your vendor. This file may
be modified by the user, subject to additional terms of the license agreement.
@par Specification
**/
#include <FspInitPreMem.h>
#include <Register/Cpuid.h>
#include <Register/Msr.h>
#include <CpuRegs.h>
#include <Library/PostCodeLib.h>
#include <Library/FspCommonLib.h>
#include <Library/PerformanceLib.h>
#include <Library/MemoryAllocationLib.h>
extern EFI_GUID gFspSiliconFvGuid;
extern EFI_GUID gFspPerformanceDataGuid;
EFI_PEI_RESET_PPI mResetPpi = {
ResetSystem
};
static EFI_PEI_PPI_DESCRIPTOR mPreMemPpiList[] = {
{
(EFI_PEI_PPI_DESCRIPTOR_PPI| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
&gEfiPeiResetPpiGuid,
&mResetPpi
}
};
GLOBAL_REMOVE_IF_UNREFERENCED EFI_PEI_PPI_DESCRIPTOR mPpiBootMode = {
(EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
&gEfiPeiMasterBootModePpiGuid,
NULL
};
EFI_PEI_NOTIFY_DESCRIPTOR mMemoryDiscoveredNotifyList = {
(EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
&gEfiPeiMemoryDiscoveredPpiGuid,
MemoryDiscoveredPpiNotifyCallback
};
/**
This function reset the entire platform, including all processor and devices, and
reboots the system.
@param PeiServices General purpose services available to every PEIM.
@retval EFI_SUCCESS if it completed successfully.
**/
EFI_STATUS
EFIAPI
ResetSystem (
IN CONST EFI_PEI_SERVICES **PeiServices
)
{
IoWrite8 (0xCF9, 0x06);
CpuDeadLoop ();
return EFI_SUCCESS;
}
/**
This function retrieves the top of usable low memory.
@param HobListPtr A HOB list pointer.
@retval Usable low memory top.
**/
UINT32
GetUsableLowMemTop (
CONST VOID *HobStart
)
{
EFI_PEI_HOB_POINTERS Hob;
UINT32 MemLen;
/*
* Get the HOB list for processing
*/
Hob.Raw = (VOID *)HobStart;
/*
* Collect memory ranges
*/
MemLen = 0x100000;
while (!END_OF_HOB_LIST (Hob)) {
if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
if (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) {
/*
* Need memory above 1MB to be collected here
*/
if (Hob.ResourceDescriptor->PhysicalStart >= 0x100000 &&
Hob.ResourceDescriptor->PhysicalStart < (EFI_PHYSICAL_ADDRESS) 0x100000000) {
MemLen += (UINT32) (Hob.ResourceDescriptor->ResourceLength);
}
}
}
Hob.Raw = GET_NEXT_HOB (Hob);
}
return MemLen;
}
/**
This function determines if any MTRRs have been programmed.
@retval TRUE if any MTRRs have been programmed.
@retval FALSE if no MTRRs have been programmed.
**/
BOOLEAN
CheckIfMtrrsProgrammed()
{
static UINT32 FixedMtrrs[] = {
MSR_IA32_MTRR_FIX64K_00000,
MSR_IA32_MTRR_FIX16K_80000,
MSR_IA32_MTRR_FIX16K_A0000,
MSR_IA32_MTRR_FIX4K_C0000,
MSR_IA32_MTRR_FIX4K_C8000,
MSR_IA32_MTRR_FIX4K_D0000,
MSR_IA32_MTRR_FIX4K_D8000,
MSR_IA32_MTRR_FIX4K_E0000,
MSR_IA32_MTRR_FIX4K_E8000,
MSR_IA32_MTRR_FIX4K_F0000,
MSR_IA32_MTRR_FIX4K_F8000
};
MSR_IA32_MTRRCAP_REGISTER Msr;
UINT32 Index;
UINT32 Mtrr;
for (Index = 0; Index < sizeof(FixedMtrrs) / sizeof(UINT32); ++Index) {
if (AsmReadMsr64(FixedMtrrs[Index]) != 0) return TRUE;
}
Msr.Uint64 = AsmReadMsr64(MSR_IA32_MTRRCAP);
for (Index = 0; Index < Msr.Bits.VCNT * 2; ++Index) {
Mtrr = MSR_IA32_MTRR_PHYSBASE0 + Index;
if (AsmReadMsr64(Mtrr) != 0) return TRUE;
}
return FALSE;
}
/**
This function prints MTRRs.
**/
VOID
PrintMtrrs (
VOID
)
{
DEBUG_CODE_BEGIN();
typedef struct {
char *Desc;
UINT32 Msr;
} MTRR_INFO;
MSR_IA32_MTRRCAP_REGISTER Msr;
UINT32 Index;
UINT32 Mtrr;
static MTRR_INFO MtrrInfo[] = {
{"MSR_IA32_MTRR_FIX64K_00000", MSR_IA32_MTRR_FIX64K_00000},
{"MSR_IA32_MTRR_FIX16K_80000", MSR_IA32_MTRR_FIX16K_80000},
{"MSR_IA32_MTRR_FIX16K_A0000", MSR_IA32_MTRR_FIX16K_A0000},
{"MSR_IA32_MTRR_FIX4K_C0000 ", MSR_IA32_MTRR_FIX4K_C0000},
{"MSR_IA32_MTRR_FIX4K_C8000 ", MSR_IA32_MTRR_FIX4K_C8000},
{"MSR_IA32_MTRR_FIX4K_D0000 ", MSR_IA32_MTRR_FIX4K_D0000},
{"MSR_IA32_MTRR_FIX4K_D8000 ", MSR_IA32_MTRR_FIX4K_D8000},
{"MSR_IA32_MTRR_FIX4K_E0000 ", MSR_IA32_MTRR_FIX4K_E0000},
{"MSR_IA32_MTRR_FIX4K_E8000 ", MSR_IA32_MTRR_FIX4K_E8000},
{"MSR_IA32_MTRR_FIX4K_F0000 ", MSR_IA32_MTRR_FIX4K_F0000},
{"MSR_IA32_MTRR_FIX4K_F8000 ", MSR_IA32_MTRR_FIX4K_F8000}
};
for (Index = 0; Index < sizeof(MtrrInfo) / sizeof(MTRR_INFO); ++Index) {
DEBUG ((DEBUG_INFO | DEBUG_INIT, "%a Msr %x = %016llx\n", MtrrInfo[Index].Desc, MtrrInfo[Index].Msr, AsmReadMsr64(MtrrInfo[Index].Msr)));
}
Msr.Uint64 = AsmReadMsr64(MSR_IA32_MTRRCAP);
for (Index = 0; Index < Msr.Bits.VCNT; ++Index) {
Mtrr = MSR_IA32_MTRR_PHYSBASE0 + (2 * Index);
DEBUG ((DEBUG_INFO | DEBUG_INIT, "MSR_IA32_MTRR_PHYSBASE%d Msr %x = %016llx\n",
Index, Mtrr, AsmReadMsr64(Mtrr)
));
DEBUG ((DEBUG_INFO | DEBUG_INIT, "MSR_IA32_MTRR_PHYSMASK%d Msr %x = %016llx\n",
Index, Mtrr + 1, AsmReadMsr64(Mtrr + 1)
));
}
DEBUG_CODE_END();
}
/**
This function programs Cache Attributes.
**/
VOID ProgramCacheAttributes (
VOID
)
{
UINT64 LowMemoryLength;
UINT64 HighMemoryLength;
UINT64 MaxLowMemoryLength;
FSP_GLOBAL_DATA *FspData;
MTRR_SETTINGS MtrrSetting;
EFI_STATUS Status;
///
/// Reset all MTRR setting.
///
ZeroMem (&MtrrSetting, sizeof (MTRR_SETTINGS));
//
// Disable Cache as RAM
//
DisableCacheAsRam (TRUE);
///
/// Cache the Flash area as WP to boost performance
/// Set WP cache size to fixed at 16MB for saving MTRR usage.
///
Status = MtrrSetMemoryAttributeInMtrrSettings (
&MtrrSetting,
0xff000000,
0x01000000,
CacheWriteProtected
);
ASSERT_EFI_ERROR (Status);
MtrrSetAllMtrrs (&MtrrSetting);
//
// Get system memory from HOB
//
FspGetSystemMemorySize (&LowMemoryLength, &HighMemoryLength);
FspData = GetFspGlobalDataPointer ();
DEBUG ((DEBUG_INFO | DEBUG_INIT, "MicrocodeRegionBase : 0x%08x\n", FspData->PlatformData.MicrocodeRegionBase));
DEBUG ((DEBUG_INFO | DEBUG_INIT, "MicrocodeRegionSize : 0x%08x\n", FspData->PlatformData.MicrocodeRegionSize));
DEBUG ((DEBUG_INFO | DEBUG_INIT, "CodeRegionBase : 0x%08x\n", FspData->PlatformData.CodeRegionBase));
DEBUG ((DEBUG_INFO | DEBUG_INIT, "CodeRegionSize : 0x%08x\n", FspData->PlatformData.CodeRegionSize));
DEBUG ((DEBUG_INFO, "[FSP] Memory Length (Below 4GB) = %lx.\n", LowMemoryLength));
DEBUG ((DEBUG_INFO, "[FSP] Memory Length (Above 4GB) = %lx.\n", HighMemoryLength));
//
// Set fixed MTRR values
//
Status = MtrrSetMemoryAttributeInMtrrSettings (
&MtrrSetting,
0x00000,
0xA0000,
CacheWriteBack
);
ASSERT_EFI_ERROR (Status);
Status = MtrrSetMemoryAttributeInMtrrSettings (
&MtrrSetting,
0xA0000,
0x20000,
CacheUncacheable
);
ASSERT_EFI_ERROR (Status);
Status = MtrrSetMemoryAttributeInMtrrSettings (
&MtrrSetting,
0xC0000,
0x40000,
CacheWriteBack
);
ASSERT_EFI_ERROR (Status);
//
// Set the largest range as WB and then patch smaller ranges with UC
// It can reduce the MTRR register usage
//
MaxLowMemoryLength = GetPowerOfTwo64 (LowMemoryLength);
if (LowMemoryLength != MaxLowMemoryLength) {
MaxLowMemoryLength = LShiftU64 (MaxLowMemoryLength, 1);
}
if (MaxLowMemoryLength >= 0x100000000ULL) {
MaxLowMemoryLength = (LowMemoryLength + 0x0FFFFFFF) & 0xF0000000;
}
Status = MtrrSetMemoryAttributeInMtrrSettings (
&MtrrSetting,
0x100000,
MaxLowMemoryLength - 0x100000,
CacheWriteBack
);
ASSERT_EFI_ERROR (Status);
if (LowMemoryLength != MaxLowMemoryLength) {
Status = MtrrSetMemoryAttributeInMtrrSettings (
&MtrrSetting,
LowMemoryLength,
MaxLowMemoryLength - LowMemoryLength,
CacheUncacheable
);
ASSERT_EFI_ERROR (Status);
}
if (HighMemoryLength) {
Status = MtrrSetMemoryAttributeInMtrrSettings (
&MtrrSetting,
0x100000000,
HighMemoryLength,
CacheWriteBack
);
}
///
/// Update MTRR setting from MTRR buffer
///
MtrrSetAllMtrrs (&MtrrSetting);
}
/**
Migrate FSP-M UPD data before destroying CAR.
**/
VOID
EFIAPI
MigrateFspmUpdData (
VOID
)
{
FSP_INFO_HEADER *FspInfoHeaderPtr;
VOID *FspmUpdPtrPostMem;
VOID *FspmUpdPtrPreMem;
FspInfoHeaderPtr = GetFspInfoHeader();
FspmUpdPtrPostMem = (VOID *)AllocatePages (EFI_SIZE_TO_PAGES ((UINTN)FspInfoHeaderPtr->CfgRegionSize));
ASSERT(FspmUpdPtrPostMem != NULL);
FspmUpdPtrPreMem = (VOID *)GetFspMemoryInitUpdDataPointer ();
CopyMem (FspmUpdPtrPostMem, (VOID *)FspmUpdPtrPreMem, (UINTN)FspInfoHeaderPtr->CfgRegionSize);
//
// Update FSP-M UPD pointer in FSP Global Data
//
SetFspMemoryInitUpdDataPointer((VOID *)FspmUpdPtrPostMem);
DEBUG ((DEBUG_INFO, "Migrate FSP-M UPD from %x to %x \n", FspmUpdPtrPreMem, FspmUpdPtrPostMem));
}
/**
This function reports and installs new FV
@retval EFI_SUCCESS The function completes successfully
**/
EFI_STATUS
ReportAndInstallNewFv (
VOID
)
{
EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExtHeader;
FSP_INFO_HEADER *FspInfoHeader;
EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
UINT8 *CurPtr;
UINT8 *EndPtr;
FspInfoHeader = GetFspInfoHeaderFromApiContext();
if (FspInfoHeader->Signature != FSP_INFO_HEADER_SIGNATURE) {
DEBUG ((DEBUG_ERROR, "The signature of FspInfoHeader getting from API context is invalid.\n"));
FspInfoHeader = GetFspInfoHeader();
}
CurPtr = (UINT8 *)FspInfoHeader->ImageBase;
EndPtr = CurPtr + FspInfoHeader->ImageSize - 1;
while (CurPtr < EndPtr) {
FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)CurPtr;
if (FvHeader->Signature != EFI_FVH_SIGNATURE) {
break;
}
if (FvHeader->ExtHeaderOffset != 0) {
//
// Searching for the silicon FV in the FSP image.
//
FwVolExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *) ((UINT8 *) FvHeader + FvHeader->ExtHeaderOffset);
if (CompareGuid(&FwVolExtHeader->FvName, &gFspSiliconFvGuid)) {
PeiServicesInstallFvInfoPpi (
NULL,
(VOID *)FvHeader,
(UINTN) FvHeader->FvLength,
NULL,
NULL
);
}
}
CurPtr += FvHeader->FvLength;
}
return EFI_SUCCESS;
}
/**
This function will be called when MRC is done.
@param PeiServices General purpose services available to every PEIM.
@param NotifyDescriptor Information about the notify event..
@param Ppi The notify context.
@retval EFI_SUCCESS If the function completed successfully.
**/
EFI_STATUS
EFIAPI
MemoryDiscoveredPpiNotifyCallback (
IN EFI_PEI_SERVICES **PeiServices,
IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
IN VOID *Ppi
)
{
UINT8 PhysicalAddressBits;
CPUID_VIR_PHY_ADDRESS_SIZE_EAX Eax;
VOID **HobListPtr;
DEBUG ((DEBUG_INFO | DEBUG_INIT, "Memory Discovered Notify invoked ...\n"));
AsmCpuid (CPUID_EXTENDED_FUNCTION, &Eax.Uint32, NULL, NULL, NULL);
if (Eax.Uint32 >= CPUID_VIR_PHY_ADDRESS_SIZE) {
AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE, &Eax.Uint32, NULL, NULL, NULL);
PhysicalAddressBits = (UINT8) Eax.Bits.PhysicalAddressBits;
} else {
PhysicalAddressBits = 36;
}
///
/// Create a CPU hand-off information
///
BuildCpuHob (PhysicalAddressBits, 16);
//
// Create a memory allocation HOB at fixed location.
//
BuildMemoryAllocationHob (
PcdGet32 (PcdFspCpuPeiApWakeupBufferAddr),
EFI_PAGE_SIZE,
EfiBootServicesData
);
//
// Migrate FSP-M UPD data before destroying CAR
//
MigrateFspmUpdData ();
//
// Calling use FspMemoryInit API
// Return the control directly
//
HobListPtr = (VOID **)GetFspApiParameter2 ();
//FSP Common Module(0x800) | Api Exit(0x7F)
PostCode (0x87F);
//
// This is the end of the FspMemoryInit API
// Give control back to the boot loader
//
FspMemoryInitDone (HobListPtr);
if (GetFspApiCallingIndex () == TempRamExitApiIndex) {
//TempRamExit Api Entry PostCode
//FSP Common Module(0x800) | Api Entry(0x00)
PostCode (0x800);
// AMI_OVERRIDE_START, Check BootMode is changed or not in capsule update.
{
EFI_STATUS Status;
EFI_BOOT_MODE BootMode;
Status = PeiServicesGetBootMode (&BootMode);
ASSERT_EFI_ERROR (Status);
DEBUG ((DEBUG_INFO, "Fsp TempRamExitApi BootMode: %x\n", BootMode));
}
// AMI_OVERRIDE_START
//
// Program MTRR values.
//
ProgramCacheAttributes ();
DEBUG ((DEBUG_INFO | DEBUG_INIT, "MTRR programming:\n"));
PrintMtrrs ();
//
// This is the end of the TempRamExit API
// Give control back to the boot loader
//
FspTempRamExitDone ();
}
//FSP Common Module(0x800) | Api Entry(0x00)
PostCode (0x800);
// MTRRs are not already programmed in FSP flow 1.1.
//
if (!CheckIfMtrrsProgrammed ()) {
ProgramCacheAttributes ();
DEBUG ((DEBUG_INFO | DEBUG_INIT, "MTRR programming:\n"));
PrintMtrrs ();
}
//
// Install FSP silicon FV
//
ReportAndInstallNewFv ();
DEBUG ((DEBUG_INFO | DEBUG_INIT, "Memory Discovered Notify completed ...\n"));
return EFI_SUCCESS;
}
/**
FSP 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
FspInitPreMemEntryPoint (
IN EFI_PEI_FILE_HANDLE FileHandle,
IN CONST EFI_PEI_SERVICES **PeiServices
)
{
EFI_STATUS Status;
SI_PREMEM_POLICY_PPI *SiPreMemPolicyPpi;
EFI_BOOT_MODE BootMode;
FSPM_UPD *FspmUpdDataPtr;
DEBUG ((DEBUG_INFO, "FspInitPreMemEntryPoint\n"));
//MemoryInit Phase Postcode set
SetPhaseStatusCode (0xD000);
//MemoryInit API Entry PostCode
//FSP Common Module(0x800) | Api Entry(0x00)
PostCode (0x800);
FspmUpdDataPtr = NULL;
///
/// Install Pre Memory PPIs
///
Status = PeiServicesInstallPpi (&mPreMemPpiList[0]);
ASSERT_EFI_ERROR (Status);
//
// Get the UPD pointer.
//
FspmUpdDataPtr = (FSPM_UPD *) GetFspMemoryInitUpdDataPointer ();
SetFspSiliconInitUpdDataPointer ((void *)NULL);
DEBUG_CODE_BEGIN ();
UINT32 Index;
DEBUG ((DEBUG_INFO, "Dumping FSPM_UPD - Size: 0x%8X", sizeof(FSPM_UPD)));
for (Index = 0; Index < sizeof (FSPM_UPD); ++Index) {
if (Index % 0x10 == 0) {
DEBUG ((DEBUG_INFO, "\n0x%8X:", Index));
}
DEBUG ((DEBUG_INFO, " 0x%02X", *(((UINT8 *)FspmUpdDataPtr) + Index)));
}
DEBUG ((DEBUG_INFO, "\n"));
DEBUG_CODE_END ();
//
// Get the Boot Mode
//
BootMode = FspmUpdDataPtr->FspmArchUpd.BootMode;
PeiServicesSetBootMode (BootMode);
Status = PeiServicesInstallPpi (&mPpiBootMode);
Status = SiCreatePreMemConfigBlocks (&SiPreMemPolicyPpi);
FspUpdatePeiPchPolicyPreMem (SiPreMemPolicyPpi, FspmUpdDataPtr);
FspUpdatePeiCpuPolicyPreMem (SiPreMemPolicyPpi, FspmUpdDataPtr);
FspUpdatePeiSecurityPolicyPreMem (SiPreMemPolicyPpi, FspmUpdDataPtr);//Security Policy also needs to be updated before CpuInstallPolicyPpi
FspUpdatePeiMePolicyPreMem (SiPreMemPolicyPpi, FspmUpdDataPtr);
FspUpdatePeiSaPolicyPreMem (SiPreMemPolicyPpi, FspmUpdDataPtr);
FspUpdatePeiSiPolicyPreMem (SiPreMemPolicyPpi, FspmUpdDataPtr);
Status = SiPreMemInstallPolicyPpi(SiPreMemPolicyPpi);
///
/// Now that all of the pre-permament memory activities have
/// been taken care of, post a call-back for the permament-memory
/// resident services, such as HOB construction.
/// PEI Core will switch stack after this PEIM exit. After that the MTRR
/// can be set.
///
Status = PeiServicesNotifyPpi (&mMemoryDiscoveredNotifyList);
ASSERT_EFI_ERROR (Status);
DEBUG ((DEBUG_INFO, "FspInitPreMemEntryPoint done\n"));
return Status;
}