2 SMM Memory pool management functions.
4 Copyright (c) 2009 - 2017, 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
, EFI_SIZE_TO_PAGES (MAX_POOL_SIZE
<< 1), &Address
);
148 if (EFI_ERROR (Status
)) {
149 return EFI_OUT_OF_RESOURCES
;
151 Hdr
= (FREE_POOL_HEADER
*) (UINTN
) Address
;
152 } else if (!IsListEmpty (&mSmmPoolLists
[SmmPoolType
][PoolIndex
])) {
153 Hdr
= BASE_CR (GetFirstNode (&mSmmPoolLists
[SmmPoolType
][PoolIndex
]), FREE_POOL_HEADER
, Link
);
154 RemoveEntryList (&Hdr
->Link
);
156 Status
= InternalAllocPoolByIndex (PoolType
, PoolIndex
+ 1, &Hdr
);
157 if (!EFI_ERROR (Status
)) {
158 Hdr
->Header
.Signature
= 0;
159 Hdr
->Header
.Size
>>= 1;
160 Hdr
->Header
.Available
= TRUE
;
161 Hdr
->Header
.Type
= 0;
162 Tail
= HEAD_TO_TAIL(&Hdr
->Header
);
165 InsertHeadList (&mSmmPoolLists
[SmmPoolType
][PoolIndex
], &Hdr
->Link
);
166 Hdr
= (FREE_POOL_HEADER
*)((UINT8
*)Hdr
+ Hdr
->Header
.Size
);
170 if (!EFI_ERROR (Status
)) {
171 Hdr
->Header
.Signature
= POOL_HEAD_SIGNATURE
;
172 Hdr
->Header
.Size
= MIN_POOL_SIZE
<< PoolIndex
;
173 Hdr
->Header
.Available
= FALSE
;
174 Hdr
->Header
.Type
= PoolType
;
175 Tail
= HEAD_TO_TAIL(&Hdr
->Header
);
176 Tail
->Signature
= POOL_TAIL_SIGNATURE
;
177 Tail
->Size
= Hdr
->Header
.Size
;
185 Internal Function. Free a pool by specified PoolIndex.
187 @param FreePoolHdr The pool to free.
188 @param PoolTail The pointer to the pool tail.
190 @retval EFI_SUCCESS Pool successfully freed.
194 InternalFreePoolByIndex (
195 IN FREE_POOL_HEADER
*FreePoolHdr
,
196 IN POOL_TAIL
*PoolTail
200 SMM_POOL_TYPE SmmPoolType
;
202 ASSERT ((FreePoolHdr
->Header
.Size
& (FreePoolHdr
->Header
.Size
- 1)) == 0);
203 ASSERT (((UINTN
)FreePoolHdr
& (FreePoolHdr
->Header
.Size
- 1)) == 0);
204 ASSERT (FreePoolHdr
->Header
.Size
>= MIN_POOL_SIZE
);
206 SmmPoolType
= UefiMemoryTypeToSmmPoolType(FreePoolHdr
->Header
.Type
);
208 PoolIndex
= (UINTN
) (HighBitSet32 ((UINT32
)FreePoolHdr
->Header
.Size
) - MIN_POOL_SHIFT
);
209 FreePoolHdr
->Header
.Signature
= 0;
210 FreePoolHdr
->Header
.Available
= TRUE
;
211 FreePoolHdr
->Header
.Type
= 0;
212 PoolTail
->Signature
= 0;
214 ASSERT (PoolIndex
< MAX_POOL_INDEX
);
215 InsertHeadList (&mSmmPoolLists
[SmmPoolType
][PoolIndex
], &FreePoolHdr
->Link
);
220 Allocate pool of a particular type.
222 @param PoolType Type of pool to allocate.
223 @param Size The amount of pool to allocate.
224 @param Buffer The address to return a pointer to the allocated
227 @retval EFI_INVALID_PARAMETER PoolType not valid.
228 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
229 @retval EFI_SUCCESS Pool successfully allocated.
234 SmmInternalAllocatePool (
235 IN EFI_MEMORY_TYPE PoolType
,
240 POOL_HEADER
*PoolHdr
;
242 FREE_POOL_HEADER
*FreePoolHdr
;
244 EFI_PHYSICAL_ADDRESS Address
;
249 if (PoolType
!= EfiRuntimeServicesCode
&&
250 PoolType
!= EfiRuntimeServicesData
) {
251 return EFI_INVALID_PARAMETER
;
255 // Adjust the size by the pool header & tail overhead
257 Size
+= POOL_OVERHEAD
;
258 if (Size
> MAX_POOL_SIZE
) {
259 Size
= EFI_SIZE_TO_PAGES (Size
);
260 Status
= SmmInternalAllocatePages (AllocateAnyPages
, PoolType
, Size
, &Address
);
261 if (EFI_ERROR (Status
)) {
265 PoolHdr
= (POOL_HEADER
*)(UINTN
)Address
;
266 PoolHdr
->Signature
= POOL_HEAD_SIGNATURE
;
267 PoolHdr
->Size
= EFI_PAGES_TO_SIZE (Size
);
268 PoolHdr
->Available
= FALSE
;
269 PoolHdr
->Type
= PoolType
;
270 PoolTail
= HEAD_TO_TAIL(PoolHdr
);
271 PoolTail
->Signature
= POOL_TAIL_SIGNATURE
;
272 PoolTail
->Size
= PoolHdr
->Size
;
273 *Buffer
= PoolHdr
+ 1;
277 Size
= (Size
+ MIN_POOL_SIZE
- 1) >> MIN_POOL_SHIFT
;
278 PoolIndex
= (UINTN
) HighBitSet32 ((UINT32
)Size
);
279 if ((Size
& (Size
- 1)) != 0) {
283 Status
= InternalAllocPoolByIndex (PoolType
, PoolIndex
, &FreePoolHdr
);
284 if (!EFI_ERROR(Status
)) {
285 *Buffer
= &FreePoolHdr
->Header
+ 1;
291 Allocate pool of a particular type.
293 @param PoolType Type of pool to allocate.
294 @param Size The amount of pool to allocate.
295 @param Buffer The address to return a pointer to the allocated
298 @retval EFI_INVALID_PARAMETER PoolType not valid.
299 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
300 @retval EFI_SUCCESS Pool successfully allocated.
306 IN EFI_MEMORY_TYPE PoolType
,
313 Status
= SmmInternalAllocatePool (PoolType
, Size
, Buffer
);
314 if (!EFI_ERROR (Status
)) {
315 SmmCoreUpdateProfile (
316 (EFI_PHYSICAL_ADDRESS
) (UINTN
) RETURN_ADDRESS (0),
317 MemoryProfileActionAllocatePool
,
330 @param Buffer The allocated pool entry to free.
332 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
333 @retval EFI_SUCCESS Pool successfully freed.
338 SmmInternalFreePool (
342 FREE_POOL_HEADER
*FreePoolHdr
;
345 if (Buffer
== NULL
) {
346 return EFI_INVALID_PARAMETER
;
349 FreePoolHdr
= (FREE_POOL_HEADER
*)((POOL_HEADER
*)Buffer
- 1);
350 ASSERT (FreePoolHdr
->Header
.Signature
== POOL_HEAD_SIGNATURE
);
351 ASSERT (!FreePoolHdr
->Header
.Available
);
352 PoolTail
= HEAD_TO_TAIL(&FreePoolHdr
->Header
);
353 ASSERT (PoolTail
->Signature
== POOL_TAIL_SIGNATURE
);
354 ASSERT (FreePoolHdr
->Header
.Size
== PoolTail
->Size
);
356 if (FreePoolHdr
->Header
.Signature
!= POOL_HEAD_SIGNATURE
) {
357 return EFI_INVALID_PARAMETER
;
360 if (PoolTail
->Signature
!= POOL_TAIL_SIGNATURE
) {
361 return EFI_INVALID_PARAMETER
;
364 if (FreePoolHdr
->Header
.Size
!= PoolTail
->Size
) {
365 return EFI_INVALID_PARAMETER
;
368 if (FreePoolHdr
->Header
.Size
> MAX_POOL_SIZE
) {
369 ASSERT (((UINTN
)FreePoolHdr
& EFI_PAGE_MASK
) == 0);
370 ASSERT ((FreePoolHdr
->Header
.Size
& EFI_PAGE_MASK
) == 0);
371 return SmmInternalFreePages (
372 (EFI_PHYSICAL_ADDRESS
)(UINTN
)FreePoolHdr
,
373 EFI_SIZE_TO_PAGES (FreePoolHdr
->Header
.Size
)
376 return InternalFreePoolByIndex (FreePoolHdr
, PoolTail
);
382 @param Buffer The allocated pool entry to free.
384 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
385 @retval EFI_SUCCESS Pool successfully freed.
396 Status
= SmmInternalFreePool (Buffer
);
397 if (!EFI_ERROR (Status
)) {
398 SmmCoreUpdateProfile (
399 (EFI_PHYSICAL_ADDRESS
) (UINTN
) RETURN_ADDRESS (0),
400 MemoryProfileActionFreePool
,