microsoft/mu_feature_ffa

Public

mirrored from https://github.com/microsoft/mu_feature_ffaAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
update_rust

Branches

Tags

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

Clone

HTTPS

Download ZIP

FfaFeaturePkg/Library/SecurePartitionMemoryAllocationLib/Page.c

399lines · modeblame

734c30acKun Qin1 years ago1/** @file
2MM Memory page management functions.
3
4Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
5Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR>
6SPDX-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 {
16LIST_ENTRY Link;
17UINTN 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/**
30Internal 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 (
41IN OUT FREE_PAGE_LIST *Pages,
42IN UINTN NumberOfPages,
43IN UINTN MaxAddress
44)
45{
46UINTN Top;
47UINTN Bottom;
48FREE_PAGE_LIST *Node;
49
50Top = TRUNCATE_TO_PAGES (MaxAddress + 1 - (UINTN)Pages);
51if (Top > Pages->NumberOfPages) {
52Top = Pages->NumberOfPages;
53}
54
55Bottom = Top - NumberOfPages;
56
57if (Top < Pages->NumberOfPages) {
58Node = (FREE_PAGE_LIST *)((UINTN)Pages + EFI_PAGES_TO_SIZE (Top));
59Node->NumberOfPages = Pages->NumberOfPages - Top;
60InsertHeadList (&Pages->Link, &Node->Link);
61}
62
63if (Bottom > 0) {
64Pages->NumberOfPages = Bottom;
65} else {
66RemoveEntryList (&Pages->Link);
67}
68
69return (UINTN)Pages + EFI_PAGES_TO_SIZE (Bottom);
70}
71
72/**
73Internal 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 (
84IN OUT LIST_ENTRY *FreePageList,
85IN UINTN NumberOfPages,
86IN UINTN MaxAddress
87)
88{
89LIST_ENTRY *Node;
90FREE_PAGE_LIST *Pages;
91
92for (Node = FreePageList->BackLink; Node != FreePageList; Node = Node->BackLink) {
93Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);
94if ((Pages->NumberOfPages >= NumberOfPages) &&
95((UINTN)Pages + EFI_PAGES_TO_SIZE (NumberOfPages) - 1 <= MaxAddress))
96{
97return InternalAllocPagesOnOneNode (Pages, NumberOfPages, MaxAddress);
98}
99}
100
101return (UINTN)(-1);
102}
103
104/**
105Internal 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 (
116IN OUT LIST_ENTRY *FreePageList,
117IN UINTN NumberOfPages,
118IN UINTN Address
119)
120{
121UINTN EndAddress;
122LIST_ENTRY *Node;
123FREE_PAGE_LIST *Pages;
124
125if ((Address & EFI_PAGE_MASK) != 0) {
126return ~Address;
127}
128
129EndAddress = Address + EFI_PAGES_TO_SIZE (NumberOfPages);
130for (Node = FreePageList->BackLink; Node != FreePageList; Node = Node->BackLink) {
131Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);
132if ((UINTN)Pages <= Address) {
133if ((UINTN)Pages + EFI_PAGES_TO_SIZE (Pages->NumberOfPages) < EndAddress) {
134break;
135}
136
137return InternalAllocPagesOnOneNode (Pages, NumberOfPages, EndAddress);
138}
139}
140
141return ~Address;
142}
143
144/**
145Allocates 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
149into.
150@param NumberOfPages The number of pages to allocate.
151@param Memory A pointer to receive the base allocated memory
152address.
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 (
163IN EFI_ALLOCATE_TYPE Type,
164IN EFI_MEMORY_TYPE MemoryType,
165IN UINTN NumberOfPages,
166OUT EFI_PHYSICAL_ADDRESS *Memory
167)
168{
169UINTN RequestedAddress;
170
171if ((MemoryType != EfiRuntimeServicesCode) &&
172(MemoryType != EfiRuntimeServicesData))
173{
174return EFI_INVALID_PARAMETER;
175}
176
177if (NumberOfPages > TRUNCATE_TO_PAGES ((UINTN)-1) + 1) {
178return EFI_OUT_OF_RESOURCES;
179}
180
181//
182// We don't track memory type in MM
183//
184RequestedAddress = (UINTN)*Memory;
185switch (Type) {
186case AllocateAnyPages:
187RequestedAddress = (UINTN)(-1);
188case AllocateMaxAddress:
189*Memory = InternalAllocMaxAddress (
190&mMmMemoryMap,
191NumberOfPages,
192RequestedAddress
193);
194if (*Memory == (UINTN)-1) {
195return EFI_OUT_OF_RESOURCES;
196}
197
198break;
199case AllocateAddress:
200*Memory = InternalAllocAddress (
201&mMmMemoryMap,
202NumberOfPages,
203RequestedAddress
204);
205if (*Memory != RequestedAddress) {
206return EFI_NOT_FOUND;
207}
208
209break;
210default:
211return EFI_INVALID_PARAMETER;
212}
213
214return EFI_SUCCESS;
215}
216
217/**
218Allocates 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
222into.
223@param NumberOfPages The number of pages to allocate.
224@param Memory A pointer to receive the base allocated memory
225address.
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 (
236IN EFI_ALLOCATE_TYPE Type,
237IN EFI_MEMORY_TYPE MemoryType,
238IN UINTN NumberOfPages,
239OUT EFI_PHYSICAL_ADDRESS *Memory
240)
241{
242EFI_STATUS Status;
243
244Status = MmInternalAllocatePages (Type, MemoryType, NumberOfPages, Memory);
245return Status;
246}
247
248/**
249Internal 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 (
258IN FREE_PAGE_LIST *First
259)
260{
261FREE_PAGE_LIST *Next;
262
263Next = BASE_CR (First->Link.ForwardLink, FREE_PAGE_LIST, Link);
264ASSERT (
265TRUNCATE_TO_PAGES ((UINTN)Next - (UINTN)First) >= First->NumberOfPages
266);
267
268if (TRUNCATE_TO_PAGES ((UINTN)Next - (UINTN)First) == First->NumberOfPages) {
269First->NumberOfPages += Next->NumberOfPages;
270RemoveEntryList (&Next->Link);
271Next = First;
272}
273
274return Next;
275}
276
277/**
278Frees 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 (
291IN EFI_PHYSICAL_ADDRESS Memory,
292IN UINTN NumberOfPages
293)
294{
295LIST_ENTRY *Node;
296FREE_PAGE_LIST *Pages;
297
298if ((Memory & EFI_PAGE_MASK) != 0) {
299return EFI_INVALID_PARAMETER;
300}
301
302Pages = NULL;
303Node = mMmMemoryMap.ForwardLink;
304while (Node != &mMmMemoryMap) {
305Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);
306if (Memory < (UINTN)Pages) {
307break;
308}
309
310Node = Node->ForwardLink;
311}
312
313if ((Node != &mMmMemoryMap) &&
314(Memory + EFI_PAGES_TO_SIZE (NumberOfPages) > (UINTN)Pages))
315{
316return EFI_INVALID_PARAMETER;
317}
318
319if (Node->BackLink != &mMmMemoryMap) {
320Pages = BASE_CR (Node->BackLink, FREE_PAGE_LIST, Link);
321if ((UINTN)Pages + EFI_PAGES_TO_SIZE (Pages->NumberOfPages) > Memory) {
322return EFI_INVALID_PARAMETER;
323}
324}
325
326Pages = (FREE_PAGE_LIST *)(UINTN)Memory;
327Pages->NumberOfPages = NumberOfPages;
328InsertTailList (Node, &Pages->Link);
329
330if (Pages->Link.BackLink != &mMmMemoryMap) {
331Pages = InternalMergeNodes (
332BASE_CR (Pages->Link.BackLink, FREE_PAGE_LIST, Link)
333);
334}
335
336if (Node != &mMmMemoryMap) {
337InternalMergeNodes (Pages);
338}
339
340return EFI_SUCCESS;
341}
342
343/**
344Frees 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 (
357IN EFI_PHYSICAL_ADDRESS Memory,
358IN UINTN NumberOfPages
359)
360{
361EFI_STATUS Status;
362
363Status = MmInternalFreePages (Memory, NumberOfPages);
364return Status;
365}
366
367/**
368Add 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 (
378IN EFI_PHYSICAL_ADDRESS MemBase,
379IN UINT64 MemLength,
380IN EFI_MEMORY_TYPE Type,
381IN UINT64 Attributes
382)
383{
384UINTN AlignedMemBase;
385
386//
387// Do not add memory regions that is already allocated, needs testing, or needs ECC initialization
388//
389if ((Attributes & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {
390return;
391}
392
393//
394// Align range on an EFI_PAGE_SIZE boundary
395//
396AlignedMemBase = (UINTN)(MemBase + EFI_PAGE_MASK) & ~EFI_PAGE_MASK;
397MemLength -= AlignedMemBase - MemBase;
398MmFreePages (AlignedMemBase, TRUNCATE_TO_PAGES ((UINTN)MemLength));
399}