]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/Dxe/Mem/Pool.c
Don't align image address for TeImage, because TeImage section alignment is undefined.
[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
57b4ecb9 79LIST_ENTRY mPoolHeadList = INITIALIZE_LIST_HEAD_VARIABLE (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
28a00297 102}\r
103\r
28a00297 104\r
162ed594 105/**\r
28a00297 106 Look up pool head for specified memory type.\r
107\r
022c6d45 108 @param MemoryType Memory type of which pool head is looked for\r
28a00297 109\r
162ed594 110 @return Pointer of Corresponding pool head.\r
28a00297 111\r
162ed594 112**/\r
162ed594 113POOL *\r
114LookupPoolHead (\r
115 IN EFI_MEMORY_TYPE MemoryType\r
116 )\r
28a00297 117{\r
118 LIST_ENTRY *Link;\r
119 POOL *Pool;\r
120 UINTN Index;\r
121\r
122 if (MemoryType >= 0 && MemoryType < EfiMaxMemoryType) {\r
e94a9ff7 123 return &mPoolHead[MemoryType];\r
28a00297 124 }\r
125\r
126 if (MemoryType < 0) {\r
127\r
e94a9ff7 128 for (Link = mPoolHeadList.ForwardLink; Link != &mPoolHeadList; Link = Link->ForwardLink) {\r
28a00297 129 Pool = CR(Link, POOL, Link, POOL_SIGNATURE);\r
130 if (Pool->MemoryType == MemoryType) {\r
131 return Pool;\r
132 }\r
133 }\r
134\r
135 Pool = CoreAllocatePoolI (EfiBootServicesData, sizeof (POOL));\r
136 if (Pool == NULL) {\r
137 return NULL;\r
138 }\r
139\r
140 Pool->Signature = POOL_SIGNATURE;\r
141 Pool->Used = 0;\r
142 Pool->MemoryType = MemoryType;\r
143 for (Index=0; Index < MAX_POOL_LIST; Index++) {\r
144 InitializeListHead (&Pool->FreeList[Index]);\r
145 }\r
146\r
e94a9ff7 147 InsertHeadList (&mPoolHeadList, &Pool->Link);\r
28a00297 148\r
149 return Pool;\r
150 }\r
151\r
152 return NULL;\r
153}\r
154\r
022c6d45 155\r
28a00297 156\r
162ed594 157/**\r
158 Allocate pool of a particular type.\r
159\r
022c6d45 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
162ed594 164\r
022c6d45 165 @retval EFI_INVALID_PARAMETER PoolType not valid\r
166 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.\r
162ed594 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
022c6d45 187\r
28a00297 188 *Buffer = NULL;\r
022c6d45 189\r
28a00297 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
022c6d45 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 NoPages;\r
239\r
240 ASSERT_LOCKED (&gMemoryLock);\r
241\r
242 //\r
243 // Adjust the size by the pool header & tail overhead\r
244 //\r
022c6d45 245\r
28a00297 246 //\r
247 // Adjusting the Size to be of proper alignment so that\r
248 // we don't get an unaligned access fault later when\r
249 // pool_Tail is being initialized\r
250 //\r
f0d5cbb6 251 Size = ALIGN_VARIABLE (Size);\r
28a00297 252\r
253 Size += POOL_OVERHEAD;\r
254 Index = SIZE_TO_LIST(Size);\r
255 Pool = LookupPoolHead (PoolType);\r
256 if (Pool== NULL) {\r
257 return NULL;\r
258 }\r
259 Head = NULL;\r
260\r
261 //\r
262 // If allocation is over max size, just allocate pages for the request\r
263 // (slow)\r
264 //\r
265 if (Index >= MAX_POOL_LIST) {\r
266 NoPages = EFI_SIZE_TO_PAGES(Size) + EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1;\r
267 NoPages &= ~(EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1);\r
268 Head = CoreAllocatePoolPages (PoolType, NoPages, DEFAULT_PAGE_ALLOCATION);\r
269 goto Done;\r
270 }\r
271\r
272 //\r
273 // If there's no free pool in the proper list size, go get some more pages\r
274 //\r
275 if (IsListEmpty (&Pool->FreeList[Index])) {\r
276\r
277 //\r
278 // Get another page\r
279 //\r
280 NewPage = CoreAllocatePoolPages(PoolType, EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION), DEFAULT_PAGE_ALLOCATION);\r
281 if (NewPage == NULL) {\r
282 goto Done;\r
283 }\r
284\r
285 //\r
286 // Carve up new page into free pool blocks\r
287 //\r
162ed594 288 Offset = 0;\r
289 while (Offset < DEFAULT_PAGE_ALLOCATION) {\r
28a00297 290 ASSERT (Index < MAX_POOL_LIST);\r
291 FSize = LIST_TO_SIZE(Index);\r
292\r
162ed594 293 while (Offset + FSize <= DEFAULT_PAGE_ALLOCATION) {\r
022c6d45 294 Free = (POOL_FREE *) &NewPage[Offset];\r
28a00297 295 Free->Signature = POOL_FREE_SIGNATURE;\r
296 Free->Index = (UINT32)Index;\r
297 InsertHeadList (&Pool->FreeList[Index], &Free->Link);\r
162ed594 298 Offset += FSize;\r
28a00297 299 }\r
300\r
301 Index -= 1;\r
302 }\r
303\r
162ed594 304 ASSERT (Offset == DEFAULT_PAGE_ALLOCATION);\r
28a00297 305 Index = SIZE_TO_LIST(Size);\r
306 }\r
307\r
308 //\r
309 // Remove entry from free pool list\r
310 //\r
311 Free = CR (Pool->FreeList[Index].ForwardLink, POOL_FREE, Link, POOL_FREE_SIGNATURE);\r
312 RemoveEntryList (&Free->Link);\r
313\r
314 Head = (POOL_HEAD *) Free;\r
315\r
316Done:\r
317 Buffer = NULL;\r
318\r
319 if (Head != NULL) {\r
022c6d45 320\r
28a00297 321 //\r
322 // If we have a pool buffer, fill in the header & tail info\r
323 //\r
324 Head->Signature = POOL_HEAD_SIGNATURE;\r
325 Head->Size = (UINT32) Size;\r
326 Head->Type = (EFI_MEMORY_TYPE) PoolType;\r
327 Tail = HEAD_TO_TAIL (Head);\r
328 Tail->Signature = POOL_TAIL_SIGNATURE;\r
329 Tail->Size = (UINT32) Size;\r
330 Buffer = Head->Data;\r
331 DEBUG_CLEAR_MEMORY (Buffer, Size - POOL_OVERHEAD);\r
332\r
e94a9ff7 333 DEBUG ((\r
334 DEBUG_POOL,\r
57b4ecb9 335 "AllocatePoolI: Type %x, Addr %p (len %lx) %,ld\n", PoolType,\r
022c6d45 336 Buffer,\r
57b4ecb9 337 (UINT64)(Size - POOL_OVERHEAD),\r
338 (UINT64) Pool->Used\r
e94a9ff7 339 ));\r
28a00297 340\r
341 //\r
342 // Account the allocation\r
343 //\r
344 Pool->Used += Size;\r
345\r
346 } else {\r
57b4ecb9 347 DEBUG ((DEBUG_ERROR | DEBUG_POOL, "AllocatePool: failed to allocate %ld bytes\n", (UINT64) Size));\r
28a00297 348 }\r
349\r
350 return Buffer;\r
351}\r
022c6d45 352\r
28a00297 353\r
354\r
162ed594 355/**\r
28a00297 356 Frees pool.\r
357\r
022c6d45 358 @param Buffer The allocated pool entry to free\r
28a00297 359\r
022c6d45 360 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.\r
162ed594 361 @retval EFI_SUCCESS Pool successfully freed.\r
28a00297 362\r
162ed594 363**/\r
364EFI_STATUS\r
365EFIAPI\r
366CoreFreePool (\r
367 IN VOID *Buffer\r
368 )\r
28a00297 369{\r
370 EFI_STATUS Status;\r
371\r
e94a9ff7 372 if (Buffer == NULL) {\r
28a00297 373 return EFI_INVALID_PARAMETER;\r
374 }\r
375\r
376 CoreAcquireMemoryLock ();\r
377 Status = CoreFreePoolI (Buffer);\r
378 CoreReleaseMemoryLock ();\r
379 return Status;\r
380}\r
381\r
382\r
28a00297 383\r
162ed594 384/**\r
28a00297 385 Internal function to free a pool entry.\r
28a00297 386 Caller must have the memory lock held\r
387\r
022c6d45 388 @param Buffer The allocated pool entry to free\r
28a00297 389\r
022c6d45 390 @retval EFI_INVALID_PARAMETER Buffer not valid\r
162ed594 391 @retval EFI_SUCCESS Buffer successfully freed.\r
28a00297 392\r
162ed594 393**/\r
394EFI_STATUS\r
395CoreFreePoolI (\r
396 IN VOID *Buffer\r
397 )\r
28a00297 398{\r
399 POOL *Pool;\r
400 POOL_HEAD *Head;\r
401 POOL_TAIL *Tail;\r
402 POOL_FREE *Free;\r
403 UINTN Index;\r
404 UINTN NoPages;\r
405 UINTN Size;\r
406 CHAR8 *NewPage;\r
407 UINTN FSize;\r
162ed594 408 UINTN Offset;\r
28a00297 409 BOOLEAN AllFree;\r
410\r
57b4ecb9 411 ASSERT(Buffer != NULL);\r
28a00297 412 //\r
413 // Get the head & tail of the pool entry\r
414 //\r
415 Head = CR (Buffer, POOL_HEAD, Data, POOL_HEAD_SIGNATURE);\r
57b4ecb9 416 ASSERT(Head != NULL);\r
28a00297 417\r
418 if (Head->Signature != POOL_HEAD_SIGNATURE) {\r
419 return EFI_INVALID_PARAMETER;\r
420 }\r
421\r
422 Tail = HEAD_TO_TAIL (Head);\r
57b4ecb9 423 ASSERT(Tail != NULL);\r
28a00297 424\r
425 //\r
426 // Debug\r
427 //\r
428 ASSERT (Tail->Signature == POOL_TAIL_SIGNATURE);\r
429 ASSERT (Head->Size == Tail->Size);\r
430 ASSERT_LOCKED (&gMemoryLock);\r
431\r
432 if (Tail->Signature != POOL_TAIL_SIGNATURE) {\r
433 return EFI_INVALID_PARAMETER;\r
434 }\r
435\r
436 if (Head->Size != Tail->Size) {\r
437 return EFI_INVALID_PARAMETER;\r
438 }\r
439\r
440 //\r
441 // Determine the pool type and account for it\r
442 //\r
443 Size = Head->Size;\r
444 Pool = LookupPoolHead (Head->Type);\r
445 if (Pool == NULL) {\r
446 return EFI_INVALID_PARAMETER;\r
447 }\r
448 Pool->Used -= Size;\r
57b4ecb9 449 DEBUG ((DEBUG_POOL, "FreePool: %p (len %lx) %,ld\n", Head->Data, (UINT64)(Head->Size - POOL_OVERHEAD), (UINT64) Pool->Used));\r
28a00297 450\r
451 //\r
022c6d45 452 // Determine the pool list\r
28a00297 453 //\r
454 Index = SIZE_TO_LIST(Size);\r
455 DEBUG_CLEAR_MEMORY (Head, Size);\r
456\r
457 //\r
458 // If it's not on the list, it must be pool pages\r
459 //\r
460 if (Index >= MAX_POOL_LIST) {\r
461\r
462 //\r
463 // Return the memory pages back to free memory\r
464 //\r
465 NoPages = EFI_SIZE_TO_PAGES(Size) + EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1;\r
466 NoPages &= ~(EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION) - 1);\r
467 CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS) (UINTN) Head, NoPages);\r
468\r
469 } else {\r
470\r
471 //\r
472 // Put the pool entry onto the free pool list\r
473 //\r
474 Free = (POOL_FREE *) Head;\r
57b4ecb9 475 ASSERT(Free != NULL);\r
28a00297 476 Free->Signature = POOL_FREE_SIGNATURE;\r
477 Free->Index = (UINT32)Index;\r
478 InsertHeadList (&Pool->FreeList[Index], &Free->Link);\r
479\r
480 //\r
022c6d45 481 // See if all the pool entries in the same page as Free are freed pool\r
28a00297 482 // entries\r
483 //\r
484 NewPage = (CHAR8 *)((UINTN)Free & ~((DEFAULT_PAGE_ALLOCATION) -1));\r
485 Free = (POOL_FREE *) &NewPage[0];\r
e94a9ff7 486 ASSERT(Free != NULL);\r
28a00297 487\r
488 if (Free->Signature == POOL_FREE_SIGNATURE) {\r
489\r
490 Index = Free->Index;\r
491\r
492 AllFree = TRUE;\r
162ed594 493 Offset = 0;\r
022c6d45 494\r
162ed594 495 while ((Offset < DEFAULT_PAGE_ALLOCATION) && (AllFree)) {\r
28a00297 496 FSize = LIST_TO_SIZE(Index);\r
162ed594 497 while (Offset + FSize <= DEFAULT_PAGE_ALLOCATION) {\r
498 Free = (POOL_FREE *) &NewPage[Offset];\r
57b4ecb9 499 ASSERT(Free != NULL);\r
28a00297 500 if (Free->Signature != POOL_FREE_SIGNATURE) {\r
501 AllFree = FALSE;\r
502 }\r
162ed594 503 Offset += FSize;\r
28a00297 504 }\r
505 Index -= 1;\r
506 }\r
507\r
508 if (AllFree) {\r
509\r
510 //\r
022c6d45 511 // All of the pool entries in the same page as Free are free pool\r
28a00297 512 // entries\r
513 // Remove all of these pool entries from the free loop lists.\r
514 //\r
515 Free = (POOL_FREE *) &NewPage[0];\r
57b4ecb9 516 ASSERT(Free != NULL);\r
28a00297 517 Index = Free->Index;\r
162ed594 518 Offset = 0;\r
022c6d45 519\r
162ed594 520 while (Offset < DEFAULT_PAGE_ALLOCATION) {\r
28a00297 521 FSize = LIST_TO_SIZE(Index);\r
162ed594 522 while (Offset + FSize <= DEFAULT_PAGE_ALLOCATION) {\r
523 Free = (POOL_FREE *) &NewPage[Offset];\r
57b4ecb9 524 ASSERT(Free != NULL);\r
28a00297 525 RemoveEntryList (&Free->Link);\r
162ed594 526 Offset += FSize;\r
28a00297 527 }\r
528 Index -= 1;\r
529 }\r
530\r
531 //\r
532 // Free the page\r
533 //\r
534 CoreFreePoolPages ((EFI_PHYSICAL_ADDRESS) (UINTN)NewPage, EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION));\r
535 }\r
536 }\r
537 }\r
538\r
539 //\r
022c6d45 540 // If this is an OS specific memory type, then check to see if the last\r
28a00297 541 // portion of that memory type has been freed. If it has, then free the\r
542 // list entry for that memory type\r
543 //\r
544 if (Pool->MemoryType < 0 && Pool->Used == 0) {\r
545 RemoveEntryList (&Pool->Link);\r
546 CoreFreePoolI (Pool);\r
547 }\r
548\r
549 return EFI_SUCCESS;\r
550}\r