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
;
47 Bottom
= Top
- NumberOfPages
;
49 if (Top
< Pages
->NumberOfPages
) {
50 Node
= (FREE_PAGE_LIST
*)((UINTN
)Pages
+ EFI_PAGES_TO_SIZE (Top
));
51 Node
->NumberOfPages
= Pages
->NumberOfPages
- Top
;
52 InsertHeadList (&Pages
->Link
, &Node
->Link
);
56 Pages
->NumberOfPages
= Bottom
;
58 RemoveEntryList (&Pages
->Link
);
61 return (UINTN
)Pages
+ EFI_PAGES_TO_SIZE (Bottom
);
65 Internal Function. Allocate n pages from free page list below MaxAddress.
67 @param FreePageList The free page node.
68 @param NumberOfPages Number of pages to be allocated.
69 @param MaxAddress Request to allocate memory below this address.
71 @return Memory address of allocated pages.
75 InternalAllocMaxAddress (
76 IN OUT LIST_ENTRY
*FreePageList
,
77 IN UINTN NumberOfPages
,
82 FREE_PAGE_LIST
*Pages
;
84 for (Node
= FreePageList
->BackLink
; Node
!= FreePageList
; Node
= Node
->BackLink
) {
85 Pages
= BASE_CR (Node
, FREE_PAGE_LIST
, Link
);
86 if ((Pages
->NumberOfPages
>= NumberOfPages
) &&
87 ((UINTN
)Pages
+ EFI_PAGES_TO_SIZE (NumberOfPages
) - 1 <= MaxAddress
))
89 return InternalAllocPagesOnOneNode (Pages
, NumberOfPages
, MaxAddress
);
97 Internal Function. Allocate n pages from free page list at given address.
99 @param FreePageList The free page node.
100 @param NumberOfPages Number of pages to be allocated.
101 @param MaxAddress Request to allocate memory below this address.
103 @return Memory address of allocated pages.
107 InternalAllocAddress (
108 IN OUT LIST_ENTRY
*FreePageList
,
109 IN UINTN NumberOfPages
,
115 FREE_PAGE_LIST
*Pages
;
117 if ((Address
& EFI_PAGE_MASK
) != 0) {
121 EndAddress
= Address
+ EFI_PAGES_TO_SIZE (NumberOfPages
);
122 for (Node
= FreePageList
->BackLink
; Node
!= FreePageList
; Node
= Node
->BackLink
) {
123 Pages
= BASE_CR (Node
, FREE_PAGE_LIST
, Link
);
124 if ((UINTN
)Pages
<= Address
) {
125 if ((UINTN
)Pages
+ EFI_PAGES_TO_SIZE (Pages
->NumberOfPages
) < EndAddress
) {
129 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.
154 MmInternalAllocatePages (
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
))
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
;
191 case AllocateAddress
:
192 *Memory
= InternalAllocAddress (
197 if (*Memory
!= RequestedAddress
) {
198 return EFI_NOT_FOUND
;
203 return EFI_INVALID_PARAMETER
;
210 Allocates pages from the memory map.
212 @param Type The type of allocation to perform.
213 @param MemoryType The type of memory to turn the allocated pages
215 @param NumberOfPages The number of pages to allocate.
216 @param Memory A pointer to receive the base allocated memory
219 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.
220 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
221 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
222 @retval EFI_SUCCESS Pages successfully allocated.
228 IN EFI_ALLOCATE_TYPE Type
,
229 IN EFI_MEMORY_TYPE MemoryType
,
230 IN UINTN NumberOfPages
,
231 OUT EFI_PHYSICAL_ADDRESS
*Memory
236 Status
= MmInternalAllocatePages (Type
, MemoryType
, NumberOfPages
, Memory
);
241 Internal Function. Merge two adjacent nodes.
243 @param First The first of two nodes to merge.
245 @return Pointer to node after merge (if success) or pointer to next node (if fail).
250 IN FREE_PAGE_LIST
*First
253 FREE_PAGE_LIST
*Next
;
255 Next
= BASE_CR (First
->Link
.ForwardLink
, FREE_PAGE_LIST
, Link
);
257 TRUNCATE_TO_PAGES ((UINTN
)Next
- (UINTN
)First
) >= First
->NumberOfPages
260 if (TRUNCATE_TO_PAGES ((UINTN
)Next
- (UINTN
)First
) == First
->NumberOfPages
) {
261 First
->NumberOfPages
+= Next
->NumberOfPages
;
262 RemoveEntryList (&Next
->Link
);
270 Frees previous allocated pages.
272 @param Memory Base address of memory being freed.
273 @param NumberOfPages The number of pages to free.
275 @retval EFI_NOT_FOUND Could not find the entry that covers the range.
276 @retval EFI_INVALID_PARAMETER Address not aligned.
277 @return EFI_SUCCESS Pages successfully freed.
282 MmInternalFreePages (
283 IN EFI_PHYSICAL_ADDRESS Memory
,
284 IN UINTN NumberOfPages
288 FREE_PAGE_LIST
*Pages
;
290 if ((Memory
& EFI_PAGE_MASK
) != 0) {
291 return EFI_INVALID_PARAMETER
;
295 Node
= mMmMemoryMap
.ForwardLink
;
296 while (Node
!= &mMmMemoryMap
) {
297 Pages
= BASE_CR (Node
, FREE_PAGE_LIST
, Link
);
298 if (Memory
< (UINTN
)Pages
) {
302 Node
= Node
->ForwardLink
;
305 if ((Node
!= &mMmMemoryMap
) &&
306 (Memory
+ EFI_PAGES_TO_SIZE (NumberOfPages
) > (UINTN
)Pages
))
308 return EFI_INVALID_PARAMETER
;
311 if (Node
->BackLink
!= &mMmMemoryMap
) {
312 Pages
= BASE_CR (Node
->BackLink
, FREE_PAGE_LIST
, Link
);
313 if ((UINTN
)Pages
+ EFI_PAGES_TO_SIZE (Pages
->NumberOfPages
) > Memory
) {
314 return EFI_INVALID_PARAMETER
;
318 Pages
= (FREE_PAGE_LIST
*)(UINTN
)Memory
;
319 Pages
->NumberOfPages
= NumberOfPages
;
320 InsertTailList (Node
, &Pages
->Link
);
322 if (Pages
->Link
.BackLink
!= &mMmMemoryMap
) {
323 Pages
= InternalMergeNodes (
324 BASE_CR (Pages
->Link
.BackLink
, FREE_PAGE_LIST
, Link
)
328 if (Node
!= &mMmMemoryMap
) {
329 InternalMergeNodes (Pages
);
336 Frees previous allocated pages.
338 @param Memory Base address of memory being freed.
339 @param NumberOfPages The number of pages to free.
341 @retval EFI_NOT_FOUND Could not find the entry that covers the range.
342 @retval EFI_INVALID_PARAMETER Address not aligned.
343 @return EFI_SUCCESS Pages successfully freed.
349 IN EFI_PHYSICAL_ADDRESS Memory
,
350 IN UINTN NumberOfPages
355 Status
= MmInternalFreePages (Memory
, NumberOfPages
);
360 Add free MMRAM region for use by memory service.
362 @param MemBase Base address of memory region.
363 @param MemLength Length of the memory region.
364 @param Type Memory type.
365 @param Attributes Memory region state.
370 IN EFI_PHYSICAL_ADDRESS MemBase
,
372 IN EFI_MEMORY_TYPE Type
,
376 UINTN AlignedMemBase
;
379 // Do not add memory regions that is already allocated, needs testing, or needs ECC initialization
381 if ((Attributes
& (EFI_ALLOCATED
| EFI_NEEDS_TESTING
| EFI_NEEDS_ECC_INITIALIZATION
)) != 0) {
386 // Align range on an EFI_PAGE_SIZE boundary
388 AlignedMemBase
= (UINTN
)(MemBase
+ EFI_PAGE_MASK
) & ~EFI_PAGE_MASK
;
389 MemLength
-= AlignedMemBase
- MemBase
;
390 MmFreePages (AlignedMemBase
, TRUNCATE_TO_PAGES ((UINTN
)MemLength
));