2 SMM Memory page 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"
17 #define TRUNCATE_TO_PAGES(a) ((a) >> EFI_PAGE_SHIFT)
24 LIST_ENTRY mSmmMemoryMap
= INITIALIZE_LIST_HEAD_VARIABLE (mSmmMemoryMap
);
27 Internal Function. Allocate n pages from given free page node.
29 @param Pages The free page node.
30 @param NumberOfPages Number of pages to be allocated.
31 @param MaxAddress Request to allocate memory below this address.
33 @return Memory address of allocated pages.
37 InternalAllocPagesOnOneNode (
38 IN OUT FREE_PAGE_LIST
*Pages
,
39 IN UINTN NumberOfPages
,
47 Top
= TRUNCATE_TO_PAGES (MaxAddress
+ 1 - (UINTN
)Pages
);
48 if (Top
> Pages
->NumberOfPages
) {
49 Top
= Pages
->NumberOfPages
;
51 Bottom
= Top
- NumberOfPages
;
53 if (Top
< Pages
->NumberOfPages
) {
54 Node
= (FREE_PAGE_LIST
*)((UINTN
)Pages
+ EFI_PAGES_TO_SIZE (Top
));
55 Node
->NumberOfPages
= Pages
->NumberOfPages
- Top
;
56 InsertHeadList (&Pages
->Link
, &Node
->Link
);
60 Pages
->NumberOfPages
= Bottom
;
62 RemoveEntryList (&Pages
->Link
);
65 return (UINTN
)Pages
+ EFI_PAGES_TO_SIZE (Bottom
);
69 Internal Function. Allocate n pages from free page list below MaxAddress.
71 @param FreePageList The free page node.
72 @param NumberOfPages Number of pages to be allocated.
73 @param MaxAddress Request to allocate memory below this address.
75 @return Memory address of allocated pages.
79 InternalAllocMaxAddress (
80 IN OUT LIST_ENTRY
*FreePageList
,
81 IN UINTN NumberOfPages
,
86 FREE_PAGE_LIST
*Pages
;
88 for (Node
= FreePageList
->BackLink
; Node
!= FreePageList
; Node
= Node
->BackLink
) {
89 Pages
= BASE_CR (Node
, FREE_PAGE_LIST
, Link
);
90 if (Pages
->NumberOfPages
>= NumberOfPages
&&
91 (UINTN
)Pages
+ EFI_PAGES_TO_SIZE (NumberOfPages
) - 1 <= MaxAddress
) {
92 return InternalAllocPagesOnOneNode (Pages
, NumberOfPages
, MaxAddress
);
99 Internal Function. Allocate n pages from free page list at given address.
101 @param FreePageList The free page node.
102 @param NumberOfPages Number of pages to be allocated.
103 @param MaxAddress Request to allocate memory below this address.
105 @return Memory address of allocated pages.
109 InternalAllocAddress (
110 IN OUT LIST_ENTRY
*FreePageList
,
111 IN UINTN NumberOfPages
,
117 FREE_PAGE_LIST
*Pages
;
119 if ((Address
& EFI_PAGE_MASK
) != 0) {
123 EndAddress
= Address
+ EFI_PAGES_TO_SIZE (NumberOfPages
);
124 for (Node
= FreePageList
->BackLink
; Node
!= FreePageList
; Node
= Node
->BackLink
) {
125 Pages
= BASE_CR (Node
, FREE_PAGE_LIST
, Link
);
126 if ((UINTN
)Pages
<= Address
) {
127 if ((UINTN
)Pages
+ EFI_PAGES_TO_SIZE (Pages
->NumberOfPages
) < EndAddress
) {
130 return InternalAllocPagesOnOneNode (Pages
, NumberOfPages
, EndAddress
);
137 Allocates pages from the memory map.
139 @param Type The type of allocation to perform.
140 @param MemoryType The type of memory to turn the allocated pages
142 @param NumberOfPages The number of pages to allocate.
143 @param Memory A pointer to receive the base allocated memory
146 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.
147 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
148 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
149 @retval EFI_SUCCESS Pages successfully allocated.
155 IN EFI_ALLOCATE_TYPE Type
,
156 IN EFI_MEMORY_TYPE MemoryType
,
157 IN UINTN NumberOfPages
,
158 OUT EFI_PHYSICAL_ADDRESS
*Memory
161 UINTN RequestedAddress
;
163 if (MemoryType
!= EfiRuntimeServicesCode
&&
164 MemoryType
!= EfiRuntimeServicesData
) {
165 return EFI_INVALID_PARAMETER
;
168 if (NumberOfPages
> TRUNCATE_TO_PAGES ((UINTN
)-1) + 1) {
169 return EFI_OUT_OF_RESOURCES
;
173 // We don't track memory type in SMM
175 RequestedAddress
= (UINTN
)*Memory
;
177 case AllocateAnyPages
:
178 RequestedAddress
= (UINTN
)(-1);
179 case AllocateMaxAddress
:
180 *Memory
= InternalAllocMaxAddress (
185 if (*Memory
== (UINTN
)-1) {
186 return EFI_OUT_OF_RESOURCES
;
189 case AllocateAddress
:
190 *Memory
= InternalAllocAddress (
195 if (*Memory
!= RequestedAddress
) {
196 return EFI_NOT_FOUND
;
200 return EFI_INVALID_PARAMETER
;
206 Internal Function. Merge two adjacent nodes.
208 @param First The first of two nodes to merge.
210 @return Pointer to node after merge (if success) or pointer to next node (if fail).
215 IN FREE_PAGE_LIST
*First
218 FREE_PAGE_LIST
*Next
;
220 Next
= BASE_CR (First
->Link
.ForwardLink
, FREE_PAGE_LIST
, Link
);
222 TRUNCATE_TO_PAGES ((UINTN
)Next
- (UINTN
)First
) >= First
->NumberOfPages
);
224 if (TRUNCATE_TO_PAGES ((UINTN
)Next
- (UINTN
)First
) == First
->NumberOfPages
) {
225 First
->NumberOfPages
+= Next
->NumberOfPages
;
226 RemoveEntryList (&Next
->Link
);
233 Frees previous allocated pages.
235 @param Memory Base address of memory being freed.
236 @param NumberOfPages The number of pages to free.
238 @retval EFI_NOT_FOUND Could not find the entry that covers the range.
239 @retval EFI_INVALID_PARAMETER Address not aligned.
240 @return EFI_SUCCESS Pages successfully freed.
246 IN EFI_PHYSICAL_ADDRESS Memory
,
247 IN UINTN NumberOfPages
251 FREE_PAGE_LIST
*Pages
;
253 if ((Memory
& EFI_PAGE_MASK
) != 0) {
254 return EFI_INVALID_PARAMETER
;
258 Node
= mSmmMemoryMap
.ForwardLink
;
259 while (Node
!= &mSmmMemoryMap
) {
260 Pages
= BASE_CR (Node
, FREE_PAGE_LIST
, Link
);
261 if (Memory
< (UINTN
)Pages
) {
264 Node
= Node
->ForwardLink
;
267 if (Node
!= &mSmmMemoryMap
&&
268 Memory
+ EFI_PAGES_TO_SIZE (NumberOfPages
) > (UINTN
)Pages
) {
269 return EFI_INVALID_PARAMETER
;
272 if (Node
->BackLink
!= &mSmmMemoryMap
) {
273 Pages
= BASE_CR (Node
->BackLink
, FREE_PAGE_LIST
, Link
);
274 if ((UINTN
)Pages
+ EFI_PAGES_TO_SIZE (Pages
->NumberOfPages
) > Memory
) {
275 return EFI_INVALID_PARAMETER
;
279 Pages
= (FREE_PAGE_LIST
*)(UINTN
)Memory
;
280 Pages
->NumberOfPages
= NumberOfPages
;
281 InsertTailList (Node
, &Pages
->Link
);
283 if (Pages
->Link
.BackLink
!= &mSmmMemoryMap
) {
284 Pages
= InternalMergeNodes (
285 BASE_CR (Pages
->Link
.BackLink
, FREE_PAGE_LIST
, Link
)
289 if (Node
!= &mSmmMemoryMap
) {
290 InternalMergeNodes (Pages
);
297 Add free SMRAM region for use by memory service.
299 @param MemBase Base address of memory region.
300 @param MemLength Length of the memory region.
301 @param Type Memory type.
302 @param Attributes Memory region state.
307 IN EFI_PHYSICAL_ADDRESS MemBase
,
309 IN EFI_MEMORY_TYPE Type
,
313 UINTN AlignedMemBase
;
316 // Do not add memory regions that is already allocated, needs testing, or needs ECC initialization
318 if ((Attributes
& (EFI_ALLOCATED
| EFI_NEEDS_TESTING
| EFI_NEEDS_ECC_INITIALIZATION
)) != 0) {
323 // Align range on an EFI_PAGE_SIZE boundary
325 AlignedMemBase
= (UINTN
)(MemBase
+ EFI_PAGE_MASK
) & ~EFI_PAGE_MASK
;
326 MemLength
-= AlignedMemBase
- MemBase
;
327 SmmFreePages (AlignedMemBase
, TRUNCATE_TO_PAGES ((UINTN
)MemLength
));