]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/PiSmmCore/Pool.c
Enable "Load Module At fixed Address" feature in SMM Core
[mirror_edk2.git] / MdeModulePkg / Core / PiSmmCore / Pool.c
CommitLineData
e42e9404 1/** @file\r
2 SMM Memory pool management functions.\r
3\r
4 Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
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
17//\r
18// MIN_POOL_SHIFT must not be less than 5\r
19//\r
20#define MIN_POOL_SHIFT 6\r
21#define MIN_POOL_SIZE (1 << MIN_POOL_SHIFT)\r
22\r
23//\r
24// MAX_POOL_SHIFT must not be less than EFI_PAGE_SHIFT - 1\r
25//\r
26#define MAX_POOL_SHIFT (EFI_PAGE_SHIFT - 1)\r
27#define MAX_POOL_SIZE (1 << MAX_POOL_SHIFT)\r
28\r
29//\r
30// MAX_POOL_INDEX are calculated by maximum and minimum pool sizes\r
31//\r
32#define MAX_POOL_INDEX (MAX_POOL_SHIFT - MIN_POOL_SHIFT + 1)\r
33\r
34typedef struct {\r
35 UINTN Size;\r
36 BOOLEAN Available;\r
37} POOL_HEADER;\r
38\r
39typedef struct {\r
40 POOL_HEADER Header;\r
41 LIST_ENTRY Link;\r
42} FREE_POOL_HEADER;\r
43\r
44LIST_ENTRY mSmmPoolLists[MAX_POOL_INDEX];\r
3c447c27 45//\r
46// To cache the SMRAM base since when Loading modules At fixed address feature is enabled, \r
47// all module is assigned an offset relative the SMRAM base in build time.\r
48//\r
49GLOBAL_REMOVE_IF_UNREFERENCED EFI_PHYSICAL_ADDRESS gLoadModuleAtFixAddressSmramBase = 0;\r
e42e9404 50\r
51/**\r
52 Called to initialize the memory service.\r
53\r
54 @param SmramRangeCount Number of SMRAM Regions\r
55 @param SmramRanges Pointer to SMRAM Descriptors\r
56\r
57**/\r
58VOID\r
59SmmInitializeMemoryServices (\r
60 IN UINTN SmramRangeCount,\r
61 IN EFI_SMRAM_DESCRIPTOR *SmramRanges\r
62 )\r
63{\r
3c447c27 64 UINTN Index;\r
65 UINT64 SmmCodeSize;\r
66 UINTN CurrentSmramRangesIndex;\r
67 UINT64 MaxSize;\r
e42e9404 68\r
69 //\r
70 // Initialize Pool list\r
71 //\r
72 for (Index = sizeof (mSmmPoolLists) / sizeof (*mSmmPoolLists); Index > 0;) {\r
73 InitializeListHead (&mSmmPoolLists[--Index]);\r
74 }\r
3c447c27 75 CurrentSmramRangesIndex = 0;\r
76 //\r
77 // If Loadding Module At fixed Address feature is enabled, cache the SMRAM base here\r
78 //\r
79 if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {\r
80 //\r
81 // Build tool will calculate the smm code size and then patch the PcdLoadFixAddressSmmCodePageNumber\r
82 //\r
83 SmmCodeSize = LShiftU64 (PcdGet32(PcdLoadFixAddressSmmCodePageNumber), EFI_PAGE_SHIFT);\r
84 \r
85 //\r
86 // Find the largest SMRAM range between 1MB and 4GB that is at least 256KB - 4K in size\r
87 //\r
88 for (Index = 0, MaxSize = SIZE_256KB - EFI_PAGE_SIZE; Index < SmramRangeCount; Index++) {\r
89 if (SmramRanges[Index].CpuStart >= BASE_1MB) {\r
90 if ((SmramRanges[Index].CpuStart + SmramRanges[Index].PhysicalSize) <= BASE_4GB) {\r
91 if (SmramRanges[Index].PhysicalSize >= MaxSize) {\r
92 MaxSize = SmramRanges[Index].PhysicalSize;\r
93 CurrentSmramRangesIndex = Index;\r
94 }\r
95 }\r
96 }\r
97 }\r
98 gLoadModuleAtFixAddressSmramBase = SmramRanges[CurrentSmramRangesIndex].CpuStart;\r
99 \r
100 //\r
101 // cut out a memory range from this SMRAM range with the size SmmCodeSize to hold SMM driver code\r
102 // A notable thing is that SMM core is already loaded into this range.\r
103 //\r
104 SmramRanges[CurrentSmramRangesIndex].CpuStart = SmramRanges[CurrentSmramRangesIndex].CpuStart + SmmCodeSize; \r
105 SmramRanges[CurrentSmramRangesIndex].PhysicalSize = SmramRanges[CurrentSmramRangesIndex].PhysicalSize - SmmCodeSize;\r
106 }\r
e42e9404 107 //\r
108 // Initialize free SMRAM regions\r
109 //\r
110 for (Index = 0; Index < SmramRangeCount; Index++) {\r
111 SmmAddMemoryRegion (\r
112 SmramRanges[Index].CpuStart,\r
113 SmramRanges[Index].PhysicalSize,\r
114 EfiConventionalMemory,\r
115 SmramRanges[Index].RegionState\r
116 );\r
117 }\r
3c447c27 118\r
e42e9404 119}\r
120\r
121/**\r
122 Internal Function. Allocate a pool by specified PoolIndex.\r
123\r
124 @param PoolIndex Index which indicate the Pool size.\r
125 @param FreePoolHdr The returned Free pool.\r
126\r
127 @retval EFI_OUT_OF_RESOURCES Allocation failed.\r
128 @retval EFI_SUCCESS Pool successfully allocated.\r
129\r
130**/\r
131EFI_STATUS\r
132InternalAllocPoolByIndex (\r
133 IN UINTN PoolIndex,\r
134 OUT FREE_POOL_HEADER **FreePoolHdr\r
135 )\r
136{\r
137 EFI_STATUS Status;\r
138 FREE_POOL_HEADER *Hdr;\r
139\r
52c0d06b 140 ASSERT (PoolIndex <= MAX_POOL_INDEX);\r
e42e9404 141 Status = EFI_SUCCESS;\r
142 if (PoolIndex == MAX_POOL_INDEX) {\r
143 Hdr = (FREE_POOL_HEADER *)AllocatePages (EFI_SIZE_TO_PAGES (MAX_POOL_SIZE << 1));\r
144 if (Hdr == NULL) {\r
5b422a7b 145 return EFI_OUT_OF_RESOURCES;\r
e42e9404 146 }\r
147 } else if (!IsListEmpty (&mSmmPoolLists[PoolIndex])) {\r
148 Hdr = BASE_CR (GetFirstNode (&mSmmPoolLists[PoolIndex]), FREE_POOL_HEADER, Link);\r
149 RemoveEntryList (&Hdr->Link);\r
150 } else {\r
151 Status = InternalAllocPoolByIndex (PoolIndex + 1, &Hdr);\r
152 if (!EFI_ERROR (Status)) {\r
153 Hdr->Header.Size >>= 1;\r
154 Hdr->Header.Available = TRUE;\r
155 InsertHeadList (&mSmmPoolLists[PoolIndex], &Hdr->Link);\r
156 Hdr = (FREE_POOL_HEADER*)((UINT8*)Hdr + Hdr->Header.Size);\r
157 }\r
158 }\r
159\r
160 if (!EFI_ERROR (Status)) {\r
161 Hdr->Header.Size = MIN_POOL_SIZE << PoolIndex;\r
162 Hdr->Header.Available = FALSE;\r
163 }\r
164\r
165 *FreePoolHdr = Hdr;\r
166 return Status;\r
167}\r
168\r
169/**\r
170 Internal Function. Free a pool by specified PoolIndex.\r
171\r
172 @param FreePoolHdr The pool to free.\r
173\r
174 @retval EFI_SUCCESS Pool successfully freed.\r
175\r
176**/\r
177EFI_STATUS\r
178InternalFreePoolByIndex (\r
179 IN FREE_POOL_HEADER *FreePoolHdr\r
180 )\r
181{\r
182 UINTN PoolIndex;\r
183\r
184 ASSERT ((FreePoolHdr->Header.Size & (FreePoolHdr->Header.Size - 1)) == 0);\r
185 ASSERT (((UINTN)FreePoolHdr & (FreePoolHdr->Header.Size - 1)) == 0);\r
186 ASSERT (FreePoolHdr->Header.Size >= MIN_POOL_SIZE);\r
187\r
188 PoolIndex = HighBitSet32 ((UINT32)FreePoolHdr->Header.Size) - MIN_POOL_SHIFT;\r
189 FreePoolHdr->Header.Available = TRUE;\r
5b422a7b 190 ASSERT (PoolIndex < MAX_POOL_INDEX);\r
e42e9404 191 InsertHeadList (&mSmmPoolLists[PoolIndex], &FreePoolHdr->Link);\r
192 return EFI_SUCCESS;\r
193}\r
194\r
195/**\r
196 Allocate pool of a particular type.\r
197\r
198 @param PoolType Type of pool to allocate.\r
199 @param Size The amount of pool to allocate.\r
200 @param Buffer The address to return a pointer to the allocated\r
201 pool.\r
202\r
203 @retval EFI_INVALID_PARAMETER PoolType not valid.\r
204 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.\r
205 @retval EFI_SUCCESS Pool successfully allocated.\r
206\r
207**/\r
208EFI_STATUS\r
209EFIAPI\r
210SmmAllocatePool (\r
211 IN EFI_MEMORY_TYPE PoolType,\r
212 IN UINTN Size,\r
213 OUT VOID **Buffer\r
214 )\r
215{\r
216 POOL_HEADER *PoolHdr;\r
217 FREE_POOL_HEADER *FreePoolHdr;\r
218 EFI_STATUS Status;\r
219 EFI_PHYSICAL_ADDRESS Address;\r
220 UINTN PoolIndex;\r
221\r
222 if (PoolType != EfiRuntimeServicesCode &&\r
223 PoolType != EfiRuntimeServicesData) {\r
224 return EFI_INVALID_PARAMETER;\r
225 }\r
226\r
227 if (Size == 0) {\r
228 *Buffer = NULL;\r
229 return EFI_SUCCESS;\r
230 }\r
231\r
232 Size += sizeof (*PoolHdr);\r
233 if (Size > MAX_POOL_SIZE) {\r
234 Size = EFI_SIZE_TO_PAGES (Size);\r
235 Status = SmmAllocatePages (AllocateAnyPages, PoolType, Size, &Address);\r
236 if (EFI_ERROR (Status)) {\r
237 return Status;\r
238 }\r
239\r
240 PoolHdr = (POOL_HEADER*)(UINTN)Address;\r
241 PoolHdr->Size = EFI_PAGES_TO_SIZE (Size);\r
242 PoolHdr->Available = FALSE;\r
243 *Buffer = PoolHdr + 1;\r
244 return Status;\r
245 }\r
246\r
247 Size = (Size + MIN_POOL_SIZE - 1) >> MIN_POOL_SHIFT;\r
248 PoolIndex = HighBitSet32 ((UINT32)Size);\r
249 if ((Size & (Size - 1)) != 0) {\r
250 PoolIndex++;\r
251 }\r
252\r
253 Status = InternalAllocPoolByIndex (PoolIndex, &FreePoolHdr);\r
254 *Buffer = &FreePoolHdr->Header + 1;\r
255 return Status;\r
256}\r
257\r
258/**\r
259 Frees pool.\r
260\r
261 @param Buffer The allocated pool entry to free.\r
262\r
263 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.\r
264 @retval EFI_SUCCESS Pool successfully freed.\r
265\r
266**/\r
267EFI_STATUS\r
268EFIAPI\r
269SmmFreePool (\r
270 IN VOID *Buffer\r
271 )\r
272{\r
273 FREE_POOL_HEADER *FreePoolHdr;\r
274\r
275 if (Buffer == NULL) {\r
276 return EFI_INVALID_PARAMETER;\r
277 }\r
278\r
279 FreePoolHdr = (FREE_POOL_HEADER*)((POOL_HEADER*)Buffer - 1);\r
280 ASSERT (!FreePoolHdr->Header.Available);\r
281\r
282 if (FreePoolHdr->Header.Size > MAX_POOL_SIZE) {\r
283 ASSERT (((UINTN)FreePoolHdr & EFI_PAGE_MASK) == 0);\r
284 ASSERT ((FreePoolHdr->Header.Size & EFI_PAGE_MASK) == 0);\r
285 return SmmFreePages (\r
286 (EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr,\r
287 EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size)\r
288 );\r
289 }\r
290 return InternalFreePoolByIndex (FreePoolHdr);\r
291}\r