microsoft/mu_feature_ffa

Public

mirrored fromhttps://github.com/microsoft/mu_feature_ffaAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
2d8ac10050d373d1c4b45aea63f17d763a4fc3f0

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

FfaFeaturePkg/Library/SecurePartitionMemoryAllocationLib/Page.c

399lines · modecode

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