]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/Dxe/Mem/pool.c
Add comments and DoxyGen format for these files.
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Mem / pool.c
CommitLineData
504214c4 1/** @file \r
28a00297 2\r
504214c4
LG
3 UEFI Memory pool management functions.\r
4\r
5Copyright (c) 2006 - 2008, Intel Corporation \r
28a00297 6All rights reserved. This program and the accompanying materials \r
7are licensed and made available under the terms and conditions of the BSD License \r
8which accompanies this distribution. The full text of the license may be found at \r
9http://opensource.org/licenses/bsd-license.php \r
10 \r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
13\r
504214c4 14**/\r
28a00297 15\r
16#include <DxeMain.h>\r
17\r
18#define POOL_FREE_SIGNATURE EFI_SIGNATURE_32('p','f','r','0')\r
19typedef struct {\r
20 UINT32 Signature;\r
21 UINT32 Index;\r
22 LIST_ENTRY Link;\r
23} POOL_FREE;\r
24\r
25\r
26#define POOL_HEAD_SIGNATURE EFI_SIGNATURE_32('p','h','d','0')\r
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
35#define SIZE_OF_POOL_HEAD EFI_FIELD_OFFSET(POOL_HEAD,Data)\r
36\r
37#define POOL_TAIL_SIGNATURE EFI_SIGNATURE_32('p','t','a','l')\r
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
63#define POOL_SIGNATURE EFI_SIGNATURE_32('p','l','s','t')\r
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
70} POOL; \r
71\r
72\r
73POOL PoolHead[EfiMaxMemoryType];\r
74LIST_ENTRY PoolHeadList;\r
75\r
76//\r
77//\r
78//\r
79\r
80VOID\r
81CoreInitializePool (\r
82 VOID\r
83 )\r
84/*++\r
85\r
86Routine Description:\r
87\r
88 Called to initialize the pool.\r
89\r
90Arguments:\r
91\r
92 None\r
93\r
94Returns:\r
95\r
96 None\r
97\r
98--*/\r
99{\r
100 UINTN Type;\r
101 UINTN Index;\r
102\r
103 for (Type=0; Type < EfiMaxMemoryType; Type++) {\r
104 PoolHead[Type].Signature = 0;\r
105 PoolHead[Type].Used = 0;\r
106 PoolHead[Type].MemoryType = (EFI_MEMORY_TYPE) Type;\r
107 for (Index=0; Index < MAX_POOL_LIST; Index++) {\r
108 InitializeListHead (&PoolHead[Type].FreeList[Index]);\r
109 }\r
110 }\r
111 InitializeListHead (&PoolHeadList);\r
112}\r
113\r
114STATIC\r
115POOL *\r
116LookupPoolHead (\r
117 IN EFI_MEMORY_TYPE MemoryType\r
118 )\r
119/*++\r
120\r
121Routine Description:\r
122\r
123 Look up pool head for specified memory type.\r
124\r
125Arguments:\r
126\r
127 MemoryType - Memory type of which pool head is looked for\r
128\r
129Returns:\r
130\r
131 Pointer of Corresponding pool head.\r
132\r
133--*/\r
134{\r
135 LIST_ENTRY *Link;\r
136 POOL *Pool;\r
137 UINTN Index;\r
138\r
139 if (MemoryType >= 0 && MemoryType < EfiMaxMemoryType) {\r
140 return &PoolHead[MemoryType];\r
141 }\r
142\r
143 if (MemoryType < 0) {\r
144\r
145 for (Link = PoolHeadList.ForwardLink; Link != &PoolHeadList; Link = Link->ForwardLink) {\r
146 Pool = CR(Link, POOL, Link, POOL_SIGNATURE);\r
147 if (Pool->MemoryType == MemoryType) {\r
148 return Pool;\r
149 }\r
150 }\r
151\r
152 Pool = CoreAllocatePoolI (EfiBootServicesData, sizeof (POOL));\r
153 if (Pool == NULL) {\r
154 return NULL;\r
155 }\r
156\r
157 Pool->Signature = POOL_SIGNATURE;\r
158 Pool->Used = 0;\r
159 Pool->MemoryType = MemoryType;\r
160 for (Index=0; Index < MAX_POOL_LIST; Index++) {\r
161 InitializeListHead (&Pool->FreeList[Index]);\r
162 }\r
163\r
164 InsertHeadList (&PoolHeadList, &Pool->Link);\r
165\r
166 return Pool;\r
167 }\r
168\r
169 return NULL;\r
170}\r
171\r
172 \r
173\r
174EFI_STATUS\r
175EFIAPI\r
176CoreAllocatePool (\r
177 IN EFI_MEMORY_TYPE PoolType,\r
178 IN UINTN Size,\r
179 OUT VOID **Buffer\r
180 )\r
181/*++\r
182\r
183Routine Description:\r
184\r
185 Allocate pool of a particular type.\r
186\r
187Arguments:\r
188\r
189 PoolType - Type of pool to allocate\r
190\r
191 Size - The amount of pool to allocate\r
192\r
193 Buffer - The address to return a pointer to the allocated pool\r
194\r
195Returns:\r
196\r
197 EFI_INVALID_PARAMETER - PoolType not valid\r
198 \r
199 EFI_OUT_OF_RESOURCES - Size exceeds max pool size or allocation failed. \r
200 \r
201 EFI_SUCCESS - Pool successfully allocated.\r
202\r
203--*/\r
204{\r
205 EFI_STATUS Status;\r
206\r
207 //\r
208 // If it's not a valid type, fail it\r
209 //\r
210 if ((PoolType >= EfiMaxMemoryType && PoolType <= 0x7fffffff) ||\r
211 PoolType == EfiConventionalMemory) {\r
212 return EFI_INVALID_PARAMETER;\r
213 }\r
214 \r
215 *Buffer = NULL;\r
216 \r
217 //\r
218 // If size is too large, fail it\r
219 // Base on the EFI spec, return status of EFI_OUT_OF_RESOURCES\r
220 //\r
221 if (Size > MAX_POOL_SIZE) {\r
222 return EFI_OUT_OF_RESOURCES;\r
223 }\r
224\r
225 //\r
226 // Acquire the memory lock and make the allocation\r
227 //\r
228 Status = CoreAcquireLockOrFail (&gMemoryLock);\r
229 if (EFI_ERROR (Status)) {\r
230 return EFI_OUT_OF_RESOURCES;\r
231 }\r
232\r
233 *Buffer = CoreAllocatePoolI (PoolType, Size);\r
234 CoreReleaseMemoryLock ();\r
235 return (*Buffer != NULL) ? EFI_SUCCESS : EFI_OUT_OF_RESOURCES;\r
236}\r
237\r
238\r
239VOID *\r
240CoreAllocatePoolI (\r
241 IN EFI_MEMORY_TYPE PoolType,\r
242 IN UINTN Size\r
243 )\r
244/*++\r
245\r
246Routine Description:\r
247\r
248 Internal function to allocate pool of a particular type.\r
249\r
250 Caller must have the memory lock held\r
251\r
252\r
253Arguments:\r
254\r
255 PoolType - Type of pool to allocate\r
256\r
257 Size - The amount of pool to allocate\r
258\r
259Returns:\r
260\r
261 The allocate pool, or NULL\r
262\r
263--*/\r
264{\r
265 POOL *Pool;\r
266 POOL_FREE *Free;\r
267 POOL_HEAD *Head;\r
268 POOL_TAIL *Tail;\r
269 CHAR8 *NewPage;\r
270 VOID *Buffer;\r
271 UINTN Index;\r
272 UINTN FSize;\r
273 UINTN offset;\r
274 UINTN Adjustment;\r
275 UINTN NoPages;\r
276\r
277 ASSERT_LOCKED (&gMemoryLock);\r
278\r
279 //\r
280 // Adjust the size by the pool header & tail overhead\r
281 //\r
282 \r
283 //\r
284 // Adjusting the Size to be of proper alignment so that\r
285 // we don't get an unaligned access fault later when\r
286 // pool_Tail is being initialized\r
287 //\r
288 ALIGN_VARIABLE (Size, Adjustment);\r
289\r
290 Size += POOL_OVERHEAD;\r
291 Index = SIZE_TO_LIST(Size);\r
292 Pool = LookupPoolHead (PoolType);\r
293 if (Pool== NULL) {\r
294 return NULL;\r
295 }\r
296 Head = NULL;\r
297\r
298 //\r
299 // If allocation is over max size, just allocate pages for the request\r
300 // (slow)\r
301 //\r
302 if (Index >= MAX_POOL_LIST) {\r
303 NoPages = EFI_SIZE_TO_PAGES(Size) + EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1;\r
304 NoPages &= ~(EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1);\r
305 Head = CoreAllocatePoolPages (PoolType, NoPages, DEFAULT_PAGE_ALLOCATION);\r
306 goto Done;\r
307 }\r
308\r
309 //\r
310 // If there's no free pool in the proper list size, go get some more pages\r
311 //\r
312 if (IsListEmpty (&Pool->FreeList[Index])) {\r
313\r
314 //\r
315 // Get another page\r
316 //\r
317 NewPage = CoreAllocatePoolPages(PoolType, EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION), DEFAULT_PAGE_ALLOCATION);\r
318 if (NewPage == NULL) {\r
319 goto Done;\r
320 }\r
321\r
322 //\r
323 // Carve up new page into free pool blocks\r
324 //\r
325 offset = 0;\r
326 while (offset < DEFAULT_PAGE_ALLOCATION) {\r
327 ASSERT (Index < MAX_POOL_LIST);\r
328 FSize = LIST_TO_SIZE(Index);\r
329\r
330 while (offset + FSize <= DEFAULT_PAGE_ALLOCATION) {\r
331 Free = (POOL_FREE *) &NewPage[offset]; \r
332 Free->Signature = POOL_FREE_SIGNATURE;\r
333 Free->Index = (UINT32)Index;\r
334 InsertHeadList (&Pool->FreeList[Index], &Free->Link);\r
335 offset += FSize;\r
336 }\r
337\r
338 Index -= 1;\r
339 }\r
340\r
341 ASSERT (offset == DEFAULT_PAGE_ALLOCATION);\r
342 Index = SIZE_TO_LIST(Size);\r
343 }\r
344\r
345 //\r
346 // Remove entry from free pool list\r
347 //\r
348 Free = CR (Pool->FreeList[Index].ForwardLink, POOL_FREE, Link, POOL_FREE_SIGNATURE);\r
349 RemoveEntryList (&Free->Link);\r
350\r
351 Head = (POOL_HEAD *) Free;\r
352\r
353Done:\r
354 Buffer = NULL;\r
355\r
356 if (Head != NULL) {\r
357 \r
358 //\r
359 // If we have a pool buffer, fill in the header & tail info\r
360 //\r
361 Head->Signature = POOL_HEAD_SIGNATURE;\r
362 Head->Size = (UINT32) Size;\r
363 Head->Type = (EFI_MEMORY_TYPE) PoolType;\r
364 Tail = HEAD_TO_TAIL (Head);\r
365 Tail->Signature = POOL_TAIL_SIGNATURE;\r
366 Tail->Size = (UINT32) Size;\r
367 Buffer = Head->Data;\r
368 DEBUG_CLEAR_MEMORY (Buffer, Size - POOL_OVERHEAD);\r
369\r
370 DEBUG (\r
371 (EFI_D_POOL,\r
88c8f7fb 372 "AllocatePoolI: Type %x, Addr %x (len %x) %,d\n",\r
28a00297 373 PoolType, \r
374 Buffer, \r
375 Size - POOL_OVERHEAD, \r
376 Pool->Used)\r
377 );\r
378\r
379 //\r
380 // Account the allocation\r
381 //\r
382 Pool->Used += Size;\r
383\r
384 } else {\r
385 DEBUG ((EFI_D_ERROR | EFI_D_POOL, "AllocatePool: failed to allocate %d bytes\n", Size));\r
386 }\r
387\r
388 return Buffer;\r
389}\r
390 \r
391\r
392\r
393EFI_STATUS\r
394EFIAPI\r
395CoreFreePool (\r
396 IN VOID *Buffer\r
397 )\r
398/*++\r
399\r
400Routine Description:\r
401\r
402 Frees pool.\r
403\r
404Arguments:\r
405\r
406 Buffer - The allocated pool entry to free\r
407\r
408Returns:\r
409\r
410 EFI_INVALID_PARAMETER - Buffer is not a valid value.\r
411 \r
412 EFI_SUCCESS - Pool successfully freed.\r
413\r
414--*/\r
415{\r
416 EFI_STATUS Status;\r
417\r
418 if (NULL == Buffer) {\r
419 return EFI_INVALID_PARAMETER;\r
420 }\r
421\r
422 CoreAcquireMemoryLock ();\r
423 Status = CoreFreePoolI (Buffer);\r
424 CoreReleaseMemoryLock ();\r
425 return Status;\r
426}\r
427\r
428\r
429EFI_STATUS\r
430CoreFreePoolI (\r
431 IN VOID *Buffer\r
432 )\r
433/*++\r
434\r
435Routine Description:\r
436\r
437 Internal function to free a pool entry.\r
438\r
439 Caller must have the memory lock held\r
440\r
441\r
442Arguments:\r
443\r
444 Buffer - The allocated pool entry to free\r
445\r
446Returns:\r
447\r
448 EFI_INVALID_PARAMETER - Buffer not valid\r
449 \r
450 EFI_SUCCESS - Buffer successfully freed.\r
451\r
452--*/\r
453{\r
454 POOL *Pool;\r
455 POOL_HEAD *Head;\r
456 POOL_TAIL *Tail;\r
457 POOL_FREE *Free;\r
458 UINTN Index;\r
459 UINTN NoPages;\r
460 UINTN Size;\r
461 CHAR8 *NewPage;\r
462 UINTN FSize;\r
463 UINTN offset;\r
464 BOOLEAN AllFree;\r
465\r
466 ASSERT(NULL != Buffer);\r
467 //\r
468 // Get the head & tail of the pool entry\r
469 //\r
470 Head = CR (Buffer, POOL_HEAD, Data, POOL_HEAD_SIGNATURE);\r
471 ASSERT(NULL != Head);\r
472\r
473 if (Head->Signature != POOL_HEAD_SIGNATURE) {\r
474 return EFI_INVALID_PARAMETER;\r
475 }\r
476\r
477 Tail = HEAD_TO_TAIL (Head);\r
478 ASSERT(NULL != Tail);\r
479\r
480 //\r
481 // Debug\r
482 //\r
483 ASSERT (Tail->Signature == POOL_TAIL_SIGNATURE);\r
484 ASSERT (Head->Size == Tail->Size);\r
485 ASSERT_LOCKED (&gMemoryLock);\r
486\r
487 if (Tail->Signature != POOL_TAIL_SIGNATURE) {\r
488 return EFI_INVALID_PARAMETER;\r
489 }\r
490\r
491 if (Head->Size != Tail->Size) {\r
492 return EFI_INVALID_PARAMETER;\r
493 }\r
494\r
495 //\r
496 // Determine the pool type and account for it\r
497 //\r
498 Size = Head->Size;\r
499 Pool = LookupPoolHead (Head->Type);\r
500 if (Pool == NULL) {\r
501 return EFI_INVALID_PARAMETER;\r
502 }\r
503 Pool->Used -= Size;\r
504 DEBUG ((EFI_D_POOL, "FreePool: %x (len %x) %,d\n", Head->Data, Head->Size - POOL_OVERHEAD, Pool->Used));\r
505\r
506 //\r
507 // Determine the pool list \r
508 //\r
509 Index = SIZE_TO_LIST(Size);\r
510 DEBUG_CLEAR_MEMORY (Head, Size);\r
511\r
512 //\r
513 // If it's not on the list, it must be pool pages\r
514 //\r
515 if (Index >= MAX_POOL_LIST) {\r
516\r
517 //\r
518 // Return the memory pages back to free memory\r
519 //\r
520 NoPages = EFI_SIZE_TO_PAGES(Size) + EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1;\r
521 NoPages &= ~(EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1);\r
522 CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS) (UINTN) Head, NoPages);\r
523\r
524 } else {\r
525\r
526 //\r
527 // Put the pool entry onto the free pool list\r
528 //\r
529 Free = (POOL_FREE *) Head;\r
530 ASSERT(NULL != Free);\r
531 Free->Signature = POOL_FREE_SIGNATURE;\r
532 Free->Index = (UINT32)Index;\r
533 InsertHeadList (&Pool->FreeList[Index], &Free->Link);\r
534\r
535 //\r
536 // See if all the pool entries in the same page as Free are freed pool \r
537 // entries\r
538 //\r
539 NewPage = (CHAR8 *)((UINTN)Free & ~((DEFAULT_PAGE_ALLOCATION) -1));\r
540 Free = (POOL_FREE *) &NewPage[0];\r
541 ASSERT(NULL != Free);\r
542\r
543 if (Free->Signature == POOL_FREE_SIGNATURE) {\r
544\r
545 Index = Free->Index;\r
546\r
547 AllFree = TRUE;\r
548 offset = 0;\r
549 \r
550 while ((offset < DEFAULT_PAGE_ALLOCATION) && (AllFree)) {\r
551 FSize = LIST_TO_SIZE(Index);\r
552 while (offset + FSize <= DEFAULT_PAGE_ALLOCATION) {\r
553 Free = (POOL_FREE *) &NewPage[offset];\r
554 ASSERT(NULL != Free);\r
555 if (Free->Signature != POOL_FREE_SIGNATURE) {\r
556 AllFree = FALSE;\r
557 }\r
558 offset += FSize;\r
559 }\r
560 Index -= 1;\r
561 }\r
562\r
563 if (AllFree) {\r
564\r
565 //\r
566 // All of the pool entries in the same page as Free are free pool \r
567 // entries\r
568 // Remove all of these pool entries from the free loop lists.\r
569 //\r
570 Free = (POOL_FREE *) &NewPage[0];\r
571 ASSERT(NULL != Free);\r
572 Index = Free->Index;\r
573 offset = 0;\r
574 \r
575 while (offset < DEFAULT_PAGE_ALLOCATION) {\r
576 FSize = LIST_TO_SIZE(Index);\r
577 while (offset + FSize <= DEFAULT_PAGE_ALLOCATION) {\r
578 Free = (POOL_FREE *) &NewPage[offset];\r
579 ASSERT(NULL != Free);\r
580 RemoveEntryList (&Free->Link);\r
581 offset += FSize;\r
582 }\r
583 Index -= 1;\r
584 }\r
585\r
586 //\r
587 // Free the page\r
588 //\r
589 CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS) (UINTN)NewPage, EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION));\r
590 }\r
591 }\r
592 }\r
593\r
594 //\r
595 // If this is an OS specific memory type, then check to see if the last \r
596 // portion of that memory type has been freed. If it has, then free the\r
597 // list entry for that memory type\r
598 //\r
599 if (Pool->MemoryType < 0 && Pool->Used == 0) {\r
600 RemoveEntryList (&Pool->Link);\r
601 CoreFreePoolI (Pool);\r
602 }\r
603\r
604 return EFI_SUCCESS;\r
605}\r