]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/PiSmmCore/Pool.c
UefiCpuPkg/PiSmmCpuDxeSmm: Add SmmMemoryAttribute protocol
[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
5f4d3e17 147 Status = SmmInternalAllocatePages (AllocateAnyPages, PoolType, EFI_SIZE_TO_PAGES (MAX_POOL_SIZE << 1), &Address);\r
84edd20b 148 if (EFI_ERROR (Status)) {\r
5b422a7b 149 return EFI_OUT_OF_RESOURCES;\r
e42e9404 150 }\r
84edd20b 151 Hdr = (FREE_POOL_HEADER *) (UINTN) Address;\r
5f4d3e17
JY
152 } else if (!IsListEmpty (&mSmmPoolLists[SmmPoolType][PoolIndex])) {\r
153 Hdr = BASE_CR (GetFirstNode (&mSmmPoolLists[SmmPoolType][PoolIndex]), FREE_POOL_HEADER, Link);\r
e42e9404 154 RemoveEntryList (&Hdr->Link);\r
155 } else {\r
5f4d3e17 156 Status = InternalAllocPoolByIndex (PoolType, PoolIndex + 1, &Hdr);\r
e42e9404 157 if (!EFI_ERROR (Status)) {\r
861c8dff 158 Hdr->Header.Signature = 0;\r
e42e9404 159 Hdr->Header.Size >>= 1;\r
160 Hdr->Header.Available = TRUE;\r
861c8dff
SZ
161 Hdr->Header.Type = 0;\r
162 Tail = HEAD_TO_TAIL(&Hdr->Header);\r
163 Tail->Signature = 0;\r
164 Tail->Size = 0;\r
5f4d3e17 165 InsertHeadList (&mSmmPoolLists[SmmPoolType][PoolIndex], &Hdr->Link);\r
e42e9404 166 Hdr = (FREE_POOL_HEADER*)((UINT8*)Hdr + Hdr->Header.Size);\r
167 }\r
168 }\r
169\r
170 if (!EFI_ERROR (Status)) {\r
861c8dff 171 Hdr->Header.Signature = POOL_HEAD_SIGNATURE;\r
e42e9404 172 Hdr->Header.Size = MIN_POOL_SIZE << PoolIndex;\r
173 Hdr->Header.Available = FALSE;\r
5f4d3e17 174 Hdr->Header.Type = PoolType;\r
861c8dff
SZ
175 Tail = HEAD_TO_TAIL(&Hdr->Header);\r
176 Tail->Signature = POOL_TAIL_SIGNATURE;\r
177 Tail->Size = Hdr->Header.Size;\r
e42e9404 178 }\r
179\r
180 *FreePoolHdr = Hdr;\r
181 return Status;\r
182}\r
183\r
184/**\r
185 Internal Function. Free a pool by specified PoolIndex.\r
186\r
187 @param FreePoolHdr The pool to free.\r
f8f931f6 188 @param PoolTail The pointer to the pool tail.\r
e42e9404 189\r
190 @retval EFI_SUCCESS Pool successfully freed.\r
191\r
192**/\r
193EFI_STATUS\r
194InternalFreePoolByIndex (\r
f8f931f6
HW
195 IN FREE_POOL_HEADER *FreePoolHdr,\r
196 IN POOL_TAIL *PoolTail\r
e42e9404 197 )\r
198{\r
5f4d3e17
JY
199 UINTN PoolIndex;\r
200 SMM_POOL_TYPE SmmPoolType;\r
e42e9404 201\r
202 ASSERT ((FreePoolHdr->Header.Size & (FreePoolHdr->Header.Size - 1)) == 0);\r
203 ASSERT (((UINTN)FreePoolHdr & (FreePoolHdr->Header.Size - 1)) == 0);\r
204 ASSERT (FreePoolHdr->Header.Size >= MIN_POOL_SIZE);\r
205\r
5f4d3e17
JY
206 SmmPoolType = UefiMemoryTypeToSmmPoolType(FreePoolHdr->Header.Type);\r
207\r
fbe12b79 208 PoolIndex = (UINTN) (HighBitSet32 ((UINT32)FreePoolHdr->Header.Size) - MIN_POOL_SHIFT);\r
861c8dff 209 FreePoolHdr->Header.Signature = 0;\r
e42e9404 210 FreePoolHdr->Header.Available = TRUE;\r
861c8dff 211 FreePoolHdr->Header.Type = 0;\r
861c8dff
SZ
212 PoolTail->Signature = 0;\r
213 PoolTail->Size = 0;\r
5b422a7b 214 ASSERT (PoolIndex < MAX_POOL_INDEX);\r
5f4d3e17 215 InsertHeadList (&mSmmPoolLists[SmmPoolType][PoolIndex], &FreePoolHdr->Link);\r
e42e9404 216 return EFI_SUCCESS;\r
217}\r
218\r
219/**\r
220 Allocate pool of a particular type.\r
221\r
222 @param PoolType Type of pool to allocate.\r
223 @param Size The amount of pool to allocate.\r
224 @param Buffer The address to return a pointer to the allocated\r
225 pool.\r
226\r
227 @retval EFI_INVALID_PARAMETER PoolType not valid.\r
228 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.\r
229 @retval EFI_SUCCESS Pool successfully allocated.\r
230\r
231**/\r
232EFI_STATUS\r
233EFIAPI\r
84edd20b 234SmmInternalAllocatePool (\r
e42e9404 235 IN EFI_MEMORY_TYPE PoolType,\r
236 IN UINTN Size,\r
237 OUT VOID **Buffer\r
238 )\r
239{\r
240 POOL_HEADER *PoolHdr;\r
861c8dff 241 POOL_TAIL *PoolTail;\r
e42e9404 242 FREE_POOL_HEADER *FreePoolHdr;\r
243 EFI_STATUS Status;\r
244 EFI_PHYSICAL_ADDRESS Address;\r
245 UINTN PoolIndex;\r
246\r
89558f16
HW
247 Address = 0;\r
248\r
e42e9404 249 if (PoolType != EfiRuntimeServicesCode &&\r
250 PoolType != EfiRuntimeServicesData) {\r
251 return EFI_INVALID_PARAMETER;\r
252 }\r
253\r
861c8dff
SZ
254 //\r
255 // Adjust the size by the pool header & tail overhead\r
256 //\r
257 Size += POOL_OVERHEAD;\r
e42e9404 258 if (Size > MAX_POOL_SIZE) {\r
259 Size = EFI_SIZE_TO_PAGES (Size);\r
84edd20b 260 Status = SmmInternalAllocatePages (AllocateAnyPages, PoolType, Size, &Address);\r
e42e9404 261 if (EFI_ERROR (Status)) {\r
262 return Status;\r
263 }\r
264\r
265 PoolHdr = (POOL_HEADER*)(UINTN)Address;\r
861c8dff 266 PoolHdr->Signature = POOL_HEAD_SIGNATURE;\r
e42e9404 267 PoolHdr->Size = EFI_PAGES_TO_SIZE (Size);\r
268 PoolHdr->Available = FALSE;\r
5f4d3e17 269 PoolHdr->Type = PoolType;\r
861c8dff
SZ
270 PoolTail = HEAD_TO_TAIL(PoolHdr);\r
271 PoolTail->Signature = POOL_TAIL_SIGNATURE;\r
272 PoolTail->Size = PoolHdr->Size;\r
e42e9404 273 *Buffer = PoolHdr + 1;\r
274 return Status;\r
275 }\r
276\r
277 Size = (Size + MIN_POOL_SIZE - 1) >> MIN_POOL_SHIFT;\r
fbe12b79 278 PoolIndex = (UINTN) HighBitSet32 ((UINT32)Size);\r
e42e9404 279 if ((Size & (Size - 1)) != 0) {\r
280 PoolIndex++;\r
281 }\r
282\r
5f4d3e17 283 Status = InternalAllocPoolByIndex (PoolType, PoolIndex, &FreePoolHdr);\r
bf14e107
SZ
284 if (!EFI_ERROR(Status)) {\r
285 *Buffer = &FreePoolHdr->Header + 1;\r
286 }\r
e42e9404 287 return Status;\r
288}\r
289\r
84edd20b
SZ
290/**\r
291 Allocate pool of a particular type.\r
292\r
293 @param PoolType Type of pool to allocate.\r
294 @param Size The amount of pool to allocate.\r
295 @param Buffer The address to return a pointer to the allocated\r
296 pool.\r
297\r
298 @retval EFI_INVALID_PARAMETER PoolType not valid.\r
299 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.\r
300 @retval EFI_SUCCESS Pool successfully allocated.\r
301\r
302**/\r
303EFI_STATUS\r
304EFIAPI\r
305SmmAllocatePool (\r
306 IN EFI_MEMORY_TYPE PoolType,\r
307 IN UINTN Size,\r
308 OUT VOID **Buffer\r
309 )\r
310{\r
311 EFI_STATUS Status;\r
312\r
313 Status = SmmInternalAllocatePool (PoolType, Size, Buffer);\r
314 if (!EFI_ERROR (Status)) {\r
e524f680
SZ
315 SmmCoreUpdateProfile (\r
316 (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),\r
317 MemoryProfileActionAllocatePool,\r
318 PoolType,\r
319 Size,\r
320 *Buffer,\r
321 NULL\r
322 );\r
84edd20b
SZ
323 }\r
324 return Status;\r
325}\r
326\r
e42e9404 327/**\r
328 Frees pool.\r
329\r
330 @param Buffer The allocated pool entry to free.\r
331\r
332 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.\r
333 @retval EFI_SUCCESS Pool successfully freed.\r
334\r
335**/\r
336EFI_STATUS\r
337EFIAPI\r
84edd20b 338SmmInternalFreePool (\r
e42e9404 339 IN VOID *Buffer\r
340 )\r
341{\r
342 FREE_POOL_HEADER *FreePoolHdr;\r
861c8dff 343 POOL_TAIL *PoolTail;\r
e42e9404 344\r
345 if (Buffer == NULL) {\r
346 return EFI_INVALID_PARAMETER;\r
347 }\r
348\r
349 FreePoolHdr = (FREE_POOL_HEADER*)((POOL_HEADER*)Buffer - 1);\r
861c8dff 350 ASSERT (FreePoolHdr->Header.Signature == POOL_HEAD_SIGNATURE);\r
e42e9404 351 ASSERT (!FreePoolHdr->Header.Available);\r
861c8dff
SZ
352 PoolTail = HEAD_TO_TAIL(&FreePoolHdr->Header);\r
353 ASSERT (PoolTail->Signature == POOL_TAIL_SIGNATURE);\r
354 ASSERT (FreePoolHdr->Header.Size == PoolTail->Size);\r
355\r
356 if (FreePoolHdr->Header.Signature != POOL_HEAD_SIGNATURE) {\r
357 return EFI_INVALID_PARAMETER;\r
358 }\r
359\r
360 if (PoolTail->Signature != POOL_TAIL_SIGNATURE) {\r
361 return EFI_INVALID_PARAMETER;\r
362 }\r
363\r
364 if (FreePoolHdr->Header.Size != PoolTail->Size) {\r
365 return EFI_INVALID_PARAMETER;\r
366 }\r
e42e9404 367\r
368 if (FreePoolHdr->Header.Size > MAX_POOL_SIZE) {\r
369 ASSERT (((UINTN)FreePoolHdr & EFI_PAGE_MASK) == 0);\r
370 ASSERT ((FreePoolHdr->Header.Size & EFI_PAGE_MASK) == 0);\r
84edd20b 371 return SmmInternalFreePages (\r
e42e9404 372 (EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr,\r
373 EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size)\r
374 );\r
375 }\r
f8f931f6 376 return InternalFreePoolByIndex (FreePoolHdr, PoolTail);\r
e42e9404 377}\r
84edd20b
SZ
378\r
379/**\r
380 Frees pool.\r
381\r
382 @param Buffer The allocated pool entry to free.\r
383\r
384 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.\r
385 @retval EFI_SUCCESS Pool successfully freed.\r
386\r
387**/\r
388EFI_STATUS\r
389EFIAPI\r
390SmmFreePool (\r
391 IN VOID *Buffer\r
392 )\r
393{\r
394 EFI_STATUS Status;\r
395\r
396 Status = SmmInternalFreePool (Buffer);\r
397 if (!EFI_ERROR (Status)) {\r
e524f680
SZ
398 SmmCoreUpdateProfile (\r
399 (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),\r
400 MemoryProfileActionFreePool,\r
401 EfiMaxMemoryType,\r
402 0,\r
403 Buffer,\r
404 NULL\r
405 );\r
84edd20b
SZ
406 }\r
407 return Status;\r
408}\r