]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/PiSmmCore/Pool.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Core / PiSmmCore / Pool.c
1 /** @file
2 SMM Memory pool management functions.
3
4 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "PiSmmCore.h"
10
11 LIST_ENTRY mSmmPoolLists[SmmPoolTypeMax][MAX_POOL_INDEX];
12 //
13 // To cache the SMRAM base since when Loading modules At fixed address feature is enabled,
14 // all module is assigned an offset relative the SMRAM base in build time.
15 //
16 GLOBAL_REMOVE_IF_UNREFERENCED EFI_PHYSICAL_ADDRESS gLoadModuleAtFixAddressSmramBase = 0;
17
18 /**
19 Convert a UEFI memory type to SMM pool type.
20
21 @param[in] MemoryType Type of pool to allocate.
22
23 @return SMM pool type
24 **/
25 SMM_POOL_TYPE
26 UefiMemoryTypeToSmmPoolType (
27 IN EFI_MEMORY_TYPE MemoryType
28 )
29 {
30 ASSERT ((MemoryType == EfiRuntimeServicesCode) || (MemoryType == EfiRuntimeServicesData));
31 switch (MemoryType) {
32 case EfiRuntimeServicesCode:
33 return SmmPoolTypeCode;
34 case EfiRuntimeServicesData:
35 return SmmPoolTypeData;
36 default:
37 return SmmPoolTypeMax;
38 }
39 }
40
41 /**
42 Called to initialize the memory service.
43
44 @param SmramRangeCount Number of SMRAM Regions
45 @param SmramRanges Pointer to SMRAM Descriptors
46
47 **/
48 VOID
49 SmmInitializeMemoryServices (
50 IN UINTN SmramRangeCount,
51 IN EFI_SMRAM_DESCRIPTOR *SmramRanges
52 )
53 {
54 UINTN Index;
55 EFI_STATUS Status;
56 UINTN SmmPoolTypeIndex;
57 EFI_LOAD_FIXED_ADDRESS_CONFIGURATION_TABLE *LMFAConfigurationTable;
58
59 //
60 // Initialize Pool list
61 //
62 for (SmmPoolTypeIndex = 0; SmmPoolTypeIndex < SmmPoolTypeMax; SmmPoolTypeIndex++) {
63 for (Index = 0; Index < ARRAY_SIZE (mSmmPoolLists[SmmPoolTypeIndex]); Index++) {
64 InitializeListHead (&mSmmPoolLists[SmmPoolTypeIndex][Index]);
65 }
66 }
67
68 Status = EfiGetSystemConfigurationTable (
69 &gLoadFixedAddressConfigurationTableGuid,
70 (VOID **)&LMFAConfigurationTable
71 );
72 if (!EFI_ERROR (Status) && (LMFAConfigurationTable != NULL)) {
73 gLoadModuleAtFixAddressSmramBase = LMFAConfigurationTable->SmramBase;
74 }
75
76 //
77 // Add Free SMRAM regions
78 // Need add Free memory at first, to let gSmmMemoryMap record data
79 //
80 for (Index = 0; Index < SmramRangeCount; Index++) {
81 if ((SmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {
82 continue;
83 }
84
85 SmmAddMemoryRegion (
86 SmramRanges[Index].CpuStart,
87 SmramRanges[Index].PhysicalSize,
88 EfiConventionalMemory,
89 SmramRanges[Index].RegionState
90 );
91 }
92
93 //
94 // Add the allocated SMRAM regions
95 //
96 for (Index = 0; Index < SmramRangeCount; Index++) {
97 if ((SmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) == 0) {
98 continue;
99 }
100
101 SmmAddMemoryRegion (
102 SmramRanges[Index].CpuStart,
103 SmramRanges[Index].PhysicalSize,
104 EfiConventionalMemory,
105 SmramRanges[Index].RegionState
106 );
107 }
108 }
109
110 /**
111 Internal Function. Allocate a pool by specified PoolIndex.
112
113 @param PoolType Type of pool to allocate.
114 @param PoolIndex Index which indicate the Pool size.
115 @param FreePoolHdr The returned Free pool.
116
117 @retval EFI_OUT_OF_RESOURCES Allocation failed.
118 @retval EFI_SUCCESS Pool successfully allocated.
119
120 **/
121 EFI_STATUS
122 InternalAllocPoolByIndex (
123 IN EFI_MEMORY_TYPE PoolType,
124 IN UINTN PoolIndex,
125 OUT FREE_POOL_HEADER **FreePoolHdr
126 )
127 {
128 EFI_STATUS Status;
129 FREE_POOL_HEADER *Hdr;
130 POOL_TAIL *Tail;
131 EFI_PHYSICAL_ADDRESS Address;
132 SMM_POOL_TYPE SmmPoolType;
133
134 Address = 0;
135 SmmPoolType = UefiMemoryTypeToSmmPoolType (PoolType);
136
137 ASSERT (PoolIndex <= MAX_POOL_INDEX);
138 Status = EFI_SUCCESS;
139 Hdr = NULL;
140 if (PoolIndex == MAX_POOL_INDEX) {
141 Status = SmmInternalAllocatePages (
142 AllocateAnyPages,
143 PoolType,
144 EFI_SIZE_TO_PAGES (MAX_POOL_SIZE << 1),
145 &Address,
146 FALSE
147 );
148 if (EFI_ERROR (Status)) {
149 return EFI_OUT_OF_RESOURCES;
150 }
151
152 Hdr = (FREE_POOL_HEADER *)(UINTN)Address;
153 } else if (!IsListEmpty (&mSmmPoolLists[SmmPoolType][PoolIndex])) {
154 Hdr = BASE_CR (GetFirstNode (&mSmmPoolLists[SmmPoolType][PoolIndex]), FREE_POOL_HEADER, Link);
155 RemoveEntryList (&Hdr->Link);
156 } else {
157 Status = InternalAllocPoolByIndex (PoolType, PoolIndex + 1, &Hdr);
158 if (!EFI_ERROR (Status)) {
159 Hdr->Header.Signature = 0;
160 Hdr->Header.Size >>= 1;
161 Hdr->Header.Available = TRUE;
162 Hdr->Header.Type = 0;
163 Tail = HEAD_TO_TAIL (&Hdr->Header);
164 Tail->Signature = 0;
165 Tail->Size = 0;
166 InsertHeadList (&mSmmPoolLists[SmmPoolType][PoolIndex], &Hdr->Link);
167 Hdr = (FREE_POOL_HEADER *)((UINT8 *)Hdr + Hdr->Header.Size);
168 }
169 }
170
171 if (!EFI_ERROR (Status)) {
172 Hdr->Header.Signature = POOL_HEAD_SIGNATURE;
173 Hdr->Header.Size = MIN_POOL_SIZE << PoolIndex;
174 Hdr->Header.Available = FALSE;
175 Hdr->Header.Type = PoolType;
176 Tail = HEAD_TO_TAIL (&Hdr->Header);
177 Tail->Signature = POOL_TAIL_SIGNATURE;
178 Tail->Size = Hdr->Header.Size;
179 }
180
181 *FreePoolHdr = Hdr;
182 return Status;
183 }
184
185 /**
186 Internal Function. Free a pool by specified PoolIndex.
187
188 @param FreePoolHdr The pool to free.
189 @param PoolTail The pointer to the pool tail.
190
191 @retval EFI_SUCCESS Pool successfully freed.
192
193 **/
194 EFI_STATUS
195 InternalFreePoolByIndex (
196 IN FREE_POOL_HEADER *FreePoolHdr,
197 IN POOL_TAIL *PoolTail
198 )
199 {
200 UINTN PoolIndex;
201 SMM_POOL_TYPE SmmPoolType;
202
203 ASSERT ((FreePoolHdr->Header.Size & (FreePoolHdr->Header.Size - 1)) == 0);
204 ASSERT (((UINTN)FreePoolHdr & (FreePoolHdr->Header.Size - 1)) == 0);
205 ASSERT (FreePoolHdr->Header.Size >= MIN_POOL_SIZE);
206
207 SmmPoolType = UefiMemoryTypeToSmmPoolType (FreePoolHdr->Header.Type);
208
209 PoolIndex = (UINTN)(HighBitSet32 ((UINT32)FreePoolHdr->Header.Size) - MIN_POOL_SHIFT);
210 FreePoolHdr->Header.Signature = 0;
211 FreePoolHdr->Header.Available = TRUE;
212 FreePoolHdr->Header.Type = 0;
213 PoolTail->Signature = 0;
214 PoolTail->Size = 0;
215 ASSERT (PoolIndex < MAX_POOL_INDEX);
216 InsertHeadList (&mSmmPoolLists[SmmPoolType][PoolIndex], &FreePoolHdr->Link);
217 return EFI_SUCCESS;
218 }
219
220 /**
221 Allocate pool of a particular type.
222
223 @param PoolType Type of pool to allocate.
224 @param Size The amount of pool to allocate.
225 @param Buffer The address to return a pointer to the allocated
226 pool.
227
228 @retval EFI_INVALID_PARAMETER PoolType not valid.
229 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
230 @retval EFI_SUCCESS Pool successfully allocated.
231
232 **/
233 EFI_STATUS
234 EFIAPI
235 SmmInternalAllocatePool (
236 IN EFI_MEMORY_TYPE PoolType,
237 IN UINTN Size,
238 OUT VOID **Buffer
239 )
240 {
241 POOL_HEADER *PoolHdr;
242 POOL_TAIL *PoolTail;
243 FREE_POOL_HEADER *FreePoolHdr;
244 EFI_STATUS Status;
245 EFI_PHYSICAL_ADDRESS Address;
246 UINTN PoolIndex;
247 BOOLEAN HasPoolTail;
248 BOOLEAN NeedGuard;
249 UINTN NoPages;
250
251 Address = 0;
252
253 if ((PoolType != EfiRuntimeServicesCode) &&
254 (PoolType != EfiRuntimeServicesData))
255 {
256 return EFI_INVALID_PARAMETER;
257 }
258
259 NeedGuard = IsPoolTypeToGuard (PoolType);
260 HasPoolTail = !(NeedGuard &&
261 ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0));
262
263 //
264 // Adjust the size by the pool header & tail overhead
265 //
266 Size += POOL_OVERHEAD;
267 if ((Size > MAX_POOL_SIZE) || NeedGuard) {
268 if (!HasPoolTail) {
269 Size -= sizeof (POOL_TAIL);
270 }
271
272 NoPages = EFI_SIZE_TO_PAGES (Size);
273 Status = SmmInternalAllocatePages (
274 AllocateAnyPages,
275 PoolType,
276 NoPages,
277 &Address,
278 NeedGuard
279 );
280 if (EFI_ERROR (Status)) {
281 return Status;
282 }
283
284 if (NeedGuard) {
285 ASSERT (VerifyMemoryGuard (Address, NoPages) == TRUE);
286 Address = (EFI_PHYSICAL_ADDRESS)(UINTN)AdjustPoolHeadA (
287 Address,
288 NoPages,
289 Size
290 );
291 }
292
293 PoolHdr = (POOL_HEADER *)(UINTN)Address;
294 PoolHdr->Signature = POOL_HEAD_SIGNATURE;
295 PoolHdr->Size = EFI_PAGES_TO_SIZE (NoPages);
296 PoolHdr->Available = FALSE;
297 PoolHdr->Type = PoolType;
298
299 if (HasPoolTail) {
300 PoolTail = HEAD_TO_TAIL (PoolHdr);
301 PoolTail->Signature = POOL_TAIL_SIGNATURE;
302 PoolTail->Size = PoolHdr->Size;
303 }
304
305 *Buffer = PoolHdr + 1;
306 return Status;
307 }
308
309 Size = (Size + MIN_POOL_SIZE - 1) >> MIN_POOL_SHIFT;
310 PoolIndex = (UINTN)HighBitSet32 ((UINT32)Size);
311 if ((Size & (Size - 1)) != 0) {
312 PoolIndex++;
313 }
314
315 Status = InternalAllocPoolByIndex (PoolType, PoolIndex, &FreePoolHdr);
316 if (!EFI_ERROR (Status)) {
317 *Buffer = &FreePoolHdr->Header + 1;
318 }
319
320 return Status;
321 }
322
323 /**
324 Allocate pool of a particular type.
325
326 @param PoolType Type of pool to allocate.
327 @param Size The amount of pool to allocate.
328 @param Buffer The address to return a pointer to the allocated
329 pool.
330
331 @retval EFI_INVALID_PARAMETER PoolType not valid.
332 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
333 @retval EFI_SUCCESS Pool successfully allocated.
334
335 **/
336 EFI_STATUS
337 EFIAPI
338 SmmAllocatePool (
339 IN EFI_MEMORY_TYPE PoolType,
340 IN UINTN Size,
341 OUT VOID **Buffer
342 )
343 {
344 EFI_STATUS Status;
345
346 Status = SmmInternalAllocatePool (PoolType, Size, Buffer);
347 if (!EFI_ERROR (Status)) {
348 SmmCoreUpdateProfile (
349 (EFI_PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),
350 MemoryProfileActionAllocatePool,
351 PoolType,
352 Size,
353 *Buffer,
354 NULL
355 );
356 }
357
358 return Status;
359 }
360
361 /**
362 Frees pool.
363
364 @param Buffer The allocated pool entry to free.
365
366 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
367 @retval EFI_SUCCESS Pool successfully freed.
368
369 **/
370 EFI_STATUS
371 EFIAPI
372 SmmInternalFreePool (
373 IN VOID *Buffer
374 )
375 {
376 FREE_POOL_HEADER *FreePoolHdr;
377 POOL_TAIL *PoolTail;
378 BOOLEAN HasPoolTail;
379 BOOLEAN MemoryGuarded;
380
381 if (Buffer == NULL) {
382 return EFI_INVALID_PARAMETER;
383 }
384
385 FreePoolHdr = (FREE_POOL_HEADER *)((POOL_HEADER *)Buffer - 1);
386 ASSERT (FreePoolHdr->Header.Signature == POOL_HEAD_SIGNATURE);
387 ASSERT (!FreePoolHdr->Header.Available);
388 if (FreePoolHdr->Header.Signature != POOL_HEAD_SIGNATURE) {
389 return EFI_INVALID_PARAMETER;
390 }
391
392 MemoryGuarded = IsHeapGuardEnabled () &&
393 IsMemoryGuarded ((EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr);
394 HasPoolTail = !(MemoryGuarded &&
395 ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0));
396
397 if (HasPoolTail) {
398 PoolTail = HEAD_TO_TAIL (&FreePoolHdr->Header);
399 ASSERT (PoolTail->Signature == POOL_TAIL_SIGNATURE);
400 ASSERT (FreePoolHdr->Header.Size == PoolTail->Size);
401 if (PoolTail->Signature != POOL_TAIL_SIGNATURE) {
402 return EFI_INVALID_PARAMETER;
403 }
404
405 if (FreePoolHdr->Header.Size != PoolTail->Size) {
406 return EFI_INVALID_PARAMETER;
407 }
408 } else {
409 PoolTail = NULL;
410 }
411
412 if (MemoryGuarded) {
413 Buffer = AdjustPoolHeadF ((EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr);
414 return SmmInternalFreePages (
415 (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer,
416 EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size),
417 TRUE
418 );
419 }
420
421 if (FreePoolHdr->Header.Size > MAX_POOL_SIZE) {
422 ASSERT (((UINTN)FreePoolHdr & EFI_PAGE_MASK) == 0);
423 ASSERT ((FreePoolHdr->Header.Size & EFI_PAGE_MASK) == 0);
424 return SmmInternalFreePages (
425 (EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr,
426 EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size),
427 FALSE
428 );
429 }
430
431 return InternalFreePoolByIndex (FreePoolHdr, PoolTail);
432 }
433
434 /**
435 Frees pool.
436
437 @param Buffer The allocated pool entry to free.
438
439 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
440 @retval EFI_SUCCESS Pool successfully freed.
441
442 **/
443 EFI_STATUS
444 EFIAPI
445 SmmFreePool (
446 IN VOID *Buffer
447 )
448 {
449 EFI_STATUS Status;
450
451 Status = SmmInternalFreePool (Buffer);
452 if (!EFI_ERROR (Status)) {
453 SmmCoreUpdateProfile (
454 (EFI_PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),
455 MemoryProfileActionFreePool,
456 EfiMaxMemoryType,
457 0,
458 Buffer,
459 NULL
460 );
461 }
462
463 return Status;
464 }