]>
Commit | Line | Data |
---|---|---|
23c98c94 | 1 | /** @file\r |
504214c4 LG |
2 | UEFI Memory pool management functions.\r |
3 | \r | |
63ebde8e | 4 | Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r |
9d510e61 | 5 | SPDX-License-Identifier: BSD-2-Clause-Patent\r |
28a00297 | 6 | \r |
504214c4 | 7 | **/\r |
28a00297 | 8 | \r |
9c4ac31c | 9 | #include "DxeMain.h"\r |
ec90508b | 10 | #include "Imem.h"\r |
e63da9f0 | 11 | #include "HeapGuard.h"\r |
28a00297 | 12 | \r |
1436aea4 | 13 | STATIC EFI_LOCK mPoolMemoryLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);\r |
f31c36c2 | 14 | \r |
1436aea4 | 15 | #define POOL_FREE_SIGNATURE SIGNATURE_32('p','f','r','0')\r |
28a00297 | 16 | typedef struct {\r |
1436aea4 MK |
17 | UINT32 Signature;\r |
18 | UINT32 Index;\r | |
19 | LIST_ENTRY Link;\r | |
28a00297 | 20 | } POOL_FREE;\r |
21 | \r | |
1436aea4 MK |
22 | #define POOL_HEAD_SIGNATURE SIGNATURE_32('p','h','d','0')\r |
23 | #define POOLPAGE_HEAD_SIGNATURE SIGNATURE_32('p','h','d','1')\r | |
28a00297 | 24 | typedef struct {\r |
1436aea4 MK |
25 | UINT32 Signature;\r |
26 | UINT32 Reserved;\r | |
27 | EFI_MEMORY_TYPE Type;\r | |
28 | UINTN Size;\r | |
29 | CHAR8 Data[1];\r | |
28a00297 | 30 | } POOL_HEAD;\r |
31 | \r | |
1436aea4 | 32 | #define SIZE_OF_POOL_HEAD OFFSET_OF(POOL_HEAD,Data)\r |
28a00297 | 33 | \r |
1436aea4 | 34 | #define POOL_TAIL_SIGNATURE SIGNATURE_32('p','t','a','l')\r |
28a00297 | 35 | typedef struct {\r |
1436aea4 MK |
36 | UINT32 Signature;\r |
37 | UINT32 Reserved;\r | |
38 | UINTN Size;\r | |
28a00297 | 39 | } POOL_TAIL;\r |
40 | \r | |
1436aea4 | 41 | #define POOL_OVERHEAD (SIZE_OF_POOL_HEAD + sizeof(POOL_TAIL))\r |
28a00297 | 42 | \r |
43 | #define HEAD_TO_TAIL(a) \\r | |
44 | ((POOL_TAIL *) (((CHAR8 *) (a)) + (a)->Size - sizeof(POOL_TAIL)));\r | |
45 | \r | |
f2c7daf6 AB |
46 | //\r |
47 | // Each element is the sum of the 2 previous ones: this allows us to migrate\r | |
48 | // blocks between bins by splitting them up, while not wasting too much memory\r | |
49 | // as we would in a strict power-of-2 sequence\r | |
50 | //\r | |
1436aea4 | 51 | STATIC CONST UINT16 mPoolSizeTable[] = {\r |
467d5f6b | 52 | 128, 256, 384, 640, 1024, 1664, 2688, 4352, 7040, 11392, 18432, 29824\r |
f2c7daf6 | 53 | };\r |
28a00297 | 54 | \r |
1436aea4 MK |
55 | #define SIZE_TO_LIST(a) (GetPoolIndexFromSize (a))\r |
56 | #define LIST_TO_SIZE(a) (mPoolSizeTable [a])\r | |
28a00297 | 57 | \r |
1436aea4 | 58 | #define MAX_POOL_LIST (ARRAY_SIZE (mPoolSizeTable))\r |
28a00297 | 59 | \r |
1436aea4 | 60 | #define MAX_POOL_SIZE (MAX_ADDRESS - POOL_OVERHEAD)\r |
28a00297 | 61 | \r |
62 | //\r | |
63 | // Globals\r | |
64 | //\r | |
65 | \r | |
f3f2e05d | 66 | #define POOL_SIGNATURE SIGNATURE_32('p','l','s','t')\r |
28a00297 | 67 | typedef struct {\r |
1436aea4 MK |
68 | INTN Signature;\r |
69 | UINTN Used;\r | |
70 | EFI_MEMORY_TYPE MemoryType;\r | |
71 | LIST_ENTRY FreeList[MAX_POOL_LIST];\r | |
72 | LIST_ENTRY Link;\r | |
022c6d45 | 73 | } POOL;\r |
28a00297 | 74 | \r |
28a00297 | 75 | //\r |
e94a9ff7 | 76 | // Pool header for each memory type.\r |
77 | //\r | |
1436aea4 | 78 | POOL mPoolHead[EfiMaxMemoryType];\r |
e94a9ff7 | 79 | \r |
28a00297 | 80 | //\r |
e94a9ff7 | 81 | // List of pool header to search for the appropriate memory type.\r |
28a00297 | 82 | //\r |
1436aea4 | 83 | LIST_ENTRY mPoolHeadList = INITIALIZE_LIST_HEAD_VARIABLE (mPoolHeadList);\r |
28a00297 | 84 | \r |
dd51e45b SQ |
85 | /**\r |
86 | Get pool size table index from the specified size.\r | |
87 | \r | |
88 | @param Size The specified size to get index from pool table.\r | |
89 | \r | |
90 | @return The index of pool size table.\r | |
91 | \r | |
92 | **/\r | |
f2c7daf6 AB |
93 | STATIC\r |
94 | UINTN\r | |
95 | GetPoolIndexFromSize (\r | |
1436aea4 | 96 | UINTN Size\r |
f2c7daf6 AB |
97 | )\r |
98 | {\r | |
1436aea4 | 99 | UINTN Index;\r |
f2c7daf6 AB |
100 | \r |
101 | for (Index = 0; Index < MAX_POOL_LIST; Index++) {\r | |
1436aea4 | 102 | if (mPoolSizeTable[Index] >= Size) {\r |
f2c7daf6 AB |
103 | return Index;\r |
104 | }\r | |
105 | }\r | |
1436aea4 | 106 | \r |
f2c7daf6 AB |
107 | return MAX_POOL_LIST;\r |
108 | }\r | |
162ed594 | 109 | \r |
110 | /**\r | |
111 | Called to initialize the pool.\r | |
112 | \r | |
113 | **/\r | |
28a00297 | 114 | VOID\r |
115 | CoreInitializePool (\r | |
116 | VOID\r | |
117 | )\r | |
28a00297 | 118 | {\r |
119 | UINTN Type;\r | |
120 | UINTN Index;\r | |
121 | \r | |
1436aea4 | 122 | for (Type = 0; Type < EfiMaxMemoryType; Type++) {\r |
e94a9ff7 | 123 | mPoolHead[Type].Signature = 0;\r |
124 | mPoolHead[Type].Used = 0;\r | |
1436aea4 MK |
125 | mPoolHead[Type].MemoryType = (EFI_MEMORY_TYPE)Type;\r |
126 | for (Index = 0; Index < MAX_POOL_LIST; Index++) {\r | |
bb683bf4 | 127 | InitializeListHead (&mPoolHead[Type].FreeList[Index]);\r |
28a00297 | 128 | }\r |
129 | }\r | |
28a00297 | 130 | }\r |
131 | \r | |
162ed594 | 132 | /**\r |
28a00297 | 133 | Look up pool head for specified memory type.\r |
134 | \r | |
022c6d45 | 135 | @param MemoryType Memory type of which pool head is looked for\r |
28a00297 | 136 | \r |
162ed594 | 137 | @return Pointer of Corresponding pool head.\r |
28a00297 | 138 | \r |
162ed594 | 139 | **/\r |
162ed594 | 140 | POOL *\r |
141 | LookupPoolHead (\r | |
142 | IN EFI_MEMORY_TYPE MemoryType\r | |
143 | )\r | |
28a00297 | 144 | {\r |
1436aea4 MK |
145 | LIST_ENTRY *Link;\r |
146 | POOL *Pool;\r | |
147 | UINTN Index;\r | |
28a00297 | 148 | \r |
3d78c020 | 149 | if ((UINT32)MemoryType < EfiMaxMemoryType) {\r |
e94a9ff7 | 150 | return &mPoolHead[MemoryType];\r |
28a00297 | 151 | }\r |
152 | \r | |
dc8d93ca | 153 | //\r |
8ee25f48 SZ |
154 | // MemoryType values in the range 0x80000000..0xFFFFFFFF are reserved for use by UEFI\r |
155 | // OS loaders that are provided by operating system vendors.\r | |
156 | // MemoryType values in the range 0x70000000..0x7FFFFFFF are reserved for OEM use.\r | |
dc8d93ca | 157 | //\r |
1436aea4 | 158 | if ((UINT32)MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) {\r |
e94a9ff7 | 159 | for (Link = mPoolHeadList.ForwardLink; Link != &mPoolHeadList; Link = Link->ForwardLink) {\r |
1436aea4 | 160 | Pool = CR (Link, POOL, Link, POOL_SIGNATURE);\r |
28a00297 | 161 | if (Pool->MemoryType == MemoryType) {\r |
162 | return Pool;\r | |
163 | }\r | |
164 | }\r | |
165 | \r | |
e63da9f0 | 166 | Pool = CoreAllocatePoolI (EfiBootServicesData, sizeof (POOL), FALSE);\r |
28a00297 | 167 | if (Pool == NULL) {\r |
168 | return NULL;\r | |
169 | }\r | |
170 | \r | |
1436aea4 MK |
171 | Pool->Signature = POOL_SIGNATURE;\r |
172 | Pool->Used = 0;\r | |
28a00297 | 173 | Pool->MemoryType = MemoryType;\r |
1436aea4 | 174 | for (Index = 0; Index < MAX_POOL_LIST; Index++) {\r |
28a00297 | 175 | InitializeListHead (&Pool->FreeList[Index]);\r |
176 | }\r | |
177 | \r | |
e94a9ff7 | 178 | InsertHeadList (&mPoolHeadList, &Pool->Link);\r |
28a00297 | 179 | \r |
180 | return Pool;\r | |
181 | }\r | |
182 | \r | |
183 | return NULL;\r | |
184 | }\r | |
185 | \r | |
162ed594 | 186 | /**\r |
187 | Allocate pool of a particular type.\r | |
188 | \r | |
022c6d45 | 189 | @param PoolType Type of pool to allocate\r |
190 | @param Size The amount of pool to allocate\r | |
191 | @param Buffer The address to return a pointer to the allocated\r | |
192 | pool\r | |
162ed594 | 193 | \r |
2eb989bc SZ |
194 | @retval EFI_INVALID_PARAMETER Buffer is NULL.\r |
195 | PoolType is in the range EfiMaxMemoryType..0x6FFFFFFF.\r | |
196 | PoolType is EfiPersistentMemory.\r | |
022c6d45 | 197 | @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.\r |
162ed594 | 198 | @retval EFI_SUCCESS Pool successfully allocated.\r |
199 | \r | |
200 | **/\r | |
28a00297 | 201 | EFI_STATUS\r |
202 | EFIAPI\r | |
84edd20b | 203 | CoreInternalAllocatePool (\r |
28a00297 | 204 | IN EFI_MEMORY_TYPE PoolType,\r |
205 | IN UINTN Size,\r | |
206 | OUT VOID **Buffer\r | |
207 | )\r | |
28a00297 | 208 | {\r |
1436aea4 MK |
209 | EFI_STATUS Status;\r |
210 | BOOLEAN NeedGuard;\r | |
28a00297 | 211 | \r |
212 | //\r | |
213 | // If it's not a valid type, fail it\r | |
214 | //\r | |
1436aea4 | 215 | if (((PoolType >= EfiMaxMemoryType) && (PoolType < MEMORY_TYPE_OEM_RESERVED_MIN)) ||\r |
96192ba5 | 216 | (PoolType == EfiConventionalMemory) || (PoolType == EfiPersistentMemory) || (PoolType == EfiUnacceptedMemoryType))\r |
1436aea4 | 217 | {\r |
28a00297 | 218 | return EFI_INVALID_PARAMETER;\r |
219 | }\r | |
022c6d45 | 220 | \r |
3e058701 ED |
221 | if (Buffer == NULL) {\r |
222 | return EFI_INVALID_PARAMETER;\r | |
223 | }\r | |
224 | \r | |
28a00297 | 225 | *Buffer = NULL;\r |
022c6d45 | 226 | \r |
28a00297 | 227 | //\r |
228 | // If size is too large, fail it\r | |
229 | // Base on the EFI spec, return status of EFI_OUT_OF_RESOURCES\r | |
230 | //\r | |
231 | if (Size > MAX_POOL_SIZE) {\r | |
232 | return EFI_OUT_OF_RESOURCES;\r | |
233 | }\r | |
234 | \r | |
e63da9f0 JW |
235 | NeedGuard = IsPoolTypeToGuard (PoolType) && !mOnGuarding;\r |
236 | \r | |
28a00297 | 237 | //\r |
238 | // Acquire the memory lock and make the allocation\r | |
239 | //\r | |
f31c36c2 | 240 | Status = CoreAcquireLockOrFail (&mPoolMemoryLock);\r |
28a00297 | 241 | if (EFI_ERROR (Status)) {\r |
242 | return EFI_OUT_OF_RESOURCES;\r | |
243 | }\r | |
244 | \r | |
e63da9f0 | 245 | *Buffer = CoreAllocatePoolI (PoolType, Size, NeedGuard);\r |
f31c36c2 | 246 | CoreReleaseLock (&mPoolMemoryLock);\r |
28a00297 | 247 | return (*Buffer != NULL) ? EFI_SUCCESS : EFI_OUT_OF_RESOURCES;\r |
248 | }\r | |
249 | \r | |
84edd20b SZ |
250 | /**\r |
251 | Allocate pool of a particular type.\r | |
252 | \r | |
253 | @param PoolType Type of pool to allocate\r | |
254 | @param Size The amount of pool to allocate\r | |
255 | @param Buffer The address to return a pointer to the allocated\r | |
256 | pool\r | |
257 | \r | |
2eb989bc SZ |
258 | @retval EFI_INVALID_PARAMETER Buffer is NULL.\r |
259 | PoolType is in the range EfiMaxMemoryType..0x6FFFFFFF.\r | |
260 | PoolType is EfiPersistentMemory.\r | |
84edd20b SZ |
261 | @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.\r |
262 | @retval EFI_SUCCESS Pool successfully allocated.\r | |
263 | \r | |
264 | **/\r | |
265 | EFI_STATUS\r | |
266 | EFIAPI\r | |
267 | CoreAllocatePool (\r | |
268 | IN EFI_MEMORY_TYPE PoolType,\r | |
269 | IN UINTN Size,\r | |
270 | OUT VOID **Buffer\r | |
271 | )\r | |
272 | {\r | |
273 | EFI_STATUS Status;\r | |
28a00297 | 274 | \r |
84edd20b SZ |
275 | Status = CoreInternalAllocatePool (PoolType, Size, Buffer);\r |
276 | if (!EFI_ERROR (Status)) {\r | |
1d60fe96 | 277 | CoreUpdateProfile (\r |
1436aea4 | 278 | (EFI_PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),\r |
1d60fe96 SZ |
279 | MemoryProfileActionAllocatePool,\r |
280 | PoolType,\r | |
281 | Size,\r | |
282 | *Buffer,\r | |
283 | NULL\r | |
284 | );\r | |
74a88770 | 285 | InstallMemoryAttributesTableOnMemoryAllocation (PoolType);\r |
84edd20b | 286 | }\r |
1436aea4 | 287 | \r |
84edd20b SZ |
288 | return Status;\r |
289 | }\r | |
28a00297 | 290 | \r |
7babb437 BD |
291 | /**\r |
292 | Internal function. Used by the pool functions to allocate pages\r | |
293 | to back pool allocation requests.\r | |
294 | \r | |
295 | @param PoolType The type of memory for the new pool pages\r | |
296 | @param NoPages No of pages to allocate\r | |
297 | @param Granularity Bits to align.\r | |
e63da9f0 | 298 | @param NeedGuard Flag to indicate Guard page is needed or not\r |
7babb437 BD |
299 | \r |
300 | @return The allocated memory, or NULL\r | |
301 | \r | |
302 | **/\r | |
f31c36c2 AB |
303 | STATIC\r |
304 | VOID *\r | |
305 | CoreAllocatePoolPagesI (\r | |
1436aea4 MK |
306 | IN EFI_MEMORY_TYPE PoolType,\r |
307 | IN UINTN NoPages,\r | |
308 | IN UINTN Granularity,\r | |
309 | IN BOOLEAN NeedGuard\r | |
f31c36c2 AB |
310 | )\r |
311 | {\r | |
312 | VOID *Buffer;\r | |
313 | EFI_STATUS Status;\r | |
314 | \r | |
315 | Status = CoreAcquireLockOrFail (&gMemoryLock);\r | |
316 | if (EFI_ERROR (Status)) {\r | |
317 | return NULL;\r | |
318 | }\r | |
319 | \r | |
e63da9f0 | 320 | Buffer = CoreAllocatePoolPages (PoolType, NoPages, Granularity, NeedGuard);\r |
f31c36c2 AB |
321 | CoreReleaseMemoryLock ();\r |
322 | \r | |
7eb927db | 323 | if (Buffer != NULL) {\r |
e63da9f0 JW |
324 | if (NeedGuard) {\r |
325 | SetGuardForMemory ((EFI_PHYSICAL_ADDRESS)(UINTN)Buffer, NoPages);\r | |
326 | }\r | |
1436aea4 MK |
327 | \r |
328 | ApplyMemoryProtectionPolicy (\r | |
329 | EfiConventionalMemory,\r | |
330 | PoolType,\r | |
331 | (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer,\r | |
332 | EFI_PAGES_TO_SIZE (NoPages)\r | |
333 | );\r | |
7eb927db | 334 | }\r |
1436aea4 | 335 | \r |
f31c36c2 AB |
336 | return Buffer;\r |
337 | }\r | |
338 | \r | |
162ed594 | 339 | /**\r |
28a00297 | 340 | Internal function to allocate pool of a particular type.\r |
28a00297 | 341 | Caller must have the memory lock held\r |
342 | \r | |
022c6d45 | 343 | @param PoolType Type of pool to allocate\r |
344 | @param Size The amount of pool to allocate\r | |
e63da9f0 | 345 | @param NeedGuard Flag to indicate Guard page is needed or not\r |
28a00297 | 346 | \r |
162ed594 | 347 | @return The allocate pool, or NULL\r |
28a00297 | 348 | \r |
162ed594 | 349 | **/\r |
350 | VOID *\r | |
351 | CoreAllocatePoolI (\r | |
352 | IN EFI_MEMORY_TYPE PoolType,\r | |
e63da9f0 JW |
353 | IN UINTN Size,\r |
354 | IN BOOLEAN NeedGuard\r | |
162ed594 | 355 | )\r |
28a00297 | 356 | {\r |
1436aea4 MK |
357 | POOL *Pool;\r |
358 | POOL_FREE *Free;\r | |
359 | POOL_HEAD *Head;\r | |
360 | POOL_TAIL *Tail;\r | |
361 | CHAR8 *NewPage;\r | |
362 | VOID *Buffer;\r | |
363 | UINTN Index;\r | |
364 | UINTN FSize;\r | |
365 | UINTN Offset, MaxOffset;\r | |
366 | UINTN NoPages;\r | |
367 | UINTN Granularity;\r | |
368 | BOOLEAN HasPoolTail;\r | |
369 | BOOLEAN PageAsPool;\r | |
28a00297 | 370 | \r |
f31c36c2 | 371 | ASSERT_LOCKED (&mPoolMemoryLock);\r |
28a00297 | 372 | \r |
1436aea4 MK |
373 | if ((PoolType == EfiACPIReclaimMemory) ||\r |
374 | (PoolType == EfiACPIMemoryNVS) ||\r | |
375 | (PoolType == EfiRuntimeServicesCode) ||\r | |
376 | (PoolType == EfiRuntimeServicesData))\r | |
377 | {\r | |
d4731a98 | 378 | Granularity = RUNTIME_PAGE_ALLOCATION_GRANULARITY;\r |
7970100c | 379 | } else {\r |
d4731a98 | 380 | Granularity = DEFAULT_PAGE_ALLOCATION_GRANULARITY;\r |
7970100c AB |
381 | }\r |
382 | \r | |
28a00297 | 383 | //\r |
384 | // Adjust the size by the pool header & tail overhead\r | |
385 | //\r | |
022c6d45 | 386 | \r |
1436aea4 MK |
387 | HasPoolTail = !(NeedGuard &&\r |
388 | ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0));\r | |
63ebde8e | 389 | PageAsPool = (IsHeapGuardEnabled (GUARD_HEAP_TYPE_FREED) && !mOnGuarding);\r |
e63da9f0 | 390 | \r |
28a00297 | 391 | //\r |
392 | // Adjusting the Size to be of proper alignment so that\r | |
393 | // we don't get an unaligned access fault later when\r | |
394 | // pool_Tail is being initialized\r | |
395 | //\r | |
f0d5cbb6 | 396 | Size = ALIGN_VARIABLE (Size);\r |
28a00297 | 397 | \r |
398 | Size += POOL_OVERHEAD;\r | |
1436aea4 MK |
399 | Index = SIZE_TO_LIST (Size);\r |
400 | Pool = LookupPoolHead (PoolType);\r | |
401 | if (Pool == NULL) {\r | |
28a00297 | 402 | return NULL;\r |
403 | }\r | |
1436aea4 | 404 | \r |
28a00297 | 405 | Head = NULL;\r |
406 | \r | |
407 | //\r | |
408 | // If allocation is over max size, just allocate pages for the request\r | |
409 | // (slow)\r | |
410 | //\r | |
1436aea4 | 411 | if ((Index >= SIZE_TO_LIST (Granularity)) || NeedGuard || PageAsPool) {\r |
e63da9f0 JW |
412 | if (!HasPoolTail) {\r |
413 | Size -= sizeof (POOL_TAIL);\r | |
414 | }\r | |
1436aea4 MK |
415 | \r |
416 | NoPages = EFI_SIZE_TO_PAGES (Size) + EFI_SIZE_TO_PAGES (Granularity) - 1;\r | |
7970100c | 417 | NoPages &= ~(UINTN)(EFI_SIZE_TO_PAGES (Granularity) - 1);\r |
1436aea4 | 418 | Head = CoreAllocatePoolPagesI (PoolType, NoPages, Granularity, NeedGuard);\r |
e63da9f0 JW |
419 | if (NeedGuard) {\r |
420 | Head = AdjustPoolHeadA ((EFI_PHYSICAL_ADDRESS)(UINTN)Head, NoPages, Size);\r | |
421 | }\r | |
1436aea4 | 422 | \r |
28a00297 | 423 | goto Done;\r |
424 | }\r | |
425 | \r | |
426 | //\r | |
427 | // If there's no free pool in the proper list size, go get some more pages\r | |
428 | //\r | |
429 | if (IsListEmpty (&Pool->FreeList[Index])) {\r | |
1436aea4 | 430 | Offset = LIST_TO_SIZE (Index);\r |
6860b92c AB |
431 | MaxOffset = Granularity;\r |
432 | \r | |
433 | //\r | |
434 | // Check the bins holding larger blocks, and carve one up if needed\r | |
435 | //\r | |
436 | while (++Index < SIZE_TO_LIST (Granularity)) {\r | |
437 | if (!IsListEmpty (&Pool->FreeList[Index])) {\r | |
438 | Free = CR (Pool->FreeList[Index].ForwardLink, POOL_FREE, Link, POOL_FREE_SIGNATURE);\r | |
439 | RemoveEntryList (&Free->Link);\r | |
1436aea4 | 440 | NewPage = (VOID *)Free;\r |
6860b92c AB |
441 | MaxOffset = LIST_TO_SIZE (Index);\r |
442 | goto Carve;\r | |
443 | }\r | |
444 | }\r | |
445 | \r | |
28a00297 | 446 | //\r |
447 | // Get another page\r | |
448 | //\r | |
1436aea4 MK |
449 | NewPage = CoreAllocatePoolPagesI (\r |
450 | PoolType,\r | |
451 | EFI_SIZE_TO_PAGES (Granularity),\r | |
452 | Granularity,\r | |
453 | NeedGuard\r | |
454 | );\r | |
28a00297 | 455 | if (NewPage == NULL) {\r |
456 | goto Done;\r | |
457 | }\r | |
458 | \r | |
459 | //\r | |
f8aabf6e | 460 | // Serve the allocation request from the head of the allocated block\r |
28a00297 | 461 | //\r |
6860b92c | 462 | Carve:\r |
1436aea4 | 463 | Head = (POOL_HEAD *)NewPage;\r |
f8aabf6e AB |
464 | \r |
465 | //\r | |
466 | // Carve up remaining space into free pool blocks\r | |
467 | //\r | |
6860b92c AB |
468 | Index--;\r |
469 | while (Offset < MaxOffset) {\r | |
28a00297 | 470 | ASSERT (Index < MAX_POOL_LIST);\r |
1436aea4 | 471 | FSize = LIST_TO_SIZE (Index);\r |
28a00297 | 472 | \r |
6860b92c | 473 | while (Offset + FSize <= MaxOffset) {\r |
1436aea4 | 474 | Free = (POOL_FREE *)&NewPage[Offset];\r |
28a00297 | 475 | Free->Signature = POOL_FREE_SIGNATURE;\r |
476 | Free->Index = (UINT32)Index;\r | |
477 | InsertHeadList (&Pool->FreeList[Index], &Free->Link);\r | |
162ed594 | 478 | Offset += FSize;\r |
28a00297 | 479 | }\r |
1436aea4 | 480 | \r |
28a00297 | 481 | Index -= 1;\r |
482 | }\r | |
483 | \r | |
6860b92c | 484 | ASSERT (Offset == MaxOffset);\r |
f8aabf6e | 485 | goto Done;\r |
28a00297 | 486 | }\r |
487 | \r | |
488 | //\r | |
489 | // Remove entry from free pool list\r | |
490 | //\r | |
491 | Free = CR (Pool->FreeList[Index].ForwardLink, POOL_FREE, Link, POOL_FREE_SIGNATURE);\r | |
492 | RemoveEntryList (&Free->Link);\r | |
493 | \r | |
1436aea4 | 494 | Head = (POOL_HEAD *)Free;\r |
28a00297 | 495 | \r |
496 | Done:\r | |
497 | Buffer = NULL;\r | |
498 | \r | |
499 | if (Head != NULL) {\r | |
e63da9f0 JW |
500 | //\r |
501 | // Account the allocation\r | |
502 | //\r | |
503 | Pool->Used += Size;\r | |
504 | \r | |
28a00297 | 505 | //\r |
506 | // If we have a pool buffer, fill in the header & tail info\r | |
507 | //\r | |
63ebde8e | 508 | Head->Signature = (PageAsPool) ? POOLPAGE_HEAD_SIGNATURE : POOL_HEAD_SIGNATURE;\r |
bb683bf4 | 509 | Head->Size = Size;\r |
1436aea4 | 510 | Head->Type = (EFI_MEMORY_TYPE)PoolType;\r |
28a00297 | 511 | Buffer = Head->Data;\r |
e63da9f0 JW |
512 | \r |
513 | if (HasPoolTail) {\r | |
514 | Tail = HEAD_TO_TAIL (Head);\r | |
515 | Tail->Signature = POOL_TAIL_SIGNATURE;\r | |
516 | Tail->Size = Size;\r | |
517 | \r | |
518 | Size -= POOL_OVERHEAD;\r | |
519 | } else {\r | |
520 | Size -= SIZE_OF_POOL_HEAD;\r | |
521 | }\r | |
522 | \r | |
523 | DEBUG_CLEAR_MEMORY (Buffer, Size);\r | |
28a00297 | 524 | \r |
e94a9ff7 | 525 | DEBUG ((\r |
526 | DEBUG_POOL,\r | |
1436aea4 MK |
527 | "AllocatePoolI: Type %x, Addr %p (len %lx) %,ld\n",\r |
528 | PoolType,\r | |
022c6d45 | 529 | Buffer,\r |
e63da9f0 | 530 | (UINT64)Size,\r |
1436aea4 | 531 | (UINT64)Pool->Used\r |
e94a9ff7 | 532 | ));\r |
28a00297 | 533 | } else {\r |
1436aea4 | 534 | DEBUG ((DEBUG_ERROR | DEBUG_POOL, "AllocatePool: failed to allocate %ld bytes\n", (UINT64)Size));\r |
28a00297 | 535 | }\r |
536 | \r | |
537 | return Buffer;\r | |
538 | }\r | |
022c6d45 | 539 | \r |
162ed594 | 540 | /**\r |
28a00297 | 541 | Frees pool.\r |
542 | \r | |
022c6d45 | 543 | @param Buffer The allocated pool entry to free\r |
925f0d1a | 544 | @param PoolType Pointer to pool type\r |
28a00297 | 545 | \r |
022c6d45 | 546 | @retval EFI_INVALID_PARAMETER Buffer is not a valid value.\r |
162ed594 | 547 | @retval EFI_SUCCESS Pool successfully freed.\r |
28a00297 | 548 | \r |
162ed594 | 549 | **/\r |
550 | EFI_STATUS\r | |
551 | EFIAPI\r | |
84edd20b | 552 | CoreInternalFreePool (\r |
1436aea4 MK |
553 | IN VOID *Buffer,\r |
554 | OUT EFI_MEMORY_TYPE *PoolType OPTIONAL\r | |
162ed594 | 555 | )\r |
28a00297 | 556 | {\r |
1436aea4 | 557 | EFI_STATUS Status;\r |
28a00297 | 558 | \r |
e94a9ff7 | 559 | if (Buffer == NULL) {\r |
28a00297 | 560 | return EFI_INVALID_PARAMETER;\r |
561 | }\r | |
562 | \r | |
f31c36c2 | 563 | CoreAcquireLock (&mPoolMemoryLock);\r |
925f0d1a | 564 | Status = CoreFreePoolI (Buffer, PoolType);\r |
f31c36c2 | 565 | CoreReleaseLock (&mPoolMemoryLock);\r |
28a00297 | 566 | return Status;\r |
567 | }\r | |
568 | \r | |
84edd20b SZ |
569 | /**\r |
570 | Frees pool.\r | |
571 | \r | |
572 | @param Buffer The allocated pool entry to free\r | |
573 | \r | |
574 | @retval EFI_INVALID_PARAMETER Buffer is not a valid value.\r | |
575 | @retval EFI_SUCCESS Pool successfully freed.\r | |
576 | \r | |
577 | **/\r | |
578 | EFI_STATUS\r | |
579 | EFIAPI\r | |
580 | CoreFreePool (\r | |
581 | IN VOID *Buffer\r | |
582 | )\r | |
583 | {\r | |
1436aea4 MK |
584 | EFI_STATUS Status;\r |
585 | EFI_MEMORY_TYPE PoolType;\r | |
736a692e | 586 | \r |
925f0d1a | 587 | Status = CoreInternalFreePool (Buffer, &PoolType);\r |
736a692e | 588 | if (!EFI_ERROR (Status)) {\r |
1d60fe96 | 589 | CoreUpdateProfile (\r |
1436aea4 | 590 | (EFI_PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),\r |
1d60fe96 SZ |
591 | MemoryProfileActionFreePool,\r |
592 | PoolType,\r | |
593 | 0,\r | |
594 | Buffer,\r | |
595 | NULL\r | |
596 | );\r | |
74a88770 | 597 | InstallMemoryAttributesTableOnMemoryAllocation (PoolType);\r |
736a692e | 598 | }\r |
1436aea4 | 599 | \r |
736a692e HT |
600 | return Status;\r |
601 | }\r | |
28a00297 | 602 | \r |
7babb437 BD |
603 | /**\r |
604 | Internal function. Frees pool pages allocated via CoreAllocatePoolPagesI().\r | |
605 | \r | |
606 | @param PoolType The type of memory for the pool pages\r | |
607 | @param Memory The base address to free\r | |
608 | @param NoPages The number of pages to free\r | |
609 | \r | |
610 | **/\r | |
f31c36c2 AB |
611 | STATIC\r |
612 | VOID\r | |
613 | CoreFreePoolPagesI (\r | |
1436aea4 MK |
614 | IN EFI_MEMORY_TYPE PoolType,\r |
615 | IN EFI_PHYSICAL_ADDRESS Memory,\r | |
616 | IN UINTN NoPages\r | |
f31c36c2 AB |
617 | )\r |
618 | {\r | |
619 | CoreAcquireMemoryLock ();\r | |
620 | CoreFreePoolPages (Memory, NoPages);\r | |
621 | CoreReleaseMemoryLock ();\r | |
7eb927db | 622 | \r |
63ebde8e | 623 | GuardFreedPagesChecked (Memory, NoPages);\r |
1436aea4 MK |
624 | ApplyMemoryProtectionPolicy (\r |
625 | PoolType,\r | |
626 | EfiConventionalMemory,\r | |
627 | (EFI_PHYSICAL_ADDRESS)(UINTN)Memory,\r | |
628 | EFI_PAGES_TO_SIZE (NoPages)\r | |
629 | );\r | |
f31c36c2 AB |
630 | }\r |
631 | \r | |
e63da9f0 JW |
632 | /**\r |
633 | Internal function. Frees guarded pool pages.\r | |
634 | \r | |
635 | @param PoolType The type of memory for the pool pages\r | |
636 | @param Memory The base address to free\r | |
637 | @param NoPages The number of pages to free\r | |
638 | \r | |
639 | **/\r | |
640 | STATIC\r | |
641 | VOID\r | |
642 | CoreFreePoolPagesWithGuard (\r | |
1436aea4 MK |
643 | IN EFI_MEMORY_TYPE PoolType,\r |
644 | IN EFI_PHYSICAL_ADDRESS Memory,\r | |
645 | IN UINTN NoPages\r | |
e63da9f0 JW |
646 | )\r |
647 | {\r | |
1436aea4 MK |
648 | EFI_PHYSICAL_ADDRESS MemoryGuarded;\r |
649 | UINTN NoPagesGuarded;\r | |
e63da9f0 JW |
650 | \r |
651 | MemoryGuarded = Memory;\r | |
652 | NoPagesGuarded = NoPages;\r | |
653 | \r | |
654 | AdjustMemoryF (&Memory, &NoPages);\r | |
1263ecf2 JW |
655 | //\r |
656 | // It's safe to unset Guard page inside memory lock because there should\r | |
657 | // be no memory allocation occurred in updating memory page attribute at\r | |
658 | // this point. And unsetting Guard page before free will prevent Guard\r | |
659 | // page just freed back to pool from being allocated right away before\r | |
660 | // marking it usable (from non-present to present).\r | |
661 | //\r | |
662 | UnsetGuardForMemory (MemoryGuarded, NoPagesGuarded);\r | |
6cf0a677 JW |
663 | if (NoPages > 0) {\r |
664 | CoreFreePoolPagesI (PoolType, Memory, NoPages);\r | |
665 | }\r | |
e63da9f0 JW |
666 | }\r |
667 | \r | |
162ed594 | 668 | /**\r |
28a00297 | 669 | Internal function to free a pool entry.\r |
28a00297 | 670 | Caller must have the memory lock held\r |
671 | \r | |
022c6d45 | 672 | @param Buffer The allocated pool entry to free\r |
925f0d1a | 673 | @param PoolType Pointer to pool type\r |
28a00297 | 674 | \r |
022c6d45 | 675 | @retval EFI_INVALID_PARAMETER Buffer not valid\r |
162ed594 | 676 | @retval EFI_SUCCESS Buffer successfully freed.\r |
28a00297 | 677 | \r |
162ed594 | 678 | **/\r |
679 | EFI_STATUS\r | |
680 | CoreFreePoolI (\r | |
1436aea4 MK |
681 | IN VOID *Buffer,\r |
682 | OUT EFI_MEMORY_TYPE *PoolType OPTIONAL\r | |
162ed594 | 683 | )\r |
28a00297 | 684 | {\r |
1436aea4 MK |
685 | POOL *Pool;\r |
686 | POOL_HEAD *Head;\r | |
687 | POOL_TAIL *Tail;\r | |
688 | POOL_FREE *Free;\r | |
689 | UINTN Index;\r | |
690 | UINTN NoPages;\r | |
691 | UINTN Size;\r | |
692 | CHAR8 *NewPage;\r | |
693 | UINTN Offset;\r | |
694 | BOOLEAN AllFree;\r | |
695 | UINTN Granularity;\r | |
696 | BOOLEAN IsGuarded;\r | |
697 | BOOLEAN HasPoolTail;\r | |
698 | BOOLEAN PageAsPool;\r | |
699 | \r | |
700 | ASSERT (Buffer != NULL);\r | |
28a00297 | 701 | //\r |
702 | // Get the head & tail of the pool entry\r | |
703 | //\r | |
63ebde8e | 704 | Head = BASE_CR (Buffer, POOL_HEAD, Data);\r |
1436aea4 MK |
705 | ASSERT (Head != NULL);\r |
706 | \r | |
707 | if ((Head->Signature != POOL_HEAD_SIGNATURE) &&\r | |
708 | (Head->Signature != POOLPAGE_HEAD_SIGNATURE))\r | |
709 | {\r | |
710 | ASSERT (\r | |
711 | Head->Signature == POOL_HEAD_SIGNATURE ||\r | |
712 | Head->Signature == POOLPAGE_HEAD_SIGNATURE\r | |
713 | );\r | |
28a00297 | 714 | return EFI_INVALID_PARAMETER;\r |
715 | }\r | |
716 | \r | |
1436aea4 MK |
717 | IsGuarded = IsPoolTypeToGuard (Head->Type) &&\r |
718 | IsMemoryGuarded ((EFI_PHYSICAL_ADDRESS)(UINTN)Head);\r | |
e63da9f0 JW |
719 | HasPoolTail = !(IsGuarded &&\r |
720 | ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0));\r | |
63ebde8e | 721 | PageAsPool = (Head->Signature == POOLPAGE_HEAD_SIGNATURE);\r |
e63da9f0 JW |
722 | \r |
723 | if (HasPoolTail) {\r | |
724 | Tail = HEAD_TO_TAIL (Head);\r | |
725 | ASSERT (Tail != NULL);\r | |
726 | \r | |
727 | //\r | |
728 | // Debug\r | |
729 | //\r | |
730 | ASSERT (Tail->Signature == POOL_TAIL_SIGNATURE);\r | |
731 | ASSERT (Head->Size == Tail->Size);\r | |
732 | \r | |
733 | if (Tail->Signature != POOL_TAIL_SIGNATURE) {\r | |
734 | return EFI_INVALID_PARAMETER;\r | |
735 | }\r | |
736 | \r | |
737 | if (Head->Size != Tail->Size) {\r | |
738 | return EFI_INVALID_PARAMETER;\r | |
739 | }\r | |
28a00297 | 740 | }\r |
741 | \r | |
e63da9f0 JW |
742 | ASSERT_LOCKED (&mPoolMemoryLock);\r |
743 | \r | |
28a00297 | 744 | //\r |
745 | // Determine the pool type and account for it\r | |
746 | //\r | |
747 | Size = Head->Size;\r | |
748 | Pool = LookupPoolHead (Head->Type);\r | |
749 | if (Pool == NULL) {\r | |
750 | return EFI_INVALID_PARAMETER;\r | |
751 | }\r | |
28a00297 | 752 | \r |
1436aea4 MK |
753 | Pool->Used -= Size;\r |
754 | DEBUG ((DEBUG_POOL, "FreePool: %p (len %lx) %,ld\n", Head->Data, (UINT64)(Head->Size - POOL_OVERHEAD), (UINT64)Pool->Used));\r | |
7970100c | 755 | \r |
1436aea4 MK |
756 | if ((Head->Type == EfiACPIReclaimMemory) ||\r |
757 | (Head->Type == EfiACPIMemoryNVS) ||\r | |
758 | (Head->Type == EfiRuntimeServicesCode) ||\r | |
759 | (Head->Type == EfiRuntimeServicesData))\r | |
760 | {\r | |
d4731a98 | 761 | Granularity = RUNTIME_PAGE_ALLOCATION_GRANULARITY;\r |
7970100c | 762 | } else {\r |
d4731a98 | 763 | Granularity = DEFAULT_PAGE_ALLOCATION_GRANULARITY;\r |
7970100c AB |
764 | }\r |
765 | \r | |
925f0d1a SZ |
766 | if (PoolType != NULL) {\r |
767 | *PoolType = Head->Type;\r | |
768 | }\r | |
769 | \r | |
28a00297 | 770 | //\r |
022c6d45 | 771 | // Determine the pool list\r |
28a00297 | 772 | //\r |
1436aea4 | 773 | Index = SIZE_TO_LIST (Size);\r |
28a00297 | 774 | DEBUG_CLEAR_MEMORY (Head, Size);\r |
775 | \r | |
776 | //\r | |
777 | // If it's not on the list, it must be pool pages\r | |
778 | //\r | |
1436aea4 | 779 | if ((Index >= SIZE_TO_LIST (Granularity)) || IsGuarded || PageAsPool) {\r |
28a00297 | 780 | //\r |
781 | // Return the memory pages back to free memory\r | |
782 | //\r | |
1436aea4 | 783 | NoPages = EFI_SIZE_TO_PAGES (Size) + EFI_SIZE_TO_PAGES (Granularity) - 1;\r |
7970100c | 784 | NoPages &= ~(UINTN)(EFI_SIZE_TO_PAGES (Granularity) - 1);\r |
e63da9f0 JW |
785 | if (IsGuarded) {\r |
786 | Head = AdjustPoolHeadF ((EFI_PHYSICAL_ADDRESS)(UINTN)Head);\r | |
787 | CoreFreePoolPagesWithGuard (\r | |
788 | Pool->MemoryType,\r | |
789 | (EFI_PHYSICAL_ADDRESS)(UINTN)Head,\r | |
790 | NoPages\r | |
791 | );\r | |
792 | } else {\r | |
793 | CoreFreePoolPagesI (\r | |
794 | Pool->MemoryType,\r | |
795 | (EFI_PHYSICAL_ADDRESS)(UINTN)Head,\r | |
796 | NoPages\r | |
797 | );\r | |
798 | }\r | |
28a00297 | 799 | } else {\r |
28a00297 | 800 | //\r |
801 | // Put the pool entry onto the free pool list\r | |
802 | //\r | |
1436aea4 MK |
803 | Free = (POOL_FREE *)Head;\r |
804 | ASSERT (Free != NULL);\r | |
28a00297 | 805 | Free->Signature = POOL_FREE_SIGNATURE;\r |
806 | Free->Index = (UINT32)Index;\r | |
807 | InsertHeadList (&Pool->FreeList[Index], &Free->Link);\r | |
808 | \r | |
809 | //\r | |
022c6d45 | 810 | // See if all the pool entries in the same page as Free are freed pool\r |
28a00297 | 811 | // entries\r |
812 | //\r | |
7970100c | 813 | NewPage = (CHAR8 *)((UINTN)Free & ~(Granularity - 1));\r |
1436aea4 MK |
814 | Free = (POOL_FREE *)&NewPage[0];\r |
815 | ASSERT (Free != NULL);\r | |
28a00297 | 816 | \r |
817 | if (Free->Signature == POOL_FREE_SIGNATURE) {\r | |
28a00297 | 818 | AllFree = TRUE;\r |
1436aea4 | 819 | Offset = 0;\r |
022c6d45 | 820 | \r |
7970100c | 821 | while ((Offset < Granularity) && (AllFree)) {\r |
1436aea4 MK |
822 | Free = (POOL_FREE *)&NewPage[Offset];\r |
823 | ASSERT (Free != NULL);\r | |
7e8e2205 AB |
824 | if (Free->Signature != POOL_FREE_SIGNATURE) {\r |
825 | AllFree = FALSE;\r | |
28a00297 | 826 | }\r |
1436aea4 MK |
827 | \r |
828 | Offset += LIST_TO_SIZE (Free->Index);\r | |
28a00297 | 829 | }\r |
830 | \r | |
831 | if (AllFree) {\r | |
28a00297 | 832 | //\r |
022c6d45 | 833 | // All of the pool entries in the same page as Free are free pool\r |
28a00297 | 834 | // entries\r |
835 | // Remove all of these pool entries from the free loop lists.\r | |
836 | //\r | |
1436aea4 MK |
837 | Free = (POOL_FREE *)&NewPage[0];\r |
838 | ASSERT (Free != NULL);\r | |
162ed594 | 839 | Offset = 0;\r |
022c6d45 | 840 | \r |
7970100c | 841 | while (Offset < Granularity) {\r |
1436aea4 MK |
842 | Free = (POOL_FREE *)&NewPage[Offset];\r |
843 | ASSERT (Free != NULL);\r | |
7e8e2205 | 844 | RemoveEntryList (&Free->Link);\r |
1436aea4 | 845 | Offset += LIST_TO_SIZE (Free->Index);\r |
28a00297 | 846 | }\r |
847 | \r | |
848 | //\r | |
849 | // Free the page\r | |
850 | //\r | |
1436aea4 MK |
851 | CoreFreePoolPagesI (\r |
852 | Pool->MemoryType,\r | |
853 | (EFI_PHYSICAL_ADDRESS)(UINTN)NewPage,\r | |
854 | EFI_SIZE_TO_PAGES (Granularity)\r | |
855 | );\r | |
28a00297 | 856 | }\r |
857 | }\r | |
858 | }\r | |
859 | \r | |
860 | //\r | |
09159a29 | 861 | // If this is an OS/OEM specific memory type, then check to see if the last\r |
28a00297 | 862 | // portion of that memory type has been freed. If it has, then free the\r |
863 | // list entry for that memory type\r | |
864 | //\r | |
1436aea4 | 865 | if (((UINT32)Pool->MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) && (Pool->Used == 0)) {\r |
28a00297 | 866 | RemoveEntryList (&Pool->Link);\r |
925f0d1a | 867 | CoreFreePoolI (Pool, NULL);\r |
28a00297 | 868 | }\r |
869 | \r | |
870 | return EFI_SUCCESS;\r | |
871 | }\r |