]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/PiSmmCore/Pool.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Core / PiSmmCore / Pool.c
CommitLineData
e42e9404 1/** @file\r
2 SMM Memory pool management functions.\r
3\r
d1102dba 4 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r
9d510e61 5 SPDX-License-Identifier: BSD-2-Clause-Patent\r
e42e9404 6\r
7**/\r
8\r
9#include "PiSmmCore.h"\r
10\r
5f4d3e17 11LIST_ENTRY mSmmPoolLists[SmmPoolTypeMax][MAX_POOL_INDEX];\r
3c447c27 12//\r
d1102dba 13// To cache the SMRAM base since when Loading modules At fixed address feature is enabled,\r
3c447c27 14// all module is assigned an offset relative the SMRAM base in build time.\r
15//\r
16GLOBAL_REMOVE_IF_UNREFERENCED EFI_PHYSICAL_ADDRESS gLoadModuleAtFixAddressSmramBase = 0;\r
e42e9404 17\r
5f4d3e17
JY
18/**\r
19 Convert a UEFI memory type to SMM pool type.\r
20\r
21 @param[in] MemoryType Type of pool to allocate.\r
22\r
23 @return SMM pool type\r
24**/\r
25SMM_POOL_TYPE\r
26UefiMemoryTypeToSmmPoolType (\r
27 IN EFI_MEMORY_TYPE MemoryType\r
28 )\r
29{\r
30 ASSERT ((MemoryType == EfiRuntimeServicesCode) || (MemoryType == EfiRuntimeServicesData));\r
31 switch (MemoryType) {\r
32 case EfiRuntimeServicesCode:\r
33 return SmmPoolTypeCode;\r
34 case EfiRuntimeServicesData:\r
35 return SmmPoolTypeData;\r
36 default:\r
37 return SmmPoolTypeMax;\r
38 }\r
39}\r
40\r
41\r
e42e9404 42/**\r
43 Called to initialize the memory service.\r
44\r
45 @param SmramRangeCount Number of SMRAM Regions\r
46 @param SmramRanges Pointer to SMRAM Descriptors\r
47\r
48**/\r
49VOID\r
50SmmInitializeMemoryServices (\r
51 IN UINTN SmramRangeCount,\r
52 IN EFI_SMRAM_DESCRIPTOR *SmramRanges\r
53 )\r
54{\r
3c447c27 55 UINTN Index;\r
94a1bc12 56 EFI_STATUS Status;\r
5f4d3e17 57 UINTN SmmPoolTypeIndex;\r
94a1bc12 58 EFI_LOAD_FIXED_ADDRESS_CONFIGURATION_TABLE *LMFAConfigurationTable;\r
e42e9404 59\r
60 //\r
61 // Initialize Pool list\r
62 //\r
5f4d3e17
JY
63 for (SmmPoolTypeIndex = 0; SmmPoolTypeIndex < SmmPoolTypeMax; SmmPoolTypeIndex++) {\r
64 for (Index = 0; Index < ARRAY_SIZE (mSmmPoolLists[SmmPoolTypeIndex]); Index++) {\r
65 InitializeListHead (&mSmmPoolLists[SmmPoolTypeIndex][Index]);\r
66 }\r
e42e9404 67 }\r
94a1bc12
LG
68\r
69 Status = EfiGetSystemConfigurationTable (\r
70 &gLoadFixedAddressConfigurationTableGuid,\r
71 (VOID **) &LMFAConfigurationTable\r
72 );\r
73 if (!EFI_ERROR (Status) && LMFAConfigurationTable != NULL) {\r
74 gLoadModuleAtFixAddressSmramBase = LMFAConfigurationTable->SmramBase;\r
3c447c27 75 }\r
94a1bc12 76\r
e42e9404 77 //\r
bb34cc8c 78 // Add Free SMRAM regions\r
285a682c 79 // Need add Free memory at first, to let gSmmMemoryMap record data\r
e42e9404 80 //\r
81 for (Index = 0; Index < SmramRangeCount; Index++) {\r
285a682c
JY
82 if ((SmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {\r
83 continue;\r
84 }\r
85 SmmAddMemoryRegion (\r
86 SmramRanges[Index].CpuStart,\r
87 SmramRanges[Index].PhysicalSize,\r
88 EfiConventionalMemory,\r
89 SmramRanges[Index].RegionState\r
90 );\r
91 }\r
92\r
bb34cc8c
LG
93 //\r
94 // Add the allocated SMRAM regions\r
95 //\r
285a682c
JY
96 for (Index = 0; Index < SmramRangeCount; Index++) {\r
97 if ((SmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) == 0) {\r
98 continue;\r
99 }\r
e42e9404 100 SmmAddMemoryRegion (\r
101 SmramRanges[Index].CpuStart,\r
102 SmramRanges[Index].PhysicalSize,\r
103 EfiConventionalMemory,\r
104 SmramRanges[Index].RegionState\r
105 );\r
106 }\r
3c447c27 107\r
e42e9404 108}\r
109\r
110/**\r
111 Internal Function. Allocate a pool by specified PoolIndex.\r
112\r
5f4d3e17 113 @param PoolType Type of pool to allocate.\r
e42e9404 114 @param PoolIndex Index which indicate the Pool size.\r
115 @param FreePoolHdr The returned Free pool.\r
116\r
117 @retval EFI_OUT_OF_RESOURCES Allocation failed.\r
118 @retval EFI_SUCCESS Pool successfully allocated.\r
119\r
120**/\r
121EFI_STATUS\r
122InternalAllocPoolByIndex (\r
5f4d3e17 123 IN EFI_MEMORY_TYPE PoolType,\r
e42e9404 124 IN UINTN PoolIndex,\r
125 OUT FREE_POOL_HEADER **FreePoolHdr\r
126 )\r
127{\r
84edd20b
SZ
128 EFI_STATUS Status;\r
129 FREE_POOL_HEADER *Hdr;\r
861c8dff 130 POOL_TAIL *Tail;\r
84edd20b 131 EFI_PHYSICAL_ADDRESS Address;\r
5f4d3e17
JY
132 SMM_POOL_TYPE SmmPoolType;\r
133\r
89558f16 134 Address = 0;\r
5f4d3e17 135 SmmPoolType = UefiMemoryTypeToSmmPoolType(PoolType);\r
e42e9404 136\r
52c0d06b 137 ASSERT (PoolIndex <= MAX_POOL_INDEX);\r
e42e9404 138 Status = EFI_SUCCESS;\r
bf14e107 139 Hdr = NULL;\r
e42e9404 140 if (PoolIndex == MAX_POOL_INDEX) {\r
e63da9f0
JW
141 Status = SmmInternalAllocatePages (AllocateAnyPages, PoolType,\r
142 EFI_SIZE_TO_PAGES (MAX_POOL_SIZE << 1),\r
143 &Address, FALSE);\r
84edd20b 144 if (EFI_ERROR (Status)) {\r
5b422a7b 145 return EFI_OUT_OF_RESOURCES;\r
e42e9404 146 }\r
84edd20b 147 Hdr = (FREE_POOL_HEADER *) (UINTN) Address;\r
5f4d3e17
JY
148 } else if (!IsListEmpty (&mSmmPoolLists[SmmPoolType][PoolIndex])) {\r
149 Hdr = BASE_CR (GetFirstNode (&mSmmPoolLists[SmmPoolType][PoolIndex]), FREE_POOL_HEADER, Link);\r
e42e9404 150 RemoveEntryList (&Hdr->Link);\r
151 } else {\r
5f4d3e17 152 Status = InternalAllocPoolByIndex (PoolType, PoolIndex + 1, &Hdr);\r
e42e9404 153 if (!EFI_ERROR (Status)) {\r
861c8dff 154 Hdr->Header.Signature = 0;\r
e42e9404 155 Hdr->Header.Size >>= 1;\r
156 Hdr->Header.Available = TRUE;\r
861c8dff
SZ
157 Hdr->Header.Type = 0;\r
158 Tail = HEAD_TO_TAIL(&Hdr->Header);\r
159 Tail->Signature = 0;\r
160 Tail->Size = 0;\r
5f4d3e17 161 InsertHeadList (&mSmmPoolLists[SmmPoolType][PoolIndex], &Hdr->Link);\r
e42e9404 162 Hdr = (FREE_POOL_HEADER*)((UINT8*)Hdr + Hdr->Header.Size);\r
163 }\r
164 }\r
165\r
166 if (!EFI_ERROR (Status)) {\r
861c8dff 167 Hdr->Header.Signature = POOL_HEAD_SIGNATURE;\r
e42e9404 168 Hdr->Header.Size = MIN_POOL_SIZE << PoolIndex;\r
169 Hdr->Header.Available = FALSE;\r
5f4d3e17 170 Hdr->Header.Type = PoolType;\r
861c8dff
SZ
171 Tail = HEAD_TO_TAIL(&Hdr->Header);\r
172 Tail->Signature = POOL_TAIL_SIGNATURE;\r
173 Tail->Size = Hdr->Header.Size;\r
e42e9404 174 }\r
175\r
176 *FreePoolHdr = Hdr;\r
177 return Status;\r
178}\r
179\r
180/**\r
181 Internal Function. Free a pool by specified PoolIndex.\r
182\r
183 @param FreePoolHdr The pool to free.\r
f8f931f6 184 @param PoolTail The pointer to the pool tail.\r
e42e9404 185\r
186 @retval EFI_SUCCESS Pool successfully freed.\r
187\r
188**/\r
189EFI_STATUS\r
190InternalFreePoolByIndex (\r
f8f931f6
HW
191 IN FREE_POOL_HEADER *FreePoolHdr,\r
192 IN POOL_TAIL *PoolTail\r
e42e9404 193 )\r
194{\r
5f4d3e17
JY
195 UINTN PoolIndex;\r
196 SMM_POOL_TYPE SmmPoolType;\r
e42e9404 197\r
198 ASSERT ((FreePoolHdr->Header.Size & (FreePoolHdr->Header.Size - 1)) == 0);\r
199 ASSERT (((UINTN)FreePoolHdr & (FreePoolHdr->Header.Size - 1)) == 0);\r
200 ASSERT (FreePoolHdr->Header.Size >= MIN_POOL_SIZE);\r
201\r
5f4d3e17
JY
202 SmmPoolType = UefiMemoryTypeToSmmPoolType(FreePoolHdr->Header.Type);\r
203\r
fbe12b79 204 PoolIndex = (UINTN) (HighBitSet32 ((UINT32)FreePoolHdr->Header.Size) - MIN_POOL_SHIFT);\r
861c8dff 205 FreePoolHdr->Header.Signature = 0;\r
e42e9404 206 FreePoolHdr->Header.Available = TRUE;\r
861c8dff 207 FreePoolHdr->Header.Type = 0;\r
861c8dff
SZ
208 PoolTail->Signature = 0;\r
209 PoolTail->Size = 0;\r
5b422a7b 210 ASSERT (PoolIndex < MAX_POOL_INDEX);\r
5f4d3e17 211 InsertHeadList (&mSmmPoolLists[SmmPoolType][PoolIndex], &FreePoolHdr->Link);\r
e42e9404 212 return EFI_SUCCESS;\r
213}\r
214\r
215/**\r
216 Allocate pool of a particular type.\r
217\r
218 @param PoolType Type of pool to allocate.\r
219 @param Size The amount of pool to allocate.\r
220 @param Buffer The address to return a pointer to the allocated\r
221 pool.\r
222\r
223 @retval EFI_INVALID_PARAMETER PoolType not valid.\r
224 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.\r
225 @retval EFI_SUCCESS Pool successfully allocated.\r
226\r
227**/\r
228EFI_STATUS\r
229EFIAPI\r
84edd20b 230SmmInternalAllocatePool (\r
e42e9404 231 IN EFI_MEMORY_TYPE PoolType,\r
232 IN UINTN Size,\r
233 OUT VOID **Buffer\r
234 )\r
235{\r
236 POOL_HEADER *PoolHdr;\r
861c8dff 237 POOL_TAIL *PoolTail;\r
e42e9404 238 FREE_POOL_HEADER *FreePoolHdr;\r
239 EFI_STATUS Status;\r
240 EFI_PHYSICAL_ADDRESS Address;\r
241 UINTN PoolIndex;\r
e63da9f0
JW
242 BOOLEAN HasPoolTail;\r
243 BOOLEAN NeedGuard;\r
244 UINTN NoPages;\r
e42e9404 245\r
89558f16
HW
246 Address = 0;\r
247\r
e42e9404 248 if (PoolType != EfiRuntimeServicesCode &&\r
249 PoolType != EfiRuntimeServicesData) {\r
250 return EFI_INVALID_PARAMETER;\r
251 }\r
252\r
e63da9f0
JW
253 NeedGuard = IsPoolTypeToGuard (PoolType);\r
254 HasPoolTail = !(NeedGuard &&\r
255 ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0));\r
256\r
861c8dff
SZ
257 //\r
258 // Adjust the size by the pool header & tail overhead\r
259 //\r
260 Size += POOL_OVERHEAD;\r
e63da9f0
JW
261 if (Size > MAX_POOL_SIZE || NeedGuard) {\r
262 if (!HasPoolTail) {\r
263 Size -= sizeof (POOL_TAIL);\r
264 }\r
265\r
266 NoPages = EFI_SIZE_TO_PAGES (Size);\r
267 Status = SmmInternalAllocatePages (AllocateAnyPages, PoolType, NoPages,\r
268 &Address, NeedGuard);\r
e42e9404 269 if (EFI_ERROR (Status)) {\r
270 return Status;\r
271 }\r
272\r
e63da9f0
JW
273 if (NeedGuard) {\r
274 ASSERT (VerifyMemoryGuard (Address, NoPages) == TRUE);\r
275 Address = (EFI_PHYSICAL_ADDRESS)(UINTN)AdjustPoolHeadA (\r
276 Address,\r
277 NoPages,\r
278 Size\r
279 );\r
280 }\r
281\r
e42e9404 282 PoolHdr = (POOL_HEADER*)(UINTN)Address;\r
861c8dff 283 PoolHdr->Signature = POOL_HEAD_SIGNATURE;\r
94edadf5 284 PoolHdr->Size = EFI_PAGES_TO_SIZE (NoPages);\r
e42e9404 285 PoolHdr->Available = FALSE;\r
5f4d3e17 286 PoolHdr->Type = PoolType;\r
e63da9f0
JW
287\r
288 if (HasPoolTail) {\r
289 PoolTail = HEAD_TO_TAIL (PoolHdr);\r
290 PoolTail->Signature = POOL_TAIL_SIGNATURE;\r
291 PoolTail->Size = PoolHdr->Size;\r
292 }\r
293\r
e42e9404 294 *Buffer = PoolHdr + 1;\r
295 return Status;\r
296 }\r
297\r
298 Size = (Size + MIN_POOL_SIZE - 1) >> MIN_POOL_SHIFT;\r
fbe12b79 299 PoolIndex = (UINTN) HighBitSet32 ((UINT32)Size);\r
e42e9404 300 if ((Size & (Size - 1)) != 0) {\r
301 PoolIndex++;\r
302 }\r
303\r
5f4d3e17 304 Status = InternalAllocPoolByIndex (PoolType, PoolIndex, &FreePoolHdr);\r
bf14e107
SZ
305 if (!EFI_ERROR(Status)) {\r
306 *Buffer = &FreePoolHdr->Header + 1;\r
307 }\r
e42e9404 308 return Status;\r
309}\r
310\r
84edd20b
SZ
311/**\r
312 Allocate pool of a particular type.\r
313\r
314 @param PoolType Type of pool to allocate.\r
315 @param Size The amount of pool to allocate.\r
316 @param Buffer The address to return a pointer to the allocated\r
317 pool.\r
318\r
319 @retval EFI_INVALID_PARAMETER PoolType not valid.\r
320 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.\r
321 @retval EFI_SUCCESS Pool successfully allocated.\r
322\r
323**/\r
324EFI_STATUS\r
325EFIAPI\r
326SmmAllocatePool (\r
327 IN EFI_MEMORY_TYPE PoolType,\r
328 IN UINTN Size,\r
329 OUT VOID **Buffer\r
330 )\r
331{\r
332 EFI_STATUS Status;\r
333\r
334 Status = SmmInternalAllocatePool (PoolType, Size, Buffer);\r
335 if (!EFI_ERROR (Status)) {\r
e524f680
SZ
336 SmmCoreUpdateProfile (\r
337 (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),\r
338 MemoryProfileActionAllocatePool,\r
339 PoolType,\r
340 Size,\r
341 *Buffer,\r
342 NULL\r
343 );\r
84edd20b
SZ
344 }\r
345 return Status;\r
346}\r
347\r
e42e9404 348/**\r
349 Frees pool.\r
350\r
351 @param Buffer The allocated pool entry to free.\r
352\r
353 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.\r
354 @retval EFI_SUCCESS Pool successfully freed.\r
355\r
356**/\r
357EFI_STATUS\r
358EFIAPI\r
84edd20b 359SmmInternalFreePool (\r
e42e9404 360 IN VOID *Buffer\r
361 )\r
362{\r
363 FREE_POOL_HEADER *FreePoolHdr;\r
861c8dff 364 POOL_TAIL *PoolTail;\r
e63da9f0
JW
365 BOOLEAN HasPoolTail;\r
366 BOOLEAN MemoryGuarded;\r
e42e9404 367\r
368 if (Buffer == NULL) {\r
369 return EFI_INVALID_PARAMETER;\r
370 }\r
371\r
e63da9f0
JW
372 MemoryGuarded = IsHeapGuardEnabled () &&\r
373 IsMemoryGuarded ((EFI_PHYSICAL_ADDRESS)(UINTN)Buffer);\r
374 HasPoolTail = !(MemoryGuarded &&\r
375 ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0));\r
376\r
e42e9404 377 FreePoolHdr = (FREE_POOL_HEADER*)((POOL_HEADER*)Buffer - 1);\r
861c8dff 378 ASSERT (FreePoolHdr->Header.Signature == POOL_HEAD_SIGNATURE);\r
e42e9404 379 ASSERT (!FreePoolHdr->Header.Available);\r
861c8dff
SZ
380 if (FreePoolHdr->Header.Signature != POOL_HEAD_SIGNATURE) {\r
381 return EFI_INVALID_PARAMETER;\r
382 }\r
383\r
e63da9f0
JW
384 if (HasPoolTail) {\r
385 PoolTail = HEAD_TO_TAIL (&FreePoolHdr->Header);\r
386 ASSERT (PoolTail->Signature == POOL_TAIL_SIGNATURE);\r
387 ASSERT (FreePoolHdr->Header.Size == PoolTail->Size);\r
388 if (PoolTail->Signature != POOL_TAIL_SIGNATURE) {\r
389 return EFI_INVALID_PARAMETER;\r
390 }\r
391\r
392 if (FreePoolHdr->Header.Size != PoolTail->Size) {\r
393 return EFI_INVALID_PARAMETER;\r
394 }\r
395 } else {\r
396 PoolTail = NULL;\r
861c8dff
SZ
397 }\r
398\r
e63da9f0
JW
399 if (MemoryGuarded) {\r
400 Buffer = AdjustPoolHeadF ((EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr);\r
401 return SmmInternalFreePages (\r
402 (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer,\r
403 EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size),\r
404 TRUE\r
405 );\r
861c8dff 406 }\r
e42e9404 407\r
408 if (FreePoolHdr->Header.Size > MAX_POOL_SIZE) {\r
409 ASSERT (((UINTN)FreePoolHdr & EFI_PAGE_MASK) == 0);\r
410 ASSERT ((FreePoolHdr->Header.Size & EFI_PAGE_MASK) == 0);\r
84edd20b 411 return SmmInternalFreePages (\r
e42e9404 412 (EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr,\r
e63da9f0
JW
413 EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size),\r
414 FALSE\r
e42e9404 415 );\r
416 }\r
f8f931f6 417 return InternalFreePoolByIndex (FreePoolHdr, PoolTail);\r
e42e9404 418}\r
84edd20b
SZ
419\r
420/**\r
421 Frees pool.\r
422\r
423 @param Buffer The allocated pool entry to free.\r
424\r
425 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.\r
426 @retval EFI_SUCCESS Pool successfully freed.\r
427\r
428**/\r
429EFI_STATUS\r
430EFIAPI\r
431SmmFreePool (\r
432 IN VOID *Buffer\r
433 )\r
434{\r
435 EFI_STATUS Status;\r
436\r
437 Status = SmmInternalFreePool (Buffer);\r
438 if (!EFI_ERROR (Status)) {\r
e524f680
SZ
439 SmmCoreUpdateProfile (\r
440 (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),\r
441 MemoryProfileActionFreePool,\r
442 EfiMaxMemoryType,\r
443 0,\r
444 Buffer,\r
445 NULL\r
446 );\r
84edd20b
SZ
447 }\r
448 return Status;\r
449}\r