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 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include "StandaloneMmCore.h"
12 #define NEXT_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \
13 ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) + (Size)))
15 #define TRUNCATE_TO_PAGES(a) ((a) >> EFI_PAGE_SHIFT)
17 LIST_ENTRY mMmMemoryMap
= INITIALIZE_LIST_HEAD_VARIABLE (mMmMemoryMap
);
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 MmInternalAllocatePages (
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 MM
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
= MmInternalAllocatePages (Type
, MemoryType
, NumberOfPages
, Memory
);
232 Internal Function. Merge two adjacent nodes.
234 @param First The first of two nodes to merge.
236 @return Pointer to node after merge (if success) or pointer to next node (if fail).
241 IN FREE_PAGE_LIST
*First
244 FREE_PAGE_LIST
*Next
;
246 Next
= BASE_CR (First
->Link
.ForwardLink
, FREE_PAGE_LIST
, Link
);
248 TRUNCATE_TO_PAGES ((UINTN
)Next
- (UINTN
)First
) >= First
->NumberOfPages
);
250 if (TRUNCATE_TO_PAGES ((UINTN
)Next
- (UINTN
)First
) == First
->NumberOfPages
) {
251 First
->NumberOfPages
+= Next
->NumberOfPages
;
252 RemoveEntryList (&Next
->Link
);
259 Frees previous allocated pages.
261 @param Memory Base address of memory being freed.
262 @param NumberOfPages The number of pages to free.
264 @retval EFI_NOT_FOUND Could not find the entry that covers the range.
265 @retval EFI_INVALID_PARAMETER Address not aligned.
266 @return EFI_SUCCESS Pages successfully freed.
271 MmInternalFreePages (
272 IN EFI_PHYSICAL_ADDRESS Memory
,
273 IN UINTN NumberOfPages
277 FREE_PAGE_LIST
*Pages
;
279 if ((Memory
& EFI_PAGE_MASK
) != 0) {
280 return EFI_INVALID_PARAMETER
;
284 Node
= mMmMemoryMap
.ForwardLink
;
285 while (Node
!= &mMmMemoryMap
) {
286 Pages
= BASE_CR (Node
, FREE_PAGE_LIST
, Link
);
287 if (Memory
< (UINTN
)Pages
) {
290 Node
= Node
->ForwardLink
;
293 if (Node
!= &mMmMemoryMap
&&
294 Memory
+ EFI_PAGES_TO_SIZE (NumberOfPages
) > (UINTN
)Pages
) {
295 return EFI_INVALID_PARAMETER
;
298 if (Node
->BackLink
!= &mMmMemoryMap
) {
299 Pages
= BASE_CR (Node
->BackLink
, FREE_PAGE_LIST
, Link
);
300 if ((UINTN
)Pages
+ EFI_PAGES_TO_SIZE (Pages
->NumberOfPages
) > Memory
) {
301 return EFI_INVALID_PARAMETER
;
305 Pages
= (FREE_PAGE_LIST
*)(UINTN
)Memory
;
306 Pages
->NumberOfPages
= NumberOfPages
;
307 InsertTailList (Node
, &Pages
->Link
);
309 if (Pages
->Link
.BackLink
!= &mMmMemoryMap
) {
310 Pages
= InternalMergeNodes (
311 BASE_CR (Pages
->Link
.BackLink
, FREE_PAGE_LIST
, Link
)
315 if (Node
!= &mMmMemoryMap
) {
316 InternalMergeNodes (Pages
);
323 Frees previous allocated pages.
325 @param Memory Base address of memory being freed.
326 @param NumberOfPages The number of pages to free.
328 @retval EFI_NOT_FOUND Could not find the entry that covers the range.
329 @retval EFI_INVALID_PARAMETER Address not aligned.
330 @return EFI_SUCCESS Pages successfully freed.
336 IN EFI_PHYSICAL_ADDRESS Memory
,
337 IN UINTN NumberOfPages
342 Status
= MmInternalFreePages (Memory
, NumberOfPages
);
347 Add free MMRAM region for use by memory service.
349 @param MemBase Base address of memory region.
350 @param MemLength Length of the memory region.
351 @param Type Memory type.
352 @param Attributes Memory region state.
357 IN EFI_PHYSICAL_ADDRESS MemBase
,
359 IN EFI_MEMORY_TYPE Type
,
363 UINTN AlignedMemBase
;
366 // Do not add memory regions that is already allocated, needs testing, or needs ECC initialization
368 if ((Attributes
& (EFI_ALLOCATED
| EFI_NEEDS_TESTING
| EFI_NEEDS_ECC_INITIALIZATION
)) != 0) {
373 // Align range on an EFI_PAGE_SIZE boundary
375 AlignedMemBase
= (UINTN
)(MemBase
+ EFI_PAGE_MASK
) & ~EFI_PAGE_MASK
;
376 MemLength
-= AlignedMemBase
- MemBase
;
377 MmFreePages (AlignedMemBase
, TRUNCATE_TO_PAGES ((UINTN
)MemLength
));