]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/PiSmmCore/Pool.c
MdeModulePkg/PiSmmCore: AllocatePool should use MemoryType.
[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
5f4d3e17
JY
62 UINT64 SmmCodeSize;\r
63 UINTN CurrentSmramRangesIndex;\r
64 UINT64 MaxSize;\r
65 UINTN SmmPoolTypeIndex;\r
e42e9404 66\r
67 //\r
68 // Initialize Pool list\r
69 //\r
5f4d3e17
JY
70 for (SmmPoolTypeIndex = 0; SmmPoolTypeIndex < SmmPoolTypeMax; SmmPoolTypeIndex++) {\r
71 for (Index = 0; Index < ARRAY_SIZE (mSmmPoolLists[SmmPoolTypeIndex]); Index++) {\r
72 InitializeListHead (&mSmmPoolLists[SmmPoolTypeIndex][Index]);\r
73 }\r
e42e9404 74 }\r
3c447c27 75 CurrentSmramRangesIndex = 0;\r
76 //\r
2048c585 77 // If Loading Module At fixed Address feature is enabled, cache the SMRAM base here\r
3c447c27 78 //\r
79 if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {\r
80 //\r
81 // Build tool will calculate the smm code size and then patch the PcdLoadFixAddressSmmCodePageNumber\r
82 //\r
83 SmmCodeSize = LShiftU64 (PcdGet32(PcdLoadFixAddressSmmCodePageNumber), EFI_PAGE_SHIFT);\r
84 \r
85 //\r
86 // Find the largest SMRAM range between 1MB and 4GB that is at least 256KB - 4K in size\r
87 //\r
88 for (Index = 0, MaxSize = SIZE_256KB - EFI_PAGE_SIZE; Index < SmramRangeCount; Index++) {\r
2c0f06f0 89 //\r
90 // Skip any SMRAM region that is already allocated, needs testing, or needs ECC initialization\r
91 //\r
92 if ((SmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {\r
93 continue;\r
94 }\r
95\r
3c447c27 96 if (SmramRanges[Index].CpuStart >= BASE_1MB) {\r
10e4e4f6 97 if ((SmramRanges[Index].CpuStart + SmramRanges[Index].PhysicalSize - 1) <= MAX_ADDRESS) {\r
3c447c27 98 if (SmramRanges[Index].PhysicalSize >= MaxSize) {\r
99 MaxSize = SmramRanges[Index].PhysicalSize;\r
100 CurrentSmramRangesIndex = Index;\r
101 }\r
102 }\r
103 }\r
104 }\r
105 gLoadModuleAtFixAddressSmramBase = SmramRanges[CurrentSmramRangesIndex].CpuStart;\r
106 \r
107 //\r
108 // cut out a memory range from this SMRAM range with the size SmmCodeSize to hold SMM driver code\r
109 // A notable thing is that SMM core is already loaded into this range.\r
110 //\r
111 SmramRanges[CurrentSmramRangesIndex].CpuStart = SmramRanges[CurrentSmramRangesIndex].CpuStart + SmmCodeSize; \r
112 SmramRanges[CurrentSmramRangesIndex].PhysicalSize = SmramRanges[CurrentSmramRangesIndex].PhysicalSize - SmmCodeSize;\r
113 }\r
e42e9404 114 //\r
bb34cc8c 115 // Add Free SMRAM regions\r
285a682c 116 // Need add Free memory at first, to let gSmmMemoryMap record data\r
e42e9404 117 //\r
118 for (Index = 0; Index < SmramRangeCount; Index++) {\r
285a682c
JY
119 if ((SmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {\r
120 continue;\r
121 }\r
122 SmmAddMemoryRegion (\r
123 SmramRanges[Index].CpuStart,\r
124 SmramRanges[Index].PhysicalSize,\r
125 EfiConventionalMemory,\r
126 SmramRanges[Index].RegionState\r
127 );\r
128 }\r
129\r
bb34cc8c
LG
130 //\r
131 // Add the allocated SMRAM regions\r
132 //\r
285a682c
JY
133 for (Index = 0; Index < SmramRangeCount; Index++) {\r
134 if ((SmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) == 0) {\r
135 continue;\r
136 }\r
e42e9404 137 SmmAddMemoryRegion (\r
138 SmramRanges[Index].CpuStart,\r
139 SmramRanges[Index].PhysicalSize,\r
140 EfiConventionalMemory,\r
141 SmramRanges[Index].RegionState\r
142 );\r
143 }\r
3c447c27 144\r
e42e9404 145}\r
146\r
147/**\r
148 Internal Function. Allocate a pool by specified PoolIndex.\r
149\r
5f4d3e17 150 @param PoolType Type of pool to allocate.\r
e42e9404 151 @param PoolIndex Index which indicate the Pool size.\r
152 @param FreePoolHdr The returned Free pool.\r
153\r
154 @retval EFI_OUT_OF_RESOURCES Allocation failed.\r
155 @retval EFI_SUCCESS Pool successfully allocated.\r
156\r
157**/\r
158EFI_STATUS\r
159InternalAllocPoolByIndex (\r
5f4d3e17 160 IN EFI_MEMORY_TYPE PoolType,\r
e42e9404 161 IN UINTN PoolIndex,\r
162 OUT FREE_POOL_HEADER **FreePoolHdr\r
163 )\r
164{\r
84edd20b
SZ
165 EFI_STATUS Status;\r
166 FREE_POOL_HEADER *Hdr;\r
167 EFI_PHYSICAL_ADDRESS Address;\r
5f4d3e17
JY
168 SMM_POOL_TYPE SmmPoolType;\r
169\r
170 SmmPoolType = UefiMemoryTypeToSmmPoolType(PoolType);\r
e42e9404 171\r
52c0d06b 172 ASSERT (PoolIndex <= MAX_POOL_INDEX);\r
e42e9404 173 Status = EFI_SUCCESS;\r
bf14e107 174 Hdr = NULL;\r
e42e9404 175 if (PoolIndex == MAX_POOL_INDEX) {\r
5f4d3e17 176 Status = SmmInternalAllocatePages (AllocateAnyPages, PoolType, EFI_SIZE_TO_PAGES (MAX_POOL_SIZE << 1), &Address);\r
84edd20b 177 if (EFI_ERROR (Status)) {\r
5b422a7b 178 return EFI_OUT_OF_RESOURCES;\r
e42e9404 179 }\r
84edd20b 180 Hdr = (FREE_POOL_HEADER *) (UINTN) Address;\r
5f4d3e17
JY
181 } else if (!IsListEmpty (&mSmmPoolLists[SmmPoolType][PoolIndex])) {\r
182 Hdr = BASE_CR (GetFirstNode (&mSmmPoolLists[SmmPoolType][PoolIndex]), FREE_POOL_HEADER, Link);\r
e42e9404 183 RemoveEntryList (&Hdr->Link);\r
184 } else {\r
5f4d3e17 185 Status = InternalAllocPoolByIndex (PoolType, PoolIndex + 1, &Hdr);\r
e42e9404 186 if (!EFI_ERROR (Status)) {\r
187 Hdr->Header.Size >>= 1;\r
188 Hdr->Header.Available = TRUE;\r
5f4d3e17
JY
189 Hdr->Header.Type = PoolType;\r
190 InsertHeadList (&mSmmPoolLists[SmmPoolType][PoolIndex], &Hdr->Link);\r
e42e9404 191 Hdr = (FREE_POOL_HEADER*)((UINT8*)Hdr + Hdr->Header.Size);\r
192 }\r
193 }\r
194\r
195 if (!EFI_ERROR (Status)) {\r
196 Hdr->Header.Size = MIN_POOL_SIZE << PoolIndex;\r
197 Hdr->Header.Available = FALSE;\r
5f4d3e17 198 Hdr->Header.Type = PoolType;\r
e42e9404 199 }\r
200\r
201 *FreePoolHdr = Hdr;\r
202 return Status;\r
203}\r
204\r
205/**\r
206 Internal Function. Free a pool by specified PoolIndex.\r
207\r
208 @param FreePoolHdr The pool to free.\r
209\r
210 @retval EFI_SUCCESS Pool successfully freed.\r
211\r
212**/\r
213EFI_STATUS\r
214InternalFreePoolByIndex (\r
215 IN FREE_POOL_HEADER *FreePoolHdr\r
216 )\r
217{\r
5f4d3e17
JY
218 UINTN PoolIndex;\r
219 SMM_POOL_TYPE SmmPoolType;\r
e42e9404 220\r
221 ASSERT ((FreePoolHdr->Header.Size & (FreePoolHdr->Header.Size - 1)) == 0);\r
222 ASSERT (((UINTN)FreePoolHdr & (FreePoolHdr->Header.Size - 1)) == 0);\r
223 ASSERT (FreePoolHdr->Header.Size >= MIN_POOL_SIZE);\r
224\r
5f4d3e17
JY
225 SmmPoolType = UefiMemoryTypeToSmmPoolType(FreePoolHdr->Header.Type);\r
226\r
fbe12b79 227 PoolIndex = (UINTN) (HighBitSet32 ((UINT32)FreePoolHdr->Header.Size) - MIN_POOL_SHIFT);\r
e42e9404 228 FreePoolHdr->Header.Available = TRUE;\r
5b422a7b 229 ASSERT (PoolIndex < MAX_POOL_INDEX);\r
5f4d3e17 230 InsertHeadList (&mSmmPoolLists[SmmPoolType][PoolIndex], &FreePoolHdr->Link);\r
e42e9404 231 return EFI_SUCCESS;\r
232}\r
233\r
234/**\r
235 Allocate pool of a particular type.\r
236\r
237 @param PoolType Type of pool to allocate.\r
238 @param Size The amount of pool to allocate.\r
239 @param Buffer The address to return a pointer to the allocated\r
240 pool.\r
241\r
242 @retval EFI_INVALID_PARAMETER PoolType not valid.\r
243 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.\r
244 @retval EFI_SUCCESS Pool successfully allocated.\r
245\r
246**/\r
247EFI_STATUS\r
248EFIAPI\r
84edd20b 249SmmInternalAllocatePool (\r
e42e9404 250 IN EFI_MEMORY_TYPE PoolType,\r
251 IN UINTN Size,\r
252 OUT VOID **Buffer\r
253 )\r
254{\r
255 POOL_HEADER *PoolHdr;\r
256 FREE_POOL_HEADER *FreePoolHdr;\r
257 EFI_STATUS Status;\r
258 EFI_PHYSICAL_ADDRESS Address;\r
259 UINTN PoolIndex;\r
260\r
261 if (PoolType != EfiRuntimeServicesCode &&\r
262 PoolType != EfiRuntimeServicesData) {\r
263 return EFI_INVALID_PARAMETER;\r
264 }\r
265\r
e42e9404 266 Size += sizeof (*PoolHdr);\r
267 if (Size > MAX_POOL_SIZE) {\r
268 Size = EFI_SIZE_TO_PAGES (Size);\r
84edd20b 269 Status = SmmInternalAllocatePages (AllocateAnyPages, PoolType, Size, &Address);\r
e42e9404 270 if (EFI_ERROR (Status)) {\r
271 return Status;\r
272 }\r
273\r
274 PoolHdr = (POOL_HEADER*)(UINTN)Address;\r
275 PoolHdr->Size = EFI_PAGES_TO_SIZE (Size);\r
276 PoolHdr->Available = FALSE;\r
5f4d3e17 277 PoolHdr->Type = PoolType;\r
e42e9404 278 *Buffer = PoolHdr + 1;\r
279 return Status;\r
280 }\r
281\r
282 Size = (Size + MIN_POOL_SIZE - 1) >> MIN_POOL_SHIFT;\r
fbe12b79 283 PoolIndex = (UINTN) HighBitSet32 ((UINT32)Size);\r
e42e9404 284 if ((Size & (Size - 1)) != 0) {\r
285 PoolIndex++;\r
286 }\r
287\r
5f4d3e17 288 Status = InternalAllocPoolByIndex (PoolType, PoolIndex, &FreePoolHdr);\r
bf14e107
SZ
289 if (!EFI_ERROR(Status)) {\r
290 *Buffer = &FreePoolHdr->Header + 1;\r
291 }\r
e42e9404 292 return Status;\r
293}\r
294\r
84edd20b
SZ
295/**\r
296 Allocate pool of a particular type.\r
297\r
298 @param PoolType Type of pool to allocate.\r
299 @param Size The amount of pool to allocate.\r
300 @param Buffer The address to return a pointer to the allocated\r
301 pool.\r
302\r
303 @retval EFI_INVALID_PARAMETER PoolType not valid.\r
304 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.\r
305 @retval EFI_SUCCESS Pool successfully allocated.\r
306\r
307**/\r
308EFI_STATUS\r
309EFIAPI\r
310SmmAllocatePool (\r
311 IN EFI_MEMORY_TYPE PoolType,\r
312 IN UINTN Size,\r
313 OUT VOID **Buffer\r
314 )\r
315{\r
316 EFI_STATUS Status;\r
317\r
318 Status = SmmInternalAllocatePool (PoolType, Size, Buffer);\r
319 if (!EFI_ERROR (Status)) {\r
e524f680
SZ
320 SmmCoreUpdateProfile (\r
321 (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),\r
322 MemoryProfileActionAllocatePool,\r
323 PoolType,\r
324 Size,\r
325 *Buffer,\r
326 NULL\r
327 );\r
84edd20b
SZ
328 }\r
329 return Status;\r
330}\r
331\r
e42e9404 332/**\r
333 Frees pool.\r
334\r
335 @param Buffer The allocated pool entry to free.\r
336\r
337 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.\r
338 @retval EFI_SUCCESS Pool successfully freed.\r
339\r
340**/\r
341EFI_STATUS\r
342EFIAPI\r
84edd20b 343SmmInternalFreePool (\r
e42e9404 344 IN VOID *Buffer\r
345 )\r
346{\r
347 FREE_POOL_HEADER *FreePoolHdr;\r
348\r
349 if (Buffer == NULL) {\r
350 return EFI_INVALID_PARAMETER;\r
351 }\r
352\r
353 FreePoolHdr = (FREE_POOL_HEADER*)((POOL_HEADER*)Buffer - 1);\r
354 ASSERT (!FreePoolHdr->Header.Available);\r
355\r
356 if (FreePoolHdr->Header.Size > MAX_POOL_SIZE) {\r
357 ASSERT (((UINTN)FreePoolHdr & EFI_PAGE_MASK) == 0);\r
358 ASSERT ((FreePoolHdr->Header.Size & EFI_PAGE_MASK) == 0);\r
84edd20b 359 return SmmInternalFreePages (\r
e42e9404 360 (EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr,\r
361 EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size)\r
362 );\r
363 }\r
364 return InternalFreePoolByIndex (FreePoolHdr);\r
365}\r
84edd20b
SZ
366\r
367/**\r
368 Frees pool.\r
369\r
370 @param Buffer The allocated pool entry to free.\r
371\r
372 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.\r
373 @retval EFI_SUCCESS Pool successfully freed.\r
374\r
375**/\r
376EFI_STATUS\r
377EFIAPI\r
378SmmFreePool (\r
379 IN VOID *Buffer\r
380 )\r
381{\r
382 EFI_STATUS Status;\r
383\r
384 Status = SmmInternalFreePool (Buffer);\r
385 if (!EFI_ERROR (Status)) {\r
e524f680
SZ
386 SmmCoreUpdateProfile (\r
387 (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),\r
388 MemoryProfileActionFreePool,\r
389 EfiMaxMemoryType,\r
390 0,\r
391 Buffer,\r
392 NULL\r
393 );\r
84edd20b
SZ
394 }\r
395 return Status;\r
396}\r