]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Core/Dxe/Mem/Pool.c
MdeModulePkg: define PCD for DXE memory protection policy
[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 return Buffer;\r
314}\r
315\r
316/**\r
317 Internal function to allocate pool of a particular type.\r
318 Caller must have the memory lock held\r
319\r
320 @param PoolType Type of pool to allocate\r
321 @param Size The amount of pool to allocate\r
322\r
323 @return The allocate pool, or NULL\r
324\r
325**/\r
326VOID *\r
327CoreAllocatePoolI (\r
328 IN EFI_MEMORY_TYPE PoolType,\r
329 IN UINTN Size\r
330 )\r
331{\r
332 POOL *Pool;\r
333 POOL_FREE *Free;\r
334 POOL_HEAD *Head;\r
335 POOL_TAIL *Tail;\r
336 CHAR8 *NewPage;\r
337 VOID *Buffer;\r
338 UINTN Index;\r
339 UINTN FSize;\r
340 UINTN Offset, MaxOffset;\r
341 UINTN NoPages;\r
342 UINTN Granularity;\r
343\r
344 ASSERT_LOCKED (&mPoolMemoryLock);\r
345\r
346 if (PoolType == EfiACPIReclaimMemory ||\r
347 PoolType == EfiACPIMemoryNVS ||\r
348 PoolType == EfiRuntimeServicesCode ||\r
349 PoolType == EfiRuntimeServicesData) {\r
350\r
351 Granularity = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;\r
352 } else {\r
353 Granularity = DEFAULT_PAGE_ALLOCATION;\r
354 }\r
355\r
356 //\r
357 // Adjust the size by the pool header & tail overhead\r
358 //\r
359\r
360 //\r
361 // Adjusting the Size to be of proper alignment so that\r
362 // we don't get an unaligned access fault later when\r
363 // pool_Tail is being initialized\r
364 //\r
365 Size = ALIGN_VARIABLE (Size);\r
366\r
367 Size += POOL_OVERHEAD;\r
368 Index = SIZE_TO_LIST(Size);\r
369 Pool = LookupPoolHead (PoolType);\r
370 if (Pool== NULL) {\r
371 return NULL;\r
372 }\r
373 Head = NULL;\r
374\r
375 //\r
376 // If allocation is over max size, just allocate pages for the request\r
377 // (slow)\r
378 //\r
379 if (Index >= SIZE_TO_LIST (Granularity)) {\r
380 NoPages = EFI_SIZE_TO_PAGES(Size) + EFI_SIZE_TO_PAGES (Granularity) - 1;\r
381 NoPages &= ~(UINTN)(EFI_SIZE_TO_PAGES (Granularity) - 1);\r
382 Head = CoreAllocatePoolPagesI (PoolType, NoPages, Granularity);\r
383 goto Done;\r
384 }\r
385\r
386 //\r
387 // If there's no free pool in the proper list size, go get some more pages\r
388 //\r
389 if (IsListEmpty (&Pool->FreeList[Index])) {\r
390\r
391 Offset = LIST_TO_SIZE (Index);\r
392 MaxOffset = Granularity;\r
393\r
394 //\r
395 // Check the bins holding larger blocks, and carve one up if needed\r
396 //\r
397 while (++Index < SIZE_TO_LIST (Granularity)) {\r
398 if (!IsListEmpty (&Pool->FreeList[Index])) {\r
399 Free = CR (Pool->FreeList[Index].ForwardLink, POOL_FREE, Link, POOL_FREE_SIGNATURE);\r
400 RemoveEntryList (&Free->Link);\r
401 NewPage = (VOID *) Free;\r
402 MaxOffset = LIST_TO_SIZE (Index);\r
403 goto Carve;\r
404 }\r
405 }\r
406\r
407 //\r
408 // Get another page\r
409 //\r
410 NewPage = CoreAllocatePoolPagesI (PoolType, EFI_SIZE_TO_PAGES (Granularity), Granularity);\r
411 if (NewPage == NULL) {\r
412 goto Done;\r
413 }\r
414\r
415 //\r
416 // Serve the allocation request from the head of the allocated block\r
417 //\r
418Carve:\r
419 Head = (POOL_HEAD *) NewPage;\r
420\r
421 //\r
422 // Carve up remaining space into free pool blocks\r
423 //\r
424 Index--;\r
425 while (Offset < MaxOffset) {\r
426 ASSERT (Index < MAX_POOL_LIST);\r
427 FSize = LIST_TO_SIZE(Index);\r
428\r
429 while (Offset + FSize <= MaxOffset) {\r
430 Free = (POOL_FREE *) &NewPage[Offset];\r
431 Free->Signature = POOL_FREE_SIGNATURE;\r
432 Free->Index = (UINT32)Index;\r
433 InsertHeadList (&Pool->FreeList[Index], &Free->Link);\r
434 Offset += FSize;\r
435 }\r
436 Index -= 1;\r
437 }\r
438\r
439 ASSERT (Offset == MaxOffset);\r
440 goto Done;\r
441 }\r
442\r
443 //\r
444 // Remove entry from free pool list\r
445 //\r
446 Free = CR (Pool->FreeList[Index].ForwardLink, POOL_FREE, Link, POOL_FREE_SIGNATURE);\r
447 RemoveEntryList (&Free->Link);\r
448\r
449 Head = (POOL_HEAD *) Free;\r
450\r
451Done:\r
452 Buffer = NULL;\r
453\r
454 if (Head != NULL) {\r
455\r
456 //\r
457 // If we have a pool buffer, fill in the header & tail info\r
458 //\r
459 Head->Signature = POOL_HEAD_SIGNATURE;\r
460 Head->Size = Size;\r
461 Head->Type = (EFI_MEMORY_TYPE) PoolType;\r
462 Tail = HEAD_TO_TAIL (Head);\r
463 Tail->Signature = POOL_TAIL_SIGNATURE;\r
464 Tail->Size = Size;\r
465 Buffer = Head->Data;\r
466 DEBUG_CLEAR_MEMORY (Buffer, Size - POOL_OVERHEAD);\r
467\r
468 DEBUG ((\r
469 DEBUG_POOL,\r
470 "AllocatePoolI: Type %x, Addr %p (len %lx) %,ld\n", PoolType,\r
471 Buffer,\r
472 (UINT64)(Size - POOL_OVERHEAD),\r
473 (UINT64) Pool->Used\r
474 ));\r
475\r
476 //\r
477 // Account the allocation\r
478 //\r
479 Pool->Used += Size;\r
480\r
481 } else {\r
482 DEBUG ((DEBUG_ERROR | DEBUG_POOL, "AllocatePool: failed to allocate %ld bytes\n", (UINT64) Size));\r
483 }\r
484\r
485 return Buffer;\r
486}\r
487\r
488\r
489\r
490/**\r
491 Frees pool.\r
492\r
493 @param Buffer The allocated pool entry to free\r
494 @param PoolType Pointer to pool type\r
495\r
496 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.\r
497 @retval EFI_SUCCESS Pool successfully freed.\r
498\r
499**/\r
500EFI_STATUS\r
501EFIAPI\r
502CoreInternalFreePool (\r
503 IN VOID *Buffer,\r
504 OUT EFI_MEMORY_TYPE *PoolType OPTIONAL\r
505 )\r
506{\r
507 EFI_STATUS Status;\r
508\r
509 if (Buffer == NULL) {\r
510 return EFI_INVALID_PARAMETER;\r
511 }\r
512\r
513 CoreAcquireLock (&mPoolMemoryLock);\r
514 Status = CoreFreePoolI (Buffer, PoolType);\r
515 CoreReleaseLock (&mPoolMemoryLock);\r
516 return Status;\r
517}\r
518\r
519/**\r
520 Frees pool.\r
521\r
522 @param Buffer The allocated pool entry to free\r
523\r
524 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.\r
525 @retval EFI_SUCCESS Pool successfully freed.\r
526\r
527**/\r
528EFI_STATUS\r
529EFIAPI\r
530CoreFreePool (\r
531 IN VOID *Buffer\r
532 )\r
533{\r
534 EFI_STATUS Status;\r
535 EFI_MEMORY_TYPE PoolType;\r
536\r
537 Status = CoreInternalFreePool (Buffer, &PoolType);\r
538 if (!EFI_ERROR (Status)) {\r
539 CoreUpdateProfile (\r
540 (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),\r
541 MemoryProfileActionFreePool,\r
542 PoolType,\r
543 0,\r
544 Buffer,\r
545 NULL\r
546 );\r
547 InstallMemoryAttributesTableOnMemoryAllocation (PoolType);\r
548 }\r
549 return Status;\r
550}\r
551\r
552STATIC\r
553VOID\r
554CoreFreePoolPagesI (\r
555 IN EFI_MEMORY_TYPE PoolType,\r
556 IN EFI_PHYSICAL_ADDRESS Memory,\r
557 IN UINTN NoPages\r
558 )\r
559{\r
560 CoreAcquireMemoryLock ();\r
561 CoreFreePoolPages (Memory, NoPages);\r
562 CoreReleaseMemoryLock ();\r
563}\r
564\r
565/**\r
566 Internal function to free a pool entry.\r
567 Caller must have the memory lock held\r
568\r
569 @param Buffer The allocated pool entry to free\r
570 @param PoolType Pointer to pool type\r
571\r
572 @retval EFI_INVALID_PARAMETER Buffer not valid\r
573 @retval EFI_SUCCESS Buffer successfully freed.\r
574\r
575**/\r
576EFI_STATUS\r
577CoreFreePoolI (\r
578 IN VOID *Buffer,\r
579 OUT EFI_MEMORY_TYPE *PoolType OPTIONAL\r
580 )\r
581{\r
582 POOL *Pool;\r
583 POOL_HEAD *Head;\r
584 POOL_TAIL *Tail;\r
585 POOL_FREE *Free;\r
586 UINTN Index;\r
587 UINTN NoPages;\r
588 UINTN Size;\r
589 CHAR8 *NewPage;\r
590 UINTN Offset;\r
591 BOOLEAN AllFree;\r
592 UINTN Granularity;\r
593\r
594 ASSERT(Buffer != NULL);\r
595 //\r
596 // Get the head & tail of the pool entry\r
597 //\r
598 Head = CR (Buffer, POOL_HEAD, Data, POOL_HEAD_SIGNATURE);\r
599 ASSERT(Head != NULL);\r
600\r
601 if (Head->Signature != POOL_HEAD_SIGNATURE) {\r
602 return EFI_INVALID_PARAMETER;\r
603 }\r
604\r
605 Tail = HEAD_TO_TAIL (Head);\r
606 ASSERT(Tail != NULL);\r
607\r
608 //\r
609 // Debug\r
610 //\r
611 ASSERT (Tail->Signature == POOL_TAIL_SIGNATURE);\r
612 ASSERT (Head->Size == Tail->Size);\r
613 ASSERT_LOCKED (&mPoolMemoryLock);\r
614\r
615 if (Tail->Signature != POOL_TAIL_SIGNATURE) {\r
616 return EFI_INVALID_PARAMETER;\r
617 }\r
618\r
619 if (Head->Size != Tail->Size) {\r
620 return EFI_INVALID_PARAMETER;\r
621 }\r
622\r
623 //\r
624 // Determine the pool type and account for it\r
625 //\r
626 Size = Head->Size;\r
627 Pool = LookupPoolHead (Head->Type);\r
628 if (Pool == NULL) {\r
629 return EFI_INVALID_PARAMETER;\r
630 }\r
631 Pool->Used -= Size;\r
632 DEBUG ((DEBUG_POOL, "FreePool: %p (len %lx) %,ld\n", Head->Data, (UINT64)(Head->Size - POOL_OVERHEAD), (UINT64) Pool->Used));\r
633\r
634 if (Head->Type == EfiACPIReclaimMemory ||\r
635 Head->Type == EfiACPIMemoryNVS ||\r
636 Head->Type == EfiRuntimeServicesCode ||\r
637 Head->Type == EfiRuntimeServicesData) {\r
638\r
639 Granularity = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;\r
640 } else {\r
641 Granularity = DEFAULT_PAGE_ALLOCATION;\r
642 }\r
643\r
644 if (PoolType != NULL) {\r
645 *PoolType = Head->Type;\r
646 }\r
647\r
648 //\r
649 // Determine the pool list\r
650 //\r
651 Index = SIZE_TO_LIST(Size);\r
652 DEBUG_CLEAR_MEMORY (Head, Size);\r
653\r
654 //\r
655 // If it's not on the list, it must be pool pages\r
656 //\r
657 if (Index >= SIZE_TO_LIST (Granularity)) {\r
658\r
659 //\r
660 // Return the memory pages back to free memory\r
661 //\r
662 NoPages = EFI_SIZE_TO_PAGES(Size) + EFI_SIZE_TO_PAGES (Granularity) - 1;\r
663 NoPages &= ~(UINTN)(EFI_SIZE_TO_PAGES (Granularity) - 1);\r
664 CoreFreePoolPagesI (Pool->MemoryType, (EFI_PHYSICAL_ADDRESS) (UINTN) Head, NoPages);\r
665\r
666 } else {\r
667\r
668 //\r
669 // Put the pool entry onto the free pool list\r
670 //\r
671 Free = (POOL_FREE *) Head;\r
672 ASSERT(Free != NULL);\r
673 Free->Signature = POOL_FREE_SIGNATURE;\r
674 Free->Index = (UINT32)Index;\r
675 InsertHeadList (&Pool->FreeList[Index], &Free->Link);\r
676\r
677 //\r
678 // See if all the pool entries in the same page as Free are freed pool\r
679 // entries\r
680 //\r
681 NewPage = (CHAR8 *)((UINTN)Free & ~(Granularity - 1));\r
682 Free = (POOL_FREE *) &NewPage[0];\r
683 ASSERT(Free != NULL);\r
684\r
685 if (Free->Signature == POOL_FREE_SIGNATURE) {\r
686\r
687 AllFree = TRUE;\r
688 Offset = 0;\r
689\r
690 while ((Offset < Granularity) && (AllFree)) {\r
691 Free = (POOL_FREE *) &NewPage[Offset];\r
692 ASSERT(Free != NULL);\r
693 if (Free->Signature != POOL_FREE_SIGNATURE) {\r
694 AllFree = FALSE;\r
695 }\r
696 Offset += LIST_TO_SIZE(Free->Index);\r
697 }\r
698\r
699 if (AllFree) {\r
700\r
701 //\r
702 // All of the pool entries in the same page as Free are free pool\r
703 // entries\r
704 // Remove all of these pool entries from the free loop lists.\r
705 //\r
706 Free = (POOL_FREE *) &NewPage[0];\r
707 ASSERT(Free != NULL);\r
708 Offset = 0;\r
709\r
710 while (Offset < Granularity) {\r
711 Free = (POOL_FREE *) &NewPage[Offset];\r
712 ASSERT(Free != NULL);\r
713 RemoveEntryList (&Free->Link);\r
714 Offset += LIST_TO_SIZE(Free->Index);\r
715 }\r
716\r
717 //\r
718 // Free the page\r
719 //\r
720 CoreFreePoolPagesI (Pool->MemoryType, (EFI_PHYSICAL_ADDRESS) (UINTN)NewPage,\r
721 EFI_SIZE_TO_PAGES (Granularity));\r
722 }\r
723 }\r
724 }\r
725\r
726 //\r
727 // If this is an OS/OEM specific memory type, then check to see if the last\r
728 // portion of that memory type has been freed. If it has, then free the\r
729 // list entry for that memory type\r
730 //\r
731 if (((UINT32) Pool->MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) && Pool->Used == 0) {\r
732 RemoveEntryList (&Pool->Link);\r
733 CoreFreePoolI (Pool, NULL);\r
734 }\r
735\r
736 return EFI_SUCCESS;\r
737}\r
738\r