]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/PiSmmCore/Pool.c
MdeModulePkg DxeCore/PiSmmCore: Add UEFI memory and SMRAM profile support.
[mirror_edk2.git] / MdeModulePkg / Core / PiSmmCore / Pool.c
CommitLineData
e42e9404 1/** @file\r
2 SMM Memory pool management functions.\r
3\r
84edd20b 4 Copyright (c) 2009 - 2014, 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
70 if ((SmramRanges[Index].CpuStart + SmramRanges[Index].PhysicalSize) <= BASE_4GB) {\r
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
123 if (PoolIndex == MAX_POOL_INDEX) {\r
84edd20b
SZ
124 Status = SmmInternalAllocatePages (AllocateAnyPages, EfiRuntimeServicesData, EFI_SIZE_TO_PAGES (MAX_POOL_SIZE << 1), &Address);\r
125 if (EFI_ERROR (Status)) {\r
5b422a7b 126 return EFI_OUT_OF_RESOURCES;\r
e42e9404 127 }\r
84edd20b 128 Hdr = (FREE_POOL_HEADER *) (UINTN) Address;\r
e42e9404 129 } else if (!IsListEmpty (&mSmmPoolLists[PoolIndex])) {\r
130 Hdr = BASE_CR (GetFirstNode (&mSmmPoolLists[PoolIndex]), FREE_POOL_HEADER, Link);\r
131 RemoveEntryList (&Hdr->Link);\r
132 } else {\r
133 Status = InternalAllocPoolByIndex (PoolIndex + 1, &Hdr);\r
134 if (!EFI_ERROR (Status)) {\r
135 Hdr->Header.Size >>= 1;\r
136 Hdr->Header.Available = TRUE;\r
137 InsertHeadList (&mSmmPoolLists[PoolIndex], &Hdr->Link);\r
138 Hdr = (FREE_POOL_HEADER*)((UINT8*)Hdr + Hdr->Header.Size);\r
139 }\r
140 }\r
141\r
142 if (!EFI_ERROR (Status)) {\r
143 Hdr->Header.Size = MIN_POOL_SIZE << PoolIndex;\r
144 Hdr->Header.Available = FALSE;\r
145 }\r
146\r
147 *FreePoolHdr = Hdr;\r
148 return Status;\r
149}\r
150\r
151/**\r
152 Internal Function. Free a pool by specified PoolIndex.\r
153\r
154 @param FreePoolHdr The pool to free.\r
155\r
156 @retval EFI_SUCCESS Pool successfully freed.\r
157\r
158**/\r
159EFI_STATUS\r
160InternalFreePoolByIndex (\r
161 IN FREE_POOL_HEADER *FreePoolHdr\r
162 )\r
163{\r
164 UINTN PoolIndex;\r
165\r
166 ASSERT ((FreePoolHdr->Header.Size & (FreePoolHdr->Header.Size - 1)) == 0);\r
167 ASSERT (((UINTN)FreePoolHdr & (FreePoolHdr->Header.Size - 1)) == 0);\r
168 ASSERT (FreePoolHdr->Header.Size >= MIN_POOL_SIZE);\r
169\r
fbe12b79 170 PoolIndex = (UINTN) (HighBitSet32 ((UINT32)FreePoolHdr->Header.Size) - MIN_POOL_SHIFT);\r
e42e9404 171 FreePoolHdr->Header.Available = TRUE;\r
5b422a7b 172 ASSERT (PoolIndex < MAX_POOL_INDEX);\r
e42e9404 173 InsertHeadList (&mSmmPoolLists[PoolIndex], &FreePoolHdr->Link);\r
174 return EFI_SUCCESS;\r
175}\r
176\r
177/**\r
178 Allocate pool of a particular type.\r
179\r
180 @param PoolType Type of pool to allocate.\r
181 @param Size The amount of pool to allocate.\r
182 @param Buffer The address to return a pointer to the allocated\r
183 pool.\r
184\r
185 @retval EFI_INVALID_PARAMETER PoolType not valid.\r
186 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.\r
187 @retval EFI_SUCCESS Pool successfully allocated.\r
188\r
189**/\r
190EFI_STATUS\r
191EFIAPI\r
84edd20b 192SmmInternalAllocatePool (\r
e42e9404 193 IN EFI_MEMORY_TYPE PoolType,\r
194 IN UINTN Size,\r
195 OUT VOID **Buffer\r
196 )\r
197{\r
198 POOL_HEADER *PoolHdr;\r
199 FREE_POOL_HEADER *FreePoolHdr;\r
200 EFI_STATUS Status;\r
201 EFI_PHYSICAL_ADDRESS Address;\r
202 UINTN PoolIndex;\r
203\r
204 if (PoolType != EfiRuntimeServicesCode &&\r
205 PoolType != EfiRuntimeServicesData) {\r
206 return EFI_INVALID_PARAMETER;\r
207 }\r
208\r
e42e9404 209 Size += sizeof (*PoolHdr);\r
210 if (Size > MAX_POOL_SIZE) {\r
211 Size = EFI_SIZE_TO_PAGES (Size);\r
84edd20b 212 Status = SmmInternalAllocatePages (AllocateAnyPages, PoolType, Size, &Address);\r
e42e9404 213 if (EFI_ERROR (Status)) {\r
214 return Status;\r
215 }\r
216\r
217 PoolHdr = (POOL_HEADER*)(UINTN)Address;\r
218 PoolHdr->Size = EFI_PAGES_TO_SIZE (Size);\r
219 PoolHdr->Available = FALSE;\r
220 *Buffer = PoolHdr + 1;\r
221 return Status;\r
222 }\r
223\r
224 Size = (Size + MIN_POOL_SIZE - 1) >> MIN_POOL_SHIFT;\r
fbe12b79 225 PoolIndex = (UINTN) HighBitSet32 ((UINT32)Size);\r
e42e9404 226 if ((Size & (Size - 1)) != 0) {\r
227 PoolIndex++;\r
228 }\r
229\r
230 Status = InternalAllocPoolByIndex (PoolIndex, &FreePoolHdr);\r
231 *Buffer = &FreePoolHdr->Header + 1;\r
232 return Status;\r
233}\r
234\r
84edd20b
SZ
235/**\r
236 Allocate pool of a particular type.\r
237\r
238 @param PoolType Type of pool to allocate.\r
239 @param Size The amount of pool to allocate.\r
240 @param Buffer The address to return a pointer to the allocated\r
241 pool.\r
242\r
243 @retval EFI_INVALID_PARAMETER PoolType not valid.\r
244 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.\r
245 @retval EFI_SUCCESS Pool successfully allocated.\r
246\r
247**/\r
248EFI_STATUS\r
249EFIAPI\r
250SmmAllocatePool (\r
251 IN EFI_MEMORY_TYPE PoolType,\r
252 IN UINTN Size,\r
253 OUT VOID **Buffer\r
254 )\r
255{\r
256 EFI_STATUS Status;\r
257\r
258 Status = SmmInternalAllocatePool (PoolType, Size, Buffer);\r
259 if (!EFI_ERROR (Status)) {\r
260 SmmCoreUpdateProfile ((EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0), MemoryProfileActionAllocatePool, PoolType, Size, *Buffer);\r
261 }\r
262 return Status;\r
263}\r
264\r
e42e9404 265/**\r
266 Frees pool.\r
267\r
268 @param Buffer The allocated pool entry to free.\r
269\r
270 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.\r
271 @retval EFI_SUCCESS Pool successfully freed.\r
272\r
273**/\r
274EFI_STATUS\r
275EFIAPI\r
84edd20b 276SmmInternalFreePool (\r
e42e9404 277 IN VOID *Buffer\r
278 )\r
279{\r
280 FREE_POOL_HEADER *FreePoolHdr;\r
281\r
282 if (Buffer == NULL) {\r
283 return EFI_INVALID_PARAMETER;\r
284 }\r
285\r
286 FreePoolHdr = (FREE_POOL_HEADER*)((POOL_HEADER*)Buffer - 1);\r
287 ASSERT (!FreePoolHdr->Header.Available);\r
288\r
289 if (FreePoolHdr->Header.Size > MAX_POOL_SIZE) {\r
290 ASSERT (((UINTN)FreePoolHdr & EFI_PAGE_MASK) == 0);\r
291 ASSERT ((FreePoolHdr->Header.Size & EFI_PAGE_MASK) == 0);\r
84edd20b 292 return SmmInternalFreePages (\r
e42e9404 293 (EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr,\r
294 EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size)\r
295 );\r
296 }\r
297 return InternalFreePoolByIndex (FreePoolHdr);\r
298}\r
84edd20b
SZ
299\r
300/**\r
301 Frees pool.\r
302\r
303 @param Buffer The allocated pool entry to free.\r
304\r
305 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.\r
306 @retval EFI_SUCCESS Pool successfully freed.\r
307\r
308**/\r
309EFI_STATUS\r
310EFIAPI\r
311SmmFreePool (\r
312 IN VOID *Buffer\r
313 )\r
314{\r
315 EFI_STATUS Status;\r
316\r
317 Status = SmmInternalFreePool (Buffer);\r
318 if (!EFI_ERROR (Status)) {\r
319 SmmCoreUpdateProfile ((EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0), MemoryProfileActionFreePool, 0, 0, Buffer);\r
320 }\r
321 return Status;\r
322}\r