]> 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 /**
43 Called to initialize the memory service.
44
45 @param SmramRangeCount Number of SMRAM Regions
46 @param SmramRanges Pointer to SMRAM Descriptors
47
48 **/
49 VOID
50 SmmInitializeMemoryServices (
51 IN UINTN SmramRangeCount,
52 IN EFI_SMRAM_DESCRIPTOR *SmramRanges
53 )
54 {
55 UINTN Index;
56 EFI_STATUS Status;
57 UINTN SmmPoolTypeIndex;
58 EFI_LOAD_FIXED_ADDRESS_CONFIGURATION_TABLE *LMFAConfigurationTable;
59
60 //
61 // Initialize Pool list
62 //
63 for (SmmPoolTypeIndex = 0; SmmPoolTypeIndex < SmmPoolTypeMax; SmmPoolTypeIndex++) {
64 for (Index = 0; Index < ARRAY_SIZE (mSmmPoolLists[SmmPoolTypeIndex]); Index++) {
65 InitializeListHead (&mSmmPoolLists[SmmPoolTypeIndex][Index]);
66 }
67 }
68
69 Status = EfiGetSystemConfigurationTable (
70 &gLoadFixedAddressConfigurationTableGuid,
71 (VOID **) &LMFAConfigurationTable
72 );
73 if (!EFI_ERROR (Status) && LMFAConfigurationTable != NULL) {
74 gLoadModuleAtFixAddressSmramBase = LMFAConfigurationTable->SmramBase;
75 }
76
77 //
78 // Add Free SMRAM regions
79 // Need add Free memory at first, to let gSmmMemoryMap record data
80 //
81 for (Index = 0; Index < SmramRangeCount; Index++) {
82 if ((SmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {
83 continue;
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 SmmAddMemoryRegion (
101 SmramRanges[Index].CpuStart,
102 SmramRanges[Index].PhysicalSize,
103 EfiConventionalMemory,
104 SmramRanges[Index].RegionState
105 );
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 (AllocateAnyPages, PoolType,
142 EFI_SIZE_TO_PAGES (MAX_POOL_SIZE << 1),
143 &Address, FALSE);
144 if (EFI_ERROR (Status)) {
145 return EFI_OUT_OF_RESOURCES;
146 }
147 Hdr = (FREE_POOL_HEADER *) (UINTN) Address;
148 } else if (!IsListEmpty (&mSmmPoolLists[SmmPoolType][PoolIndex])) {
149 Hdr = BASE_CR (GetFirstNode (&mSmmPoolLists[SmmPoolType][PoolIndex]), FREE_POOL_HEADER, Link);
150 RemoveEntryList (&Hdr->Link);
151 } else {
152 Status = InternalAllocPoolByIndex (PoolType, PoolIndex + 1, &Hdr);
153 if (!EFI_ERROR (Status)) {
154 Hdr->Header.Signature = 0;
155 Hdr->Header.Size >>= 1;
156 Hdr->Header.Available = TRUE;
157 Hdr->Header.Type = 0;
158 Tail = HEAD_TO_TAIL(&Hdr->Header);
159 Tail->Signature = 0;
160 Tail->Size = 0;
161 InsertHeadList (&mSmmPoolLists[SmmPoolType][PoolIndex], &Hdr->Link);
162 Hdr = (FREE_POOL_HEADER*)((UINT8*)Hdr + Hdr->Header.Size);
163 }
164 }
165
166 if (!EFI_ERROR (Status)) {
167 Hdr->Header.Signature = POOL_HEAD_SIGNATURE;
168 Hdr->Header.Size = MIN_POOL_SIZE << PoolIndex;
169 Hdr->Header.Available = FALSE;
170 Hdr->Header.Type = PoolType;
171 Tail = HEAD_TO_TAIL(&Hdr->Header);
172 Tail->Signature = POOL_TAIL_SIGNATURE;
173 Tail->Size = Hdr->Header.Size;
174 }
175
176 *FreePoolHdr = Hdr;
177 return Status;
178 }
179
180 /**
181 Internal Function. Free a pool by specified PoolIndex.
182
183 @param FreePoolHdr The pool to free.
184 @param PoolTail The pointer to the pool tail.
185
186 @retval EFI_SUCCESS Pool successfully freed.
187
188 **/
189 EFI_STATUS
190 InternalFreePoolByIndex (
191 IN FREE_POOL_HEADER *FreePoolHdr,
192 IN POOL_TAIL *PoolTail
193 )
194 {
195 UINTN PoolIndex;
196 SMM_POOL_TYPE SmmPoolType;
197
198 ASSERT ((FreePoolHdr->Header.Size & (FreePoolHdr->Header.Size - 1)) == 0);
199 ASSERT (((UINTN)FreePoolHdr & (FreePoolHdr->Header.Size - 1)) == 0);
200 ASSERT (FreePoolHdr->Header.Size >= MIN_POOL_SIZE);
201
202 SmmPoolType = UefiMemoryTypeToSmmPoolType(FreePoolHdr->Header.Type);
203
204 PoolIndex = (UINTN) (HighBitSet32 ((UINT32)FreePoolHdr->Header.Size) - MIN_POOL_SHIFT);
205 FreePoolHdr->Header.Signature = 0;
206 FreePoolHdr->Header.Available = TRUE;
207 FreePoolHdr->Header.Type = 0;
208 PoolTail->Signature = 0;
209 PoolTail->Size = 0;
210 ASSERT (PoolIndex < MAX_POOL_INDEX);
211 InsertHeadList (&mSmmPoolLists[SmmPoolType][PoolIndex], &FreePoolHdr->Link);
212 return EFI_SUCCESS;
213 }
214
215 /**
216 Allocate pool of a particular type.
217
218 @param PoolType Type of pool to allocate.
219 @param Size The amount of pool to allocate.
220 @param Buffer The address to return a pointer to the allocated
221 pool.
222
223 @retval EFI_INVALID_PARAMETER PoolType not valid.
224 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
225 @retval EFI_SUCCESS Pool successfully allocated.
226
227 **/
228 EFI_STATUS
229 EFIAPI
230 SmmInternalAllocatePool (
231 IN EFI_MEMORY_TYPE PoolType,
232 IN UINTN Size,
233 OUT VOID **Buffer
234 )
235 {
236 POOL_HEADER *PoolHdr;
237 POOL_TAIL *PoolTail;
238 FREE_POOL_HEADER *FreePoolHdr;
239 EFI_STATUS Status;
240 EFI_PHYSICAL_ADDRESS Address;
241 UINTN PoolIndex;
242 BOOLEAN HasPoolTail;
243 BOOLEAN NeedGuard;
244 UINTN NoPages;
245
246 Address = 0;
247
248 if (PoolType != EfiRuntimeServicesCode &&
249 PoolType != EfiRuntimeServicesData) {
250 return EFI_INVALID_PARAMETER;
251 }
252
253 NeedGuard = IsPoolTypeToGuard (PoolType);
254 HasPoolTail = !(NeedGuard &&
255 ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0));
256
257 //
258 // Adjust the size by the pool header & tail overhead
259 //
260 Size += POOL_OVERHEAD;
261 if (Size > MAX_POOL_SIZE || NeedGuard) {
262 if (!HasPoolTail) {
263 Size -= sizeof (POOL_TAIL);
264 }
265
266 NoPages = EFI_SIZE_TO_PAGES (Size);
267 Status = SmmInternalAllocatePages (AllocateAnyPages, PoolType, NoPages,
268 &Address, NeedGuard);
269 if (EFI_ERROR (Status)) {
270 return Status;
271 }
272
273 if (NeedGuard) {
274 ASSERT (VerifyMemoryGuard (Address, NoPages) == TRUE);
275 Address = (EFI_PHYSICAL_ADDRESS)(UINTN)AdjustPoolHeadA (
276 Address,
277 NoPages,
278 Size
279 );
280 }
281
282 PoolHdr = (POOL_HEADER*)(UINTN)Address;
283 PoolHdr->Signature = POOL_HEAD_SIGNATURE;
284 PoolHdr->Size = EFI_PAGES_TO_SIZE (NoPages);
285 PoolHdr->Available = FALSE;
286 PoolHdr->Type = PoolType;
287
288 if (HasPoolTail) {
289 PoolTail = HEAD_TO_TAIL (PoolHdr);
290 PoolTail->Signature = POOL_TAIL_SIGNATURE;
291 PoolTail->Size = PoolHdr->Size;
292 }
293
294 *Buffer = PoolHdr + 1;
295 return Status;
296 }
297
298 Size = (Size + MIN_POOL_SIZE - 1) >> MIN_POOL_SHIFT;
299 PoolIndex = (UINTN) HighBitSet32 ((UINT32)Size);
300 if ((Size & (Size - 1)) != 0) {
301 PoolIndex++;
302 }
303
304 Status = InternalAllocPoolByIndex (PoolType, PoolIndex, &FreePoolHdr);
305 if (!EFI_ERROR(Status)) {
306 *Buffer = &FreePoolHdr->Header + 1;
307 }
308 return Status;
309 }
310
311 /**
312 Allocate pool of a particular type.
313
314 @param PoolType Type of pool to allocate.
315 @param Size The amount of pool to allocate.
316 @param Buffer The address to return a pointer to the allocated
317 pool.
318
319 @retval EFI_INVALID_PARAMETER PoolType not valid.
320 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
321 @retval EFI_SUCCESS Pool successfully allocated.
322
323 **/
324 EFI_STATUS
325 EFIAPI
326 SmmAllocatePool (
327 IN EFI_MEMORY_TYPE PoolType,
328 IN UINTN Size,
329 OUT VOID **Buffer
330 )
331 {
332 EFI_STATUS Status;
333
334 Status = SmmInternalAllocatePool (PoolType, Size, Buffer);
335 if (!EFI_ERROR (Status)) {
336 SmmCoreUpdateProfile (
337 (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),
338 MemoryProfileActionAllocatePool,
339 PoolType,
340 Size,
341 *Buffer,
342 NULL
343 );
344 }
345 return Status;
346 }
347
348 /**
349 Frees pool.
350
351 @param Buffer The allocated pool entry to free.
352
353 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
354 @retval EFI_SUCCESS Pool successfully freed.
355
356 **/
357 EFI_STATUS
358 EFIAPI
359 SmmInternalFreePool (
360 IN VOID *Buffer
361 )
362 {
363 FREE_POOL_HEADER *FreePoolHdr;
364 POOL_TAIL *PoolTail;
365 BOOLEAN HasPoolTail;
366 BOOLEAN MemoryGuarded;
367
368 if (Buffer == NULL) {
369 return EFI_INVALID_PARAMETER;
370 }
371
372 MemoryGuarded = IsHeapGuardEnabled () &&
373 IsMemoryGuarded ((EFI_PHYSICAL_ADDRESS)(UINTN)Buffer);
374 HasPoolTail = !(MemoryGuarded &&
375 ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0));
376
377 FreePoolHdr = (FREE_POOL_HEADER*)((POOL_HEADER*)Buffer - 1);
378 ASSERT (FreePoolHdr->Header.Signature == POOL_HEAD_SIGNATURE);
379 ASSERT (!FreePoolHdr->Header.Available);
380 if (FreePoolHdr->Header.Signature != POOL_HEAD_SIGNATURE) {
381 return EFI_INVALID_PARAMETER;
382 }
383
384 if (HasPoolTail) {
385 PoolTail = HEAD_TO_TAIL (&FreePoolHdr->Header);
386 ASSERT (PoolTail->Signature == POOL_TAIL_SIGNATURE);
387 ASSERT (FreePoolHdr->Header.Size == PoolTail->Size);
388 if (PoolTail->Signature != POOL_TAIL_SIGNATURE) {
389 return EFI_INVALID_PARAMETER;
390 }
391
392 if (FreePoolHdr->Header.Size != PoolTail->Size) {
393 return EFI_INVALID_PARAMETER;
394 }
395 } else {
396 PoolTail = NULL;
397 }
398
399 if (MemoryGuarded) {
400 Buffer = AdjustPoolHeadF ((EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr);
401 return SmmInternalFreePages (
402 (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer,
403 EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size),
404 TRUE
405 );
406 }
407
408 if (FreePoolHdr->Header.Size > MAX_POOL_SIZE) {
409 ASSERT (((UINTN)FreePoolHdr & EFI_PAGE_MASK) == 0);
410 ASSERT ((FreePoolHdr->Header.Size & EFI_PAGE_MASK) == 0);
411 return SmmInternalFreePages (
412 (EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr,
413 EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size),
414 FALSE
415 );
416 }
417 return InternalFreePoolByIndex (FreePoolHdr, PoolTail);
418 }
419
420 /**
421 Frees pool.
422
423 @param Buffer The allocated pool entry to free.
424
425 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
426 @retval EFI_SUCCESS Pool successfully freed.
427
428 **/
429 EFI_STATUS
430 EFIAPI
431 SmmFreePool (
432 IN VOID *Buffer
433 )
434 {
435 EFI_STATUS Status;
436
437 Status = SmmInternalFreePool (Buffer);
438 if (!EFI_ERROR (Status)) {
439 SmmCoreUpdateProfile (
440 (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),
441 MemoryProfileActionFreePool,
442 EfiMaxMemoryType,
443 0,
444 Buffer,
445 NULL
446 );
447 }
448 return Status;
449 }