]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/Dxe/Mem/Pool.c
Fix comparisons of enumerated types which may cause warnings for some compilers.
[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
3e058701 4Copyright (c) 2006 - 2012, 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
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
3d78c020 123 if ((UINT32)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
68db1228 131 if ((INT32)MemoryType < 0) {\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
3e058701 170 @retval EFI_INVALID_PARAMETER PoolType not valid or Buffer is NULL. \r
022c6d45 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
3e058701
ED
193 if (Buffer == NULL) {\r
194 return EFI_INVALID_PARAMETER;\r
195 }\r
196\r
28a00297 197 *Buffer = NULL;\r
022c6d45 198\r
28a00297 199 //\r
200 // If size is too large, fail it\r
201 // Base on the EFI spec, return status of EFI_OUT_OF_RESOURCES\r
202 //\r
203 if (Size > MAX_POOL_SIZE) {\r
204 return EFI_OUT_OF_RESOURCES;\r
205 }\r
206\r
207 //\r
208 // Acquire the memory lock and make the allocation\r
209 //\r
210 Status = CoreAcquireLockOrFail (&gMemoryLock);\r
211 if (EFI_ERROR (Status)) {\r
212 return EFI_OUT_OF_RESOURCES;\r
213 }\r
214\r
215 *Buffer = CoreAllocatePoolI (PoolType, Size);\r
216 CoreReleaseMemoryLock ();\r
217 return (*Buffer != NULL) ? EFI_SUCCESS : EFI_OUT_OF_RESOURCES;\r
218}\r
219\r
220\r
28a00297 221\r
162ed594 222/**\r
28a00297 223 Internal function to allocate pool of a particular type.\r
28a00297 224 Caller must have the memory lock held\r
225\r
022c6d45 226 @param PoolType Type of pool to allocate\r
227 @param Size The amount of pool to allocate\r
28a00297 228\r
162ed594 229 @return The allocate pool, or NULL\r
28a00297 230\r
162ed594 231**/\r
232VOID *\r
233CoreAllocatePoolI (\r
234 IN EFI_MEMORY_TYPE PoolType,\r
235 IN UINTN Size\r
236 )\r
28a00297 237{\r
238 POOL *Pool;\r
239 POOL_FREE *Free;\r
240 POOL_HEAD *Head;\r
241 POOL_TAIL *Tail;\r
242 CHAR8 *NewPage;\r
243 VOID *Buffer;\r
244 UINTN Index;\r
245 UINTN FSize;\r
162ed594 246 UINTN Offset;\r
28a00297 247 UINTN NoPages;\r
248\r
249 ASSERT_LOCKED (&gMemoryLock);\r
250\r
251 //\r
252 // Adjust the size by the pool header & tail overhead\r
253 //\r
022c6d45 254\r
28a00297 255 //\r
256 // Adjusting the Size to be of proper alignment so that\r
257 // we don't get an unaligned access fault later when\r
258 // pool_Tail is being initialized\r
259 //\r
f0d5cbb6 260 Size = ALIGN_VARIABLE (Size);\r
28a00297 261\r
262 Size += POOL_OVERHEAD;\r
263 Index = SIZE_TO_LIST(Size);\r
264 Pool = LookupPoolHead (PoolType);\r
265 if (Pool== NULL) {\r
266 return NULL;\r
267 }\r
268 Head = NULL;\r
269\r
270 //\r
271 // If allocation is over max size, just allocate pages for the request\r
272 // (slow)\r
273 //\r
274 if (Index >= MAX_POOL_LIST) {\r
275 NoPages = EFI_SIZE_TO_PAGES(Size) + EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1;\r
276 NoPages &= ~(EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1);\r
277 Head = CoreAllocatePoolPages (PoolType, NoPages, DEFAULT_PAGE_ALLOCATION);\r
278 goto Done;\r
279 }\r
280\r
281 //\r
282 // If there's no free pool in the proper list size, go get some more pages\r
283 //\r
284 if (IsListEmpty (&Pool->FreeList[Index])) {\r
285\r
286 //\r
287 // Get another page\r
288 //\r
289 NewPage = CoreAllocatePoolPages(PoolType, EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION), DEFAULT_PAGE_ALLOCATION);\r
290 if (NewPage == NULL) {\r
291 goto Done;\r
292 }\r
293\r
294 //\r
295 // Carve up new page into free pool blocks\r
296 //\r
162ed594 297 Offset = 0;\r
298 while (Offset < DEFAULT_PAGE_ALLOCATION) {\r
28a00297 299 ASSERT (Index < MAX_POOL_LIST);\r
300 FSize = LIST_TO_SIZE(Index);\r
301\r
162ed594 302 while (Offset + FSize <= DEFAULT_PAGE_ALLOCATION) {\r
022c6d45 303 Free = (POOL_FREE *) &NewPage[Offset];\r
28a00297 304 Free->Signature = POOL_FREE_SIGNATURE;\r
305 Free->Index = (UINT32)Index;\r
306 InsertHeadList (&Pool->FreeList[Index], &Free->Link);\r
162ed594 307 Offset += FSize;\r
28a00297 308 }\r
309\r
310 Index -= 1;\r
311 }\r
312\r
162ed594 313 ASSERT (Offset == DEFAULT_PAGE_ALLOCATION);\r
28a00297 314 Index = SIZE_TO_LIST(Size);\r
315 }\r
316\r
317 //\r
318 // Remove entry from free pool list\r
319 //\r
320 Free = CR (Pool->FreeList[Index].ForwardLink, POOL_FREE, Link, POOL_FREE_SIGNATURE);\r
321 RemoveEntryList (&Free->Link);\r
322\r
323 Head = (POOL_HEAD *) Free;\r
324\r
325Done:\r
326 Buffer = NULL;\r
327\r
328 if (Head != NULL) {\r
022c6d45 329\r
28a00297 330 //\r
331 // If we have a pool buffer, fill in the header & tail info\r
332 //\r
333 Head->Signature = POOL_HEAD_SIGNATURE;\r
334 Head->Size = (UINT32) Size;\r
335 Head->Type = (EFI_MEMORY_TYPE) PoolType;\r
336 Tail = HEAD_TO_TAIL (Head);\r
337 Tail->Signature = POOL_TAIL_SIGNATURE;\r
338 Tail->Size = (UINT32) Size;\r
339 Buffer = Head->Data;\r
340 DEBUG_CLEAR_MEMORY (Buffer, Size - POOL_OVERHEAD);\r
341\r
e94a9ff7 342 DEBUG ((\r
343 DEBUG_POOL,\r
57b4ecb9 344 "AllocatePoolI: Type %x, Addr %p (len %lx) %,ld\n", PoolType,\r
022c6d45 345 Buffer,\r
57b4ecb9 346 (UINT64)(Size - POOL_OVERHEAD),\r
347 (UINT64) Pool->Used\r
e94a9ff7 348 ));\r
28a00297 349\r
350 //\r
351 // Account the allocation\r
352 //\r
353 Pool->Used += Size;\r
354\r
355 } else {\r
57b4ecb9 356 DEBUG ((DEBUG_ERROR | DEBUG_POOL, "AllocatePool: failed to allocate %ld bytes\n", (UINT64) Size));\r
28a00297 357 }\r
358\r
359 return Buffer;\r
360}\r
022c6d45 361\r
28a00297 362\r
363\r
162ed594 364/**\r
28a00297 365 Frees pool.\r
366\r
022c6d45 367 @param Buffer The allocated pool entry to free\r
28a00297 368\r
022c6d45 369 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.\r
162ed594 370 @retval EFI_SUCCESS Pool successfully freed.\r
28a00297 371\r
162ed594 372**/\r
373EFI_STATUS\r
374EFIAPI\r
375CoreFreePool (\r
376 IN VOID *Buffer\r
377 )\r
28a00297 378{\r
379 EFI_STATUS Status;\r
380\r
e94a9ff7 381 if (Buffer == NULL) {\r
28a00297 382 return EFI_INVALID_PARAMETER;\r
383 }\r
384\r
385 CoreAcquireMemoryLock ();\r
386 Status = CoreFreePoolI (Buffer);\r
387 CoreReleaseMemoryLock ();\r
388 return Status;\r
389}\r
390\r
391\r
28a00297 392\r
162ed594 393/**\r
28a00297 394 Internal function to free a pool entry.\r
28a00297 395 Caller must have the memory lock held\r
396\r
022c6d45 397 @param Buffer The allocated pool entry to free\r
28a00297 398\r
022c6d45 399 @retval EFI_INVALID_PARAMETER Buffer not valid\r
162ed594 400 @retval EFI_SUCCESS Buffer successfully freed.\r
28a00297 401\r
162ed594 402**/\r
403EFI_STATUS\r
404CoreFreePoolI (\r
405 IN VOID *Buffer\r
406 )\r
28a00297 407{\r
408 POOL *Pool;\r
409 POOL_HEAD *Head;\r
410 POOL_TAIL *Tail;\r
411 POOL_FREE *Free;\r
412 UINTN Index;\r
413 UINTN NoPages;\r
414 UINTN Size;\r
415 CHAR8 *NewPage;\r
416 UINTN FSize;\r
162ed594 417 UINTN Offset;\r
28a00297 418 BOOLEAN AllFree;\r
419\r
57b4ecb9 420 ASSERT(Buffer != NULL);\r
28a00297 421 //\r
422 // Get the head & tail of the pool entry\r
423 //\r
424 Head = CR (Buffer, POOL_HEAD, Data, POOL_HEAD_SIGNATURE);\r
57b4ecb9 425 ASSERT(Head != NULL);\r
28a00297 426\r
427 if (Head->Signature != POOL_HEAD_SIGNATURE) {\r
428 return EFI_INVALID_PARAMETER;\r
429 }\r
430\r
431 Tail = HEAD_TO_TAIL (Head);\r
57b4ecb9 432 ASSERT(Tail != NULL);\r
28a00297 433\r
434 //\r
435 // Debug\r
436 //\r
437 ASSERT (Tail->Signature == POOL_TAIL_SIGNATURE);\r
438 ASSERT (Head->Size == Tail->Size);\r
439 ASSERT_LOCKED (&gMemoryLock);\r
440\r
441 if (Tail->Signature != POOL_TAIL_SIGNATURE) {\r
442 return EFI_INVALID_PARAMETER;\r
443 }\r
444\r
445 if (Head->Size != Tail->Size) {\r
446 return EFI_INVALID_PARAMETER;\r
447 }\r
448\r
449 //\r
450 // Determine the pool type and account for it\r
451 //\r
452 Size = Head->Size;\r
453 Pool = LookupPoolHead (Head->Type);\r
454 if (Pool == NULL) {\r
455 return EFI_INVALID_PARAMETER;\r
456 }\r
457 Pool->Used -= Size;\r
57b4ecb9 458 DEBUG ((DEBUG_POOL, "FreePool: %p (len %lx) %,ld\n", Head->Data, (UINT64)(Head->Size - POOL_OVERHEAD), (UINT64) Pool->Used));\r
28a00297 459\r
460 //\r
022c6d45 461 // Determine the pool list\r
28a00297 462 //\r
463 Index = SIZE_TO_LIST(Size);\r
464 DEBUG_CLEAR_MEMORY (Head, Size);\r
465\r
466 //\r
467 // If it's not on the list, it must be pool pages\r
468 //\r
469 if (Index >= MAX_POOL_LIST) {\r
470\r
471 //\r
472 // Return the memory pages back to free memory\r
473 //\r
474 NoPages = EFI_SIZE_TO_PAGES(Size) + EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1;\r
475 NoPages &= ~(EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1);\r
476 CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS) (UINTN) Head, NoPages);\r
477\r
478 } else {\r
479\r
480 //\r
481 // Put the pool entry onto the free pool list\r
482 //\r
483 Free = (POOL_FREE *) Head;\r
57b4ecb9 484 ASSERT(Free != NULL);\r
28a00297 485 Free->Signature = POOL_FREE_SIGNATURE;\r
486 Free->Index = (UINT32)Index;\r
487 InsertHeadList (&Pool->FreeList[Index], &Free->Link);\r
488\r
489 //\r
022c6d45 490 // See if all the pool entries in the same page as Free are freed pool\r
28a00297 491 // entries\r
492 //\r
493 NewPage = (CHAR8 *)((UINTN)Free & ~((DEFAULT_PAGE_ALLOCATION) -1));\r
494 Free = (POOL_FREE *) &NewPage[0];\r
e94a9ff7 495 ASSERT(Free != NULL);\r
28a00297 496\r
497 if (Free->Signature == POOL_FREE_SIGNATURE) {\r
498\r
499 Index = Free->Index;\r
500\r
501 AllFree = TRUE;\r
162ed594 502 Offset = 0;\r
022c6d45 503\r
162ed594 504 while ((Offset < DEFAULT_PAGE_ALLOCATION) && (AllFree)) {\r
28a00297 505 FSize = LIST_TO_SIZE(Index);\r
162ed594 506 while (Offset + FSize <= DEFAULT_PAGE_ALLOCATION) {\r
507 Free = (POOL_FREE *) &NewPage[Offset];\r
57b4ecb9 508 ASSERT(Free != NULL);\r
28a00297 509 if (Free->Signature != POOL_FREE_SIGNATURE) {\r
510 AllFree = FALSE;\r
511 }\r
162ed594 512 Offset += FSize;\r
28a00297 513 }\r
514 Index -= 1;\r
515 }\r
516\r
517 if (AllFree) {\r
518\r
519 //\r
022c6d45 520 // All of the pool entries in the same page as Free are free pool\r
28a00297 521 // entries\r
522 // Remove all of these pool entries from the free loop lists.\r
523 //\r
524 Free = (POOL_FREE *) &NewPage[0];\r
57b4ecb9 525 ASSERT(Free != NULL);\r
28a00297 526 Index = Free->Index;\r
162ed594 527 Offset = 0;\r
022c6d45 528\r
162ed594 529 while (Offset < DEFAULT_PAGE_ALLOCATION) {\r
28a00297 530 FSize = LIST_TO_SIZE(Index);\r
162ed594 531 while (Offset + FSize <= DEFAULT_PAGE_ALLOCATION) {\r
532 Free = (POOL_FREE *) &NewPage[Offset];\r
57b4ecb9 533 ASSERT(Free != NULL);\r
28a00297 534 RemoveEntryList (&Free->Link);\r
162ed594 535 Offset += FSize;\r
28a00297 536 }\r
537 Index -= 1;\r
538 }\r
539\r
540 //\r
541 // Free the page\r
542 //\r
543 CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS) (UINTN)NewPage, EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION));\r
544 }\r
545 }\r
546 }\r
547\r
548 //\r
022c6d45 549 // If this is an OS specific memory type, then check to see if the last\r
28a00297 550 // portion of that memory type has been freed. If it has, then free the\r
551 // list entry for that memory type\r
552 //\r
3d78c020 553 if ((INT32)Pool->MemoryType < 0 && Pool->Used == 0) {\r
28a00297 554 RemoveEntryList (&Pool->Link);\r
555 CoreFreePoolI (Pool);\r
556 }\r
557\r
558 return EFI_SUCCESS;\r
559}\r