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