2 SMM Memory page management functions.
4 Copyright (c) 2009 - 2014, 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 #define TRUNCATE_TO_PAGES(a) ((a) >> EFI_PAGE_SHIFT)
19 LIST_ENTRY mSmmMemoryMap
= INITIALIZE_LIST_HEAD_VARIABLE (mSmmMemoryMap
);
22 Internal Function. Allocate n pages from given free page node.
24 @param Pages The free page node.
25 @param NumberOfPages Number of pages to be allocated.
26 @param MaxAddress Request to allocate memory below this address.
28 @return Memory address of allocated pages.
32 InternalAllocPagesOnOneNode (
33 IN OUT FREE_PAGE_LIST
*Pages
,
34 IN UINTN NumberOfPages
,
42 Top
= TRUNCATE_TO_PAGES (MaxAddress
+ 1 - (UINTN
)Pages
);
43 if (Top
> Pages
->NumberOfPages
) {
44 Top
= Pages
->NumberOfPages
;
46 Bottom
= Top
- NumberOfPages
;
48 if (Top
< Pages
->NumberOfPages
) {
49 Node
= (FREE_PAGE_LIST
*)((UINTN
)Pages
+ EFI_PAGES_TO_SIZE (Top
));
50 Node
->NumberOfPages
= Pages
->NumberOfPages
- Top
;
51 InsertHeadList (&Pages
->Link
, &Node
->Link
);
55 Pages
->NumberOfPages
= Bottom
;
57 RemoveEntryList (&Pages
->Link
);
60 return (UINTN
)Pages
+ EFI_PAGES_TO_SIZE (Bottom
);
64 Internal Function. Allocate n pages from free page list below MaxAddress.
66 @param FreePageList The free page node.
67 @param NumberOfPages Number of pages to be allocated.
68 @param MaxAddress Request to allocate memory below this address.
70 @return Memory address of allocated pages.
74 InternalAllocMaxAddress (
75 IN OUT LIST_ENTRY
*FreePageList
,
76 IN UINTN NumberOfPages
,
81 FREE_PAGE_LIST
*Pages
;
83 for (Node
= FreePageList
->BackLink
; Node
!= FreePageList
; Node
= Node
->BackLink
) {
84 Pages
= BASE_CR (Node
, FREE_PAGE_LIST
, Link
);
85 if (Pages
->NumberOfPages
>= NumberOfPages
&&
86 (UINTN
)Pages
+ EFI_PAGES_TO_SIZE (NumberOfPages
) - 1 <= MaxAddress
) {
87 return InternalAllocPagesOnOneNode (Pages
, NumberOfPages
, MaxAddress
);
94 Internal Function. Allocate n pages from free page list at given address.
96 @param FreePageList The free page node.
97 @param NumberOfPages Number of pages to be allocated.
98 @param MaxAddress Request to allocate memory below this address.
100 @return Memory address of allocated pages.
104 InternalAllocAddress (
105 IN OUT LIST_ENTRY
*FreePageList
,
106 IN UINTN NumberOfPages
,
112 FREE_PAGE_LIST
*Pages
;
114 if ((Address
& EFI_PAGE_MASK
) != 0) {
118 EndAddress
= Address
+ EFI_PAGES_TO_SIZE (NumberOfPages
);
119 for (Node
= FreePageList
->BackLink
; Node
!= FreePageList
; Node
= Node
->BackLink
) {
120 Pages
= BASE_CR (Node
, FREE_PAGE_LIST
, Link
);
121 if ((UINTN
)Pages
<= Address
) {
122 if ((UINTN
)Pages
+ EFI_PAGES_TO_SIZE (Pages
->NumberOfPages
) < EndAddress
) {
125 return InternalAllocPagesOnOneNode (Pages
, NumberOfPages
, EndAddress
);
132 Allocates pages from the memory map.
134 @param Type The type of allocation to perform.
135 @param MemoryType The type of memory to turn the allocated pages
137 @param NumberOfPages The number of pages to allocate.
138 @param Memory A pointer to receive the base allocated memory
141 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.
142 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
143 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
144 @retval EFI_SUCCESS Pages successfully allocated.
149 SmmInternalAllocatePages (
150 IN EFI_ALLOCATE_TYPE Type
,
151 IN EFI_MEMORY_TYPE MemoryType
,
152 IN UINTN NumberOfPages
,
153 OUT EFI_PHYSICAL_ADDRESS
*Memory
156 UINTN RequestedAddress
;
158 if (MemoryType
!= EfiRuntimeServicesCode
&&
159 MemoryType
!= EfiRuntimeServicesData
) {
160 return EFI_INVALID_PARAMETER
;
163 if (NumberOfPages
> TRUNCATE_TO_PAGES ((UINTN
)-1) + 1) {
164 return EFI_OUT_OF_RESOURCES
;
168 // We don't track memory type in SMM
170 RequestedAddress
= (UINTN
)*Memory
;
172 case AllocateAnyPages
:
173 RequestedAddress
= (UINTN
)(-1);
174 case AllocateMaxAddress
:
175 *Memory
= InternalAllocMaxAddress (
180 if (*Memory
== (UINTN
)-1) {
181 return EFI_OUT_OF_RESOURCES
;
184 case AllocateAddress
:
185 *Memory
= InternalAllocAddress (
190 if (*Memory
!= RequestedAddress
) {
191 return EFI_NOT_FOUND
;
195 return EFI_INVALID_PARAMETER
;
201 Allocates pages from the memory map.
203 @param Type The type of allocation to perform.
204 @param MemoryType The type of memory to turn the allocated pages
206 @param NumberOfPages The number of pages to allocate.
207 @param Memory A pointer to receive the base allocated memory
210 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.
211 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
212 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
213 @retval EFI_SUCCESS Pages successfully allocated.
219 IN EFI_ALLOCATE_TYPE Type
,
220 IN EFI_MEMORY_TYPE MemoryType
,
221 IN UINTN NumberOfPages
,
222 OUT EFI_PHYSICAL_ADDRESS
*Memory
227 Status
= SmmInternalAllocatePages (Type
, MemoryType
, NumberOfPages
, Memory
);
228 if (!EFI_ERROR (Status
)) {
229 SmmCoreUpdateProfile ((EFI_PHYSICAL_ADDRESS
) (UINTN
) RETURN_ADDRESS (0), MemoryProfileActionAllocatePages
, MemoryType
, EFI_PAGES_TO_SIZE (NumberOfPages
), (VOID
*) (UINTN
) *Memory
);
235 Internal Function. Merge two adjacent nodes.
237 @param First The first of two nodes to merge.
239 @return Pointer to node after merge (if success) or pointer to next node (if fail).
244 IN FREE_PAGE_LIST
*First
247 FREE_PAGE_LIST
*Next
;
249 Next
= BASE_CR (First
->Link
.ForwardLink
, FREE_PAGE_LIST
, Link
);
251 TRUNCATE_TO_PAGES ((UINTN
)Next
- (UINTN
)First
) >= First
->NumberOfPages
);
253 if (TRUNCATE_TO_PAGES ((UINTN
)Next
- (UINTN
)First
) == First
->NumberOfPages
) {
254 First
->NumberOfPages
+= Next
->NumberOfPages
;
255 RemoveEntryList (&Next
->Link
);
262 Frees previous allocated pages.
264 @param Memory Base address of memory being freed.
265 @param NumberOfPages The number of pages to free.
267 @retval EFI_NOT_FOUND Could not find the entry that covers the range.
268 @retval EFI_INVALID_PARAMETER Address not aligned.
269 @return EFI_SUCCESS Pages successfully freed.
274 SmmInternalFreePages (
275 IN EFI_PHYSICAL_ADDRESS Memory
,
276 IN UINTN NumberOfPages
280 FREE_PAGE_LIST
*Pages
;
282 if ((Memory
& EFI_PAGE_MASK
) != 0) {
283 return EFI_INVALID_PARAMETER
;
287 Node
= mSmmMemoryMap
.ForwardLink
;
288 while (Node
!= &mSmmMemoryMap
) {
289 Pages
= BASE_CR (Node
, FREE_PAGE_LIST
, Link
);
290 if (Memory
< (UINTN
)Pages
) {
293 Node
= Node
->ForwardLink
;
296 if (Node
!= &mSmmMemoryMap
&&
297 Memory
+ EFI_PAGES_TO_SIZE (NumberOfPages
) > (UINTN
)Pages
) {
298 return EFI_INVALID_PARAMETER
;
301 if (Node
->BackLink
!= &mSmmMemoryMap
) {
302 Pages
= BASE_CR (Node
->BackLink
, FREE_PAGE_LIST
, Link
);
303 if ((UINTN
)Pages
+ EFI_PAGES_TO_SIZE (Pages
->NumberOfPages
) > Memory
) {
304 return EFI_INVALID_PARAMETER
;
308 Pages
= (FREE_PAGE_LIST
*)(UINTN
)Memory
;
309 Pages
->NumberOfPages
= NumberOfPages
;
310 InsertTailList (Node
, &Pages
->Link
);
312 if (Pages
->Link
.BackLink
!= &mSmmMemoryMap
) {
313 Pages
= InternalMergeNodes (
314 BASE_CR (Pages
->Link
.BackLink
, FREE_PAGE_LIST
, Link
)
318 if (Node
!= &mSmmMemoryMap
) {
319 InternalMergeNodes (Pages
);
326 Frees previous allocated pages.
328 @param Memory Base address of memory being freed.
329 @param NumberOfPages The number of pages to free.
331 @retval EFI_NOT_FOUND Could not find the entry that covers the range.
332 @retval EFI_INVALID_PARAMETER Address not aligned.
333 @return EFI_SUCCESS Pages successfully freed.
339 IN EFI_PHYSICAL_ADDRESS Memory
,
340 IN UINTN NumberOfPages
345 Status
= SmmInternalFreePages (Memory
, NumberOfPages
);
346 if (!EFI_ERROR (Status
)) {
347 SmmCoreUpdateProfile ((EFI_PHYSICAL_ADDRESS
) (UINTN
) RETURN_ADDRESS (0), MemoryProfileActionFreePages
, 0, EFI_PAGES_TO_SIZE (NumberOfPages
), (VOID
*) (UINTN
) Memory
);
353 Add free SMRAM region for use by memory service.
355 @param MemBase Base address of memory region.
356 @param MemLength Length of the memory region.
357 @param Type Memory type.
358 @param Attributes Memory region state.
363 IN EFI_PHYSICAL_ADDRESS MemBase
,
365 IN EFI_MEMORY_TYPE Type
,
369 UINTN AlignedMemBase
;
372 // Do not add memory regions that is already allocated, needs testing, or needs ECC initialization
374 if ((Attributes
& (EFI_ALLOCATED
| EFI_NEEDS_TESTING
| EFI_NEEDS_ECC_INITIALIZATION
)) != 0) {
379 // Align range on an EFI_PAGE_SIZE boundary
381 AlignedMemBase
= (UINTN
)(MemBase
+ EFI_PAGE_MASK
) & ~EFI_PAGE_MASK
;
382 MemLength
-= AlignedMemBase
- MemBase
;
383 SmmFreePages (AlignedMemBase
, TRUNCATE_TO_PAGES ((UINTN
)MemLength
));