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