]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Core/PiSmmCore/Pool.c
MdeModulePkg: remove PE/COFF header workaround for ELILO on IPF
[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 - 2018, 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,\r
148 EFI_SIZE_TO_PAGES (MAX_POOL_SIZE << 1),\r
149 &Address, FALSE);\r
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;\r
249 BOOLEAN NeedGuard;\r
250 UINTN NoPages;\r
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);\r
260 HasPoolTail = !(NeedGuard &&\r
261 ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0));\r
262\r
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) {\r
268 if (!HasPoolTail) {\r
269 Size -= sizeof (POOL_TAIL);\r
270 }\r
271\r
272 NoPages = EFI_SIZE_TO_PAGES (Size);\r
273 Status = SmmInternalAllocatePages (AllocateAnyPages, PoolType, NoPages,\r
274 &Address, NeedGuard);\r
275 if (EFI_ERROR (Status)) {\r
276 return Status;\r
277 }\r
278\r
279 if (NeedGuard) {\r
280 ASSERT (VerifyMemoryGuard (Address, NoPages) == TRUE);\r
281 Address = (EFI_PHYSICAL_ADDRESS)(UINTN)AdjustPoolHeadA (\r
282 Address,\r
283 NoPages,\r
284 Size\r
285 );\r
286 }\r
287\r
288 PoolHdr = (POOL_HEADER*)(UINTN)Address;\r
289 PoolHdr->Signature = POOL_HEAD_SIGNATURE;\r
290 PoolHdr->Size = EFI_PAGES_TO_SIZE (NoPages);\r
291 PoolHdr->Available = FALSE;\r
292 PoolHdr->Type = PoolType;\r
293\r
294 if (HasPoolTail) {\r
295 PoolTail = HEAD_TO_TAIL (PoolHdr);\r
296 PoolTail->Signature = POOL_TAIL_SIGNATURE;\r
297 PoolTail->Size = PoolHdr->Size;\r
298 }\r
299\r
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;\r
372 BOOLEAN MemoryGuarded;\r
373\r
374 if (Buffer == NULL) {\r
375 return EFI_INVALID_PARAMETER;\r
376 }\r
377\r
378 MemoryGuarded = IsHeapGuardEnabled () &&\r
379 IsMemoryGuarded ((EFI_PHYSICAL_ADDRESS)(UINTN)Buffer);\r
380 HasPoolTail = !(MemoryGuarded &&\r
381 ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0));\r
382\r
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) {\r
391 PoolTail = HEAD_TO_TAIL (&FreePoolHdr->Header);\r
392 ASSERT (PoolTail->Signature == POOL_TAIL_SIGNATURE);\r
393 ASSERT (FreePoolHdr->Header.Size == PoolTail->Size);\r
394 if (PoolTail->Signature != POOL_TAIL_SIGNATURE) {\r
395 return EFI_INVALID_PARAMETER;\r
396 }\r
397\r
398 if (FreePoolHdr->Header.Size != PoolTail->Size) {\r
399 return EFI_INVALID_PARAMETER;\r
400 }\r
401 } else {\r
402 PoolTail = NULL;\r
403 }\r
404\r
405 if (MemoryGuarded) {\r
406 Buffer = AdjustPoolHeadF ((EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr);\r
407 return SmmInternalFreePages (\r
408 (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer,\r
409 EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size),\r
410 TRUE\r
411 );\r
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),\r
420 FALSE\r
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