2 SMM Memory pool management functions.
4 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
11 LIST_ENTRY mSmmPoolLists
[SmmPoolTypeMax
][MAX_POOL_INDEX
];
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.
16 GLOBAL_REMOVE_IF_UNREFERENCED EFI_PHYSICAL_ADDRESS gLoadModuleAtFixAddressSmramBase
= 0;
19 Convert a UEFI memory type to SMM pool type.
21 @param[in] MemoryType Type of pool to allocate.
26 UefiMemoryTypeToSmmPoolType (
27 IN EFI_MEMORY_TYPE MemoryType
30 ASSERT ((MemoryType
== EfiRuntimeServicesCode
) || (MemoryType
== EfiRuntimeServicesData
));
32 case EfiRuntimeServicesCode
:
33 return SmmPoolTypeCode
;
34 case EfiRuntimeServicesData
:
35 return SmmPoolTypeData
;
37 return SmmPoolTypeMax
;
43 Called to initialize the memory service.
45 @param SmramRangeCount Number of SMRAM Regions
46 @param SmramRanges Pointer to SMRAM Descriptors
50 SmmInitializeMemoryServices (
51 IN UINTN SmramRangeCount
,
52 IN EFI_SMRAM_DESCRIPTOR
*SmramRanges
57 UINTN SmmPoolTypeIndex
;
58 EFI_LOAD_FIXED_ADDRESS_CONFIGURATION_TABLE
*LMFAConfigurationTable
;
61 // Initialize Pool list
63 for (SmmPoolTypeIndex
= 0; SmmPoolTypeIndex
< SmmPoolTypeMax
; SmmPoolTypeIndex
++) {
64 for (Index
= 0; Index
< ARRAY_SIZE (mSmmPoolLists
[SmmPoolTypeIndex
]); Index
++) {
65 InitializeListHead (&mSmmPoolLists
[SmmPoolTypeIndex
][Index
]);
69 Status
= EfiGetSystemConfigurationTable (
70 &gLoadFixedAddressConfigurationTableGuid
,
71 (VOID
**) &LMFAConfigurationTable
73 if (!EFI_ERROR (Status
) && LMFAConfigurationTable
!= NULL
) {
74 gLoadModuleAtFixAddressSmramBase
= LMFAConfigurationTable
->SmramBase
;
78 // Add Free SMRAM regions
79 // Need add Free memory at first, to let gSmmMemoryMap record data
81 for (Index
= 0; Index
< SmramRangeCount
; Index
++) {
82 if ((SmramRanges
[Index
].RegionState
& (EFI_ALLOCATED
| EFI_NEEDS_TESTING
| EFI_NEEDS_ECC_INITIALIZATION
)) != 0) {
86 SmramRanges
[Index
].CpuStart
,
87 SmramRanges
[Index
].PhysicalSize
,
88 EfiConventionalMemory
,
89 SmramRanges
[Index
].RegionState
94 // Add the allocated SMRAM regions
96 for (Index
= 0; Index
< SmramRangeCount
; Index
++) {
97 if ((SmramRanges
[Index
].RegionState
& (EFI_ALLOCATED
| EFI_NEEDS_TESTING
| EFI_NEEDS_ECC_INITIALIZATION
)) == 0) {
101 SmramRanges
[Index
].CpuStart
,
102 SmramRanges
[Index
].PhysicalSize
,
103 EfiConventionalMemory
,
104 SmramRanges
[Index
].RegionState
111 Internal Function. Allocate a pool by specified PoolIndex.
113 @param PoolType Type of pool to allocate.
114 @param PoolIndex Index which indicate the Pool size.
115 @param FreePoolHdr The returned Free pool.
117 @retval EFI_OUT_OF_RESOURCES Allocation failed.
118 @retval EFI_SUCCESS Pool successfully allocated.
122 InternalAllocPoolByIndex (
123 IN EFI_MEMORY_TYPE PoolType
,
125 OUT FREE_POOL_HEADER
**FreePoolHdr
129 FREE_POOL_HEADER
*Hdr
;
131 EFI_PHYSICAL_ADDRESS Address
;
132 SMM_POOL_TYPE SmmPoolType
;
135 SmmPoolType
= UefiMemoryTypeToSmmPoolType(PoolType
);
137 ASSERT (PoolIndex
<= MAX_POOL_INDEX
);
138 Status
= EFI_SUCCESS
;
140 if (PoolIndex
== MAX_POOL_INDEX
) {
141 Status
= SmmInternalAllocatePages (AllocateAnyPages
, PoolType
,
142 EFI_SIZE_TO_PAGES (MAX_POOL_SIZE
<< 1),
144 if (EFI_ERROR (Status
)) {
145 return EFI_OUT_OF_RESOURCES
;
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
);
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
);
161 InsertHeadList (&mSmmPoolLists
[SmmPoolType
][PoolIndex
], &Hdr
->Link
);
162 Hdr
= (FREE_POOL_HEADER
*)((UINT8
*)Hdr
+ Hdr
->Header
.Size
);
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
;
181 Internal Function. Free a pool by specified PoolIndex.
183 @param FreePoolHdr The pool to free.
184 @param PoolTail The pointer to the pool tail.
186 @retval EFI_SUCCESS Pool successfully freed.
190 InternalFreePoolByIndex (
191 IN FREE_POOL_HEADER
*FreePoolHdr
,
192 IN POOL_TAIL
*PoolTail
196 SMM_POOL_TYPE SmmPoolType
;
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
);
202 SmmPoolType
= UefiMemoryTypeToSmmPoolType(FreePoolHdr
->Header
.Type
);
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;
210 ASSERT (PoolIndex
< MAX_POOL_INDEX
);
211 InsertHeadList (&mSmmPoolLists
[SmmPoolType
][PoolIndex
], &FreePoolHdr
->Link
);
216 Allocate pool of a particular type.
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
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.
230 SmmInternalAllocatePool (
231 IN EFI_MEMORY_TYPE PoolType
,
236 POOL_HEADER
*PoolHdr
;
238 FREE_POOL_HEADER
*FreePoolHdr
;
240 EFI_PHYSICAL_ADDRESS Address
;
248 if (PoolType
!= EfiRuntimeServicesCode
&&
249 PoolType
!= EfiRuntimeServicesData
) {
250 return EFI_INVALID_PARAMETER
;
253 NeedGuard
= IsPoolTypeToGuard (PoolType
);
254 HasPoolTail
= !(NeedGuard
&&
255 ((PcdGet8 (PcdHeapGuardPropertyMask
) & BIT7
) == 0));
258 // Adjust the size by the pool header & tail overhead
260 Size
+= POOL_OVERHEAD
;
261 if (Size
> MAX_POOL_SIZE
|| NeedGuard
) {
263 Size
-= sizeof (POOL_TAIL
);
266 NoPages
= EFI_SIZE_TO_PAGES (Size
);
267 Status
= SmmInternalAllocatePages (AllocateAnyPages
, PoolType
, NoPages
,
268 &Address
, NeedGuard
);
269 if (EFI_ERROR (Status
)) {
274 ASSERT (VerifyMemoryGuard (Address
, NoPages
) == TRUE
);
275 Address
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AdjustPoolHeadA (
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
;
289 PoolTail
= HEAD_TO_TAIL (PoolHdr
);
290 PoolTail
->Signature
= POOL_TAIL_SIGNATURE
;
291 PoolTail
->Size
= PoolHdr
->Size
;
294 *Buffer
= PoolHdr
+ 1;
298 Size
= (Size
+ MIN_POOL_SIZE
- 1) >> MIN_POOL_SHIFT
;
299 PoolIndex
= (UINTN
) HighBitSet32 ((UINT32
)Size
);
300 if ((Size
& (Size
- 1)) != 0) {
304 Status
= InternalAllocPoolByIndex (PoolType
, PoolIndex
, &FreePoolHdr
);
305 if (!EFI_ERROR(Status
)) {
306 *Buffer
= &FreePoolHdr
->Header
+ 1;
312 Allocate pool of a particular type.
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
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.
327 IN EFI_MEMORY_TYPE PoolType
,
334 Status
= SmmInternalAllocatePool (PoolType
, Size
, Buffer
);
335 if (!EFI_ERROR (Status
)) {
336 SmmCoreUpdateProfile (
337 (EFI_PHYSICAL_ADDRESS
) (UINTN
) RETURN_ADDRESS (0),
338 MemoryProfileActionAllocatePool
,
351 @param Buffer The allocated pool entry to free.
353 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
354 @retval EFI_SUCCESS Pool successfully freed.
359 SmmInternalFreePool (
363 FREE_POOL_HEADER
*FreePoolHdr
;
366 BOOLEAN MemoryGuarded
;
368 if (Buffer
== NULL
) {
369 return EFI_INVALID_PARAMETER
;
372 MemoryGuarded
= IsHeapGuardEnabled () &&
373 IsMemoryGuarded ((EFI_PHYSICAL_ADDRESS
)(UINTN
)Buffer
);
374 HasPoolTail
= !(MemoryGuarded
&&
375 ((PcdGet8 (PcdHeapGuardPropertyMask
) & BIT7
) == 0));
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
;
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
;
392 if (FreePoolHdr
->Header
.Size
!= PoolTail
->Size
) {
393 return EFI_INVALID_PARAMETER
;
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
),
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
),
417 return InternalFreePoolByIndex (FreePoolHdr
, PoolTail
);
423 @param Buffer The allocated pool entry to free.
425 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
426 @retval EFI_SUCCESS Pool successfully freed.
437 Status
= SmmInternalFreePool (Buffer
);
438 if (!EFI_ERROR (Status
)) {
439 SmmCoreUpdateProfile (
440 (EFI_PHYSICAL_ADDRESS
) (UINTN
) RETURN_ADDRESS (0),
441 MemoryProfileActionFreePool
,