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