]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Core/Dxe/Mem/Pool.c
MdeModulePkg: EfiUnacceptedMemoryType is not allowed in AllocatePool
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Mem / Pool.c
index a435b9760c0e3e9dd812c7b75498efa4af2ad130..b20cbfdedbab88fa87e45ba2d9a017288fd5b2da 100644 (file)
@@ -1,60 +1,63 @@
 /** @file\r
   UEFI Memory pool management functions.\r
 \r
-Copyright (c) 2006 - 2012, 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
+#define POOL_FREE_SIGNATURE  SIGNATURE_32('p','f','r','0')\r
 typedef struct {\r
-  UINT32          Signature;\r
-  UINT32          Index;\r
-  LIST_ENTRY      Link;\r
+  UINT32        Signature;\r
+  UINT32        Index;\r
+  LIST_ENTRY    Link;\r
 } 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          Size;\r
-  EFI_MEMORY_TYPE Type;\r
-  UINTN           Reserved;\r
-  CHAR8           Data[1];\r
+  UINT32             Signature;\r
+  UINT32             Reserved;\r
+  EFI_MEMORY_TYPE    Type;\r
+  UINTN              Size;\r
+  CHAR8              Data[1];\r
 } POOL_HEAD;\r
 \r
-#define SIZE_OF_POOL_HEAD OFFSET_OF(POOL_HEAD,Data)\r
+#define SIZE_OF_POOL_HEAD  OFFSET_OF(POOL_HEAD,Data)\r
 \r
-#define POOL_TAIL_SIGNATURE   SIGNATURE_32('p','t','a','l')\r
+#define POOL_TAIL_SIGNATURE  SIGNATURE_32('p','t','a','l')\r
 typedef struct {\r
-  UINT32      Signature;\r
-  UINT32      Size;\r
+  UINT32    Signature;\r
+  UINT32    Reserved;\r
+  UINTN     Size;\r
 } POOL_TAIL;\r
 \r
-\r
-#define POOL_SHIFT  7\r
-\r
-#define POOL_OVERHEAD (SIZE_OF_POOL_HEAD + sizeof(POOL_TAIL))\r
+#define POOL_OVERHEAD  (SIZE_OF_POOL_HEAD + sizeof(POOL_TAIL))\r
 \r
 #define HEAD_TO_TAIL(a)   \\r
   ((POOL_TAIL *) (((CHAR8 *) (a)) + (a)->Size - sizeof(POOL_TAIL)));\r
 \r
+//\r
+// Each element is the sum of the 2 previous ones: this allows us to migrate\r
+// blocks between bins by splitting them up, while not wasting too much memory\r
+// as we would in a strict power-of-2 sequence\r
+//\r
+STATIC CONST UINT16  mPoolSizeTable[] = {\r
+  128, 256, 384, 640, 1024, 1664, 2688, 4352, 7040, 11392, 18432, 29824\r
+};\r
 \r
-#define SIZE_TO_LIST(a)   ((a) >> POOL_SHIFT)\r
-#define LIST_TO_SIZE(a)   ((a+1) << POOL_SHIFT)\r
+#define SIZE_TO_LIST(a)  (GetPoolIndexFromSize (a))\r
+#define LIST_TO_SIZE(a)  (mPoolSizeTable [a])\r
 \r
-#define MAX_POOL_LIST       SIZE_TO_LIST(DEFAULT_PAGE_ALLOCATION)\r
+#define MAX_POOL_LIST  (ARRAY_SIZE (mPoolSizeTable))\r
 \r
-#define MAX_POOL_SIZE     (MAX_ADDRESS - POOL_OVERHEAD)\r
+#define MAX_POOL_SIZE  (MAX_ADDRESS - POOL_OVERHEAD)\r
 \r
 //\r
 // Globals\r
@@ -62,23 +65,47 @@ typedef struct {
 \r
 #define POOL_SIGNATURE  SIGNATURE_32('p','l','s','t')\r
 typedef struct {\r
-    INTN             Signature;\r
-    UINTN            Used;\r
-    EFI_MEMORY_TYPE  MemoryType;\r
-    LIST_ENTRY       FreeList[MAX_POOL_LIST];\r
-    LIST_ENTRY       Link;\r
+  INTN               Signature;\r
+  UINTN              Used;\r
+  EFI_MEMORY_TYPE    MemoryType;\r
+  LIST_ENTRY         FreeList[MAX_POOL_LIST];\r
+  LIST_ENTRY         Link;\r
 } POOL;\r
 \r
 //\r
 // Pool header for each memory type.\r
 //\r
-POOL            mPoolHead[EfiMaxMemoryType];\r
+POOL  mPoolHead[EfiMaxMemoryType];\r
 \r
 //\r
 // List of pool header to search for the appropriate memory type.\r
 //\r
-LIST_ENTRY      mPoolHeadList = INITIALIZE_LIST_HEAD_VARIABLE (mPoolHeadList);\r
+LIST_ENTRY  mPoolHeadList = INITIALIZE_LIST_HEAD_VARIABLE (mPoolHeadList);\r
+\r
+/**\r
+  Get pool size table index from the specified size.\r
+\r
+  @param  Size          The specified size to get index from pool table.\r
+\r
+  @return               The index of pool size table.\r
+\r
+**/\r
+STATIC\r
+UINTN\r
+GetPoolIndexFromSize (\r
+  UINTN  Size\r
+  )\r
+{\r
+  UINTN  Index;\r
+\r
+  for (Index = 0; Index < MAX_POOL_LIST; Index++) {\r
+    if (mPoolSizeTable[Index] >= Size) {\r
+      return Index;\r
+    }\r
+  }\r
 \r
+  return MAX_POOL_LIST;\r
+}\r
 \r
 /**\r
   Called to initialize the pool.\r
@@ -92,17 +119,16 @@ CoreInitializePool (
   UINTN  Type;\r
   UINTN  Index;\r
 \r
-  for (Type=0; Type < EfiMaxMemoryType; Type++) {\r
+  for (Type = 0; Type < EfiMaxMemoryType; Type++) {\r
     mPoolHead[Type].Signature  = 0;\r
     mPoolHead[Type].Used       = 0;\r
-    mPoolHead[Type].MemoryType = (EFI_MEMORY_TYPE) Type;\r
-    for (Index=0; Index < MAX_POOL_LIST; Index++) {\r
-        InitializeListHead (&mPoolHead[Type].FreeList[Index]);\r
+    mPoolHead[Type].MemoryType = (EFI_MEMORY_TYPE)Type;\r
+    for (Index = 0; Index < MAX_POOL_LIST; Index++) {\r
+      InitializeListHead (&mPoolHead[Type].FreeList[Index]);\r
     }\r
   }\r
 }\r
 \r
-\r
 /**\r
   Look up pool head for specified memory type.\r
 \r
@@ -116,36 +142,36 @@ LookupPoolHead (
   IN EFI_MEMORY_TYPE  MemoryType\r
   )\r
 {\r
-  LIST_ENTRY      *Link;\r
-  POOL            *Pool;\r
-  UINTN           Index;\r
+  LIST_ENTRY  *Link;\r
+  POOL        *Pool;\r
+  UINTN       Index;\r
 \r
-  if (MemoryType >= 0 && MemoryType < EfiMaxMemoryType) {\r
+  if ((UINT32)MemoryType < EfiMaxMemoryType) {\r
     return &mPoolHead[MemoryType];\r
   }\r
 \r
   //\r
-  // MemoryType values in the range 0x80000000..0xFFFFFFFF are reserved for use by UEFI \r
-  // OS loaders that are provided by operating system vendors\r
+  // MemoryType values in the range 0x80000000..0xFFFFFFFF are reserved for use by UEFI\r
+  // OS loaders that are provided by operating system vendors.\r
+  // MemoryType values in the range 0x70000000..0x7FFFFFFF are reserved for OEM use.\r
   //\r
-  if (MemoryType >= (INT32)0x80000000 && MemoryType <= (INT32)0xffffffff) {\r
-\r
+  if ((UINT32)MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) {\r
     for (Link = mPoolHeadList.ForwardLink; Link != &mPoolHeadList; Link = Link->ForwardLink) {\r
-      Pool = CR(Link, POOL, Link, POOL_SIGNATURE);\r
+      Pool = CR (Link, POOL, Link, POOL_SIGNATURE);\r
       if (Pool->MemoryType == MemoryType) {\r
         return Pool;\r
       }\r
     }\r
 \r
-    Pool = CoreAllocatePoolI (EfiBootServicesData, sizeof (POOL));\r
+    Pool = CoreAllocatePoolI (EfiBootServicesData, sizeof (POOL), FALSE);\r
     if (Pool == NULL) {\r
       return NULL;\r
     }\r
 \r
-    Pool->Signature = POOL_SIGNATURE;\r
-    Pool->Used      = 0;\r
+    Pool->Signature  = POOL_SIGNATURE;\r
+    Pool->Used       = 0;\r
     Pool->MemoryType = MemoryType;\r
-    for (Index=0; Index < MAX_POOL_LIST; Index++) {\r
+    for (Index = 0; Index < MAX_POOL_LIST; Index++) {\r
       InitializeListHead (&Pool->FreeList[Index]);\r
     }\r
 \r
@@ -157,8 +183,6 @@ LookupPoolHead (
   return NULL;\r
 }\r
 \r
-\r
-\r
 /**\r
   Allocate pool of a particular type.\r
 \r
@@ -167,26 +191,30 @@ LookupPoolHead (
   @param  Buffer                 The address to return a pointer to the allocated\r
                                  pool\r
 \r
-  @retval EFI_INVALID_PARAMETER  PoolType not valid or Buffer is NULL. \r
+  @retval EFI_INVALID_PARAMETER  Buffer is NULL.\r
+                                 PoolType is in the range EfiMaxMemoryType..0x6FFFFFFF.\r
+                                 PoolType is EfiPersistentMemory.\r
   @retval EFI_OUT_OF_RESOURCES   Size exceeds max pool size or allocation failed.\r
   @retval EFI_SUCCESS            Pool successfully allocated.\r
 \r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
-CoreAllocatePool (\r
+CoreInternalAllocatePool (\r
   IN EFI_MEMORY_TYPE  PoolType,\r
   IN UINTN            Size,\r
   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
   //\r
-  if ((PoolType >= EfiMaxMemoryType && PoolType <= 0x7fffffff) ||\r
-       PoolType == EfiConventionalMemory) {\r
+  if (((PoolType >= EfiMaxMemoryType) && (PoolType < MEMORY_TYPE_OEM_RESERVED_MIN)) ||\r
+      (PoolType == EfiConventionalMemory) || (PoolType == EfiPersistentMemory) || (PoolType == EfiUnacceptedMemoryType))\r
+  {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
@@ -204,20 +232,109 @@ CoreAllocatePool (
     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
+/**\r
+  Allocate pool of a particular type.\r
+\r
+  @param  PoolType               Type of pool to allocate\r
+  @param  Size                   The amount of pool to allocate\r
+  @param  Buffer                 The address to return a pointer to the allocated\r
+                                 pool\r
 \r
+  @retval EFI_INVALID_PARAMETER  Buffer is NULL.\r
+                                 PoolType is in the range EfiMaxMemoryType..0x6FFFFFFF.\r
+                                 PoolType is EfiPersistentMemory.\r
+  @retval EFI_OUT_OF_RESOURCES   Size exceeds max pool size or allocation failed.\r
+  @retval EFI_SUCCESS            Pool successfully allocated.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CoreAllocatePool (\r
+  IN EFI_MEMORY_TYPE  PoolType,\r
+  IN UINTN            Size,\r
+  OUT VOID            **Buffer\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  Status = CoreInternalAllocatePool (PoolType, Size, Buffer);\r
+  if (!EFI_ERROR (Status)) {\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
+\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
+\r
+    ApplyMemoryProtectionPolicy (\r
+      EfiConventionalMemory,\r
+      PoolType,\r
+      (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer,\r
+      EFI_PAGES_TO_SIZE (NoPages)\r
+      );\r
+  }\r
+\r
+  return Buffer;\r
+}\r
 \r
 /**\r
   Internal function to allocate pool of a particular type.\r
@@ -225,6 +342,7 @@ CoreAllocatePool (
 \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
@@ -232,26 +350,44 @@ 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
-  POOL_FREE   *Free;\r
-  POOL_HEAD   *Head;\r
-  POOL_TAIL   *Tail;\r
-  CHAR8       *NewPage;\r
-  VOID        *Buffer;\r
-  UINTN       Index;\r
-  UINTN       FSize;\r
-  UINTN       Offset;\r
-  UINTN       NoPages;\r
-\r
-  ASSERT_LOCKED (&gMemoryLock);\r
+  POOL       *Pool;\r
+  POOL_FREE  *Free;\r
+  POOL_HEAD  *Head;\r
+  POOL_TAIL  *Tail;\r
+  CHAR8      *NewPage;\r
+  VOID       *Buffer;\r
+  UINTN      Index;\r
+  UINTN      FSize;\r
+  UINTN      Offset, MaxOffset;\r
+  UINTN      NoPages;\r
+  UINTN      Granularity;\r
+  BOOLEAN    HasPoolTail;\r
+  BOOLEAN    PageAsPool;\r
+\r
+  ASSERT_LOCKED (&mPoolMemoryLock);\r
+\r
+  if ((PoolType == EfiACPIReclaimMemory) ||\r
+      (PoolType == EfiACPIMemoryNVS) ||\r
+      (PoolType == EfiRuntimeServicesCode) ||\r
+      (PoolType == EfiRuntimeServicesData))\r
+  {\r
+    Granularity = RUNTIME_PAGE_ALLOCATION_GRANULARITY;\r
+  } else {\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
@@ -260,21 +396,30 @@ CoreAllocatePoolI (
   Size = ALIGN_VARIABLE (Size);\r
 \r
   Size += POOL_OVERHEAD;\r
-  Index = SIZE_TO_LIST(Size);\r
-  Pool = LookupPoolHead (PoolType);\r
-  if (Pool== NULL) {\r
+  Index = SIZE_TO_LIST (Size);\r
+  Pool  = LookupPoolHead (PoolType);\r
+  if (Pool == NULL) {\r
     return NULL;\r
   }\r
+\r
   Head = NULL;\r
 \r
   //\r
   // If allocation is over max size, just allocate pages for the request\r
   // (slow)\r
   //\r
-  if (Index >= MAX_POOL_LIST) {\r
-    NoPages = EFI_SIZE_TO_PAGES(Size) + EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1;\r
-    NoPages &= ~(EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1);\r
-    Head = CoreAllocatePoolPages (PoolType, NoPages, DEFAULT_PAGE_ALLOCATION);\r
+  if ((Index >= SIZE_TO_LIST (Granularity)) || NeedGuard || PageAsPool) {\r
+    if (!HasPoolTail) {\r
+      Size -= sizeof (POOL_TAIL);\r
+    }\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     = CoreAllocatePoolPagesI (PoolType, NoPages, Granularity, NeedGuard);\r
+    if (NeedGuard) {\r
+      Head = AdjustPoolHeadA ((EFI_PHYSICAL_ADDRESS)(UINTN)Head, NoPages, Size);\r
+    }\r
+\r
     goto Done;\r
   }\r
 \r
@@ -282,25 +427,51 @@ CoreAllocatePoolI (
   // If there's no free pool in the proper list size, go get some more pages\r
   //\r
   if (IsListEmpty (&Pool->FreeList[Index])) {\r
+    Offset    = LIST_TO_SIZE (Index);\r
+    MaxOffset = Granularity;\r
+\r
+    //\r
+    // Check the bins holding larger blocks, and carve one up if needed\r
+    //\r
+    while (++Index < SIZE_TO_LIST (Granularity)) {\r
+      if (!IsListEmpty (&Pool->FreeList[Index])) {\r
+        Free = CR (Pool->FreeList[Index].ForwardLink, POOL_FREE, Link, POOL_FREE_SIGNATURE);\r
+        RemoveEntryList (&Free->Link);\r
+        NewPage   = (VOID *)Free;\r
+        MaxOffset = LIST_TO_SIZE (Index);\r
+        goto Carve;\r
+      }\r
+    }\r
 \r
     //\r
     // Get another page\r
     //\r
-    NewPage = CoreAllocatePoolPages(PoolType, EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION), DEFAULT_PAGE_ALLOCATION);\r
+    NewPage = CoreAllocatePoolPagesI (\r
+                PoolType,\r
+                EFI_SIZE_TO_PAGES (Granularity),\r
+                Granularity,\r
+                NeedGuard\r
+                );\r
     if (NewPage == NULL) {\r
       goto Done;\r
     }\r
 \r
     //\r
-    // Carve up new page into free pool blocks\r
+    // Serve the allocation request from the head of the allocated block\r
+    //\r
+Carve:\r
+    Head = (POOL_HEAD *)NewPage;\r
+\r
+    //\r
+    // Carve up remaining space into free pool blocks\r
     //\r
-    Offset = 0;\r
-    while (Offset < DEFAULT_PAGE_ALLOCATION) {\r
+    Index--;\r
+    while (Offset < MaxOffset) {\r
       ASSERT (Index < MAX_POOL_LIST);\r
-      FSize = LIST_TO_SIZE(Index);\r
+      FSize = LIST_TO_SIZE (Index);\r
 \r
-      while (Offset + FSize <= DEFAULT_PAGE_ALLOCATION) {\r
-        Free = (POOL_FREE *) &NewPage[Offset];\r
+      while (Offset + FSize <= MaxOffset) {\r
+        Free            = (POOL_FREE *)&NewPage[Offset];\r
         Free->Signature = POOL_FREE_SIGNATURE;\r
         Free->Index     = (UINT32)Index;\r
         InsertHeadList (&Pool->FreeList[Index], &Free->Link);\r
@@ -310,8 +481,8 @@ CoreAllocatePoolI (
       Index -= 1;\r
     }\r
 \r
-    ASSERT (Offset == DEFAULT_PAGE_ALLOCATION);\r
-    Index = SIZE_TO_LIST(Size);\r
+    ASSERT (Offset == MaxOffset);\r
+    goto Done;\r
   }\r
 \r
   //\r
@@ -320,51 +491,57 @@ CoreAllocatePoolI (
   Free = CR (Pool->FreeList[Index].ForwardLink, POOL_FREE, Link, POOL_FREE_SIGNATURE);\r
   RemoveEntryList (&Free->Link);\r
 \r
-  Head = (POOL_HEAD *) Free;\r
+  Head = (POOL_HEAD *)Free;\r
 \r
 Done:\r
   Buffer = NULL;\r
 \r
   if (Head != NULL) {\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->Size      = (UINT32) Size;\r
-    Head->Type      = (EFI_MEMORY_TYPE) PoolType;\r
-    Tail            = HEAD_TO_TAIL (Head);\r
-    Tail->Signature = POOL_TAIL_SIGNATURE;\r
-    Tail->Size      = (UINT32) Size;\r
+    Head->Signature = (PageAsPool) ? POOLPAGE_HEAD_SIGNATURE : POOL_HEAD_SIGNATURE;\r
+    Head->Size      = Size;\r
+    Head->Type      = (EFI_MEMORY_TYPE)PoolType;\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
+      "AllocatePoolI: Type %x, Addr %p (len %lx) %,ld\n",\r
+      PoolType,\r
       Buffer,\r
-      (UINT64)(Size - POOL_OVERHEAD),\r
-      (UINT64) Pool->Used\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
+    DEBUG ((DEBUG_ERROR | DEBUG_POOL, "AllocatePool: failed to allocate %ld bytes\n", (UINT64)Size));\r
   }\r
 \r
   return Buffer;\r
 }\r
 \r
-\r
-\r
 /**\r
   Frees pool.\r
 \r
   @param  Buffer                 The allocated pool entry to free\r
+  @param  PoolType               Pointer to pool type\r
 \r
   @retval EFI_INVALID_PARAMETER  Buffer is not a valid value.\r
   @retval EFI_SUCCESS            Pool successfully freed.\r
@@ -372,29 +549,128 @@ Done:
 **/\r
 EFI_STATUS\r
 EFIAPI\r
