]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/PiSmmCore/Pool.c
Merge branch 'master' of https://github.com/tianocore/edk2
[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
45 for (Index = sizeof (mSmmPoolLists) / sizeof (*mSmmPoolLists); Index > 0;) {\r
46 InitializeListHead (&mSmmPoolLists[--Index]);\r
47 }\r
3c447c27 48 CurrentSmramRangesIndex = 0;\r
49 //\r
50 // If Loadding Module At fixed Address feature is enabled, cache the SMRAM base here\r
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
89 //\r
90 for (Index = 0; Index < SmramRangeCount; Index++) {\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
3c447c27 98\r
e42e9404 99}\r
100\r
101/**\r
102 Internal Function. Allocate a pool by specified PoolIndex.\r
103\r
104 @param PoolIndex Index which indicate the Pool size.\r
105 @param FreePoolHdr The returned Free pool.\r
106\r
107 @retval EFI_OUT_OF_RESOURCES Allocation failed.\r
108 @retval EFI_SUCCESS Pool successfully allocated.\r
109\r
110**/\r
111EFI_STATUS\r
112InternalAllocPoolByIndex (\r
113 IN UINTN PoolIndex,\r
114 OUT FREE_POOL_HEADER **FreePoolHdr\r
115 )\r
116{\r
84edd20b
SZ
117 EFI_STATUS Status;\r
118 FREE_POOL_HEADER *Hdr;\r
119 EFI_PHYSICAL_ADDRESS Address;\r
e42e9404 120\r
52c0d06b 121 ASSERT (PoolIndex <= MAX_POOL_INDEX);\r
e42e9404 122 Status = EFI_SUCCESS;\r
bf14e107 123 Hdr = NULL;\r
e42e9404 124 if (PoolIndex == MAX_POOL_INDEX) {\r
84edd20b
SZ
125 Status = SmmInternalAllocatePages (AllocateAnyPages, EfiRuntimeServicesData, EFI_SIZE_TO_PAGES (MAX_POOL_SIZE << 1), &Address);\r
126 if (EFI_ERROR (Status)) {\r
5b422a7b 127 return EFI_OUT_OF_RESOURCES;\r
e42e9404 128 }\r
84edd20b 129 Hdr = (FREE_POOL_HEADER *) (UINTN) Address;\r
e42e9404 130 } else if (!IsListEmpty (&mSmmPoolLists[PoolIndex])) {\r
131 Hdr = BASE_CR (GetFirstNode (&mSmmPoolLists[PoolIndex]), FREE_POOL_HEADER, Link);\r
132 RemoveEntryList (&Hdr->Link);\r
133 } else {\r
134 Status = InternalAllocPoolByIndex (PoolIndex + 1, &Hdr);\r
135 if (!EFI_ERROR (Status)) {\r
136 Hdr->Header.Size >>= 1;\r
137 Hdr->Header.Available = TRUE;\r
138 InsertHeadList (&mSmmPoolLists[PoolIndex], &Hdr->Link);\r
139 Hdr = (FREE_POOL_HEADER*)((UINT8*)Hdr + Hdr->Header.Size);\r
140 }\r
141 }\r
142\r
143 if (!EFI_ERROR (Status)) {\r
144 Hdr->Header.Size = MIN_POOL_SIZE << PoolIndex;\r
145 Hdr->Header.Available = FALSE;\r
146 }\r
147\r
148 *FreePoolHdr = Hdr;\r
149 return Status;\r
150}\r
151\r
152/**\r
153 Internal Function. Free a pool by specified PoolIndex.\r
154\r
155 @param FreePoolHdr The pool to free.\r
156\r
157 @retval EFI_SUCCESS Pool successfully freed.\r
158\r
159**/\r
160EFI_STATUS\r
161InternalFreePoolByIndex (\r
162 IN FREE_POOL_HEADER *FreePoolHdr\r
163 )\r
164{\r
165 UINTN PoolIndex;\r
166\r
167 ASSERT ((FreePoolHdr->Header.Size & (FreePoolHdr->Header.Size - 1)) == 0);\r
168 ASSERT (((UINTN)FreePoolHdr & (FreePoolHdr->Header.Size - 1)) == 0);\r
169 ASSERT (FreePoolHdr->Header.Size >= MIN_POOL_SIZE);\r
170\r
fbe12b79 171 PoolIndex = (UINTN) (HighBitSet32 ((UINT32)FreePoolHdr->Header.Size) - MIN_POOL_SHIFT);\r
e42e9404 172 FreePoolHdr->Header.Available = TRUE;\r
5b422a7b 173 ASSERT (PoolIndex < MAX_POOL_INDEX);\r
e42e9404 174 InsertHeadList (&mSmmPoolLists[PoolIndex], &FreePoolHdr->Link);\r
175 return EFI_SUCCESS;\r
176}\r
177\r
178/**\r
179 Allocate pool of a particular type.\r
180\r
181 @param PoolType Type of pool to allocate.\r
182 @param Size The amount of pool to allocate.\r
183 @param Buffer The address to return a pointer to the allocated\r
184 pool.\r
185\r
186 @retval EFI_INVALID_PARAMETER PoolType not valid.\r
187 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.\r
188 @retval EFI_SUCCESS Pool successfully allocated.\r
189\r
190**/\r
191EFI_STATUS\r
192EFIAPI\r
84edd20b 193SmmInternalAllocatePool (\r
e42e9404 194 IN EFI_MEMORY_TYPE PoolType,\r
195 IN UINTN Size,\r
196 OUT VOID **Buffer\r
197 )\r
198{\r
199 POOL_HEADER *PoolHdr;\r
200 FREE_POOL_HEADER *FreePoolHdr;\r
201 EFI_STATUS Status;\r
202 EFI_PHYSICAL_ADDRESS Address;\r
203 UINTN PoolIndex;\r
204\r
205 if (PoolType != EfiRuntimeServicesCode &&\r
206 PoolType != EfiRuntimeServicesData) {\r
207 return EFI_INVALID_PARAMETER;\r
208 }\r
209\r
e42e9404 210 Size += sizeof (*PoolHdr);\r
211 if (Size > MAX_POOL_SIZE) {\r
212 Size = EFI_SIZE_TO_PAGES (Size);\r
84edd20b 213 Status = SmmInternalAllocatePages (AllocateAnyPages, PoolType, Size, &Address);\r
e42e9404 214 if (EFI_ERROR (Status)) {\r
215 return Status;\r
216 }\r
217\r
218 PoolHdr = (POOL_HEADER*)(UINTN)Address;\r
219 PoolHdr->Size = EFI_PAGES_TO_SIZE (Size);\r
220 PoolHdr->Available = FALSE;\r
221 *Buffer = PoolHdr + 1;\r
222 return Status;\r
223 }\r
224\r
225 Size = (Size + MIN_POOL_SIZE - 1) >> MIN_POOL_SHIFT;\r
fbe12b79 226 PoolIndex = (UINTN) HighBitSet32 ((UINT32)Size);\r
e42e9404 227 if ((Size & (Size - 1)) != 0) {\r
228 PoolIndex++;\r
229 }\r
230\r
231 Status = InternalAllocPoolByIndex (PoolIndex, &FreePoolHdr);\r
bf14e107
SZ
232 if (!EFI_ERROR(Status)) {\r
233 *Buffer = &FreePoolHdr->Header + 1;\r
234 }\r
e42e9404 235 return Status;\r
236}\r
237\r
84edd20b
SZ
238/**\r
239 Allocate pool of a particular type.\r
240\r
241 @param PoolType Type of pool to allocate.\r
242 @param Size The amount of pool to allocate.\r
243 @param Buffer The address to return a pointer to the allocated\r
244 pool.\r
245\r
246 @retval EFI_INVALID_PARAMETER PoolType not valid.\r
247 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.\r
248 @retval EFI_SUCCESS Pool successfully allocated.\r
249\r
250**/\r
251EFI_STATUS\r
252EFIAPI\r
253SmmAllocatePool (\r
254 IN EFI_MEMORY_TYPE PoolType,\r
255 IN UINTN Size,\r
256 OUT VOID **Buffer\r
257 )\r
258{\r
259 EFI_STATUS Status;\r
260\r
261 Status = SmmInternalAllocatePool (PoolType, Size, Buffer);\r
262 if (!EFI_ERROR (Status)) {\r
e524f680
SZ
263 SmmCoreUpdateProfile (\r
264 (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),\r
265 MemoryProfileActionAllocatePool,\r
266 PoolType,\r
267 Size,\r
268 *Buffer,\r
269 NULL\r
270 );\r
84edd20b
SZ
271 }\r
272 return Status;\r
273}\r
274\r
e42e9404 275/**\r
276 Frees pool.\r
277\r
278 @param Buffer The allocated pool entry to free.\r
279\r
280 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.\r
281 @retval EFI_SUCCESS Pool successfully freed.\r
282\r
283**/\r
284EFI_STATUS\r
285EFIAPI\r
84edd20b 286SmmInternalFreePool (\r
e42e9404 287 IN VOID *Buffer\r
288 )\r
289{\r
290 FREE_POOL_HEADER *FreePoolHdr;\r
291\r
292 if (Buffer == NULL) {\r
293 return EFI_INVALID_PARAMETER;\r
294 }\r
295\r
296 FreePoolHdr = (FREE_POOL_HEADER*)((POOL_HEADER*)Buffer - 1);\r
297 ASSERT (!FreePoolHdr->Header.Available);\r
298\r
299 if (FreePoolHdr->Header.Size > MAX_POOL_SIZE) {\r
300 ASSERT (((UINTN)FreePoolHdr & EFI_PAGE_MASK) == 0);\r
301 ASSERT ((FreePoolHdr->Header.Size & EFI_PAGE_MASK) == 0);\r
84edd20b 302 return SmmInternalFreePages (\r
e42e9404 303 (EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr,\r
304 EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size)\r
305 );\r
306 }\r
307 return InternalFreePoolByIndex (FreePoolHdr);\r
308}\r
84edd20b
SZ
309\r
310/**\r
311 Frees pool.\r
312\r
313 @param Buffer The allocated pool entry to free.\r
314\r
315 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.\r
316 @retval EFI_SUCCESS Pool successfully freed.\r
317\r
318**/\r
319EFI_STATUS\r
320EFIAPI\r
321SmmFreePool (\r
322 IN VOID *Buffer\r
323 )\r
324{\r
325 EFI_STATUS Status;\r
326\r
327 Status = SmmInternalFreePool (Buffer);\r
328 if (!EFI_ERROR (Status)) {\r
e524f680
SZ
329 SmmCoreUpdateProfile (\r
330 (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),\r
331 MemoryProfileActionFreePool,\r
332 EfiMaxMemoryType,\r
333 0,\r
334 Buffer,\r
335 NULL\r
336 );\r
84edd20b
SZ
337 }\r
338 return Status;\r
339}\r