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