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