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