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