]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/Dxe/Mem/Pool.c
MdeModulePkg DxeCore: Enhance memory profile for memory leak detection
[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
28a00297 17\r
f3f2e05d 18#define POOL_FREE_SIGNATURE SIGNATURE_32('p','f','r','0')\r
28a00297 19typedef struct {\r
20 UINT32 Signature;\r
21 UINT32 Index;\r
22 LIST_ENTRY Link;\r
23} POOL_FREE;\r
24\r
25\r
f3f2e05d 26#define POOL_HEAD_SIGNATURE SIGNATURE_32('p','h','d','0')\r
28a00297 27typedef struct {\r
28 UINT32 Signature;\r
bb683bf4 29 UINT32 Reserved;\r
28a00297 30 EFI_MEMORY_TYPE Type;\r
bb683bf4 31 UINTN Size;\r
28a00297 32 CHAR8 Data[1];\r
33} POOL_HEAD;\r
34\r
f3f2e05d 35#define SIZE_OF_POOL_HEAD OFFSET_OF(POOL_HEAD,Data)\r
28a00297 36\r
f3f2e05d 37#define POOL_TAIL_SIGNATURE SIGNATURE_32('p','t','a','l')\r
28a00297 38typedef struct {\r
39 UINT32 Signature;\r
bb683bf4
SZ
40 UINT32 Reserved;\r
41 UINTN Size;\r
28a00297 42} POOL_TAIL;\r
43\r
28a00297 44#define POOL_OVERHEAD (SIZE_OF_POOL_HEAD + sizeof(POOL_TAIL))\r
45\r
46#define HEAD_TO_TAIL(a) \\r
47 ((POOL_TAIL *) (((CHAR8 *) (a)) + (a)->Size - sizeof(POOL_TAIL)));\r
48\r
f2c7daf6
AB
49//\r
50// Each element is the sum of the 2 previous ones: this allows us to migrate\r
51// blocks between bins by splitting them up, while not wasting too much memory\r
52// as we would in a strict power-of-2 sequence\r
53//\r
54STATIC CONST UINT16 mPoolSizeTable[] = {\r
467d5f6b 55 128, 256, 384, 640, 1024, 1664, 2688, 4352, 7040, 11392, 18432, 29824\r
f2c7daf6 56};\r
28a00297 57\r
f2c7daf6
AB
58#define SIZE_TO_LIST(a) (GetPoolIndexFromSize (a))\r
59#define LIST_TO_SIZE(a) (mPoolSizeTable [a])\r
28a00297 60\r
f2c7daf6 61#define MAX_POOL_LIST (sizeof (mPoolSizeTable) / sizeof (mPoolSizeTable[0]))\r
28a00297 62\r
63#define MAX_POOL_SIZE (MAX_ADDRESS - POOL_OVERHEAD)\r
64\r
65//\r
66// Globals\r
67//\r
68\r
f3f2e05d 69#define POOL_SIGNATURE SIGNATURE_32('p','l','s','t')\r
28a00297 70typedef struct {\r
71 INTN Signature;\r
72 UINTN Used;\r
73 EFI_MEMORY_TYPE MemoryType;\r
74 LIST_ENTRY FreeList[MAX_POOL_LIST];\r
75 LIST_ENTRY Link;\r
022c6d45 76} POOL;\r
28a00297 77\r
28a00297 78//\r
e94a9ff7 79// Pool header for each memory type.\r
80//\r
81POOL mPoolHead[EfiMaxMemoryType];\r
82\r
28a00297 83//\r
e94a9ff7 84// List of pool header to search for the appropriate memory type.\r
28a00297 85//\r
57b4ecb9 86LIST_ENTRY mPoolHeadList = INITIALIZE_LIST_HEAD_VARIABLE (mPoolHeadList);\r
28a00297 87\r
dd51e45b
SQ
88/**\r
89 Get pool size table index from the specified size.\r
90\r
91 @param Size The specified size to get index from pool table.\r
92\r
93 @return The index of pool size table.\r
94\r
95**/\r
f2c7daf6
AB
96STATIC\r
97UINTN\r
98GetPoolIndexFromSize (\r
99 UINTN Size\r
100 )\r
101{\r
102 UINTN Index;\r
103\r
104 for (Index = 0; Index < MAX_POOL_LIST; Index++) {\r
105 if (mPoolSizeTable [Index] >= Size) {\r
106 return Index;\r
107 }\r
108 }\r
109 return MAX_POOL_LIST;\r
110}\r
162ed594 111\r
112/**\r
113 Called to initialize the pool.\r
114\r
115**/\r
28a00297 116VOID\r
117CoreInitializePool (\r
118 VOID\r
119 )\r
28a00297 120{\r
121 UINTN Type;\r
122 UINTN Index;\r
123\r
124 for (Type=0; Type < EfiMaxMemoryType; Type++) {\r
e94a9ff7 125 mPoolHead[Type].Signature = 0;\r
126 mPoolHead[Type].Used = 0;\r
127 mPoolHead[Type].MemoryType = (EFI_MEMORY_TYPE) Type;\r
28a00297 128 for (Index=0; Index < MAX_POOL_LIST; Index++) {\r
bb683bf4 129 InitializeListHead (&mPoolHead[Type].FreeList[Index]);\r
28a00297 130 }\r
131 }\r
28a00297 132}\r
133\r
28a00297 134\r
162ed594 135/**\r
28a00297 136 Look up pool head for specified memory type.\r
137\r
022c6d45 138 @param MemoryType Memory type of which pool head is looked for\r
28a00297 139\r
162ed594 140 @return Pointer of Corresponding pool head.\r
28a00297 141\r
162ed594 142**/\r
162ed594 143POOL *\r
144LookupPoolHead (\r
145 IN EFI_MEMORY_TYPE MemoryType\r
146 )\r
28a00297 147{\r
148 LIST_ENTRY *Link;\r
149 POOL *Pool;\r
150 UINTN Index;\r
151\r
3d78c020 152 if ((UINT32)MemoryType < EfiMaxMemoryType) {\r
e94a9ff7 153 return &mPoolHead[MemoryType];\r
28a00297 154 }\r
155\r
dc8d93ca 156 //\r
8ee25f48
SZ
157 // MemoryType values in the range 0x80000000..0xFFFFFFFF are reserved for use by UEFI\r
158 // OS loaders that are provided by operating system vendors.\r
159 // MemoryType values in the range 0x70000000..0x7FFFFFFF are reserved for OEM use.\r
dc8d93ca 160 //\r
8ee25f48 161 if ((UINT32) MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) {\r
28a00297 162\r
e94a9ff7 163 for (Link = mPoolHeadList.ForwardLink; Link != &mPoolHeadList; Link = Link->ForwardLink) {\r
28a00297 164 Pool = CR(Link, POOL, Link, POOL_SIGNATURE);\r
165 if (Pool->MemoryType == MemoryType) {\r
166 return Pool;\r
167 }\r
168 }\r
169\r
170 Pool = CoreAllocatePoolI (EfiBootServicesData, sizeof (POOL));\r
171 if (Pool == NULL) {\r
172 return NULL;\r
173 }\r
174\r
175 Pool->Signature = POOL_SIGNATURE;\r
176 Pool->Used = 0;\r
177 Pool->MemoryType = MemoryType;\r
178 for (Index=0; Index < MAX_POOL_LIST; Index++) {\r
179 InitializeListHead (&Pool->FreeList[Index]);\r
180 }\r
181\r
e94a9ff7 182 InsertHeadList (&mPoolHeadList, &Pool->Link);\r
28a00297 183\r
184 return Pool;\r
185 }\r
186\r
187 return NULL;\r
188}\r
189\r
022c6d45 190\r
28a00297 191\r
162ed594 192/**\r
193 Allocate pool of a particular type.\r
194\r
022c6d45 195 @param PoolType Type of pool to allocate\r
196 @param Size The amount of pool to allocate\r
197 @param Buffer The address to return a pointer to the allocated\r
198 pool\r
162ed594 199\r
2eb989bc
SZ
200 @retval EFI_INVALID_PARAMETER Buffer is NULL.\r
201 PoolType is in the range EfiMaxMemoryType..0x6FFFFFFF.\r
202 PoolType is EfiPersistentMemory.\r
022c6d45 203 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.\r
162ed594 204 @retval EFI_SUCCESS Pool successfully allocated.\r
205\r
206**/\r
28a00297 207EFI_STATUS\r
208EFIAPI\r
84edd20b 209CoreInternalAllocatePool (\r
28a00297 210 IN EFI_MEMORY_TYPE PoolType,\r
211 IN UINTN Size,\r
212 OUT VOID **Buffer\r
213 )\r
28a00297 214{\r
215 EFI_STATUS Status;\r
216\r
217 //\r
218 // If it's not a valid type, fail it\r
219 //\r
8ee25f48 220 if ((PoolType >= EfiMaxMemoryType && PoolType < MEMORY_TYPE_OEM_RESERVED_MIN) ||\r
a671a012 221 (PoolType == EfiConventionalMemory) || (PoolType == EfiPersistentMemory)) {\r
28a00297 222 return EFI_INVALID_PARAMETER;\r
223 }\r
022c6d45 224\r
3e058701
ED
225 if (Buffer == NULL) {\r
226 return EFI_INVALID_PARAMETER;\r
227 }\r
228\r
28a00297 229 *Buffer = NULL;\r
022c6d45 230\r
28a00297 231 //\r
232 // If size is too large, fail it\r
233 // Base on the EFI spec, return status of EFI_OUT_OF_RESOURCES\r
234 //\r
235 if (Size > MAX_POOL_SIZE) {\r
236 return EFI_OUT_OF_RESOURCES;\r
237 }\r
238\r
239 //\r
240 // Acquire the memory lock and make the allocation\r
241 //\r
242 Status = CoreAcquireLockOrFail (&gMemoryLock);\r
243 if (EFI_ERROR (Status)) {\r
244 return EFI_OUT_OF_RESOURCES;\r
245 }\r
246\r
247 *Buffer = CoreAllocatePoolI (PoolType, Size);\r
248 CoreReleaseMemoryLock ();\r
249 return (*Buffer != NULL) ? EFI_SUCCESS : EFI_OUT_OF_RESOURCES;\r
250}\r
251\r
84edd20b
SZ
252/**\r
253 Allocate pool of a particular type.\r
254\r
255 @param PoolType Type of pool to allocate\r
256 @param Size The amount of pool to allocate\r
257 @param Buffer The address to return a pointer to the allocated\r
258 pool\r
259\r
2eb989bc
SZ
260 @retval EFI_INVALID_PARAMETER Buffer is NULL.\r
261 PoolType is in the range EfiMaxMemoryType..0x6FFFFFFF.\r
262 PoolType is EfiPersistentMemory.\r
84edd20b
SZ
263 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.\r
264 @retval EFI_SUCCESS Pool successfully allocated.\r
265\r
266**/\r
267EFI_STATUS\r
268EFIAPI\r
269CoreAllocatePool (\r
270 IN EFI_MEMORY_TYPE PoolType,\r
271 IN UINTN Size,\r
272 OUT VOID **Buffer\r
273 )\r
274{\r
275 EFI_STATUS Status;\r
28a00297 276\r
84edd20b
SZ
277 Status = CoreInternalAllocatePool (PoolType, Size, Buffer);\r
278 if (!EFI_ERROR (Status)) {\r
1d60fe96
SZ
279 CoreUpdateProfile (\r
280 (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),\r
281 MemoryProfileActionAllocatePool,\r
282 PoolType,\r
283 Size,\r
284 *Buffer,\r
285 NULL\r
286 );\r
74a88770 287 InstallMemoryAttributesTableOnMemoryAllocation (PoolType);\r
84edd20b
SZ
288 }\r
289 return Status;\r
290}\r
28a00297 291\r
162ed594 292/**\r
28a00297 293 Internal function to allocate pool of a particular type.\r
28a00297 294 Caller must have the memory lock held\r
295\r
022c6d45 296 @param PoolType Type of pool to allocate\r
297 @param Size The amount of pool to allocate\r
28a00297 298\r
162ed594 299 @return The allocate pool, or NULL\r
28a00297 300\r
162ed594 301**/\r
302VOID *\r
303CoreAllocatePoolI (\r
304 IN EFI_MEMORY_TYPE PoolType,\r
305 IN UINTN Size\r
306 )\r
28a00297 307{\r
308 POOL *Pool;\r
309 POOL_FREE *Free;\r
310 POOL_HEAD *Head;\r
311 POOL_TAIL *Tail;\r
312 CHAR8 *NewPage;\r
313 VOID *Buffer;\r
314 UINTN Index;\r
315 UINTN FSize;\r
6860b92c 316 UINTN Offset, MaxOffset;\r
28a00297 317 UINTN NoPages;\r
7970100c 318 UINTN Granularity;\r
28a00297 319\r
320 ASSERT_LOCKED (&gMemoryLock);\r
321\r
7970100c
AB
322 if (PoolType == EfiACPIReclaimMemory ||\r
323 PoolType == EfiACPIMemoryNVS ||\r
324 PoolType == EfiRuntimeServicesCode ||\r
325 PoolType == EfiRuntimeServicesData) {\r
326\r
327 Granularity = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;\r
328 } else {\r
329 Granularity = DEFAULT_PAGE_ALLOCATION;\r
330 }\r
331\r
28a00297 332 //\r
333 // Adjust the size by the pool header & tail overhead\r
334 //\r
022c6d45 335\r
28a00297 336 //\r
337 // Adjusting the Size to be of proper alignment so that\r
338 // we don't get an unaligned access fault later when\r
339 // pool_Tail is being initialized\r
340 //\r
f0d5cbb6 341 Size = ALIGN_VARIABLE (Size);\r
28a00297 342\r
343 Size += POOL_OVERHEAD;\r
344 Index = SIZE_TO_LIST(Size);\r
345 Pool = LookupPoolHead (PoolType);\r
346 if (Pool== NULL) {\r
347 return NULL;\r
348 }\r
349 Head = NULL;\r
350\r
351 //\r
352 // If allocation is over max size, just allocate pages for the request\r
353 // (slow)\r
354 //\r
f2c7daf6 355 if (Index >= SIZE_TO_LIST (Granularity)) {\r
7970100c
AB
356 NoPages = EFI_SIZE_TO_PAGES(Size) + EFI_SIZE_TO_PAGES (Granularity) - 1;\r
357 NoPages &= ~(UINTN)(EFI_SIZE_TO_PAGES (Granularity) - 1);\r
358 Head = CoreAllocatePoolPages (PoolType, NoPages, Granularity);\r
28a00297 359 goto Done;\r
360 }\r
361\r
362 //\r
363 // If there's no free pool in the proper list size, go get some more pages\r
364 //\r
365 if (IsListEmpty (&Pool->FreeList[Index])) {\r
366\r
6860b92c
AB
367 Offset = LIST_TO_SIZE (Index);\r
368 MaxOffset = Granularity;\r
369\r
370 //\r
371 // Check the bins holding larger blocks, and carve one up if needed\r
372 //\r
373 while (++Index < SIZE_TO_LIST (Granularity)) {\r
374 if (!IsListEmpty (&Pool->FreeList[Index])) {\r
375 Free = CR (Pool->FreeList[Index].ForwardLink, POOL_FREE, Link, POOL_FREE_SIGNATURE);\r
376 RemoveEntryList (&Free->Link);\r
377 NewPage = (VOID *) Free;\r
378 MaxOffset = LIST_TO_SIZE (Index);\r
379 goto Carve;\r
380 }\r
381 }\r
382\r
28a00297 383 //\r
384 // Get another page\r
385 //\r
7970100c 386 NewPage = CoreAllocatePoolPages(PoolType, EFI_SIZE_TO_PAGES (Granularity), Granularity);\r
28a00297 387 if (NewPage == NULL) {\r
388 goto Done;\r
389 }\r
390\r
391 //\r
f8aabf6e 392 // Serve the allocation request from the head of the allocated block\r
28a00297 393 //\r
6860b92c 394Carve:\r
f8aabf6e 395 Head = (POOL_HEAD *) NewPage;\r
f8aabf6e
AB
396\r
397 //\r
398 // Carve up remaining space into free pool blocks\r
399 //\r
6860b92c
AB
400 Index--;\r
401 while (Offset < MaxOffset) {\r
28a00297 402 ASSERT (Index < MAX_POOL_LIST);\r
403 FSize = LIST_TO_SIZE(Index);\r
404\r
6860b92c 405 while (Offset + FSize <= MaxOffset) {\r
022c6d45 406 Free = (POOL_FREE *) &NewPage[Offset];\r
28a00297 407 Free->Signature = POOL_FREE_SIGNATURE;\r
408 Free->Index = (UINT32)Index;\r
409 InsertHeadList (&Pool->FreeList[Index], &Free->Link);\r
162ed594 410 Offset += FSize;\r
28a00297 411 }\r
28a00297 412 Index -= 1;\r
413 }\r
414\r
6860b92c 415 ASSERT (Offset == MaxOffset);\r
f8aabf6e 416 goto Done;\r
28a00297 417 }\r
418\r
419 //\r
420 // Remove entry from free pool list\r
421 //\r
422 Free = CR (Pool->FreeList[Index].ForwardLink, POOL_FREE, Link, POOL_FREE_SIGNATURE);\r
423 RemoveEntryList (&Free->Link);\r
424\r
425 Head = (POOL_HEAD *) Free;\r
426\r
427Done:\r
428 Buffer = NULL;\r
429\r
430 if (Head != NULL) {\r
022c6d45 431\r
28a00297 432 //\r
433 // If we have a pool buffer, fill in the header & tail info\r
434 //\r
435 Head->Signature = POOL_HEAD_SIGNATURE;\r
bb683bf4 436 Head->Size = Size;\r
28a00297 437 Head->Type = (EFI_MEMORY_TYPE) PoolType;\r
438 Tail = HEAD_TO_TAIL (Head);\r
439 Tail->Signature = POOL_TAIL_SIGNATURE;\r
bb683bf4 440 Tail->Size = Size;\r
28a00297 441 Buffer = Head->Data;\r
442 DEBUG_CLEAR_MEMORY (Buffer, Size - POOL_OVERHEAD);\r
443\r
e94a9ff7 444 DEBUG ((\r
445 DEBUG_POOL,\r
57b4ecb9 446 "AllocatePoolI: Type %x, Addr %p (len %lx) %,ld\n", PoolType,\r
022c6d45 447 Buffer,\r
57b4ecb9 448 (UINT64)(Size - POOL_OVERHEAD),\r
449 (UINT64) Pool->Used\r
e94a9ff7 450 ));\r
28a00297 451\r
452 //\r
453 // Account the allocation\r
454 //\r
455 Pool->Used += Size;\r
456\r
457 } else {\r
57b4ecb9 458 DEBUG ((DEBUG_ERROR | DEBUG_POOL, "AllocatePool: failed to allocate %ld bytes\n", (UINT64) Size));\r
28a00297 459 }\r
460\r
461 return Buffer;\r
462}\r
022c6d45 463\r
28a00297 464\r
465\r
162ed594 466/**\r
28a00297 467 Frees pool.\r
468\r
022c6d45 469 @param Buffer The allocated pool entry to free\r
925f0d1a 470 @param PoolType Pointer to pool type\r
28a00297 471\r
022c6d45 472 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.\r
162ed594 473 @retval EFI_SUCCESS Pool successfully freed.\r
28a00297 474\r
162ed594 475**/\r
476EFI_STATUS\r
477EFIAPI\r
84edd20b 478CoreInternalFreePool (\r
925f0d1a
SZ
479 IN VOID *Buffer,\r
480 OUT EFI_MEMORY_TYPE *PoolType OPTIONAL\r
162ed594 481 )\r
28a00297 482{\r
483 EFI_STATUS Status;\r
484\r
e94a9ff7 485 if (Buffer == NULL) {\r
28a00297 486 return EFI_INVALID_PARAMETER;\r
487 }\r
488\r
489 CoreAcquireMemoryLock ();\r
925f0d1a 490 Status = CoreFreePoolI (Buffer, PoolType);\r
28a00297 491 CoreReleaseMemoryLock ();\r
492 return Status;\r
493}\r
494\r
84edd20b
SZ
495/**\r
496 Frees pool.\r
497\r
498 @param Buffer The allocated pool entry to free\r
499\r
500 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.\r
501 @retval EFI_SUCCESS Pool successfully freed.\r
502\r
503**/\r
504EFI_STATUS\r
505EFIAPI\r
506CoreFreePool (\r
507 IN VOID *Buffer\r
508 )\r
509{\r
925f0d1a
SZ
510 EFI_STATUS Status;\r
511 EFI_MEMORY_TYPE PoolType;\r
736a692e 512\r
925f0d1a 513 Status = CoreInternalFreePool (Buffer, &PoolType);\r
736a692e 514 if (!EFI_ERROR (Status)) {\r
1d60fe96
SZ
515 CoreUpdateProfile (\r
516 (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),\r
517 MemoryProfileActionFreePool,\r
518 PoolType,\r
519 0,\r
520 Buffer,\r
521 NULL\r
522 );\r
74a88770 523 InstallMemoryAttributesTableOnMemoryAllocation (PoolType);\r
736a692e
HT
524 }\r
525 return Status;\r
526}\r
28a00297 527\r
162ed594 528/**\r
28a00297 529 Internal function to free a pool entry.\r
28a00297 530 Caller must have the memory lock held\r
531\r
022c6d45 532 @param Buffer The allocated pool entry to free\r
925f0d1a 533 @param PoolType Pointer to pool type\r
28a00297 534\r
022c6d45 535 @retval EFI_INVALID_PARAMETER Buffer not valid\r
162ed594 536 @retval EFI_SUCCESS Buffer successfully freed.\r
28a00297 537\r
162ed594 538**/\r
539EFI_STATUS\r
540CoreFreePoolI (\r
925f0d1a
SZ
541 IN VOID *Buffer,\r
542 OUT EFI_MEMORY_TYPE *PoolType OPTIONAL\r
162ed594 543 )\r
28a00297 544{\r
545 POOL *Pool;\r
546 POOL_HEAD *Head;\r
547 POOL_TAIL *Tail;\r
548 POOL_FREE *Free;\r
549 UINTN Index;\r
550 UINTN NoPages;\r
551 UINTN Size;\r
552 CHAR8 *NewPage;\r
162ed594 553 UINTN Offset;\r
28a00297 554 BOOLEAN AllFree;\r
7970100c 555 UINTN Granularity;\r
28a00297 556\r
57b4ecb9 557 ASSERT(Buffer != NULL);\r
28a00297 558 //\r
559 // Get the head & tail of the pool entry\r
560 //\r
561 Head = CR (Buffer, POOL_HEAD, Data, POOL_HEAD_SIGNATURE);\r
57b4ecb9 562 ASSERT(Head != NULL);\r
28a00297 563\r
564 if (Head->Signature != POOL_HEAD_SIGNATURE) {\r
565 return EFI_INVALID_PARAMETER;\r
566 }\r
567\r
568 Tail = HEAD_TO_TAIL (Head);\r
57b4ecb9 569 ASSERT(Tail != NULL);\r
28a00297 570\r
571 //\r
572 // Debug\r
573 //\r
574 ASSERT (Tail->Signature == POOL_TAIL_SIGNATURE);\r
575 ASSERT (Head->Size == Tail->Size);\r
576 ASSERT_LOCKED (&gMemoryLock);\r
577\r
578 if (Tail->Signature != POOL_TAIL_SIGNATURE) {\r
579 return EFI_INVALID_PARAMETER;\r
580 }\r
581\r
582 if (Head->Size != Tail->Size) {\r
583 return EFI_INVALID_PARAMETER;\r
584 }\r
585\r
586 //\r
587 // Determine the pool type and account for it\r
588 //\r
589 Size = Head->Size;\r
590 Pool = LookupPoolHead (Head->Type);\r
591 if (Pool == NULL) {\r
592 return EFI_INVALID_PARAMETER;\r
593 }\r
594 Pool->Used -= Size;\r
57b4ecb9 595 DEBUG ((DEBUG_POOL, "FreePool: %p (len %lx) %,ld\n", Head->Data, (UINT64)(Head->Size - POOL_OVERHEAD), (UINT64) Pool->Used));\r
28a00297 596\r
7970100c
AB
597 if (Head->Type == EfiACPIReclaimMemory ||\r
598 Head->Type == EfiACPIMemoryNVS ||\r
599 Head->Type == EfiRuntimeServicesCode ||\r
600 Head->Type == EfiRuntimeServicesData) {\r
601\r
602 Granularity = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;\r
603 } else {\r
604 Granularity = DEFAULT_PAGE_ALLOCATION;\r
605 }\r
606\r
925f0d1a
SZ
607 if (PoolType != NULL) {\r
608 *PoolType = Head->Type;\r
609 }\r
610\r
28a00297 611 //\r
022c6d45 612 // Determine the pool list\r
28a00297 613 //\r
614 Index = SIZE_TO_LIST(Size);\r
615 DEBUG_CLEAR_MEMORY (Head, Size);\r
616\r
617 //\r
618 // If it's not on the list, it must be pool pages\r
619 //\r
f2c7daf6 620 if (Index >= SIZE_TO_LIST (Granularity)) {\r
28a00297 621\r
622 //\r
623 // Return the memory pages back to free memory\r
624 //\r
7970100c
AB
625 NoPages = EFI_SIZE_TO_PAGES(Size) + EFI_SIZE_TO_PAGES (Granularity) - 1;\r
626 NoPages &= ~(UINTN)(EFI_SIZE_TO_PAGES (Granularity) - 1);\r
28a00297 627 CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS) (UINTN) Head, NoPages);\r
628\r
629 } else {\r
630\r
631 //\r
632 // Put the pool entry onto the free pool list\r
633 //\r
634 Free = (POOL_FREE *) Head;\r
57b4ecb9 635 ASSERT(Free != NULL);\r
28a00297 636 Free->Signature = POOL_FREE_SIGNATURE;\r
637 Free->Index = (UINT32)Index;\r
638 InsertHeadList (&Pool->FreeList[Index], &Free->Link);\r
639\r
640 //\r
022c6d45 641 // See if all the pool entries in the same page as Free are freed pool\r
28a00297 642 // entries\r
643 //\r
7970100c 644 NewPage = (CHAR8 *)((UINTN)Free & ~(Granularity - 1));\r
28a00297 645 Free = (POOL_FREE *) &NewPage[0];\r
e94a9ff7 646 ASSERT(Free != NULL);\r
28a00297 647\r
648 if (Free->Signature == POOL_FREE_SIGNATURE) {\r
649\r
28a00297 650 AllFree = TRUE;\r
162ed594 651 Offset = 0;\r
022c6d45 652\r
7970100c 653 while ((Offset < Granularity) && (AllFree)) {\r
7e8e2205
AB
654 Free = (POOL_FREE *) &NewPage[Offset];\r
655 ASSERT(Free != NULL);\r
656 if (Free->Signature != POOL_FREE_SIGNATURE) {\r
657 AllFree = FALSE;\r
28a00297 658 }\r
7e8e2205 659 Offset += LIST_TO_SIZE(Free->Index);\r
28a00297 660 }\r
661\r
662 if (AllFree) {\r
663\r
664 //\r
022c6d45 665 // All of the pool entries in the same page as Free are free pool\r
28a00297 666 // entries\r
667 // Remove all of these pool entries from the free loop lists.\r
668 //\r
669 Free = (POOL_FREE *) &NewPage[0];\r
57b4ecb9 670 ASSERT(Free != NULL);\r
162ed594 671 Offset = 0;\r
022c6d45 672\r
7970100c 673 while (Offset < Granularity) {\r
7e8e2205
AB
674 Free = (POOL_FREE *) &NewPage[Offset];\r
675 ASSERT(Free != NULL);\r
676 RemoveEntryList (&Free->Link);\r
677 Offset += LIST_TO_SIZE(Free->Index);\r
28a00297 678 }\r
679\r
680 //\r
681 // Free the page\r
682 //\r
7970100c 683 CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS) (UINTN)NewPage, EFI_SIZE_TO_PAGES (Granularity));\r
28a00297 684 }\r
685 }\r
686 }\r
687\r
688 //\r
09159a29 689 // If this is an OS/OEM specific memory type, then check to see if the last\r
28a00297 690 // portion of that memory type has been freed. If it has, then free the\r
691 // list entry for that memory type\r
692 //\r
09159a29 693 if (((UINT32) Pool->MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) && Pool->Used == 0) {\r
28a00297 694 RemoveEntryList (&Pool->Link);\r
925f0d1a 695 CoreFreePoolI (Pool, NULL);\r
28a00297 696 }\r
697\r
698 return EFI_SUCCESS;\r
699}\r
84edd20b 700\r