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