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