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