]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/PiSmmCore/Pool.c
MdeModulePkg/PiSmmCore: AllocatePool should use MemoryType.
[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[SmmPoolTypeMax][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 Convert a UEFI memory type to SMM pool type.
26
27 @param[in] MemoryType Type of pool to allocate.
28
29 @return SMM pool type
30 **/
31 SMM_POOL_TYPE
32 UefiMemoryTypeToSmmPoolType (
33 IN EFI_MEMORY_TYPE MemoryType
34 )
35 {
36 ASSERT ((MemoryType == EfiRuntimeServicesCode) || (MemoryType == EfiRuntimeServicesData));
37 switch (MemoryType) {
38 case EfiRuntimeServicesCode:
39 return SmmPoolTypeCode;
40 case EfiRuntimeServicesData:
41 return SmmPoolTypeData;
42 default:
43 return SmmPoolTypeMax;
44 }
45 }
46
47
48 /**
49 Called to initialize the memory service.
50
51 @param SmramRangeCount Number of SMRAM Regions
52 @param SmramRanges Pointer to SMRAM Descriptors
53
54 **/
55 VOID
56 SmmInitializeMemoryServices (
57 IN UINTN SmramRangeCount,
58 IN EFI_SMRAM_DESCRIPTOR *SmramRanges
59 )
60 {
61 UINTN Index;
62 UINT64 SmmCodeSize;
63 UINTN CurrentSmramRangesIndex;
64 UINT64 MaxSize;
65 UINTN SmmPoolTypeIndex;
66
67 //
68 // Initialize Pool list
69 //
70 for (SmmPoolTypeIndex = 0; SmmPoolTypeIndex < SmmPoolTypeMax; SmmPoolTypeIndex++) {
71 for (Index = 0; Index < ARRAY_SIZE (mSmmPoolLists[SmmPoolTypeIndex]); Index++) {
72 InitializeListHead (&mSmmPoolLists[SmmPoolTypeIndex][Index]);
73 }
74 }
75 CurrentSmramRangesIndex = 0;
76 //
77 // If Loading Module At fixed Address feature is enabled, cache the SMRAM base here
78 //
79 if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {
80 //
81 // Build tool will calculate the smm code size and then patch the PcdLoadFixAddressSmmCodePageNumber
82 //
83 SmmCodeSize = LShiftU64 (PcdGet32(PcdLoadFixAddressSmmCodePageNumber), EFI_PAGE_SHIFT);
84
85 //
86 // Find the largest SMRAM range between 1MB and 4GB that is at least 256KB - 4K in size
87 //
88 for (Index = 0, MaxSize = SIZE_256KB - EFI_PAGE_SIZE; Index < SmramRangeCount; Index++) {
89 //
90 // Skip any SMRAM region that is already allocated, needs testing, or needs ECC initialization
91 //
92 if ((SmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {
93 continue;
94 }
95
96 if (SmramRanges[Index].CpuStart >= BASE_1MB) {
97 if ((SmramRanges[Index].CpuStart + SmramRanges[Index].PhysicalSize - 1) <= MAX_ADDRESS) {
98 if (SmramRanges[Index].PhysicalSize >= MaxSize) {
99 MaxSize = SmramRanges[Index].PhysicalSize;
100 CurrentSmramRangesIndex = Index;
101 }
102 }
103 }
104 }
105 gLoadModuleAtFixAddressSmramBase = SmramRanges[CurrentSmramRangesIndex].CpuStart;
106
107 //
108 // cut out a memory range from this SMRAM range with the size SmmCodeSize to hold SMM driver code
109 // A notable thing is that SMM core is already loaded into this range.
110 //
111 SmramRanges[CurrentSmramRangesIndex].CpuStart = SmramRanges[CurrentSmramRangesIndex].CpuStart + SmmCodeSize;
112 SmramRanges[CurrentSmramRangesIndex].PhysicalSize = SmramRanges[CurrentSmramRangesIndex].PhysicalSize - SmmCodeSize;
113 }
114 //
115 // Add Free SMRAM regions
116 // Need add Free memory at first, to let gSmmMemoryMap record data
117 //
118 for (Index = 0; Index < SmramRangeCount; Index++) {
119 if ((SmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {
120 continue;
121 }
122 SmmAddMemoryRegion (
123 SmramRanges[Index].CpuStart,
124 SmramRanges[Index].PhysicalSize,
125 EfiConventionalMemory,
126 SmramRanges[Index].RegionState
127 );
128 }
129
130 //
131 // Add the allocated SMRAM regions
132 //
133 for (Index = 0; Index < SmramRangeCount; Index++) {
134 if ((SmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) == 0) {
135 continue;
136 }
137 SmmAddMemoryRegion (
138 SmramRanges[Index].CpuStart,
139 SmramRanges[Index].PhysicalSize,
140 EfiConventionalMemory,
141 SmramRanges[Index].RegionState
142 );
143 }
144
145 }
146
147 /**
148 Internal Function. Allocate a pool by specified PoolIndex.
149
150 @param PoolType Type of pool to allocate.
151 @param PoolIndex Index which indicate the Pool size.
152 @param FreePoolHdr The returned Free pool.
153
154 @retval EFI_OUT_OF_RESOURCES Allocation failed.
155 @retval EFI_SUCCESS Pool successfully allocated.
156
157 **/
158 EFI_STATUS
159 InternalAllocPoolByIndex (
160 IN EFI_MEMORY_TYPE PoolType,
161 IN UINTN PoolIndex,
162 OUT FREE_POOL_HEADER **FreePoolHdr
163 )
164 {
165 EFI_STATUS Status;
166 FREE_POOL_HEADER *Hdr;
167 EFI_PHYSICAL_ADDRESS Address;
168 SMM_POOL_TYPE SmmPoolType;
169
170 SmmPoolType = UefiMemoryTypeToSmmPoolType(PoolType);
171
172 ASSERT (PoolIndex <= MAX_POOL_INDEX);
173 Status = EFI_SUCCESS;
174 Hdr = NULL;
175 if (PoolIndex == MAX_POOL_INDEX) {
176 Status = SmmInternalAllocatePages (AllocateAnyPages, PoolType, EFI_SIZE_TO_PAGES (MAX_POOL_SIZE << 1), &Address);
177 if (EFI_ERROR (Status)) {
178 return EFI_OUT_OF_RESOURCES;
179 }
180 Hdr = (FREE_POOL_HEADER *) (UINTN) Address;
181 } else if (!IsListEmpty (&mSmmPoolLists[SmmPoolType][PoolIndex])) {
182 Hdr = BASE_CR (GetFirstNode (&mSmmPoolLists[SmmPoolType][PoolIndex]), FREE_POOL_HEADER, Link);
183 RemoveEntryList (&Hdr->Link);
184 } else {
185 Status = InternalAllocPoolByIndex (PoolType, PoolIndex + 1, &Hdr);
186 if (!EFI_ERROR (Status)) {
187 Hdr->Header.Size >>= 1;
188 Hdr->Header.Available = TRUE;
189 Hdr->Header.Type = PoolType;
190 InsertHeadList (&mSmmPoolLists[SmmPoolType][PoolIndex], &Hdr->Link);
191 Hdr = (FREE_POOL_HEADER*)((UINT8*)Hdr + Hdr->Header.Size);
192 }
193 }
194
195 if (!EFI_ERROR (Status)) {
196 Hdr->Header.Size = MIN_POOL_SIZE << PoolIndex;
197 Hdr->Header.Available = FALSE;
198 Hdr->Header.Type = PoolType;
199 }
200
201 *FreePoolHdr = Hdr;
202 return Status;
203 }
204
205 /**
206 Internal Function. Free a pool by specified PoolIndex.
207
208 @param FreePoolHdr The pool to free.
209
210 @retval EFI_SUCCESS Pool successfully freed.
211
212 **/
213 EFI_STATUS
214 InternalFreePoolByIndex (
215 IN FREE_POOL_HEADER *FreePoolHdr
216 )
217 {
218 UINTN PoolIndex;
219 SMM_POOL_TYPE SmmPoolType;
220
221 ASSERT ((FreePoolHdr->Header.Size & (FreePoolHdr->Header.Size - 1)) == 0);
222 ASSERT (((UINTN)FreePoolHdr & (FreePoolHdr->Header.Size - 1)) == 0);
223 ASSERT (FreePoolHdr->Header.Size >= MIN_POOL_SIZE);
224
225 SmmPoolType = UefiMemoryTypeToSmmPoolType(FreePoolHdr->Header.Type);
226
227 PoolIndex = (UINTN) (HighBitSet32 ((UINT32)FreePoolHdr->Header.Size) - MIN_POOL_SHIFT);
228 FreePoolHdr->Header.Available = TRUE;
229 ASSERT (PoolIndex < MAX_POOL_INDEX);
230 InsertHeadList (&mSmmPoolLists[SmmPoolType][PoolIndex], &FreePoolHdr->Link);
231 return EFI_SUCCESS;
232 }
233
234 /**
235 Allocate pool of a particular type.
236
237 @param PoolType Type of pool to allocate.
238 @param Size The amount of pool to allocate.
239 @param Buffer The address to return a pointer to the allocated
240 pool.
241
242 @retval EFI_INVALID_PARAMETER PoolType not valid.
243 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
244 @retval EFI_SUCCESS Pool successfully allocated.
245
246 **/
247 EFI_STATUS
248 EFIAPI
249 SmmInternalAllocatePool (
250 IN EFI_MEMORY_TYPE PoolType,
251 IN UINTN Size,
252 OUT VOID **Buffer
253 )
254 {
255 POOL_HEADER *PoolHdr;
256 FREE_POOL_HEADER *FreePoolHdr;
257 EFI_STATUS Status;
258 EFI_PHYSICAL_ADDRESS Address;
259 UINTN PoolIndex;
260
261 if (PoolType != EfiRuntimeServicesCode &&
262 PoolType != EfiRuntimeServicesData) {
263 return EFI_INVALID_PARAMETER;
264 }
265
266 Size += sizeof (*PoolHdr);
267 if (Size > MAX_POOL_SIZE) {
268 Size = EFI_SIZE_TO_PAGES (Size);
269 Status = SmmInternalAllocatePages (AllocateAnyPages, PoolType, Size, &Address);
270 if (EFI_ERROR (Status)) {
271 return Status;
272 }
273
274 PoolHdr = (POOL_HEADER*)(UINTN)Address;
275 PoolHdr->Size = EFI_PAGES_TO_SIZE (Size);
276 PoolHdr->Available = FALSE;
277 PoolHdr->Type = PoolType;
278 *Buffer = PoolHdr + 1;
279 return Status;
280 }
281
282 Size = (Size + MIN_POOL_SIZE - 1) >> MIN_POOL_SHIFT;
283 PoolIndex = (UINTN) HighBitSet32 ((UINT32)Size);
284 if ((Size & (Size - 1)) != 0) {
285 PoolIndex++;
286 }
287
288 Status = InternalAllocPoolByIndex (PoolType, PoolIndex, &FreePoolHdr);
289 if (!EFI_ERROR(Status)) {
290 *Buffer = &FreePoolHdr->Header + 1;
291 }
292 return Status;
293 }
294
295 /**
296 Allocate pool of a particular type.
297
298 @param PoolType Type of pool to allocate.
299 @param Size The amount of pool to allocate.
300 @param Buffer The address to return a pointer to the allocated
301 pool.
302
303 @retval EFI_INVALID_PARAMETER PoolType not valid.
304 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
305 @retval EFI_SUCCESS Pool successfully allocated.
306
307 **/
308 EFI_STATUS
309 EFIAPI
310 SmmAllocatePool (
311 IN EFI_MEMORY_TYPE PoolType,
312 IN UINTN Size,
313 OUT VOID **Buffer
314 )
315 {
316 EFI_STATUS Status;
317
318 Status = SmmInternalAllocatePool (PoolType, Size, Buffer);
319 if (!EFI_ERROR (Status)) {
320 SmmCoreUpdateProfile (
321 (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),
322 MemoryProfileActionAllocatePool,
323 PoolType,
324 Size,
325 *Buffer,
326 NULL
327 );
328 }
329 return Status;
330 }
331
332 /**
333 Frees pool.
334
335 @param Buffer The allocated pool entry to free.
336
337 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
338 @retval EFI_SUCCESS Pool successfully freed.
339
340 **/
341 EFI_STATUS
342 EFIAPI
343 SmmInternalFreePool (
344 IN VOID *Buffer
345 )
346 {
347 FREE_POOL_HEADER *FreePoolHdr;
348
349 if (Buffer == NULL) {
350 return EFI_INVALID_PARAMETER;
351 }
352
353 FreePoolHdr = (FREE_POOL_HEADER*)((POOL_HEADER*)Buffer - 1);
354 ASSERT (!FreePoolHdr->Header.Available);
355
356 if (FreePoolHdr->Header.Size > MAX_POOL_SIZE) {
357 ASSERT (((UINTN)FreePoolHdr & EFI_PAGE_MASK) == 0);
358 ASSERT ((FreePoolHdr->Header.Size & EFI_PAGE_MASK) == 0);
359 return SmmInternalFreePages (
360 (EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr,
361 EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size)
362 );
363 }
364 return InternalFreePoolByIndex (FreePoolHdr);
365 }
366
367 /**
368 Frees pool.
369
370 @param Buffer The allocated pool entry to free.
371
372 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
373 @retval EFI_SUCCESS Pool successfully freed.
374
375 **/
376 EFI_STATUS
377 EFIAPI
378 SmmFreePool (
379 IN VOID *Buffer
380 )
381 {
382 EFI_STATUS Status;
383
384 Status = SmmInternalFreePool (Buffer);
385 if (!EFI_ERROR (Status)) {
386 SmmCoreUpdateProfile (
387 (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),
388 MemoryProfileActionFreePool,
389 EfiMaxMemoryType,
390 0,
391 Buffer,
392 NULL
393 );
394 }
395 return Status;
396 }