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