2 MM Memory page management functions.
4 Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
5 Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR>
6 This program and the accompanying materials are licensed and made available
7 under the terms and conditions of the BSD License which accompanies this
8 distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "StandaloneMmCore.h"
18 #define NEXT_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \
19 ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) + (Size)))
21 #define TRUNCATE_TO_PAGES(a) ((a) >> EFI_PAGE_SHIFT)
23 LIST_ENTRY mMmMemoryMap
= INITIALIZE_LIST_HEAD_VARIABLE (mMmMemoryMap
);
28 Internal Function. Allocate n pages from given free page node.
30 @param Pages The free page node.
31 @param NumberOfPages Number of pages to be allocated.
32 @param MaxAddress Request to allocate memory below this address.
34 @return Memory address of allocated pages.
38 InternalAllocPagesOnOneNode (
39 IN OUT FREE_PAGE_LIST
*Pages
,
40 IN UINTN NumberOfPages
,
48 Top
= TRUNCATE_TO_PAGES (MaxAddress
+ 1 - (UINTN
)Pages
);
49 if (Top
> Pages
->NumberOfPages
) {
50 Top
= Pages
->NumberOfPages
;
52 Bottom
= Top
- NumberOfPages
;
54 if (Top
< Pages
->NumberOfPages
) {
55 Node
= (FREE_PAGE_LIST
*)((UINTN
)Pages
+ EFI_PAGES_TO_SIZE (Top
));
56 Node
->NumberOfPages
= Pages
->NumberOfPages
- Top
;
57 InsertHeadList (&Pages
->Link
, &Node
->Link
);
61 Pages
->NumberOfPages
= Bottom
;
63 RemoveEntryList (&Pages
->Link
);
66 return (UINTN
)Pages
+ EFI_PAGES_TO_SIZE (Bottom
);
70 Internal Function. Allocate n pages from free page list below MaxAddress.
72 @param FreePageList The free page node.
73 @param NumberOfPages Number of pages to be allocated.
74 @param MaxAddress Request to allocate memory below this address.
76 @return Memory address of allocated pages.
80 InternalAllocMaxAddress (
81 IN OUT LIST_ENTRY
*FreePageList
,
82 IN UINTN NumberOfPages
,
87 FREE_PAGE_LIST
*Pages
;
89 for (Node
= FreePageList
->BackLink
; Node
!= FreePageList
; Node
= Node
->BackLink
) {
90 Pages
= BASE_CR (Node
, FREE_PAGE_LIST
, Link
);
91 if (Pages
->NumberOfPages
>= NumberOfPages
&&
92 (UINTN
)Pages
+ EFI_PAGES_TO_SIZE (NumberOfPages
) - 1 <= MaxAddress
) {
93 return InternalAllocPagesOnOneNode (Pages
, NumberOfPages
, MaxAddress
);
100 Internal Function. Allocate n pages from free page list at given address.
102 @param FreePageList The free page node.
103 @param NumberOfPages Number of pages to be allocated.
104 @param MaxAddress Request to allocate memory below this address.
106 @return Memory address of allocated pages.
110 InternalAllocAddress (
111 IN OUT LIST_ENTRY
*FreePageList
,
112 IN UINTN NumberOfPages
,
118 FREE_PAGE_LIST
*Pages
;
120 if ((Address
& EFI_PAGE_MASK
) != 0) {
124 EndAddress
= Address
+ EFI_PAGES_TO_SIZE (NumberOfPages
);
125 for (Node
= FreePageList
->BackLink
; Node
!= FreePageList
; Node
= Node
->BackLink
) {
126 Pages
= BASE_CR (Node
, FREE_PAGE_LIST
, Link
);
127 if ((UINTN
)Pages
<= Address
) {
128 if ((UINTN
)Pages
+ EFI_PAGES_TO_SIZE (Pages
->NumberOfPages
) < EndAddress
) {
131 return InternalAllocPagesOnOneNode (Pages
, NumberOfPages
, EndAddress
);
138 Allocates pages from the memory map.
140 @param Type The type of allocation to perform.
141 @param MemoryType The type of memory to turn the allocated pages
143 @param NumberOfPages The number of pages to allocate.
144 @param Memory A pointer to receive the base allocated memory
147 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.
148 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
149 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
150 @retval EFI_SUCCESS Pages successfully allocated.
155 MmInternalAllocatePages (
156 IN EFI_ALLOCATE_TYPE Type
,
157 IN EFI_MEMORY_TYPE MemoryType
,
158 IN UINTN NumberOfPages
,
159 OUT EFI_PHYSICAL_ADDRESS
*Memory
162 UINTN RequestedAddress
;
164 if (MemoryType
!= EfiRuntimeServicesCode
&&
165 MemoryType
!= EfiRuntimeServicesData
) {
166 return EFI_INVALID_PARAMETER
;
169 if (NumberOfPages
> TRUNCATE_TO_PAGES ((UINTN
)-1) + 1) {
170 return EFI_OUT_OF_RESOURCES
;
174 // We don't track memory type in MM
176 RequestedAddress
= (UINTN
)*Memory
;
178 case AllocateAnyPages
:
179 RequestedAddress
= (UINTN
)(-1);
180 case AllocateMaxAddress
:
181 *Memory
= InternalAllocMaxAddress (
186 if (*Memory
== (UINTN
)-1) {
187 return EFI_OUT_OF_RESOURCES
;
190 case AllocateAddress
:
191 *Memory
= InternalAllocAddress (
196 if (*Memory
!= RequestedAddress
) {
197 return EFI_NOT_FOUND
;
201 return EFI_INVALID_PARAMETER
;
207 Allocates pages from the memory map.
209 @param Type The type of allocation to perform.
210 @param MemoryType The type of memory to turn the allocated pages
212 @param NumberOfPages The number of pages to allocate.
213 @param Memory A pointer to receive the base allocated memory
216 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.
217 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
218 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
219 @retval EFI_SUCCESS Pages successfully allocated.
225 IN EFI_ALLOCATE_TYPE Type
,
226 IN EFI_MEMORY_TYPE MemoryType
,
227 IN UINTN NumberOfPages
,
228 OUT EFI_PHYSICAL_ADDRESS
*Memory
233 Status
= MmInternalAllocatePages (Type
, MemoryType
, NumberOfPages
, Memory
);
238 Internal Function. Merge two adjacent nodes.
240 @param First The first of two nodes to merge.
242 @return Pointer to node after merge (if success) or pointer to next node (if fail).
247 IN FREE_PAGE_LIST
*First
250 FREE_PAGE_LIST
*Next
;
252 Next
= BASE_CR (First
->Link
.ForwardLink
, FREE_PAGE_LIST
, Link
);
254 TRUNCATE_TO_PAGES ((UINTN
)Next
- (UINTN
)First
) >= First
->NumberOfPages
);
256 if (TRUNCATE_TO_PAGES ((UINTN
)Next
- (UINTN
)First
) == First
->NumberOfPages
) {
257 First
->NumberOfPages
+= Next
->NumberOfPages
;
258 RemoveEntryList (&Next
->Link
);
265 Frees previous allocated pages.
267 @param Memory Base address of memory being freed.
268 @param NumberOfPages The number of pages to free.
270 @retval EFI_NOT_FOUND Could not find the entry that covers the range.
271 @retval EFI_INVALID_PARAMETER Address not aligned.
272 @return EFI_SUCCESS Pages successfully freed.
277 MmInternalFreePages (
278 IN EFI_PHYSICAL_ADDRESS Memory
,
279 IN UINTN NumberOfPages
283 FREE_PAGE_LIST
*Pages
;
285 if ((Memory
& EFI_PAGE_MASK
) != 0) {
286 return EFI_INVALID_PARAMETER
;
290 Node
= mMmMemoryMap
.ForwardLink
;
291 while (Node
!= &mMmMemoryMap
) {
292 Pages
= BASE_CR (Node
, FREE_PAGE_LIST
, Link
);
293 if (Memory
< (UINTN
)Pages
) {
296 Node
= Node
->ForwardLink
;
299 if (Node
!= &mMmMemoryMap
&&
300 Memory
+ EFI_PAGES_TO_SIZE (NumberOfPages
) > (UINTN
)Pages
) {
301 return EFI_INVALID_PARAMETER
;
304 if (Node
->BackLink
!= &mMmMemoryMap
) {
305 Pages
= BASE_CR (Node
->BackLink
, FREE_PAGE_LIST
, Link
);
306 if ((UINTN
)Pages
+ EFI_PAGES_TO_SIZE (Pages
->NumberOfPages
) > Memory
) {
307 return EFI_INVALID_PARAMETER
;
311 Pages
= (FREE_PAGE_LIST
*)(UINTN
)Memory
;
312 Pages
->NumberOfPages
= NumberOfPages
;
313 InsertTailList (Node
, &Pages
->Link
);
315 if (Pages
->Link
.BackLink
!= &mMmMemoryMap
) {
316 Pages
= InternalMergeNodes (
317 BASE_CR (Pages
->Link
.BackLink
, FREE_PAGE_LIST
, Link
)
321 if (Node
!= &mMmMemoryMap
) {
322 InternalMergeNodes (Pages
);
329 Frees previous allocated pages.
331 @param Memory Base address of memory being freed.
332 @param NumberOfPages The number of pages to free.
334 @retval EFI_NOT_FOUND Could not find the entry that covers the range.
335 @retval EFI_INVALID_PARAMETER Address not aligned.
336 @return EFI_SUCCESS Pages successfully freed.
342 IN EFI_PHYSICAL_ADDRESS Memory
,
343 IN UINTN NumberOfPages
348 Status
= MmInternalFreePages (Memory
, NumberOfPages
);
353 Add free MMRAM 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 MmFreePages (AlignedMemBase
, TRUNCATE_TO_PAGES ((UINTN
)MemLength
));