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