X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=MdeModulePkg%2FCore%2FDxe%2FMem%2FPage.c;h=962ae90d3dd68e48708761bff4610750a20ee9bd;hp=7e8fa94d7d4fe33d589f9c172281c8d0de5436e9;hb=e38451cd9a87f86d9c699281252d381e10dcc98e;hpb=4879e13097830f9c7cb924a674bcf96cb7686baf diff --git a/MdeModulePkg/Core/Dxe/Mem/Page.c b/MdeModulePkg/Core/Dxe/Mem/Page.c index 7e8fa94d7d..962ae90d3d 100644 --- a/MdeModulePkg/Core/Dxe/Mem/Page.c +++ b/MdeModulePkg/Core/Dxe/Mem/Page.c @@ -1,7 +1,7 @@ /** @file UEFI Memory page management functions. -Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.
+Copyright (c) 2007 - 2017, 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 @@ -14,8 +14,7 @@ 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) +#include "HeapGuard.h" // // Entry for tracking the memory regions for each memory type to coalesce similar memory types @@ -190,7 +189,9 @@ CoreAddRange ( // used for other purposes. // if (Type == EfiConventionalMemory && Start == 0 && (End >= EFI_PAGE_SIZE - 1)) { - SetMem ((VOID *)(UINTN)Start, EFI_PAGE_SIZE, 0); + if ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT0) == 0) { + SetMem ((VOID *)(UINTN)Start, EFI_PAGE_SIZE, 0); + } } // @@ -287,12 +288,17 @@ 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, + FALSE + ); + 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); } @@ -754,6 +760,17 @@ CoreConvertPagesEx ( return EFI_NOT_FOUND; } + // + // If we are converting the type of the range from EfiConventionalMemory to + // another type, we have to ensure that the entire range is covered by a + // single entry. + // + if (ChangingType && (NewType != EfiConventionalMemory)) { + if (Entry->End < End) { + DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ConvertPages: range %lx - %lx covers multiple entries\n", Start, End)); + return EFI_NOT_FOUND; + } + } // // Convert range to the end, or to the end of the descriptor // if that's all we've got @@ -777,7 +794,12 @@ CoreConvertPagesEx ( // 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")); + DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ConvertPages: Incompatible memory types, ")); + if (Entry->Type == EfiConventionalMemory) { + DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "the pages to free have been freed\n")); + } else { + DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "the pages to allocate have been allocated\n")); + } return EFI_NOT_FOUND; } @@ -878,17 +900,41 @@ CoreConvertPagesEx ( // 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) { + // + // 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 (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)); + // + // If Heap Guard is enabled, the page at the top and/or bottom of + // this memory block to free might be inaccessible. Skipping them + // to avoid page fault exception. + // + UINT64 StartToClear; + UINT64 EndToClear; + + StartToClear = Start; + EndToClear = RangeEnd; + if (PcdGet8 (PcdHeapGuardPropertyMask) & (BIT1|BIT0)) { + if (IsGuardPage(StartToClear)) { + StartToClear += EFI_PAGE_SIZE; + } + if (IsGuardPage (EndToClear)) { + EndToClear -= EFI_PAGE_SIZE; + } + ASSERT (EndToClear > StartToClear); + } + + DEBUG_CLEAR_MEMORY( + (VOID *)(UINTN)StartToClear, + (UINTN)(EndToClear - StartToClear + 1) + ); } } @@ -975,6 +1021,7 @@ CoreUpdateMemoryAttributes ( @param NewType The type of memory the range is going to be turned into @param Alignment Bits to align with + @param NeedGuard Flag to indicate Guard page is needed or not @return The base address of the range, or 0 if the range was not found @@ -985,7 +1032,8 @@ CoreFindFreePagesI ( IN UINT64 MinAddress, IN UINT64 NumberOfPages, IN EFI_MEMORY_TYPE NewType, - IN UINTN Alignment + IN UINTN Alignment, + IN BOOLEAN NeedGuard ) { UINT64 NumberOfBytes; @@ -1077,6 +1125,17 @@ CoreFindFreePagesI ( // If this is the best match so far remember it // if (DescEnd > Target) { + if (NeedGuard) { + DescEnd = AdjustMemoryS ( + DescEnd + 1 - DescNumberOfBytes, + DescNumberOfBytes, + NumberOfBytes + ); + if (DescEnd == 0) { + continue; + } + } + Target = DescEnd; } } @@ -1107,6 +1166,7 @@ CoreFindFreePagesI ( @param NewType The type of memory the range is going to be turned into @param Alignment Bits to align with + @param NeedGuard Flag to indicate Guard page is needed or not @return The base address of the range, or 0 if the range was not found. @@ -1116,7 +1176,8 @@ FindFreePages ( IN UINT64 MaxAddress, IN UINT64 NoPages, IN EFI_MEMORY_TYPE NewType, - IN UINTN Alignment + IN UINTN Alignment, + IN BOOLEAN NeedGuard ) { UINT64 Start; @@ -1130,7 +1191,8 @@ FindFreePages ( mMemoryTypeStatistics[NewType].BaseAddress, NoPages, NewType, - Alignment + Alignment, + NeedGuard ); if (Start != 0) { return Start; @@ -1141,7 +1203,8 @@ FindFreePages ( // Attempt to find free pages in the default allocation bin // if (MaxAddress >= mDefaultMaximumAddress) { - Start = CoreFindFreePagesI (mDefaultMaximumAddress, 0, NoPages, NewType, Alignment); + Start = CoreFindFreePagesI (mDefaultMaximumAddress, 0, NoPages, NewType, + Alignment, NeedGuard); if (Start != 0) { if (Start < mDefaultBaseAddress) { mDefaultBaseAddress = Start; @@ -1156,7 +1219,8 @@ FindFreePages ( // address range. If this allocation fails, then there are not enough // resources anywhere to satisfy the request. // - Start = CoreFindFreePagesI (MaxAddress, 0, NoPages, NewType, Alignment); + Start = CoreFindFreePagesI (MaxAddress, 0, NoPages, NewType, Alignment, + NeedGuard); if (Start != 0) { return Start; } @@ -1171,7 +1235,7 @@ FindFreePages ( // // If any memory resources were promoted, then re-attempt the allocation // - return FindFreePages (MaxAddress, NoPages, NewType, Alignment); + return FindFreePages (MaxAddress, NoPages, NewType, Alignment, NeedGuard); } @@ -1184,6 +1248,7 @@ FindFreePages ( @param NumberOfPages The number of pages to allocate @param Memory A pointer to receive the base allocated memory address + @param NeedGuard Flag to indicate Guard page is needed or not @return Status. On success, Memory is filled in with the base address allocated @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in @@ -1199,7 +1264,8 @@ CoreInternalAllocatePages ( IN EFI_ALLOCATE_TYPE Type, IN EFI_MEMORY_TYPE MemoryType, IN UINTN NumberOfPages, - IN OUT EFI_PHYSICAL_ADDRESS *Memory + IN OUT EFI_PHYSICAL_ADDRESS *Memory, + IN BOOLEAN NeedGuard ) { EFI_STATUS Status; @@ -1222,14 +1288,14 @@ CoreInternalAllocatePages ( 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) { @@ -1285,7 +1351,8 @@ CoreInternalAllocatePages ( // If not a specific address, then find an address to allocate // if (Type != AllocateAddress) { - Start = FindFreePages (MaxAddress, NumberOfPages, MemoryType, Alignment); + Start = FindFreePages (MaxAddress, NumberOfPages, MemoryType, Alignment, + NeedGuard); if (Start == 0) { Status = EFI_OUT_OF_RESOURCES; goto Done; @@ -1295,12 +1362,19 @@ CoreInternalAllocatePages ( // // Convert pages from FreeMemory to the requested type // - Status = CoreConvertPages (Start, NumberOfPages, MemoryType); + if (NeedGuard) { + Status = CoreConvertPagesWithGuard(Start, NumberOfPages, MemoryType); + } else { + Status = CoreConvertPages(Start, NumberOfPages, MemoryType); + } Done: CoreReleaseMemoryLock (); if (!EFI_ERROR (Status)) { + if (NeedGuard) { + SetGuardForMemory (Start, NumberOfPages); + } *Memory = Start; } @@ -1335,8 +1409,11 @@ CoreAllocatePages ( ) { EFI_STATUS Status; + BOOLEAN NeedGuard; - Status = CoreInternalAllocatePages (Type, MemoryType, NumberOfPages, Memory); + NeedGuard = IsPageTypeToGuard (MemoryType, Type) && !mOnGuarding; + Status = CoreInternalAllocatePages (Type, MemoryType, NumberOfPages, Memory, + NeedGuard); if (!EFI_ERROR (Status)) { CoreUpdateProfile ( (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0), @@ -1377,6 +1454,7 @@ CoreInternalFreePages ( LIST_ENTRY *Link; MEMORY_MAP *Entry; UINTN Alignment; + BOOLEAN IsGuarded; // // Free the range @@ -1386,6 +1464,7 @@ CoreInternalFreePages ( // // Find the entry that the covers the range // + IsGuarded = FALSE; Entry = NULL; for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) { Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE); @@ -1398,7 +1477,7 @@ CoreInternalFreePages ( goto Done; } - Alignment = EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT; + Alignment = DEFAULT_PAGE_ALLOCATION_GRANULARITY; ASSERT (Entry != NULL); if (Entry->Type == EfiACPIReclaimMemory || @@ -1406,7 +1485,7 @@ CoreInternalFreePages ( Entry->Type == EfiRuntimeServicesCode || Entry->Type == EfiRuntimeServicesData) { - Alignment = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT; + Alignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY; } @@ -1422,14 +1501,20 @@ CoreInternalFreePages ( *MemoryType = Entry->Type; } - Status = CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory); - - if (EFI_ERROR (Status)) { - goto Done; + IsGuarded = IsPageTypeToGuard (Entry->Type, AllocateAnyPages) && + IsMemoryGuarded (Memory); + if (IsGuarded) { + Status = CoreConvertPagesWithGuard (Memory, NumberOfPages, + EfiConventionalMemory); + } else { + Status = CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory); } Done: CoreReleaseMemoryLock (); + if (IsGuarded) { + UnsetGuardForMemory(Memory, NumberOfPages); + } return Status; } @@ -1602,6 +1687,7 @@ CoreGetMemoryMap ( EFI_GCD_MAP_ENTRY MergeGcdMapEntry; EFI_MEMORY_TYPE Type; EFI_MEMORY_DESCRIPTOR *MemoryMapStart; + EFI_MEMORY_DESCRIPTOR *MemoryMapEnd; // // Make sure the parameters are valid @@ -1619,7 +1705,7 @@ CoreGetMemoryMap ( 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 == EfiGcdMemoryTypePersistentMemory) || + if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypePersistent) || (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) || ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) && ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME))) { @@ -1767,7 +1853,7 @@ CoreGetMemoryMap ( MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size); } - if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypePersistentMemory) { + if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypePersistent) { // // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR, // it will be recorded as page PhysicalStart and NumberOfPages. @@ -1811,6 +1897,25 @@ CoreGetMemoryMap ( // BufferSize = ((UINT8 *)MemoryMap - (UINT8 *)MemoryMapStart); + // + // Note: Some OSs will treat EFI_MEMORY_DESCRIPTOR.Attribute as really + // set attributes and change memory paging attribute accordingly. + // But current EFI_MEMORY_DESCRIPTOR.Attribute is assigned by + // value from Capabilities in GCD memory map. This might cause + // boot problems. Clearing all paging related capabilities can + // workaround it. Following code is supposed to be removed once + // the usage of EFI_MEMORY_DESCRIPTOR.Attribute is clarified in + // UEFI spec and adopted by both EDK-II Core and all supported + // OSs. + // + MemoryMapEnd = MemoryMap; + MemoryMap = MemoryMapStart; + while (MemoryMap < MemoryMapEnd) { + MemoryMap->Attribute &= ~(UINT64)(EFI_MEMORY_RP | EFI_MEMORY_RO | + EFI_MEMORY_XP); + MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, Size); + } + Status = EFI_SUCCESS; Done: @@ -1827,6 +1932,12 @@ Done: *MemoryMapSize = BufferSize; + DEBUG_CODE ( + if (PcdGet8 (PcdHeapGuardPropertyMask) & (BIT1|BIT0)) { + DumpGuardedMemoryBitmap (); + } + ); + return Status; } @@ -1838,6 +1949,7 @@ Done: @param PoolType The type of memory for the new pool pages @param NumberOfPages No of pages to allocate @param Alignment Bits to align. + @param NeedGuard Flag to indicate Guard page is needed or not @return The allocated memory, or NULL @@ -1846,7 +1958,8 @@ VOID * CoreAllocatePoolPages ( IN EFI_MEMORY_TYPE PoolType, IN UINTN NumberOfPages, - IN UINTN Alignment + IN UINTN Alignment, + IN BOOLEAN NeedGuard ) { UINT64 Start; @@ -1854,7 +1967,8 @@ CoreAllocatePoolPages ( // // Find the pages to convert // - Start = FindFreePages (MAX_ADDRESS, NumberOfPages, PoolType, Alignment); + Start = FindFreePages (MAX_ADDRESS, NumberOfPages, PoolType, Alignment, + NeedGuard); // // Convert it to boot services data @@ -1862,7 +1976,11 @@ CoreAllocatePoolPages ( if (Start == 0) { DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "AllocatePoolPages: failed to allocate %d pages\n", (UINT32)NumberOfPages)); } else { - CoreConvertPages (Start, NumberOfPages, PoolType); + if (NeedGuard) { + CoreConvertPagesWithGuard (Start, NumberOfPages, PoolType); + } else { + CoreConvertPages (Start, NumberOfPages, PoolType); + } } return (VOID *)(UINTN) Start; @@ -1925,12 +2043,12 @@ CoreTerminateMemoryMap ( if (mMemoryTypeStatistics[Entry->Type].Runtime) { ASSERT (Entry->Type != EfiACPIReclaimMemory); ASSERT (Entry->Type != EfiACPIMemoryNVS); - if ((Entry->Start & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) != 0) { + 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) & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) != 0) { + 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;