-CoreFreePool (\r
-  IN VOID        *Buffer\r
+CoreInternalFreePool (\r
+  IN VOID              *Buffer,\r
+  OUT EFI_MEMORY_TYPE  *PoolType OPTIONAL\r
   )\r
 {\r
-  EFI_STATUS Status;\r
+  EFI_STATUS  Status;\r
 \r
   if (Buffer == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
+  CoreAcquireLock (&mPoolMemoryLock);\r
+  Status = CoreFreePoolI (Buffer, PoolType);\r
+  CoreReleaseLock (&mPoolMemoryLock);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Frees pool.\r
+\r
+  @param  Buffer                 The allocated pool entry to free\r
+\r
+  @retval EFI_INVALID_PARAMETER  Buffer is not a valid value.\r
+  @retval EFI_SUCCESS            Pool successfully freed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CoreFreePool (\r
+  IN VOID  *Buffer\r
+  )\r
+{\r
+  EFI_STATUS       Status;\r
+  EFI_MEMORY_TYPE  PoolType;\r
+\r
+  Status = CoreInternalFreePool (Buffer, &PoolType);\r
+  if (!EFI_ERROR (Status)) {\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
+\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
-  Status = CoreFreePoolI (Buffer);\r
+  CoreFreePoolPages (Memory, NoPages);\r
   CoreReleaseMemoryLock ();\r
-  return Status;\r
+\r
+  GuardFreedPagesChecked (Memory, NoPages);\r
+  ApplyMemoryProtectionPolicy (\r
+    PoolType,\r
+    EfiConventionalMemory,\r
+    (EFI_PHYSICAL_ADDRESS)(UINTN)Memory,\r
+    EFI_PAGES_TO_SIZE (NoPages)\r
+    );\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
 \r
   @param  Buffer                 The allocated pool entry to free\r
+  @param  PoolType               Pointer to pool type\r
 \r
   @retval EFI_INVALID_PARAMETER  Buffer not valid\r
   @retval EFI_SUCCESS            Buffer successfully freed.\r
@@ -402,50 +678,69 @@ CoreFreePool (
 **/\r
 EFI_STATUS\r
 CoreFreePoolI (\r
-  IN VOID       *Buffer\r
+  IN VOID              *Buffer,\r
+  OUT EFI_MEMORY_TYPE  *PoolType OPTIONAL\r
   )\r
 {\r
-  POOL        *Pool;\r
-  POOL_HEAD   *Head;\r
-  POOL_TAIL   *Tail;\r
-  POOL_FREE   *Free;\r
-  UINTN       Index;\r
-  UINTN       NoPages;\r
-  UINTN       Size;\r
-  CHAR8       *NewPage;\r
-  UINTN       FSize;\r
-  UINTN       Offset;\r
-  BOOLEAN     AllFree;\r
-\r
-  ASSERT(Buffer != NULL);\r
+  POOL       *Pool;\r
+  POOL_HEAD  *Head;\r
+  POOL_TAIL  *Tail;\r
+  POOL_FREE  *Free;\r
+  UINTN      Index;\r
+  UINTN      NoPages;\r
+  UINTN      Size;\r
+  CHAR8      *NewPage;\r
+  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
-  ASSERT(Head != NULL);\r
-\r
-  if (Head->Signature != POOL_HEAD_SIGNATURE) {\r
+  Head = BASE_CR (Buffer, POOL_HEAD, Data);\r
+  ASSERT (Head != NULL);\r
+\r
+  if ((Head->Signature != POOL_HEAD_SIGNATURE) &&\r
+      (Head->Signature != POOLPAGE_HEAD_SIGNATURE))\r
+  {\r
+    ASSERT (\r
+      Head->Signature == POOL_HEAD_SIGNATURE ||\r
+      Head->Signature == POOLPAGE_HEAD_SIGNATURE\r
+      );\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
@@ -454,34 +749,59 @@ CoreFreePoolI (
   if (Pool == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
+\r
   Pool->Used -= Size;\r
-  DEBUG ((DEBUG_POOL, "FreePool: %p (len %lx) %,ld\n", Head->Data, (UINT64)(Head->Size - POOL_OVERHEAD), (UINT64) Pool->Used));\r
+  DEBUG ((DEBUG_POOL, "FreePool: %p (len %lx) %,ld\n", Head->Data, (UINT64)(Head->Size - POOL_OVERHEAD), (UINT64)Pool->Used));\r
+\r
+  if ((Head->Type == EfiACPIReclaimMemory) ||\r
+      (Head->Type == EfiACPIMemoryNVS) ||\r
+      (Head->Type == EfiRuntimeServicesCode) ||\r
+      (Head->Type == EfiRuntimeServicesData))\r
+  {\r
+    Granularity = RUNTIME_PAGE_ALLOCATION_GRANULARITY;\r
+  } else {\r
+    Granularity = DEFAULT_PAGE_ALLOCATION_GRANULARITY;\r
+  }\r
+\r
+  if (PoolType != NULL) {\r
+    *PoolType = Head->Type;\r
+  }\r
 \r
   //\r
   // Determine the pool list\r
   //\r
-  Index = SIZE_TO_LIST(Size);\r
+  Index = SIZE_TO_LIST (Size);\r
   DEBUG_CLEAR_MEMORY (Head, Size);\r
 \r
   //\r
   // If it's not on the list, it must be pool pages\r
   //\r
-  if (Index >= MAX_POOL_LIST) {\r
-\r
+  if ((Index >= SIZE_TO_LIST (Granularity)) || IsGuarded || PageAsPool) {\r
     //\r
     // Return the memory pages back to free memory\r
     //\r
-    NoPages = EFI_SIZE_TO_PAGES(Size) + EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1;\r
-    NoPages &= ~(EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1);\r
-    CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS) (UINTN) Head, NoPages);\r
-\r
+    NoPages  = EFI_SIZE_TO_PAGES (Size) + EFI_SIZE_TO_PAGES (Granularity) - 1;\r
+    NoPages &= ~(UINTN)(EFI_SIZE_TO_PAGES (Granularity) - 1);\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
   } else {\r
-\r
     //\r
     // Put the pool entry onto the free pool list\r
     //\r
-    Free = (POOL_FREE *) Head;\r
-    ASSERT(Free != NULL);\r
+    Free = (POOL_FREE *)Head;\r
+    ASSERT (Free != NULL);\r
     Free->Signature = POOL_FREE_SIGNATURE;\r
     Free->Index     = (UINT32)Index;\r
     InsertHeadList (&Pool->FreeList[Index], &Free->Link);\r
@@ -490,69 +810,61 @@ CoreFreePoolI (
     // See if all the pool entries in the same page as Free are freed pool\r
     // entries\r
     //\r
-    NewPage = (CHAR8 *)((UINTN)Free & ~((DEFAULT_PAGE_ALLOCATION) -1));\r
-    Free = (POOL_FREE *) &NewPage[0];\r
-    ASSERT(Free != NULL);\r
+    NewPage = (CHAR8 *)((UINTN)Free & ~(Granularity - 1));\r
+    Free    = (POOL_FREE *)&NewPage[0];\r
+    ASSERT (Free != NULL);\r
 \r
     if (Free->Signature == POOL_FREE_SIGNATURE) {\r
-\r
-      Index = Free->Index;\r
-\r
       AllFree = TRUE;\r
-      Offset = 0;\r
-\r
-      while ((Offset < DEFAULT_PAGE_ALLOCATION) && (AllFree)) {\r
-        FSize = LIST_TO_SIZE(Index);\r
-        while (Offset + FSize <= DEFAULT_PAGE_ALLOCATION) {\r
-          Free = (POOL_FREE *) &NewPage[Offset];\r
-          ASSERT(Free != NULL);\r
-          if (Free->Signature != POOL_FREE_SIGNATURE) {\r
-            AllFree = FALSE;\r
-          }\r
-          Offset += FSize;\r
+      Offset  = 0;\r
+\r
+      while ((Offset < Granularity) && (AllFree)) {\r
+        Free = (POOL_FREE *)&NewPage[Offset];\r
+        ASSERT (Free != NULL);\r
+        if (Free->Signature != POOL_FREE_SIGNATURE) {\r
+          AllFree = FALSE;\r
         }\r
-        Index -= 1;\r
+\r
+        Offset += LIST_TO_SIZE (Free->Index);\r
       }\r
 \r
       if (AllFree) {\r
-\r
         //\r
         // All of the pool entries in the same page as Free are free pool\r
         // entries\r
         // Remove all of these pool entries from the free loop lists.\r
         //\r
-        Free = (POOL_FREE *) &NewPage[0];\r
-        ASSERT(Free != NULL);\r
-        Index = Free->Index;\r
+        Free = (POOL_FREE *)&NewPage[0];\r
+        ASSERT (Free != NULL);\r
         Offset = 0;\r
 \r
-        while (Offset < DEFAULT_PAGE_ALLOCATION) {\r
-          FSize = LIST_TO_SIZE(Index);\r
-          while (Offset + FSize <= DEFAULT_PAGE_ALLOCATION) {\r
-            Free = (POOL_FREE *) &NewPage[Offset];\r
-            ASSERT(Free != NULL);\r
-            RemoveEntryList (&Free->Link);\r
-            Offset += FSize;\r
-          }\r
-          Index -= 1;\r
+        while (Offset < Granularity) {\r
+          Free = (POOL_FREE *)&NewPage[Offset];\r
+          ASSERT (Free != NULL);\r
+          RemoveEntryList (&Free->Link);\r
+          Offset += LIST_TO_SIZE (Free->Index);\r
         }\r
 \r
         //\r
         // Free the page\r
         //\r
-        CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS) (UINTN)NewPage, EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION));\r
+        CoreFreePoolPagesI (\r
+          Pool->MemoryType,\r
+          (EFI_PHYSICAL_ADDRESS)(UINTN)NewPage,\r
+          EFI_SIZE_TO_PAGES (Granularity)\r
+          );\r
       }\r
     }\r
   }\r
 \r
   //\r
-  // If this is an OS specific memory type, then check to see if the last\r
+  // If this is an OS/OEM specific memory type, then check to see if the last\r
   // portion of that memory type has been freed.  If it has, then free the\r
   // list entry for that memory type\r
   //\r
-  if (Pool->MemoryType < 0 && Pool->Used == 0) {\r
+  if (((UINT32)Pool->MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) && (Pool->Used == 0)) {\r
     RemoveEntryList (&Pool->Link);\r
-    CoreFreePoolI (Pool);\r
+    CoreFreePoolI (Pool, NULL);\r
   }\r
 \r
   return EFI_SUCCESS;\r