]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/Dxe/Mem/Pool.c
MdeModulePkg: Fix unix style of EOL
[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
645 CoreFreePoolPagesI (PoolType, Memory, NoPages);\r
646\r
647 UnsetGuardForMemory (MemoryGuarded, NoPagesGuarded);\r
648}\r
649\r
162ed594 650/**\r
28a00297 651 Internal function to free a pool entry.\r
28a00297 652 Caller must have the memory lock held\r
653\r
022c6d45 654 @param Buffer The allocated pool entry to free\r
925f0d1a 655 @param PoolType Pointer to pool type\r
28a00297 656\r
022c6d45 657 @retval EFI_INVALID_PARAMETER Buffer not valid\r
162ed594 658 @retval EFI_SUCCESS Buffer successfully freed.\r
28a00297 659\r
162ed594 660**/\r
661EFI_STATUS\r
662CoreFreePoolI (\r
925f0d1a
SZ
663 IN VOID *Buffer,\r
664 OUT EFI_MEMORY_TYPE *PoolType OPTIONAL\r
162ed594 665 )\r
28a00297 666{\r
667 POOL *Pool;\r
668 POOL_HEAD *Head;\r
669 POOL_TAIL *Tail;\r
670 POOL_FREE *Free;\r
671 UINTN Index;\r
672 UINTN NoPages;\r
673 UINTN Size;\r
674 CHAR8 *NewPage;\r
162ed594 675 UINTN Offset;\r
28a00297 676 BOOLEAN AllFree;\r
7970100c 677 UINTN Granularity;\r
e63da9f0
JW
678 BOOLEAN IsGuarded;\r
679 BOOLEAN HasPoolTail;\r
28a00297 680\r
57b4ecb9 681 ASSERT(Buffer != NULL);\r
28a00297 682 //\r
683 // Get the head & tail of the pool entry\r
684 //\r
685 Head = CR (Buffer, POOL_HEAD, Data, POOL_HEAD_SIGNATURE);\r
57b4ecb9 686 ASSERT(Head != NULL);\r
28a00297 687\r
688 if (Head->Signature != POOL_HEAD_SIGNATURE) {\r
689 return EFI_INVALID_PARAMETER;\r
690 }\r
691\r
e63da9f0
JW
692 IsGuarded = IsPoolTypeToGuard (Head->Type) &&\r
693 IsMemoryGuarded ((EFI_PHYSICAL_ADDRESS)(UINTN)Head);\r
694 HasPoolTail = !(IsGuarded &&\r
695 ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0));\r
696\r
697 if (HasPoolTail) {\r
698 Tail = HEAD_TO_TAIL (Head);\r
699 ASSERT (Tail != NULL);\r
700\r
701 //\r
702 // Debug\r
703 //\r
704 ASSERT (Tail->Signature == POOL_TAIL_SIGNATURE);\r
705 ASSERT (Head->Size == Tail->Size);\r
706\r
707 if (Tail->Signature != POOL_TAIL_SIGNATURE) {\r
708 return EFI_INVALID_PARAMETER;\r
709 }\r
710\r
711 if (Head->Size != Tail->Size) {\r
712 return EFI_INVALID_PARAMETER;\r
713 }\r
28a00297 714 }\r
715\r
e63da9f0
JW
716 ASSERT_LOCKED (&mPoolMemoryLock);\r
717\r
28a00297 718 //\r
719 // Determine the pool type and account for it\r
720 //\r
721 Size = Head->Size;\r
722 Pool = LookupPoolHead (Head->Type);\r
723 if (Pool == NULL) {\r
724 return EFI_INVALID_PARAMETER;\r
725 }\r
726 Pool->Used -= Size;\r
57b4ecb9 727 DEBUG ((DEBUG_POOL, "FreePool: %p (len %lx) %,ld\n", Head->Data, (UINT64)(Head->Size - POOL_OVERHEAD), (UINT64) Pool->Used));\r
28a00297 728\r
7970100c
AB
729 if (Head->Type == EfiACPIReclaimMemory ||\r
730 Head->Type == EfiACPIMemoryNVS ||\r
731 Head->Type == EfiRuntimeServicesCode ||\r
732 Head->Type == EfiRuntimeServicesData) {\r
733\r
d4731a98 734 Granularity = RUNTIME_PAGE_ALLOCATION_GRANULARITY;\r
7970100c 735 } else {\r
d4731a98 736 Granularity = DEFAULT_PAGE_ALLOCATION_GRANULARITY;\r
7970100c
AB
737 }\r
738\r
925f0d1a
SZ
739 if (PoolType != NULL) {\r
740 *PoolType = Head->Type;\r
741 }\r
742\r
28a00297 743 //\r
022c6d45 744 // Determine the pool list\r
28a00297 745 //\r
746 Index = SIZE_TO_LIST(Size);\r
747 DEBUG_CLEAR_MEMORY (Head, Size);\r
748\r
749 //\r
750 // If it's not on the list, it must be pool pages\r
751 //\r
e63da9f0 752 if (Index >= SIZE_TO_LIST (Granularity) || IsGuarded) {\r
28a00297 753\r
754 //\r
755 // Return the memory pages back to free memory\r
756 //\r
e63da9f0 757 NoPages = EFI_SIZE_TO_PAGES (Size) + EFI_SIZE_TO_PAGES (Granularity) - 1;\r
7970100c 758 NoPages &= ~(UINTN)(EFI_SIZE_TO_PAGES (Granularity) - 1);\r
e63da9f0
JW
759 if (IsGuarded) {\r
760 Head = AdjustPoolHeadF ((EFI_PHYSICAL_ADDRESS)(UINTN)Head);\r
761 CoreFreePoolPagesWithGuard (\r
762 Pool->MemoryType,\r
763 (EFI_PHYSICAL_ADDRESS)(UINTN)Head,\r
764 NoPages\r
765 );\r
766 } else {\r
767 CoreFreePoolPagesI (\r
768 Pool->MemoryType,\r
769 (EFI_PHYSICAL_ADDRESS)(UINTN)Head,\r
770 NoPages\r
771 );\r
772 }\r
28a00297 773\r
774 } else {\r
775\r
776 //\r
777 // Put the pool entry onto the free pool list\r
778 //\r
779 Free = (POOL_FREE *) Head;\r
57b4ecb9 780 ASSERT(Free != NULL);\r
28a00297 781 Free->Signature = POOL_FREE_SIGNATURE;\r
782 Free->Index = (UINT32)Index;\r
783 InsertHeadList (&Pool->FreeList[Index], &Free->Link);\r
784\r
785 //\r
022c6d45 786 // See if all the pool entries in the same page as Free are freed pool\r
28a00297 787 // entries\r
788 //\r
7970100c 789 NewPage = (CHAR8 *)((UINTN)Free & ~(Granularity - 1));\r
28a00297 790 Free = (POOL_FREE *) &NewPage[0];\r
e94a9ff7 791 ASSERT(Free != NULL);\r
28a00297 792\r
793 if (Free->Signature == POOL_FREE_SIGNATURE) {\r
794\r
28a00297 795 AllFree = TRUE;\r
162ed594 796 Offset = 0;\r
022c6d45 797\r
7970100c 798 while ((Offset < Granularity) && (AllFree)) {\r
7e8e2205
AB
799 Free = (POOL_FREE *) &NewPage[Offset];\r
800 ASSERT(Free != NULL);\r
801 if (Free->Signature != POOL_FREE_SIGNATURE) {\r
802 AllFree = FALSE;\r
28a00297 803 }\r
7e8e2205 804 Offset += LIST_TO_SIZE(Free->Index);\r
28a00297 805 }\r
806\r
807 if (AllFree) {\r
808\r
809 //\r
022c6d45 810 // All of the pool entries in the same page as Free are free pool\r
28a00297 811 // entries\r
812 // Remove all of these pool entries from the free loop lists.\r
813 //\r
814 Free = (POOL_FREE *) &NewPage[0];\r
57b4ecb9 815 ASSERT(Free != NULL);\r
162ed594 816 Offset = 0;\r
022c6d45 817\r
7970100c 818 while (Offset < Granularity) {\r
7e8e2205
AB
819 Free = (POOL_FREE *) &NewPage[Offset];\r
820 ASSERT(Free != NULL);\r
821 RemoveEntryList (&Free->Link);\r
822 Offset += LIST_TO_SIZE(Free->Index);\r
28a00297 823 }\r
824\r
825 //\r
826 // Free the page\r
827 //\r
f31c36c2
AB
828 CoreFreePoolPagesI (Pool->MemoryType, (EFI_PHYSICAL_ADDRESS) (UINTN)NewPage,\r
829 EFI_SIZE_TO_PAGES (Granularity));\r
28a00297 830 }\r
831 }\r
832 }\r
833\r
834 //\r
09159a29 835 // If this is an OS/OEM specific memory type, then check to see if the last\r
28a00297 836 // portion of that memory type has been freed. If it has, then free the\r
837 // list entry for that memory type\r
838 //\r
09159a29 839 if (((UINT32) Pool->MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) && Pool->Used == 0) {\r
28a00297 840 RemoveEntryList (&Pool->Link);\r
925f0d1a 841 CoreFreePoolI (Pool, NULL);\r
28a00297 842 }\r
843\r
844 return EFI_SUCCESS;\r
845}\r
84edd20b 846\r