]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/Dxe/Mem/Pool.c
MdeModulePkg/Core: fix feature conflict between NX and heap guard
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Mem / Pool.c
CommitLineData
23c98c94 1/** @file\r
504214c4
LG
2 UEFI Memory pool management functions.\r
3\r
09159a29 4Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>\r
cd5ebaa0 5This program and the accompanying materials\r
23c98c94 6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
28a00297 12\r
504214c4 13**/\r
28a00297 14\r
9c4ac31c 15#include "DxeMain.h"\r
ec90508b 16#include "Imem.h"\r
e63da9f0 17#include "HeapGuard.h"\r
28a00297 18\r
f31c36c2
AB
19STATIC EFI_LOCK mPoolMemoryLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);\r
20\r
f3f2e05d 21#define POOL_FREE_SIGNATURE SIGNATURE_32('p','f','r','0')\r
28a00297 22typedef struct {\r
23 UINT32 Signature;\r
24 UINT32 Index;\r
25 LIST_ENTRY Link;\r
26} POOL_FREE;\r
27\r
28\r
f3f2e05d 29#define POOL_HEAD_SIGNATURE SIGNATURE_32('p','h','d','0')\r
28a00297 30typedef struct {\r
31 UINT32 Signature;\r
bb683bf4 32 UINT32 Reserved;\r
28a00297 33 EFI_MEMORY_TYPE Type;\r
bb683bf4 34 UINTN Size;\r
28a00297 35 CHAR8 Data[1];\r
36} POOL_HEAD;\r
37\r
f3f2e05d 38#define SIZE_OF_POOL_HEAD OFFSET_OF(POOL_HEAD,Data)\r
28a00297 39\r
f3f2e05d 40#define POOL_TAIL_SIGNATURE SIGNATURE_32('p','t','a','l')\r
28a00297 41typedef struct {\r
42 UINT32 Signature;\r
bb683bf4
SZ
43 UINT32 Reserved;\r
44 UINTN Size;\r
28a00297 45} POOL_TAIL;\r
46\r
28a00297 47#define POOL_OVERHEAD (SIZE_OF_POOL_HEAD + sizeof(POOL_TAIL))\r
48\r
49#define HEAD_TO_TAIL(a) \\r
50 ((POOL_TAIL *) (((CHAR8 *) (a)) + (a)->Size - sizeof(POOL_TAIL)));\r
51\r
f2c7daf6
AB
52//\r
53// Each element is the sum of the 2 previous ones: this allows us to migrate\r
54// blocks between bins by splitting them up, while not wasting too much memory\r
55// as we would in a strict power-of-2 sequence\r
56//\r
57STATIC CONST UINT16 mPoolSizeTable[] = {\r
467d5f6b 58 128, 256, 384, 640, 1024, 1664, 2688, 4352, 7040, 11392, 18432, 29824\r
f2c7daf6 59};\r
28a00297 60\r
f2c7daf6
AB
61#define SIZE_TO_LIST(a) (GetPoolIndexFromSize (a))\r
62#define LIST_TO_SIZE(a) (mPoolSizeTable [a])\r
28a00297 63\r
ed998e06 64#define MAX_POOL_LIST (ARRAY_SIZE (mPoolSizeTable))\r
28a00297 65\r
66#define MAX_POOL_SIZE (MAX_ADDRESS - POOL_OVERHEAD)\r
67\r
68//\r
69// Globals\r
70//\r
71\r
f3f2e05d 72#define POOL_SIGNATURE SIGNATURE_32('p','l','s','t')\r
28a00297 73typedef struct {\r
74 INTN Signature;\r
75 UINTN Used;\r
76 EFI_MEMORY_TYPE MemoryType;\r
77 LIST_ENTRY FreeList[MAX_POOL_LIST];\r
78 LIST_ENTRY Link;\r
022c6d45 79} POOL;\r
28a00297 80\r
28a00297 81//\r
e94a9ff7 82// Pool header for each memory type.\r
83//\r
84POOL mPoolHead[EfiMaxMemoryType];\r
85\r
28a00297 86//\r
e94a9ff7 87// List of pool header to search for the appropriate memory type.\r
28a00297 88//\r
57b4ecb9 89LIST_ENTRY mPoolHeadList = INITIALIZE_LIST_HEAD_VARIABLE (mPoolHeadList);\r
28a00297 90\r
dd51e45b
SQ
91/**\r
92 Get pool size table index from the specified size.\r
93\r
94 @param Size The specified size to get index from pool table.\r
95\r
96 @return The index of pool size table.\r
97\r
98**/\r
f2c7daf6
AB
99STATIC\r
100UINTN\r
101GetPoolIndexFromSize (\r
102 UINTN Size\r
103 )\r
104{\r
105 UINTN Index;\r
106\r
107 for (Index = 0; Index < MAX_POOL_LIST; Index++) {\r
108 if (mPoolSizeTable [Index] >= Size) {\r
109 return Index;\r
110 }\r
111 }\r
112 return MAX_POOL_LIST;\r
113}\r
162ed594 114\r
115/**\r
116 Called to initialize the pool.\r
117\r
118**/\r
28a00297 119VOID\r
120CoreInitializePool (\r
121 VOID\r
122 )\r
28a00297 123{\r
124 UINTN Type;\r
125 UINTN Index;\r
126\r
127 for (Type=0; Type < EfiMaxMemoryType; Type++) {\r
e94a9ff7 128 mPoolHead[Type].Signature = 0;\r
129 mPoolHead[Type].Used = 0;\r
130 mPoolHead[Type].MemoryType = (EFI_MEMORY_TYPE) Type;\r
28a00297 131 for (Index=0; Index < MAX_POOL_LIST; Index++) {\r
bb683bf4 132 InitializeListHead (&mPoolHead[Type].FreeList[Index]);\r
28a00297 133 }\r
134 }\r
28a00297 135}\r
136\r
28a00297 137\r
162ed594 138/**\r
28a00297 139 Look up pool head for specified memory type.\r
140\r
022c6d45 141 @param MemoryType Memory type of which pool head is looked for\r
28a00297 142\r
162ed594 143 @return Pointer of Corresponding pool head.\r
28a00297 144\r
162ed594 145**/\r
162ed594 146POOL *\r
147LookupPoolHead (\r
148 IN EFI_MEMORY_TYPE MemoryType\r
149 )\r
28a00297 150{\r
151 LIST_ENTRY *Link;\r
152 POOL *Pool;\r
153 UINTN Index;\r
154\r
3d78c020 155 if ((UINT32)MemoryType < EfiMaxMemoryType) {\r
e94a9ff7 156 return &mPoolHead[MemoryType];\r
28a00297 157 }\r
158\r
dc8d93ca 159 //\r
8ee25f48
SZ
160 // MemoryType values in the range 0x80000000..0xFFFFFFFF are reserved for use by UEFI\r
161 // OS loaders that are provided by operating system vendors.\r
162 // MemoryType values in the range 0x70000000..0x7FFFFFFF are reserved for OEM use.\r
dc8d93ca 163 //\r
8ee25f48 164 if ((UINT32) MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) {\r
28a00297 165\r
e94a9ff7 166 for (Link = mPoolHeadList.ForwardLink; Link != &mPoolHeadList; Link = Link->ForwardLink) {\r
28a00297 167 Pool = CR(Link, POOL, Link, POOL_SIGNATURE);\r
168 if (Pool->MemoryType == MemoryType) {\r
169 return Pool;\r
170 }\r
171 }\r
172\r
e63da9f0 173 Pool = CoreAllocatePoolI (EfiBootServicesData, sizeof (POOL), FALSE);\r
28a00297 174 if (Pool == NULL) {\r
175 return NULL;\r
176 }\r
177\r
178 Pool->Signature = POOL_SIGNATURE;\r
179 Pool->Used = 0;\r
180 Pool->MemoryType = MemoryType;\r
181 for (Index=0; Index < MAX_POOL_LIST; Index++) {\r
182 InitializeListHead (&Pool->FreeList[Index]);\r
183 }\r
184\r
e94a9ff7 185 InsertHeadList (&mPoolHeadList, &Pool->Link);\r
28a00297 186\r
187 return Pool;\r
188 }\r
189\r
190 return NULL;\r
191}\r
192\r
022c6d45 193\r
28a00297 194\r
162ed594 195/**\r
196 Allocate pool of a particular type.\r
197\r
022c6d45 198 @param PoolType Type of pool to allocate\r
199 @param Size The amount of pool to allocate\r
200 @param Buffer The address to return a pointer to the allocated\r
201 pool\r
162ed594 202\r
2eb989bc
SZ
203 @retval EFI_INVALID_PARAMETER Buffer is NULL.\r
204 PoolType is in the range EfiMaxMemoryType..0x6FFFFFFF.\r
205 PoolType is EfiPersistentMemory.\r
022c6d45 206 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.\r
162ed594 207 @retval EFI_SUCCESS Pool successfully allocated.\r
208\r
209**/\r
28a00297 210EFI_STATUS\r
211EFIAPI\r
84edd20b 212CoreInternalAllocatePool (\r
28a00297 213 IN EFI_MEMORY_TYPE PoolType,\r
214 IN UINTN Size,\r
215 OUT VOID **Buffer\r
216 )\r
28a00297 217{\r
e63da9f0
JW
218 EFI_STATUS Status;\r
219 BOOLEAN NeedGuard;\r
28a00297 220\r
221 //\r
222 // If it's not a valid type, fail it\r
223 //\r
8ee25f48 224 if ((PoolType >= EfiMaxMemoryType && PoolType < MEMORY_TYPE_OEM_RESERVED_MIN) ||\r
a671a012 225 (PoolType == EfiConventionalMemory) || (PoolType == EfiPersistentMemory)) {\r
28a00297 226 return EFI_INVALID_PARAMETER;\r
227 }\r
022c6d45 228\r
3e058701
ED
229 if (Buffer == NULL) {\r
230 return EFI_INVALID_PARAMETER;\r
231 }\r
232\r
28a00297 233 *Buffer = NULL;\r
022c6d45 234\r
28a00297 235 //\r
236 // If size is too large, fail it\r
237 // Base on the EFI spec, return status of EFI_OUT_OF_RESOURCES\r
238 //\r
239 if (Size > MAX_POOL_SIZE) {\r
240 return EFI_OUT_OF_RESOURCES;\r
241 }\r
242\r
e63da9f0
JW
243 NeedGuard = IsPoolTypeToGuard (PoolType) && !mOnGuarding;\r
244\r
28a00297 245 //\r
246 // Acquire the memory lock and make the allocation\r
247 //\r
f31c36c2 248 Status = CoreAcquireLockOrFail (&mPoolMemoryLock);\r
28a00297 249 if (EFI_ERROR (Status)) {\r
250 return EFI_OUT_OF_RESOURCES;\r
251 }\r
252\r
e63da9f0 253 *Buffer = CoreAllocatePoolI (PoolType, Size, NeedGuard);\r
f31c36c2 254 CoreReleaseLock (&mPoolMemoryLock);\r
28a00297 255 return (*Buffer != NULL) ? EFI_SUCCESS : EFI_OUT_OF_RESOURCES;\r
256}\r
257\r
84edd20b
SZ
258/**\r
259 Allocate pool of a particular type.\r
260\r
261 @param PoolType Type of pool to allocate\r
262 @param Size The amount of pool to allocate\r
263 @param Buffer The address to return a pointer to the allocated\r
264 pool\r
265\r
2eb989bc
SZ
266 @retval EFI_INVALID_PARAMETER Buffer is NULL.\r
267 PoolType is in the range EfiMaxMemoryType..0x6FFFFFFF.\r
268 PoolType is EfiPersistentMemory.\r
84edd20b
SZ
269 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.\r
270 @retval EFI_SUCCESS Pool successfully allocated.\r
271\r
272**/\r
273EFI_STATUS\r
274EFIAPI\r
275CoreAllocatePool (\r
276 IN EFI_MEMORY_TYPE PoolType,\r
277 IN UINTN Size,\r
278 OUT VOID **Buffer\r
279 )\r
280{\r
281 EFI_STATUS Status;\r
28a00297 282\r
84edd20b
SZ
283 Status = CoreInternalAllocatePool (PoolType, Size, Buffer);\r
284 if (!EFI_ERROR (Status)) {\r
1d60fe96
SZ
285 CoreUpdateProfile (\r
286 (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),\r
287 MemoryProfileActionAllocatePool,\r
288 PoolType,\r
289 Size,\r
290 *Buffer,\r
291 NULL\r
292 );\r
74a88770 293 InstallMemoryAttributesTableOnMemoryAllocation (PoolType);\r
84edd20b
SZ
294 }\r
295 return Status;\r
296}\r
28a00297 297\r
7babb437
BD
298/**\r
299 Internal function. Used by the pool functions to allocate pages\r
300 to back pool allocation requests.\r
301\r
302 @param PoolType The type of memory for the new pool pages\r
303 @param NoPages No of pages to allocate\r
304 @param Granularity Bits to align.\r
e63da9f0 305 @param NeedGuard Flag to indicate Guard page is needed or not\r
7babb437
BD
306\r
307 @return The allocated memory, or NULL\r
308\r
309**/\r
f31c36c2
AB
310STATIC\r
311VOID *\r
312CoreAllocatePoolPagesI (\r
313 IN EFI_MEMORY_TYPE PoolType,\r
314 IN UINTN NoPages,\r
e63da9f0
JW
315 IN UINTN Granularity,\r
316 IN BOOLEAN NeedGuard\r
f31c36c2
AB
317 )\r
318{\r
319 VOID *Buffer;\r
320 EFI_STATUS Status;\r
321\r
322 Status = CoreAcquireLockOrFail (&gMemoryLock);\r
323 if (EFI_ERROR (Status)) {\r
324 return NULL;\r
325 }\r
326\r
e63da9f0 327 Buffer = CoreAllocatePoolPages (PoolType, NoPages, Granularity, NeedGuard);\r
f31c36c2
AB
328 CoreReleaseMemoryLock ();\r
329\r
7eb927db 330 if (Buffer != NULL) {\r
e63da9f0
JW
331 if (NeedGuard) {\r
332 SetGuardForMemory ((EFI_PHYSICAL_ADDRESS)(UINTN)Buffer, NoPages);\r
333 }\r
334 ApplyMemoryProtectionPolicy(EfiConventionalMemory, PoolType,\r
7eb927db
AB
335 (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer, EFI_PAGES_TO_SIZE (NoPages));\r
336 }\r
f31c36c2
AB
337 return Buffer;\r
338}\r
339\r
162ed594 340/**\r
28a00297 341 Internal function to allocate pool of a particular type.\r
28a00297 342 Caller must have the memory lock held\r
343\r
022c6d45 344 @param PoolType Type of pool to allocate\r
345 @param Size The amount of pool to allocate\r
e63da9f0 346 @param NeedGuard Flag to indicate Guard page is needed or not\r
28a00297 347\r
162ed594 348 @return The allocate pool, or NULL\r
28a00297 349\r
162ed594 350**/\r
351VOID *\r
352CoreAllocatePoolI (\r
353 IN EFI_MEMORY_TYPE PoolType,\r
e63da9f0
JW
354 IN UINTN Size,\r
355 IN BOOLEAN NeedGuard\r
162ed594 356 )\r
28a00297 357{\r
358 POOL *Pool;\r
359 POOL_FREE *Free;\r
360 POOL_HEAD *Head;\r
361 POOL_TAIL *Tail;\r
362 CHAR8 *NewPage;\r
363 VOID *Buffer;\r
364 UINTN Index;\r
365 UINTN FSize;\r
6860b92c 366 UINTN Offset, MaxOffset;\r
28a00297 367 UINTN NoPages;\r
7970100c 368 UINTN Granularity;\r
e63da9f0 369 BOOLEAN HasPoolTail;\r
28a00297 370\r
f31c36c2 371 ASSERT_LOCKED (&mPoolMemoryLock);\r
28a00297 372\r
7970100c
AB
373 if (PoolType == EfiACPIReclaimMemory ||\r
374 PoolType == EfiACPIMemoryNVS ||\r
375 PoolType == EfiRuntimeServicesCode ||\r
376 PoolType == EfiRuntimeServicesData) {\r
377\r
d4731a98 378 Granularity = RUNTIME_PAGE_ALLOCATION_GRANULARITY;\r
7970100c 379 } else {\r
d4731a98 380 Granularity = DEFAULT_PAGE_ALLOCATION_GRANULARITY;\r
7970100c
AB
381 }\r
382\r
28a00297 383 //\r
384 // Adjust the size by the pool header & tail overhead\r
385 //\r
022c6d45 386\r
e63da9f0
JW
387 HasPoolTail = !(NeedGuard &&\r
388 ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0));\r
389\r
28a00297 390 //\r
391 // Adjusting the Size to be of proper alignment so that\r
392 // we don't get an unaligned access fault later when\r
393 // pool_Tail is being initialized\r
394 //\r
f0d5cbb6 395 Size = ALIGN_VARIABLE (Size);\r
28a00297 396\r
397 Size += POOL_OVERHEAD;\r
398 Index = SIZE_TO_LIST(Size);\r
399 Pool = LookupPoolHead (PoolType);\r
400 if (Pool== NULL) {\r
401 return NULL;\r
402 }\r
403 Head = NULL;\r
404\r
405 //\r
406 // If allocation is over max size, just allocate pages for the request\r
407 // (slow)\r
408 //\r
e63da9f0
JW
409 if (Index >= SIZE_TO_LIST (Granularity) || NeedGuard) {\r
410 if (!HasPoolTail) {\r
411 Size -= sizeof (POOL_TAIL);\r
412 }\r
413 NoPages = EFI_SIZE_TO_PAGES (Size) + EFI_SIZE_TO_PAGES (Granularity) - 1;\r
7970100c 414 NoPages &= ~(UINTN)(EFI_SIZE_TO_PAGES (Granularity) - 1);\r
e63da9f0
JW
415 Head = CoreAllocatePoolPagesI (PoolType, NoPages, Granularity, NeedGuard);\r
416 if (NeedGuard) {\r
417 Head = AdjustPoolHeadA ((EFI_PHYSICAL_ADDRESS)(UINTN)Head, NoPages, Size);\r
418 }\r
28a00297 419 goto Done;\r
420 }\r
421\r
422 //\r
423 // If there's no free pool in the proper list size, go get some more pages\r
424 //\r
425 if (IsListEmpty (&Pool->FreeList[Index])) {\r
426\r
6860b92c
AB
427 Offset = LIST_TO_SIZE (Index);\r
428 MaxOffset = Granularity;\r
429\r
430 //\r
431 // Check the bins holding larger blocks, and carve one up if needed\r
432 //\r
433 while (++Index < SIZE_TO_LIST (Granularity)) {\r
434 if (!IsListEmpty (&Pool->FreeList[Index])) {\r
435 Free = CR (Pool->FreeList[Index].ForwardLink, POOL_FREE, Link, POOL_FREE_SIGNATURE);\r
436 RemoveEntryList (&Free->Link);\r
437 NewPage = (VOID *) Free;\r
438 MaxOffset = LIST_TO_SIZE (Index);\r
439 goto Carve;\r
440 }\r
441 }\r
442\r
28a00297 443 //\r
444 // Get another page\r
445 //\r
e63da9f0
JW
446 NewPage = CoreAllocatePoolPagesI (PoolType, EFI_SIZE_TO_PAGES (Granularity),\r
447 Granularity, NeedGuard);\r
28a00297 448 if (NewPage == NULL) {\r
449 goto Done;\r
450 }\r
451\r
452 //\r
f8aabf6e 453 // Serve the allocation request from the head of the allocated block\r
28a00297 454 //\r
6860b92c 455Carve:\r
f8aabf6e 456 Head = (POOL_HEAD *) NewPage;\r
f8aabf6e
AB
457\r
458 //\r
459 // Carve up remaining space into free pool blocks\r
460 //\r
6860b92c
AB
461 Index--;\r
462 while (Offset < MaxOffset) {\r
28a00297 463 ASSERT (Index < MAX_POOL_LIST);\r
464 FSize = LIST_TO_SIZE(Index);\r
465\r
6860b92c 466 while (Offset + FSize <= MaxOffset) {\r
022c6d45 467 Free = (POOL_FREE *) &NewPage[Offset];\r
28a00297 468 Free->Signature = POOL_FREE_SIGNATURE;\r
469 Free->Index = (UINT32)Index;\r
470 InsertHeadList (&Pool->FreeList[Index], &Free->Link);\r
162ed594 471 Offset += FSize;\r
28a00297 472 }\r
28a00297 473 Index -= 1;\r
474 }\r
475\r
6860b92c 476 ASSERT (Offset == MaxOffset);\r
f8aabf6e 477 goto Done;\r
28a00297 478 }\r
479\r
480 //\r
481 // Remove entry from free pool list\r
482 //\r
483 Free = CR (Pool->FreeList[Index].ForwardLink, POOL_FREE, Link, POOL_FREE_SIGNATURE);\r
484 RemoveEntryList (&Free->Link);\r
485\r
486 Head = (POOL_HEAD *) Free;\r
487\r
488Done:\r
489 Buffer = NULL;\r
490\r
491 if (Head != NULL) {\r
022c6d45 492\r
e63da9f0
JW
493 //\r
494 // Account the allocation\r
495 //\r
496 Pool->Used += Size;\r
497\r
28a00297 498 //\r
499 // If we have a pool buffer, fill in the header & tail info\r
500 //\r
501 Head->Signature = POOL_HEAD_SIGNATURE;\r
bb683bf4 502 Head->Size = Size;\r
28a00297 503 Head->Type = (EFI_MEMORY_TYPE) PoolType;\r
28a00297 504 Buffer = Head->Data;\r
e63da9f0
JW
505\r
506 if (HasPoolTail) {\r
507 Tail = HEAD_TO_TAIL (Head);\r
508 Tail->Signature = POOL_TAIL_SIGNATURE;\r
509 Tail->Size = Size;\r
510\r
511 Size -= POOL_OVERHEAD;\r
512 } else {\r
513 Size -= SIZE_OF_POOL_HEAD;\r
514 }\r
515\r
516 DEBUG_CLEAR_MEMORY (Buffer, Size);\r
28a00297 517\r
e94a9ff7 518 DEBUG ((\r
519 DEBUG_POOL,\r
57b4ecb9 520 "AllocatePoolI: Type %x, Addr %p (len %lx) %,ld\n", PoolType,\r
022c6d45 521 Buffer,\r
e63da9f0 522 (UINT64)Size,\r
57b4ecb9 523 (UINT64) Pool->Used\r
e94a9ff7 524 ));\r
28a00297 525\r
28a00297 526\r
527 } else {\r
57b4ecb9 528 DEBUG ((DEBUG_ERROR | DEBUG_POOL, "AllocatePool: failed to allocate %ld bytes\n", (UINT64) Size));\r
28a00297 529 }\r
530\r
531 return Buffer;\r
532}\r
022c6d45 533\r
28a00297 534\r
535\r
162ed594 536/**\r
28a00297 537 Frees pool.\r
538\r
022c6d45 539 @param Buffer The allocated pool entry to free\r
925f0d1a 540 @param PoolType Pointer to pool type\r
28a00297 541\r
022c6d45 542 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.\r
162ed594 543 @retval EFI_SUCCESS Pool successfully freed.\r
28a00297 544\r
162ed594 545**/\r
546EFI_STATUS\r
547EFIAPI\r
84edd20b 548CoreInternalFreePool (\r
925f0d1a
SZ
549 IN VOID *Buffer,\r
550 OUT EFI_MEMORY_TYPE *PoolType OPTIONAL\r
162ed594 551 )\r
28a00297 552{\r
553 EFI_STATUS Status;\r
554\r
e94a9ff7 555 if (Buffer == NULL) {\r
28a00297 556 return EFI_INVALID_PARAMETER;\r
557 }\r
558\r
f31c36c2 559 CoreAcquireLock (&mPoolMemoryLock);\r
925f0d1a 560 Status = CoreFreePoolI (Buffer, PoolType);\r
f31c36c2 561 CoreReleaseLock (&mPoolMemoryLock);\r
28a00297 562 return Status;\r
563}\r
564\r
84edd20b
SZ
565/**\r
566 Frees pool.\r
567\r
568 @param Buffer The allocated pool entry to free\r
569\r
570 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.\r
571 @retval EFI_SUCCESS Pool successfully freed.\r
572\r
573**/\r
574EFI_STATUS\r
575EFIAPI\r
576CoreFreePool (\r
577 IN VOID *Buffer\r
578 )\r
579{\r
925f0d1a
SZ
580 EFI_STATUS Status;\r
581 EFI_MEMORY_TYPE PoolType;\r
736a692e 582\r
925f0d1a 583 Status = CoreInternalFreePool (Buffer, &PoolType);\r
736a692e 584 if (!EFI_ERROR (Status)) {\r
1d60fe96
SZ
585 CoreUpdateProfile (\r
586 (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),\r
587 MemoryProfileActionFreePool,\r
588 PoolType,\r
589 0,\r
590 Buffer,\r
591 NULL\r
592 );\r
74a88770 593 InstallMemoryAttributesTableOnMemoryAllocation (PoolType);\r
736a692e
HT
594 }\r
595 return Status;\r
596}\r
28a00297 597\r
7babb437
BD
598/**\r
599 Internal function. Frees pool pages allocated via CoreAllocatePoolPagesI().\r
600\r
601 @param PoolType The type of memory for the pool pages\r
602 @param Memory The base address to free\r
603 @param NoPages The number of pages to free\r
604\r
605**/\r
f31c36c2
AB
606STATIC\r
607VOID\r
608CoreFreePoolPagesI (\r
609 IN EFI_MEMORY_TYPE PoolType,\r
610 IN EFI_PHYSICAL_ADDRESS Memory,\r
611 IN UINTN NoPages\r
612 )\r
613{\r
614 CoreAcquireMemoryLock ();\r
615 CoreFreePoolPages (Memory, NoPages);\r
616 CoreReleaseMemoryLock ();\r
7eb927db
AB
617\r
618 ApplyMemoryProtectionPolicy (PoolType, EfiConventionalMemory,\r
619 (EFI_PHYSICAL_ADDRESS)(UINTN)Memory, EFI_PAGES_TO_SIZE (NoPages));\r
f31c36c2
AB
620}\r
621\r
e63da9f0
JW
622/**\r
623 Internal function. Frees guarded pool pages.\r
624\r
625 @param PoolType The type of memory for the pool pages\r
626 @param Memory The base address to free\r
627 @param NoPages The number of pages to free\r
628\r
629**/\r
630STATIC\r
631VOID\r
632CoreFreePoolPagesWithGuard (\r
633 IN EFI_MEMORY_TYPE PoolType,\r
634 IN EFI_PHYSICAL_ADDRESS Memory,\r
635 IN UINTN NoPages\r
636 )\r
637{\r
638 EFI_PHYSICAL_ADDRESS MemoryGuarded;\r
639 UINTN NoPagesGuarded;\r
640\r
641 MemoryGuarded = Memory;\r
642 NoPagesGuarded = NoPages;\r
643\r
644 AdjustMemoryF (&Memory, &NoPages);\r
1263ecf2
JW
645 //\r
646 // It's safe to unset Guard page inside memory lock because there should\r
647 // be no memory allocation occurred in updating memory page attribute at\r
648 // this point. And unsetting Guard page before free will prevent Guard\r
649 // page just freed back to pool from being allocated right away before\r
650 // marking it usable (from non-present to present).\r
651 //\r
652 UnsetGuardForMemory (MemoryGuarded, NoPagesGuarded);\r
6cf0a677
JW
653 if (NoPages > 0) {\r
654 CoreFreePoolPagesI (PoolType, Memory, NoPages);\r
655 }\r
e63da9f0
JW
656}\r
657\r
162ed594 658/**\r
28a00297 659 Internal function to free a pool entry.\r
28a00297 660 Caller must have the memory lock held\r
661\r
022c6d45 662 @param Buffer The allocated pool entry to free\r
925f0d1a 663 @param PoolType Pointer to pool type\r
28a00297 664\r
022c6d45 665 @retval EFI_INVALID_PARAMETER Buffer not valid\r
162ed594 666 @retval EFI_SUCCESS Buffer successfully freed.\r
28a00297 667\r
162ed594 668**/\r
669EFI_STATUS\r
670CoreFreePoolI (\r
925f0d1a
SZ
671 IN VOID *Buffer,\r
672 OUT EFI_MEMORY_TYPE *PoolType OPTIONAL\r
162ed594 673 )\r
28a00297 674{\r
675 POOL *Pool;\r
676 POOL_HEAD *Head;\r
677 POOL_TAIL *Tail;\r
678 POOL_FREE *Free;\r
679 UINTN Index;\r
680 UINTN NoPages;\r
681 UINTN Size;\r
682 CHAR8 *NewPage;\r
162ed594 683 UINTN Offset;\r
28a00297 684 BOOLEAN AllFree;\r
7970100c 685 UINTN Granularity;\r
e63da9f0
JW
686 BOOLEAN IsGuarded;\r
687 BOOLEAN HasPoolTail;\r
28a00297 688\r
57b4ecb9 689 ASSERT(Buffer != NULL);\r
28a00297 690 //\r
691 // Get the head & tail of the pool entry\r
692 //\r
693 Head = CR (Buffer, POOL_HEAD, Data, POOL_HEAD_SIGNATURE);\r
57b4ecb9 694 ASSERT(Head != NULL);\r
28a00297 695\r
696 if (Head->Signature != POOL_HEAD_SIGNATURE) {\r
697 return EFI_INVALID_PARAMETER;\r
698 }\r
699\r
e63da9f0
JW
700 IsGuarded = IsPoolTypeToGuard (Head->Type) &&\r
701 IsMemoryGuarded ((EFI_PHYSICAL_ADDRESS)(UINTN)Head);\r
702 HasPoolTail = !(IsGuarded &&\r
703 ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0));\r
704\r
705 if (HasPoolTail) {\r
706 Tail = HEAD_TO_TAIL (Head);\r
707 ASSERT (Tail != NULL);\r
708\r
709 //\r
710 // Debug\r
711 //\r
712 ASSERT (Tail->Signature == POOL_TAIL_SIGNATURE);\r
713 ASSERT (Head->Size == Tail->Size);\r
714\r
715 if (Tail->Signature != POOL_TAIL_SIGNATURE) {\r
716 return EFI_INVALID_PARAMETER;\r
717 }\r
718\r
719 if (Head->Size != Tail->Size) {\r
720 return EFI_INVALID_PARAMETER;\r
721 }\r
28a00297 722 }\r
723\r
e63da9f0
JW
724 ASSERT_LOCKED (&mPoolMemoryLock);\r
725\r
28a00297 726 //\r
727 // Determine the pool type and account for it\r
728 //\r
729 Size = Head->Size;\r
730 Pool = LookupPoolHead (Head->Type);\r
731 if (Pool == NULL) {\r
732 return EFI_INVALID_PARAMETER;\r
733 }\r
734 Pool->Used -= Size;\r
57b4ecb9 735 DEBUG ((DEBUG_POOL, "FreePool: %p (len %lx) %,ld\n", Head->Data, (UINT64)(Head->Size - POOL_OVERHEAD), (UINT64) Pool->Used));\r
28a00297 736\r
7970100c
AB
737 if (Head->Type == EfiACPIReclaimMemory ||\r
738 Head->Type == EfiACPIMemoryNVS ||\r
739 Head->Type == EfiRuntimeServicesCode ||\r
740 Head->Type == EfiRuntimeServicesData) {\r
741\r
d4731a98 742 Granularity = RUNTIME_PAGE_ALLOCATION_GRANULARITY;\r
7970100c 743 } else {\r
d4731a98 744 Granularity = DEFAULT_PAGE_ALLOCATION_GRANULARITY;\r
7970100c
AB
745 }\r
746\r
925f0d1a
SZ
747 if (PoolType != NULL) {\r
748 *PoolType = Head->Type;\r
749 }\r
750\r
28a00297 751 //\r
022c6d45 752 // Determine the pool list\r
28a00297 753 //\r
754 Index = SIZE_TO_LIST(Size);\r
755 DEBUG_CLEAR_MEMORY (Head, Size);\r
756\r
757 //\r
758 // If it's not on the list, it must be pool pages\r
759 //\r
e63da9f0 760 if (Index >= SIZE_TO_LIST (Granularity) || IsGuarded) {\r
28a00297 761\r
762 //\r
763 // Return the memory pages back to free memory\r
764 //\r
e63da9f0 765 NoPages = EFI_SIZE_TO_PAGES (Size) + EFI_SIZE_TO_PAGES (Granularity) - 1;\r
7970100c 766 NoPages &= ~(UINTN)(EFI_SIZE_TO_PAGES (Granularity) - 1);\r
e63da9f0
JW
767 if (IsGuarded) {\r
768 Head = AdjustPoolHeadF ((EFI_PHYSICAL_ADDRESS)(UINTN)Head);\r
769 CoreFreePoolPagesWithGuard (\r
770 Pool->MemoryType,\r
771 (EFI_PHYSICAL_ADDRESS)(UINTN)Head,\r
772 NoPages\r
773 );\r
774 } else {\r
775 CoreFreePoolPagesI (\r
776 Pool->MemoryType,\r
777 (EFI_PHYSICAL_ADDRESS)(UINTN)Head,\r
778 NoPages\r
779 );\r
780 }\r
28a00297 781\r
782 } else {\r
783\r
784 //\r
785 // Put the pool entry onto the free pool list\r
786 //\r
787 Free = (POOL_FREE *) Head;\r
57b4ecb9 788 ASSERT(Free != NULL);\r
28a00297 789 Free->Signature = POOL_FREE_SIGNATURE;\r
790 Free->Index = (UINT32)Index;\r
791 InsertHeadList (&Pool->FreeList[Index], &Free->Link);\r
792\r
793 //\r
022c6d45 794 // See if all the pool entries in the same page as Free are freed pool\r
28a00297 795 // entries\r
796 //\r
7970100c 797 NewPage = (CHAR8 *)((UINTN)Free & ~(Granularity - 1));\r
28a00297 798 Free = (POOL_FREE *) &NewPage[0];\r
e94a9ff7 799 ASSERT(Free != NULL);\r
28a00297 800\r
801 if (Free->Signature == POOL_FREE_SIGNATURE) {\r
802\r
28a00297 803 AllFree = TRUE;\r
162ed594 804 Offset = 0;\r
022c6d45 805\r
7970100c 806 while ((Offset < Granularity) && (AllFree)) {\r
7e8e2205
AB
807 Free = (POOL_FREE *) &NewPage[Offset];\r
808 ASSERT(Free != NULL);\r
809 if (Free->Signature != POOL_FREE_SIGNATURE) {\r
810 AllFree = FALSE;\r
28a00297 811 }\r
7e8e2205 812 Offset += LIST_TO_SIZE(Free->Index);\r
28a00297 813 }\r
814\r
815 if (AllFree) {\r
816\r
817 //\r
022c6d45 818 // All of the pool entries in the same page as Free are free pool\r
28a00297 819 // entries\r
820 // Remove all of these pool entries from the free loop lists.\r
821 //\r
822 Free = (POOL_FREE *) &NewPage[0];\r
57b4ecb9 823 ASSERT(Free != NULL);\r
162ed594 824 Offset = 0;\r
022c6d45 825\r
7970100c 826 while (Offset < Granularity) {\r
7e8e2205
AB
827 Free = (POOL_FREE *) &NewPage[Offset];\r
828 ASSERT(Free != NULL);\r
829 RemoveEntryList (&Free->Link);\r
830 Offset += LIST_TO_SIZE(Free->Index);\r
28a00297 831 }\r
832\r
833 //\r
834 // Free the page\r
835 //\r
f31c36c2
AB
836 CoreFreePoolPagesI (Pool->MemoryType, (EFI_PHYSICAL_ADDRESS) (UINTN)NewPage,\r
837 EFI_SIZE_TO_PAGES (Granularity));\r
28a00297 838 }\r
839 }\r
840 }\r
841\r
842 //\r
09159a29 843 // If this is an OS/OEM specific memory type, then check to see if the last\r
28a00297 844 // portion of that memory type has been freed. If it has, then free the\r
845 // list entry for that memory type\r
846 //\r
09159a29 847 if (((UINT32) Pool->MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) && Pool->Used == 0) {\r
28a00297 848 RemoveEntryList (&Pool->Link);\r
925f0d1a 849 CoreFreePoolI (Pool, NULL);\r
28a00297 850 }\r
851\r
852 return EFI_SUCCESS;\r
853}\r
84edd20b 854\r