]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/Dxe/Mem/Pool.c
Update the copyright notice format
[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
cd5ebaa0
HT
4Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
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
29 UINT32 Size;\r
30 EFI_MEMORY_TYPE Type;\r
31 UINTN Reserved;\r
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
40 UINT32 Size;\r
41} POOL_TAIL;\r
42\r
43\r
44#define POOL_SHIFT 7\r
45\r
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
51\r
52#define SIZE_TO_LIST(a) ((a) >> POOL_SHIFT)\r
53#define LIST_TO_SIZE(a) ((a+1) << POOL_SHIFT)\r
54\r
55#define MAX_POOL_LIST SIZE_TO_LIST(DEFAULT_PAGE_ALLOCATION)\r
56\r
57#define MAX_POOL_SIZE (MAX_ADDRESS - POOL_OVERHEAD)\r
58\r
59//\r
60// Globals\r
61//\r
62\r
f3f2e05d 63#define POOL_SIGNATURE SIGNATURE_32('p','l','s','t')\r
28a00297 64typedef struct {\r
65 INTN Signature;\r
66 UINTN Used;\r
67 EFI_MEMORY_TYPE MemoryType;\r
68 LIST_ENTRY FreeList[MAX_POOL_LIST];\r
69 LIST_ENTRY Link;\r
022c6d45 70} POOL;\r
28a00297 71\r
28a00297 72//\r
e94a9ff7 73// Pool header for each memory type.\r
74//\r
75POOL mPoolHead[EfiMaxMemoryType];\r
76\r
28a00297 77//\r
e94a9ff7 78// List of pool header to search for the appropriate memory type.\r
28a00297 79//\r
57b4ecb9 80LIST_ENTRY mPoolHeadList = INITIALIZE_LIST_HEAD_VARIABLE (mPoolHeadList);\r
28a00297 81\r
162ed594 82\r
83/**\r
84 Called to initialize the pool.\r
85\r
86**/\r
28a00297 87VOID\r
88CoreInitializePool (\r
89 VOID\r
90 )\r
28a00297 91{\r
92 UINTN Type;\r
93 UINTN Index;\r
94\r
95 for (Type=0; Type < EfiMaxMemoryType; Type++) {\r
e94a9ff7 96 mPoolHead[Type].Signature = 0;\r
97 mPoolHead[Type].Used = 0;\r
98 mPoolHead[Type].MemoryType = (EFI_MEMORY_TYPE) Type;\r
28a00297 99 for (Index=0; Index < MAX_POOL_LIST; Index++) {\r
e94a9ff7 100 InitializeListHead (&mPoolHead[Type].FreeList[Index]);\r
28a00297 101 }\r
102 }\r
28a00297 103}\r
104\r
28a00297 105\r
162ed594 106/**\r
28a00297 107 Look up pool head for specified memory type.\r
108\r
022c6d45 109 @param MemoryType Memory type of which pool head is looked for\r
28a00297 110\r
162ed594 111 @return Pointer of Corresponding pool head.\r
28a00297 112\r
162ed594 113**/\r
162ed594 114POOL *\r
115LookupPoolHead (\r
116 IN EFI_MEMORY_TYPE MemoryType\r
117 )\r
28a00297 118{\r
119 LIST_ENTRY *Link;\r
120 POOL *Pool;\r
121 UINTN Index;\r
122\r
123 if (MemoryType >= 0 && MemoryType < EfiMaxMemoryType) {\r
e94a9ff7 124 return &mPoolHead[MemoryType];\r
28a00297 125 }\r
126\r
dc8d93ca 127 //\r
128 // MemoryType values in the range 0x80000000..0xFFFFFFFF are reserved for use by UEFI \r
129 // OS loaders that are provided by operating system vendors\r
130 //\r
c5d00b30 131 if (MemoryType >= (INT32)0x80000000 && MemoryType <= (INT32)0xffffffff) {\r
28a00297 132\r
e94a9ff7 133 for (Link = mPoolHeadList.ForwardLink; Link != &mPoolHeadList; Link = Link->ForwardLink) {\r
28a00297 134 Pool = CR(Link, POOL, Link, POOL_SIGNATURE);\r
135 if (Pool->MemoryType == MemoryType) {\r
136 return Pool;\r
137 }\r
138 }\r
139\r
140 Pool = CoreAllocatePoolI (EfiBootServicesData, sizeof (POOL));\r
141 if (Pool == NULL) {\r
142 return NULL;\r
143 }\r
144\r
145 Pool->Signature = POOL_SIGNATURE;\r
146 Pool->Used = 0;\r
147 Pool->MemoryType = MemoryType;\r
148 for (Index=0; Index < MAX_POOL_LIST; Index++) {\r
149 InitializeListHead (&Pool->FreeList[Index]);\r
150 }\r
151\r
e94a9ff7 152 InsertHeadList (&mPoolHeadList, &Pool->Link);\r
28a00297 153\r
154 return Pool;\r
155 }\r
156\r
157 return NULL;\r
158}\r
159\r
022c6d45 160\r
28a00297 161\r
162ed594 162/**\r
163 Allocate pool of a particular type.\r
164\r
022c6d45 165 @param PoolType Type of pool to allocate\r
166 @param Size The amount of pool to allocate\r
167 @param Buffer The address to return a pointer to the allocated\r
168 pool\r
162ed594 169\r
022c6d45 170 @retval EFI_INVALID_PARAMETER PoolType not valid\r
171 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.\r
162ed594 172 @retval EFI_SUCCESS Pool successfully allocated.\r
173\r
174**/\r
28a00297 175EFI_STATUS\r
176EFIAPI\r
177CoreAllocatePool (\r
178 IN EFI_MEMORY_TYPE PoolType,\r
179 IN UINTN Size,\r
180 OUT VOID **Buffer\r
181 )\r
28a00297 182{\r
183 EFI_STATUS Status;\r
184\r
185 //\r
186 // If it's not a valid type, fail it\r
187 //\r
188 if ((PoolType >= EfiMaxMemoryType && PoolType <= 0x7fffffff) ||\r
189 PoolType == EfiConventionalMemory) {\r
190 return EFI_INVALID_PARAMETER;\r
191 }\r
022c6d45 192\r
28a00297 193 *Buffer = NULL;\r
022c6d45 194\r
28a00297 195 //\r
196 // If size is too large, fail it\r
197 // Base on the EFI spec, return status of EFI_OUT_OF_RESOURCES\r
198 //\r
199 if (Size > MAX_POOL_SIZE) {\r
200 return EFI_OUT_OF_RESOURCES;\r
201 }\r
202\r
203 //\r
204 // Acquire the memory lock and make the allocation\r
205 //\r
206 Status = CoreAcquireLockOrFail (&gMemoryLock);\r
207 if (EFI_ERROR (Status)) {\r
208 return EFI_OUT_OF_RESOURCES;\r
209 }\r
210\r
211 *Buffer = CoreAllocatePoolI (PoolType, Size);\r
212 CoreReleaseMemoryLock ();\r
213 return (*Buffer != NULL) ? EFI_SUCCESS : EFI_OUT_OF_RESOURCES;\r
214}\r
215\r
216\r
28a00297 217\r
162ed594 218/**\r
28a00297 219 Internal function to allocate pool of a particular type.\r
28a00297 220 Caller must have the memory lock held\r
221\r
022c6d45 222 @param PoolType Type of pool to allocate\r
223 @param Size The amount of pool to allocate\r
28a00297 224\r
162ed594 225 @return The allocate pool, or NULL\r
28a00297 226\r
162ed594 227**/\r
228VOID *\r
229CoreAllocatePoolI (\r
230 IN EFI_MEMORY_TYPE PoolType,\r
231 IN UINTN Size\r
232 )\r
28a00297 233{\r
234 POOL *Pool;\r
235 POOL_FREE *Free;\r
236 POOL_HEAD *Head;\r
237 POOL_TAIL *Tail;\r
238 CHAR8 *NewPage;\r
239 VOID *Buffer;\r
240 UINTN Index;\r
241 UINTN FSize;\r
162ed594 242 UINTN Offset;\r
28a00297 243 UINTN NoPages;\r
244\r
245 ASSERT_LOCKED (&gMemoryLock);\r
246\r
247 //\r
248 // Adjust the size by the pool header & tail overhead\r
249 //\r
022c6d45 250\r
28a00297 251 //\r
252 // Adjusting the Size to be of proper alignment so that\r
253 // we don't get an unaligned access fault later when\r
254 // pool_Tail is being initialized\r
255 //\r
f0d5cbb6 256 Size = ALIGN_VARIABLE (Size);\r
28a00297 257\r
258 Size += POOL_OVERHEAD;\r
259 Index = SIZE_TO_LIST(Size);\r
260 Pool = LookupPoolHead (PoolType);\r
261 if (Pool== NULL) {\r
262 return NULL;\r
263 }\r
264 Head = NULL;\r
265\r
266 //\r
267 // If allocation is over max size, just allocate pages for the request\r
268 // (slow)\r
269 //\r
270 if (Index >= MAX_POOL_LIST) {\r
271 NoPages = EFI_SIZE_TO_PAGES(Size) + EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1;\r
272 NoPages &= ~(EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1);\r
273 Head = CoreAllocatePoolPages (PoolType, NoPages, DEFAULT_PAGE_ALLOCATION);\r
274 goto Done;\r
275 }\r
276\r
277 //\r
278 // If there's no free pool in the proper list size, go get some more pages\r
279 //\r
280 if (IsListEmpty (&Pool->FreeList[Index])) {\r
281\r
282 //\r
283 // Get another page\r
284 //\r
285 NewPage = CoreAllocatePoolPages(PoolType, EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION), DEFAULT_PAGE_ALLOCATION);\r
286 if (NewPage == NULL) {\r
287 goto Done;\r
288 }\r
289\r
290 //\r
291 // Carve up new page into free pool blocks\r
292 //\r
162ed594 293 Offset = 0;\r
294 while (Offset < DEFAULT_PAGE_ALLOCATION) {\r
28a00297 295 ASSERT (Index < MAX_POOL_LIST);\r
296 FSize = LIST_TO_SIZE(Index);\r
297\r
162ed594 298 while (Offset + FSize <= DEFAULT_PAGE_ALLOCATION) {\r
022c6d45 299 Free = (POOL_FREE *) &NewPage[Offset];\r
28a00297 300 Free->Signature = POOL_FREE_SIGNATURE;\r
301 Free->Index = (UINT32)Index;\r
302 InsertHeadList (&Pool->FreeList[Index], &Free->Link);\r
162ed594 303 Offset += FSize;\r
28a00297 304 }\r
305\r
306 Index -= 1;\r
307 }\r
308\r
162ed594 309 ASSERT (Offset == DEFAULT_PAGE_ALLOCATION);\r
28a00297 310 Index = SIZE_TO_LIST(Size);\r
311 }\r
312\r
313 //\r
314 // Remove entry from free pool list\r
315 //\r
316 Free = CR (Pool->FreeList[Index].ForwardLink, POOL_FREE, Link, POOL_FREE_SIGNATURE);\r
317 RemoveEntryList (&Free->Link);\r
318\r
319 Head = (POOL_HEAD *) Free;\r
320\r
321Done:\r
322 Buffer = NULL;\r
323\r
324 if (Head != NULL) {\r
022c6d45 325\r
28a00297 326 //\r
327 // If we have a pool buffer, fill in the header & tail info\r
328 //\r
329 Head->Signature = POOL_HEAD_SIGNATURE;\r
330 Head->Size = (UINT32) Size;\r
331 Head->Type = (EFI_MEMORY_TYPE) PoolType;\r
332 Tail = HEAD_TO_TAIL (Head);\r
333 Tail->Signature = POOL_TAIL_SIGNATURE;\r
334 Tail->Size = (UINT32) Size;\r
335 Buffer = Head->Data;\r
336 DEBUG_CLEAR_MEMORY (Buffer, Size - POOL_OVERHEAD);\r
337\r
e94a9ff7 338 DEBUG ((\r
339 DEBUG_POOL,\r
57b4ecb9 340 "AllocatePoolI: Type %x, Addr %p (len %lx) %,ld\n", PoolType,\r
022c6d45 341 Buffer,\r
57b4ecb9 342 (UINT64)(Size - POOL_OVERHEAD),\r
343 (UINT64) Pool->Used\r
e94a9ff7 344 ));\r
28a00297 345\r
346 //\r
347 // Account the allocation\r
348 //\r
349 Pool->Used += Size;\r
350\r
351 } else {\r
57b4ecb9 352 DEBUG ((DEBUG_ERROR | DEBUG_POOL, "AllocatePool: failed to allocate %ld bytes\n", (UINT64) Size));\r
28a00297 353 }\r
354\r
355 return Buffer;\r
356}\r
022c6d45 357\r
28a00297 358\r
359\r
162ed594 360/**\r
28a00297 361 Frees pool.\r
362\r
022c6d45 363 @param Buffer The allocated pool entry to free\r
28a00297 364\r
022c6d45 365 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.\r
162ed594 366 @retval EFI_SUCCESS Pool successfully freed.\r
28a00297 367\r
162ed594 368**/\r
369EFI_STATUS\r
370EFIAPI\r
371CoreFreePool (\r
372 IN VOID *Buffer\r
373 )\r
28a00297 374{\r
375 EFI_STATUS Status;\r
376\r
e94a9ff7 377 if (Buffer == NULL) {\r
28a00297 378 return EFI_INVALID_PARAMETER;\r
379 }\r
380\r
381 CoreAcquireMemoryLock ();\r
382 Status = CoreFreePoolI (Buffer);\r
383 CoreReleaseMemoryLock ();\r
384 return Status;\r
385}\r
386\r
387\r
28a00297 388\r
162ed594 389/**\r
28a00297 390 Internal function to free a pool entry.\r
28a00297 391 Caller must have the memory lock held\r
392\r
022c6d45 393 @param Buffer The allocated pool entry to free\r
28a00297 394\r
022c6d45 395 @retval EFI_INVALID_PARAMETER Buffer not valid\r
162ed594 396 @retval EFI_SUCCESS Buffer successfully freed.\r
28a00297 397\r
162ed594 398**/\r
399EFI_STATUS\r
400CoreFreePoolI (\r
401 IN VOID *Buffer\r
402 )\r
28a00297 403{\r
404 POOL *Pool;\r
405 POOL_HEAD *Head;\r
406 POOL_TAIL *Tail;\r
407 POOL_FREE *Free;\r
408 UINTN Index;\r
409 UINTN NoPages;\r
410 UINTN Size;\r
411 CHAR8 *NewPage;\r
412 UINTN FSize;\r
162ed594 413 UINTN Offset;\r
28a00297 414 BOOLEAN AllFree;\r
415\r
57b4ecb9 416 ASSERT(Buffer != NULL);\r
28a00297 417 //\r
418 // Get the head & tail of the pool entry\r
419 //\r
420 Head = CR (Buffer, POOL_HEAD, Data, POOL_HEAD_SIGNATURE);\r
57b4ecb9 421 ASSERT(Head != NULL);\r
28a00297 422\r
423 if (Head->Signature != POOL_HEAD_SIGNATURE) {\r
424 return EFI_INVALID_PARAMETER;\r
425 }\r
426\r
427 Tail = HEAD_TO_TAIL (Head);\r
57b4ecb9 428 ASSERT(Tail != NULL);\r
28a00297 429\r
430 //\r
431 // Debug\r
432 //\r
433 ASSERT (Tail->Signature == POOL_TAIL_SIGNATURE);\r
434 ASSERT (Head->Size == Tail->Size);\r
435 ASSERT_LOCKED (&gMemoryLock);\r
436\r
437 if (Tail->Signature != POOL_TAIL_SIGNATURE) {\r
438 return EFI_INVALID_PARAMETER;\r
439 }\r
440\r
441 if (Head->Size != Tail->Size) {\r
442 return EFI_INVALID_PARAMETER;\r
443 }\r
444\r
445 //\r
446 // Determine the pool type and account for it\r
447 //\r
448 Size = Head->Size;\r
449 Pool = LookupPoolHead (Head->Type);\r
450 if (Pool == NULL) {\r
451 return EFI_INVALID_PARAMETER;\r
452 }\r
453 Pool->Used -= Size;\r
57b4ecb9 454 DEBUG ((DEBUG_POOL, "FreePool: %p (len %lx) %,ld\n", Head->Data, (UINT64)(Head->Size - POOL_OVERHEAD), (UINT64) Pool->Used));\r
28a00297 455\r
456 //\r
022c6d45 457 // Determine the pool list\r
28a00297 458 //\r
459 Index = SIZE_TO_LIST(Size);\r
460 DEBUG_CLEAR_MEMORY (Head, Size);\r
461\r
462 //\r
463 // If it's not on the list, it must be pool pages\r
464 //\r
465 if (Index >= MAX_POOL_LIST) {\r
466\r
467 //\r
468 // Return the memory pages back to free memory\r
469 //\r
470 NoPages = EFI_SIZE_TO_PAGES(Size) + EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1;\r
471 NoPages &= ~(EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1);\r
472 CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS) (UINTN) Head, NoPages);\r
473\r
474 } else {\r
475\r
476 //\r
477 // Put the pool entry onto the free pool list\r
478 //\r
479 Free = (POOL_FREE *) Head;\r
57b4ecb9 480 ASSERT(Free != NULL);\r
28a00297 481 Free->Signature = POOL_FREE_SIGNATURE;\r
482 Free->Index = (UINT32)Index;\r
483 InsertHeadList (&Pool->FreeList[Index], &Free->Link);\r
484\r
485 //\r
022c6d45 486 // See if all the pool entries in the same page as Free are freed pool\r
28a00297 487 // entries\r
488 //\r
489 NewPage = (CHAR8 *)((UINTN)Free & ~((DEFAULT_PAGE_ALLOCATION) -1));\r
490 Free = (POOL_FREE *) &NewPage[0];\r
e94a9ff7 491 ASSERT(Free != NULL);\r
28a00297 492\r
493 if (Free->Signature == POOL_FREE_SIGNATURE) {\r
494\r
495 Index = Free->Index;\r
496\r
497 AllFree = TRUE;\r
162ed594 498 Offset = 0;\r
022c6d45 499\r
162ed594 500 while ((Offset < DEFAULT_PAGE_ALLOCATION) && (AllFree)) {\r
28a00297 501 FSize = LIST_TO_SIZE(Index);\r
162ed594 502 while (Offset + FSize <= DEFAULT_PAGE_ALLOCATION) {\r
503 Free = (POOL_FREE *) &NewPage[Offset];\r
57b4ecb9 504 ASSERT(Free != NULL);\r
28a00297 505 if (Free->Signature != POOL_FREE_SIGNATURE) {\r
506 AllFree = FALSE;\r
507 }\r
162ed594 508 Offset += FSize;\r
28a00297 509 }\r
510 Index -= 1;\r
511 }\r
512\r
513 if (AllFree) {\r
514\r
515 //\r
022c6d45 516 // All of the pool entries in the same page as Free are free pool\r
28a00297 517 // entries\r
518 // Remove all of these pool entries from the free loop lists.\r
519 //\r
520 Free = (POOL_FREE *) &NewPage[0];\r
57b4ecb9 521 ASSERT(Free != NULL);\r
28a00297 522 Index = Free->Index;\r
162ed594 523 Offset = 0;\r
022c6d45 524\r
162ed594 525 while (Offset < DEFAULT_PAGE_ALLOCATION) {\r
28a00297 526 FSize = LIST_TO_SIZE(Index);\r
162ed594 527 while (Offset + FSize <= DEFAULT_PAGE_ALLOCATION) {\r
528 Free = (POOL_FREE *) &NewPage[Offset];\r
57b4ecb9 529 ASSERT(Free != NULL);\r
28a00297 530 RemoveEntryList (&Free->Link);\r
162ed594 531 Offset += FSize;\r
28a00297 532 }\r
533 Index -= 1;\r
534 }\r
535\r
536 //\r
537 // Free the page\r
538 //\r
539 CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS) (UINTN)NewPage, EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION));\r
540 }\r
541 }\r
542 }\r
543\r
544 //\r
022c6d45 545 // If this is an OS specific memory type, then check to see if the last\r
28a00297 546 // portion of that memory type has been freed. If it has, then free the\r
547 // list entry for that memory type\r
548 //\r
549 if (Pool->MemoryType < 0 && Pool->Used == 0) {\r
550 RemoveEntryList (&Pool->Link);\r
551 CoreFreePoolI (Pool);\r
552 }\r
553\r
554 return EFI_SUCCESS;\r
555}\r