]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/PiSmmCore/Page.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Core / PiSmmCore / Page.c
1 /** @file
2 SMM Memory page management functions.
3
4 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "PiSmmCore.h"
10 #include <Library/SmmServicesTableLib.h>
11
12 #define TRUNCATE_TO_PAGES(a) ((a) >> EFI_PAGE_SHIFT)
13
14 LIST_ENTRY mSmmMemoryMap = INITIALIZE_LIST_HEAD_VARIABLE (mSmmMemoryMap);
15
16 //
17 // For GetMemoryMap()
18 //
19
20 #define MEMORY_MAP_SIGNATURE SIGNATURE_32('m','m','a','p')
21 typedef struct {
22 UINTN Signature;
23 LIST_ENTRY Link;
24
25 BOOLEAN FromStack;
26 EFI_MEMORY_TYPE Type;
27 UINT64 Start;
28 UINT64 End;
29 } MEMORY_MAP;
30
31 LIST_ENTRY gMemoryMap = INITIALIZE_LIST_HEAD_VARIABLE (gMemoryMap);
32
33 #define MAX_MAP_DEPTH 6
34
35 ///
36 /// mMapDepth - depth of new descriptor stack
37 ///
38 UINTN mMapDepth = 0;
39 ///
40 /// mMapStack - space to use as temp storage to build new map descriptors
41 ///
42 MEMORY_MAP mMapStack[MAX_MAP_DEPTH];
43 UINTN mFreeMapStack = 0;
44 ///
45 /// This list maintain the free memory map list
46 ///
47 LIST_ENTRY mFreeMemoryMapEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mFreeMemoryMapEntryList);
48
49 /**
50 Allocates pages from the memory map.
51
52 @param[in] Type The type of allocation to perform.
53 @param[in] MemoryType The type of memory to turn the allocated pages
54 into.
55 @param[in] NumberOfPages The number of pages to allocate.
56 @param[out] Memory A pointer to receive the base allocated memory
57 address.
58 @param[in] AddRegion If this memory is new added region.
59 @param[in] NeedGuard Flag to indicate Guard page is needed
60 or not
61
62 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.
63 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
64 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
65 @retval EFI_SUCCESS Pages successfully allocated.
66
67 **/
68 EFI_STATUS
69 SmmInternalAllocatePagesEx (
70 IN EFI_ALLOCATE_TYPE Type,
71 IN EFI_MEMORY_TYPE MemoryType,
72 IN UINTN NumberOfPages,
73 OUT EFI_PHYSICAL_ADDRESS *Memory,
74 IN BOOLEAN AddRegion,
75 IN BOOLEAN NeedGuard
76 );
77
78 /**
79 Internal function. Deque a descriptor entry from the mFreeMemoryMapEntryList.
80 If the list is emtry, then allocate a new page to refuel the list.
81 Please Note this algorithm to allocate the memory map descriptor has a property
82 that the memory allocated for memory entries always grows, and will never really be freed.
83
84 @return The Memory map descriptor dequeued from the mFreeMemoryMapEntryList
85
86 **/
87 MEMORY_MAP *
88 AllocateMemoryMapEntry (
89 VOID
90 )
91 {
92 EFI_PHYSICAL_ADDRESS Mem;
93 EFI_STATUS Status;
94 MEMORY_MAP *FreeDescriptorEntries;
95 MEMORY_MAP *Entry;
96 UINTN Index;
97
98 // DEBUG((DEBUG_INFO, "AllocateMemoryMapEntry\n"));
99
100 if (IsListEmpty (&mFreeMemoryMapEntryList)) {
101 // DEBUG((DEBUG_INFO, "mFreeMemoryMapEntryList is empty\n"));
102 //
103 // The list is empty, to allocate one page to refuel the list
104 //
105 Status = SmmInternalAllocatePagesEx (
106 AllocateAnyPages,
107 EfiRuntimeServicesData,
108 EFI_SIZE_TO_PAGES (RUNTIME_PAGE_ALLOCATION_GRANULARITY),
109 &Mem,
110 TRUE,
111 FALSE
112 );
113 ASSERT_EFI_ERROR (Status);
114 if (!EFI_ERROR (Status)) {
115 FreeDescriptorEntries = (MEMORY_MAP *)(UINTN)Mem;
116 // DEBUG((DEBUG_INFO, "New FreeDescriptorEntries - 0x%x\n", FreeDescriptorEntries));
117 //
118 // Enqueue the free memory map entries into the list
119 //
120 for (Index = 0; Index < RUNTIME_PAGE_ALLOCATION_GRANULARITY / sizeof (MEMORY_MAP); Index++) {
121 FreeDescriptorEntries[Index].Signature = MEMORY_MAP_SIGNATURE;
122 InsertTailList (&mFreeMemoryMapEntryList, &FreeDescriptorEntries[Index].Link);
123 }
124 } else {
125 return NULL;
126 }
127 }
128
129 //
130 // dequeue the first descriptor from the list
131 //
132 Entry = CR (mFreeMemoryMapEntryList.ForwardLink, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
133 RemoveEntryList (&Entry->Link);
134
135 return Entry;
136 }
137
138 /**
139 Internal function. Moves any memory descriptors that are on the
140 temporary descriptor stack to heap.
141
142 **/
143 VOID
144 CoreFreeMemoryMapStack (
145 VOID
146 )
147 {
148 MEMORY_MAP *Entry;
149
150 //
151 // If already freeing the map stack, then return
152 //
153 if (mFreeMapStack != 0) {
154 ASSERT (FALSE);
155 return;
156 }
157
158 //
159 // Move the temporary memory descriptor stack into pool
160 //
161 mFreeMapStack += 1;
162
163 while (mMapDepth != 0) {
164 //
165 // Deque an memory map entry from mFreeMemoryMapEntryList
166 //
167 Entry = AllocateMemoryMapEntry ();
168 ASSERT (Entry);
169
170 //
171 // Update to proper entry
172 //
173 mMapDepth -= 1;
174
175 if (mMapStack[mMapDepth].Link.ForwardLink != NULL) {
176 CopyMem (Entry, &mMapStack[mMapDepth], sizeof (MEMORY_MAP));
177 Entry->FromStack = FALSE;
178
179 //
180 // Move this entry to general memory
181 //
182 InsertTailList (&mMapStack[mMapDepth].Link, &Entry->Link);
183 RemoveEntryList (&mMapStack[mMapDepth].Link);
184 mMapStack[mMapDepth].Link.ForwardLink = NULL;
185 }
186 }
187
188 mFreeMapStack -= 1;
189 }
190
191 /**
192 Insert new entry from memory map.
193
194 @param[in] Link The old memory map entry to be linked.
195 @param[in] Start The start address of new memory map entry.
196 @param[in] End The end address of new memory map entry.
197 @param[in] Type The type of new memory map entry.
198 @param[in] Next If new entry is inserted to the next of old entry.
199 @param[in] AddRegion If this memory is new added region.
200 **/
201 VOID
202 InsertNewEntry (
203 IN LIST_ENTRY *Link,
204 IN UINT64 Start,
205 IN UINT64 End,
206 IN EFI_MEMORY_TYPE Type,
207 IN BOOLEAN Next,
208 IN BOOLEAN AddRegion
209 )
210 {
211 MEMORY_MAP *Entry;
212
213 Entry = &mMapStack[mMapDepth];
214 mMapDepth += 1;
215 ASSERT (mMapDepth < MAX_MAP_DEPTH);
216 Entry->FromStack = TRUE;
217
218 Entry->Signature = MEMORY_MAP_SIGNATURE;
219 Entry->Type = Type;
220 Entry->Start = Start;
221 Entry->End = End;
222 if (Next) {
223 InsertHeadList (Link, &Entry->Link);
224 } else {
225 InsertTailList (Link, &Entry->Link);
226 }
227 }
228
229 /**
230 Remove old entry from memory map.
231
232 @param[in] Entry Memory map entry to be removed.
233 **/
234 VOID
235 RemoveOldEntry (
236 IN MEMORY_MAP *Entry
237 )
238 {
239 RemoveEntryList (&Entry->Link);
240 Entry->Link.ForwardLink = NULL;
241
242 if (!Entry->FromStack) {
243 InsertTailList (&mFreeMemoryMapEntryList, &Entry->Link);
244 }
245 }
246
247 /**
248 Update SMM memory map entry.
249
250 @param[in] Type The type of allocation to perform.
251 @param[in] Memory The base of memory address.
252 @param[in] NumberOfPages The number of pages to allocate.
253 @param[in] AddRegion If this memory is new added region.
254 **/
255 VOID
256 ConvertSmmMemoryMapEntry (
257 IN EFI_MEMORY_TYPE Type,
258 IN EFI_PHYSICAL_ADDRESS Memory,
259 IN UINTN NumberOfPages,
260 IN BOOLEAN AddRegion
261 )
262 {
263 LIST_ENTRY *Link;
264 MEMORY_MAP *Entry;
265 MEMORY_MAP *NextEntry;
266 LIST_ENTRY *NextLink;
267 MEMORY_MAP *PreviousEntry;
268 LIST_ENTRY *PreviousLink;
269 EFI_PHYSICAL_ADDRESS Start;
270 EFI_PHYSICAL_ADDRESS End;
271
272 Start = Memory;
273 End = Memory + EFI_PAGES_TO_SIZE (NumberOfPages) - 1;
274
275 //
276 // Exclude memory region
277 //
278 Link = gMemoryMap.ForwardLink;
279 while (Link != &gMemoryMap) {
280 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
281 Link = Link->ForwardLink;
282
283 //
284 // ---------------------------------------------------
285 // | +----------+ +------+ +------+ +------+ |
286 // ---|gMemoryMep|---|Entry1|---|Entry2|---|Entry3|---
287 // +----------+ ^ +------+ +------+ +------+
288 // |
289 // +------+
290 // |EntryX|
291 // +------+
292 //
293 if (Entry->Start > End) {
294 if ((Entry->Start == End + 1) && (Entry->Type == Type)) {
295 Entry->Start = Start;
296 return;
297 }
298
299 InsertNewEntry (
300 &Entry->Link,
301 Start,
302 End,
303 Type,
304 FALSE,
305 AddRegion
306 );
307 return;
308 }
309
310 if ((Entry->Start <= Start) && (Entry->End >= End)) {
311 if (Entry->Type != Type) {
312 if (Entry->Start < Start) {
313 //
314 // ---------------------------------------------------
315 // | +----------+ +------+ +------+ +------+ |
316 // ---|gMemoryMep|---|Entry1|---|EntryX|---|Entry3|---
317 // +----------+ +------+ ^ +------+ +------+
318 // |
319 // +------+
320 // |EntryA|
321 // +------+
322 //
323 InsertNewEntry (
324 &Entry->Link,
325 Entry->Start,
326 Start - 1,
327 Entry->Type,
328 FALSE,
329 AddRegion
330 );
331 }
332
333 if (Entry->End > End) {
334 //
335 // ---------------------------------------------------
336 // | +----------+ +------+ +------+ +------+ |
337 // ---|gMemoryMep|---|Entry1|---|EntryX|---|Entry3|---
338 // +----------+ +------+ +------+ ^ +------+
339 // |
340 // +------+
341 // |EntryZ|
342 // +------+
343 //
344 InsertNewEntry (
345 &Entry->Link,
346 End + 1,
347 Entry->End,
348 Entry->Type,
349 TRUE,
350 AddRegion
351 );
352 }
353
354 //
355 // Update this node
356 //
357 Entry->Start = Start;
358 Entry->End = End;
359 Entry->Type = Type;
360
361 //
362 // Check adjacent
363 //
364 NextLink = Entry->Link.ForwardLink;
365 if (NextLink != &gMemoryMap) {
366 NextEntry = CR (NextLink, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
367 //
368 // ---------------------------------------------------
369 // | +----------+ +------+ +-----------------+ |
370 // ---|gMemoryMep|---|Entry1|---|EntryX Entry3|---
371 // +----------+ +------+ +-----------------+
372 //
373 if ((Entry->Type == NextEntry->Type) && (Entry->End + 1 == NextEntry->Start)) {
374 Entry->End = NextEntry->End;
375 RemoveOldEntry (NextEntry);
376 }
377 }
378
379 PreviousLink = Entry->Link.BackLink;
380 if (PreviousLink != &gMemoryMap) {
381 PreviousEntry = CR (PreviousLink, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
382 //
383 // ---------------------------------------------------
384 // | +----------+ +-----------------+ +------+ |
385 // ---|gMemoryMep|---|Entry1 EntryX|---|Entry3|---
386 // +----------+ +-----------------+ +------+
387 //
388 if ((PreviousEntry->Type == Entry->Type) && (PreviousEntry->End + 1 == Entry->Start)) {
389 PreviousEntry->End = Entry->End;
390 RemoveOldEntry (Entry);
391 }
392 }
393 }
394
395 return;
396 }
397 }
398
399 //
400 // ---------------------------------------------------
401 // | +----------+ +------+ +------+ +------+ |
402 // ---|gMemoryMep|---|Entry1|---|Entry2|---|Entry3|---
403 // +----------+ +------+ +------+ +------+ ^
404 // |
405 // +------+
406 // |EntryX|
407 // +------+
408 //
409 Link = gMemoryMap.BackLink;
410 if (Link != &gMemoryMap) {
411 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
412 if ((Entry->End + 1 == Start) && (Entry->Type == Type)) {
413 Entry->End = End;
414 return;
415 }
416 }
417
418 InsertNewEntry (
419 &gMemoryMap,
420 Start,
421 End,
422 Type,
423 FALSE,
424 AddRegion
425 );
426 return;
427 }
428
429 /**
430 Return the count of Smm memory map entry.
431
432 @return The count of Smm memory map entry.
433 **/
434 UINTN
435 GetSmmMemoryMapEntryCount (
436 VOID
437 )
438 {
439 LIST_ENTRY *Link;
440 UINTN Count;
441
442 Count = 0;
443 Link = gMemoryMap.ForwardLink;
444 while (Link != &gMemoryMap) {
445 Link = Link->ForwardLink;
446 Count++;
447 }
448
449 return Count;
450 }
451
452 /**
453 Internal Function. Allocate n pages from given free page node.
454
455 @param Pages The free page node.
456 @param NumberOfPages Number of pages to be allocated.
457 @param MaxAddress Request to allocate memory below this address.
458
459 @return Memory address of allocated pages.
460
461 **/
462 UINTN
463 InternalAllocPagesOnOneNode (
464 IN OUT FREE_PAGE_LIST *Pages,
465 IN UINTN NumberOfPages,
466 IN UINTN MaxAddress
467 )
468 {
469 UINTN Top;
470 UINTN Bottom;
471 FREE_PAGE_LIST *Node;
472
473 Top = TRUNCATE_TO_PAGES (MaxAddress + 1 - (UINTN)Pages);
474 if (Top > Pages->NumberOfPages) {
475 Top = Pages->NumberOfPages;
476 }
477
478 Bottom = Top - NumberOfPages;
479
480 if (Top < Pages->NumberOfPages) {
481 Node = (FREE_PAGE_LIST *)((UINTN)Pages + EFI_PAGES_TO_SIZE (Top));
482 Node->NumberOfPages = Pages->NumberOfPages - Top;
483 InsertHeadList (&Pages->Link, &Node->Link);
484 }
485
486 if (Bottom > 0) {
487 Pages->NumberOfPages = Bottom;
488 } else {
489 RemoveEntryList (&Pages->Link);
490 }
491
492 return (UINTN)Pages + EFI_PAGES_TO_SIZE (Bottom);
493 }
494
495 /**
496 Internal Function. Allocate n pages from free page list below MaxAddress.
497
498 @param FreePageList The free page node.
499 @param NumberOfPages Number of pages to be allocated.
500 @param MaxAddress Request to allocate memory below this address.
501
502 @return Memory address of allocated pages.
503
504 **/
505 UINTN
506 InternalAllocMaxAddress (
507 IN OUT LIST_ENTRY *FreePageList,
508 IN UINTN NumberOfPages,
509 IN UINTN MaxAddress
510 )
511 {
512 LIST_ENTRY *Node;
513 FREE_PAGE_LIST *Pages;
514
515 for (Node = FreePageList->BackLink; Node != FreePageList; Node = Node->BackLink) {
516 Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);
517 if ((Pages->NumberOfPages >= NumberOfPages) &&
518 ((UINTN)Pages + EFI_PAGES_TO_SIZE (NumberOfPages) - 1 <= MaxAddress))
519 {
520 return InternalAllocPagesOnOneNode (Pages, NumberOfPages, MaxAddress);
521 }
522 }
523
524 return (UINTN)(-1);
525 }
526
527 /**
528 Internal Function. Allocate n pages from free page list at given address.
529
530 @param FreePageList The free page node.
531 @param NumberOfPages Number of pages to be allocated.
532 @param MaxAddress Request to allocate memory below this address.
533
534 @return Memory address of allocated pages.
535
536 **/
537 UINTN
538 InternalAllocAddress (
539 IN OUT LIST_ENTRY *FreePageList,
540 IN UINTN NumberOfPages,
541 IN UINTN Address
542 )
543 {
544 UINTN EndAddress;
545 LIST_ENTRY *Node;
546 FREE_PAGE_LIST *Pages;
547
548 if ((Address & EFI_PAGE_MASK) != 0) {
549 return ~Address;
550 }
551
552 EndAddress = Address + EFI_PAGES_TO_SIZE (NumberOfPages);
553 for (Node = FreePageList->BackLink; Node != FreePageList; Node = Node->BackLink) {
554 Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);
555 if ((UINTN)Pages <= Address) {
556 if ((UINTN)Pages + EFI_PAGES_TO_SIZE (Pages->NumberOfPages) < EndAddress) {
557 break;
558 }
559
560 return InternalAllocPagesOnOneNode (Pages, NumberOfPages, EndAddress);
561 }
562 }
563
564 return ~Address;
565 }
566
567 /**
568 Allocates pages from the memory map.
569
570 @param[in] Type The type of allocation to perform.
571 @param[in] MemoryType The type of memory to turn the allocated pages
572 into.
573 @param[in] NumberOfPages The number of pages to allocate.
574 @param[out] Memory A pointer to receive the base allocated memory
575 address.
576 @param[in] AddRegion If this memory is new added region.
577 @param[in] NeedGuard Flag to indicate Guard page is needed
578 or not
579
580 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.
581 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
582 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
583 @retval EFI_SUCCESS Pages successfully allocated.
584
585 **/
586 EFI_STATUS
587 SmmInternalAllocatePagesEx (
588 IN EFI_ALLOCATE_TYPE Type,
589 IN EFI_MEMORY_TYPE MemoryType,
590 IN UINTN NumberOfPages,
591 OUT EFI_PHYSICAL_ADDRESS *Memory,
592 IN BOOLEAN AddRegion,
593 IN BOOLEAN NeedGuard
594 )
595 {
596 UINTN RequestedAddress;
597
598 if ((MemoryType != EfiRuntimeServicesCode) &&
599 (MemoryType != EfiRuntimeServicesData))
600 {
601 return EFI_INVALID_PARAMETER;
602 }
603
604 if (NumberOfPages > TRUNCATE_TO_PAGES ((UINTN)-1) + 1) {
605 return EFI_OUT_OF_RESOURCES;
606 }
607
608 //
609 // We don't track memory type in SMM
610 //
611 RequestedAddress = (UINTN)*Memory;
612 switch (Type) {
613 case AllocateAnyPages:
614 RequestedAddress = (UINTN)(-1);
615 case AllocateMaxAddress:
616 if (NeedGuard) {
617 *Memory = InternalAllocMaxAddressWithGuard (
618 &mSmmMemoryMap,
619 NumberOfPages,
620 RequestedAddress,
621 MemoryType
622 );
623 if (*Memory == (UINTN)-1) {
624 return EFI_OUT_OF_RESOURCES;
625 } else {
626 ASSERT (VerifyMemoryGuard (*Memory, NumberOfPages) == TRUE);
627 return EFI_SUCCESS;
628 }
629 }
630
631 *Memory = InternalAllocMaxAddress (
632 &mSmmMemoryMap,
633 NumberOfPages,
634 RequestedAddress
635 );
636 if (*Memory == (UINTN)-1) {
637 return EFI_OUT_OF_RESOURCES;
638 }
639
640 break;
641 case AllocateAddress:
642 *Memory = InternalAllocAddress (
643 &mSmmMemoryMap,
644 NumberOfPages,
645 RequestedAddress
646 );
647 if (*Memory != RequestedAddress) {
648 return EFI_NOT_FOUND;
649 }
650
651 break;
652 default:
653 return EFI_INVALID_PARAMETER;
654 }
655
656 //
657 // Update SmmMemoryMap here.
658 //
659 ConvertSmmMemoryMapEntry (MemoryType, *Memory, NumberOfPages, AddRegion);
660 if (!AddRegion) {
661 CoreFreeMemoryMapStack ();
662 }
663
664 return EFI_SUCCESS;
665 }
666
667 /**
668 Allocates pages from the memory map.
669
670 @param[in] Type The type of allocation to perform.
671 @param[in] MemoryType The type of memory to turn the allocated pages
672 into.
673 @param[in] NumberOfPages The number of pages to allocate.
674 @param[out] Memory A pointer to receive the base allocated memory
675 address.
676 @param[in] NeedGuard Flag to indicate Guard page is needed
677 or not
678
679 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.
680 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
681 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
682 @retval EFI_SUCCESS Pages successfully allocated.
683
684 **/
685 EFI_STATUS
686 EFIAPI
687 SmmInternalAllocatePages (
688 IN EFI_ALLOCATE_TYPE Type,
689 IN EFI_MEMORY_TYPE MemoryType,
690 IN UINTN NumberOfPages,
691 OUT EFI_PHYSICAL_ADDRESS *Memory,
692 IN BOOLEAN NeedGuard
693 )
694 {
695 return SmmInternalAllocatePagesEx (
696 Type,
697 MemoryType,
698 NumberOfPages,
699 Memory,
700 FALSE,
701 NeedGuard
702 );
703 }
704
705 /**
706 Allocates pages from the memory map.
707
708 @param Type The type of allocation to perform.
709 @param MemoryType The type of memory to turn the allocated pages
710 into.
711 @param NumberOfPages The number of pages to allocate.
712 @param Memory A pointer to receive the base allocated memory
713 address.
714
715 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.
716 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
717 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
718 @retval EFI_SUCCESS Pages successfully allocated.
719
720 **/
721 EFI_STATUS
722 EFIAPI
723 SmmAllocatePages (
724 IN EFI_ALLOCATE_TYPE Type,
725 IN EFI_MEMORY_TYPE MemoryType,
726 IN UINTN NumberOfPages,
727 OUT EFI_PHYSICAL_ADDRESS *Memory
728 )
729 {
730 EFI_STATUS Status;
731 BOOLEAN NeedGuard;
732
733 NeedGuard = IsPageTypeToGuard (MemoryType, Type);
734 Status = SmmInternalAllocatePages (
735 Type,
736 MemoryType,
737 NumberOfPages,
738 Memory,
739 NeedGuard
740 );
741 if (!EFI_ERROR (Status)) {
742 SmmCoreUpdateProfile (
743 (EFI_PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),
744 MemoryProfileActionAllocatePages,
745 MemoryType,
746 EFI_PAGES_TO_SIZE (NumberOfPages),
747 (VOID *)(UINTN)*Memory,
748 NULL
749 );
750 }
751
752 return Status;
753 }
754
755 /**
756 Internal Function. Merge two adjacent nodes.
757
758 @param First The first of two nodes to merge.
759
760 @return Pointer to node after merge (if success) or pointer to next node (if fail).
761
762 **/
763 FREE_PAGE_LIST *
764 InternalMergeNodes (
765 IN FREE_PAGE_LIST *First
766 )
767 {
768 FREE_PAGE_LIST *Next;
769
770 Next = BASE_CR (First->Link.ForwardLink, FREE_PAGE_LIST, Link);
771 ASSERT (
772 TRUNCATE_TO_PAGES ((UINTN)Next - (UINTN)First) >= First->NumberOfPages
773 );
774
775 if (TRUNCATE_TO_PAGES ((UINTN)Next - (UINTN)First) == First->NumberOfPages) {
776 First->NumberOfPages += Next->NumberOfPages;
777 RemoveEntryList (&Next->Link);
778 Next = First;
779 }
780
781 return Next;
782 }
783
784 /**
785 Frees previous allocated pages.
786
787 @param[in] Memory Base address of memory being freed.
788 @param[in] NumberOfPages The number of pages to free.
789 @param[in] AddRegion If this memory is new added region.
790
791 @retval EFI_NOT_FOUND Could not find the entry that covers the range.
792 @retval EFI_INVALID_PARAMETER Address not aligned, Address is zero or NumberOfPages is zero.
793 @return EFI_SUCCESS Pages successfully freed.
794
795 **/
796 EFI_STATUS
797 SmmInternalFreePagesEx (
798 IN EFI_PHYSICAL_ADDRESS Memory,
799 IN UINTN NumberOfPages,
800 IN BOOLEAN AddRegion
801 )
802 {
803 LIST_ENTRY *Node;
804 FREE_PAGE_LIST *Pages;
805
806 if (((Memory & EFI_PAGE_MASK) != 0) || (Memory == 0) || (NumberOfPages == 0)) {
807 return EFI_INVALID_PARAMETER;
808 }
809
810 Pages = NULL;
811 Node = mSmmMemoryMap.ForwardLink;
812 while (Node != &mSmmMemoryMap) {
813 Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);
814 if (Memory < (UINTN)Pages) {
815 break;
816 }
817
818 Node = Node->ForwardLink;
819 }
820
821 if ((Node != &mSmmMemoryMap) &&
822 (Memory + EFI_PAGES_TO_SIZE (NumberOfPages) > (UINTN)Pages))
823 {
824 return EFI_INVALID_PARAMETER;
825 }
826
827 if (Node->BackLink != &mSmmMemoryMap) {
828 Pages = BASE_CR (Node->BackLink, FREE_PAGE_LIST, Link);
829 if ((UINTN)Pages + EFI_PAGES_TO_SIZE (Pages->NumberOfPages) > Memory) {
830 return EFI_INVALID_PARAMETER;
831 }
832 }
833
834 Pages = (FREE_PAGE_LIST *)(UINTN)Memory;
835 Pages->NumberOfPages = NumberOfPages;
836 InsertTailList (Node, &Pages->Link);
837
838 if (Pages->Link.BackLink != &mSmmMemoryMap) {
839 Pages = InternalMergeNodes (
840 BASE_CR (Pages->Link.BackLink, FREE_PAGE_LIST, Link)
841 );
842 }
843
844 if (Node != &mSmmMemoryMap) {
845 InternalMergeNodes (Pages);
846 }
847
848 //
849 // Update SmmMemoryMap here.
850 //
851 ConvertSmmMemoryMapEntry (EfiConventionalMemory, Memory, NumberOfPages, AddRegion);
852 if (!AddRegion) {
853 CoreFreeMemoryMapStack ();
854 }
855
856 return EFI_SUCCESS;
857 }
858
859 /**
860 Frees previous allocated pages.
861
862 @param[in] Memory Base address of memory being freed.
863 @param[in] NumberOfPages The number of pages to free.
864 @param[in] IsGuarded Is the memory to free guarded or not.
865
866 @retval EFI_NOT_FOUND Could not find the entry that covers the range.
867 @retval EFI_INVALID_PARAMETER Address not aligned, Address is zero or NumberOfPages is zero.
868 @return EFI_SUCCESS Pages successfully freed.
869
870 **/
871 EFI_STATUS
872 EFIAPI
873 SmmInternalFreePages (
874 IN EFI_PHYSICAL_ADDRESS Memory,
875 IN UINTN NumberOfPages,
876 IN BOOLEAN IsGuarded
877 )
878 {
879 if (IsGuarded) {
880 return SmmInternalFreePagesExWithGuard (Memory, NumberOfPages, FALSE);
881 }
882
883 return SmmInternalFreePagesEx (Memory, NumberOfPages, FALSE);
884 }
885
886 /**
887 Check whether the input range is in memory map.
888
889 @param Memory Base address of memory being inputed.
890 @param NumberOfPages The number of pages.
891
892 @retval TRUE In memory map.
893 @retval FALSE Not in memory map.
894
895 **/
896 BOOLEAN
897 InMemMap (
898 IN EFI_PHYSICAL_ADDRESS Memory,
899 IN UINTN NumberOfPages
900 )
901 {
902 LIST_ENTRY *Link;
903 MEMORY_MAP *Entry;
904 EFI_PHYSICAL_ADDRESS Last;
905
906 Last = Memory + EFI_PAGES_TO_SIZE (NumberOfPages) - 1;
907
908 Link = gMemoryMap.ForwardLink;
909 while (Link != &gMemoryMap) {
910 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
911 Link = Link->ForwardLink;
912
913 if ((Entry->Start <= Memory) && (Entry->End >= Last)) {
914 return TRUE;
915 }
916 }
917
918 return FALSE;
919 }
920
921 /**
922 Frees previous allocated pages.
923
924 @param Memory Base address of memory being freed.
925 @param NumberOfPages The number of pages to free.
926
927 @retval EFI_NOT_FOUND Could not find the entry that covers the range.
928 @retval EFI_INVALID_PARAMETER Address not aligned, Address is zero or NumberOfPages is zero.
929 @return EFI_SUCCESS Pages successfully freed.
930
931 **/
932 EFI_STATUS
933 EFIAPI
934 SmmFreePages (
935 IN EFI_PHYSICAL_ADDRESS Memory,
936 IN UINTN NumberOfPages
937 )
938 {
939 EFI_STATUS Status;
940 BOOLEAN IsGuarded;
941
942 if (!InMemMap (Memory, NumberOfPages)) {
943 return EFI_NOT_FOUND;
944 }
945
946 IsGuarded = IsHeapGuardEnabled () && IsMemoryGuarded (Memory);
947 Status = SmmInternalFreePages (Memory, NumberOfPages, IsGuarded);
948 if (!EFI_ERROR (Status)) {
949 SmmCoreUpdateProfile (
950 (EFI_PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),
951 MemoryProfileActionFreePages,
952 EfiMaxMemoryType,
953 EFI_PAGES_TO_SIZE (NumberOfPages),
954 (VOID *)(UINTN)Memory,
955 NULL
956 );
957 }
958
959 return Status;
960 }
961
962 /**
963 Add free SMRAM region for use by memory service.
964
965 @param MemBase Base address of memory region.
966 @param MemLength Length of the memory region.
967 @param Type Memory type.
968 @param Attributes Memory region state.
969
970 **/
971 VOID
972 SmmAddMemoryRegion (
973 IN EFI_PHYSICAL_ADDRESS MemBase,
974 IN UINT64 MemLength,
975 IN EFI_MEMORY_TYPE Type,
976 IN UINT64 Attributes
977 )
978 {
979 UINTN AlignedMemBase;
980
981 //
982 // Add EfiRuntimeServicesData for memory regions that is already allocated, needs testing, or needs ECC initialization
983 //
984 if ((Attributes & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {
985 Type = EfiRuntimeServicesData;
986 } else {
987 Type = EfiConventionalMemory;
988 }
989
990 DEBUG ((DEBUG_INFO, "SmmAddMemoryRegion\n"));
991 DEBUG ((DEBUG_INFO, " MemBase - 0x%lx\n", MemBase));
992 DEBUG ((DEBUG_INFO, " MemLength - 0x%lx\n", MemLength));
993 DEBUG ((DEBUG_INFO, " Type - 0x%x\n", Type));
994 DEBUG ((DEBUG_INFO, " Attributes - 0x%lx\n", Attributes));
995
996 //
997 // Align range on an EFI_PAGE_SIZE boundary
998 //
999 AlignedMemBase = (UINTN)(MemBase + EFI_PAGE_MASK) & ~EFI_PAGE_MASK;
1000 MemLength -= AlignedMemBase - MemBase;
1001 if (Type == EfiConventionalMemory) {
1002 SmmInternalFreePagesEx (AlignedMemBase, TRUNCATE_TO_PAGES ((UINTN)MemLength), TRUE);
1003 } else {
1004 ConvertSmmMemoryMapEntry (EfiRuntimeServicesData, AlignedMemBase, TRUNCATE_TO_PAGES ((UINTN)MemLength), TRUE);
1005 }
1006
1007 CoreFreeMemoryMapStack ();
1008 }
1009
1010 /**
1011 This function returns a copy of the current memory map. The map is an array of
1012 memory descriptors, each of which describes a contiguous block of memory.
1013
1014 @param[in, out] MemoryMapSize A pointer to the size, in bytes, of the
1015 MemoryMap buffer. On input, this is the size of
1016 the buffer allocated by the caller. On output,
1017 it is the size of the buffer returned by the
1018 firmware if the buffer was large enough, or the
1019 size of the buffer needed to contain the map if
1020 the buffer was too small.
1021 @param[in, out] MemoryMap A pointer to the buffer in which firmware places
1022 the current memory map.
1023 @param[out] MapKey A pointer to the location in which firmware
1024 returns the key for the current memory map.
1025 @param[out] DescriptorSize A pointer to the location in which firmware
1026 returns the size, in bytes, of an individual
1027 EFI_MEMORY_DESCRIPTOR.
1028 @param[out] DescriptorVersion A pointer to the location in which firmware
1029 returns the version number associated with the
1030 EFI_MEMORY_DESCRIPTOR.
1031
1032 @retval EFI_SUCCESS The memory map was returned in the MemoryMap
1033 buffer.
1034 @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current
1035 buffer size needed to hold the memory map is
1036 returned in MemoryMapSize.
1037 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
1038
1039 **/
1040 EFI_STATUS
1041 EFIAPI
1042 SmmCoreGetMemoryMap (
1043 IN OUT UINTN *MemoryMapSize,
1044 IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
1045 OUT UINTN *MapKey,
1046 OUT UINTN *DescriptorSize,
1047 OUT UINT32 *DescriptorVersion
1048 )
1049 {
1050 UINTN Count;
1051 LIST_ENTRY *Link;
1052 MEMORY_MAP *Entry;
1053 UINTN Size;
1054 UINTN BufferSize;
1055
1056 Size = sizeof (EFI_MEMORY_DESCRIPTOR);
1057
1058 //
1059 // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will
1060 // prevent people from having pointer math bugs in their code.
1061 // now you have to use *DescriptorSize to make things work.
1062 //
1063 Size += sizeof (UINT64) - (Size % sizeof (UINT64));
1064
1065 if (DescriptorSize != NULL) {
1066 *DescriptorSize = Size;
1067 }
1068
1069 if (DescriptorVersion != NULL) {
1070 *DescriptorVersion = EFI_MEMORY_DESCRIPTOR_VERSION;
1071 }
1072
1073 Count = GetSmmMemoryMapEntryCount ();
1074 BufferSize = Size * Count;
1075 if (*MemoryMapSize < BufferSize) {
1076 *MemoryMapSize = BufferSize;
1077 return EFI_BUFFER_TOO_SMALL;
1078 }
1079
1080 *MemoryMapSize = BufferSize;
1081 if (MemoryMap == NULL) {
1082 return EFI_INVALID_PARAMETER;
1083 }
1084
1085 ZeroMem (MemoryMap, BufferSize);
1086 Link = gMemoryMap.ForwardLink;
1087 while (Link != &gMemoryMap) {
1088 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
1089 Link = Link->ForwardLink;
1090
1091 MemoryMap->Type = Entry->Type;
1092 MemoryMap->PhysicalStart = Entry->Start;
1093 MemoryMap->NumberOfPages = RShiftU64 (Entry->End - Entry->Start + 1, EFI_PAGE_SHIFT);
1094
1095 MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, Size);
1096 }
1097
1098 return EFI_SUCCESS;
1099 }