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 CurrentSmramRangesIndex
;
65 UINTN SmmPoolTypeIndex
;
68 // Initialize Pool list
70 for (SmmPoolTypeIndex
= 0; SmmPoolTypeIndex
< SmmPoolTypeMax
; SmmPoolTypeIndex
++) {
71 for (Index
= 0; Index
< ARRAY_SIZE (mSmmPoolLists
[SmmPoolTypeIndex
]); Index
++) {
72 InitializeListHead (&mSmmPoolLists
[SmmPoolTypeIndex
][Index
]);
75 CurrentSmramRangesIndex
= 0;
77 // If Loading Module At fixed Address feature is enabled, cache the SMRAM base here
79 if (PcdGet64(PcdLoadModuleAtFixAddressEnable
) != 0) {
81 // Build tool will calculate the smm code size and then patch the PcdLoadFixAddressSmmCodePageNumber
83 SmmCodeSize
= LShiftU64 (PcdGet32(PcdLoadFixAddressSmmCodePageNumber
), EFI_PAGE_SHIFT
);
86 // Find the largest SMRAM range between 1MB and 4GB that is at least 256KB - 4K in size
88 for (Index
= 0, MaxSize
= SIZE_256KB
- EFI_PAGE_SIZE
; Index
< SmramRangeCount
; Index
++) {
90 // Skip any SMRAM region that is already allocated, needs testing, or needs ECC initialization
92 if ((SmramRanges
[Index
].RegionState
& (EFI_ALLOCATED
| EFI_NEEDS_TESTING
| EFI_NEEDS_ECC_INITIALIZATION
)) != 0) {
96 if (SmramRanges
[Index
].CpuStart
>= BASE_1MB
) {
97 if ((SmramRanges
[Index
].CpuStart
+ SmramRanges
[Index
].PhysicalSize
- 1) <= MAX_ADDRESS
) {
98 if (SmramRanges
[Index
].PhysicalSize
>= MaxSize
) {
99 MaxSize
= SmramRanges
[Index
].PhysicalSize
;
100 CurrentSmramRangesIndex
= Index
;
105 gLoadModuleAtFixAddressSmramBase
= SmramRanges
[CurrentSmramRangesIndex
].CpuStart
;
108 // cut out a memory range from this SMRAM range with the size SmmCodeSize to hold SMM driver code
109 // A notable thing is that SMM core is already loaded into this range.
111 SmramRanges
[CurrentSmramRangesIndex
].CpuStart
= SmramRanges
[CurrentSmramRangesIndex
].CpuStart
+ SmmCodeSize
;
112 SmramRanges
[CurrentSmramRangesIndex
].PhysicalSize
= SmramRanges
[CurrentSmramRangesIndex
].PhysicalSize
- SmmCodeSize
;
115 // Add Free SMRAM regions
116 // Need add Free memory at first, to let gSmmMemoryMap record data
118 for (Index
= 0; Index
< SmramRangeCount
; Index
++) {
119 if ((SmramRanges
[Index
].RegionState
& (EFI_ALLOCATED
| EFI_NEEDS_TESTING
| EFI_NEEDS_ECC_INITIALIZATION
)) != 0) {
123 SmramRanges
[Index
].CpuStart
,
124 SmramRanges
[Index
].PhysicalSize
,
125 EfiConventionalMemory
,
126 SmramRanges
[Index
].RegionState
131 // Add the allocated SMRAM regions
133 for (Index
= 0; Index
< SmramRangeCount
; Index
++) {
134 if ((SmramRanges
[Index
].RegionState
& (EFI_ALLOCATED
| EFI_NEEDS_TESTING
| EFI_NEEDS_ECC_INITIALIZATION
)) == 0) {
138 SmramRanges
[Index
].CpuStart
,
139 SmramRanges
[Index
].PhysicalSize
,
140 EfiConventionalMemory
,
141 SmramRanges
[Index
].RegionState
148 Internal Function. Allocate a pool by specified PoolIndex.
150 @param PoolType Type of pool to allocate.
151 @param PoolIndex Index which indicate the Pool size.
152 @param FreePoolHdr The returned Free pool.
154 @retval EFI_OUT_OF_RESOURCES Allocation failed.
155 @retval EFI_SUCCESS Pool successfully allocated.
159 InternalAllocPoolByIndex (
160 IN EFI_MEMORY_TYPE PoolType
,
162 OUT FREE_POOL_HEADER
**FreePoolHdr
166 FREE_POOL_HEADER
*Hdr
;
167 EFI_PHYSICAL_ADDRESS Address
;
168 SMM_POOL_TYPE SmmPoolType
;
170 SmmPoolType
= UefiMemoryTypeToSmmPoolType(PoolType
);
172 ASSERT (PoolIndex
<= MAX_POOL_INDEX
);
173 Status
= EFI_SUCCESS
;
175 if (PoolIndex
== MAX_POOL_INDEX
) {
176 Status
= SmmInternalAllocatePages (AllocateAnyPages
, PoolType
, EFI_SIZE_TO_PAGES (MAX_POOL_SIZE
<< 1), &Address
);
177 if (EFI_ERROR (Status
)) {
178 return EFI_OUT_OF_RESOURCES
;
180 Hdr
= (FREE_POOL_HEADER
*) (UINTN
) Address
;
181 } else if (!IsListEmpty (&mSmmPoolLists
[SmmPoolType
][PoolIndex
])) {
182 Hdr
= BASE_CR (GetFirstNode (&mSmmPoolLists
[SmmPoolType
][PoolIndex
]), FREE_POOL_HEADER
, Link
);
183 RemoveEntryList (&Hdr
->Link
);
185 Status
= InternalAllocPoolByIndex (PoolType
, PoolIndex
+ 1, &Hdr
);
186 if (!EFI_ERROR (Status
)) {
187 Hdr
->Header
.Size
>>= 1;
188 Hdr
->Header
.Available
= TRUE
;
189 Hdr
->Header
.Type
= PoolType
;
190 InsertHeadList (&mSmmPoolLists
[SmmPoolType
][PoolIndex
], &Hdr
->Link
);
191 Hdr
= (FREE_POOL_HEADER
*)((UINT8
*)Hdr
+ Hdr
->Header
.Size
);
195 if (!EFI_ERROR (Status
)) {
196 Hdr
->Header
.Size
= MIN_POOL_SIZE
<< PoolIndex
;
197 Hdr
->Header
.Available
= FALSE
;
198 Hdr
->Header
.Type
= PoolType
;
206 Internal Function. Free a pool by specified PoolIndex.
208 @param FreePoolHdr The pool to free.
210 @retval EFI_SUCCESS Pool successfully freed.
214 InternalFreePoolByIndex (
215 IN FREE_POOL_HEADER
*FreePoolHdr
219 SMM_POOL_TYPE SmmPoolType
;
221 ASSERT ((FreePoolHdr
->Header
.Size
& (FreePoolHdr
->Header
.Size
- 1)) == 0);
222 ASSERT (((UINTN
)FreePoolHdr
& (FreePoolHdr
->Header
.Size
- 1)) == 0);
223 ASSERT (FreePoolHdr
->Header
.Size
>= MIN_POOL_SIZE
);
225 SmmPoolType
= UefiMemoryTypeToSmmPoolType(FreePoolHdr
->Header
.Type
);
227 PoolIndex
= (UINTN
) (HighBitSet32 ((UINT32
)FreePoolHdr
->Header
.Size
) - MIN_POOL_SHIFT
);
228 FreePoolHdr
->Header
.Available
= TRUE
;
229 ASSERT (PoolIndex
< MAX_POOL_INDEX
);
230 InsertHeadList (&mSmmPoolLists
[SmmPoolType
][PoolIndex
], &FreePoolHdr
->Link
);
235 Allocate pool of a particular type.
237 @param PoolType Type of pool to allocate.
238 @param Size The amount of pool to allocate.
239 @param Buffer The address to return a pointer to the allocated
242 @retval EFI_INVALID_PARAMETER PoolType not valid.
243 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
244 @retval EFI_SUCCESS Pool successfully allocated.
249 SmmInternalAllocatePool (
250 IN EFI_MEMORY_TYPE PoolType
,
255 POOL_HEADER
*PoolHdr
;
256 FREE_POOL_HEADER
*FreePoolHdr
;
258 EFI_PHYSICAL_ADDRESS Address
;
261 if (PoolType
!= EfiRuntimeServicesCode
&&
262 PoolType
!= EfiRuntimeServicesData
) {
263 return EFI_INVALID_PARAMETER
;
266 Size
+= sizeof (*PoolHdr
);
267 if (Size
> MAX_POOL_SIZE
) {
268 Size
= EFI_SIZE_TO_PAGES (Size
);
269 Status
= SmmInternalAllocatePages (AllocateAnyPages
, PoolType
, Size
, &Address
);
270 if (EFI_ERROR (Status
)) {
274 PoolHdr
= (POOL_HEADER
*)(UINTN
)Address
;
275 PoolHdr
->Size
= EFI_PAGES_TO_SIZE (Size
);
276 PoolHdr
->Available
= FALSE
;
277 PoolHdr
->Type
= PoolType
;
278 *Buffer
= PoolHdr
+ 1;
282 Size
= (Size
+ MIN_POOL_SIZE
- 1) >> MIN_POOL_SHIFT
;
283 PoolIndex
= (UINTN
) HighBitSet32 ((UINT32
)Size
);
284 if ((Size
& (Size
- 1)) != 0) {
288 Status
= InternalAllocPoolByIndex (PoolType
, PoolIndex
, &FreePoolHdr
);
289 if (!EFI_ERROR(Status
)) {
290 *Buffer
= &FreePoolHdr
->Header
+ 1;
296 Allocate pool of a particular type.
298 @param PoolType Type of pool to allocate.
299 @param Size The amount of pool to allocate.
300 @param Buffer The address to return a pointer to the allocated
303 @retval EFI_INVALID_PARAMETER PoolType not valid.
304 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
305 @retval EFI_SUCCESS Pool successfully allocated.
311 IN EFI_MEMORY_TYPE PoolType
,
318 Status
= SmmInternalAllocatePool (PoolType
, Size
, Buffer
);
319 if (!EFI_ERROR (Status
)) {
320 SmmCoreUpdateProfile (
321 (EFI_PHYSICAL_ADDRESS
) (UINTN
) RETURN_ADDRESS (0),
322 MemoryProfileActionAllocatePool
,
335 @param Buffer The allocated pool entry to free.
337 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
338 @retval EFI_SUCCESS Pool successfully freed.
343 SmmInternalFreePool (
347 FREE_POOL_HEADER
*FreePoolHdr
;
349 if (Buffer
== NULL
) {
350 return EFI_INVALID_PARAMETER
;
353 FreePoolHdr
= (FREE_POOL_HEADER
*)((POOL_HEADER
*)Buffer
- 1);
354 ASSERT (!FreePoolHdr
->Header
.Available
);
356 if (FreePoolHdr
->Header
.Size
> MAX_POOL_SIZE
) {
357 ASSERT (((UINTN
)FreePoolHdr
& EFI_PAGE_MASK
) == 0);
358 ASSERT ((FreePoolHdr
->Header
.Size
& EFI_PAGE_MASK
) == 0);
359 return SmmInternalFreePages (
360 (EFI_PHYSICAL_ADDRESS
)(UINTN
)FreePoolHdr
,
361 EFI_SIZE_TO_PAGES (FreePoolHdr
->Header
.Size
)
364 return InternalFreePoolByIndex (FreePoolHdr
);
370 @param Buffer The allocated pool entry to free.
372 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
373 @retval EFI_SUCCESS Pool successfully freed.
384 Status
= SmmInternalFreePool (Buffer
);
385 if (!EFI_ERROR (Status
)) {
386 SmmCoreUpdateProfile (
387 (EFI_PHYSICAL_ADDRESS
) (UINTN
) RETURN_ADDRESS (0),
388 MemoryProfileActionFreePool
,