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