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