]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/PiSmmCore/Pool.c
MdeModulePkg/Ufs: Wait fDeviceInit be cleared by devices during init
[mirror_edk2.git] / MdeModulePkg / Core / PiSmmCore / Pool.c
CommitLineData
e42e9404 1/** @file\r
2 SMM Memory pool management functions.\r
3\r
89558f16 4 Copyright (c) 2009 - 2017, 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
94a1bc12 62 EFI_STATUS Status;\r
5f4d3e17 63 UINTN SmmPoolTypeIndex;\r
94a1bc12 64 EFI_LOAD_FIXED_ADDRESS_CONFIGURATION_TABLE *LMFAConfigurationTable;\r
e42e9404 65\r
66 //\r
67 // Initialize Pool list\r
68 //\r
5f4d3e17
JY
69 for (SmmPoolTypeIndex = 0; SmmPoolTypeIndex < SmmPoolTypeMax; SmmPoolTypeIndex++) {\r
70 for (Index = 0; Index < ARRAY_SIZE (mSmmPoolLists[SmmPoolTypeIndex]); Index++) {\r
71 InitializeListHead (&mSmmPoolLists[SmmPoolTypeIndex][Index]);\r
72 }\r
e42e9404 73 }\r
94a1bc12
LG
74\r
75 Status = EfiGetSystemConfigurationTable (\r
76 &gLoadFixedAddressConfigurationTableGuid,\r
77 (VOID **) &LMFAConfigurationTable\r
78 );\r
79 if (!EFI_ERROR (Status) && LMFAConfigurationTable != NULL) {\r
80 gLoadModuleAtFixAddressSmramBase = LMFAConfigurationTable->SmramBase;\r
3c447c27 81 }\r
94a1bc12 82\r
e42e9404 83 //\r
bb34cc8c 84 // Add Free SMRAM regions\r
285a682c 85 // Need add Free memory at first, to let gSmmMemoryMap record data\r
e42e9404 86 //\r
87 for (Index = 0; Index < SmramRangeCount; Index++) {\r
285a682c
JY
88 if ((SmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {\r
89 continue;\r
90 }\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
98\r
bb34cc8c
LG
99 //\r
100 // Add the allocated SMRAM regions\r
101 //\r
285a682c
JY
102 for (Index = 0; Index < SmramRangeCount; Index++) {\r
103 if ((SmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) == 0) {\r
104 continue;\r
105 }\r
e42e9404 106 SmmAddMemoryRegion (\r
107 SmramRanges[Index].CpuStart,\r
108 SmramRanges[Index].PhysicalSize,\r
109 EfiConventionalMemory,\r
110 SmramRanges[Index].RegionState\r
111 );\r
112 }\r
3c447c27 113\r
e42e9404 114}\r
115\r
116/**\r
117 Internal Function. Allocate a pool by specified PoolIndex.\r
118\r
5f4d3e17 119 @param PoolType Type of pool to allocate.\r
e42e9404 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
5f4d3e17 129 IN EFI_MEMORY_TYPE PoolType,\r
e42e9404 130 IN UINTN PoolIndex,\r
131 OUT FREE_POOL_HEADER **FreePoolHdr\r
132 )\r
133{\r
84edd20b
SZ
134 EFI_STATUS Status;\r
135 FREE_POOL_HEADER *Hdr;\r
136 EFI_PHYSICAL_ADDRESS Address;\r
5f4d3e17
JY
137 SMM_POOL_TYPE SmmPoolType;\r
138\r
89558f16 139 Address = 0;\r
5f4d3e17 140 SmmPoolType = UefiMemoryTypeToSmmPoolType(PoolType);\r
e42e9404 141\r
52c0d06b 142 ASSERT (PoolIndex <= MAX_POOL_INDEX);\r
e42e9404 143 Status = EFI_SUCCESS;\r
bf14e107 144 Hdr = NULL;\r
e42e9404 145 if (PoolIndex == MAX_POOL_INDEX) {\r
5f4d3e17 146 Status = SmmInternalAllocatePages (AllocateAnyPages, PoolType, EFI_SIZE_TO_PAGES (MAX_POOL_SIZE << 1), &Address);\r
84edd20b 147 if (EFI_ERROR (Status)) {\r
5b422a7b 148 return EFI_OUT_OF_RESOURCES;\r
e42e9404 149 }\r
84edd20b 150 Hdr = (FREE_POOL_HEADER *) (UINTN) Address;\r
5f4d3e17
JY
151 } else if (!IsListEmpty (&mSmmPoolLists[SmmPoolType][PoolIndex])) {\r
152 Hdr = BASE_CR (GetFirstNode (&mSmmPoolLists[SmmPoolType][PoolIndex]), FREE_POOL_HEADER, Link);\r
e42e9404 153 RemoveEntryList (&Hdr->Link);\r
154 } else {\r
5f4d3e17 155 Status = InternalAllocPoolByIndex (PoolType, PoolIndex + 1, &Hdr);\r
e42e9404 156 if (!EFI_ERROR (Status)) {\r
157 Hdr->Header.Size >>= 1;\r
158 Hdr->Header.Available = TRUE;\r
5f4d3e17
JY
159 Hdr->Header.Type = PoolType;\r
160 InsertHeadList (&mSmmPoolLists[SmmPoolType][PoolIndex], &Hdr->Link);\r
e42e9404 161 Hdr = (FREE_POOL_HEADER*)((UINT8*)Hdr + Hdr->Header.Size);\r
162 }\r
163 }\r
164\r
165 if (!EFI_ERROR (Status)) {\r
166 Hdr->Header.Size = MIN_POOL_SIZE << PoolIndex;\r
167 Hdr->Header.Available = FALSE;\r
5f4d3e17 168 Hdr->Header.Type = PoolType;\r
e42e9404 169 }\r
170\r
171 *FreePoolHdr = Hdr;\r
172 return Status;\r
173}\r
174\r
175/**\r
176 Internal Function. Free a pool by specified PoolIndex.\r
177\r
178 @param FreePoolHdr The pool to free.\r
179\r
180 @retval EFI_SUCCESS Pool successfully freed.\r
181\r
182**/\r
183EFI_STATUS\r
184InternalFreePoolByIndex (\r
185 IN FREE_POOL_HEADER *FreePoolHdr\r
186 )\r
187{\r
5f4d3e17
JY
188 UINTN PoolIndex;\r
189 SMM_POOL_TYPE SmmPoolType;\r
e42e9404 190\r
191 ASSERT ((FreePoolHdr->Header.Size & (FreePoolHdr->Header.Size - 1)) == 0);\r
192 ASSERT (((UINTN)FreePoolHdr & (FreePoolHdr->Header.Size - 1)) == 0);\r
193 ASSERT (FreePoolHdr->Header.Size >= MIN_POOL_SIZE);\r
194\r
5f4d3e17
JY
195 SmmPoolType = UefiMemoryTypeToSmmPoolType(FreePoolHdr->Header.Type);\r
196\r
fbe12b79 197 PoolIndex = (UINTN) (HighBitSet32 ((UINT32)FreePoolHdr->Header.Size) - MIN_POOL_SHIFT);\r
e42e9404 198 FreePoolHdr->Header.Available = TRUE;\r
5b422a7b 199 ASSERT (PoolIndex < MAX_POOL_INDEX);\r
5f4d3e17 200 InsertHeadList (&mSmmPoolLists[SmmPoolType][PoolIndex], &FreePoolHdr->Link);\r
e42e9404 201 return EFI_SUCCESS;\r
202}\r
203\r
204/**\r
205 Allocate pool of a particular type.\r
206\r
207 @param PoolType Type of pool to allocate.\r
208 @param Size The amount of pool to allocate.\r
209 @param Buffer The address to return a pointer to the allocated\r
210 pool.\r
211\r
212 @retval EFI_INVALID_PARAMETER PoolType not valid.\r
213 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.\r
214 @retval EFI_SUCCESS Pool successfully allocated.\r
215\r
216**/\r
217EFI_STATUS\r
218EFIAPI\r
84edd20b 219SmmInternalAllocatePool (\r
e42e9404 220 IN EFI_MEMORY_TYPE PoolType,\r
221 IN UINTN Size,\r
222 OUT VOID **Buffer\r
223 )\r
224{\r
225 POOL_HEADER *PoolHdr;\r
226 FREE_POOL_HEADER *FreePoolHdr;\r
227 EFI_STATUS Status;\r
228 EFI_PHYSICAL_ADDRESS Address;\r
229 UINTN PoolIndex;\r
230\r
89558f16
HW
231 Address = 0;\r
232\r
e42e9404 233 if (PoolType != EfiRuntimeServicesCode &&\r
234 PoolType != EfiRuntimeServicesData) {\r
235 return EFI_INVALID_PARAMETER;\r
236 }\r
237\r
e42e9404 238 Size += sizeof (*PoolHdr);\r
239 if (Size > MAX_POOL_SIZE) {\r
240 Size = EFI_SIZE_TO_PAGES (Size);\r
84edd20b 241 Status = SmmInternalAllocatePages (AllocateAnyPages, PoolType, Size, &Address);\r
e42e9404 242 if (EFI_ERROR (Status)) {\r
243 return Status;\r
244 }\r
245\r
246 PoolHdr = (POOL_HEADER*)(UINTN)Address;\r
247 PoolHdr->Size = EFI_PAGES_TO_SIZE (Size);\r
248 PoolHdr->Available = FALSE;\r
5f4d3e17 249 PoolHdr->Type = PoolType;\r
e42e9404 250 *Buffer = PoolHdr + 1;\r
251 return Status;\r
252 }\r
253\r
254 Size = (Size + MIN_POOL_SIZE - 1) >> MIN_POOL_SHIFT;\r
fbe12b79 255 PoolIndex = (UINTN) HighBitSet32 ((UINT32)Size);\r
e42e9404 256 if ((Size & (Size - 1)) != 0) {\r
257 PoolIndex++;\r
258 }\r
259\r
5f4d3e17 260 Status = InternalAllocPoolByIndex (PoolType, PoolIndex, &FreePoolHdr);\r
bf14e107
SZ
261 if (!EFI_ERROR(Status)) {\r
262 *Buffer = &FreePoolHdr->Header + 1;\r
263 }\r
e42e9404 264 return Status;\r
265}\r
266\r
84edd20b
SZ
267/**\r
268 Allocate pool of a particular type.\r
269\r
270 @param PoolType Type of pool to allocate.\r
271 @param Size The amount of pool to allocate.\r
272 @param Buffer The address to return a pointer to the allocated\r
273 pool.\r
274\r
275 @retval EFI_INVALID_PARAMETER PoolType not valid.\r
276 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.\r
277 @retval EFI_SUCCESS Pool successfully allocated.\r
278\r
279**/\r
280EFI_STATUS\r
281EFIAPI\r
282SmmAllocatePool (\r
283 IN EFI_MEMORY_TYPE PoolType,\r
284 IN UINTN Size,\r
285 OUT VOID **Buffer\r
286 )\r
287{\r
288 EFI_STATUS Status;\r
289\r
290 Status = SmmInternalAllocatePool (PoolType, Size, Buffer);\r
291 if (!EFI_ERROR (Status)) {\r
e524f680
SZ
292 SmmCoreUpdateProfile (\r
293 (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),\r
294 MemoryProfileActionAllocatePool,\r
295 PoolType,\r
296 Size,\r
297 *Buffer,\r
298 NULL\r
299 );\r
84edd20b
SZ
300 }\r
301 return Status;\r
302}\r
303\r
e42e9404 304/**\r
305 Frees pool.\r
306\r
307 @param Buffer The allocated pool entry to free.\r
308\r
309 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.\r
310 @retval EFI_SUCCESS Pool successfully freed.\r
311\r
312**/\r
313EFI_STATUS\r
314EFIAPI\r
84edd20b 315SmmInternalFreePool (\r
e42e9404 316 IN VOID *Buffer\r
317 )\r
318{\r
319 FREE_POOL_HEADER *FreePoolHdr;\r
320\r
321 if (Buffer == NULL) {\r
322 return EFI_INVALID_PARAMETER;\r
323 }\r
324\r
325 FreePoolHdr = (FREE_POOL_HEADER*)((POOL_HEADER*)Buffer - 1);\r
326 ASSERT (!FreePoolHdr->Header.Available);\r
327\r
328 if (FreePoolHdr->Header.Size > MAX_POOL_SIZE) {\r
329 ASSERT (((UINTN)FreePoolHdr & EFI_PAGE_MASK) == 0);\r
330 ASSERT ((FreePoolHdr->Header.Size & EFI_PAGE_MASK) == 0);\r
84edd20b 331 return SmmInternalFreePages (\r
e42e9404 332 (EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr,\r
333 EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size)\r
334 );\r
335 }\r
336 return InternalFreePoolByIndex (FreePoolHdr);\r
337}\r
84edd20b
SZ
338\r
339/**\r
340 Frees pool.\r
341\r
342 @param Buffer The allocated pool entry to free.\r
343\r
344 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.\r
345 @retval EFI_SUCCESS Pool successfully freed.\r
346\r
347**/\r
348EFI_STATUS\r
349EFIAPI\r
350SmmFreePool (\r
351 IN VOID *Buffer\r
352 )\r
353{\r
354 EFI_STATUS Status;\r
355\r
356 Status = SmmInternalFreePool (Buffer);\r
357 if (!EFI_ERROR (Status)) {\r
e524f680
SZ
358 SmmCoreUpdateProfile (\r
359 (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),\r
360 MemoryProfileActionFreePool,\r
361 EfiMaxMemoryType,\r
362 0,\r
363 Buffer,\r
364 NULL\r
365 );\r
84edd20b
SZ
366 }\r
367 return Status;\r
368}\r