]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Core/Dxe/Mem/Pool.c
1) Add type cast for better coding style.
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Mem / Pool.c
... / ...
CommitLineData
1/** @file\r
2 UEFI Memory pool management functions.\r
3\r
4Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>\r
5This 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
12\r
13**/\r
14\r
15#include "DxeMain.h"\r
16#include "Imem.h"\r
17\r
18#define POOL_FREE_SIGNATURE 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 SIGNATURE_32('p','h','d','0')\r
27typedef struct {\r
28 UINT32 Signature;\r
29 UINT32 Reserved;\r
30 EFI_MEMORY_TYPE Type;\r
31 UINTN Size;\r
32 CHAR8 Data[1];\r
33} POOL_HEAD;\r
34\r
35#define SIZE_OF_POOL_HEAD OFFSET_OF(POOL_HEAD,Data)\r
36\r
37#define POOL_TAIL_SIGNATURE SIGNATURE_32('p','t','a','l')\r
38typedef struct {\r
39 UINT32 Signature;\r
40 UINT32 Reserved;\r
41 UINTN Size;\r
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
64#define POOL_SIGNATURE SIGNATURE_32('p','l','s','t')\r
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
71} POOL;\r
72\r
73//\r
74// Pool header for each memory type.\r
75//\r
76POOL mPoolHead[EfiMaxMemoryType];\r
77\r
78//\r
79// List of pool header to search for the appropriate memory type.\r
80//\r
81LIST_ENTRY mPoolHeadList = INITIALIZE_LIST_HEAD_VARIABLE (mPoolHeadList);\r
82\r
83\r
84/**\r
85 Called to initialize the pool.\r
86\r
87**/\r
88VOID\r
89CoreInitializePool (\r
90 VOID\r
91 )\r
92{\r
93 UINTN Type;\r
94 UINTN Index;\r
95\r
96 for (Type=0; Type < EfiMaxMemoryType; Type++) {\r
97 mPoolHead[Type].Signature = 0;\r
98 mPoolHead[Type].Used = 0;\r
99 mPoolHead[Type].MemoryType = (EFI_MEMORY_TYPE) Type;\r
100 for (Index=0; Index < MAX_POOL_LIST; Index++) {\r
101 InitializeListHead (&mPoolHead[Type].FreeList[Index]);\r
102 }\r
103 }\r
104}\r
105\r
106\r
107/**\r
108 Look up pool head for specified memory type.\r
109\r
110 @param MemoryType Memory type of which pool head is looked for\r
111\r
112 @return Pointer of Corresponding pool head.\r
113\r
114**/\r
115POOL *\r
116LookupPoolHead (\r
117 IN EFI_MEMORY_TYPE MemoryType\r
118 )\r
119{\r
120 LIST_ENTRY *Link;\r
121 POOL *Pool;\r
122 UINTN Index;\r
123\r
124 if ((UINT32)MemoryType < EfiMaxMemoryType) {\r
125 return &mPoolHead[MemoryType];\r
126 }\r
127\r
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
132 if ((INT32)MemoryType < 0) {\r
133\r
134 for (Link = mPoolHeadList.ForwardLink; Link != &mPoolHeadList; Link = Link->ForwardLink) {\r
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
153 InsertHeadList (&mPoolHeadList, &Pool->Link);\r
154\r
155 return Pool;\r
156 }\r
157\r
158 return NULL;\r
159}\r
160\r
161\r
162\r
163/**\r
164 Allocate pool of a particular type.\r
165\r
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
170\r
171 @retval EFI_INVALID_PARAMETER PoolType not valid or Buffer is NULL. \r
172 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.\r
173 @retval EFI_SUCCESS Pool successfully allocated.\r
174\r
175**/\r
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
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
193\r
194 if (Buffer == NULL) {\r
195 return EFI_INVALID_PARAMETER;\r
196 }\r
197\r
198 *Buffer = NULL;\r
199\r
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
222\r
223/**\r
224 Internal function to allocate pool of a particular type.\r
225 Caller must have the memory lock held\r
226\r
227 @param PoolType Type of pool to allocate\r
228 @param Size The amount of pool to allocate\r
229\r
230 @return The allocate pool, or NULL\r
231\r
232**/\r
233VOID *\r
234CoreAllocatePoolI (\r
235 IN EFI_MEMORY_TYPE PoolType,\r
236 IN UINTN Size\r
237 )\r
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
247 UINTN Offset;\r
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
255\r
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
261 Size = ALIGN_VARIABLE (Size);\r
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 &= ~(UINTN)(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
298 Offset = 0;\r
299 while (Offset < DEFAULT_PAGE_ALLOCATION) {\r
300 ASSERT (Index < MAX_POOL_LIST);\r
301 FSize = LIST_TO_SIZE(Index);\r
302\r
303 while (Offset + FSize <= DEFAULT_PAGE_ALLOCATION) {\r
304 Free = (POOL_FREE *) &NewPage[Offset];\r
305 Free->Signature = POOL_FREE_SIGNATURE;\r
306 Free->Index = (UINT32)Index;\r
307 InsertHeadList (&Pool->FreeList[Index], &Free->Link);\r
308 Offset += FSize;\r
309 }\r
310\r
311 Index -= 1;\r
312 }\r
313\r
314 ASSERT (Offset == DEFAULT_PAGE_ALLOCATION);\r
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
330\r
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
335 Head->Size = Size;\r
336 Head->Type = (EFI_MEMORY_TYPE) PoolType;\r
337 Tail = HEAD_TO_TAIL (Head);\r
338 Tail->Signature = POOL_TAIL_SIGNATURE;\r
339 Tail->Size = Size;\r
340 Buffer = Head->Data;\r
341 DEBUG_CLEAR_MEMORY (Buffer, Size - POOL_OVERHEAD);\r
342\r
343 DEBUG ((\r
344 DEBUG_POOL,\r
345 "AllocatePoolI: Type %x, Addr %p (len %lx) %,ld\n", PoolType,\r
346 Buffer,\r
347 (UINT64)(Size - POOL_OVERHEAD),\r
348 (UINT64) Pool->Used\r
349 ));\r
350\r
351 //\r
352 // Account the allocation\r
353 //\r
354 Pool->Used += Size;\r
355\r
356 } else {\r
357 DEBUG ((DEBUG_ERROR | DEBUG_POOL, "AllocatePool: failed to allocate %ld bytes\n", (UINT64) Size));\r
358 }\r
359\r
360 return Buffer;\r
361}\r
362\r
363\r
364\r
365/**\r
366 Frees pool.\r
367\r
368 @param Buffer The allocated pool entry to free\r
369\r
370 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.\r
371 @retval EFI_SUCCESS Pool successfully freed.\r
372\r
373**/\r
374EFI_STATUS\r
375EFIAPI\r
376CoreFreePool (\r
377 IN VOID *Buffer\r
378 )\r
379{\r
380 EFI_STATUS Status;\r
381\r
382 if (Buffer == NULL) {\r
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
393\r
394/**\r
395 Internal function to free a pool entry.\r
396 Caller must have the memory lock held\r
397\r
398 @param Buffer The allocated pool entry to free\r
399\r
400 @retval EFI_INVALID_PARAMETER Buffer not valid\r
401 @retval EFI_SUCCESS Buffer successfully freed.\r
402\r
403**/\r
404EFI_STATUS\r
405CoreFreePoolI (\r
406 IN VOID *Buffer\r
407 )\r
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
418 UINTN Offset;\r
419 BOOLEAN AllFree;\r
420\r
421 ASSERT(Buffer != NULL);\r
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
426 ASSERT(Head != NULL);\r
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
433 ASSERT(Tail != NULL);\r
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
459 DEBUG ((DEBUG_POOL, "FreePool: %p (len %lx) %,ld\n", Head->Data, (UINT64)(Head->Size - POOL_OVERHEAD), (UINT64) Pool->Used));\r
460\r
461 //\r
462 // Determine the pool list\r
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 &= ~(UINTN)(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
485 ASSERT(Free != NULL);\r
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
491 // See if all the pool entries in the same page as Free are freed pool\r
492 // entries\r
493 //\r
494 NewPage = (CHAR8 *)((UINTN)Free & ~((DEFAULT_PAGE_ALLOCATION) -1));\r
495 Free = (POOL_FREE *) &NewPage[0];\r
496 ASSERT(Free != NULL);\r
497\r
498 if (Free->Signature == POOL_FREE_SIGNATURE) {\r
499\r
500 Index = Free->Index;\r
501\r
502 AllFree = TRUE;\r
503 Offset = 0;\r
504\r
505 while ((Offset < DEFAULT_PAGE_ALLOCATION) && (AllFree)) {\r
506 FSize = LIST_TO_SIZE(Index);\r
507 while (Offset + FSize <= DEFAULT_PAGE_ALLOCATION) {\r
508 Free = (POOL_FREE *) &NewPage[Offset];\r
509 ASSERT(Free != NULL);\r
510 if (Free->Signature != POOL_FREE_SIGNATURE) {\r
511 AllFree = FALSE;\r
512 }\r
513 Offset += FSize;\r
514 }\r
515 Index -= 1;\r
516 }\r
517\r
518 if (AllFree) {\r
519\r
520 //\r
521 // All of the pool entries in the same page as Free are free pool\r
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
526 ASSERT(Free != NULL);\r
527 Index = Free->Index;\r
528 Offset = 0;\r
529\r
530 while (Offset < DEFAULT_PAGE_ALLOCATION) {\r
531 FSize = LIST_TO_SIZE(Index);\r
532 while (Offset + FSize <= DEFAULT_PAGE_ALLOCATION) {\r
533 Free = (POOL_FREE *) &NewPage[Offset];\r
534 ASSERT(Free != NULL);\r
535 RemoveEntryList (&Free->Link);\r
536 Offset += FSize;\r
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
550 // If this is an OS specific memory type, then check to see if the last\r
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
554 if ((INT32)Pool->MemoryType < 0 && Pool->Used == 0) {\r
555 RemoveEntryList (&Pool->Link);\r
556 CoreFreePoolI (Pool);\r
557 }\r
558\r
559 return EFI_SUCCESS;\r
560}\r