]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Core/PiSmmCore/Pool.c
MdeModulePkg/SmmCore: Add Context in SmiHandlerProfileUnregister.
[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 - 2016, 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 EFI_PHYSICAL_ADDRESS Address;\r
137 SMM_POOL_TYPE SmmPoolType;\r
138\r
139 SmmPoolType = UefiMemoryTypeToSmmPoolType(PoolType);\r
140\r
141 ASSERT (PoolIndex <= MAX_POOL_INDEX);\r
142 Status = EFI_SUCCESS;\r
143 Hdr = NULL;\r
144 if (PoolIndex == MAX_POOL_INDEX) {\r
145 Status = SmmInternalAllocatePages (AllocateAnyPages, PoolType, EFI_SIZE_TO_PAGES (MAX_POOL_SIZE << 1), &Address);\r
146 if (EFI_ERROR (Status)) {\r
147 return EFI_OUT_OF_RESOURCES;\r
148 }\r
149 Hdr = (FREE_POOL_HEADER *) (UINTN) Address;\r
150 } else if (!IsListEmpty (&mSmmPoolLists[SmmPoolType][PoolIndex])) {\r
151 Hdr = BASE_CR (GetFirstNode (&mSmmPoolLists[SmmPoolType][PoolIndex]), FREE_POOL_HEADER, Link);\r
152 RemoveEntryList (&Hdr->Link);\r
153 } else {\r
154 Status = InternalAllocPoolByIndex (PoolType, PoolIndex + 1, &Hdr);\r
155 if (!EFI_ERROR (Status)) {\r
156 Hdr->Header.Size >>= 1;\r
157 Hdr->Header.Available = TRUE;\r
158 Hdr->Header.Type = PoolType;\r
159 InsertHeadList (&mSmmPoolLists[SmmPoolType][PoolIndex], &Hdr->Link);\r
160 Hdr = (FREE_POOL_HEADER*)((UINT8*)Hdr + Hdr->Header.Size);\r
161 }\r
162 }\r
163\r
164 if (!EFI_ERROR (Status)) {\r
165 Hdr->Header.Size = MIN_POOL_SIZE << PoolIndex;\r
166 Hdr->Header.Available = FALSE;\r
167 Hdr->Header.Type = PoolType;\r
168 }\r
169\r
170 *FreePoolHdr = Hdr;\r
171 return Status;\r
172}\r
173\r
174/**\r
175 Internal Function. Free a pool by specified PoolIndex.\r
176\r
177 @param FreePoolHdr The pool to free.\r
178\r
179 @retval EFI_SUCCESS Pool successfully freed.\r
180\r
181**/\r
182EFI_STATUS\r
183InternalFreePoolByIndex (\r
184 IN FREE_POOL_HEADER *FreePoolHdr\r
185 )\r
186{\r
187 UINTN PoolIndex;\r
188 SMM_POOL_TYPE SmmPoolType;\r
189\r
190 ASSERT ((FreePoolHdr->Header.Size & (FreePoolHdr->Header.Size - 1)) == 0);\r
191 ASSERT (((UINTN)FreePoolHdr & (FreePoolHdr->Header.Size - 1)) == 0);\r
192 ASSERT (FreePoolHdr->Header.Size >= MIN_POOL_SIZE);\r
193\r
194 SmmPoolType = UefiMemoryTypeToSmmPoolType(FreePoolHdr->Header.Type);\r
195\r
196 PoolIndex = (UINTN) (HighBitSet32 ((UINT32)FreePoolHdr->Header.Size) - MIN_POOL_SHIFT);\r
197 FreePoolHdr->Header.Available = TRUE;\r
198 ASSERT (PoolIndex < MAX_POOL_INDEX);\r
199 InsertHeadList (&mSmmPoolLists[SmmPoolType][PoolIndex], &FreePoolHdr->Link);\r
200 return EFI_SUCCESS;\r
201}\r
202\r
203/**\r
204 Allocate pool of a particular type.\r
205\r
206 @param PoolType Type of pool to allocate.\r
207 @param Size The amount of pool to allocate.\r
208 @param Buffer The address to return a pointer to the allocated\r
209 pool.\r
210\r
211 @retval EFI_INVALID_PARAMETER PoolType not valid.\r
212 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.\r
213 @retval EFI_SUCCESS Pool successfully allocated.\r
214\r
215**/\r
216EFI_STATUS\r
217EFIAPI\r
218SmmInternalAllocatePool (\r
219 IN EFI_MEMORY_TYPE PoolType,\r
220 IN UINTN Size,\r
221 OUT VOID **Buffer\r
222 )\r
223{\r
224 POOL_HEADER *PoolHdr;\r
225 FREE_POOL_HEADER *FreePoolHdr;\r
226 EFI_STATUS Status;\r
227 EFI_PHYSICAL_ADDRESS Address;\r
228 UINTN PoolIndex;\r
229\r
230 if (PoolType != EfiRuntimeServicesCode &&\r
231 PoolType != EfiRuntimeServicesData) {\r
232 return EFI_INVALID_PARAMETER;\r
233 }\r
234\r
235 Size += sizeof (*PoolHdr);\r
236 if (Size > MAX_POOL_SIZE) {\r
237 Size = EFI_SIZE_TO_PAGES (Size);\r
238 Status = SmmInternalAllocatePages (AllocateAnyPages, PoolType, Size, &Address);\r
239 if (EFI_ERROR (Status)) {\r
240 return Status;\r
241 }\r
242\r
243 PoolHdr = (POOL_HEADER*)(UINTN)Address;\r
244 PoolHdr->Size = EFI_PAGES_TO_SIZE (Size);\r
245 PoolHdr->Available = FALSE;\r
246 PoolHdr->Type = PoolType;\r
247 *Buffer = PoolHdr + 1;\r
248 return Status;\r
249 }\r
250\r
251 Size = (Size + MIN_POOL_SIZE - 1) >> MIN_POOL_SHIFT;\r
252 PoolIndex = (UINTN) HighBitSet32 ((UINT32)Size);\r
253 if ((Size & (Size - 1)) != 0) {\r
254 PoolIndex++;\r
255 }\r
256\r
257 Status = InternalAllocPoolByIndex (PoolType, PoolIndex, &FreePoolHdr);\r
258 if (!EFI_ERROR(Status)) {\r
259 *Buffer = &FreePoolHdr->Header + 1;\r
260 }\r
261 return Status;\r
262}\r
263\r
264/**\r
265 Allocate pool of a particular type.\r
266\r
267 @param PoolType Type of pool to allocate.\r
268 @param Size The amount of pool to allocate.\r
269 @param Buffer The address to return a pointer to the allocated\r
270 pool.\r
271\r
272 @retval EFI_INVALID_PARAMETER PoolType not valid.\r
273 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.\r
274 @retval EFI_SUCCESS Pool successfully allocated.\r
275\r
276**/\r
277EFI_STATUS\r
278EFIAPI\r
279SmmAllocatePool (\r
280 IN EFI_MEMORY_TYPE PoolType,\r
281 IN UINTN Size,\r
282 OUT VOID **Buffer\r
283 )\r
284{\r
285 EFI_STATUS Status;\r
286\r
287 Status = SmmInternalAllocatePool (PoolType, Size, Buffer);\r
288 if (!EFI_ERROR (Status)) {\r
289 SmmCoreUpdateProfile (\r
290 (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),\r
291 MemoryProfileActionAllocatePool,\r
292 PoolType,\r
293 Size,\r
294 *Buffer,\r
295 NULL\r
296 );\r
297 }\r
298 return Status;\r
299}\r
300\r
301/**\r
302 Frees pool.\r
303\r
304 @param Buffer The allocated pool entry to free.\r
305\r
306 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.\r
307 @retval EFI_SUCCESS Pool successfully freed.\r
308\r
309**/\r
310EFI_STATUS\r
311EFIAPI\r
312SmmInternalFreePool (\r
313 IN VOID *Buffer\r
314 )\r
315{\r
316 FREE_POOL_HEADER *FreePoolHdr;\r
317\r
318 if (Buffer == NULL) {\r
319 return EFI_INVALID_PARAMETER;\r
320 }\r
321\r
322 FreePoolHdr = (FREE_POOL_HEADER*)((POOL_HEADER*)Buffer - 1);\r
323 ASSERT (!FreePoolHdr->Header.Available);\r
324\r
325 if (FreePoolHdr->Header.Size > MAX_POOL_SIZE) {\r
326 ASSERT (((UINTN)FreePoolHdr & EFI_PAGE_MASK) == 0);\r
327 ASSERT ((FreePoolHdr->Header.Size & EFI_PAGE_MASK) == 0);\r
328 return SmmInternalFreePages (\r
329 (EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr,\r
330 EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size)\r
331 );\r
332 }\r
333 return InternalFreePoolByIndex (FreePoolHdr);\r
334}\r
335\r
336/**\r
337 Frees pool.\r
338\r
339 @param Buffer The allocated pool entry to free.\r
340\r
341 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.\r
342 @retval EFI_SUCCESS Pool successfully freed.\r
343\r
344**/\r
345EFI_STATUS\r
346EFIAPI\r
347SmmFreePool (\r
348 IN VOID *Buffer\r
349 )\r
350{\r
351 EFI_STATUS Status;\r
352\r
353 Status = SmmInternalFreePool (Buffer);\r
354 if (!EFI_ERROR (Status)) {\r
355 SmmCoreUpdateProfile (\r
356 (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),\r
357 MemoryProfileActionFreePool,\r
358 EfiMaxMemoryType,\r
359 0,\r
360 Buffer,\r
361 NULL\r
362 );\r
363 }\r
364 return Status;\r
365}\r