X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=MdeModulePkg%2FCore%2FDxe%2FMem%2FPage.c;h=260a30a214c7117a148e61863c4657f6366a6c45;hp=fa54e7f0e63f9b6e7b37e6a75bfe42d87feaf83b;hb=d4731a98a3a5ddc2fed73d2998884f2cbee44ba9;hpb=f3f2e05db8c89628498ec4efdb16184747824c63 diff --git a/MdeModulePkg/Core/Dxe/Mem/Page.c b/MdeModulePkg/Core/Dxe/Mem/Page.c index fa54e7f0e6..260a30a214 100644 --- a/MdeModulePkg/Core/Dxe/Mem/Page.c +++ b/MdeModulePkg/Core/Dxe/Mem/Page.c @@ -1,8 +1,8 @@ /** @file UEFI Memory page management functions. -Copyright (c) 2007 - 2008, Intel Corporation.
-All rights reserved. This program and the accompanying materials +Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.
+This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php @@ -15,8 +15,6 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include "DxeMain.h" #include "Imem.h" -#define EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT (EFI_PAGE_SIZE) - // // Entry for tracking the memory regions for each memory type to coalesce similar memory types // @@ -28,7 +26,7 @@ typedef struct { UINTN InformationIndex; BOOLEAN Special; BOOLEAN Runtime; -} EFI_MEMORY_TYPE_STAISTICS; +} EFI_MEMORY_TYPE_STATISTICS; // // MemoryMap - The current memory map @@ -52,7 +50,7 @@ UINTN mFreeMapStack = 0; LIST_ENTRY mFreeMemoryMapEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mFreeMemoryMapEntryList); BOOLEAN mMemoryTypeInformationInitialized = FALSE; -EFI_MEMORY_TYPE_STAISTICS mMemoryTypeStatistics[EfiMaxMemoryType + 1] = { +EFI_MEMORY_TYPE_STATISTICS mMemoryTypeStatistics[EfiMaxMemoryType + 1] = { { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE }, // EfiReservedMemoryType { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiLoaderCode { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiLoaderData @@ -67,10 +65,12 @@ EFI_MEMORY_TYPE_STAISTICS mMemoryTypeStatistics[EfiMaxMemoryType + 1] = { { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiMemoryMappedIO { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiMemoryMappedIOPortSpace { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, TRUE }, // EfiPalCode + { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiPersistentMemory { 0, MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE } // EfiMaxMemoryType }; EFI_PHYSICAL_ADDRESS mDefaultMaximumAddress = MAX_ADDRESS; +EFI_PHYSICAL_ADDRESS mDefaultBaseAddress = MAX_ADDRESS; EFI_MEMORY_TYPE_INFORMATION gMemoryTypeInformation[EfiMaxMemoryType + 1] = { { EfiReservedMemoryType, 0 }, @@ -87,9 +87,15 @@ EFI_MEMORY_TYPE_INFORMATION gMemoryTypeInformation[EfiMaxMemoryType + 1] = { { EfiMemoryMappedIO, 0 }, { EfiMemoryMappedIOPortSpace, 0 }, { EfiPalCode, 0 }, + { EfiPersistentMemory, 0 }, { EfiMaxMemoryType, 0 } }; - +// +// Only used when load module at fixed address feature is enabled. True means the memory is alreay successfully allocated +// and ready to load the module in to specified address.or else, the memory is not ready and module will be loaded at a +// address assigned by DXE core. +// +GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN gLoadFixedAddressCodeMemoryReady = FALSE; /** Enter critical section by gaining lock on gMemoryLock. @@ -171,7 +177,20 @@ CoreAddRange ( ASSERT_LOCKED (&gMemoryLock); DEBUG ((DEBUG_PAGE, "AddRange: %lx-%lx to %d\n", Start, End, Type)); - + + // + // If memory of type EfiConventionalMemory is being added that includes the page + // starting at address 0, then zero the page starting at address 0. This has + // two benifits. It helps find NULL pointer bugs and it also maximizes + // compatibility with operating systems that may evaluate memory in this page + // for legacy data structures. If memory of any other type is added starting + // at address 0, then do not zero the page at address 0 because the page is being + // used for other purposes. + // + if (Type == EfiConventionalMemory && Start == 0 && (End >= EFI_PAGE_SIZE - 1)) { + SetMem ((VOID *)(UINTN)Start, EFI_PAGE_SIZE, 0); + } + // // Memory map being altered so updated key // @@ -183,7 +202,7 @@ CoreAddRange ( // If we are in EFI 1.10 compatability mode no event groups will be // found and nothing will happen we we call this function. These events // will get signaled but since a lock is held around the call to this - // function the notificaiton events will only be called after this funciton + // function the notificaiton events will only be called after this function // returns and the lock is released. // CoreNotifySignalList (&gEfiEventMemoryMapChangeGuid); @@ -266,12 +285,14 @@ AllocateMemoryMapEntry ( // // The list is empty, to allocate one page to refuel the list // - FreeDescriptorEntries = CoreAllocatePoolPages (EfiBootServicesData, EFI_SIZE_TO_PAGES(DEFAULT_PAGE_ALLOCATION), DEFAULT_PAGE_ALLOCATION); - if(FreeDescriptorEntries != NULL) { + FreeDescriptorEntries = CoreAllocatePoolPages (EfiBootServicesData, + EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION_GRANULARITY), + DEFAULT_PAGE_ALLOCATION_GRANULARITY); + if (FreeDescriptorEntries != NULL) { // // Enque the free memmory map entries into the list // - for (Index = 0; Index< DEFAULT_PAGE_ALLOCATION / sizeof(MEMORY_MAP); Index++) { + for (Index = 0; Index < DEFAULT_PAGE_ALLOCATION_GRANULARITY / sizeof(MEMORY_MAP); Index++) { FreeDescriptorEntries[Index].Signature = MEMORY_MAP_SIGNATURE; InsertTailList (&mFreeMemoryMapEntryList, &FreeDescriptorEntries[Index].Link); } @@ -369,18 +390,20 @@ CoreFreeMemoryMapStack ( Find untested but initialized memory regions in GCD map and convert them to be DXE allocatable. **/ -VOID +BOOLEAN PromoteMemoryResource ( VOID ) { - LIST_ENTRY *Link; - EFI_GCD_MAP_ENTRY *Entry; + LIST_ENTRY *Link; + EFI_GCD_MAP_ENTRY *Entry; + BOOLEAN Promoted; DEBUG ((DEBUG_PAGE, "Promote the memory resource\n")); CoreAcquireGcdMemoryLock (); + Promoted = FALSE; Link = mGcdMemorySpaceMap.ForwardLink; while (Link != &mGcdMemorySpaceMap) { @@ -393,7 +416,11 @@ PromoteMemoryResource ( // // Update the GCD map // - Entry->GcdMemoryType = EfiGcdMemoryTypeSystemMemory; + if ((Entry->Capabilities & EFI_MEMORY_MORE_RELIABLE) == EFI_MEMORY_MORE_RELIABLE) { + Entry->GcdMemoryType = EfiGcdMemoryTypeMoreReliable; + } else { + Entry->GcdMemoryType = EfiGcdMemoryTypeSystemMemory; + } Entry->Capabilities |= EFI_MEMORY_TESTED; Entry->ImageHandle = gDxeCoreImageHandle; Entry->DeviceHandle = NULL; @@ -410,6 +437,7 @@ PromoteMemoryResource ( ); CoreFreeMemoryMapStack (); + Promoted = TRUE; } Link = Link->ForwardLink; @@ -417,9 +445,72 @@ PromoteMemoryResource ( CoreReleaseGcdMemoryLock (); - return; + return Promoted; } +/** + This function try to allocate Runtime code & Boot time code memory range. If LMFA enabled, 2 patchable PCD + PcdLoadFixAddressRuntimeCodePageNumber & PcdLoadFixAddressBootTimeCodePageNumber which are set by tools will record the + size of boot time and runtime code. +**/ +VOID +CoreLoadingFixedAddressHook ( + VOID + ) +{ + UINT32 RuntimeCodePageNumber; + UINT32 BootTimeCodePageNumber; + EFI_PHYSICAL_ADDRESS RuntimeCodeBase; + EFI_PHYSICAL_ADDRESS BootTimeCodeBase; + EFI_STATUS Status; + + // + // Make sure these 2 areas are not initialzied. + // + if (!gLoadFixedAddressCodeMemoryReady) { + RuntimeCodePageNumber = PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber); + BootTimeCodePageNumber= PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber); + RuntimeCodeBase = (EFI_PHYSICAL_ADDRESS)(gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress - EFI_PAGES_TO_SIZE (RuntimeCodePageNumber)); + BootTimeCodeBase = (EFI_PHYSICAL_ADDRESS)(RuntimeCodeBase - EFI_PAGES_TO_SIZE (BootTimeCodePageNumber)); + // + // Try to allocate runtime memory. + // + Status = CoreAllocatePages ( + AllocateAddress, + EfiRuntimeServicesCode, + RuntimeCodePageNumber, + &RuntimeCodeBase + ); + if (EFI_ERROR(Status)) { + // + // Runtime memory allocation failed + // + return; + } + // + // Try to allocate boot memory. + // + Status = CoreAllocatePages ( + AllocateAddress, + EfiBootServicesCode, + BootTimeCodePageNumber, + &BootTimeCodeBase + ); + if (EFI_ERROR(Status)) { + // + // boot memory allocation failed. Free Runtime code range and will try the allocation again when + // new memory range is installed. + // + CoreFreePages ( + RuntimeCodeBase, + RuntimeCodePageNumber + ); + return; + } + gLoadFixedAddressCodeMemoryReady = TRUE; + } + return; +} /** Called to initialize the memory map and add descriptors to @@ -448,21 +539,30 @@ CoreAddMemoryDescriptor ( EFI_STATUS Status; UINTN Index; UINTN FreeIndex; - + if ((Start & EFI_PAGE_MASK) != 0) { return; } - if (Type >= EfiMaxMemoryType && Type <= 0x7fffffff) { + if (Type >= EfiMaxMemoryType && Type < MEMORY_TYPE_OEM_RESERVED_MIN) { return; } - CoreAcquireMemoryLock (); End = Start + LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT) - 1; CoreAddRange (Type, Start, End, Attribute); CoreFreeMemoryMapStack (); CoreReleaseMemoryLock (); + ApplyMemoryProtectionPolicy (EfiMaxMemoryType, Type, Start, + LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT)); + + // + // If Loading Module At Fixed Address feature is enabled. try to allocate memory with Runtime code & Boot time code type + // + if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) { + CoreLoadingFixedAddressHook(); + } + // // Check to see if the statistics for the different memory types have already been established // @@ -470,6 +570,7 @@ CoreAddMemoryDescriptor ( return; } + // // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array // @@ -478,10 +579,9 @@ CoreAddMemoryDescriptor ( // Make sure the memory type in the gMemoryTypeInformation[] array is valid // Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[Index].Type); - if (Type < 0 || Type > EfiMaxMemoryType) { + if ((UINT32)Type > EfiMaxMemoryType) { continue; } - if (gMemoryTypeInformation[Index].NumberOfPages != 0) { // // Allocate pages for the current memory type from the top of available memory @@ -503,7 +603,7 @@ CoreAddMemoryDescriptor ( // Make sure the memory type in the gMemoryTypeInformation[] array is valid // Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[FreeIndex].Type); - if (Type < 0 || Type > EfiMaxMemoryType) { + if ((UINT32)Type > EfiMaxMemoryType) { continue; } @@ -546,10 +646,9 @@ CoreAddMemoryDescriptor ( // Make sure the memory type in the gMemoryTypeInformation[] array is valid // Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[Index].Type); - if (Type < 0 || Type > EfiMaxMemoryType) { + if ((UINT32)Type > EfiMaxMemoryType) { continue; } - if (gMemoryTypeInformation[Index].NumberOfPages != 0) { CoreFreePages ( mMemoryTypeStatistics[Type].BaseAddress, @@ -581,13 +680,17 @@ CoreAddMemoryDescriptor ( /** - Internal function. Converts a memory range to the specified type. - The range must exist in the memory map. + Internal function. Converts a memory range to the specified type or attributes. + The range must exist in the memory map. Either ChangingType or + ChangingAttributes must be set, but not both. @param Start The first address of the range Must be page aligned @param NumberOfPages The number of pages to convert + @param ChangingType Boolean indicating that type value should be changed @param NewType The new type for the memory range + @param ChangingAttributes Boolean indicating that attributes value should be changed + @param NewAttributes The new attributes for the memory range @retval EFI_INVALID_PARAMETER Invalid parameter @retval EFI_NOT_FOUND Could not find a descriptor cover the specified @@ -597,10 +700,13 @@ CoreAddMemoryDescriptor ( **/ EFI_STATUS -CoreConvertPages ( +CoreConvertPagesEx ( IN UINT64 Start, IN UINT64 NumberOfPages, - IN EFI_MEMORY_TYPE NewType + IN BOOLEAN ChangingType, + IN EFI_MEMORY_TYPE NewType, + IN BOOLEAN ChangingAttributes, + IN UINT64 NewAttributes ) { @@ -608,6 +714,7 @@ CoreConvertPages ( UINT64 End; UINT64 RangeEnd; UINT64 Attribute; + EFI_MEMORY_TYPE MemType; LIST_ENTRY *Link; MEMORY_MAP *Entry; @@ -619,8 +726,9 @@ CoreConvertPages ( ASSERT ((Start & EFI_PAGE_MASK) == 0); ASSERT (End > Start) ; ASSERT_LOCKED (&gMemoryLock); + ASSERT ( (ChangingType == FALSE) || (ChangingAttributes == FALSE) ); - if (NumberOfPages == 0 || ((Start & EFI_PAGE_MASK) != 0) || (Start > (Start + NumberOfBytes))) { + if (NumberOfPages == 0 || ((Start & EFI_PAGE_MASK) != 0) || (Start >= End)) { return EFI_INVALID_PARAMETER; } @@ -651,40 +759,49 @@ CoreConvertPages ( // if that's all we've got // RangeEnd = End; + + ASSERT (Entry != NULL); if (Entry->End < End) { RangeEnd = Entry->End; } - DEBUG ((DEBUG_PAGE, "ConvertRange: %lx-%lx to %d\n", Start, RangeEnd, NewType)); - - // - // Debug code - verify conversion is allowed - // - if (!(NewType == EfiConventionalMemory ? 1 : 0) ^ (Entry->Type == EfiConventionalMemory ? 1 : 0)) { - DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ConvertPages: Incompatible memory types\n")); - return EFI_NOT_FOUND; + if (ChangingType) { + DEBUG ((DEBUG_PAGE, "ConvertRange: %lx-%lx to type %d\n", Start, RangeEnd, NewType)); + } + if (ChangingAttributes) { + DEBUG ((DEBUG_PAGE, "ConvertRange: %lx-%lx to attr %lx\n", Start, RangeEnd, NewAttributes)); } - // - // Update counters for the number of pages allocated to each memory type - // - if (Entry->Type >= 0 && Entry->Type < EfiMaxMemoryType) { - if (Start >= mMemoryTypeStatistics[Entry->Type].BaseAddress && - Start <= mMemoryTypeStatistics[Entry->Type].MaximumAddress) { - if (NumberOfPages > mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages) { - mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages = 0; - } else { - mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages -= NumberOfPages; + if (ChangingType) { + // + // Debug code - verify conversion is allowed + // + if (!(NewType == EfiConventionalMemory ? 1 : 0) ^ (Entry->Type == EfiConventionalMemory ? 1 : 0)) { + DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ConvertPages: Incompatible memory types\n")); + return EFI_NOT_FOUND; + } + + // + // Update counters for the number of pages allocated to each memory type + // + if ((UINT32)Entry->Type < EfiMaxMemoryType) { + if ((Start >= mMemoryTypeStatistics[Entry->Type].BaseAddress && Start <= mMemoryTypeStatistics[Entry->Type].MaximumAddress) || + (Start >= mDefaultBaseAddress && Start <= mDefaultMaximumAddress) ) { + if (NumberOfPages > mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages) { + mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages = 0; + } else { + mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages -= NumberOfPages; + } } } - } - if (NewType >= 0 && NewType < EfiMaxMemoryType) { - if (Start >= mMemoryTypeStatistics[NewType].BaseAddress && Start <= mMemoryTypeStatistics[NewType].MaximumAddress) { - mMemoryTypeStatistics[NewType].CurrentNumberOfPages += NumberOfPages; - if (mMemoryTypeStatistics[NewType].CurrentNumberOfPages > - gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages) { - gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages = (UINT32)mMemoryTypeStatistics[NewType].CurrentNumberOfPages; + if ((UINT32)NewType < EfiMaxMemoryType) { + if ((Start >= mMemoryTypeStatistics[NewType].BaseAddress && Start <= mMemoryTypeStatistics[NewType].MaximumAddress) || + (Start >= mDefaultBaseAddress && Start <= mDefaultMaximumAddress) ) { + mMemoryTypeStatistics[NewType].CurrentNumberOfPages += NumberOfPages; + if (mMemoryTypeStatistics[NewType].CurrentNumberOfPages > gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages) { + gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages = (UINT32)mMemoryTypeStatistics[NewType].CurrentNumberOfPages; + } } } } @@ -738,9 +855,15 @@ CoreConvertPages ( // // The new range inherits the same Attribute as the Entry - //it is being cut out of + // it is being cut out of unless attributes are being changed // - Attribute = Entry->Attribute; + if (ChangingType) { + Attribute = Entry->Attribute; + MemType = NewType; + } else { + Attribute = NewAttributes; + MemType = Entry->Type; + } // // If the descriptor is empty, then remove it from the map @@ -753,7 +876,21 @@ CoreConvertPages ( // // Add our new range in // - CoreAddRange (NewType, Start, RangeEnd, Attribute); + CoreAddRange (MemType, Start, RangeEnd, Attribute); + if (ChangingType && (MemType == EfiConventionalMemory)) { + // + // Avoid calling DEBUG_CLEAR_MEMORY() for an address of 0 because this + // macro will ASSERT() if address is 0. Instead, CoreAddRange() guarantees + // that the page starting at address 0 is always filled with zeros. + // + if (Start == 0) { + if (RangeEnd > EFI_PAGE_SIZE) { + DEBUG_CLEAR_MEMORY ((VOID *)(UINTN) EFI_PAGE_SIZE, (UINTN) (RangeEnd - EFI_PAGE_SIZE + 1)); + } + } else { + DEBUG_CLEAR_MEMORY ((VOID *)(UINTN) Start, (UINTN) (RangeEnd - Start + 1)); + } + } // // Move any map descriptor stack to general pool @@ -774,12 +911,66 @@ CoreConvertPages ( } +/** + Internal function. Converts a memory range to the specified type. + The range must exist in the memory map. + + @param Start The first address of the range Must be page + aligned + @param NumberOfPages The number of pages to convert + @param NewType The new type for the memory range + + @retval EFI_INVALID_PARAMETER Invalid parameter + @retval EFI_NOT_FOUND Could not find a descriptor cover the specified + range or convertion not allowed. + @retval EFI_SUCCESS Successfully converts the memory range to the + specified type. + +**/ +EFI_STATUS +CoreConvertPages ( + IN UINT64 Start, + IN UINT64 NumberOfPages, + IN EFI_MEMORY_TYPE NewType + ) +{ + return CoreConvertPagesEx(Start, NumberOfPages, TRUE, NewType, FALSE, 0); +} + + +/** + Internal function. Converts a memory range to use new attributes. + + @param Start The first address of the range Must be page + aligned + @param NumberOfPages The number of pages to convert + @param NewAttributes The new attributes value for the range. + +**/ +VOID +CoreUpdateMemoryAttributes ( + IN EFI_PHYSICAL_ADDRESS Start, + IN UINT64 NumberOfPages, + IN UINT64 NewAttributes + ) +{ + CoreAcquireMemoryLock (); + + // + // Update the attributes to the new value + // + CoreConvertPagesEx(Start, NumberOfPages, FALSE, (EFI_MEMORY_TYPE)0, TRUE, NewAttributes); + + CoreReleaseMemoryLock (); +} + /** Internal function. Finds a consecutive free page range below the requested address. @param MaxAddress The address that the range must be below + @param MinAddress The address that the range must be above @param NumberOfPages Number of pages needed @param NewType The type of memory the range is going to be turned into @@ -791,6 +982,7 @@ CoreConvertPages ( UINT64 CoreFindFreePagesI ( IN UINT64 MaxAddress, + IN UINT64 MinAddress, IN UINT64 NumberOfPages, IN EFI_MEMORY_TYPE NewType, IN UINTN Alignment @@ -822,7 +1014,7 @@ CoreFindFreePagesI ( // // Set MaxAddress to a page boundary // - MaxAddress &= ~EFI_PAGE_MASK; + MaxAddress &= ~(UINT64)EFI_PAGE_MASK; // // Set MaxAddress to end of the page @@ -847,9 +1039,9 @@ CoreFindFreePagesI ( DescEnd = Entry->End; // - // If desc is past max allowed address, skip it + // If desc is past max allowed address or below min allowed address, skip it // - if (DescStart >= MaxAddress) { + if ((DescStart >= MaxAddress) || (DescEnd < MinAddress)) { continue; } @@ -862,6 +1054,11 @@ CoreFindFreePagesI ( DescEnd = ((DescEnd + 1) & (~(Alignment - 1))) - 1; + // Skip if DescEnd is less than DescStart after alignment clipping + if (DescEnd < DescStart) { + continue; + } + // // Compute the number of bytes we can used from this // descriptor, and see it's enough to satisfy the request @@ -869,6 +1066,12 @@ CoreFindFreePagesI ( DescNumberOfBytes = DescEnd - DescStart + 1; if (DescNumberOfBytes >= NumberOfBytes) { + // + // If the start of the allocated range is below the min address allowed, skip it + // + if ((DescEnd - NumberOfBytes + 1) < MinAddress) { + continue; + } // // If this is the best match so far remember it @@ -916,41 +1119,62 @@ FindFreePages ( IN UINTN Alignment ) { - UINT64 NewMaxAddress; - UINT64 Start; + UINT64 Start; - NewMaxAddress = MaxAddress; + // + // Attempt to find free pages in the preferred bin based on the requested memory type + // + if ((UINT32)NewType < EfiMaxMemoryType && MaxAddress >= mMemoryTypeStatistics[NewType].MaximumAddress) { + Start = CoreFindFreePagesI ( + mMemoryTypeStatistics[NewType].MaximumAddress, + mMemoryTypeStatistics[NewType].BaseAddress, + NoPages, + NewType, + Alignment + ); + if (Start != 0) { + return Start; + } + } - if (NewType >= 0 && NewType < EfiMaxMemoryType && NewMaxAddress >= mMemoryTypeStatistics[NewType].MaximumAddress) { - NewMaxAddress = mMemoryTypeStatistics[NewType].MaximumAddress; - } else { - if (NewMaxAddress > mDefaultMaximumAddress) { - NewMaxAddress = mDefaultMaximumAddress; + // + // Attempt to find free pages in the default allocation bin + // + if (MaxAddress >= mDefaultMaximumAddress) { + Start = CoreFindFreePagesI (mDefaultMaximumAddress, 0, NoPages, NewType, Alignment); + if (Start != 0) { + if (Start < mDefaultBaseAddress) { + mDefaultBaseAddress = Start; + } + return Start; } } - Start = CoreFindFreePagesI (NewMaxAddress, NoPages, NewType, Alignment); - if (Start == 0) { - Start = CoreFindFreePagesI (MaxAddress, NoPages, NewType, Alignment); - if (Start == 0) { - // - // Here means there may be no enough memory to use, so try to go through - // all the memory descript to promote the untested memory directly - // - PromoteMemoryResource (); + // + // The allocation did not succeed in any of the prefered bins even after + // promoting resources. Attempt to find free pages anywhere is the requested + // address range. If this allocation fails, then there are not enough + // resources anywhere to satisfy the request. + // + Start = CoreFindFreePagesI (MaxAddress, 0, NoPages, NewType, Alignment); + if (Start != 0) { + return Start; + } - // - // Allocate memory again after the memory resource re-arranged - // - Start = CoreFindFreePagesI (MaxAddress, NoPages, NewType, Alignment); - } + // + // If allocations from the preferred bins fail, then attempt to promote memory resources. + // + if (!PromoteMemoryResource ()) { + return 0; } - return Start; + // + // If any memory resources were promoted, then re-attempt the allocation + // + return FindFreePages (MaxAddress, NoPages, NewType, Alignment); } - /** Allocates pages from the memory map. @@ -971,7 +1195,7 @@ FindFreePages ( **/ EFI_STATUS EFIAPI -CoreAllocatePages ( +CoreInternalAllocatePages ( IN EFI_ALLOCATE_TYPE Type, IN EFI_MEMORY_TYPE MemoryType, IN UINTN NumberOfPages, @@ -980,26 +1204,32 @@ CoreAllocatePages ( { EFI_STATUS Status; UINT64 Start; + UINT64 NumberOfBytes; + UINT64 End; UINT64 MaxAddress; UINTN Alignment; - if (Type < AllocateAnyPages || Type >= (UINTN) MaxAllocateType) { + if ((UINT32)Type >= MaxAllocateType) { + return EFI_INVALID_PARAMETER; + } + + if ((MemoryType >= EfiMaxMemoryType && MemoryType < MEMORY_TYPE_OEM_RESERVED_MIN) || + (MemoryType == EfiConventionalMemory) || (MemoryType == EfiPersistentMemory)) { return EFI_INVALID_PARAMETER; } - if ((MemoryType >= EfiMaxMemoryType && MemoryType <= 0x7fffffff) || - MemoryType == EfiConventionalMemory) { + if (Memory == NULL) { return EFI_INVALID_PARAMETER; } - Alignment = EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT; + Alignment = DEFAULT_PAGE_ALLOCATION_GRANULARITY; if (MemoryType == EfiACPIReclaimMemory || MemoryType == EfiACPIMemoryNVS || MemoryType == EfiRuntimeServicesCode || MemoryType == EfiRuntimeServicesData) { - Alignment = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT; + Alignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY; } if (Type == AllocateAddress) { @@ -1021,6 +1251,30 @@ CoreAllocatePages ( // MaxAddress = MAX_ADDRESS; + // + // Check for Type AllocateAddress, + // if NumberOfPages is 0 or + // if (NumberOfPages << EFI_PAGE_SHIFT) is above MAX_ADDRESS or + // if (Start + NumberOfBytes) rolls over 0 or + // if Start is above MAX_ADDRESS or + // if End is above MAX_ADDRESS, + // return EFI_NOT_FOUND. + // + if (Type == AllocateAddress) { + if ((NumberOfPages == 0) || + (NumberOfPages > RShiftU64 (MaxAddress, EFI_PAGE_SHIFT))) { + return EFI_NOT_FOUND; + } + NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT); + End = Start + NumberOfBytes - 1; + + if ((Start >= End) || + (Start > MaxAddress) || + (End > MaxAddress)) { + return EFI_NOT_FOUND; + } + } + if (Type == AllocateMaxAddress) { MaxAddress = Start; } @@ -1053,12 +1307,58 @@ Done: return Status; } +/** + Allocates pages from the memory map. + + @param Type The type of allocation to perform + @param MemoryType The type of memory to turn the allocated pages + into + @param NumberOfPages The number of pages to allocate + @param Memory A pointer to receive the base allocated memory + address + + @return Status. On success, Memory is filled in with the base address allocated + @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in + spec. + @retval EFI_NOT_FOUND Could not allocate pages match the requirement. + @retval EFI_OUT_OF_RESOURCES No enough pages to allocate. + @retval EFI_SUCCESS Pages successfully allocated. + +**/ +EFI_STATUS +EFIAPI +CoreAllocatePages ( + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN NumberOfPages, + OUT EFI_PHYSICAL_ADDRESS *Memory + ) +{ + EFI_STATUS Status; + + Status = CoreInternalAllocatePages (Type, MemoryType, NumberOfPages, Memory); + if (!EFI_ERROR (Status)) { + CoreUpdateProfile ( + (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0), + MemoryProfileActionAllocatePages, + MemoryType, + EFI_PAGES_TO_SIZE (NumberOfPages), + (VOID *) (UINTN) *Memory, + NULL + ); + InstallMemoryAttributesTableOnMemoryAllocation (MemoryType); + ApplyMemoryProtectionPolicy (EfiConventionalMemory, MemoryType, *Memory, + EFI_PAGES_TO_SIZE (NumberOfPages)); + } + return Status; +} /** Frees previous allocated pages. @param Memory Base address of memory being freed @param NumberOfPages The number of pages to free + @param MemoryType Pointer to memory type @retval EFI_NOT_FOUND Could not find the entry that covers the range @retval EFI_INVALID_PARAMETER Address not aligned @@ -1067,9 +1367,10 @@ Done: **/ EFI_STATUS EFIAPI -CoreFreePages ( +CoreInternalFreePages ( IN EFI_PHYSICAL_ADDRESS Memory, - IN UINTN NumberOfPages + IN UINTN NumberOfPages, + OUT EFI_MEMORY_TYPE *MemoryType OPTIONAL ) { EFI_STATUS Status; @@ -1093,48 +1394,164 @@ CoreFreePages ( } } if (Link == &gMemoryMap) { - CoreReleaseMemoryLock (); - return EFI_NOT_FOUND; + Status = EFI_NOT_FOUND; + goto Done; } - Alignment = EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT; + Alignment = DEFAULT_PAGE_ALLOCATION_GRANULARITY; + ASSERT (Entry != NULL); if (Entry->Type == EfiACPIReclaimMemory || Entry->Type == EfiACPIMemoryNVS || Entry->Type == EfiRuntimeServicesCode || Entry->Type == EfiRuntimeServicesData) { - Alignment = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT; + Alignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY; } if ((Memory & (Alignment - 1)) != 0) { - CoreReleaseMemoryLock (); - return EFI_INVALID_PARAMETER; + Status = EFI_INVALID_PARAMETER; + goto Done; } NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1; NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1); + if (MemoryType != NULL) { + *MemoryType = Entry->Type; + } + Status = CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory); + if (EFI_ERROR (Status)) { + goto Done; + } + +Done: CoreReleaseMemoryLock (); + return Status; +} - if (EFI_ERROR (Status)) { - return Status; +/** + Frees previous allocated pages. + + @param Memory Base address of memory being freed + @param NumberOfPages The number of pages to free + + @retval EFI_NOT_FOUND Could not find the entry that covers the range + @retval EFI_INVALID_PARAMETER Address not aligned + @return EFI_SUCCESS -Pages successfully freed. + +**/ +EFI_STATUS +EFIAPI +CoreFreePages ( + IN EFI_PHYSICAL_ADDRESS Memory, + IN UINTN NumberOfPages + ) +{ + EFI_STATUS Status; + EFI_MEMORY_TYPE MemoryType; + + Status = CoreInternalFreePages (Memory, NumberOfPages, &MemoryType); + if (!EFI_ERROR (Status)) { + CoreUpdateProfile ( + (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0), + MemoryProfileActionFreePages, + MemoryType, + EFI_PAGES_TO_SIZE (NumberOfPages), + (VOID *) (UINTN) Memory, + NULL + ); + InstallMemoryAttributesTableOnMemoryAllocation (MemoryType); + ApplyMemoryProtectionPolicy (MemoryType, EfiConventionalMemory, Memory, + EFI_PAGES_TO_SIZE (NumberOfPages)); } + return Status; +} +/** + This function checks to see if the last memory map descriptor in a memory map + can be merged with any of the other memory map descriptors in a memorymap. + Memory descriptors may be merged if they are adjacent and have the same type + and attributes. + + @param MemoryMap A pointer to the start of the memory map. + @param MemoryMapDescriptor A pointer to the last descriptor in MemoryMap. + @param DescriptorSize The size, in bytes, of an individual + EFI_MEMORY_DESCRIPTOR. + + @return A pointer to the next available descriptor in MemoryMap + +**/ +EFI_MEMORY_DESCRIPTOR * +MergeMemoryMapDescriptor ( + IN EFI_MEMORY_DESCRIPTOR *MemoryMap, + IN EFI_MEMORY_DESCRIPTOR *MemoryMapDescriptor, + IN UINTN DescriptorSize + ) +{ // - // Destroy the contents + // Traverse the array of descriptors in MemoryMap // - if (Memory < MAX_ADDRESS) { - DEBUG_CLEAR_MEMORY ((VOID *)(UINTN)Memory, NumberOfPages << EFI_PAGE_SHIFT); + for (; MemoryMap != MemoryMapDescriptor; MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, DescriptorSize)) { + // + // Check to see if the Type fields are identical. + // + if (MemoryMap->Type != MemoryMapDescriptor->Type) { + continue; + } + + // + // Check to see if the Attribute fields are identical. + // + if (MemoryMap->Attribute != MemoryMapDescriptor->Attribute) { + continue; + } + + // + // Check to see if MemoryMapDescriptor is immediately above MemoryMap + // + if (MemoryMap->PhysicalStart + EFI_PAGES_TO_SIZE ((UINTN)MemoryMap->NumberOfPages) == MemoryMapDescriptor->PhysicalStart) { + // + // Merge MemoryMapDescriptor into MemoryMap + // + MemoryMap->NumberOfPages += MemoryMapDescriptor->NumberOfPages; + + // + // Return MemoryMapDescriptor as the next available slot int he MemoryMap array + // + return MemoryMapDescriptor; + } + + // + // Check to see if MemoryMapDescriptor is immediately below MemoryMap + // + if (MemoryMap->PhysicalStart - EFI_PAGES_TO_SIZE ((UINTN)MemoryMapDescriptor->NumberOfPages) == MemoryMapDescriptor->PhysicalStart) { + // + // Merge MemoryMapDescriptor into MemoryMap + // + MemoryMap->PhysicalStart = MemoryMapDescriptor->PhysicalStart; + MemoryMap->VirtualStart = MemoryMapDescriptor->VirtualStart; + MemoryMap->NumberOfPages += MemoryMapDescriptor->NumberOfPages; + + // + // Return MemoryMapDescriptor as the next available slot int he MemoryMap array + // + return MemoryMapDescriptor; + } } - return Status; + // + // MemoryMapDescrtiptor could not be merged with any descriptors in MemoryMap. + // + // Return the slot immediately after MemoryMapDescriptor as the next available + // slot in the MemoryMap array + // + return NEXT_MEMORY_DESCRIPTOR (MemoryMapDescriptor, DescriptorSize); } - /** This function returns a copy of the current memory map. The map is an array of memory descriptors, each of which describes a contiguous block of memory. @@ -1178,11 +1595,13 @@ CoreGetMemoryMap ( EFI_STATUS Status; UINTN Size; UINTN BufferSize; - UINTN NumberOfRuntimeEntries; + UINTN NumberOfEntries; LIST_ENTRY *Link; MEMORY_MAP *Entry; EFI_GCD_MAP_ENTRY *GcdMapEntry; + EFI_GCD_MAP_ENTRY MergeGcdMapEntry; EFI_MEMORY_TYPE Type; + EFI_MEMORY_DESCRIPTOR *MemoryMapStart; // // Make sure the parameters are valid @@ -1194,16 +1613,17 @@ CoreGetMemoryMap ( CoreAcquireGcdMemoryLock (); // - // Count the number of Reserved and MMIO entries that are marked for runtime use + // Count the number of Reserved and runtime MMIO entries + // And, count the number of Persistent entries. // - NumberOfRuntimeEntries = 0; + NumberOfEntries = 0; for (Link = mGcdMemorySpaceMap.ForwardLink; Link != &mGcdMemorySpaceMap; Link = Link->ForwardLink) { GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE); - if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) || - (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo)) { - if ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME) { - NumberOfRuntimeEntries++; - } + if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypePersistentMemory) || + (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) || + ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) && + ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME))) { + NumberOfEntries ++; } } @@ -1229,7 +1649,7 @@ CoreGetMemoryMap ( // // Compute the buffer size needed to fit the entire map // - BufferSize = Size * NumberOfRuntimeEntries; + BufferSize = Size * NumberOfEntries; for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) { BufferSize += Size; } @@ -1248,6 +1668,7 @@ CoreGetMemoryMap ( // Build the map // ZeroMem (MemoryMap, BufferSize); + MemoryMapStart = MemoryMap; for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) { Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE); ASSERT (Entry->VirtualStart == 0); @@ -1277,50 +1698,122 @@ CoreGetMemoryMap ( } } MemoryMap->Attribute = Entry->Attribute; - if (mMemoryTypeStatistics[MemoryMap->Type].Runtime) { - MemoryMap->Attribute |= EFI_MEMORY_RUNTIME; + if (MemoryMap->Type < EfiMaxMemoryType) { + if (mMemoryTypeStatistics[MemoryMap->Type].Runtime) { + MemoryMap->Attribute |= EFI_MEMORY_RUNTIME; + } } - MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, Size); + // + // Check to see if the new Memory Map Descriptor can be merged with an + // existing descriptor if they are adjacent and have the same attributes + // + MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size); } - for (Link = mGcdMemorySpaceMap.ForwardLink; Link != &mGcdMemorySpaceMap; Link = Link->ForwardLink) { - GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE); - if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) || - (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo)) { - if ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME) { - // - // Create EFI_MEMORY_DESCRIPTOR for every Reserved and MMIO GCD entries - // that are marked for runtime use - // - MemoryMap->PhysicalStart = GcdMapEntry->BaseAddress; - MemoryMap->VirtualStart = 0; - MemoryMap->NumberOfPages = RShiftU64 ((GcdMapEntry->EndAddress - GcdMapEntry->BaseAddress + 1), EFI_PAGE_SHIFT); - MemoryMap->Attribute = GcdMapEntry->Attributes & ~EFI_MEMORY_PORT_IO; - - if (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) { - MemoryMap->Type = EfiReservedMemoryType; - } else if (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) { - if ((GcdMapEntry->Attributes & EFI_MEMORY_PORT_IO) == EFI_MEMORY_PORT_IO) { - MemoryMap->Type = EfiMemoryMappedIOPortSpace; - } else { - MemoryMap->Type = EfiMemoryMappedIO; - } - } + + ZeroMem (&MergeGcdMapEntry, sizeof (MergeGcdMapEntry)); + GcdMapEntry = NULL; + for (Link = mGcdMemorySpaceMap.ForwardLink; ; Link = Link->ForwardLink) { + if (Link != &mGcdMemorySpaceMap) { + // + // Merge adjacent same type and attribute GCD memory range + // + GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE); + + if ((MergeGcdMapEntry.Capabilities == GcdMapEntry->Capabilities) && + (MergeGcdMapEntry.Attributes == GcdMapEntry->Attributes) && + (MergeGcdMapEntry.GcdMemoryType == GcdMapEntry->GcdMemoryType) && + (MergeGcdMapEntry.GcdIoType == GcdMapEntry->GcdIoType)) { + MergeGcdMapEntry.EndAddress = GcdMapEntry->EndAddress; + continue; + } + } - MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, Size); + if ((MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeReserved) || + ((MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) && + ((MergeGcdMapEntry.Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME))) { + // + // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR, + // it will be recorded as page PhysicalStart and NumberOfPages. + // + ASSERT ((MergeGcdMapEntry.BaseAddress & EFI_PAGE_MASK) == 0); + ASSERT (((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1) & EFI_PAGE_MASK) == 0); + + // + // Create EFI_MEMORY_DESCRIPTOR for every Reserved and runtime MMIO GCD entries + // + MemoryMap->PhysicalStart = MergeGcdMapEntry.BaseAddress; + MemoryMap->VirtualStart = 0; + MemoryMap->NumberOfPages = RShiftU64 ((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1), EFI_PAGE_SHIFT); + MemoryMap->Attribute = (MergeGcdMapEntry.Attributes & ~EFI_MEMORY_PORT_IO) | + (MergeGcdMapEntry.Capabilities & (EFI_MEMORY_RP | EFI_MEMORY_WP | EFI_MEMORY_XP | EFI_MEMORY_RO | + EFI_MEMORY_UC | EFI_MEMORY_UCE | EFI_MEMORY_WC | EFI_MEMORY_WT | EFI_MEMORY_WB)); + + if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeReserved) { + MemoryMap->Type = EfiReservedMemoryType; + } else if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) { + if ((MergeGcdMapEntry.Attributes & EFI_MEMORY_PORT_IO) == EFI_MEMORY_PORT_IO) { + MemoryMap->Type = EfiMemoryMappedIOPortSpace; + } else { + MemoryMap->Type = EfiMemoryMappedIO; + } } + + // + // Check to see if the new Memory Map Descriptor can be merged with an + // existing descriptor if they are adjacent and have the same attributes + // + MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size); + } + + if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypePersistentMemory) { + // + // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR, + // it will be recorded as page PhysicalStart and NumberOfPages. + // + ASSERT ((MergeGcdMapEntry.BaseAddress & EFI_PAGE_MASK) == 0); + ASSERT (((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1) & EFI_PAGE_MASK) == 0); + + // + // Create EFI_MEMORY_DESCRIPTOR for every Persistent GCD entries + // + MemoryMap->PhysicalStart = MergeGcdMapEntry.BaseAddress; + MemoryMap->VirtualStart = 0; + MemoryMap->NumberOfPages = RShiftU64 ((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1), EFI_PAGE_SHIFT); + MemoryMap->Attribute = MergeGcdMapEntry.Attributes | EFI_MEMORY_NV | + (MergeGcdMapEntry.Capabilities & (EFI_MEMORY_RP | EFI_MEMORY_WP | EFI_MEMORY_XP | EFI_MEMORY_RO | + EFI_MEMORY_UC | EFI_MEMORY_UCE | EFI_MEMORY_WC | EFI_MEMORY_WT | EFI_MEMORY_WB)); + MemoryMap->Type = EfiPersistentMemory; + + // + // Check to see if the new Memory Map Descriptor can be merged with an + // existing descriptor if they are adjacent and have the same attributes + // + MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size); + } + if (Link == &mGcdMemorySpaceMap) { + // + // break loop when arrive at head. + // + break; + } + if (GcdMapEntry != NULL) { + // + // Copy new GCD map entry for the following GCD range merge + // + CopyMem (&MergeGcdMapEntry, GcdMapEntry, sizeof (MergeGcdMapEntry)); } } + // + // Compute the size of the buffer actually used after all memory map descriptor merge operations + // + BufferSize = ((UINT8 *)MemoryMap - (UINT8 *)MemoryMapStart); + Status = EFI_SUCCESS; Done: - - CoreReleaseMemoryLock (); - - CoreReleaseGcdMemoryLock (); - // // Update the map key finally // @@ -1328,6 +1821,10 @@ Done: *MapKey = mMemoryMapKey; } + CoreReleaseMemoryLock (); + + CoreReleaseGcdMemoryLock (); + *MemoryMapSize = BufferSize; return Status; @@ -1363,7 +1860,7 @@ CoreAllocatePoolPages ( // Convert it to boot services data // if (Start == 0) { - DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "AllocatePoolPages: failed to allocate %d pages\n", NumberOfPages)); + DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "AllocatePoolPages: failed to allocate %d pages\n", (UINT32)NumberOfPages)); } else { CoreConvertPages (Start, NumberOfPages, PoolType); } @@ -1424,21 +1921,20 @@ CoreTerminateMemoryMap ( for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) { Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE); - if ((Entry->Attribute & EFI_MEMORY_RUNTIME) != 0) { - if (Entry->Type == EfiACPIReclaimMemory || Entry->Type == EfiACPIMemoryNVS) { - DEBUG((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: ACPI memory entry has RUNTIME attribute set.\n")); - Status = EFI_INVALID_PARAMETER; - goto Done; - } - if ((Entry->Start & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) != 0) { - DEBUG((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n")); - Status = EFI_INVALID_PARAMETER; - goto Done; - } - if (((Entry->End + 1) & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) != 0) { - DEBUG((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n")); - Status = EFI_INVALID_PARAMETER; - goto Done; + if (Entry->Type < EfiMaxMemoryType) { + if (mMemoryTypeStatistics[Entry->Type].Runtime) { + ASSERT (Entry->Type != EfiACPIReclaimMemory); + ASSERT (Entry->Type != EfiACPIMemoryNVS); + if ((Entry->Start & (RUNTIME_PAGE_ALLOCATION_GRANULARITY - 1)) != 0) { + DEBUG((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n")); + Status = EFI_INVALID_PARAMETER; + goto Done; + } + if (((Entry->End + 1) & (RUNTIME_PAGE_ALLOCATION_GRANULARITY - 1)) != 0) { + DEBUG((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n")); + Status = EFI_INVALID_PARAMETER; + goto Done; + } } } }