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