2 SMM Memory pool management functions.
4 Copyright (c) 2009 - 2015, 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
[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 Called to initialize the memory service.
27 @param SmramRangeCount Number of SMRAM Regions
28 @param SmramRanges Pointer to SMRAM Descriptors
32 SmmInitializeMemoryServices (
33 IN UINTN SmramRangeCount
,
34 IN EFI_SMRAM_DESCRIPTOR
*SmramRanges
39 UINTN CurrentSmramRangesIndex
;
43 // Initialize Pool list
45 for (Index
= sizeof (mSmmPoolLists
) / sizeof (*mSmmPoolLists
); Index
> 0;) {
46 InitializeListHead (&mSmmPoolLists
[--Index
]);
48 CurrentSmramRangesIndex
= 0;
50 // If Loadding Module At fixed Address feature is enabled, cache the SMRAM base here
52 if (PcdGet64(PcdLoadModuleAtFixAddressEnable
) != 0) {
54 // Build tool will calculate the smm code size and then patch the PcdLoadFixAddressSmmCodePageNumber
56 SmmCodeSize
= LShiftU64 (PcdGet32(PcdLoadFixAddressSmmCodePageNumber
), EFI_PAGE_SHIFT
);
59 // Find the largest SMRAM range between 1MB and 4GB that is at least 256KB - 4K in size
61 for (Index
= 0, MaxSize
= SIZE_256KB
- EFI_PAGE_SIZE
; Index
< SmramRangeCount
; Index
++) {
63 // Skip any SMRAM region that is already allocated, needs testing, or needs ECC initialization
65 if ((SmramRanges
[Index
].RegionState
& (EFI_ALLOCATED
| EFI_NEEDS_TESTING
| EFI_NEEDS_ECC_INITIALIZATION
)) != 0) {
69 if (SmramRanges
[Index
].CpuStart
>= BASE_1MB
) {
70 if ((SmramRanges
[Index
].CpuStart
+ SmramRanges
[Index
].PhysicalSize
) <= BASE_4GB
) {
71 if (SmramRanges
[Index
].PhysicalSize
>= MaxSize
) {
72 MaxSize
= SmramRanges
[Index
].PhysicalSize
;
73 CurrentSmramRangesIndex
= Index
;
78 gLoadModuleAtFixAddressSmramBase
= SmramRanges
[CurrentSmramRangesIndex
].CpuStart
;
81 // cut out a memory range from this SMRAM range with the size SmmCodeSize to hold SMM driver code
82 // A notable thing is that SMM core is already loaded into this range.
84 SmramRanges
[CurrentSmramRangesIndex
].CpuStart
= SmramRanges
[CurrentSmramRangesIndex
].CpuStart
+ SmmCodeSize
;
85 SmramRanges
[CurrentSmramRangesIndex
].PhysicalSize
= SmramRanges
[CurrentSmramRangesIndex
].PhysicalSize
- SmmCodeSize
;
88 // Initialize free SMRAM regions
90 for (Index
= 0; Index
< SmramRangeCount
; Index
++) {
92 SmramRanges
[Index
].CpuStart
,
93 SmramRanges
[Index
].PhysicalSize
,
94 EfiConventionalMemory
,
95 SmramRanges
[Index
].RegionState
102 Internal Function. Allocate a pool by specified PoolIndex.
104 @param PoolIndex Index which indicate the Pool size.
105 @param FreePoolHdr The returned Free pool.
107 @retval EFI_OUT_OF_RESOURCES Allocation failed.
108 @retval EFI_SUCCESS Pool successfully allocated.
112 InternalAllocPoolByIndex (
114 OUT FREE_POOL_HEADER
**FreePoolHdr
118 FREE_POOL_HEADER
*Hdr
;
119 EFI_PHYSICAL_ADDRESS Address
;
121 ASSERT (PoolIndex
<= MAX_POOL_INDEX
);
122 Status
= EFI_SUCCESS
;
124 if (PoolIndex
== MAX_POOL_INDEX
) {
125 Status
= SmmInternalAllocatePages (AllocateAnyPages
, EfiRuntimeServicesData
, EFI_SIZE_TO_PAGES (MAX_POOL_SIZE
<< 1), &Address
);
126 if (EFI_ERROR (Status
)) {
127 return EFI_OUT_OF_RESOURCES
;
129 Hdr
= (FREE_POOL_HEADER
*) (UINTN
) Address
;
130 } else if (!IsListEmpty (&mSmmPoolLists
[PoolIndex
])) {
131 Hdr
= BASE_CR (GetFirstNode (&mSmmPoolLists
[PoolIndex
]), FREE_POOL_HEADER
, Link
);
132 RemoveEntryList (&Hdr
->Link
);
134 Status
= InternalAllocPoolByIndex (PoolIndex
+ 1, &Hdr
);
135 if (!EFI_ERROR (Status
)) {
136 Hdr
->Header
.Size
>>= 1;
137 Hdr
->Header
.Available
= TRUE
;
138 InsertHeadList (&mSmmPoolLists
[PoolIndex
], &Hdr
->Link
);
139 Hdr
= (FREE_POOL_HEADER
*)((UINT8
*)Hdr
+ Hdr
->Header
.Size
);
143 if (!EFI_ERROR (Status
)) {
144 Hdr
->Header
.Size
= MIN_POOL_SIZE
<< PoolIndex
;
145 Hdr
->Header
.Available
= FALSE
;
153 Internal Function. Free a pool by specified PoolIndex.
155 @param FreePoolHdr The pool to free.
157 @retval EFI_SUCCESS Pool successfully freed.
161 InternalFreePoolByIndex (
162 IN FREE_POOL_HEADER
*FreePoolHdr
167 ASSERT ((FreePoolHdr
->Header
.Size
& (FreePoolHdr
->Header
.Size
- 1)) == 0);
168 ASSERT (((UINTN
)FreePoolHdr
& (FreePoolHdr
->Header
.Size
- 1)) == 0);
169 ASSERT (FreePoolHdr
->Header
.Size
>= MIN_POOL_SIZE
);
171 PoolIndex
= (UINTN
) (HighBitSet32 ((UINT32
)FreePoolHdr
->Header
.Size
) - MIN_POOL_SHIFT
);
172 FreePoolHdr
->Header
.Available
= TRUE
;
173 ASSERT (PoolIndex
< MAX_POOL_INDEX
);
174 InsertHeadList (&mSmmPoolLists
[PoolIndex
], &FreePoolHdr
->Link
);
179 Allocate pool of a particular type.
181 @param PoolType Type of pool to allocate.
182 @param Size The amount of pool to allocate.
183 @param Buffer The address to return a pointer to the allocated
186 @retval EFI_INVALID_PARAMETER PoolType not valid.
187 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
188 @retval EFI_SUCCESS Pool successfully allocated.
193 SmmInternalAllocatePool (
194 IN EFI_MEMORY_TYPE PoolType
,
199 POOL_HEADER
*PoolHdr
;
200 FREE_POOL_HEADER
*FreePoolHdr
;
202 EFI_PHYSICAL_ADDRESS Address
;
205 if (PoolType
!= EfiRuntimeServicesCode
&&
206 PoolType
!= EfiRuntimeServicesData
) {
207 return EFI_INVALID_PARAMETER
;
210 Size
+= sizeof (*PoolHdr
);
211 if (Size
> MAX_POOL_SIZE
) {
212 Size
= EFI_SIZE_TO_PAGES (Size
);
213 Status
= SmmInternalAllocatePages (AllocateAnyPages
, PoolType
, Size
, &Address
);
214 if (EFI_ERROR (Status
)) {
218 PoolHdr
= (POOL_HEADER
*)(UINTN
)Address
;
219 PoolHdr
->Size
= EFI_PAGES_TO_SIZE (Size
);
220 PoolHdr
->Available
= FALSE
;
221 *Buffer
= PoolHdr
+ 1;
225 Size
= (Size
+ MIN_POOL_SIZE
- 1) >> MIN_POOL_SHIFT
;
226 PoolIndex
= (UINTN
) HighBitSet32 ((UINT32
)Size
);
227 if ((Size
& (Size
- 1)) != 0) {
231 Status
= InternalAllocPoolByIndex (PoolIndex
, &FreePoolHdr
);
232 if (!EFI_ERROR(Status
)) {
233 *Buffer
= &FreePoolHdr
->Header
+ 1;
239 Allocate pool of a particular type.
241 @param PoolType Type of pool to allocate.
242 @param Size The amount of pool to allocate.
243 @param Buffer The address to return a pointer to the allocated
246 @retval EFI_INVALID_PARAMETER PoolType not valid.
247 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
248 @retval EFI_SUCCESS Pool successfully allocated.
254 IN EFI_MEMORY_TYPE PoolType
,
261 Status
= SmmInternalAllocatePool (PoolType
, Size
, Buffer
);
262 if (!EFI_ERROR (Status
)) {
263 SmmCoreUpdateProfile ((EFI_PHYSICAL_ADDRESS
) (UINTN
) RETURN_ADDRESS (0), MemoryProfileActionAllocatePool
, PoolType
, Size
, *Buffer
);
271 @param Buffer The allocated pool entry to free.
273 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
274 @retval EFI_SUCCESS Pool successfully freed.
279 SmmInternalFreePool (
283 FREE_POOL_HEADER
*FreePoolHdr
;
285 if (Buffer
== NULL
) {
286 return EFI_INVALID_PARAMETER
;
289 FreePoolHdr
= (FREE_POOL_HEADER
*)((POOL_HEADER
*)Buffer
- 1);
290 ASSERT (!FreePoolHdr
->Header
.Available
);
292 if (FreePoolHdr
->Header
.Size
> MAX_POOL_SIZE
) {
293 ASSERT (((UINTN
)FreePoolHdr
& EFI_PAGE_MASK
) == 0);
294 ASSERT ((FreePoolHdr
->Header
.Size
& EFI_PAGE_MASK
) == 0);
295 return SmmInternalFreePages (
296 (EFI_PHYSICAL_ADDRESS
)(UINTN
)FreePoolHdr
,
297 EFI_SIZE_TO_PAGES (FreePoolHdr
->Header
.Size
)
300 return InternalFreePoolByIndex (FreePoolHdr
);
306 @param Buffer The allocated pool entry to free.
308 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
309 @retval EFI_SUCCESS Pool successfully freed.
320 Status
= SmmInternalFreePool (Buffer
);
321 if (!EFI_ERROR (Status
)) {
322 SmmCoreUpdateProfile ((EFI_PHYSICAL_ADDRESS
) (UINTN
) RETURN_ADDRESS (0), MemoryProfileActionFreePool
, 0, 0, Buffer
);