diff --git a/MdeModulePkg/Core/Dxe/DxeMain.h b/MdeModulePkg/Core/Dxe/DxeMain.h index 86a7be2f51..53e26703f8 100644 --- a/MdeModulePkg/Core/Dxe/DxeMain.h +++ b/MdeModulePkg/Core/Dxe/DxeMain.h @@ -277,6 +277,12 @@ CoreInitializePool ( VOID ); +VOID +CoreSetMemoryTypeInformationRange ( + IN EFI_PHYSICAL_ADDRESS Start, + IN UINT64 Length + ); + /** Called to initialize the memory map and add descriptors to the current descriptor list. diff --git a/MdeModulePkg/Core/Dxe/Gcd/Gcd.c b/MdeModulePkg/Core/Dxe/Gcd/Gcd.c index 792cd2e0af..c450d1bf25 100644 --- a/MdeModulePkg/Core/Dxe/Gcd/Gcd.c +++ b/MdeModulePkg/Core/Dxe/Gcd/Gcd.c @@ -2238,6 +2238,8 @@ CoreInitializeMemoryServices ( EFI_HOB_HANDOFF_INFO_TABLE *PhitHob; EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob; EFI_HOB_RESOURCE_DESCRIPTOR *PhitResourceHob; + EFI_HOB_RESOURCE_DESCRIPTOR *MemoryTypeInformationResourceHob; + UINTN Count; EFI_PHYSICAL_ADDRESS BaseAddress; UINT64 Length; UINT64 Attributes; @@ -2289,12 +2291,47 @@ CoreInitializeMemoryServices ( // // See if a Memory Type Information HOB is available // - GuidHob = GetFirstGuidHob (&gEfiMemoryTypeInformationGuid); + MemoryTypeInformationResourceHob = NULL; + GuidHob = GetFirstGuidHob (&gEfiMemoryTypeInformationGuid); if (GuidHob != NULL) { EfiMemoryTypeInformation = GET_GUID_HOB_DATA (GuidHob); DataSize = GET_GUID_HOB_DATA_SIZE (GuidHob); if ((EfiMemoryTypeInformation != NULL) && (DataSize > 0) && (DataSize <= (EfiMaxMemoryType + 1) * sizeof (EFI_MEMORY_TYPE_INFORMATION))) { CopyMem (&gMemoryTypeInformation, EfiMemoryTypeInformation, DataSize); + + // + // Look for Resource Descriptor HOB with a ResourceType of System Memory + // and an Owner GUID of gEfiMemoryTypeInformationGuid. If more than 1 is + // found, then set MemoryTypeInformationResourceHob to NULL. + // + Count = 0; + for (Hob.Raw = *HobStart; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) { + if (GET_HOB_TYPE (Hob) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) { + continue; + } + + ResourceHob = Hob.ResourceDescriptor; + if (!CompareGuid (&ResourceHob->Owner, &gEfiMemoryTypeInformationGuid)) { + continue; + } + + Count++; + if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) { + continue; + } + + if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) != TESTED_MEMORY_ATTRIBUTES) { + continue; + } + + if (ResourceHob->ResourceLength >= CalculateTotalMemoryBinSizeNeeded ()) { + MemoryTypeInformationResourceHob = ResourceHob; + } + } + + if (Count > 1) { + MemoryTypeInformationResourceHob = NULL; + } } } @@ -2344,6 +2381,15 @@ CoreInitializeMemoryServices ( PhitResourceHob = ResourceHob; Found = TRUE; + // + // If a Memory Type Information Resource HOB was found and is the same + // Resource HOB that describes the PHIT HOB, then ignore the Memory Type + // Information Resource HOB. + // + if (MemoryTypeInformationResourceHob == PhitResourceHob) { + MemoryTypeInformationResourceHob = NULL; + } + // // Compute range between PHIT EfiMemoryTop and the end of the Resource Descriptor HOB // @@ -2387,8 +2433,9 @@ CoreInitializeMemoryServices ( if (Length < MinimalMemorySizeNeeded) { // // Search all the resource descriptor HOBs from the highest possible addresses down for a memory - // region that is big enough to initialize the DXE core. Always skip the PHIT Resource HOB. - // The max address must be within the physically addressible range for the processor. + // region that is big enough to initialize the DXE core. Always skip the PHIT Resource HOB + // and the Memory Type Information Resource HOB. The max address must be within the physically + // addressable range for the processor. // HighAddress = MAX_ALLOC_ADDRESS; for (Hob.Raw = *HobStart; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) { @@ -2399,6 +2446,13 @@ CoreInitializeMemoryServices ( continue; } + // + // Skip the Resource Descriptor HOB that contains Memory Type Information bins + // + if (Hob.ResourceDescriptor == MemoryTypeInformationResourceHob) { + continue; + } + // // Skip all HOBs except Resource Descriptor HOBs // @@ -2466,6 +2520,18 @@ CoreInitializeMemoryServices ( Capabilities = CoreConvertResourceDescriptorHobAttributesToCapabilities (EfiGcdMemoryTypeSystemMemory, Attributes); } + if (MemoryTypeInformationResourceHob != NULL) { + // + // If a Memory Type Information Resource HOB was found, then use the address + // range of the Memory Type Information Resource HOB as the preferred + // address range for the Memory Type Information bins. + // + CoreSetMemoryTypeInformationRange ( + MemoryTypeInformationResourceHob->PhysicalStart, + MemoryTypeInformationResourceHob->ResourceLength + ); + } + // // Declare the very first memory region, so the EFI Memory Services are available. // diff --git a/MdeModulePkg/Core/Dxe/Mem/Page.c b/MdeModulePkg/Core/Dxe/Mem/Page.c index 6497af5733..3205732ede 100644 --- a/MdeModulePkg/Core/Dxe/Mem/Page.c +++ b/MdeModulePkg/Core/Dxe/Mem/Page.c @@ -532,6 +532,108 @@ CoreLoadingFixedAddressHook ( return; } +/** + Sets the preferred memory range to use for the Memory Type Information bins. + This service must be called before fist call to CoreAddMemoryDescriptor(). + + If the location of the Memory Type Information bins has already been + established or the size of the range provides is smaller than all the + Memory Type Information bins, then the range provides is not used. + + @param Start The start address of the Memory Type Information range. + @param Length The size, in bytes, of the Memory Type Information range. +**/ +VOID +CoreSetMemoryTypeInformationRange ( + IN EFI_PHYSICAL_ADDRESS Start, + IN UINT64 Length + ) +{ + EFI_PHYSICAL_ADDRESS Top; + EFI_MEMORY_TYPE Type; + UINTN Index; + UINTN Size; + + // + // Return if Memory Type Information bin locations have already been set + // + if (mMemoryTypeInformationInitialized) { + DEBUG ((DEBUG_ERROR, "%a: Ignored. Bins already set.\n", __func__)); + return; + } + + // + // Return if size of the Memory Type Information bins is greater than Length + // + Size = 0; + for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) { + // + // Make sure the memory type in the gMemoryTypeInformation[] array is valid + // + Type = (EFI_MEMORY_TYPE)(gMemoryTypeInformation[Index].Type); + if ((UINT32)Type > EfiMaxMemoryType) { + continue; + } + + Size += EFI_PAGES_TO_SIZE (gMemoryTypeInformation[Index].NumberOfPages); + } + + if (Size > Length) { + return; + } + + // + // Loop through each memory type in the order specified by the + // gMemoryTypeInformation[] array + // + Top = Start + Length; + for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) { + // + // Make sure the memory type in the gMemoryTypeInformation[] array is valid + // + Type = (EFI_MEMORY_TYPE)(gMemoryTypeInformation[Index].Type); + if ((UINT32)Type > EfiMaxMemoryType) { + continue; + } + + if (gMemoryTypeInformation[Index].NumberOfPages != 0) { + mMemoryTypeStatistics[Type].MaximumAddress = Top - 1; + Top -= EFI_PAGES_TO_SIZE (gMemoryTypeInformation[Index].NumberOfPages); + mMemoryTypeStatistics[Type].BaseAddress = Top; + + // + // If the current base address is the lowest address so far, then update + // the default maximum address + // + if (mMemoryTypeStatistics[Type].BaseAddress < mDefaultMaximumAddress) { + mDefaultMaximumAddress = mMemoryTypeStatistics[Type].BaseAddress - 1; + } + + mMemoryTypeStatistics[Type].NumberOfPages = gMemoryTypeInformation[Index].NumberOfPages; + gMemoryTypeInformation[Index].NumberOfPages = 0; + } + } + + // + // If the number of pages reserved for a memory type is 0, then all + // allocations for that type should be in the default range. + // + for (Type = (EFI_MEMORY_TYPE)0; Type < EfiMaxMemoryType; Type++) { + for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) { + if (Type == (EFI_MEMORY_TYPE)gMemoryTypeInformation[Index].Type) { + mMemoryTypeStatistics[Type].InformationIndex = Index; + } + } + + mMemoryTypeStatistics[Type].CurrentNumberOfPages = 0; + if (mMemoryTypeStatistics[Type].MaximumAddress == MAX_ALLOC_ADDRESS) { + mMemoryTypeStatistics[Type].MaximumAddress = mDefaultMaximumAddress; + } + } + + mMemoryTypeInformationInitialized = TRUE; +} + /** Called to initialize the memory map and add descriptors to the current descriptor list. diff --git a/MdeModulePkg/Include/Guid/MemoryTypeInformation.h b/MdeModulePkg/Include/Guid/MemoryTypeInformation.h index e97d88765e..65adcf478b 100644 --- a/MdeModulePkg/Include/Guid/MemoryTypeInformation.h +++ b/MdeModulePkg/Include/Guid/MemoryTypeInformation.h @@ -1,14 +1,18 @@ /** @file This file defines: - * Memory Type Information GUID for HOB and Variable. + * Memory Type Information GUID for Guided HOB and Variable. * Memory Type Information Variable Name. * Memory Type Information GUID HOB data structure. - The memory type information HOB and variable can - be used to store the information for each memory type in Variable or HOB. + The memory type information HOB and variable can be used to store information + for each memory type in Variable or HOB. -Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
-SPDX-License-Identifier: BSD-2-Clause-Patent + The Memory Type Information GUID can also be optionally used as the Owner + field of a Resource Descriptor HOB to provide the preferred memory range + for the memory types described in the Memory Type Information GUID HOB. + + Copyright (c) 2006, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent **/