2 SMM Memory pool management functions.
4 Copyright (c) 2009 - 2018, 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
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.
15 #include "PiSmmCore.h"
17 LIST_ENTRY mSmmPoolLists
[SmmPoolTypeMax
][MAX_POOL_INDEX
];
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.
22 GLOBAL_REMOVE_IF_UNREFERENCED EFI_PHYSICAL_ADDRESS gLoadModuleAtFixAddressSmramBase
= 0;
25 Convert a UEFI memory type to SMM pool type.
27 @param[in] MemoryType Type of pool to allocate.
32 UefiMemoryTypeToSmmPoolType (
33 IN EFI_MEMORY_TYPE MemoryType
36 ASSERT ((MemoryType
== EfiRuntimeServicesCode
) || (MemoryType
== EfiRuntimeServicesData
));
38 case EfiRuntimeServicesCode
:
39 return SmmPoolTypeCode
;
40 case EfiRuntimeServicesData
:
41 return SmmPoolTypeData
;
43 return SmmPoolTypeMax
;
49 Called to initialize the memory service.
51 @param SmramRangeCount Number of SMRAM Regions
52 @param SmramRanges Pointer to SMRAM Descriptors
56 SmmInitializeMemoryServices (
57 IN UINTN SmramRangeCount
,
58 IN EFI_SMRAM_DESCRIPTOR
*SmramRanges
63 UINTN SmmPoolTypeIndex
;
64 EFI_LOAD_FIXED_ADDRESS_CONFIGURATION_TABLE
*LMFAConfigurationTable
;
67 // Initialize Pool list
69 for (SmmPoolTypeIndex
= 0; SmmPoolTypeIndex
< SmmPoolTypeMax
; SmmPoolTypeIndex
++) {
70 for (Index
= 0; Index
< ARRAY_SIZE (mSmmPoolLists
[SmmPoolTypeIndex
]); Index
++) {
71 InitializeListHead (&mSmmPoolLists
[SmmPoolTypeIndex
][Index
]);
75 Status
= EfiGetSystemConfigurationTable (
76 &gLoadFixedAddressConfigurationTableGuid
,
77 (VOID
**) &LMFAConfigurationTable
79 if (!EFI_ERROR (Status
) && LMFAConfigurationTable
!= NULL
) {
80 gLoadModuleAtFixAddressSmramBase
= LMFAConfigurationTable
->SmramBase
;
84 // Add Free SMRAM regions
85 // Need add Free memory at first, to let gSmmMemoryMap record data
87 for (Index
= 0; Index
< SmramRangeCount
; Index
++) {
88 if ((SmramRanges
[Index
].RegionState
& (EFI_ALLOCATED
| EFI_NEEDS_TESTING
| EFI_NEEDS_ECC_INITIALIZATION
)) != 0) {
92 SmramRanges
[Index
].CpuStart
,
93 SmramRanges
[Index
].PhysicalSize
,
94 EfiConventionalMemory
,
95 SmramRanges
[Index
].RegionState
100 // Add the allocated SMRAM regions
102 for (Index
= 0; Index
< SmramRangeCount
; Index
++) {
103 if ((SmramRanges
[Index
].RegionState
& (EFI_ALLOCATED
| EFI_NEEDS_TESTING
| EFI_NEEDS_ECC_INITIALIZATION
)) == 0) {
107 SmramRanges
[Index
].CpuStart
,
108 SmramRanges
[Index
].PhysicalSize
,
109 EfiConventionalMemory
,
110 SmramRanges
[Index
].RegionState
117 Internal Function. Allocate a pool by specified PoolIndex.
119 @param PoolType Type of pool to allocate.
120 @param PoolIndex Index which indicate the Pool size.
121 @param FreePoolHdr The returned Free pool.
123 @retval EFI_OUT_OF_RESOURCES Allocation failed.
124 @retval EFI_SUCCESS Pool successfully allocated.
128 InternalAllocPoolByIndex (
129 IN EFI_MEMORY_TYPE PoolType
,
131 OUT FREE_POOL_HEADER
**FreePoolHdr
135 FREE_POOL_HEADER
*Hdr
;
137 EFI_PHYSICAL_ADDRESS Address
;
138 SMM_POOL_TYPE SmmPoolType
;
141 SmmPoolType
= UefiMemoryTypeToSmmPoolType(PoolType
);
143 ASSERT (PoolIndex
<= MAX_POOL_INDEX
);
144 Status
= EFI_SUCCESS
;
146 if (PoolIndex
== MAX_POOL_INDEX
) {
147 Status
= SmmInternalAllocatePages (AllocateAnyPages
, PoolType
,
148 EFI_SIZE_TO_PAGES (MAX_POOL_SIZE
<< 1),
150 if (EFI_ERROR (Status
)) {
151 return EFI_OUT_OF_RESOURCES
;
153 Hdr
= (FREE_POOL_HEADER
*) (UINTN
) Address
;
154 } else if (!IsListEmpty (&mSmmPoolLists
[SmmPoolType
][PoolIndex
])) {
155 Hdr
= BASE_CR (GetFirstNode (&mSmmPoolLists
[SmmPoolType
][PoolIndex
]), FREE_POOL_HEADER
, Link
);
156 RemoveEntryList (&Hdr
->Link
);
158 Status
= InternalAllocPoolByIndex (PoolType
, PoolIndex
+ 1, &Hdr
);
159 if (!EFI_ERROR (Status
)) {
160 Hdr
->Header
.Signature
= 0;
161 Hdr
->Header
.Size
>>= 1;
162 Hdr
->Header
.Available
= TRUE
;
163 Hdr
->Header
.Type
= 0;
164 Tail
= HEAD_TO_TAIL(&Hdr
->Header
);
167 InsertHeadList (&mSmmPoolLists
[SmmPoolType
][PoolIndex
], &Hdr
->Link
);
168 Hdr
= (FREE_POOL_HEADER
*)((UINT8
*)Hdr
+ Hdr
->Header
.Size
);
172 if (!EFI_ERROR (Status
)) {
173 Hdr
->Header
.Signature
= POOL_HEAD_SIGNATURE
;
174 Hdr
->Header
.Size
= MIN_POOL_SIZE
<< PoolIndex
;
175 Hdr
->Header
.Available
= FALSE
;
176 Hdr
->Header
.Type
= PoolType
;
177 Tail
= HEAD_TO_TAIL(&Hdr
->Header
);
178 Tail
->Signature
= POOL_TAIL_SIGNATURE
;
179 Tail
->Size
= Hdr
->Header
.Size
;
187 Internal Function. Free a pool by specified PoolIndex.
189 @param FreePoolHdr The pool to free.
190 @param PoolTail The pointer to the pool tail.
192 @retval EFI_SUCCESS Pool successfully freed.
196 InternalFreePoolByIndex (
197 IN FREE_POOL_HEADER
*FreePoolHdr
,
198 IN POOL_TAIL
*PoolTail
202 SMM_POOL_TYPE SmmPoolType
;
204 ASSERT ((FreePoolHdr
->Header
.Size
& (FreePoolHdr
->Header
.Size
- 1)) == 0);
205 ASSERT (((UINTN
)FreePoolHdr
& (FreePoolHdr
->Header
.Size
- 1)) == 0);
206 ASSERT (FreePoolHdr
->Header
.Size
>= MIN_POOL_SIZE
);
208 SmmPoolType
= UefiMemoryTypeToSmmPoolType(FreePoolHdr
->Header
.Type
);
210 PoolIndex
= (UINTN
) (HighBitSet32 ((UINT32
)FreePoolHdr
->Header
.Size
) - MIN_POOL_SHIFT
);
211 FreePoolHdr
->Header
.Signature
= 0;
212 FreePoolHdr
->Header
.Available
= TRUE
;
213 FreePoolHdr
->Header
.Type
= 0;
214 PoolTail
->Signature
= 0;
216 ASSERT (PoolIndex
< MAX_POOL_INDEX
);
217 InsertHeadList (&mSmmPoolLists
[SmmPoolType
][PoolIndex
], &FreePoolHdr
->Link
);
222 Allocate pool of a particular type.
224 @param PoolType Type of pool to allocate.
225 @param Size The amount of pool to allocate.
226 @param Buffer The address to return a pointer to the allocated
229 @retval EFI_INVALID_PARAMETER PoolType not valid.
230 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
231 @retval EFI_SUCCESS Pool successfully allocated.
236 SmmInternalAllocatePool (
237 IN EFI_MEMORY_TYPE PoolType
,
242 POOL_HEADER
*PoolHdr
;
244 FREE_POOL_HEADER
*FreePoolHdr
;
246 EFI_PHYSICAL_ADDRESS Address
;
254 if (PoolType
!= EfiRuntimeServicesCode
&&
255 PoolType
!= EfiRuntimeServicesData
) {
256 return EFI_INVALID_PARAMETER
;
259 NeedGuard
= IsPoolTypeToGuard (PoolType
);
260 HasPoolTail
= !(NeedGuard
&&
261 ((PcdGet8 (PcdHeapGuardPropertyMask
) & BIT7
) == 0));
264 // Adjust the size by the pool header & tail overhead
266 Size
+= POOL_OVERHEAD
;
267 if (Size
> MAX_POOL_SIZE
|| NeedGuard
) {
269 Size
-= sizeof (POOL_TAIL
);
272 NoPages
= EFI_SIZE_TO_PAGES (Size
);
273 Status
= SmmInternalAllocatePages (AllocateAnyPages
, PoolType
, NoPages
,
274 &Address
, NeedGuard
);
275 if (EFI_ERROR (Status
)) {
280 ASSERT (VerifyMemoryGuard (Address
, NoPages
) == TRUE
);
281 Address
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AdjustPoolHeadA (
288 PoolHdr
= (POOL_HEADER
*)(UINTN
)Address
;
289 PoolHdr
->Signature
= POOL_HEAD_SIGNATURE
;
290 PoolHdr
->Size
= EFI_PAGES_TO_SIZE (NoPages
);
291 PoolHdr
->Available
= FALSE
;
292 PoolHdr
->Type
= PoolType
;
295 PoolTail
= HEAD_TO_TAIL (PoolHdr
);
296 PoolTail
->Signature
= POOL_TAIL_SIGNATURE
;
297 PoolTail
->Size
= PoolHdr
->Size
;
300 *Buffer
= PoolHdr
+ 1;
304 Size
= (Size
+ MIN_POOL_SIZE
- 1) >> MIN_POOL_SHIFT
;
305 PoolIndex
= (UINTN
) HighBitSet32 ((UINT32
)Size
);
306 if ((Size
& (Size
- 1)) != 0) {
310 Status
= InternalAllocPoolByIndex (PoolType
, PoolIndex
, &FreePoolHdr
);
311 if (!EFI_ERROR(Status
)) {
312 *Buffer
= &FreePoolHdr
->Header
+ 1;
318 Allocate pool of a particular type.
320 @param PoolType Type of pool to allocate.
321 @param Size The amount of pool to allocate.
322 @param Buffer The address to return a pointer to the allocated
325 @retval EFI_INVALID_PARAMETER PoolType not valid.
326 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
327 @retval EFI_SUCCESS Pool successfully allocated.
333 IN EFI_MEMORY_TYPE PoolType
,
340 Status
= SmmInternalAllocatePool (PoolType
, Size
, Buffer
);
341 if (!EFI_ERROR (Status
)) {
342 SmmCoreUpdateProfile (
343 (EFI_PHYSICAL_ADDRESS
) (UINTN
) RETURN_ADDRESS (0),
344 MemoryProfileActionAllocatePool
,
357 @param Buffer The allocated pool entry to free.
359 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
360 @retval EFI_SUCCESS Pool successfully freed.
365 SmmInternalFreePool (
369 FREE_POOL_HEADER
*FreePoolHdr
;
372 BOOLEAN MemoryGuarded
;
374 if (Buffer
== NULL
) {
375 return EFI_INVALID_PARAMETER
;
378 MemoryGuarded
= IsHeapGuardEnabled () &&
379 IsMemoryGuarded ((EFI_PHYSICAL_ADDRESS
)(UINTN
)Buffer
);
380 HasPoolTail
= !(MemoryGuarded
&&
381 ((PcdGet8 (PcdHeapGuardPropertyMask
) & BIT7
) == 0));
383 FreePoolHdr
= (FREE_POOL_HEADER
*)((POOL_HEADER
*)Buffer
- 1);
384 ASSERT (FreePoolHdr
->Header
.Signature
== POOL_HEAD_SIGNATURE
);
385 ASSERT (!FreePoolHdr
->Header
.Available
);
386 if (FreePoolHdr
->Header
.Signature
!= POOL_HEAD_SIGNATURE
) {
387 return EFI_INVALID_PARAMETER
;
391 PoolTail
= HEAD_TO_TAIL (&FreePoolHdr
->Header
);
392 ASSERT (PoolTail
->Signature
== POOL_TAIL_SIGNATURE
);
393 ASSERT (FreePoolHdr
->Header
.Size
== PoolTail
->Size
);
394 if (PoolTail
->Signature
!= POOL_TAIL_SIGNATURE
) {
395 return EFI_INVALID_PARAMETER
;
398 if (FreePoolHdr
->Header
.Size
!= PoolTail
->Size
) {
399 return EFI_INVALID_PARAMETER
;
406 Buffer
= AdjustPoolHeadF ((EFI_PHYSICAL_ADDRESS
)(UINTN
)FreePoolHdr
);
407 return SmmInternalFreePages (
408 (EFI_PHYSICAL_ADDRESS
)(UINTN
)Buffer
,
409 EFI_SIZE_TO_PAGES (FreePoolHdr
->Header
.Size
),
414 if (FreePoolHdr
->Header
.Size
> MAX_POOL_SIZE
) {
415 ASSERT (((UINTN
)FreePoolHdr
& EFI_PAGE_MASK
) == 0);
416 ASSERT ((FreePoolHdr
->Header
.Size
& EFI_PAGE_MASK
) == 0);
417 return SmmInternalFreePages (
418 (EFI_PHYSICAL_ADDRESS
)(UINTN
)FreePoolHdr
,
419 EFI_SIZE_TO_PAGES (FreePoolHdr
->Header
.Size
),
423 return InternalFreePoolByIndex (FreePoolHdr
, PoolTail
);
429 @param Buffer The allocated pool entry to free.
431 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
432 @retval EFI_SUCCESS Pool successfully freed.
443 Status
= SmmInternalFreePool (Buffer
);
444 if (!EFI_ERROR (Status
)) {
445 SmmCoreUpdateProfile (
446 (EFI_PHYSICAL_ADDRESS
) (UINTN
) RETURN_ADDRESS (0),
447 MemoryProfileActionFreePool
,