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