]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/Dxe/Mem/Pool.c
MdeModulePkg: define PCD for DXE memory protection policy
[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
313 return Buffer;\r
314}\r
315\r
162ed594 316/**\r
28a00297 317 Internal function to allocate pool of a particular type.\r
28a00297 318 Caller must have the memory lock held\r
319\r
022c6d45 320 @param PoolType Type of pool to allocate\r
321 @param Size The amount of pool to allocate\r
28a00297 322\r
162ed594 323 @return The allocate pool, or NULL\r
28a00297 324\r
162ed594 325**/\r
326VOID *\r
327CoreAllocatePoolI (\r
328 IN EFI_MEMORY_TYPE PoolType,\r
329 IN UINTN Size\r
330 )\r
28a00297 331{\r
332 POOL *Pool;\r
333 POOL_FREE *Free;\r
334 POOL_HEAD *Head;\r
335 POOL_TAIL *Tail;\r
336 CHAR8 *NewPage;\r
337 VOID *Buffer;\r
338 UINTN Index;\r
339 UINTN FSize;\r
6860b92c 340 UINTN Offset, MaxOffset;\r
28a00297 341 UINTN NoPages;\r
7970100c 342 UINTN Granularity;\r
28a00297 343\r
f31c36c2 344 ASSERT_LOCKED (&mPoolMemoryLock);\r
28a00297 345\r
7970100c
AB
346 if (PoolType == EfiACPIReclaimMemory ||\r
347 PoolType == EfiACPIMemoryNVS ||\r
348 PoolType == EfiRuntimeServicesCode ||\r
349 PoolType == EfiRuntimeServicesData) {\r
350\r
351 Granularity = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;\r
352 } else {\r
353 Granularity = DEFAULT_PAGE_ALLOCATION;\r
354 }\r
355\r
28a00297 356 //\r
357 // Adjust the size by the pool header & tail overhead\r
358 //\r
022c6d45 359\r
28a00297 360 //\r
361 // Adjusting the Size to be of proper alignment so that\r
362 // we don't get an unaligned access fault later when\r
363 // pool_Tail is being initialized\r
364 //\r
f0d5cbb6 365 Size = ALIGN_VARIABLE (Size);\r
28a00297 366\r
367 Size += POOL_OVERHEAD;\r
368 Index = SIZE_TO_LIST(Size);\r
369 Pool = LookupPoolHead (PoolType);\r
370 if (Pool== NULL) {\r
371 return NULL;\r
372 }\r
373 Head = NULL;\r
374\r
375 //\r
376 // If allocation is over max size, just allocate pages for the request\r
377 // (slow)\r
378 //\r
f2c7daf6 379 if (Index >= SIZE_TO_LIST (Granularity)) {\r
7970100c
AB
380 NoPages = EFI_SIZE_TO_PAGES(Size) + EFI_SIZE_TO_PAGES (Granularity) - 1;\r
381 NoPages &= ~(UINTN)(EFI_SIZE_TO_PAGES (Granularity) - 1);\r
f31c36c2 382 Head = CoreAllocatePoolPagesI (PoolType, NoPages, Granularity);\r
28a00297 383 goto Done;\r
384 }\r
385\r
386 //\r
387 // If there's no free pool in the proper list size, go get some more pages\r
388 //\r
389 if (IsListEmpty (&Pool->FreeList[Index])) {\r
390\r
6860b92c
AB
391 Offset = LIST_TO_SIZE (Index);\r
392 MaxOffset = Granularity;\r
393\r
394 //\r
395 // Check the bins holding larger blocks, and carve one up if needed\r
396 //\r
397 while (++Index < SIZE_TO_LIST (Granularity)) {\r
398 if (!IsListEmpty (&Pool->FreeList[Index])) {\r
399 Free = CR (Pool->FreeList[Index].ForwardLink, POOL_FREE, Link, POOL_FREE_SIGNATURE);\r
400 RemoveEntryList (&Free->Link);\r
401 NewPage = (VOID *) Free;\r
402 MaxOffset = LIST_TO_SIZE (Index);\r
403 goto Carve;\r
404 }\r
405 }\r
406\r
28a00297 407 //\r
408 // Get another page\r
409 //\r
f31c36c2 410 NewPage = CoreAllocatePoolPagesI (PoolType, EFI_SIZE_TO_PAGES (Granularity), Granularity);\r
28a00297 411 if (NewPage == NULL) {\r
412 goto Done;\r
413 }\r
414\r
415 //\r
f8aabf6e 416 // Serve the allocation request from the head of the allocated block\r
28a00297 417 //\r
6860b92c 418Carve:\r
f8aabf6e 419 Head = (POOL_HEAD *) NewPage;\r
f8aabf6e
AB
420\r
421 //\r
422 // Carve up remaining space into free pool blocks\r
423 //\r
6860b92c
AB
424 Index--;\r
425 while (Offset < MaxOffset) {\r
28a00297 426 ASSERT (Index < MAX_POOL_LIST);\r
427 FSize = LIST_TO_SIZE(Index);\r
428\r
6860b92c 429 while (Offset + FSize <= MaxOffset) {\r
022c6d45 430 Free = (POOL_FREE *) &NewPage[Offset];\r
28a00297 431 Free->Signature = POOL_FREE_SIGNATURE;\r
432 Free->Index = (UINT32)Index;\r
433 InsertHeadList (&Pool->FreeList[Index], &Free->Link);\r
162ed594 434 Offset += FSize;\r
28a00297 435 }\r
28a00297 436 Index -= 1;\r
437 }\r
438\r
6860b92c 439 ASSERT (Offset == MaxOffset);\r
f8aabf6e 440 goto Done;\r
28a00297 441 }\r
442\r
443 //\r
444 // Remove entry from free pool list\r
445 //\r
446 Free = CR (Pool->FreeList[Index].ForwardLink, POOL_FREE, Link, POOL_FREE_SIGNATURE);\r
447 RemoveEntryList (&Free->Link);\r
448\r
449 Head = (POOL_HEAD *) Free;\r
450\r
451Done:\r
452 Buffer = NULL;\r
453\r
454 if (Head != NULL) {\r
022c6d45 455\r
28a00297 456 //\r
457 // If we have a pool buffer, fill in the header & tail info\r
458 //\r
459 Head->Signature = POOL_HEAD_SIGNATURE;\r
bb683bf4 460 Head->Size = Size;\r
28a00297 461 Head->Type = (EFI_MEMORY_TYPE) PoolType;\r
462 Tail = HEAD_TO_TAIL (Head);\r
463 Tail->Signature = POOL_TAIL_SIGNATURE;\r
bb683bf4 464 Tail->Size = Size;\r
28a00297 465 Buffer = Head->Data;\r
466 DEBUG_CLEAR_MEMORY (Buffer, Size - POOL_OVERHEAD);\r
467\r
e94a9ff7 468 DEBUG ((\r
469 DEBUG_POOL,\r
57b4ecb9 470 "AllocatePoolI: Type %x, Addr %p (len %lx) %,ld\n", PoolType,\r
022c6d45 471 Buffer,\r
57b4ecb9 472 (UINT64)(Size - POOL_OVERHEAD),\r
473 (UINT64) Pool->Used\r
e94a9ff7 474 ));\r
28a00297 475\r
476 //\r
477 // Account the allocation\r
478 //\r
479 Pool->Used += Size;\r
480\r
481 } else {\r
57b4ecb9 482 DEBUG ((DEBUG_ERROR | DEBUG_POOL, "AllocatePool: failed to allocate %ld bytes\n", (UINT64) Size));\r
28a00297 483 }\r
484\r
485 return Buffer;\r
486}\r
022c6d45 487\r
28a00297 488\r
489\r
162ed594 490/**\r
28a00297 491 Frees pool.\r
492\r
022c6d45 493 @param Buffer The allocated pool entry to free\r
925f0d1a 494 @param PoolType Pointer to pool type\r
28a00297 495\r
022c6d45 496 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.\r
162ed594 497 @retval EFI_SUCCESS Pool successfully freed.\r
28a00297 498\r
162ed594 499**/\r
500EFI_STATUS\r
501EFIAPI\r
84edd20b 502CoreInternalFreePool (\r
925f0d1a
SZ
503 IN VOID *Buffer,\r
504 OUT EFI_MEMORY_TYPE *PoolType OPTIONAL\r
162ed594 505 )\r
28a00297 506{\r
507 EFI_STATUS Status;\r
508\r
e94a9ff7 509 if (Buffer == NULL) {\r
28a00297 510 return EFI_INVALID_PARAMETER;\r
511 }\r
512\r
f31c36c2 513 CoreAcquireLock (&mPoolMemoryLock);\r
925f0d1a 514 Status = CoreFreePoolI (Buffer, PoolType);\r
f31c36c2 515 CoreReleaseLock (&mPoolMemoryLock);\r
28a00297 516 return Status;\r
517}\r
518\r
84edd20b
SZ
519/**\r
520 Frees pool.\r
521\r
522 @param Buffer The allocated pool entry to free\r
523\r
524 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.\r
525 @retval EFI_SUCCESS Pool successfully freed.\r
526\r
527**/\r
528EFI_STATUS\r
529EFIAPI\r
530CoreFreePool (\r
531 IN VOID *Buffer\r
532 )\r
533{\r
925f0d1a
SZ
534 EFI_STATUS Status;\r
535 EFI_MEMORY_TYPE PoolType;\r
736a692e 536\r
925f0d1a 537 Status = CoreInternalFreePool (Buffer, &PoolType);\r
736a692e 538 if (!EFI_ERROR (Status)) {\r
1d60fe96
SZ
539 CoreUpdateProfile (\r
540 (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),\r
541 MemoryProfileActionFreePool,\r
542 PoolType,\r
543 0,\r
544 Buffer,\r
545 NULL\r
546 );\r
74a88770 547 InstallMemoryAttributesTableOnMemoryAllocation (PoolType);\r
736a692e
HT
548 }\r
549 return Status;\r
550}\r
28a00297 551\r
f31c36c2
AB
552STATIC\r
553VOID\r
554CoreFreePoolPagesI (\r
555 IN EFI_MEMORY_TYPE PoolType,\r
556 IN EFI_PHYSICAL_ADDRESS Memory,\r
557 IN UINTN NoPages\r
558 )\r
559{\r
560 CoreAcquireMemoryLock ();\r
561 CoreFreePoolPages (Memory, NoPages);\r
562 CoreReleaseMemoryLock ();\r
563}\r
564\r
162ed594 565/**\r
28a00297 566 Internal function to free a pool entry.\r
28a00297 567 Caller must have the memory lock held\r
568\r
022c6d45 569 @param Buffer The allocated pool entry to free\r
925f0d1a 570 @param PoolType Pointer to pool type\r
28a00297 571\r
022c6d45 572 @retval EFI_INVALID_PARAMETER Buffer not valid\r
162ed594 573 @retval EFI_SUCCESS Buffer successfully freed.\r
28a00297 574\r
162ed594 575**/\r
576EFI_STATUS\r
577CoreFreePoolI (\r
925f0d1a
SZ
578 IN VOID *Buffer,\r
579 OUT EFI_MEMORY_TYPE *PoolType OPTIONAL\r
162ed594 580 )\r
28a00297 581{\r
582 POOL *Pool;\r
583 POOL_HEAD *Head;\r
584 POOL_TAIL *Tail;\r
585 POOL_FREE *Free;\r
586 UINTN Index;\r
587 UINTN NoPages;\r
588 UINTN Size;\r
589 CHAR8 *NewPage;\r
162ed594 590 UINTN Offset;\r
28a00297 591 BOOLEAN AllFree;\r
7970100c 592 UINTN Granularity;\r
28a00297 593\r
57b4ecb9 594 ASSERT(Buffer != NULL);\r
28a00297 595 //\r
596 // Get the head & tail of the pool entry\r
597 //\r
598 Head = CR (Buffer, POOL_HEAD, Data, POOL_HEAD_SIGNATURE);\r
57b4ecb9 599 ASSERT(Head != NULL);\r
28a00297 600\r
601 if (Head->Signature != POOL_HEAD_SIGNATURE) {\r
602 return EFI_INVALID_PARAMETER;\r
603 }\r
604\r
605 Tail = HEAD_TO_TAIL (Head);\r
57b4ecb9 606 ASSERT(Tail != NULL);\r
28a00297 607\r
608 //\r
609 // Debug\r
610 //\r
611 ASSERT (Tail->Signature == POOL_TAIL_SIGNATURE);\r
612 ASSERT (Head->Size == Tail->Size);\r
f31c36c2 613 ASSERT_LOCKED (&mPoolMemoryLock);\r
28a00297 614\r
615 if (Tail->Signature != POOL_TAIL_SIGNATURE) {\r
616 return EFI_INVALID_PARAMETER;\r
617 }\r
618\r
619 if (Head->Size != Tail->Size) {\r
620 return EFI_INVALID_PARAMETER;\r
621 }\r
622\r
623 //\r
624 // Determine the pool type and account for it\r
625 //\r
626 Size = Head->Size;\r
627 Pool = LookupPoolHead (Head->Type);\r
628 if (Pool == NULL) {\r
629 return EFI_INVALID_PARAMETER;\r
630 }\r
631 Pool->Used -= Size;\r
57b4ecb9 632 DEBUG ((DEBUG_POOL, "FreePool: %p (len %lx) %,ld\n", Head->Data, (UINT64)(Head->Size - POOL_OVERHEAD), (UINT64) Pool->Used));\r
28a00297 633\r
7970100c
AB
634 if (Head->Type == EfiACPIReclaimMemory ||\r
635 Head->Type == EfiACPIMemoryNVS ||\r
636 Head->Type == EfiRuntimeServicesCode ||\r
637 Head->Type == EfiRuntimeServicesData) {\r
638\r
639 Granularity = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;\r
640 } else {\r
641 Granularity = DEFAULT_PAGE_ALLOCATION;\r
642 }\r
643\r
925f0d1a
SZ
644 if (PoolType != NULL) {\r
645 *PoolType = Head->Type;\r
646 }\r
647\r
28a00297 648 //\r
022c6d45 649 // Determine the pool list\r
28a00297 650 //\r
651 Index = SIZE_TO_LIST(Size);\r
652 DEBUG_CLEAR_MEMORY (Head, Size);\r
653\r
654 //\r
655 // If it's not on the list, it must be pool pages\r
656 //\r
f2c7daf6 657 if (Index >= SIZE_TO_LIST (Granularity)) {\r
28a00297 658\r
659 //\r
660 // Return the memory pages back to free memory\r
661 //\r
7970100c
AB
662 NoPages = EFI_SIZE_TO_PAGES(Size) + EFI_SIZE_TO_PAGES (Granularity) - 1;\r
663 NoPages &= ~(UINTN)(EFI_SIZE_TO_PAGES (Granularity) - 1);\r
f31c36c2 664 CoreFreePoolPagesI (Pool->MemoryType, (EFI_PHYSICAL_ADDRESS) (UINTN) Head, NoPages);\r
28a00297 665\r
666 } else {\r
667\r
668 //\r
669 // Put the pool entry onto the free pool list\r
670 //\r
671 Free = (POOL_FREE *) Head;\r
57b4ecb9 672 ASSERT(Free != NULL);\r
28a00297 673 Free->Signature = POOL_FREE_SIGNATURE;\r
674 Free->Index = (UINT32)Index;\r
675 InsertHeadList (&Pool->FreeList[Index], &Free->Link);\r
676\r
677 //\r
022c6d45 678 // See if all the pool entries in the same page as Free are freed pool\r
28a00297 679 // entries\r
680 //\r
7970100c 681 NewPage = (CHAR8 *)((UINTN)Free & ~(Granularity - 1));\r
28a00297 682 Free = (POOL_FREE *) &NewPage[0];\r
e94a9ff7 683 ASSERT(Free != NULL);\r
28a00297 684\r
685 if (Free->Signature == POOL_FREE_SIGNATURE) {\r
686\r
28a00297 687 AllFree = TRUE;\r
162ed594 688 Offset = 0;\r
022c6d45 689\r
7970100c 690 while ((Offset < Granularity) && (AllFree)) {\r
7e8e2205
AB
691 Free = (POOL_FREE *) &NewPage[Offset];\r
692 ASSERT(Free != NULL);\r
693 if (Free->Signature != POOL_FREE_SIGNATURE) {\r
694 AllFree = FALSE;\r
28a00297 695 }\r
7e8e2205 696 Offset += LIST_TO_SIZE(Free->Index);\r
28a00297 697 }\r
698\r
699 if (AllFree) {\r
700\r
701 //\r
022c6d45 702 // All of the pool entries in the same page as Free are free pool\r
28a00297 703 // entries\r
704 // Remove all of these pool entries from the free loop lists.\r
705 //\r
706 Free = (POOL_FREE *) &NewPage[0];\r
57b4ecb9 707 ASSERT(Free != NULL);\r
162ed594 708 Offset = 0;\r
022c6d45 709\r
7970100c 710 while (Offset < Granularity) {\r
7e8e2205
AB
711 Free = (POOL_FREE *) &NewPage[Offset];\r
712 ASSERT(Free != NULL);\r
713 RemoveEntryList (&Free->Link);\r
714 Offset += LIST_TO_SIZE(Free->Index);\r
28a00297 715 }\r
716\r
717 //\r
718 // Free the page\r
719 //\r
f31c36c2
AB
720 CoreFreePoolPagesI (Pool->MemoryType, (EFI_PHYSICAL_ADDRESS) (UINTN)NewPage,\r
721 EFI_SIZE_TO_PAGES (Granularity));\r
28a00297 722 }\r
723 }\r
724 }\r
725\r
726 //\r
09159a29 727 // If this is an OS/OEM specific memory type, then check to see if the last\r
28a00297 728 // portion of that memory type has been freed. If it has, then free the\r
729 // list entry for that memory type\r
730 //\r
09159a29 731 if (((UINT32) Pool->MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) && Pool->Used == 0) {\r
28a00297 732 RemoveEntryList (&Pool->Link);\r
925f0d1a 733 CoreFreePoolI (Pool, NULL);\r
28a00297 734 }\r
735\r
736 return EFI_SUCCESS;\r
737}\r
84edd20b 738\r