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