/** @file\r
UEFI Heap Guard functions.\r
\r
-Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2017-2018, Intel Corporation. All rights reserved.<BR>\r
This program and the accompanying materials\r
are licensed and made available under the terms and conditions of the BSD License\r
which accompanies this distribution. The full text of the license may be found at\r
StartBit = (UINTN)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address);\r
EndBit = (StartBit + BitNumber - 1) % GUARDED_HEAP_MAP_ENTRY_BITS;\r
\r
- if ((StartBit + BitNumber) > GUARDED_HEAP_MAP_ENTRY_BITS) {\r
+ if ((StartBit + BitNumber) >= GUARDED_HEAP_MAP_ENTRY_BITS) {\r
Msbs = (GUARDED_HEAP_MAP_ENTRY_BITS - StartBit) %\r
GUARDED_HEAP_MAP_ENTRY_BITS;\r
Lsbs = (EndBit + 1) % GUARDED_HEAP_MAP_ENTRY_BITS;\r
StartBit = (UINTN)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address);\r
EndBit = (StartBit + BitNumber - 1) % GUARDED_HEAP_MAP_ENTRY_BITS;\r
\r
- if ((StartBit + BitNumber) > GUARDED_HEAP_MAP_ENTRY_BITS) {\r
+ if ((StartBit + BitNumber) >= GUARDED_HEAP_MAP_ENTRY_BITS) {\r
Msbs = (GUARDED_HEAP_MAP_ENTRY_BITS - StartBit) %\r
GUARDED_HEAP_MAP_ENTRY_BITS;\r
Lsbs = (EndBit + 1) % GUARDED_HEAP_MAP_ENTRY_BITS;\r
Lsbs = 0;\r
}\r
\r
- Result = RShiftU64 ((*BitMap), StartBit) & (LShiftU64 (1, Msbs) - 1);\r
- if (Lsbs > 0) {\r
- BitMap += 1;\r
- Result |= LShiftU64 ((*BitMap) & (LShiftU64 (1, Lsbs) - 1), Msbs);\r
+ if (StartBit == 0 && BitNumber == GUARDED_HEAP_MAP_ENTRY_BITS) {\r
+ Result = *BitMap;\r
+ } else {\r
+ Result = RShiftU64((*BitMap), StartBit) & (LShiftU64(1, Msbs) - 1);\r
+ if (Lsbs > 0) {\r
+ BitMap += 1;\r
+ Result |= LShiftU64 ((*BitMap) & (LShiftU64 (1, Lsbs) - 1), Msbs);\r
+ }\r
}\r
\r
return Result;\r
//\r
// Adjust current map table depth according to the address to access\r
//\r
- while (mMapLevel < GUARDED_HEAP_MAP_TABLE_DEPTH\r
- &&\r
+ while (AllocMapUnit &&\r
+ mMapLevel < GUARDED_HEAP_MAP_TABLE_DEPTH &&\r
RShiftU64 (\r
Address,\r
mLevelShift[GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel - 1]\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
- Target = Start + Size - SizeRequested;\r
-\r
//\r
- // At least one more page needed for Guard page.\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 (Size < (SizeRequested + EFI_PAGES_TO_SIZE (1))) {\r
+ if ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0) {\r
+ SizeRequested = ALIGN_VALUE(SizeRequested, 8);\r
+ }\r
+\r
+ Target = Start + Size - SizeRequested;\r
+ ASSERT (Target >= Start);\r
+ if (Target == 0) {\r
return 0;\r
}\r
\r
EFI_PHYSICAL_ADDRESS Start;\r
EFI_PHYSICAL_ADDRESS MemoryToTest;\r
UINTN PagesToFree;\r
+ UINT64 GuardBitmap;\r
+ UINT64 Attributes;\r
\r
if (Memory == NULL || NumberOfPages == NULL || *NumberOfPages == 0) {\r
return;\r
Start = *Memory;\r
PagesToFree = *NumberOfPages;\r
\r
+ //\r
+ // In case the memory to free is marked as read-only (e.g. EfiRuntimeServicesCode).\r
+ //\r
+ if (mSmmMemoryAttribute != NULL) {\r
+ Attributes = 0;\r
+ mSmmMemoryAttribute->GetMemoryAttributes (\r
+ mSmmMemoryAttribute,\r
+ Start,\r
+ EFI_PAGES_TO_SIZE (PagesToFree),\r
+ &Attributes\r
+ );\r
+ if ((Attributes & EFI_MEMORY_RO) != 0) {\r
+ mSmmMemoryAttribute->ClearMemoryAttributes (\r
+ mSmmMemoryAttribute,\r
+ Start,\r
+ EFI_PAGES_TO_SIZE (PagesToFree),\r
+ EFI_MEMORY_RO\r
+ );\r
+ }\r
+ }\r
+\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
EFI_PHYSICAL_ADDRESS MemoryToFree;\r
UINTN PagesToFree;\r
\r
+ if (((Memory & EFI_PAGE_MASK) != 0) || (Memory == 0) || (NumberOfPages == 0)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
MemoryToFree = Memory;\r
PagesToFree = NumberOfPages;\r
\r
AdjustMemoryF (&MemoryToFree, &PagesToFree);\r
UnsetGuardForMemory (Memory, NumberOfPages);\r
+ if (PagesToFree == 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
\r
return SmmInternalFreePagesEx (MemoryToFree, PagesToFree, AddRegion);\r
}\r