]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Core/Dxe/Mem/Pool.c
MdeModulePkg/Core: allow HeapGuard even before CpuArchProtocol installed
[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 //\r
646 // It's safe to unset Guard page inside memory lock because there should\r
647 // be no memory allocation occurred in updating memory page attribute at\r
648 // this point. And unsetting Guard page before free will prevent Guard\r
649 // page just freed back to pool from being allocated right away before\r
650 // marking it usable (from non-present to present).\r
651 //\r
652 UnsetGuardForMemory (MemoryGuarded, NoPagesGuarded);\r
653 if (NoPages > 0) {\r
654 CoreFreePoolPagesI (PoolType, Memory, NoPages);\r
655 }\r
656}\r
657\r
658/**\r
659 Internal function to free a pool entry.\r
660 Caller must have the memory lock held\r
661\r
662 @param Buffer The allocated pool entry to free\r
663 @param PoolType Pointer to pool type\r
664\r
665 @retval EFI_INVALID_PARAMETER Buffer not valid\r
666 @retval EFI_SUCCESS Buffer successfully freed.\r
667\r
668**/\r
669EFI_STATUS\r
670CoreFreePoolI (\r
671 IN VOID *Buffer,\r
672 OUT EFI_MEMORY_TYPE *PoolType OPTIONAL\r
673 )\r
674{\r
675 POOL *Pool;\r
676 POOL_HEAD *Head;\r
677 POOL_TAIL *Tail;\r
678 POOL_FREE *Free;\r
679 UINTN Index;\r
680 UINTN NoPages;\r
681 UINTN Size;\r
682 CHAR8 *NewPage;\r
683 UINTN Offset;\r
684 BOOLEAN AllFree;\r
685 UINTN Granularity;\r
686 BOOLEAN IsGuarded;\r
687 BOOLEAN HasPoolTail;\r
688\r
689 ASSERT(Buffer != NULL);\r
690 //\r
691 // Get the head & tail of the pool entry\r
692 //\r
693 Head = CR (Buffer, POOL_HEAD, Data, POOL_HEAD_SIGNATURE);\r
694 ASSERT(Head != NULL);\r
695\r
696 if (Head->Signature != POOL_HEAD_SIGNATURE) {\r
697 return EFI_INVALID_PARAMETER;\r
698 }\r
699\r
700 IsGuarded = IsPoolTypeToGuard (Head->Type) &&\r
701 IsMemoryGuarded ((EFI_PHYSICAL_ADDRESS)(UINTN)Head);\r
702 HasPoolTail = !(IsGuarded &&\r
703 ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0));\r
704\r
705 if (HasPoolTail) {\r
706 Tail = HEAD_TO_TAIL (Head);\r
707 ASSERT (Tail != NULL);\r
708\r
709 //\r
710 // Debug\r
711 //\r
712 ASSERT (Tail->Signature == POOL_TAIL_SIGNATURE);\r
713 ASSERT (Head->Size == Tail->Size);\r
714\r
715 if (Tail->Signature != POOL_TAIL_SIGNATURE) {\r
716 return EFI_INVALID_PARAMETER;\r
717 }\r
718\r
719 if (Head->Size != Tail->Size) {\r
720 return EFI_INVALID_PARAMETER;\r
721 }\r
722 }\r
723\r
724 ASSERT_LOCKED (&mPoolMemoryLock);\r
725\r
726 //\r
727 // Determine the pool type and account for it\r
728 //\r
729 Size = Head->Size;\r
730 Pool = LookupPoolHead (Head->Type);\r
731 if (Pool == NULL) {\r
732 return EFI_INVALID_PARAMETER;\r
733 }\r
734 Pool->Used -= Size;\r
735 DEBUG ((DEBUG_POOL, "FreePool: %p (len %lx) %,ld\n", Head->Data, (UINT64)(Head->Size - POOL_OVERHEAD), (UINT64) Pool->Used));\r
736\r
737 if (Head->Type == EfiACPIReclaimMemory ||\r
738 Head->Type == EfiACPIMemoryNVS ||\r
739 Head->Type == EfiRuntimeServicesCode ||\r
740 Head->Type == EfiRuntimeServicesData) {\r
741\r
742 Granularity = RUNTIME_PAGE_ALLOCATION_GRANULARITY;\r
743 } else {\r
744 Granularity = DEFAULT_PAGE_ALLOCATION_GRANULARITY;\r
745 }\r
746\r
747 if (PoolType != NULL) {\r
748 *PoolType = Head->Type;\r
749 }\r
750\r
751 //\r
752 // Determine the pool list\r
753 //\r
754 Index = SIZE_TO_LIST(Size);\r
755 DEBUG_CLEAR_MEMORY (Head, Size);\r
756\r
757 //\r
758 // If it's not on the list, it must be pool pages\r
759 //\r
760 if (Index >= SIZE_TO_LIST (Granularity) || IsGuarded) {\r
761\r
762 //\r
763 // Return the memory pages back to free memory\r
764 //\r
765 NoPages = EFI_SIZE_TO_PAGES (Size) + EFI_SIZE_TO_PAGES (Granularity) - 1;\r
766 NoPages &= ~(UINTN)(EFI_SIZE_TO_PAGES (Granularity) - 1);\r
767 if (IsGuarded) {\r
768 Head = AdjustPoolHeadF ((EFI_PHYSICAL_ADDRESS)(UINTN)Head);\r
769 CoreFreePoolPagesWithGuard (\r
770 Pool->MemoryType,\r
771 (EFI_PHYSICAL_ADDRESS)(UINTN)Head,\r
772 NoPages\r
773 );\r
774 } else {\r
775 CoreFreePoolPagesI (\r
776 Pool->MemoryType,\r
777 (EFI_PHYSICAL_ADDRESS)(UINTN)Head,\r
778 NoPages\r
779 );\r
780 }\r
781\r
782 } else {\r
783\r
784 //\r
785 // Put the pool entry onto the free pool list\r
786 //\r
787 Free = (POOL_FREE *) Head;\r
788 ASSERT(Free != NULL);\r
789 Free->Signature = POOL_FREE_SIGNATURE;\r
790 Free->Index = (UINT32)Index;\r
791 InsertHeadList (&Pool->FreeList[Index], &Free->Link);\r
792\r
793 //\r
794 // See if all the pool entries in the same page as Free are freed pool\r
795 // entries\r
796 //\r
797 NewPage = (CHAR8 *)((UINTN)Free & ~(Granularity - 1));\r
798 Free = (POOL_FREE *) &NewPage[0];\r
799 ASSERT(Free != NULL);\r
800\r
801 if (Free->Signature == POOL_FREE_SIGNATURE) {\r
802\r
803 AllFree = TRUE;\r
804 Offset = 0;\r
805\r
806 while ((Offset < Granularity) && (AllFree)) {\r
807 Free = (POOL_FREE *) &NewPage[Offset];\r
808 ASSERT(Free != NULL);\r
809 if (Free->Signature != POOL_FREE_SIGNATURE) {\r
810 AllFree = FALSE;\r
811 }\r
812 Offset += LIST_TO_SIZE(Free->Index);\r
813 }\r
814\r
815 if (AllFree) {\r
816\r
817 //\r
818 // All of the pool entries in the same page as Free are free pool\r
819 // entries\r
820 // Remove all of these pool entries from the free loop lists.\r
821 //\r
822 Free = (POOL_FREE *) &NewPage[0];\r
823 ASSERT(Free != NULL);\r
824 Offset = 0;\r
825\r
826 while (Offset < Granularity) {\r
827 Free = (POOL_FREE *) &NewPage[Offset];\r
828 ASSERT(Free != NULL);\r
829 RemoveEntryList (&Free->Link);\r
830 Offset += LIST_TO_SIZE(Free->Index);\r
831 }\r
832\r
833 //\r
834 // Free the page\r
835 //\r
836 CoreFreePoolPagesI (Pool->MemoryType, (EFI_PHYSICAL_ADDRESS) (UINTN)NewPage,\r
837 EFI_SIZE_TO_PAGES (Granularity));\r
838 }\r
839 }\r
840 }\r
841\r
842 //\r
843 // If this is an OS/OEM specific memory type, then check to see if the last\r
844 // portion of that memory type has been freed. If it has, then free the\r
845 // list entry for that memory type\r
846 //\r
847 if (((UINT32) Pool->MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) && Pool->Used == 0) {\r
848 RemoveEntryList (&Pool->Link);\r
849 CoreFreePoolI (Pool, NULL);\r
850 }\r
851\r
852 return EFI_SUCCESS;\r
853}\r
854\r