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