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