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