2 SMM Memory pool management functions.
4 Copyright (c) 2009 - 2010, 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"
18 // MIN_POOL_SHIFT must not be less than 5
20 #define MIN_POOL_SHIFT 6
21 #define MIN_POOL_SIZE (1 << MIN_POOL_SHIFT)
24 // MAX_POOL_SHIFT must not be less than EFI_PAGE_SHIFT - 1
26 #define MAX_POOL_SHIFT (EFI_PAGE_SHIFT - 1)
27 #define MAX_POOL_SIZE (1 << MAX_POOL_SHIFT)
30 // MAX_POOL_INDEX are calculated by maximum and minimum pool sizes
32 #define MAX_POOL_INDEX (MAX_POOL_SHIFT - MIN_POOL_SHIFT + 1)
44 LIST_ENTRY mSmmPoolLists
[MAX_POOL_INDEX
];
46 // To cache the SMRAM base since when Loading modules At fixed address feature is enabled,
47 // all module is assigned an offset relative the SMRAM base in build time.
49 GLOBAL_REMOVE_IF_UNREFERENCED EFI_PHYSICAL_ADDRESS gLoadModuleAtFixAddressSmramBase
= 0;
52 Called to initialize the memory service.
54 @param SmramRangeCount Number of SMRAM Regions
55 @param SmramRanges Pointer to SMRAM Descriptors
59 SmmInitializeMemoryServices (
60 IN UINTN SmramRangeCount
,
61 IN EFI_SMRAM_DESCRIPTOR
*SmramRanges
66 UINTN CurrentSmramRangesIndex
;
70 // Initialize Pool list
72 for (Index
= sizeof (mSmmPoolLists
) / sizeof (*mSmmPoolLists
); Index
> 0;) {
73 InitializeListHead (&mSmmPoolLists
[--Index
]);
75 CurrentSmramRangesIndex
= 0;
77 // If Loadding 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
++) {
89 if (SmramRanges
[Index
].CpuStart
>= BASE_1MB
) {
90 if ((SmramRanges
[Index
].CpuStart
+ SmramRanges
[Index
].PhysicalSize
) <= BASE_4GB
) {
91 if (SmramRanges
[Index
].PhysicalSize
>= MaxSize
) {
92 MaxSize
= SmramRanges
[Index
].PhysicalSize
;
93 CurrentSmramRangesIndex
= Index
;
98 gLoadModuleAtFixAddressSmramBase
= SmramRanges
[CurrentSmramRangesIndex
].CpuStart
;
101 // cut out a memory range from this SMRAM range with the size SmmCodeSize to hold SMM driver code
102 // A notable thing is that SMM core is already loaded into this range.
104 SmramRanges
[CurrentSmramRangesIndex
].CpuStart
= SmramRanges
[CurrentSmramRangesIndex
].CpuStart
+ SmmCodeSize
;
105 SmramRanges
[CurrentSmramRangesIndex
].PhysicalSize
= SmramRanges
[CurrentSmramRangesIndex
].PhysicalSize
- SmmCodeSize
;
108 // Initialize free SMRAM regions
110 for (Index
= 0; Index
< SmramRangeCount
; Index
++) {
112 SmramRanges
[Index
].CpuStart
,
113 SmramRanges
[Index
].PhysicalSize
,
114 EfiConventionalMemory
,
115 SmramRanges
[Index
].RegionState
122 Internal Function. Allocate a pool by specified PoolIndex.
124 @param PoolIndex Index which indicate the Pool size.
125 @param FreePoolHdr The returned Free pool.
127 @retval EFI_OUT_OF_RESOURCES Allocation failed.
128 @retval EFI_SUCCESS Pool successfully allocated.
132 InternalAllocPoolByIndex (
134 OUT FREE_POOL_HEADER
**FreePoolHdr
138 FREE_POOL_HEADER
*Hdr
;
140 ASSERT (PoolIndex
<= MAX_POOL_INDEX
);
141 Status
= EFI_SUCCESS
;
142 if (PoolIndex
== MAX_POOL_INDEX
) {
143 Hdr
= (FREE_POOL_HEADER
*)AllocatePages (EFI_SIZE_TO_PAGES (MAX_POOL_SIZE
<< 1));
145 return EFI_OUT_OF_RESOURCES
;
147 } else if (!IsListEmpty (&mSmmPoolLists
[PoolIndex
])) {
148 Hdr
= BASE_CR (GetFirstNode (&mSmmPoolLists
[PoolIndex
]), FREE_POOL_HEADER
, Link
);
149 RemoveEntryList (&Hdr
->Link
);
151 Status
= InternalAllocPoolByIndex (PoolIndex
+ 1, &Hdr
);
152 if (!EFI_ERROR (Status
)) {
153 Hdr
->Header
.Size
>>= 1;
154 Hdr
->Header
.Available
= TRUE
;
155 InsertHeadList (&mSmmPoolLists
[PoolIndex
], &Hdr
->Link
);
156 Hdr
= (FREE_POOL_HEADER
*)((UINT8
*)Hdr
+ Hdr
->Header
.Size
);
160 if (!EFI_ERROR (Status
)) {
161 Hdr
->Header
.Size
= MIN_POOL_SIZE
<< PoolIndex
;
162 Hdr
->Header
.Available
= FALSE
;
170 Internal Function. Free a pool by specified PoolIndex.
172 @param FreePoolHdr The pool to free.
174 @retval EFI_SUCCESS Pool successfully freed.
178 InternalFreePoolByIndex (
179 IN FREE_POOL_HEADER
*FreePoolHdr
184 ASSERT ((FreePoolHdr
->Header
.Size
& (FreePoolHdr
->Header
.Size
- 1)) == 0);
185 ASSERT (((UINTN
)FreePoolHdr
& (FreePoolHdr
->Header
.Size
- 1)) == 0);
186 ASSERT (FreePoolHdr
->Header
.Size
>= MIN_POOL_SIZE
);
188 PoolIndex
= HighBitSet32 ((UINT32
)FreePoolHdr
->Header
.Size
) - MIN_POOL_SHIFT
;
189 FreePoolHdr
->Header
.Available
= TRUE
;
190 ASSERT (PoolIndex
< MAX_POOL_INDEX
);
191 InsertHeadList (&mSmmPoolLists
[PoolIndex
], &FreePoolHdr
->Link
);
196 Allocate pool of a particular type.
198 @param PoolType Type of pool to allocate.
199 @param Size The amount of pool to allocate.
200 @param Buffer The address to return a pointer to the allocated
203 @retval EFI_INVALID_PARAMETER PoolType not valid.
204 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
205 @retval EFI_SUCCESS Pool successfully allocated.
211 IN EFI_MEMORY_TYPE PoolType
,
216 POOL_HEADER
*PoolHdr
;
217 FREE_POOL_HEADER
*FreePoolHdr
;
219 EFI_PHYSICAL_ADDRESS Address
;
222 if (PoolType
!= EfiRuntimeServicesCode
&&
223 PoolType
!= EfiRuntimeServicesData
) {
224 return EFI_INVALID_PARAMETER
;
232 Size
+= sizeof (*PoolHdr
);
233 if (Size
> MAX_POOL_SIZE
) {
234 Size
= EFI_SIZE_TO_PAGES (Size
);
235 Status
= SmmAllocatePages (AllocateAnyPages
, PoolType
, Size
, &Address
);
236 if (EFI_ERROR (Status
)) {
240 PoolHdr
= (POOL_HEADER
*)(UINTN
)Address
;
241 PoolHdr
->Size
= EFI_PAGES_TO_SIZE (Size
);
242 PoolHdr
->Available
= FALSE
;
243 *Buffer
= PoolHdr
+ 1;
247 Size
= (Size
+ MIN_POOL_SIZE
- 1) >> MIN_POOL_SHIFT
;
248 PoolIndex
= HighBitSet32 ((UINT32
)Size
);
249 if ((Size
& (Size
- 1)) != 0) {
253 Status
= InternalAllocPoolByIndex (PoolIndex
, &FreePoolHdr
);
254 *Buffer
= &FreePoolHdr
->Header
+ 1;
261 @param Buffer The allocated pool entry to free.
263 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
264 @retval EFI_SUCCESS Pool successfully freed.
273 FREE_POOL_HEADER
*FreePoolHdr
;
275 if (Buffer
== NULL
) {
276 return EFI_INVALID_PARAMETER
;
279 FreePoolHdr
= (FREE_POOL_HEADER
*)((POOL_HEADER
*)Buffer
- 1);
280 ASSERT (!FreePoolHdr
->Header
.Available
);
282 if (FreePoolHdr
->Header
.Size
> MAX_POOL_SIZE
) {
283 ASSERT (((UINTN
)FreePoolHdr
& EFI_PAGE_MASK
) == 0);
284 ASSERT ((FreePoolHdr
->Header
.Size
& EFI_PAGE_MASK
) == 0);
285 return SmmFreePages (
286 (EFI_PHYSICAL_ADDRESS
)(UINTN
)FreePoolHdr
,
287 EFI_SIZE_TO_PAGES (FreePoolHdr
->Header
.Size
)
290 return InternalFreePoolByIndex (FreePoolHdr
);