]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/PiSmmCore/Pool.c
MdeModulePkg/PiSmmCore: Add MemoryAttributes support.
[mirror_edk2.git] / MdeModulePkg / Core / PiSmmCore / Pool.c
1 /** @file
2 SMM Memory pool management functions.
3
4 Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials are licensed and made available
6 under the terms and conditions of the BSD License which accompanies this
7 distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "PiSmmCore.h"
16
17 LIST_ENTRY mSmmPoolLists[MAX_POOL_INDEX];
18 //
19 // To cache the SMRAM base since when Loading modules At fixed address feature is enabled,
20 // all module is assigned an offset relative the SMRAM base in build time.
21 //
22 GLOBAL_REMOVE_IF_UNREFERENCED EFI_PHYSICAL_ADDRESS gLoadModuleAtFixAddressSmramBase = 0;
23
24 /**
25 Called to initialize the memory service.
26
27 @param SmramRangeCount Number of SMRAM Regions
28 @param SmramRanges Pointer to SMRAM Descriptors
29
30 **/
31 VOID
32 SmmInitializeMemoryServices (
33 IN UINTN SmramRangeCount,
34 IN EFI_SMRAM_DESCRIPTOR *SmramRanges
35 )
36 {
37 UINTN Index;
38 UINT64 SmmCodeSize;
39 UINTN CurrentSmramRangesIndex;
40 UINT64 MaxSize;
41
42 //
43 // Initialize Pool list
44 //
45 for (Index = ARRAY_SIZE (mSmmPoolLists); Index > 0;) {
46 InitializeListHead (&mSmmPoolLists[--Index]);
47 }
48 CurrentSmramRangesIndex = 0;
49 //
50 // If Loading Module At fixed Address feature is enabled, cache the SMRAM base here
51 //
52 if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {
53 //
54 // Build tool will calculate the smm code size and then patch the PcdLoadFixAddressSmmCodePageNumber
55 //
56 SmmCodeSize = LShiftU64 (PcdGet32(PcdLoadFixAddressSmmCodePageNumber), EFI_PAGE_SHIFT);
57
58 //
59 // Find the largest SMRAM range between 1MB and 4GB that is at least 256KB - 4K in size
60 //
61 for (Index = 0, MaxSize = SIZE_256KB - EFI_PAGE_SIZE; Index < SmramRangeCount; Index++) {
62 //
63 // Skip any SMRAM region that is already allocated, needs testing, or needs ECC initialization
64 //
65 if ((SmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {
66 continue;
67 }
68
69 if (SmramRanges[Index].CpuStart >= BASE_1MB) {
70 if ((SmramRanges[Index].CpuStart + SmramRanges[Index].PhysicalSize - 1) <= MAX_ADDRESS) {
71 if (SmramRanges[Index].PhysicalSize >= MaxSize) {
72 MaxSize = SmramRanges[Index].PhysicalSize;
73 CurrentSmramRangesIndex = Index;
74 }
75 }
76 }
77 }
78 gLoadModuleAtFixAddressSmramBase = SmramRanges[CurrentSmramRangesIndex].CpuStart;
79
80 //
81 // cut out a memory range from this SMRAM range with the size SmmCodeSize to hold SMM driver code
82 // A notable thing is that SMM core is already loaded into this range.
83 //
84 SmramRanges[CurrentSmramRangesIndex].CpuStart = SmramRanges[CurrentSmramRangesIndex].CpuStart + SmmCodeSize;
85 SmramRanges[CurrentSmramRangesIndex].PhysicalSize = SmramRanges[CurrentSmramRangesIndex].PhysicalSize - SmmCodeSize;
86 }
87 //
88 // Initialize free SMRAM regions
89 // Need add Free memory at first, to let gSmmMemoryMap record data
90 //
91 for (Index = 0; Index < SmramRangeCount; Index++) {
92 if ((SmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {
93 continue;
94 }
95 SmmAddMemoryRegion (
96 SmramRanges[Index].CpuStart,
97 SmramRanges[Index].PhysicalSize,
98 EfiConventionalMemory,
99 SmramRanges[Index].RegionState
100 );
101 }
102
103 for (Index = 0; Index < SmramRangeCount; Index++) {
104 if ((SmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) == 0) {
105 continue;
106 }
107 SmmAddMemoryRegion (
108 SmramRanges[Index].CpuStart,
109 SmramRanges[Index].PhysicalSize,
110 EfiConventionalMemory,
111 SmramRanges[Index].RegionState
112 );
113 }
114
115 }
116
117 /**
118 Internal Function. Allocate a pool by specified PoolIndex.
119
120 @param PoolIndex Index which indicate the Pool size.
121 @param FreePoolHdr The returned Free pool.
122
123 @retval EFI_OUT_OF_RESOURCES Allocation failed.
124 @retval EFI_SUCCESS Pool successfully allocated.
125
126 **/
127 EFI_STATUS
128 InternalAllocPoolByIndex (
129 IN UINTN PoolIndex,
130 OUT FREE_POOL_HEADER **FreePoolHdr
131 )
132 {
133 EFI_STATUS Status;
134 FREE_POOL_HEADER *Hdr;
135 EFI_PHYSICAL_ADDRESS Address;
136
137 ASSERT (PoolIndex <= MAX_POOL_INDEX);
138 Status = EFI_SUCCESS;
139 Hdr = NULL;
140 if (PoolIndex == MAX_POOL_INDEX) {
141 Status = SmmInternalAllocatePages (AllocateAnyPages, EfiRuntimeServicesData, EFI_SIZE_TO_PAGES (MAX_POOL_SIZE << 1), &Address);
142 if (EFI_ERROR (Status)) {
143 return EFI_OUT_OF_RESOURCES;
144 }
145 Hdr = (FREE_POOL_HEADER *) (UINTN) Address;
146 } else if (!IsListEmpty (&mSmmPoolLists[PoolIndex])) {
147 Hdr = BASE_CR (GetFirstNode (&mSmmPoolLists[PoolIndex]), FREE_POOL_HEADER, Link);
148 RemoveEntryList (&Hdr->Link);
149 } else {
150 Status = InternalAllocPoolByIndex (PoolIndex + 1, &Hdr);
151 if (!EFI_ERROR (Status)) {
152 Hdr->Header.Size >>= 1;
153 Hdr->Header.Available = TRUE;
154 InsertHeadList (&mSmmPoolLists[PoolIndex], &Hdr->Link);
155 Hdr = (FREE_POOL_HEADER*)((UINT8*)Hdr + Hdr->Header.Size);
156 }
157 }
158
159 if (!EFI_ERROR (Status)) {
160 Hdr->Header.Size = MIN_POOL_SIZE << PoolIndex;
161 Hdr->Header.Available = FALSE;
162 }
163
164 *FreePoolHdr = Hdr;
165 return Status;
166 }
167
168 /**
169 Internal Function. Free a pool by specified PoolIndex.
170
171 @param FreePoolHdr The pool to free.
172
173 @retval EFI_SUCCESS Pool successfully freed.
174
175 **/
176 EFI_STATUS
177 InternalFreePoolByIndex (
178 IN FREE_POOL_HEADER *FreePoolHdr
179 )
180 {
181 UINTN PoolIndex;
182
183 ASSERT ((FreePoolHdr->Header.Size & (FreePoolHdr->Header.Size - 1)) == 0);
184 ASSERT (((UINTN)FreePoolHdr & (FreePoolHdr->Header.Size - 1)) == 0);
185 ASSERT (FreePoolHdr->Header.Size >= MIN_POOL_SIZE);
186
187 PoolIndex = (UINTN) (HighBitSet32 ((UINT32)FreePoolHdr->Header.Size) - MIN_POOL_SHIFT);
188 FreePoolHdr->Header.Available = TRUE;
189 ASSERT (PoolIndex < MAX_POOL_INDEX);
190 InsertHeadList (&mSmmPoolLists[PoolIndex], &FreePoolHdr->Link);
191 return EFI_SUCCESS;
192 }
193
194 /**
195 Allocate pool of a particular type.
196
197 @param PoolType Type of pool to allocate.
198 @param Size The amount of pool to allocate.
199 @param Buffer The address to return a pointer to the allocated
200 pool.
201
202 @retval EFI_INVALID_PARAMETER PoolType not valid.
203 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
204 @retval EFI_SUCCESS Pool successfully allocated.
205
206 **/
207 EFI_STATUS
208 EFIAPI
209 SmmInternalAllocatePool (
210 IN EFI_MEMORY_TYPE PoolType,
211 IN UINTN Size,
212 OUT VOID **Buffer
213 )
214 {
215 POOL_HEADER *PoolHdr;
216 FREE_POOL_HEADER *FreePoolHdr;
217 EFI_STATUS Status;
218 EFI_PHYSICAL_ADDRESS Address;
219 UINTN PoolIndex;
220
221 if (PoolType != EfiRuntimeServicesCode &&
222 PoolType != EfiRuntimeServicesData) {
223 return EFI_INVALID_PARAMETER;
224 }
225
226 Size += sizeof (*PoolHdr);
227 if (Size > MAX_POOL_SIZE) {
228 Size = EFI_SIZE_TO_PAGES (Size);
229 Status = SmmInternalAllocatePages (AllocateAnyPages, PoolType, Size, &Address);
230 if (EFI_ERROR (Status)) {
231 return Status;
232 }
233
234 PoolHdr = (POOL_HEADER*)(UINTN)Address;
235 PoolHdr->Size = EFI_PAGES_TO_SIZE (Size);
236 PoolHdr->Available = FALSE;
237 *Buffer = PoolHdr + 1;
238 return Status;
239 }
240
241 Size = (Size + MIN_POOL_SIZE - 1) >> MIN_POOL_SHIFT;
242 PoolIndex = (UINTN) HighBitSet32 ((UINT32)Size);
243 if ((Size & (Size - 1)) != 0) {
244 PoolIndex++;
245 }
246
247 Status = InternalAllocPoolByIndex (PoolIndex, &FreePoolHdr);
248 if (!EFI_ERROR(Status)) {
249 *Buffer = &FreePoolHdr->Header + 1;
250 }
251 return Status;
252 }
253
254 /**
255 Allocate pool of a particular type.
256
257 @param PoolType Type of pool to allocate.
258 @param Size The amount of pool to allocate.
259 @param Buffer The address to return a pointer to the allocated
260 pool.
261
262 @retval EFI_INVALID_PARAMETER PoolType not valid.
263 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
264 @retval EFI_SUCCESS Pool successfully allocated.
265
266 **/
267 EFI_STATUS
268 EFIAPI
269 SmmAllocatePool (
270 IN EFI_MEMORY_TYPE PoolType,
271 IN UINTN Size,
272 OUT VOID **Buffer
273 )
274 {
275 EFI_STATUS Status;
276
277 Status = SmmInternalAllocatePool (PoolType, Size, Buffer);
278 if (!EFI_ERROR (Status)) {
279 SmmCoreUpdateProfile (
280 (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),
281 MemoryProfileActionAllocatePool,
282 PoolType,
283 Size,
284 *Buffer,
285 NULL
286 );
287 }
288 return Status;
289 }
290
291 /**
292 Frees pool.
293
294 @param Buffer The allocated pool entry to free.
295
296 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
297 @retval EFI_SUCCESS Pool successfully freed.
298
299 **/
300 EFI_STATUS
301 EFIAPI
302 SmmInternalFreePool (
303 IN VOID *Buffer
304 )
305 {
306 FREE_POOL_HEADER *FreePoolHdr;
307
308 if (Buffer == NULL) {
309 return EFI_INVALID_PARAMETER;
310 }
311
312 FreePoolHdr = (FREE_POOL_HEADER*)((POOL_HEADER*)Buffer - 1);
313 ASSERT (!FreePoolHdr->Header.Available);
314
315 if (FreePoolHdr->Header.Size > MAX_POOL_SIZE) {
316 ASSERT (((UINTN)FreePoolHdr & EFI_PAGE_MASK) == 0);
317 ASSERT ((FreePoolHdr->Header.Size & EFI_PAGE_MASK) == 0);
318 return SmmInternalFreePages (
319 (EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr,
320 EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size)
321 );
322 }
323 return InternalFreePoolByIndex (FreePoolHdr);
324 }
325
326 /**
327 Frees pool.
328
329 @param Buffer The allocated pool entry to free.
330
331 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
332 @retval EFI_SUCCESS Pool successfully freed.
333
334 **/
335 EFI_STATUS
336 EFIAPI
337 SmmFreePool (
338 IN VOID *Buffer
339 )
340 {
341 EFI_STATUS Status;
342
343 Status = SmmInternalFreePool (Buffer);
344 if (!EFI_ERROR (Status)) {
345 SmmCoreUpdateProfile (
346 (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),
347 MemoryProfileActionFreePool,
348 EfiMaxMemoryType,
349 0,
350 Buffer,
351 NULL
352 );
353 }
354 return Status;
355 }