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