]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/PiSmmCore/Pool.c
MdeModulePkg/SmmCore: Add Context in SmiHandlerProfileUnregister.
[mirror_edk2.git] / MdeModulePkg / Core / PiSmmCore / Pool.c
CommitLineData
e42e9404 1/** @file\r
2 SMM Memory pool management functions.\r
3\r
e524f680 4 Copyright (c) 2009 - 2016, 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
136 EFI_PHYSICAL_ADDRESS Address;\r
5f4d3e17
JY
137 SMM_POOL_TYPE SmmPoolType;\r
138\r
139 SmmPoolType = UefiMemoryTypeToSmmPoolType(PoolType);\r
e42e9404 140\r
52c0d06b 141 ASSERT (PoolIndex <= MAX_POOL_INDEX);\r
e42e9404 142 Status = EFI_SUCCESS;\r
bf14e107 143 Hdr = NULL;\r
e42e9404 144 if (PoolIndex == MAX_POOL_INDEX) {\r
5f4d3e17 145 Status = SmmInternalAllocatePages (AllocateAnyPages, PoolType, EFI_SIZE_TO_PAGES (MAX_POOL_SIZE << 1), &Address);\r
84edd20b 146 if (EFI_ERROR (Status)) {\r
5b422a7b 147 return EFI_OUT_OF_RESOURCES;\r
e42e9404 148 }\r
84edd20b 149 Hdr = (FREE_POOL_HEADER *) (UINTN) Address;\r
5f4d3e17
JY
150 } else if (!IsListEmpty (&mSmmPoolLists[SmmPoolType][PoolIndex])) {\r
151 Hdr = BASE_CR (GetFirstNode (&mSmmPoolLists[SmmPoolType][PoolIndex]), FREE_POOL_HEADER, Link);\r
e42e9404 152 RemoveEntryList (&Hdr->Link);\r
153 } else {\r
5f4d3e17 154 Status = InternalAllocPoolByIndex (PoolType, PoolIndex + 1, &Hdr);\r
e42e9404 155 if (!EFI_ERROR (Status)) {\r
156 Hdr->Header.Size >>= 1;\r
157 Hdr->Header.Available = TRUE;\r
5f4d3e17
JY
158 Hdr->Header.Type = PoolType;\r
159 InsertHeadList (&mSmmPoolLists[SmmPoolType][PoolIndex], &Hdr->Link);\r
e42e9404 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
5f4d3e17 167 Hdr->Header.Type = PoolType;\r
e42e9404 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
5f4d3e17
JY
187 UINTN PoolIndex;\r
188 SMM_POOL_TYPE SmmPoolType;\r
e42e9404 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
5f4d3e17
JY
194 SmmPoolType = UefiMemoryTypeToSmmPoolType(FreePoolHdr->Header.Type);\r
195\r
fbe12b79 196 PoolIndex = (UINTN) (HighBitSet32 ((UINT32)FreePoolHdr->Header.Size) - MIN_POOL_SHIFT);\r
e42e9404 197 FreePoolHdr->Header.Available = TRUE;\r
5b422a7b 198 ASSERT (PoolIndex < MAX_POOL_INDEX);\r
5f4d3e17 199 InsertHeadList (&mSmmPoolLists[SmmPoolType][PoolIndex], &FreePoolHdr->Link);\r
e42e9404 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
84edd20b 218SmmInternalAllocatePool (\r
e42e9404 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
e42e9404 235 Size += sizeof (*PoolHdr);\r
236 if (Size > MAX_POOL_SIZE) {\r
237 Size = EFI_SIZE_TO_PAGES (Size);\r
84edd20b 238 Status = SmmInternalAllocatePages (AllocateAnyPages, PoolType, Size, &Address);\r
e42e9404 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
5f4d3e17 246 PoolHdr->Type = PoolType;\r
e42e9404 247 *Buffer = PoolHdr + 1;\r
248 return Status;\r
249 }\r
250\r
251 Size = (Size + MIN_POOL_SIZE - 1) >> MIN_POOL_SHIFT;\r
fbe12b79 252 PoolIndex = (UINTN) HighBitSet32 ((UINT32)Size);\r
e42e9404 253 if ((Size & (Size - 1)) != 0) {\r
254 PoolIndex++;\r
255 }\r
256\r
5f4d3e17 257 Status = InternalAllocPoolByIndex (PoolType, PoolIndex, &FreePoolHdr);\r
bf14e107
SZ
258 if (!EFI_ERROR(Status)) {\r
259 *Buffer = &FreePoolHdr->Header + 1;\r
260 }\r
e42e9404 261 return Status;\r
262}\r
263\r
84edd20b
SZ
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
e524f680
SZ
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
84edd20b
SZ
297 }\r
298 return Status;\r
299}\r
300\r
e42e9404 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
84edd20b 312SmmInternalFreePool (\r
e42e9404 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
84edd20b 328 return SmmInternalFreePages (\r
e42e9404 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
84edd20b
SZ
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
e524f680
SZ
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
84edd20b
SZ
363 }\r
364 return Status;\r
365}\r