/** @file Copyright (c) 2004 - 2019, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent Module Name: MemoryPeim.c Abstract: Tiano PEIM to provide the platform support functionality. This file implements the Platform Memory Range PPI --*/ #include "PlatformEarlyInit.h" // // Need min. of 48MB PEI phase // #define PEI_MIN_MEMORY_SIZE (6 * 0x800000) #define PEI_RECOVERY_MIN_MEMORY_SIZE (6 * 0x800000) // // This is the memory needed for PEI to start up DXE. // // Over-estimating this size will lead to higher fragmentation // of main memory. Under-estimation of this will cause catastrophic // failure of PEI to load DXE. Generally, the failure may only be // realized during capsule updates. // #define PRERESERVED_PEI_MEMORY ( \ EFI_SIZE_TO_PAGES (3 * 0x800000) /* PEI Core memory based stack */ \ ) EFI_MEMORY_TYPE_INFORMATION mDefaultMemoryTypeInformation[] = { { EfiACPIReclaimMemory, 0x40 }, // 0x40 pages = 256k for ASL { EfiACPIMemoryNVS, 0x40 }, // 0x40 pages = 256k MB for S3, SMM, HII, etc { EfiReservedMemoryType, 0x80 }, // 512k for BIOS Reserved { EfiRuntimeServicesCode, 0x100 }, { EfiRuntimeServicesData, 0x100 }, { EfiMaxMemoryType, 0 } }; STATIC EFI_STATUS GetMemorySize ( IN CONST EFI_PEI_SERVICES **PeiServices, OUT UINT64 *LowMemoryLength, OUT UINT64 *HighMemoryLength ); /** Initializes the valid address mask for MTRRs. This function initializes the valid bits mask and valid address mask for MTRRs. **/ UINT64 InitializeAddressMtrrMask ( VOID ) { UINT32 RegEax; UINT8 PhysicalAddressBits; UINT64 ValidMtrrBitsMask; AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL); if (RegEax >= 0x80000008) { AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL); PhysicalAddressBits = (UINT8) RegEax; } else { PhysicalAddressBits = 36; } ValidMtrrBitsMask = LShiftU64 (1, PhysicalAddressBits) - 1; return (ValidMtrrBitsMask & 0xfffffffffffff000ULL); } EFI_STATUS EFIAPI SetPeiCacheMode ( IN CONST EFI_PEI_SERVICES **PeiServices ) { EFI_STATUS Status; PEI_CACHE_PPI *CachePpi; EFI_BOOT_MODE BootMode; UINT64 MemoryLength; UINT64 MemOverflow; UINT64 MemoryLengthUc; UINT64 MaxMemoryLength; UINT64 LowMemoryLength; UINT64 HighMemoryLength; UINT8 Index; MTRR_SETTINGS MtrrSetting; UINT64 ValidMtrrAddressMask; // // Load Cache PPI // Status = (**PeiServices).LocatePpi ( PeiServices, &gPeiCachePpiGuid, // GUID 0, // Instance NULL, // EFI_PEI_PPI_DESCRIPTOR (void **)&CachePpi // PPI ); if (!EFI_ERROR(Status)) { // // Clear the CAR Settings (Default Cache Type => UC) // DEBUG ((EFI_D_INFO, "Reset cache attribute and disable CAR. \n")); CachePpi->ResetCache( (EFI_PEI_SERVICES**)PeiServices, CachePpi ); } // // Variable initialization // LowMemoryLength = 0; HighMemoryLength = 0; MemoryLengthUc = 0; Status = (*PeiServices)->GetBootMode ( PeiServices, &BootMode ); ValidMtrrAddressMask = InitializeAddressMtrrMask (); // // Determine memory usage // GetMemorySize ( PeiServices, &LowMemoryLength, &HighMemoryLength ); LowMemoryLength = (EFI_PHYSICAL_ADDRESS)MmPci32( 0, 0, 2, 0, 0x70); LowMemoryLength &= 0xFFF00000ULL; MaxMemoryLength = LowMemoryLength; // // Round up to nearest 256MB with high memory and 64MB w/o high memory // if (HighMemoryLength != 0 ) { MemOverflow = (LowMemoryLength & 0x0fffffff); if (MemOverflow != 0) { MaxMemoryLength = LowMemoryLength + (0x10000000 - MemOverflow); } } else { MemOverflow = (LowMemoryLength & 0x03ffffff); if (MemOverflow != 0) { MaxMemoryLength = LowMemoryLength + (0x4000000 - MemOverflow); } } ZeroMem (&MtrrSetting, sizeof(MTRR_SETTINGS)); for (Index = 0; Index < 2; Index++) { MtrrSetting.Fixed.Mtrr[Index]=0x0606060606060606; } for (Index = 2; Index < 11; Index++) { MtrrSetting.Fixed.Mtrr[Index]=0x0505050505050505; } // // Cache the flash area to improve the boot performance in PEI phase // Index = 0; ((MSR_IA32_MTRR_PHYSBASE_REGISTER *) &MtrrSetting.Variables.Mtrr[0].Base)->Uint64 = FixedPcdGet32 (PcdFlashAreaBaseAddress); ((MSR_IA32_MTRR_PHYSBASE_REGISTER *) &MtrrSetting.Variables.Mtrr[0].Base)->Bits.Type = CacheWriteProtected; ((MSR_IA32_MTRR_PHYSMASK_REGISTER *) &MtrrSetting.Variables.Mtrr[0].Mask)->Uint64 = (~((UINT64)(FixedPcdGet32 (PcdFlashAreaSize) - 1))) & ValidMtrrAddressMask; ((MSR_IA32_MTRR_PHYSMASK_REGISTER *) &MtrrSetting.Variables.Mtrr[0].Mask)->Bits.V = 1; Index ++; MemOverflow =0; while (MaxMemoryLength > MemOverflow){ MemoryLength = MaxMemoryLength - MemOverflow; MemoryLength = GetPowerOfTwo64 (MemoryLength); ((MSR_IA32_MTRR_PHYSBASE_REGISTER *) &MtrrSetting.Variables.Mtrr[Index].Base)->Uint64 = MemOverflow & ValidMtrrAddressMask; ((MSR_IA32_MTRR_PHYSBASE_REGISTER *) &MtrrSetting.Variables.Mtrr[Index].Base)->Bits.Type = CacheWriteBack; ((MSR_IA32_MTRR_PHYSMASK_REGISTER *) &MtrrSetting.Variables.Mtrr[Index].Mask)->Uint64 = (~(MemoryLength - 1)) & ValidMtrrAddressMask; ((MSR_IA32_MTRR_PHYSMASK_REGISTER *) &MtrrSetting.Variables.Mtrr[Index].Mask)->Bits.V = 1; MemOverflow += MemoryLength; Index++; } MemoryLength = LowMemoryLength; while (MaxMemoryLength != MemoryLength) { MemoryLengthUc = GetPowerOfTwo64 (MaxMemoryLength - MemoryLength); ((MSR_IA32_MTRR_PHYSBASE_REGISTER *) &MtrrSetting.Variables.Mtrr[Index].Base)->Uint64 = (MaxMemoryLength - MemoryLengthUc) & ValidMtrrAddressMask; ((MSR_IA32_MTRR_PHYSBASE_REGISTER *) &MtrrSetting.Variables.Mtrr[Index].Base)->Bits.Type = CacheUncacheable; ((MSR_IA32_MTRR_PHYSMASK_REGISTER *) &MtrrSetting.Variables.Mtrr[Index].Mask)->Uint64 = (~(MemoryLengthUc - 1)) & ValidMtrrAddressMask; ((MSR_IA32_MTRR_PHYSMASK_REGISTER *) &MtrrSetting.Variables.Mtrr[Index].Mask)->Bits.V = 1; MaxMemoryLength -= MemoryLengthUc; Index++; } MemOverflow =0x100000000; while (HighMemoryLength > 0) { MemoryLength = HighMemoryLength; MemoryLength = GetPowerOfTwo64 (MemoryLength); if (MemoryLength > MemOverflow){ MemoryLength = MemOverflow; } ((MSR_IA32_MTRR_PHYSBASE_REGISTER *) &MtrrSetting.Variables.Mtrr[Index].Base)->Uint64 = MemOverflow & ValidMtrrAddressMask; ((MSR_IA32_MTRR_PHYSBASE_REGISTER *) &MtrrSetting.Variables.Mtrr[Index].Base)->Bits.Type = CacheWriteBack; ((MSR_IA32_MTRR_PHYSMASK_REGISTER *) &MtrrSetting.Variables.Mtrr[Index].Mask)->Uint64 = (~(MemoryLength - 1)) & ValidMtrrAddressMask; ((MSR_IA32_MTRR_PHYSMASK_REGISTER *) &MtrrSetting.Variables.Mtrr[Index].Mask)->Bits.V = 1; MemOverflow += MemoryLength; HighMemoryLength -= MemoryLength; Index++; } for (Index = 0; Index < MTRR_NUMBER_OF_VARIABLE_MTRR; Index++) { if (MtrrSetting.Variables.Mtrr[Index].Base == 0){ break; } DEBUG ((EFI_D_INFO, "Base=%lx, Mask=%lx\n",MtrrSetting.Variables.Mtrr[Index].Base ,MtrrSetting.Variables.Mtrr[Index].Mask)); } // // set FE/E bits for IA32_MTRR_DEF_TYPE // MtrrSetting.MtrrDefType |= 3 <<10; MtrrSetAllMtrrs(&MtrrSetting); // // Dump MTRR Setting // MtrrDebugPrintAllMtrrs (); return EFI_SUCCESS; } EFI_STATUS EFIAPI SetDxeCacheMode ( IN CONST EFI_PEI_SERVICES **PeiServices ) { // // This is not needed for now. // return EFI_SUCCESS; } STATIC EFI_STATUS GetMemorySize ( IN CONST EFI_PEI_SERVICES **PeiServices, OUT UINT64 *LowMemoryLength, OUT UINT64 *HighMemoryLength ) { EFI_STATUS Status; EFI_PEI_HOB_POINTERS Hob; *HighMemoryLength = 0; *LowMemoryLength = 0x100000; // // Get the HOB list for processing // Status = (*PeiServices)->GetHobList (PeiServices, (void **)&Hob.Raw); if (EFI_ERROR(Status)) { return Status; } // // Collect memory ranges // 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) { *LowMemoryLength += (UINT64) (Hob.ResourceDescriptor->ResourceLength); } else if (Hob.ResourceDescriptor->PhysicalStart >= (EFI_PHYSICAL_ADDRESS) 0x100000000) { *HighMemoryLength += (UINT64) (Hob.ResourceDescriptor->ResourceLength); } } } Hob.Raw = GET_NEXT_HOB (Hob); } return EFI_SUCCESS; } /** Publish Memory Type Information. @param NULL @retval EFI_SUCCESS Success. @retval Others Errors have occurred. **/ EFI_STATUS EFIAPI PublishMemoryTypeInfo ( void ) { EFI_STATUS Status; EFI_PEI_READ_ONLY_VARIABLE2_PPI *Variable; UINTN DataSize; EFI_MEMORY_TYPE_INFORMATION MemoryData[EfiMaxMemoryType + 1]; Status = PeiServicesLocatePpi ( &gEfiPeiReadOnlyVariable2PpiGuid, 0, NULL, (void **)&Variable ); if (EFI_ERROR(Status)) { DEBUG((EFI_D_ERROR, "WARNING: Locating Pei variable failed 0x%x \n", Status)); DEBUG((EFI_D_ERROR, "Build Hob from default\n")); // // Build the default GUID'd HOB for DXE // BuildGuidDataHob ( &gEfiMemoryTypeInformationGuid, mDefaultMemoryTypeInformation, sizeof (mDefaultMemoryTypeInformation) ); return Status; } DataSize = sizeof (MemoryData); // // This variable is saved in BDS stage. Now read it back // Status = Variable->GetVariable ( Variable, EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME, &gEfiMemoryTypeInformationGuid, NULL, &DataSize, &MemoryData ); if (EFI_ERROR (Status)) { // //build default // DEBUG((EFI_D_ERROR, "Build Hob from default\n")); BuildGuidDataHob ( &gEfiMemoryTypeInformationGuid, mDefaultMemoryTypeInformation, sizeof (mDefaultMemoryTypeInformation) ); } else { // // Build the GUID'd HOB for DXE from variable // DEBUG((EFI_D_ERROR, "Build Hob from variable \n")); BuildGuidDataHob ( &gEfiMemoryTypeInformationGuid, MemoryData, DataSize ); } return Status; }