]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Core/PiSmmCore/Pool.c
MdeModulePkg/PiSmmCore: Implement heap guard feature for SMM mode
[mirror_edk2.git] / MdeModulePkg / Core / PiSmmCore / Pool.c
... / ...
CommitLineData
1/** @file\r
2 SMM Memory pool management functions.\r
3\r
4 Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.<BR>\r
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
17LIST_ENTRY mSmmPoolLists[SmmPoolTypeMax][MAX_POOL_INDEX];\r
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
23\r
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
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
61 UINTN Index;\r
62 EFI_STATUS Status;\r
63 UINTN SmmPoolTypeIndex;\r
64 EFI_LOAD_FIXED_ADDRESS_CONFIGURATION_TABLE *LMFAConfigurationTable;\r
65\r
66 //\r
67 // Initialize Pool list\r
68 //\r
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
73 }\r
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
81 }\r
82\r
83 //\r
84 // Add Free SMRAM regions\r
85 // Need add Free memory at first, to let gSmmMemoryMap record data\r
86 //\r
87 for (Index = 0; Index < SmramRangeCount; Index++) {\r
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
99 //\r
100 // Add the allocated SMRAM regions\r
101 //\r
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
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
113\r
114}\r
115\r
116/**\r
117 Internal Function. Allocate a pool by specified PoolIndex.\r
118\r
119 @param PoolType Type of pool to allocate.\r
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
129 IN EFI_MEMORY_TYPE PoolType,\r
130 IN UINTN PoolIndex,\r
131 OUT FREE_POOL_HEADER **FreePoolHdr\r
132 )\r
133{\r
134 EFI_STATUS Status;\r
135 FREE_POOL_HEADER *Hdr;\r
136 POOL_TAIL *Tail;\r
137 EFI_PHYSICAL_ADDRESS Address;\r
138 SMM_POOL_TYPE SmmPoolType;\r
139\r
140 Address = 0;\r
141 SmmPoolType = UefiMemoryTypeToSmmPoolType(PoolType);\r
142\r
143 ASSERT (PoolIndex <= MAX_POOL_INDEX);\r
144 Status = EFI_SUCCESS;\r
145 Hdr = NULL;\r
146 if (PoolIndex == MAX_POOL_INDEX) {\r
147 Status = SmmInternalAllocatePages (AllocateAnyPages, PoolType,
148 EFI_SIZE_TO_PAGES (MAX_POOL_SIZE << 1),
149 &Address, FALSE);
150 if (EFI_ERROR (Status)) {\r
151 return EFI_OUT_OF_RESOURCES;\r
152 }\r
153 Hdr = (FREE_POOL_HEADER *) (UINTN) Address;\r
154 } else if (!IsListEmpty (&mSmmPoolLists[SmmPoolType][PoolIndex])) {\r
155 Hdr = BASE_CR (GetFirstNode (&mSmmPoolLists[SmmPoolType][PoolIndex]), FREE_POOL_HEADER, Link);\r
156 RemoveEntryList (&Hdr->Link);\r
157 } else {\r
158 Status = InternalAllocPoolByIndex (PoolType, PoolIndex + 1, &Hdr);\r
159 if (!EFI_ERROR (Status)) {\r
160 Hdr->Header.Signature = 0;\r
161 Hdr->Header.Size >>= 1;\r
162 Hdr->Header.Available = TRUE;\r
163 Hdr->Header.Type = 0;\r
164 Tail = HEAD_TO_TAIL(&Hdr->Header);\r
165 Tail->Signature = 0;\r
166 Tail->Size = 0;\r
167 InsertHeadList (&mSmmPoolLists[SmmPoolType][PoolIndex], &Hdr->Link);\r
168 Hdr = (FREE_POOL_HEADER*)((UINT8*)Hdr + Hdr->Header.Size);\r
169 }\r
170 }\r
171\r
172 if (!EFI_ERROR (Status)) {\r
173 Hdr->Header.Signature = POOL_HEAD_SIGNATURE;\r
174 Hdr->Header.Size = MIN_POOL_SIZE << PoolIndex;\r
175 Hdr->Header.Available = FALSE;\r
176 Hdr->Header.Type = PoolType;\r
177 Tail = HEAD_TO_TAIL(&Hdr->Header);\r
178 Tail->Signature = POOL_TAIL_SIGNATURE;\r
179 Tail->Size = Hdr->Header.Size;\r
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
190 @param PoolTail The pointer to the pool tail.\r
191\r
192 @retval EFI_SUCCESS Pool successfully freed.\r
193\r
194**/\r
195EFI_STATUS\r
196InternalFreePoolByIndex (\r
197 IN FREE_POOL_HEADER *FreePoolHdr,\r
198 IN POOL_TAIL *PoolTail\r
199 )\r
200{\r
201 UINTN PoolIndex;\r
202 SMM_POOL_TYPE SmmPoolType;\r
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
208 SmmPoolType = UefiMemoryTypeToSmmPoolType(FreePoolHdr->Header.Type);\r
209\r
210 PoolIndex = (UINTN) (HighBitSet32 ((UINT32)FreePoolHdr->Header.Size) - MIN_POOL_SHIFT);\r
211 FreePoolHdr->Header.Signature = 0;\r
212 FreePoolHdr->Header.Available = TRUE;\r
213 FreePoolHdr->Header.Type = 0;\r
214 PoolTail->Signature = 0;\r
215 PoolTail->Size = 0;\r
216 ASSERT (PoolIndex < MAX_POOL_INDEX);\r
217 InsertHeadList (&mSmmPoolLists[SmmPoolType][PoolIndex], &FreePoolHdr->Link);\r
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
236SmmInternalAllocatePool (\r
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
243 POOL_TAIL *PoolTail;\r
244 FREE_POOL_HEADER *FreePoolHdr;\r
245 EFI_STATUS Status;\r
246 EFI_PHYSICAL_ADDRESS Address;\r
247 UINTN PoolIndex;\r
248 BOOLEAN HasPoolTail;
249 BOOLEAN NeedGuard;
250 UINTN NoPages;
251\r
252 Address = 0;\r
253\r
254 if (PoolType != EfiRuntimeServicesCode &&\r
255 PoolType != EfiRuntimeServicesData) {\r
256 return EFI_INVALID_PARAMETER;\r
257 }\r
258\r
259 NeedGuard = IsPoolTypeToGuard (PoolType);
260 HasPoolTail = !(NeedGuard &&
261 ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0));
262
263 //\r
264 // Adjust the size by the pool header & tail overhead\r
265 //\r
266 Size += POOL_OVERHEAD;\r
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);
275 if (EFI_ERROR (Status)) {\r
276 return Status;\r
277 }\r
278\r
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
288 PoolHdr = (POOL_HEADER*)(UINTN)Address;\r
289 PoolHdr->Signature = POOL_HEAD_SIGNATURE;\r
290 PoolHdr->Size = Size;
291 PoolHdr->Available = FALSE;\r
292 PoolHdr->Type = PoolType;\r
293
294 if (HasPoolTail) {
295 PoolTail = HEAD_TO_TAIL (PoolHdr);
296 PoolTail->Signature = POOL_TAIL_SIGNATURE;
297 PoolTail->Size = PoolHdr->Size;
298 }
299
300 *Buffer = PoolHdr + 1;\r
301 return Status;\r
302 }\r
303\r
304 Size = (Size + MIN_POOL_SIZE - 1) >> MIN_POOL_SHIFT;\r
305 PoolIndex = (UINTN) HighBitSet32 ((UINT32)Size);\r
306 if ((Size & (Size - 1)) != 0) {\r
307 PoolIndex++;\r
308 }\r
309\r
310 Status = InternalAllocPoolByIndex (PoolType, PoolIndex, &FreePoolHdr);\r
311 if (!EFI_ERROR(Status)) {\r
312 *Buffer = &FreePoolHdr->Header + 1;\r
313 }\r
314 return Status;\r
315}\r
316\r
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
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
350 }\r
351 return Status;\r
352}\r
353\r
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
365SmmInternalFreePool (\r
366 IN VOID *Buffer\r
367 )\r
368{\r
369 FREE_POOL_HEADER *FreePoolHdr;\r
370 POOL_TAIL *PoolTail;\r
371 BOOLEAN HasPoolTail;
372 BOOLEAN MemoryGuarded;
373\r
374 if (Buffer == NULL) {\r
375 return EFI_INVALID_PARAMETER;\r
376 }\r
377\r
378 MemoryGuarded = IsHeapGuardEnabled () &&
379 IsMemoryGuarded ((EFI_PHYSICAL_ADDRESS)(UINTN)Buffer);
380 HasPoolTail = !(MemoryGuarded &&
381 ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0));
382
383 FreePoolHdr = (FREE_POOL_HEADER*)((POOL_HEADER*)Buffer - 1);\r
384 ASSERT (FreePoolHdr->Header.Signature == POOL_HEAD_SIGNATURE);\r
385 ASSERT (!FreePoolHdr->Header.Available);\r
386 if (FreePoolHdr->Header.Signature != POOL_HEAD_SIGNATURE) {\r
387 return EFI_INVALID_PARAMETER;\r
388 }\r
389\r
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;
403 }\r
404\r
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 );
412 }\r
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
417 return SmmInternalFreePages (\r
418 (EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr,\r
419 EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size),
420 FALSE
421 );\r
422 }\r
423 return InternalFreePoolByIndex (FreePoolHdr, PoolTail);\r
424}\r
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
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
453 }\r
454 return Status;\r
455}\r