]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/Dxe/Mem/Pool.c
Code scrub for DiskIo, Partition & Unicode Collation
[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
15#include <DxeMain.h>\r
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
69} POOL; \r
70\r
71\r
72POOL PoolHead[EfiMaxMemoryType];\r
73LIST_ENTRY PoolHeadList;\r
74\r
75//\r
76//\r
77//\r
78\r
162ed594 79\r
80/**\r
81 Called to initialize the pool.\r
82\r
83**/\r
28a00297 84VOID\r
85CoreInitializePool (\r
86 VOID\r
87 )\r
28a00297 88{\r
89 UINTN Type;\r
90 UINTN Index;\r
91\r
92 for (Type=0; Type < EfiMaxMemoryType; Type++) {\r
93 PoolHead[Type].Signature = 0;\r
94 PoolHead[Type].Used = 0;\r
95 PoolHead[Type].MemoryType = (EFI_MEMORY_TYPE) Type;\r
96 for (Index=0; Index < MAX_POOL_LIST; Index++) {\r
97 InitializeListHead (&PoolHead[Type].FreeList[Index]);\r
98 }\r
99 }\r
100 InitializeListHead (&PoolHeadList);\r
101}\r
102\r
28a00297 103\r
162ed594 104/**\r
28a00297 105 Look up pool head for specified memory type.\r
106\r
162ed594 107 @param MemoryType Memory type of which pool head is looked for \r
28a00297 108\r
162ed594 109 @return Pointer of Corresponding pool head.\r
28a00297 110\r
162ed594 111**/\r
162ed594 112POOL *\r
113LookupPoolHead (\r
114 IN EFI_MEMORY_TYPE MemoryType\r
115 )\r
28a00297 116{\r
117 LIST_ENTRY *Link;\r
118 POOL *Pool;\r
119 UINTN Index;\r
120\r
121 if (MemoryType >= 0 && MemoryType < EfiMaxMemoryType) {\r
122 return &PoolHead[MemoryType];\r
123 }\r
124\r
125 if (MemoryType < 0) {\r
126\r
127 for (Link = PoolHeadList.ForwardLink; Link != &PoolHeadList; Link = Link->ForwardLink) {\r
128 Pool = CR(Link, POOL, Link, POOL_SIGNATURE);\r
129 if (Pool->MemoryType == MemoryType) {\r
130 return Pool;\r
131 }\r
132 }\r
133\r
134 Pool = CoreAllocatePoolI (EfiBootServicesData, sizeof (POOL));\r
135 if (Pool == NULL) {\r
136 return NULL;\r
137 }\r
138\r
139 Pool->Signature = POOL_SIGNATURE;\r
140 Pool->Used = 0;\r
141 Pool->MemoryType = MemoryType;\r
142 for (Index=0; Index < MAX_POOL_LIST; Index++) {\r
143 InitializeListHead (&Pool->FreeList[Index]);\r
144 }\r
145\r
146 InsertHeadList (&PoolHeadList, &Pool->Link);\r
147\r
148 return Pool;\r
149 }\r
150\r
151 return NULL;\r
152}\r
153\r
154 \r
155\r
162ed594 156\r
157/**\r
158 Allocate pool of a particular type.\r
159\r
160 @param PoolType Type of pool to allocate \r
161 @param Size The amount of pool to allocate \r
162 @param Buffer The address to return a pointer to the allocated \r
163 pool \r
164\r
165 @retval EFI_INVALID_PARAMETER PoolType not valid \r
166 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed. \r
167 @retval EFI_SUCCESS Pool successfully allocated.\r
168\r
169**/\r
28a00297 170EFI_STATUS\r
171EFIAPI\r
172CoreAllocatePool (\r
173 IN EFI_MEMORY_TYPE PoolType,\r
174 IN UINTN Size,\r
175 OUT VOID **Buffer\r
176 )\r
28a00297 177{\r
178 EFI_STATUS Status;\r
179\r
180 //\r
181 // If it's not a valid type, fail it\r
182 //\r
183 if ((PoolType >= EfiMaxMemoryType && PoolType <= 0x7fffffff) ||\r
184 PoolType == EfiConventionalMemory) {\r
185 return EFI_INVALID_PARAMETER;\r
186 }\r
187 \r
188 *Buffer = NULL;\r
189 \r
190 //\r
191 // If size is too large, fail it\r
192 // Base on the EFI spec, return status of EFI_OUT_OF_RESOURCES\r
193 //\r
194 if (Size > MAX_POOL_SIZE) {\r
195 return EFI_OUT_OF_RESOURCES;\r
196 }\r
197\r
198 //\r
199 // Acquire the memory lock and make the allocation\r
200 //\r
201 Status = CoreAcquireLockOrFail (&gMemoryLock);\r
202 if (EFI_ERROR (Status)) {\r
203 return EFI_OUT_OF_RESOURCES;\r
204 }\r
205\r
206 *Buffer = CoreAllocatePoolI (PoolType, Size);\r
207 CoreReleaseMemoryLock ();\r
208 return (*Buffer != NULL) ? EFI_SUCCESS : EFI_OUT_OF_RESOURCES;\r
209}\r
210\r
211\r
28a00297 212\r
162ed594 213/**\r
28a00297 214 Internal function to allocate pool of a particular type.\r
28a00297 215 Caller must have the memory lock held\r
216\r
162ed594 217 @param PoolType Type of pool to allocate \r
218 @param Size The amount of pool to allocate \r
28a00297 219\r
162ed594 220 @return The allocate pool, or NULL\r
28a00297 221\r
162ed594 222**/\r
223VOID *\r
224CoreAllocatePoolI (\r
225 IN EFI_MEMORY_TYPE PoolType,\r
226 IN UINTN Size\r
227 )\r
28a00297 228{\r
229 POOL *Pool;\r
230 POOL_FREE *Free;\r
231 POOL_HEAD *Head;\r
232 POOL_TAIL *Tail;\r
233 CHAR8 *NewPage;\r
234 VOID *Buffer;\r
235 UINTN Index;\r
236 UINTN FSize;\r
162ed594 237 UINTN Offset;\r
28a00297 238 UINTN Adjustment;\r
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
246 \r
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
252 ALIGN_VARIABLE (Size, Adjustment);\r
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
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
321 \r
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
334 DEBUG (\r
162ed594 335 (DEBUG_POOL,\r
88c8f7fb 336 "AllocatePoolI: Type %x, Addr %x (len %x) %,d\n",\r
28a00297 337 PoolType, \r
338 Buffer, \r
339 Size - POOL_OVERHEAD, \r
340 Pool->Used)\r
341 );\r
342\r
343 //\r
344 // Account the allocation\r
345 //\r
346 Pool->Used += Size;\r
347\r
348 } else {\r
162ed594 349 DEBUG ((DEBUG_ERROR | DEBUG_POOL, "AllocatePool: failed to allocate %d bytes\n", Size));\r
28a00297 350 }\r
351\r
352 return Buffer;\r
353}\r
354 \r
355\r
356\r
28a00297 357\r
162ed594 358/**\r
28a00297 359 Frees pool.\r
360\r
162ed594 361 @param Buffer The allocated pool entry to free \r
28a00297 362\r
162ed594 363 @retval EFI_INVALID_PARAMETER Buffer is not a valid value. \r
364 @retval EFI_SUCCESS Pool successfully freed.\r
28a00297 365\r
162ed594 366**/\r
367EFI_STATUS\r
368EFIAPI\r
369CoreFreePool (\r
370 IN VOID *Buffer\r
371 )\r
28a00297 372{\r
373 EFI_STATUS Status;\r
374\r
375 if (NULL == Buffer) {\r
376 return EFI_INVALID_PARAMETER;\r
377 }\r
378\r
379 CoreAcquireMemoryLock ();\r
380 Status = CoreFreePoolI (Buffer);\r
381 CoreReleaseMemoryLock ();\r
382 return Status;\r
383}\r
384\r
385\r
28a00297 386\r
162ed594 387/**\r
28a00297 388 Internal function to free a pool entry.\r
28a00297 389 Caller must have the memory lock held\r
390\r
162ed594 391 @param Buffer The allocated pool entry to free \r
28a00297 392\r
162ed594 393 @retval EFI_INVALID_PARAMETER Buffer not valid \r
394 @retval EFI_SUCCESS Buffer successfully freed.\r
28a00297 395\r
162ed594 396**/\r
397EFI_STATUS\r
398CoreFreePoolI (\r
399 IN VOID *Buffer\r
400 )\r
28a00297 401{\r
402 POOL *Pool;\r
403 POOL_HEAD *Head;\r
404 POOL_TAIL *Tail;\r
405 POOL_FREE *Free;\r
406 UINTN Index;\r
407 UINTN NoPages;\r
408 UINTN Size;\r
409 CHAR8 *NewPage;\r
410 UINTN FSize;\r
162ed594 411 UINTN Offset;\r
28a00297 412 BOOLEAN AllFree;\r
413\r
414 ASSERT(NULL != Buffer);\r
415 //\r
416 // Get the head & tail of the pool entry\r
417 //\r
418 Head = CR (Buffer, POOL_HEAD, Data, POOL_HEAD_SIGNATURE);\r
419 ASSERT(NULL != Head);\r
420\r
421 if (Head->Signature != POOL_HEAD_SIGNATURE) {\r
422 return EFI_INVALID_PARAMETER;\r
423 }\r
424\r
425 Tail = HEAD_TO_TAIL (Head);\r
426 ASSERT(NULL != Tail);\r
427\r
428 //\r
429 // Debug\r
430 //\r
431 ASSERT (Tail->Signature == POOL_TAIL_SIGNATURE);\r
432 ASSERT (Head->Size == Tail->Size);\r
433 ASSERT_LOCKED (&gMemoryLock);\r
434\r
435 if (Tail->Signature != POOL_TAIL_SIGNATURE) {\r
436 return EFI_INVALID_PARAMETER;\r
437 }\r
438\r
439 if (Head->Size != Tail->Size) {\r
440 return EFI_INVALID_PARAMETER;\r
441 }\r
442\r
443 //\r
444 // Determine the pool type and account for it\r
445 //\r
446 Size = Head->Size;\r
447 Pool = LookupPoolHead (Head->Type);\r
448 if (Pool == NULL) {\r
449 return EFI_INVALID_PARAMETER;\r
450 }\r
451 Pool->Used -= Size;\r
162ed594 452 DEBUG ((DEBUG_POOL, "FreePool: %x (len %x) %,d\n", Head->Data, Head->Size - POOL_OVERHEAD, Pool->Used));\r
28a00297 453\r
454 //\r
455 // Determine the pool list \r
456 //\r
457 Index = SIZE_TO_LIST(Size);\r
458 DEBUG_CLEAR_MEMORY (Head, Size);\r
459\r
460 //\r
461 // If it's not on the list, it must be pool pages\r
462 //\r
463 if (Index >= MAX_POOL_LIST) {\r
464\r
465 //\r
466 // Return the memory pages back to free memory\r
467 //\r
468 NoPages = EFI_SIZE_TO_PAGES(Size) + EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1;\r
469 NoPages &= ~(EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1);\r
470 CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS) (UINTN) Head, NoPages);\r
471\r
472 } else {\r
473\r
474 //\r
475 // Put the pool entry onto the free pool list\r
476 //\r
477 Free = (POOL_FREE *) Head;\r
478 ASSERT(NULL != Free);\r
479 Free->Signature = POOL_FREE_SIGNATURE;\r
480 Free->Index = (UINT32)Index;\r
481 InsertHeadList (&Pool->FreeList[Index], &Free->Link);\r
482\r
483 //\r
484 // See if all the pool entries in the same page as Free are freed pool \r
485 // entries\r
486 //\r
487 NewPage = (CHAR8 *)((UINTN)Free & ~((DEFAULT_PAGE_ALLOCATION) -1));\r
488 Free = (POOL_FREE *) &NewPage[0];\r
489 ASSERT(NULL != Free);\r
490\r
491 if (Free->Signature == POOL_FREE_SIGNATURE) {\r
492\r
493 Index = Free->Index;\r
494\r
495 AllFree = TRUE;\r
162ed594 496 Offset = 0;\r
28a00297 497 \r
162ed594 498 while ((Offset < DEFAULT_PAGE_ALLOCATION) && (AllFree)) {\r
28a00297 499 FSize = LIST_TO_SIZE(Index);\r
162ed594 500 while (Offset + FSize <= DEFAULT_PAGE_ALLOCATION) {\r
501 Free = (POOL_FREE *) &NewPage[Offset];\r
28a00297 502 ASSERT(NULL != Free);\r
503 if (Free->Signature != POOL_FREE_SIGNATURE) {\r
504 AllFree = FALSE;\r
505 }\r
162ed594 506 Offset += FSize;\r
28a00297 507 }\r
508 Index -= 1;\r
509 }\r
510\r
511 if (AllFree) {\r
512\r
513 //\r
514 // All of the pool entries in the same page as Free are free pool \r
515 // entries\r
516 // Remove all of these pool entries from the free loop lists.\r
517 //\r
518 Free = (POOL_FREE *) &NewPage[0];\r
519 ASSERT(NULL != Free);\r
520 Index = Free->Index;\r
162ed594 521 Offset = 0;\r
28a00297 522 \r
162ed594 523 while (Offset < DEFAULT_PAGE_ALLOCATION) {\r
28a00297 524 FSize = LIST_TO_SIZE(Index);\r
162ed594 525 while (Offset + FSize <= DEFAULT_PAGE_ALLOCATION) {\r
526 Free = (POOL_FREE *) &NewPage[Offset];\r
28a00297 527 ASSERT(NULL != Free);\r
528 RemoveEntryList (&Free->Link);\r
162ed594 529 Offset += FSize;\r
28a00297 530 }\r
531 Index -= 1;\r
532 }\r
533\r
534 //\r
535 // Free the page\r
536 //\r
537 CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS) (UINTN)NewPage, EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION));\r
538 }\r
539 }\r
540 }\r
541\r
542 //\r
543 // If this is an OS specific memory type, then check to see if the last \r
544 // portion of that memory type has been freed. If it has, then free the\r
545 // list entry for that memory type\r
546 //\r
547 if (Pool->MemoryType < 0 && Pool->Used == 0) {\r
548 RemoveEntryList (&Pool->Link);\r
549 CoreFreePoolI (Pool);\r
550 }\r
551\r
552 return EFI_SUCCESS;\r
553}\r