mOnGuarding = TRUE;\r
//\r
// Note: This might overwrite other attributes needed by other features,\r
- // such as memory protection (NX). Please make sure they are not enabled\r
- // at the same time.\r
+ // such as NX memory protection.\r
//\r
gCpu->SetMemoryAttributes (gCpu, BaseAddress, EFI_PAGE_SIZE, EFI_MEMORY_RP);\r
mOnGuarding = FALSE;\r
IN EFI_PHYSICAL_ADDRESS BaseAddress\r
)\r
{\r
+ UINT64 Attributes;\r
+\r
+ //\r
+ // Once the Guard page is unset, it will be freed back to memory pool. NX\r
+ // memory protection must be restored for this page if NX is enabled for free\r
+ // memory.\r
+ //\r
+ Attributes = 0;\r
+ if ((PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & (1 << EfiConventionalMemory)) != 0) {\r
+ Attributes |= EFI_MEMORY_XP;\r
+ }\r
+\r
//\r
// Set flag to make sure allocating memory without GUARD for page table\r
// operation; otherwise infinite loops could be caused.\r
// such as memory protection (NX). Please make sure they are not enabled\r
// at the same time.\r
//\r
- gCpu->SetMemoryAttributes (gCpu, BaseAddress, EFI_PAGE_SIZE, 0);\r
+ gCpu->SetMemoryAttributes (gCpu, BaseAddress, EFI_PAGE_SIZE, Attributes);\r
mOnGuarding = FALSE;\r
}\r
\r
return IsMemoryTypeToGuard (MemoryType, AllocateType, GUARD_HEAP_TYPE_PAGE);\r
}\r
\r
+/**\r
+ Check to see if the heap guard is enabled for page and/or pool allocation.\r
+\r
+ @return TRUE/FALSE.\r
+**/\r
+BOOLEAN\r
+IsHeapGuardEnabled (\r
+ VOID\r
+ )\r
+{\r
+ return IsMemoryTypeToGuard (EfiMaxMemoryType, AllocateAnyPages,\r
+ GUARD_HEAP_TYPE_POOL|GUARD_HEAP_TYPE_PAGE);\r
+}\r
+\r
/**\r
Set head Guard and tail Guard for the given memory range.\r
\r
)\r
{\r
EFI_PHYSICAL_ADDRESS GuardPage;\r
+ UINT64 GuardBitmap;\r
\r
if (NumberOfPages == 0) {\r
return;\r
//\r
// Head Guard must be one page before, if any.\r
//\r
+ // MSB-> 1 0 <-LSB\r
+ // -------------------\r
+ // Head Guard -> 0 1 -> Don't free Head Guard (shared Guard)\r
+ // Head Guard -> 0 0 -> Free Head Guard either (not shared Guard)\r
+ // 1 X -> Don't free first page (need a new Guard)\r
+ // (it'll be turned into a Guard page later)\r
+ // -------------------\r
+ // Start -> -1 -2\r
+ //\r
GuardPage = Memory - EFI_PAGES_TO_SIZE (1);\r
- if (IsHeadGuard (GuardPage)) {\r
- if (!IsMemoryGuarded (GuardPage - EFI_PAGES_TO_SIZE (1))) {\r
+ GuardBitmap = GetGuardedMemoryBits (Memory - EFI_PAGES_TO_SIZE (2), 2);\r
+ if ((GuardBitmap & BIT1) == 0) {\r
+ //\r
+ // Head Guard exists.\r
+ //\r
+ if ((GuardBitmap & BIT0) == 0) {\r
//\r
// If the head Guard is not a tail Guard of adjacent memory block,\r
// unset it.\r
//\r
UnsetGuardPage (GuardPage);\r
}\r
- } else if (IsMemoryGuarded (GuardPage)) {\r
+ } else {\r
//\r
// Pages before memory to free are still in Guard. It's a partial free\r
// case. Turn first page of memory block to free into a new Guard.\r
//\r
// Tail Guard must be the page after this memory block to free, if any.\r
//\r
+ // MSB-> 1 0 <-LSB\r
+ // --------------------\r
+ // 1 0 <- Tail Guard -> Don't free Tail Guard (shared Guard)\r
+ // 0 0 <- Tail Guard -> Free Tail Guard either (not shared Guard)\r
+ // X 1 -> Don't free last page (need a new Guard)\r
+ // (it'll be turned into a Guard page later)\r
+ // --------------------\r
+ // +1 +0 <- End\r
+ //\r
GuardPage = Memory + EFI_PAGES_TO_SIZE (NumberOfPages);\r
- if (IsTailGuard (GuardPage)) {\r
- if (!IsMemoryGuarded (GuardPage + EFI_PAGES_TO_SIZE (1))) {\r
+ GuardBitmap = GetGuardedMemoryBits (GuardPage, 2);\r
+ if ((GuardBitmap & BIT0) == 0) {\r
+ //\r
+ // Tail Guard exists.\r
+ //\r
+ if ((GuardBitmap & BIT1) == 0) {\r
//\r
// If the tail Guard is not a head Guard of adjacent memory block,\r
// free it; otherwise, keep it.\r
//\r
UnsetGuardPage (GuardPage);\r
}\r
- } else if (IsMemoryGuarded (GuardPage)) {\r
+ } else {\r
//\r
// Pages after memory to free are still in Guard. It's a partial free\r
// case. We need to keep one page to be a head Guard.\r
{\r
UINT64 Target;\r
\r
+ //\r
+ // UEFI spec requires that allocated pool must be 8-byte aligned. If it's\r
+ // indicated to put the pool near the Tail Guard, we need extra bytes to\r
+ // make sure alignment of the returned pool address.\r
+ //\r
+ if ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0) {\r
+ SizeRequested = ALIGN_VALUE(SizeRequested, 8);\r
+ }\r
+\r
Target = Start + Size - SizeRequested;\r
\r
//\r
EFI_PHYSICAL_ADDRESS Start;\r
EFI_PHYSICAL_ADDRESS MemoryToTest;\r
UINTN PagesToFree;\r
+ UINT64 GuardBitmap;\r
\r
if (Memory == NULL || NumberOfPages == NULL || *NumberOfPages == 0) {\r
return;\r
//\r
// Head Guard must be one page before, if any.\r
//\r
- MemoryToTest = Start - EFI_PAGES_TO_SIZE (1);\r
- if (IsHeadGuard (MemoryToTest)) {\r
- if (!IsMemoryGuarded (MemoryToTest - EFI_PAGES_TO_SIZE (1))) {\r
+ // MSB-> 1 0 <-LSB\r
+ // -------------------\r
+ // Head Guard -> 0 1 -> Don't free Head Guard (shared Guard)\r
+ // Head Guard -> 0 0 -> Free Head Guard either (not shared Guard)\r
+ // 1 X -> Don't free first page (need a new Guard)\r
+ // (it'll be turned into a Guard page later)\r
+ // -------------------\r
+ // Start -> -1 -2\r
+ //\r
+ MemoryToTest = Start - EFI_PAGES_TO_SIZE (2);\r
+ GuardBitmap = GetGuardedMemoryBits (MemoryToTest, 2);\r
+ if ((GuardBitmap & BIT1) == 0) {\r
+ //\r
+ // Head Guard exists.\r
+ //\r
+ if ((GuardBitmap & BIT0) == 0) {\r
//\r
// If the head Guard is not a tail Guard of adjacent memory block,\r
// free it; otherwise, keep it.\r
Start -= EFI_PAGES_TO_SIZE (1);\r
PagesToFree += 1;\r
}\r
- } else if (IsMemoryGuarded (MemoryToTest)) {\r
+ } else {\r
//\r
- // Pages before memory to free are still in Guard. It's a partial free\r
- // case. We need to keep one page to be a tail Guard.\r
+ // No Head Guard, and pages before memory to free are still in Guard. It's a\r
+ // partial free case. We need to keep one page to be a tail Guard.\r
//\r
Start += EFI_PAGES_TO_SIZE (1);\r
PagesToFree -= 1;\r
//\r
// Tail Guard must be the page after this memory block to free, if any.\r
//\r
+ // MSB-> 1 0 <-LSB\r
+ // --------------------\r
+ // 1 0 <- Tail Guard -> Don't free Tail Guard (shared Guard)\r
+ // 0 0 <- Tail Guard -> Free Tail Guard either (not shared Guard)\r
+ // X 1 -> Don't free last page (need a new Guard)\r
+ // (it'll be turned into a Guard page later)\r
+ // --------------------\r
+ // +1 +0 <- End\r
+ //\r
MemoryToTest = Start + EFI_PAGES_TO_SIZE (PagesToFree);\r
- if (IsTailGuard (MemoryToTest)) {\r
- if (!IsMemoryGuarded (MemoryToTest + EFI_PAGES_TO_SIZE (1))) {\r
+ GuardBitmap = GetGuardedMemoryBits (MemoryToTest, 2);\r
+ if ((GuardBitmap & BIT0) == 0) {\r
+ //\r
+ // Tail Guard exists.\r
+ //\r
+ if ((GuardBitmap & BIT1) == 0) {\r
//\r
// If the tail Guard is not a head Guard of adjacent memory block,\r
// free it; otherwise, keep it.\r
//\r
PagesToFree += 1;\r
}\r
- } else if (IsMemoryGuarded (MemoryToTest)) {\r
+ } else if (PagesToFree > 0) {\r
//\r
- // Pages after memory to free are still in Guard. It's a partial free\r
- // case. We need to keep one page to be a head Guard.\r
+ // No Tail Guard, and pages after memory to free are still in Guard. It's a\r
+ // partial free case. We need to keep one page to be a head Guard.\r
//\r
PagesToFree -= 1;\r
}\r
IN UINTN Size\r
)\r
{\r
- if ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) != 0) {\r
+ if (Memory == 0 || (PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) != 0) {\r
//\r
// Pool head is put near the head Guard\r
//\r
//\r
// Pool head is put near the tail Guard\r
//\r
+ Size = ALIGN_VALUE (Size, 8);\r
return (VOID *)(UINTN)(Memory + EFI_PAGES_TO_SIZE (NoPages) - Size);\r
}\r
\r
IN EFI_PHYSICAL_ADDRESS Memory\r
)\r
{\r
- if ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) != 0) {\r
+ if (Memory == 0 || (PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) != 0) {\r
//\r
// Pool head is put near the head Guard\r
//\r
IN EFI_MEMORY_TYPE NewType\r
)\r
{\r
+ UINT64 OldStart;\r
+ UINTN OldPages;\r
+\r
if (NewType == EfiConventionalMemory) {\r
+ OldStart = Start;\r
+ OldPages = NumberOfPages;\r
+\r
AdjustMemoryF (&Start, &NumberOfPages);\r
+ //\r
+ // It's safe to unset Guard page inside memory lock because there should\r
+ // be no memory allocation occurred in updating memory page attribute at\r
+ // this point. And unsetting Guard page before free will prevent Guard\r
+ // page just freed back to pool from being allocated right away before\r
+ // marking it usable (from non-present to present).\r
+ //\r
+ UnsetGuardForMemory (OldStart, OldPages);\r
+ if (NumberOfPages == 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
} else {\r
AdjustMemoryA (&Start, &NumberOfPages);\r
}\r
\r
- return CoreConvertPages(Start, NumberOfPages, NewType);\r
+ return CoreConvertPages (Start, NumberOfPages, NewType);\r
}\r
\r
/**\r
CHAR8 *Ruler1;\r
CHAR8 *Ruler2;\r
\r
- if (mGuardedMemoryMap == 0) {\r
+ if (mGuardedMemoryMap == 0 ||\r
+ mMapLevel == 0 ||\r
+ mMapLevel > GUARDED_HEAP_MAP_TABLE_DEPTH) {\r
return;\r
}\r
\r