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