2 SMM Memory pool management functions.
4 Copyright (c) 2009 - 2016, 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
;
136 EFI_PHYSICAL_ADDRESS Address
;
137 SMM_POOL_TYPE SmmPoolType
;
139 SmmPoolType
= UefiMemoryTypeToSmmPoolType(PoolType
);
141 ASSERT (PoolIndex
<= MAX_POOL_INDEX
);
142 Status
= EFI_SUCCESS
;
144 if (PoolIndex
== MAX_POOL_INDEX
) {
145 Status
= SmmInternalAllocatePages (AllocateAnyPages
, PoolType
, EFI_SIZE_TO_PAGES (MAX_POOL_SIZE
<< 1), &Address
);
146 if (EFI_ERROR (Status
)) {
147 return EFI_OUT_OF_RESOURCES
;
149 Hdr
= (FREE_POOL_HEADER
*) (UINTN
) Address
;
150 } else if (!IsListEmpty (&mSmmPoolLists
[SmmPoolType
][PoolIndex
])) {
151 Hdr
= BASE_CR (GetFirstNode (&mSmmPoolLists
[SmmPoolType
][PoolIndex
]), FREE_POOL_HEADER
, Link
);
152 RemoveEntryList (&Hdr
->Link
);
154 Status
= InternalAllocPoolByIndex (PoolType
, PoolIndex
+ 1, &Hdr
);
155 if (!EFI_ERROR (Status
)) {
156 Hdr
->Header
.Size
>>= 1;
157 Hdr
->Header
.Available
= TRUE
;
158 Hdr
->Header
.Type
= PoolType
;
159 InsertHeadList (&mSmmPoolLists
[SmmPoolType
][PoolIndex
], &Hdr
->Link
);
160 Hdr
= (FREE_POOL_HEADER
*)((UINT8
*)Hdr
+ Hdr
->Header
.Size
);
164 if (!EFI_ERROR (Status
)) {
165 Hdr
->Header
.Size
= MIN_POOL_SIZE
<< PoolIndex
;
166 Hdr
->Header
.Available
= FALSE
;
167 Hdr
->Header
.Type
= PoolType
;
175 Internal Function. Free a pool by specified PoolIndex.
177 @param FreePoolHdr The pool to free.
179 @retval EFI_SUCCESS Pool successfully freed.
183 InternalFreePoolByIndex (
184 IN FREE_POOL_HEADER
*FreePoolHdr
188 SMM_POOL_TYPE SmmPoolType
;
190 ASSERT ((FreePoolHdr
->Header
.Size
& (FreePoolHdr
->Header
.Size
- 1)) == 0);
191 ASSERT (((UINTN
)FreePoolHdr
& (FreePoolHdr
->Header
.Size
- 1)) == 0);
192 ASSERT (FreePoolHdr
->Header
.Size
>= MIN_POOL_SIZE
);
194 SmmPoolType
= UefiMemoryTypeToSmmPoolType(FreePoolHdr
->Header
.Type
);
196 PoolIndex
= (UINTN
) (HighBitSet32 ((UINT32
)FreePoolHdr
->Header
.Size
) - MIN_POOL_SHIFT
);
197 FreePoolHdr
->Header
.Available
= TRUE
;
198 ASSERT (PoolIndex
< MAX_POOL_INDEX
);
199 InsertHeadList (&mSmmPoolLists
[SmmPoolType
][PoolIndex
], &FreePoolHdr
->Link
);
204 Allocate pool of a particular type.
206 @param PoolType Type of pool to allocate.
207 @param Size The amount of pool to allocate.
208 @param Buffer The address to return a pointer to the allocated
211 @retval EFI_INVALID_PARAMETER PoolType not valid.
212 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
213 @retval EFI_SUCCESS Pool successfully allocated.
218 SmmInternalAllocatePool (
219 IN EFI_MEMORY_TYPE PoolType
,
224 POOL_HEADER
*PoolHdr
;
225 FREE_POOL_HEADER
*FreePoolHdr
;
227 EFI_PHYSICAL_ADDRESS Address
;
230 if (PoolType
!= EfiRuntimeServicesCode
&&
231 PoolType
!= EfiRuntimeServicesData
) {
232 return EFI_INVALID_PARAMETER
;
235 Size
+= sizeof (*PoolHdr
);
236 if (Size
> MAX_POOL_SIZE
) {
237 Size
= EFI_SIZE_TO_PAGES (Size
);
238 Status
= SmmInternalAllocatePages (AllocateAnyPages
, PoolType
, Size
, &Address
);
239 if (EFI_ERROR (Status
)) {
243 PoolHdr
= (POOL_HEADER
*)(UINTN
)Address
;
244 PoolHdr
->Size
= EFI_PAGES_TO_SIZE (Size
);
245 PoolHdr
->Available
= FALSE
;
246 PoolHdr
->Type
= PoolType
;
247 *Buffer
= PoolHdr
+ 1;
251 Size
= (Size
+ MIN_POOL_SIZE
- 1) >> MIN_POOL_SHIFT
;
252 PoolIndex
= (UINTN
) HighBitSet32 ((UINT32
)Size
);
253 if ((Size
& (Size
- 1)) != 0) {
257 Status
= InternalAllocPoolByIndex (PoolType
, PoolIndex
, &FreePoolHdr
);
258 if (!EFI_ERROR(Status
)) {
259 *Buffer
= &FreePoolHdr
->Header
+ 1;
265 Allocate pool of a particular type.
267 @param PoolType Type of pool to allocate.
268 @param Size The amount of pool to allocate.
269 @param Buffer The address to return a pointer to the allocated
272 @retval EFI_INVALID_PARAMETER PoolType not valid.
273 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
274 @retval EFI_SUCCESS Pool successfully allocated.
280 IN EFI_MEMORY_TYPE PoolType
,
287 Status
= SmmInternalAllocatePool (PoolType
, Size
, Buffer
);
288 if (!EFI_ERROR (Status
)) {
289 SmmCoreUpdateProfile (
290 (EFI_PHYSICAL_ADDRESS
) (UINTN
) RETURN_ADDRESS (0),
291 MemoryProfileActionAllocatePool
,
304 @param Buffer The allocated pool entry to free.
306 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
307 @retval EFI_SUCCESS Pool successfully freed.
312 SmmInternalFreePool (
316 FREE_POOL_HEADER
*FreePoolHdr
;
318 if (Buffer
== NULL
) {
319 return EFI_INVALID_PARAMETER
;
322 FreePoolHdr
= (FREE_POOL_HEADER
*)((POOL_HEADER
*)Buffer
- 1);
323 ASSERT (!FreePoolHdr
->Header
.Available
);
325 if (FreePoolHdr
->Header
.Size
> MAX_POOL_SIZE
) {
326 ASSERT (((UINTN
)FreePoolHdr
& EFI_PAGE_MASK
) == 0);
327 ASSERT ((FreePoolHdr
->Header
.Size
& EFI_PAGE_MASK
) == 0);
328 return SmmInternalFreePages (
329 (EFI_PHYSICAL_ADDRESS
)(UINTN
)FreePoolHdr
,
330 EFI_SIZE_TO_PAGES (FreePoolHdr
->Header
.Size
)
333 return InternalFreePoolByIndex (FreePoolHdr
);
339 @param Buffer The allocated pool entry to free.
341 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
342 @retval EFI_SUCCESS Pool successfully freed.
353 Status
= SmmInternalFreePool (Buffer
);
354 if (!EFI_ERROR (Status
)) {
355 SmmCoreUpdateProfile (
356 (EFI_PHYSICAL_ADDRESS
) (UINTN
) RETURN_ADDRESS (0),
357 MemoryProfileActionFreePool
,