]> git.proxmox.com Git - mirror_edk2.git/blob - StandaloneMmPkg/Core/Page.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / StandaloneMmPkg / Core / Page.c
1 /** @file
2 MM Memory page management functions.
3
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
7
8 **/
9
10 #include "StandaloneMmCore.h"
11
12 #define NEXT_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \
13 ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) + (Size)))
14
15 #define TRUNCATE_TO_PAGES(a) ((a) >> EFI_PAGE_SHIFT)
16
17 LIST_ENTRY mMmMemoryMap = INITIALIZE_LIST_HEAD_VARIABLE (mMmMemoryMap);
18
19 UINTN mMapKey;
20
21 /**
22 Internal Function. Allocate n pages from given free page node.
23
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.
27
28 @return Memory address of allocated pages.
29
30 **/
31 UINTN
32 InternalAllocPagesOnOneNode (
33 IN OUT FREE_PAGE_LIST *Pages,
34 IN UINTN NumberOfPages,
35 IN UINTN MaxAddress
36 )
37 {
38 UINTN Top;
39 UINTN Bottom;
40 FREE_PAGE_LIST *Node;
41
42 Top = TRUNCATE_TO_PAGES (MaxAddress + 1 - (UINTN)Pages);
43 if (Top > Pages->NumberOfPages) {
44 Top = Pages->NumberOfPages;
45 }
46
47 Bottom = Top - NumberOfPages;
48
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);
53 }
54
55 if (Bottom > 0) {
56 Pages->NumberOfPages = Bottom;
57 } else {
58 RemoveEntryList (&Pages->Link);
59 }
60
61 return (UINTN)Pages + EFI_PAGES_TO_SIZE (Bottom);
62 }
63
64 /**
65 Internal Function. Allocate n pages from free page list below MaxAddress.
66
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.
70
71 @return Memory address of allocated pages.
72
73 **/
74 UINTN
75 InternalAllocMaxAddress (
76 IN OUT LIST_ENTRY *FreePageList,
77 IN UINTN NumberOfPages,
78 IN UINTN MaxAddress
79 )
80 {
81 LIST_ENTRY *Node;
82 FREE_PAGE_LIST *Pages;
83
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))
88 {
89 return InternalAllocPagesOnOneNode (Pages, NumberOfPages, MaxAddress);
90 }
91 }
92
93 return (UINTN)(-1);
94 }
95
96 /**
97 Internal Function. Allocate n pages from free page list at given address.
98
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.
102
103 @return Memory address of allocated pages.
104
105 **/
106 UINTN
107 InternalAllocAddress (
108 IN OUT LIST_ENTRY *FreePageList,
109 IN UINTN NumberOfPages,
110 IN UINTN Address
111 )
112 {
113 UINTN EndAddress;
114 LIST_ENTRY *Node;
115 FREE_PAGE_LIST *Pages;
116
117 if ((Address & EFI_PAGE_MASK) != 0) {
118 return ~Address;
119 }
120
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) {
126 break;
127 }
128
129 return InternalAllocPagesOnOneNode (Pages, NumberOfPages, EndAddress);
130 }
131 }
132
133 return ~Address;
134 }
135
136 /**
137 Allocates pages from the memory map.
138
139 @param Type The type of allocation to perform.
140 @param MemoryType The type of memory to turn the allocated pages
141 into.
142 @param NumberOfPages The number of pages to allocate.
143 @param Memory A pointer to receive the base allocated memory
144 address.
145
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.
150
151 **/
152 EFI_STATUS
153 EFIAPI
154 MmInternalAllocatePages (
155 IN EFI_ALLOCATE_TYPE Type,
156 IN EFI_MEMORY_TYPE MemoryType,
157 IN UINTN NumberOfPages,
158 OUT EFI_PHYSICAL_ADDRESS *Memory
159 )
160 {
161 UINTN RequestedAddress;
162
163 if ((MemoryType != EfiRuntimeServicesCode) &&
164 (MemoryType != EfiRuntimeServicesData))
165 {
166 return EFI_INVALID_PARAMETER;
167 }
168
169 if (NumberOfPages > TRUNCATE_TO_PAGES ((UINTN)-1) + 1) {
170 return EFI_OUT_OF_RESOURCES;
171 }
172
173 //
174 // We don't track memory type in MM
175 //
176 RequestedAddress = (UINTN)*Memory;
177 switch (Type) {
178 case AllocateAnyPages:
179 RequestedAddress = (UINTN)(-1);
180 case AllocateMaxAddress:
181 *Memory = InternalAllocMaxAddress (
182 &mMmMemoryMap,
183 NumberOfPages,
184 RequestedAddress
185 );
186 if (*Memory == (UINTN)-1) {
187 return EFI_OUT_OF_RESOURCES;
188 }
189
190 break;
191 case AllocateAddress:
192 *Memory = InternalAllocAddress (
193 &mMmMemoryMap,
194 NumberOfPages,
195 RequestedAddress
196 );
197 if (*Memory != RequestedAddress) {
198 return EFI_NOT_FOUND;
199 }
200
201 break;
202 default:
203 return EFI_INVALID_PARAMETER;
204 }
205
206 return EFI_SUCCESS;
207 }
208
209 /**
210 Allocates pages from the memory map.
211
212 @param Type The type of allocation to perform.
213 @param MemoryType The type of memory to turn the allocated pages
214 into.
215 @param NumberOfPages The number of pages to allocate.
216 @param Memory A pointer to receive the base allocated memory
217 address.
218
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.
223
224 **/
225 EFI_STATUS
226 EFIAPI
227 MmAllocatePages (
228 IN EFI_ALLOCATE_TYPE Type,
229 IN EFI_MEMORY_TYPE MemoryType,
230 IN UINTN NumberOfPages,
231 OUT EFI_PHYSICAL_ADDRESS *Memory
232 )
233 {
234 EFI_STATUS Status;
235
236 Status = MmInternalAllocatePages (Type, MemoryType, NumberOfPages, Memory);
237 return Status;
238 }
239
240 /**
241 Internal Function. Merge two adjacent nodes.
242
243 @param First The first of two nodes to merge.
244
245 @return Pointer to node after merge (if success) or pointer to next node (if fail).
246
247 **/
248 FREE_PAGE_LIST *
249 InternalMergeNodes (
250 IN FREE_PAGE_LIST *First
251 )
252 {
253 FREE_PAGE_LIST *Next;
254
255 Next = BASE_CR (First->Link.ForwardLink, FREE_PAGE_LIST, Link);
256 ASSERT (
257 TRUNCATE_TO_PAGES ((UINTN)Next - (UINTN)First) >= First->NumberOfPages
258 );
259
260 if (TRUNCATE_TO_PAGES ((UINTN)Next - (UINTN)First) == First->NumberOfPages) {
261 First->NumberOfPages += Next->NumberOfPages;
262 RemoveEntryList (&Next->Link);
263 Next = First;
264 }
265
266 return Next;
267 }
268
269 /**
270 Frees previous allocated pages.
271
272 @param Memory Base address of memory being freed.
273 @param NumberOfPages The number of pages to free.
274
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.
278
279 **/
280 EFI_STATUS
281 EFIAPI
282 MmInternalFreePages (
283 IN EFI_PHYSICAL_ADDRESS Memory,
284 IN UINTN NumberOfPages
285 )
286 {
287 LIST_ENTRY *Node;
288 FREE_PAGE_LIST *Pages;
289
290 if ((Memory & EFI_PAGE_MASK) != 0) {
291 return EFI_INVALID_PARAMETER;
292 }
293
294 Pages = NULL;
295 Node = mMmMemoryMap.ForwardLink;
296 while (Node != &mMmMemoryMap) {
297 Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);
298 if (Memory < (UINTN)Pages) {
299 break;
300 }
301
302 Node = Node->ForwardLink;
303 }
304
305 if ((Node != &mMmMemoryMap) &&
306 (Memory + EFI_PAGES_TO_SIZE (NumberOfPages) > (UINTN)Pages))
307 {
308 return EFI_INVALID_PARAMETER;
309 }
310
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;
315 }
316 }
317
318 Pages = (FREE_PAGE_LIST *)(UINTN)Memory;
319 Pages->NumberOfPages = NumberOfPages;
320 InsertTailList (Node, &Pages->Link);
321
322 if (Pages->Link.BackLink != &mMmMemoryMap) {
323 Pages = InternalMergeNodes (
324 BASE_CR (Pages->Link.BackLink, FREE_PAGE_LIST, Link)
325 );
326 }
327
328 if (Node != &mMmMemoryMap) {
329 InternalMergeNodes (Pages);
330 }
331
332 return EFI_SUCCESS;
333 }
334
335 /**
336 Frees previous allocated pages.
337
338 @param Memory Base address of memory being freed.
339 @param NumberOfPages The number of pages to free.
340
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.
344
345 **/
346 EFI_STATUS
347 EFIAPI
348 MmFreePages (
349 IN EFI_PHYSICAL_ADDRESS Memory,
350 IN UINTN NumberOfPages
351 )
352 {
353 EFI_STATUS Status;
354
355 Status = MmInternalFreePages (Memory, NumberOfPages);
356 return Status;
357 }
358
359 /**
360 Add free MMRAM region for use by memory service.
361
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.
366
367 **/
368 VOID
369 MmAddMemoryRegion (
370 IN EFI_PHYSICAL_ADDRESS MemBase,
371 IN UINT64 MemLength,
372 IN EFI_MEMORY_TYPE Type,
373 IN UINT64 Attributes
374 )
375 {
376 UINTN AlignedMemBase;
377
378 //
379 // Do not add memory regions that is already allocated, needs testing, or needs ECC initialization
380 //
381 if ((Attributes & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {
382 return;
383 }
384
385 //
386 // Align range on an EFI_PAGE_SIZE boundary
387 //
388 AlignedMemBase = (UINTN)(MemBase + EFI_PAGE_MASK) & ~EFI_PAGE_MASK;
389 MemLength -= AlignedMemBase - MemBase;
390 MmFreePages (AlignedMemBase, TRUNCATE_TO_PAGES ((UINTN)MemLength));
391 }