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