]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/Dxe/Mem/Pool.c
MdePkg: Add UEFI2.5 and PI1.4 PersistentMemory definition
[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
6e1e5405 4Copyright (c) 2006 - 2014, 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
55 64, 128, 192, 320, 512, 832, 1344, 2176, 3520, 5696, 9216, 14912, 24128\r
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
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 //\r
68db1228 160 if ((INT32)MemoryType < 0) {\r
28a00297 161\r
e94a9ff7 162 for (Link = mPoolHeadList.ForwardLink; Link != &mPoolHeadList; Link = Link->ForwardLink) {\r
28a00297 163 Pool = CR(Link, POOL, Link, POOL_SIGNATURE);\r
164 if (Pool->MemoryType == MemoryType) {\r
165 return Pool;\r
166 }\r
167 }\r
168\r
169 Pool = CoreAllocatePoolI (EfiBootServicesData, sizeof (POOL));\r
170 if (Pool == NULL) {\r
171 return NULL;\r
172 }\r
173\r
174 Pool->Signature = POOL_SIGNATURE;\r
175 Pool->Used = 0;\r
176 Pool->MemoryType = MemoryType;\r
177 for (Index=0; Index < MAX_POOL_LIST; Index++) {\r
178 InitializeListHead (&Pool->FreeList[Index]);\r
179 }\r
180\r
e94a9ff7 181 InsertHeadList (&mPoolHeadList, &Pool->Link);\r
28a00297 182\r
183 return Pool;\r
184 }\r
185\r
186 return NULL;\r
187}\r
188\r
022c6d45 189\r
28a00297 190\r
162ed594 191/**\r
192 Allocate pool of a particular type.\r
193\r
022c6d45 194 @param PoolType Type of pool to allocate\r
195 @param Size The amount of pool to allocate\r
196 @param Buffer The address to return a pointer to the allocated\r
197 pool\r
162ed594 198\r
3e058701 199 @retval EFI_INVALID_PARAMETER PoolType not valid or Buffer is NULL. \r
022c6d45 200 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.\r
162ed594 201 @retval EFI_SUCCESS Pool successfully allocated.\r
202\r
203**/\r
28a00297 204EFI_STATUS\r
205EFIAPI\r
84edd20b 206CoreInternalAllocatePool (\r
28a00297 207 IN EFI_MEMORY_TYPE PoolType,\r
208 IN UINTN Size,\r
209 OUT VOID **Buffer\r
210 )\r
28a00297 211{\r
212 EFI_STATUS Status;\r
213\r
214 //\r
215 // If it's not a valid type, fail it\r
216 //\r
217 if ((PoolType >= EfiMaxMemoryType && PoolType <= 0x7fffffff) ||\r
218 PoolType == EfiConventionalMemory) {\r
219 return EFI_INVALID_PARAMETER;\r
220 }\r
022c6d45 221\r
3e058701
ED
222 if (Buffer == NULL) {\r
223 return EFI_INVALID_PARAMETER;\r
224 }\r
225\r
28a00297 226 *Buffer = NULL;\r
022c6d45 227\r
28a00297 228 //\r
229 // If size is too large, fail it\r
230 // Base on the EFI spec, return status of EFI_OUT_OF_RESOURCES\r
231 //\r
232 if (Size > MAX_POOL_SIZE) {\r
233 return EFI_OUT_OF_RESOURCES;\r
234 }\r
235\r
236 //\r
237 // Acquire the memory lock and make the allocation\r
238 //\r
239 Status = CoreAcquireLockOrFail (&gMemoryLock);\r
240 if (EFI_ERROR (Status)) {\r
241 return EFI_OUT_OF_RESOURCES;\r
242 }\r
243\r
244 *Buffer = CoreAllocatePoolI (PoolType, Size);\r
245 CoreReleaseMemoryLock ();\r
246 return (*Buffer != NULL) ? EFI_SUCCESS : EFI_OUT_OF_RESOURCES;\r
247}\r
248\r
84edd20b
SZ
249/**\r
250 Allocate pool of a particular type.\r
251\r
252 @param PoolType Type of pool to allocate\r
253 @param Size The amount of pool to allocate\r
254 @param Buffer The address to return a pointer to the allocated\r
255 pool\r
256\r
257 @retval EFI_INVALID_PARAMETER PoolType not valid or Buffer is NULL. \r
258 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.\r
259 @retval EFI_SUCCESS Pool successfully allocated.\r
260\r
261**/\r
262EFI_STATUS\r
263EFIAPI\r
264CoreAllocatePool (\r
265 IN EFI_MEMORY_TYPE PoolType,\r
266 IN UINTN Size,\r
267 OUT VOID **Buffer\r
268 )\r
269{\r
270 EFI_STATUS Status;\r
28a00297 271\r
84edd20b
SZ
272 Status = CoreInternalAllocatePool (PoolType, Size, Buffer);\r
273 if (!EFI_ERROR (Status)) {\r
274 CoreUpdateProfile ((EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0), MemoryProfileActionAllocatePool, PoolType, Size, *Buffer);\r
275 }\r
276 return Status;\r
277}\r
28a00297 278\r
162ed594 279/**\r
28a00297 280 Internal function to allocate pool of a particular type.\r
28a00297 281 Caller must have the memory lock held\r
282\r
022c6d45 283 @param PoolType Type of pool to allocate\r
284 @param Size The amount of pool to allocate\r
28a00297 285\r
162ed594 286 @return The allocate pool, or NULL\r
28a00297 287\r
162ed594 288**/\r
289VOID *\r
290CoreAllocatePoolI (\r
291 IN EFI_MEMORY_TYPE PoolType,\r
292 IN UINTN Size\r
293 )\r
28a00297 294{\r
295 POOL *Pool;\r
296 POOL_FREE *Free;\r
297 POOL_HEAD *Head;\r
298 POOL_TAIL *Tail;\r
299 CHAR8 *NewPage;\r
300 VOID *Buffer;\r
301 UINTN Index;\r
302 UINTN FSize;\r
6860b92c 303 UINTN Offset, MaxOffset;\r
28a00297 304 UINTN NoPages;\r
7970100c 305 UINTN Granularity;\r
28a00297 306\r
307 ASSERT_LOCKED (&gMemoryLock);\r
308\r
7970100c
AB
309 if (PoolType == EfiACPIReclaimMemory ||\r
310 PoolType == EfiACPIMemoryNVS ||\r
311 PoolType == EfiRuntimeServicesCode ||\r
312 PoolType == EfiRuntimeServicesData) {\r
313\r
314 Granularity = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;\r
315 } else {\r
316 Granularity = DEFAULT_PAGE_ALLOCATION;\r
317 }\r
318\r
28a00297 319 //\r
320 // Adjust the size by the pool header & tail overhead\r
321 //\r
022c6d45 322\r
28a00297 323 //\r
324 // Adjusting the Size to be of proper alignment so that\r
325 // we don't get an unaligned access fault later when\r
326 // pool_Tail is being initialized\r
327 //\r
f0d5cbb6 328 Size = ALIGN_VARIABLE (Size);\r
28a00297 329\r
330 Size += POOL_OVERHEAD;\r
331 Index = SIZE_TO_LIST(Size);\r
332 Pool = LookupPoolHead (PoolType);\r
333 if (Pool== NULL) {\r
334 return NULL;\r
335 }\r
336 Head = NULL;\r
337\r
338 //\r
339 // If allocation is over max size, just allocate pages for the request\r
340 // (slow)\r
341 //\r
f2c7daf6 342 if (Index >= SIZE_TO_LIST (Granularity)) {\r
7970100c
AB
343 NoPages = EFI_SIZE_TO_PAGES(Size) + EFI_SIZE_TO_PAGES (Granularity) - 1;\r
344 NoPages &= ~(UINTN)(EFI_SIZE_TO_PAGES (Granularity) - 1);\r
345 Head = CoreAllocatePoolPages (PoolType, NoPages, Granularity);\r
28a00297 346 goto Done;\r
347 }\r
348\r
349 //\r
350 // If there's no free pool in the proper list size, go get some more pages\r
351 //\r
352 if (IsListEmpty (&Pool->FreeList[Index])) {\r
353\r
6860b92c
AB
354 Offset = LIST_TO_SIZE (Index);\r
355 MaxOffset = Granularity;\r
356\r
357 //\r
358 // Check the bins holding larger blocks, and carve one up if needed\r
359 //\r
360 while (++Index < SIZE_TO_LIST (Granularity)) {\r
361 if (!IsListEmpty (&Pool->FreeList[Index])) {\r
362 Free = CR (Pool->FreeList[Index].ForwardLink, POOL_FREE, Link, POOL_FREE_SIGNATURE);\r
363 RemoveEntryList (&Free->Link);\r
364 NewPage = (VOID *) Free;\r
365 MaxOffset = LIST_TO_SIZE (Index);\r
366 goto Carve;\r
367 }\r
368 }\r
369\r
28a00297 370 //\r
371 // Get another page\r
372 //\r
7970100c 373 NewPage = CoreAllocatePoolPages(PoolType, EFI_SIZE_TO_PAGES (Granularity), Granularity);\r
28a00297 374 if (NewPage == NULL) {\r
375 goto Done;\r
376 }\r
377\r
378 //\r
f8aabf6e 379 // Serve the allocation request from the head of the allocated block\r
28a00297 380 //\r
6860b92c 381Carve:\r
f8aabf6e 382 Head = (POOL_HEAD *) NewPage;\r
f8aabf6e
AB
383\r
384 //\r
385 // Carve up remaining space into free pool blocks\r
386 //\r
6860b92c
AB
387 Index--;\r
388 while (Offset < MaxOffset) {\r
28a00297 389 ASSERT (Index < MAX_POOL_LIST);\r
390 FSize = LIST_TO_SIZE(Index);\r
391\r
6860b92c 392 while (Offset + FSize <= MaxOffset) {\r
022c6d45 393 Free = (POOL_FREE *) &NewPage[Offset];\r
28a00297 394 Free->Signature = POOL_FREE_SIGNATURE;\r
395 Free->Index = (UINT32)Index;\r
396 InsertHeadList (&Pool->FreeList[Index], &Free->Link);\r
162ed594 397 Offset += FSize;\r
28a00297 398 }\r
28a00297 399 Index -= 1;\r
400 }\r
401\r
6860b92c 402 ASSERT (Offset == MaxOffset);\r
f8aabf6e 403 goto Done;\r
28a00297 404 }\r
405\r
406 //\r
407 // Remove entry from free pool list\r
408 //\r
409 Free = CR (Pool->FreeList[Index].ForwardLink, POOL_FREE, Link, POOL_FREE_SIGNATURE);\r
410 RemoveEntryList (&Free->Link);\r
411\r
412 Head = (POOL_HEAD *) Free;\r
413\r
414Done:\r
415 Buffer = NULL;\r
416\r
417 if (Head != NULL) {\r
022c6d45 418\r
28a00297 419 //\r
420 // If we have a pool buffer, fill in the header & tail info\r
421 //\r
422 Head->Signature = POOL_HEAD_SIGNATURE;\r
bb683bf4 423 Head->Size = Size;\r
28a00297 424 Head->Type = (EFI_MEMORY_TYPE) PoolType;\r
425 Tail = HEAD_TO_TAIL (Head);\r
426 Tail->Signature = POOL_TAIL_SIGNATURE;\r
bb683bf4 427 Tail->Size = Size;\r
28a00297 428 Buffer = Head->Data;\r
429 DEBUG_CLEAR_MEMORY (Buffer, Size - POOL_OVERHEAD);\r
430\r
e94a9ff7 431 DEBUG ((\r
432 DEBUG_POOL,\r
57b4ecb9 433 "AllocatePoolI: Type %x, Addr %p (len %lx) %,ld\n", PoolType,\r
022c6d45 434 Buffer,\r
57b4ecb9 435 (UINT64)(Size - POOL_OVERHEAD),\r
436 (UINT64) Pool->Used\r
e94a9ff7 437 ));\r
28a00297 438\r
439 //\r
440 // Account the allocation\r
441 //\r
442 Pool->Used += Size;\r
443\r
444 } else {\r
57b4ecb9 445 DEBUG ((DEBUG_ERROR | DEBUG_POOL, "AllocatePool: failed to allocate %ld bytes\n", (UINT64) Size));\r
28a00297 446 }\r
447\r
448 return Buffer;\r
449}\r
022c6d45 450\r
28a00297 451\r
452\r
162ed594 453/**\r
28a00297 454 Frees pool.\r
455\r
022c6d45 456 @param Buffer The allocated pool entry to free\r
28a00297 457\r
022c6d45 458 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.\r
162ed594 459 @retval EFI_SUCCESS Pool successfully freed.\r
28a00297 460\r
162ed594 461**/\r
462EFI_STATUS\r
463EFIAPI\r
84edd20b 464CoreInternalFreePool (\r
162ed594 465 IN VOID *Buffer\r
466 )\r
28a00297 467{\r
468 EFI_STATUS Status;\r
469\r
e94a9ff7 470 if (Buffer == NULL) {\r
28a00297 471 return EFI_INVALID_PARAMETER;\r
472 }\r
473\r
474 CoreAcquireMemoryLock ();\r
475 Status = CoreFreePoolI (Buffer);\r
476 CoreReleaseMemoryLock ();\r
477 return Status;\r
478}\r
479\r
84edd20b
SZ
480/**\r
481 Frees pool.\r
482\r
483 @param Buffer The allocated pool entry to free\r
484\r
485 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.\r
486 @retval EFI_SUCCESS Pool successfully freed.\r
487\r
488**/\r
489EFI_STATUS\r
490EFIAPI\r
491CoreFreePool (\r
492 IN VOID *Buffer\r
493 )\r
494{\r
495 EFI_STATUS Status;\r
736a692e
HT
496\r
497 Status = CoreInternalFreePool (Buffer);\r
498 if (!EFI_ERROR (Status)) {\r
499 CoreUpdateProfile ((EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0), MemoryProfileActionFreePool, (EFI_MEMORY_TYPE) 0, 0, Buffer);\r
500 }\r
501 return Status;\r
502}\r
28a00297 503\r
162ed594 504/**\r
28a00297 505 Internal function to free a pool entry.\r
28a00297 506 Caller must have the memory lock held\r
507\r
022c6d45 508 @param Buffer The allocated pool entry to free\r
28a00297 509\r
022c6d45 510 @retval EFI_INVALID_PARAMETER Buffer not valid\r
162ed594 511 @retval EFI_SUCCESS Buffer successfully freed.\r
28a00297 512\r
162ed594 513**/\r
514EFI_STATUS\r
515CoreFreePoolI (\r
516 IN VOID *Buffer\r
517 )\r
28a00297 518{\r
519 POOL *Pool;\r
520 POOL_HEAD *Head;\r
521 POOL_TAIL *Tail;\r
522 POOL_FREE *Free;\r
523 UINTN Index;\r
524 UINTN NoPages;\r
525 UINTN Size;\r
526 CHAR8 *NewPage;\r
162ed594 527 UINTN Offset;\r
28a00297 528 BOOLEAN AllFree;\r
7970100c 529 UINTN Granularity;\r
28a00297 530\r
57b4ecb9 531 ASSERT(Buffer != NULL);\r
28a00297 532 //\r
533 // Get the head & tail of the pool entry\r
534 //\r
535 Head = CR (Buffer, POOL_HEAD, Data, POOL_HEAD_SIGNATURE);\r
57b4ecb9 536 ASSERT(Head != NULL);\r
28a00297 537\r
538 if (Head->Signature != POOL_HEAD_SIGNATURE) {\r
539 return EFI_INVALID_PARAMETER;\r
540 }\r
541\r
542 Tail = HEAD_TO_TAIL (Head);\r
57b4ecb9 543 ASSERT(Tail != NULL);\r
28a00297 544\r
545 //\r
546 // Debug\r
547 //\r
548 ASSERT (Tail->Signature == POOL_TAIL_SIGNATURE);\r
549 ASSERT (Head->Size == Tail->Size);\r
550 ASSERT_LOCKED (&gMemoryLock);\r
551\r
552 if (Tail->Signature != POOL_TAIL_SIGNATURE) {\r
553 return EFI_INVALID_PARAMETER;\r
554 }\r
555\r
556 if (Head->Size != Tail->Size) {\r
557 return EFI_INVALID_PARAMETER;\r
558 }\r
559\r
560 //\r
561 // Determine the pool type and account for it\r
562 //\r
563 Size = Head->Size;\r
564 Pool = LookupPoolHead (Head->Type);\r
565 if (Pool == NULL) {\r
566 return EFI_INVALID_PARAMETER;\r
567 }\r
568 Pool->Used -= Size;\r
57b4ecb9 569 DEBUG ((DEBUG_POOL, "FreePool: %p (len %lx) %,ld\n", Head->Data, (UINT64)(Head->Size - POOL_OVERHEAD), (UINT64) Pool->Used));\r
28a00297 570\r
7970100c
AB
571 if (Head->Type == EfiACPIReclaimMemory ||\r
572 Head->Type == EfiACPIMemoryNVS ||\r
573 Head->Type == EfiRuntimeServicesCode ||\r
574 Head->Type == EfiRuntimeServicesData) {\r
575\r
576 Granularity = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;\r
577 } else {\r
578 Granularity = DEFAULT_PAGE_ALLOCATION;\r
579 }\r
580\r
28a00297 581 //\r
022c6d45 582 // Determine the pool list\r
28a00297 583 //\r
584 Index = SIZE_TO_LIST(Size);\r
585 DEBUG_CLEAR_MEMORY (Head, Size);\r
586\r
587 //\r
588 // If it's not on the list, it must be pool pages\r
589 //\r
f2c7daf6 590 if (Index >= SIZE_TO_LIST (Granularity)) {\r
28a00297 591\r
592 //\r
593 // Return the memory pages back to free memory\r
594 //\r
7970100c
AB
595 NoPages = EFI_SIZE_TO_PAGES(Size) + EFI_SIZE_TO_PAGES (Granularity) - 1;\r
596 NoPages &= ~(UINTN)(EFI_SIZE_TO_PAGES (Granularity) - 1);\r
28a00297 597 CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS) (UINTN) Head, NoPages);\r
598\r
599 } else {\r
600\r
601 //\r
602 // Put the pool entry onto the free pool list\r
603 //\r
604 Free = (POOL_FREE *) Head;\r
57b4ecb9 605 ASSERT(Free != NULL);\r
28a00297 606 Free->Signature = POOL_FREE_SIGNATURE;\r
607 Free->Index = (UINT32)Index;\r
608 InsertHeadList (&Pool->FreeList[Index], &Free->Link);\r
609\r
610 //\r
022c6d45 611 // See if all the pool entries in the same page as Free are freed pool\r
28a00297 612 // entries\r
613 //\r
7970100c 614 NewPage = (CHAR8 *)((UINTN)Free & ~(Granularity - 1));\r
28a00297 615 Free = (POOL_FREE *) &NewPage[0];\r
e94a9ff7 616 ASSERT(Free != NULL);\r
28a00297 617\r
618 if (Free->Signature == POOL_FREE_SIGNATURE) {\r
619\r
28a00297 620 AllFree = TRUE;\r
162ed594 621 Offset = 0;\r
022c6d45 622\r
7970100c 623 while ((Offset < Granularity) && (AllFree)) {\r
7e8e2205
AB
624 Free = (POOL_FREE *) &NewPage[Offset];\r
625 ASSERT(Free != NULL);\r
626 if (Free->Signature != POOL_FREE_SIGNATURE) {\r
627 AllFree = FALSE;\r
28a00297 628 }\r
7e8e2205 629 Offset += LIST_TO_SIZE(Free->Index);\r
28a00297 630 }\r
631\r
632 if (AllFree) {\r
633\r
634 //\r
022c6d45 635 // All of the pool entries in the same page as Free are free pool\r
28a00297 636 // entries\r
637 // Remove all of these pool entries from the free loop lists.\r
638 //\r
639 Free = (POOL_FREE *) &NewPage[0];\r
57b4ecb9 640 ASSERT(Free != NULL);\r
162ed594 641 Offset = 0;\r
022c6d45 642\r
7970100c 643 while (Offset < Granularity) {\r
7e8e2205
AB
644 Free = (POOL_FREE *) &NewPage[Offset];\r
645 ASSERT(Free != NULL);\r
646 RemoveEntryList (&Free->Link);\r
647 Offset += LIST_TO_SIZE(Free->Index);\r
28a00297 648 }\r
649\r
650 //\r
651 // Free the page\r
652 //\r
7970100c 653 CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS) (UINTN)NewPage, EFI_SIZE_TO_PAGES (Granularity));\r
28a00297 654 }\r
655 }\r
656 }\r
657\r
658 //\r
022c6d45 659 // If this is an OS specific memory type, then check to see if the last\r
28a00297 660 // portion of that memory type has been freed. If it has, then free the\r
661 // list entry for that memory type\r
662 //\r
3d78c020 663 if ((INT32)Pool->MemoryType < 0 && Pool->Used == 0) {\r
28a00297 664 RemoveEntryList (&Pool->Link);\r
665 CoreFreePoolI (Pool);\r
666 }\r
667\r
668 return EFI_SUCCESS;\r
669}\r
84edd20b 670\r