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