]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Core/Dxe/Mem/Pool.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Mem / Pool.c
index 5eced88efb7572f620862783d23df74863806cfb..734fc94bf6129ad20f3e8846c9cf13aaee7266ab 100644 (file)
@@ -1,19 +1,16 @@
 /** @file\r
   UEFI Memory pool management functions.\r
 \r
-Copyright (c) 2006 - 2016, 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
-http://opensource.org/licenses/bsd-license.php\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
 #include "DxeMain.h"\r
 #include "Imem.h"\r
+#include "HeapGuard.h"\r
+\r
+STATIC EFI_LOCK mPoolMemoryLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);\r
 \r
 #define POOL_FREE_SIGNATURE   SIGNATURE_32('p','f','r','0')\r
 typedef struct {\r
@@ -23,7 +20,8 @@ typedef struct {
 } POOL_FREE;\r
 \r
 \r
-#define POOL_HEAD_SIGNATURE   SIGNATURE_32('p','h','d','0')\r
+#define POOL_HEAD_SIGNATURE       SIGNATURE_32('p','h','d','0')\r
+#define POOLPAGE_HEAD_SIGNATURE   SIGNATURE_32('p','h','d','1')\r
 typedef struct {\r
   UINT32          Signature;\r
   UINT32          Reserved;\r
@@ -52,13 +50,13 @@ typedef struct {
 // as we would in a strict power-of-2 sequence\r
 //\r
 STATIC CONST UINT16 mPoolSizeTable[] = {\r
-  64, 128, 192, 320, 512, 832, 1344, 2176, 3520, 5696, 9216, 14912, 24128\r
+  128, 256, 384, 640, 1024, 1664, 2688, 4352, 7040, 11392, 18432, 29824\r
 };\r
 \r
 #define SIZE_TO_LIST(a)   (GetPoolIndexFromSize (a))\r
 #define LIST_TO_SIZE(a)   (mPoolSizeTable [a])\r
 \r
-#define MAX_POOL_LIST     (sizeof (mPoolSizeTable) / sizeof (mPoolSizeTable[0]))\r
+#define MAX_POOL_LIST     (ARRAY_SIZE (mPoolSizeTable))\r
 \r
 #define MAX_POOL_SIZE     (MAX_ADDRESS - POOL_OVERHEAD)\r
 \r
@@ -167,7 +165,7 @@ LookupPoolHead (
       }\r
     }\r
 \r
-    Pool = CoreAllocatePoolI (EfiBootServicesData, sizeof (POOL));\r
+    Pool = CoreAllocatePoolI (EfiBootServicesData, sizeof (POOL), FALSE);\r
     if (Pool == NULL) {\r
       return NULL;\r
     }\r
@@ -212,7 +210,8 @@ CoreInternalAllocatePool (
   OUT VOID            **Buffer\r
   )\r
 {\r
-  EFI_STATUS    Status;\r
+  EFI_STATUS            Status;\r
+  BOOLEAN               NeedGuard;\r
 \r
   //\r
   // If it's not a valid type, fail it\r
@@ -236,16 +235,18 @@ CoreInternalAllocatePool (
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
+  NeedGuard = IsPoolTypeToGuard (PoolType) && !mOnGuarding;\r
+\r
   //\r
   // Acquire the memory lock and make the allocation\r
   //\r
-  Status = CoreAcquireLockOrFail (&gMemoryLock);\r
+  Status = CoreAcquireLockOrFail (&mPoolMemoryLock);\r
   if (EFI_ERROR (Status)) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
-  *Buffer = CoreAllocatePoolI (PoolType, Size);\r
-  CoreReleaseMemoryLock ();\r
+  *Buffer = CoreAllocatePoolI (PoolType, Size, NeedGuard);\r
+  CoreReleaseLock (&mPoolMemoryLock);\r
   return (*Buffer != NULL) ? EFI_SUCCESS : EFI_OUT_OF_RESOURCES;\r
 }\r
 \r
@@ -276,18 +277,68 @@ CoreAllocatePool (
 \r
   Status = CoreInternalAllocatePool (PoolType, Size, Buffer);\r
   if (!EFI_ERROR (Status)) {\r
-    CoreUpdateProfile ((EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0), MemoryProfileActionAllocatePool, PoolType, Size, *Buffer);\r
+    CoreUpdateProfile (\r
+      (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),\r
+      MemoryProfileActionAllocatePool,\r
+      PoolType,\r
+      Size,\r
+      *Buffer,\r
+      NULL\r
+      );\r
     InstallMemoryAttributesTableOnMemoryAllocation (PoolType);\r
   }\r
   return Status;\r
 }\r
 \r
+/**\r
+  Internal function.  Used by the pool functions to allocate pages\r
+  to back pool allocation requests.\r
+\r
+  @param  PoolType               The type of memory for the new pool pages\r
+  @param  NoPages                No of pages to allocate\r
+  @param  Granularity            Bits to align.\r
+  @param  NeedGuard              Flag to indicate Guard page is needed or not\r
+\r
+  @return The allocated memory, or NULL\r
+\r
+**/\r
+STATIC\r
+VOID *\r
+CoreAllocatePoolPagesI (\r
+  IN EFI_MEMORY_TYPE    PoolType,\r
+  IN UINTN              NoPages,\r
+  IN UINTN              Granularity,\r
+  IN BOOLEAN            NeedGuard\r
+  )\r
+{\r
+  VOID        *Buffer;\r
+  EFI_STATUS  Status;\r
+\r
+  Status = CoreAcquireLockOrFail (&gMemoryLock);\r
+  if (EFI_ERROR (Status)) {\r
+    return NULL;\r
+  }\r
+\r
+  Buffer = CoreAllocatePoolPages (PoolType, NoPages, Granularity, NeedGuard);\r
+  CoreReleaseMemoryLock ();\r
+\r
+  if (Buffer != NULL) {\r
+    if (NeedGuard) {\r
+      SetGuardForMemory ((EFI_PHYSICAL_ADDRESS)(UINTN)Buffer, NoPages);\r
+    }\r
+    ApplyMemoryProtectionPolicy(EfiConventionalMemory, PoolType,\r
+      (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer, EFI_PAGES_TO_SIZE (NoPages));\r
+  }\r
+  return Buffer;\r
+}\r
+\r
 /**\r
   Internal function to allocate pool of a particular type.\r
   Caller must have the memory lock held\r
 \r
   @param  PoolType               Type of pool to allocate\r
   @param  Size                   The amount of pool to allocate\r
+  @param  NeedGuard              Flag to indicate Guard page is needed or not\r
 \r
   @return The allocate pool, or NULL\r
 \r
@@ -295,7 +346,8 @@ CoreAllocatePool (
 VOID *\r
 CoreAllocatePoolI (\r
   IN EFI_MEMORY_TYPE  PoolType,\r
-  IN UINTN            Size\r
+  IN UINTN            Size,\r
+  IN BOOLEAN          NeedGuard\r
   )\r
 {\r
   POOL        *Pool;\r
@@ -309,23 +361,29 @@ CoreAllocatePoolI (
   UINTN       Offset, MaxOffset;\r
   UINTN       NoPages;\r
   UINTN       Granularity;\r
+  BOOLEAN     HasPoolTail;\r
+  BOOLEAN     PageAsPool;\r
 \r
-  ASSERT_LOCKED (&gMemoryLock);\r
+  ASSERT_LOCKED (&mPoolMemoryLock);\r
 \r
   if  (PoolType == EfiACPIReclaimMemory   ||\r
        PoolType == EfiACPIMemoryNVS       ||\r
        PoolType == EfiRuntimeServicesCode ||\r
        PoolType == EfiRuntimeServicesData) {\r
 \r
-    Granularity = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;\r
+    Granularity = RUNTIME_PAGE_ALLOCATION_GRANULARITY;\r
   } else {\r
-    Granularity = DEFAULT_PAGE_ALLOCATION;\r
+    Granularity = DEFAULT_PAGE_ALLOCATION_GRANULARITY;\r
   }\r
 \r
   //\r
   // Adjust the size by the pool header & tail overhead\r
   //\r
 \r
+  HasPoolTail  = !(NeedGuard &&\r
+                   ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0));\r
+  PageAsPool = (IsHeapGuardEnabled (GUARD_HEAP_TYPE_FREED) && !mOnGuarding);\r
+\r
   //\r
   // Adjusting the Size to be of proper alignment so that\r
   // we don't get an unaligned access fault later when\r
@@ -345,10 +403,16 @@ CoreAllocatePoolI (
   // If allocation is over max size, just allocate pages for the request\r
   // (slow)\r
   //\r
-  if (Index >= SIZE_TO_LIST (Granularity)) {\r
-    NoPages = EFI_SIZE_TO_PAGES(Size) + EFI_SIZE_TO_PAGES (Granularity) - 1;\r
+  if (Index >= SIZE_TO_LIST (Granularity) || NeedGuard || PageAsPool) {\r
+    if (!HasPoolTail) {\r
+      Size -= sizeof (POOL_TAIL);\r
+    }\r
+    NoPages = EFI_SIZE_TO_PAGES (Size) + EFI_SIZE_TO_PAGES (Granularity) - 1;\r
     NoPages &= ~(UINTN)(EFI_SIZE_TO_PAGES (Granularity) - 1);\r
-    Head = CoreAllocatePoolPages (PoolType, NoPages, Granularity);\r
+    Head = CoreAllocatePoolPagesI (PoolType, NoPages, Granularity, NeedGuard);\r
+    if (NeedGuard) {\r
+      Head = AdjustPoolHeadA ((EFI_PHYSICAL_ADDRESS)(UINTN)Head, NoPages, Size);\r
+    }\r
     goto Done;\r
   }\r
 \r
@@ -376,7 +440,8 @@ CoreAllocatePoolI (
     //\r
     // Get another page\r
     //\r
-    NewPage = CoreAllocatePoolPages(PoolType, EFI_SIZE_TO_PAGES (Granularity), Granularity);\r
+    NewPage = CoreAllocatePoolPagesI (PoolType, EFI_SIZE_TO_PAGES (Granularity),\r
+                                      Granularity, NeedGuard);\r
     if (NewPage == NULL) {\r
       goto Done;\r
     }\r
@@ -422,30 +487,39 @@ Done:
 \r
   if (Head != NULL) {\r
 \r
+    //\r
+    // Account the allocation\r
+    //\r
+    Pool->Used += Size;\r
+\r
     //\r
     // If we have a pool buffer, fill in the header & tail info\r
     //\r
-    Head->Signature = POOL_HEAD_SIGNATURE;\r
+    Head->Signature = (PageAsPool) ? POOLPAGE_HEAD_SIGNATURE : POOL_HEAD_SIGNATURE;\r
     Head->Size      = Size;\r
     Head->Type      = (EFI_MEMORY_TYPE) PoolType;\r
-    Tail            = HEAD_TO_TAIL (Head);\r
-    Tail->Signature = POOL_TAIL_SIGNATURE;\r
-    Tail->Size      = Size;\r
     Buffer          = Head->Data;\r
-    DEBUG_CLEAR_MEMORY (Buffer, Size - POOL_OVERHEAD);\r
+\r
+    if (HasPoolTail) {\r
+      Tail            = HEAD_TO_TAIL (Head);\r
+      Tail->Signature = POOL_TAIL_SIGNATURE;\r
+      Tail->Size      = Size;\r
+\r
+      Size -= POOL_OVERHEAD;\r
+    } else {\r
+      Size -= SIZE_OF_POOL_HEAD;\r
+    }\r
+\r
+    DEBUG_CLEAR_MEMORY (Buffer, Size);\r
 \r
     DEBUG ((\r
       DEBUG_POOL,\r
       "AllocatePoolI: Type %x, Addr %p (len %lx) %,ld\n", PoolType,\r
       Buffer,\r
-      (UINT64)(Size - POOL_OVERHEAD),\r
+      (UINT64)Size,\r
       (UINT64) Pool->Used\r
       ));\r
 \r
-    //\r
-    // Account the allocation\r
-    //\r
-    Pool->Used += Size;\r
 \r
   } else {\r
     DEBUG ((DEBUG_ERROR | DEBUG_POOL, "AllocatePool: failed to allocate %ld bytes\n", (UINT64) Size));\r
@@ -479,9 +553,9 @@ CoreInternalFreePool (
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  CoreAcquireMemoryLock ();\r
+  CoreAcquireLock (&mPoolMemoryLock);\r
   Status = CoreFreePoolI (Buffer, PoolType);\r
-  CoreReleaseMemoryLock ();\r
+  CoreReleaseLock (&mPoolMemoryLock);\r
   return Status;\r
 }\r
 \r
@@ -505,12 +579,80 @@ CoreFreePool (
 \r
   Status = CoreInternalFreePool (Buffer, &PoolType);\r
   if (!EFI_ERROR (Status)) {\r
-    CoreUpdateProfile ((EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0), MemoryProfileActionFreePool, (EFI_MEMORY_TYPE) 0, 0, Buffer);\r
+    CoreUpdateProfile (\r
+      (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),\r
+      MemoryProfileActionFreePool,\r
+      PoolType,\r
+      0,\r
+      Buffer,\r
+      NULL\r
+      );\r
     InstallMemoryAttributesTableOnMemoryAllocation (PoolType);\r
   }\r
   return Status;\r
 }\r
 \r
+/**\r
+  Internal function.  Frees pool pages allocated via CoreAllocatePoolPagesI().\r
+\r
+  @param  PoolType               The type of memory for the pool pages\r
+  @param  Memory                 The base address to free\r
+  @param  NoPages                The number of pages to free\r
+\r
+**/\r
+STATIC\r
+VOID\r
+CoreFreePoolPagesI (\r
+  IN EFI_MEMORY_TYPE        PoolType,\r
+  IN EFI_PHYSICAL_ADDRESS   Memory,\r
+  IN UINTN                  NoPages\r
+  )\r
+{\r
+  CoreAcquireMemoryLock ();\r
+  CoreFreePoolPages (Memory, NoPages);\r
+  CoreReleaseMemoryLock ();\r
+\r
+  GuardFreedPagesChecked (Memory, NoPages);\r
+  ApplyMemoryProtectionPolicy (PoolType, EfiConventionalMemory,\r
+    (EFI_PHYSICAL_ADDRESS)(UINTN)Memory, EFI_PAGES_TO_SIZE (NoPages));\r
+}\r
+\r
+/**\r
+  Internal function.  Frees guarded pool pages.\r
+\r
+  @param  PoolType               The type of memory for the pool pages\r
+  @param  Memory                 The base address to free\r
+  @param  NoPages                The number of pages to free\r
+\r
+**/\r
+STATIC\r
+VOID\r
+CoreFreePoolPagesWithGuard (\r
+  IN EFI_MEMORY_TYPE        PoolType,\r
+  IN EFI_PHYSICAL_ADDRESS   Memory,\r
+  IN UINTN                  NoPages\r
+  )\r
+{\r
+  EFI_PHYSICAL_ADDRESS    MemoryGuarded;\r
+  UINTN                   NoPagesGuarded;\r
+\r
+  MemoryGuarded  = Memory;\r
+  NoPagesGuarded = NoPages;\r
+\r
+  AdjustMemoryF (&Memory, &NoPages);\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 (MemoryGuarded, NoPagesGuarded);\r
+  if (NoPages > 0) {\r
+    CoreFreePoolPagesI (PoolType, Memory, NoPages);\r
+  }\r
+}\r
+\r
 /**\r
   Internal function to free a pool entry.\r
   Caller must have the memory lock held\r
@@ -539,36 +681,51 @@ CoreFreePoolI (
   UINTN       Offset;\r
   BOOLEAN     AllFree;\r
   UINTN       Granularity;\r
+  BOOLEAN     IsGuarded;\r
+  BOOLEAN     HasPoolTail;\r
+  BOOLEAN     PageAsPool;\r
 \r
   ASSERT(Buffer != NULL);\r
   //\r
   // Get the head & tail of the pool entry\r
   //\r
-  Head = CR (Buffer, POOL_HEAD, Data, POOL_HEAD_SIGNATURE);\r
+  Head = BASE_CR (Buffer, POOL_HEAD, Data);\r
   ASSERT(Head != NULL);\r
 \r
-  if (Head->Signature != POOL_HEAD_SIGNATURE) {\r
+  if (Head->Signature != POOL_HEAD_SIGNATURE &&\r
+      Head->Signature != POOLPAGE_HEAD_SIGNATURE) {\r
+    ASSERT (Head->Signature == POOL_HEAD_SIGNATURE ||\r
+            Head->Signature == POOLPAGE_HEAD_SIGNATURE);\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  Tail = HEAD_TO_TAIL (Head);\r
-  ASSERT(Tail != NULL);\r
+  IsGuarded   = IsPoolTypeToGuard (Head->Type) &&\r
+                IsMemoryGuarded ((EFI_PHYSICAL_ADDRESS)(UINTN)Head);\r
+  HasPoolTail = !(IsGuarded &&\r
+                  ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0));\r
+  PageAsPool = (Head->Signature == POOLPAGE_HEAD_SIGNATURE);\r
 \r
-  //\r
-  // Debug\r
-  //\r
-  ASSERT (Tail->Signature == POOL_TAIL_SIGNATURE);\r
-  ASSERT (Head->Size == Tail->Size);\r
-  ASSERT_LOCKED (&gMemoryLock);\r
+  if (HasPoolTail) {\r
+    Tail = HEAD_TO_TAIL (Head);\r
+    ASSERT (Tail != NULL);\r
 \r
-  if (Tail->Signature != POOL_TAIL_SIGNATURE) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
+    //\r
+    // Debug\r
+    //\r
+    ASSERT (Tail->Signature == POOL_TAIL_SIGNATURE);\r
+    ASSERT (Head->Size == Tail->Size);\r
 \r
-  if (Head->Size != Tail->Size) {\r
-    return EFI_INVALID_PARAMETER;\r
+    if (Tail->Signature != POOL_TAIL_SIGNATURE) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    if (Head->Size != Tail->Size) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
   }\r
 \r
+  ASSERT_LOCKED (&mPoolMemoryLock);\r
+\r
   //\r
   // Determine the pool type and account for it\r
   //\r
@@ -585,9 +742,9 @@ CoreFreePoolI (
        Head->Type == EfiRuntimeServicesCode ||\r
        Head->Type == EfiRuntimeServicesData) {\r
 \r
-    Granularity = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;\r
+    Granularity = RUNTIME_PAGE_ALLOCATION_GRANULARITY;\r
   } else {\r
-    Granularity = DEFAULT_PAGE_ALLOCATION;\r
+    Granularity = DEFAULT_PAGE_ALLOCATION_GRANULARITY;\r
   }\r
 \r
   if (PoolType != NULL) {\r
@@ -603,14 +760,27 @@ CoreFreePoolI (
   //\r
   // If it's not on the list, it must be pool pages\r
   //\r
-  if (Index >= SIZE_TO_LIST (Granularity)) {\r
+  if (Index >= SIZE_TO_LIST (Granularity) || IsGuarded || PageAsPool) {\r
 \r
     //\r
     // Return the memory pages back to free memory\r
     //\r
-    NoPages = EFI_SIZE_TO_PAGES(Size) + EFI_SIZE_TO_PAGES (Granularity) - 1;\r
+    NoPages = EFI_SIZE_TO_PAGES (Size) + EFI_SIZE_TO_PAGES (Granularity) - 1;\r
     NoPages &= ~(UINTN)(EFI_SIZE_TO_PAGES (Granularity) - 1);\r
-    CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS) (UINTN) Head, NoPages);\r
+    if (IsGuarded) {\r
+      Head = AdjustPoolHeadF ((EFI_PHYSICAL_ADDRESS)(UINTN)Head);\r
+      CoreFreePoolPagesWithGuard (\r
+        Pool->MemoryType,\r
+        (EFI_PHYSICAL_ADDRESS)(UINTN)Head,\r
+        NoPages\r
+        );\r
+    } else {\r
+      CoreFreePoolPagesI (\r
+        Pool->MemoryType,\r
+        (EFI_PHYSICAL_ADDRESS)(UINTN)Head,\r
+        NoPages\r
+        );\r
+    }\r
 \r
   } else {\r
 \r
@@ -666,7 +836,8 @@ CoreFreePoolI (
         //\r
         // Free the page\r
         //\r
-        CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS) (UINTN)NewPage, EFI_SIZE_TO_PAGES (Granularity));\r
+        CoreFreePoolPagesI (Pool->MemoryType, (EFI_PHYSICAL_ADDRESS) (UINTN)NewPage,\r
+          EFI_SIZE_TO_PAGES (Granularity));\r
       }\r
     }\r
   }\r