8909d46a00a2170907c437f959a17b9a531f35d8
[mirror_edk2.git] / MdeModulePkg / Core / PiSmmCore / Page.c
1 /** @file
2 SMM Memory page management functions.
3
4 Copyright (c) 2009 - 2016, 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 if (!Entry->FromStack) {
250 InsertTailList (&mFreeMemoryMapEntryList, &Entry->Link);
251 }
252 }
253
254 /**
255 Update SMM memory map entry.
256
257 @param[in] Type The type of allocation to perform.
258 @param[in] Memory The base of memory address.
259 @param[in] NumberOfPages The number of pages to allocate.
260 @param[in] AddRegion If this memory is new added region.
261 **/
262 VOID
263 ConvertSmmMemoryMapEntry (
264 IN EFI_MEMORY_TYPE Type,
265 IN EFI_PHYSICAL_ADDRESS Memory,
266 IN UINTN NumberOfPages,
267 IN BOOLEAN AddRegion
268 )
269 {
270 LIST_ENTRY *Link;
271 MEMORY_MAP *Entry;
272 MEMORY_MAP *NextEntry;
273 LIST_ENTRY *NextLink;
274 MEMORY_MAP *PreviousEntry;
275 LIST_ENTRY *PreviousLink;
276 EFI_PHYSICAL_ADDRESS Start;
277 EFI_PHYSICAL_ADDRESS End;
278
279 Start = Memory;
280 End = Memory + EFI_PAGES_TO_SIZE(NumberOfPages) - 1;
281
282 //
283 // Exclude memory region
284 //
285 Link = gMemoryMap.ForwardLink;
286 while (Link != &gMemoryMap) {
287 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
288 Link = Link->ForwardLink;
289
290 //
291 // ---------------------------------------------------
292 // | +----------+ +------+ +------+ +------+ |
293 // ---|gMemoryMep|---|Entry1|---|Entry2|---|Entry3|---
294 // +----------+ ^ +------+ +------+ +------+
295 // |
296 // +------+
297 // |EntryX|
298 // +------+
299 //
300 if (Entry->Start > End) {
301 if ((Entry->Start == End + 1) && (Entry->Type == Type)) {
302 Entry->Start = Start;
303 return ;
304 }
305 InsertNewEntry (
306 &Entry->Link,
307 Start,
308 End,
309 Type,
310 FALSE,
311 AddRegion
312 );
313 return ;
314 }
315
316 if ((Entry->Start <= Start) && (Entry->End >= End)) {
317 if (Entry->Type != Type) {
318 if (Entry->Start < Start) {
319 //
320 // ---------------------------------------------------
321 // | +----------+ +------+ +------+ +------+ |
322 // ---|gMemoryMep|---|Entry1|---|EntryX|---|Entry3|---
323 // +----------+ +------+ ^ +------+ +------+
324 // |
325 // +------+
326 // |EntryA|
327 // +------+
328 //
329 InsertNewEntry (
330 &Entry->Link,
331 Entry->Start,
332 Start - 1,
333 Entry->Type,
334 FALSE,
335 AddRegion
336 );
337 }
338 if (Entry->End > End) {
339 //
340 // ---------------------------------------------------
341 // | +----------+ +------+ +------+ +------+ |
342 // ---|gMemoryMep|---|Entry1|---|EntryX|---|Entry3|---
343 // +----------+ +------+ +------+ ^ +------+
344 // |
345 // +------+
346 // |EntryZ|
347 // +------+
348 //
349 InsertNewEntry (
350 &Entry->Link,
351 End + 1,
352 Entry->End,
353 Entry->Type,
354 TRUE,
355 AddRegion
356 );
357 }
358 //
359 // Update this node
360 //
361 Entry->Start = Start;
362 Entry->End = End;
363 Entry->Type = Type;
364
365 //
366 // Check adjacent
367 //
368 NextLink = Entry->Link.ForwardLink;
369 if (NextLink != &gMemoryMap) {
370 NextEntry = CR (NextLink, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
371 //
372 // ---------------------------------------------------
373 // | +----------+ +------+ +-----------------+ |
374 // ---|gMemoryMep|---|Entry1|---|EntryX Entry3|---
375 // +----------+ +------+ +-----------------+
376 //
377 if ((Entry->Type == NextEntry->Type) && (Entry->End + 1 == NextEntry->Start)) {
378 Entry->End = NextEntry->End;
379 RemoveOldEntry (NextEntry);
380 }
381 }
382 PreviousLink = Entry->Link.BackLink;
383 if (PreviousLink != &gMemoryMap) {
384 PreviousEntry = CR (PreviousLink, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
385 //
386 // ---------------------------------------------------
387 // | +----------+ +-----------------+ +------+ |
388 // ---|gMemoryMep|---|Entry1 EntryX|---|Entry3|---
389 // +----------+ +-----------------+ +------+
390 //
391 if ((PreviousEntry->Type == Entry->Type) && (PreviousEntry->End + 1 == Entry->Start)) {
392 PreviousEntry->End = Entry->End;
393 RemoveOldEntry (Entry);
394 }
395 }
396 }
397 return ;
398 }
399 }
400
401 //
402 // ---------------------------------------------------
403 // | +----------+ +------+ +------+ +------+ |
404 // ---|gMemoryMep|---|Entry1|---|Entry2|---|Entry3|---
405 // +----------+ +------+ +------+ +------+ ^
406 // |
407 // +------+
408 // |EntryX|
409 // +------+
410 //
411 Link = gMemoryMap.BackLink;
412 if (Link != &gMemoryMap) {
413 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
414 if ((Entry->End + 1 == Start) && (Entry->Type == Type)) {
415 Entry->End = End;
416 return ;
417 }
418 }
419 InsertNewEntry (
420 &gMemoryMap,
421 Start,
422 End,
423 Type,
424 FALSE,
425 AddRegion
426 );
427 return ;
428 }
429
430 /**
431 Return the count of Smm memory map entry.
432
433 @return The count of Smm memory map entry.
434 **/
435 UINTN
436 GetSmmMemoryMapEntryCount (
437 VOID
438 )
439 {
440 LIST_ENTRY *Link;
441 UINTN Count;
442
443 Count = 0;
444 Link = gMemoryMap.ForwardLink;
445 while (Link != &gMemoryMap) {
446 Link = Link->ForwardLink;
447 Count++;
448 }
449 return Count;
450 }
451
452 /**
453 Dump Smm memory map entry.
454 **/
455 VOID
456 DumpSmmMemoryMapEntry (
457 VOID
458 )
459 {
460 LIST_ENTRY *Link;
461 MEMORY_MAP *Entry;
462 EFI_PHYSICAL_ADDRESS Last;
463
464 Last = 0;
465 DEBUG ((DEBUG_INFO, "DumpSmmMemoryMapEntry:\n"));
466 Link = gMemoryMap.ForwardLink;
467 while (Link != &gMemoryMap) {
468 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
469 Link = Link->ForwardLink;
470
471 if ((Last != 0) && (Last != (UINT64)-1)) {
472 if (Last + 1 != Entry->Start) {
473 Last = (UINT64)-1;
474 } else {
475 Last = Entry->End;
476 }
477 } else if (Last == 0) {
478 Last = Entry->End;
479 }
480
481 DEBUG ((DEBUG_INFO, "Entry (Link - 0x%x)\n", &Entry->Link));
482 DEBUG ((DEBUG_INFO, " Signature - 0x%x\n", Entry->Signature));
483 DEBUG ((DEBUG_INFO, " Link.ForwardLink - 0x%x\n", Entry->Link.ForwardLink));
484 DEBUG ((DEBUG_INFO, " Link.BackLink - 0x%x\n", Entry->Link.BackLink));
485 DEBUG ((DEBUG_INFO, " Type - 0x%x\n", Entry->Type));
486 DEBUG ((DEBUG_INFO, " Start - 0x%016lx\n", Entry->Start));
487 DEBUG ((DEBUG_INFO, " End - 0x%016lx\n", Entry->End));
488 }
489
490 ASSERT (Last != (UINT64)-1);
491 }
492
493 /**
494 Dump Smm memory map.
495 **/
496 VOID
497 DumpSmmMemoryMap (
498 VOID
499 )
500 {
501 LIST_ENTRY *Node;
502 FREE_PAGE_LIST *Pages;
503
504 DEBUG ((DEBUG_INFO, "DumpSmmMemoryMap\n"));
505
506 Pages = NULL;
507 Node = mSmmMemoryMap.ForwardLink;
508 while (Node != &mSmmMemoryMap) {
509 Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);
510 DEBUG ((DEBUG_INFO, "Pages - 0x%x\n", Pages));
511 DEBUG ((DEBUG_INFO, "Pages->NumberOfPages - 0x%x\n", Pages->NumberOfPages));
512 Node = Node->ForwardLink;
513 }
514 }
515
516 /**
517 Check if a Smm base~length is in Smm memory map.
518
519 @param[in] Base The base address of Smm memory to be checked.
520 @param[in] Length THe length of Smm memory to be checked.
521
522 @retval TRUE Smm base~length is in smm memory map.
523 @retval FALSE Smm base~length is in smm memory map.
524 **/
525 BOOLEAN
526 SmmMemoryMapConsistencyCheckRange (
527 IN EFI_PHYSICAL_ADDRESS Base,
528 IN UINTN Length
529 )
530 {
531 LIST_ENTRY *Link;
532 MEMORY_MAP *Entry;
533 BOOLEAN Result;
534
535 Result = FALSE;
536 Link = gMemoryMap.ForwardLink;
537 while (Link != &gMemoryMap) {
538 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
539 Link = Link->ForwardLink;
540
541 if (Entry->Type != EfiConventionalMemory) {
542 continue;
543 }
544 if (Entry->Start == Base && Entry->End == Base + Length - 1) {
545 Result = TRUE;
546 break;
547 }
548 }
549
550 return Result;
551 }
552
553 /**
554 Check the consistency of Smm memory map.
555 **/
556 VOID
557 SmmMemoryMapConsistencyCheck (
558 VOID
559 )
560 {
561 LIST_ENTRY *Node;
562 FREE_PAGE_LIST *Pages;
563 BOOLEAN Result;
564
565 Pages = NULL;
566 Node = mSmmMemoryMap.ForwardLink;
567 while (Node != &mSmmMemoryMap) {
568 Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);
569 Result = SmmMemoryMapConsistencyCheckRange ((EFI_PHYSICAL_ADDRESS)(UINTN)Pages, (UINTN)EFI_PAGES_TO_SIZE(Pages->NumberOfPages));
570 ASSERT (Result);
571 Node = Node->ForwardLink;
572 }
573 }
574
575 /**
576 Internal Function. Allocate n pages from given free page node.
577
578 @param Pages The free page node.
579 @param NumberOfPages Number of pages to be allocated.
580 @param MaxAddress Request to allocate memory below this address.
581
582 @return Memory address of allocated pages.
583
584 **/
585 UINTN
586 InternalAllocPagesOnOneNode (
587 IN OUT FREE_PAGE_LIST *Pages,
588 IN UINTN NumberOfPages,
589 IN UINTN MaxAddress
590 )
591 {
592 UINTN Top;
593 UINTN Bottom;
594 FREE_PAGE_LIST *Node;
595
596 Top = TRUNCATE_TO_PAGES (MaxAddress + 1 - (UINTN)Pages);
597 if (Top > Pages->NumberOfPages) {
598 Top = Pages->NumberOfPages;
599 }
600 Bottom = Top - NumberOfPages;
601
602 if (Top < Pages->NumberOfPages) {
603 Node = (FREE_PAGE_LIST*)((UINTN)Pages + EFI_PAGES_TO_SIZE (Top));
604 Node->NumberOfPages = Pages->NumberOfPages - Top;
605 InsertHeadList (&Pages->Link, &Node->Link);
606 }
607
608 if (Bottom > 0) {
609 Pages->NumberOfPages = Bottom;
610 } else {
611 RemoveEntryList (&Pages->Link);
612 }
613
614 return (UINTN)Pages + EFI_PAGES_TO_SIZE (Bottom);
615 }
616
617 /**
618 Internal Function. Allocate n pages from free page list below MaxAddress.
619
620 @param FreePageList The free page node.
621 @param NumberOfPages Number of pages to be allocated.
622 @param MaxAddress Request to allocate memory below this address.
623
624 @return Memory address of allocated pages.
625
626 **/
627 UINTN
628 InternalAllocMaxAddress (
629 IN OUT LIST_ENTRY *FreePageList,
630 IN UINTN NumberOfPages,
631 IN UINTN MaxAddress
632 )
633 {
634 LIST_ENTRY *Node;
635 FREE_PAGE_LIST *Pages;
636
637 for (Node = FreePageList->BackLink; Node != FreePageList; Node = Node->BackLink) {
638 Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);
639 if (Pages->NumberOfPages >= NumberOfPages &&
640 (UINTN)Pages + EFI_PAGES_TO_SIZE (NumberOfPages) - 1 <= MaxAddress) {
641 return InternalAllocPagesOnOneNode (Pages, NumberOfPages, MaxAddress);
642 }
643 }
644 return (UINTN)(-1);
645 }
646
647 /**
648 Internal Function. Allocate n pages from free page list at given address.
649
650 @param FreePageList The free page node.
651 @param NumberOfPages Number of pages to be allocated.
652 @param MaxAddress Request to allocate memory below this address.
653
654 @return Memory address of allocated pages.
655
656 **/
657 UINTN
658 InternalAllocAddress (
659 IN OUT LIST_ENTRY *FreePageList,
660 IN UINTN NumberOfPages,
661 IN UINTN Address
662 )
663 {
664 UINTN EndAddress;
665 LIST_ENTRY *Node;
666 FREE_PAGE_LIST *Pages;
667
668 if ((Address & EFI_PAGE_MASK) != 0) {
669 return ~Address;
670 }
671
672 EndAddress = Address + EFI_PAGES_TO_SIZE (NumberOfPages);
673 for (Node = FreePageList->BackLink; Node!= FreePageList; Node = Node->BackLink) {
674 Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);
675 if ((UINTN)Pages <= Address) {
676 if ((UINTN)Pages + EFI_PAGES_TO_SIZE (Pages->NumberOfPages) < EndAddress) {
677 break;
678 }
679 return InternalAllocPagesOnOneNode (Pages, NumberOfPages, EndAddress);
680 }
681 }
682 return ~Address;
683 }
684
685 /**
686 Allocates pages from the memory map.
687
688 @param[in] Type The type of allocation to perform.
689 @param[in] MemoryType The type of memory to turn the allocated pages
690 into.
691 @param[in] NumberOfPages The number of pages to allocate.
692 @param[out] Memory A pointer to receive the base allocated memory
693 address.
694 @param[in] AddRegion If this memory is new added region.
695 @param[in] NeedGuard Flag to indicate Guard page is needed
696 or not
697
698 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.
699 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
700 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
701 @retval EFI_SUCCESS Pages successfully allocated.
702
703 **/
704 EFI_STATUS
705 SmmInternalAllocatePagesEx (
706 IN EFI_ALLOCATE_TYPE Type,
707 IN EFI_MEMORY_TYPE MemoryType,
708 IN UINTN NumberOfPages,
709 OUT EFI_PHYSICAL_ADDRESS *Memory,
710 IN BOOLEAN AddRegion,
711 IN BOOLEAN NeedGuard
712 )
713 {
714 UINTN RequestedAddress;
715
716 if (MemoryType != EfiRuntimeServicesCode &&
717 MemoryType != EfiRuntimeServicesData) {
718 return EFI_INVALID_PARAMETER;
719 }
720
721 if (NumberOfPages > TRUNCATE_TO_PAGES ((UINTN)-1) + 1) {
722 return EFI_OUT_OF_RESOURCES;
723 }
724
725 //
726 // We don't track memory type in SMM
727 //
728 RequestedAddress = (UINTN)*Memory;
729 switch (Type) {
730 case AllocateAnyPages:
731 RequestedAddress = (UINTN)(-1);
732 case AllocateMaxAddress:
733 if (NeedGuard) {
734 *Memory = InternalAllocMaxAddressWithGuard (
735 &mSmmMemoryMap,
736 NumberOfPages,
737 RequestedAddress,
738 MemoryType
739 );
740 if (*Memory == (UINTN)-1) {
741 return EFI_OUT_OF_RESOURCES;
742 } else {
743 ASSERT (VerifyMemoryGuard (*Memory, NumberOfPages) == TRUE);
744 return EFI_SUCCESS;
745 }
746 }
747
748 *Memory = InternalAllocMaxAddress (
749 &mSmmMemoryMap,
750 NumberOfPages,
751 RequestedAddress
752 );
753 if (*Memory == (UINTN)-1) {
754 return EFI_OUT_OF_RESOURCES;
755 }
756 break;
757 case AllocateAddress:
758 *Memory = InternalAllocAddress (
759 &mSmmMemoryMap,
760 NumberOfPages,
761 RequestedAddress
762 );
763 if (*Memory != RequestedAddress) {
764 return EFI_NOT_FOUND;
765 }
766 break;
767 default:
768 return EFI_INVALID_PARAMETER;
769 }
770
771 //
772 // Update SmmMemoryMap here.
773 //
774 ConvertSmmMemoryMapEntry (MemoryType, *Memory, NumberOfPages, AddRegion);
775 if (!AddRegion) {
776 CoreFreeMemoryMapStack();
777 }
778
779 return EFI_SUCCESS;
780 }
781
782 /**
783 Allocates pages from the memory map.
784
785 @param[in] Type The type of allocation to perform.
786 @param[in] MemoryType The type of memory to turn the allocated pages
787 into.
788 @param[in] NumberOfPages The number of pages to allocate.
789 @param[out] Memory A pointer to receive the base allocated memory
790 address.
791 @param[in] NeedGuard Flag to indicate Guard page is needed
792 or not
793
794 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.
795 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
796 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
797 @retval EFI_SUCCESS Pages successfully allocated.
798
799 **/
800 EFI_STATUS
801 EFIAPI
802 SmmInternalAllocatePages (
803 IN EFI_ALLOCATE_TYPE Type,
804 IN EFI_MEMORY_TYPE MemoryType,
805 IN UINTN NumberOfPages,
806 OUT EFI_PHYSICAL_ADDRESS *Memory,
807 IN BOOLEAN NeedGuard
808 )
809 {
810 return SmmInternalAllocatePagesEx (Type, MemoryType, NumberOfPages, Memory,
811 FALSE, NeedGuard);
812 }
813
814 /**
815 Allocates pages from the memory map.
816
817 @param Type The type of allocation to perform.
818 @param MemoryType The type of memory to turn the allocated pages
819 into.
820 @param NumberOfPages The number of pages to allocate.
821 @param Memory A pointer to receive the base allocated memory
822 address.
823
824 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.
825 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.
826 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.
827 @retval EFI_SUCCESS Pages successfully allocated.
828
829 **/
830 EFI_STATUS
831 EFIAPI
832 SmmAllocatePages (
833 IN EFI_ALLOCATE_TYPE Type,
834 IN EFI_MEMORY_TYPE MemoryType,
835 IN UINTN NumberOfPages,
836 OUT EFI_PHYSICAL_ADDRESS *Memory
837 )
838 {
839 EFI_STATUS Status;
840 BOOLEAN NeedGuard;
841
842 NeedGuard = IsPageTypeToGuard (MemoryType, Type);
843 Status = SmmInternalAllocatePages (Type, MemoryType, NumberOfPages, Memory,
844 NeedGuard);
845 if (!EFI_ERROR (Status)) {
846 SmmCoreUpdateProfile (
847 (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),
848 MemoryProfileActionAllocatePages,
849 MemoryType,
850 EFI_PAGES_TO_SIZE (NumberOfPages),
851 (VOID *) (UINTN) *Memory,
852 NULL
853 );
854 }
855 return Status;
856 }
857
858 /**
859 Internal Function. Merge two adjacent nodes.
860
861 @param First The first of two nodes to merge.
862
863 @return Pointer to node after merge (if success) or pointer to next node (if fail).
864
865 **/
866 FREE_PAGE_LIST *
867 InternalMergeNodes (
868 IN FREE_PAGE_LIST *First
869 )
870 {
871 FREE_PAGE_LIST *Next;
872
873 Next = BASE_CR (First->Link.ForwardLink, FREE_PAGE_LIST, Link);
874 ASSERT (
875 TRUNCATE_TO_PAGES ((UINTN)Next - (UINTN)First) >= First->NumberOfPages);
876
877 if (TRUNCATE_TO_PAGES ((UINTN)Next - (UINTN)First) == First->NumberOfPages) {
878 First->NumberOfPages += Next->NumberOfPages;
879 RemoveEntryList (&Next->Link);
880 Next = First;
881 }
882 return Next;
883 }
884
885 /**
886 Frees previous allocated pages.
887
888 @param[in] Memory Base address of memory being freed.
889 @param[in] NumberOfPages The number of pages to free.
890 @param[in] AddRegion If this memory is new added region.
891
892 @retval EFI_NOT_FOUND Could not find the entry that covers the range.
893 @retval EFI_INVALID_PARAMETER Address not aligned, Address is zero or NumberOfPages is zero.
894 @return EFI_SUCCESS Pages successfully freed.
895
896 **/
897 EFI_STATUS
898 SmmInternalFreePagesEx (
899 IN EFI_PHYSICAL_ADDRESS Memory,
900 IN UINTN NumberOfPages,
901 IN BOOLEAN AddRegion
902 )
903 {
904 LIST_ENTRY *Node;
905 FREE_PAGE_LIST *Pages;
906
907 if (((Memory & EFI_PAGE_MASK) != 0) || (Memory == 0) || (NumberOfPages == 0)) {
908 return EFI_INVALID_PARAMETER;
909 }
910
911 Pages = NULL;
912 Node = mSmmMemoryMap.ForwardLink;
913 while (Node != &mSmmMemoryMap) {
914 Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);
915 if (Memory < (UINTN)Pages) {
916 break;
917 }
918 Node = Node->ForwardLink;
919 }
920
921 if (Node != &mSmmMemoryMap &&
922 Memory + EFI_PAGES_TO_SIZE (NumberOfPages) > (UINTN)Pages) {
923 return EFI_INVALID_PARAMETER;
924 }
925
926 if (Node->BackLink != &mSmmMemoryMap) {
927 Pages = BASE_CR (Node->BackLink, FREE_PAGE_LIST, Link);
928 if ((UINTN)Pages + EFI_PAGES_TO_SIZE (Pages->NumberOfPages) > Memory) {
929 return EFI_INVALID_PARAMETER;
930 }
931 }
932
933 Pages = (FREE_PAGE_LIST*)(UINTN)Memory;
934 Pages->NumberOfPages = NumberOfPages;
935 InsertTailList (Node, &Pages->Link);
936
937 if (Pages->Link.BackLink != &mSmmMemoryMap) {
938 Pages = InternalMergeNodes (
939 BASE_CR (Pages->Link.BackLink, FREE_PAGE_LIST, Link)
940 );
941 }
942
943 if (Node != &mSmmMemoryMap) {
944 InternalMergeNodes (Pages);
945 }
946
947 //
948 // Update SmmMemoryMap here.
949 //
950 ConvertSmmMemoryMapEntry (EfiConventionalMemory, Memory, NumberOfPages, AddRegion);
951 if (!AddRegion) {
952 CoreFreeMemoryMapStack();
953 }
954
955 return EFI_SUCCESS;
956 }
957
958 /**
959 Frees previous allocated pages.
960
961 @param[in] Memory Base address of memory being freed.
962 @param[in] NumberOfPages The number of pages to free.
963 @param[in] IsGuarded Is the memory to free guarded or not.
964
965 @retval EFI_NOT_FOUND Could not find the entry that covers the range.
966 @retval EFI_INVALID_PARAMETER Address not aligned, Address is zero or NumberOfPages is zero.
967 @return EFI_SUCCESS Pages successfully freed.
968
969 **/
970 EFI_STATUS
971 EFIAPI
972 SmmInternalFreePages (
973 IN EFI_PHYSICAL_ADDRESS Memory,
974 IN UINTN NumberOfPages,
975 IN BOOLEAN IsGuarded
976 )
977 {
978 if (IsGuarded) {
979 return SmmInternalFreePagesExWithGuard (Memory, NumberOfPages, FALSE);
980 }
981 return SmmInternalFreePagesEx (Memory, NumberOfPages, FALSE);
982 }
983
984 /**
985 Frees previous allocated pages.
986
987 @param Memory Base address of memory being freed.
988 @param NumberOfPages The number of pages to free.
989
990 @retval EFI_NOT_FOUND Could not find the entry that covers the range.
991 @retval EFI_INVALID_PARAMETER Address not aligned, Address is zero or NumberOfPages is zero.
992 @return EFI_SUCCESS Pages successfully freed.
993
994 **/
995 EFI_STATUS
996 EFIAPI
997 SmmFreePages (
998 IN EFI_PHYSICAL_ADDRESS Memory,
999 IN UINTN NumberOfPages
1000 )
1001 {
1002 EFI_STATUS Status;
1003 BOOLEAN IsGuarded;
1004
1005 IsGuarded = IsHeapGuardEnabled () && IsMemoryGuarded (Memory);
1006 Status = SmmInternalFreePages (Memory, NumberOfPages, IsGuarded);
1007 if (!EFI_ERROR (Status)) {
1008 SmmCoreUpdateProfile (
1009 (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),
1010 MemoryProfileActionFreePages,
1011 EfiMaxMemoryType,
1012 EFI_PAGES_TO_SIZE (NumberOfPages),
1013 (VOID *) (UINTN) Memory,
1014 NULL
1015 );
1016 }
1017 return Status;
1018 }
1019
1020 /**
1021 Add free SMRAM region for use by memory service.
1022
1023 @param MemBase Base address of memory region.
1024 @param MemLength Length of the memory region.
1025 @param Type Memory type.
1026 @param Attributes Memory region state.
1027
1028 **/
1029 VOID
1030 SmmAddMemoryRegion (
1031 IN EFI_PHYSICAL_ADDRESS MemBase,
1032 IN UINT64 MemLength,
1033 IN EFI_MEMORY_TYPE Type,
1034 IN UINT64 Attributes
1035 )
1036 {
1037 UINTN AlignedMemBase;
1038
1039 //
1040 // Add EfiRuntimeServicesData for memory regions that is already allocated, needs testing, or needs ECC initialization
1041 //
1042 if ((Attributes & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {
1043 Type = EfiRuntimeServicesData;
1044 } else {
1045 Type = EfiConventionalMemory;
1046 }
1047
1048 DEBUG ((DEBUG_INFO, "SmmAddMemoryRegion\n"));
1049 DEBUG ((DEBUG_INFO, " MemBase - 0x%lx\n", MemBase));
1050 DEBUG ((DEBUG_INFO, " MemLength - 0x%lx\n", MemLength));
1051 DEBUG ((DEBUG_INFO, " Type - 0x%x\n", Type));
1052 DEBUG ((DEBUG_INFO, " Attributes - 0x%lx\n", Attributes));
1053
1054 //
1055 // Align range on an EFI_PAGE_SIZE boundary
1056 //
1057 AlignedMemBase = (UINTN)(MemBase + EFI_PAGE_MASK) & ~EFI_PAGE_MASK;
1058 MemLength -= AlignedMemBase - MemBase;
1059 if (Type == EfiConventionalMemory) {
1060 SmmInternalFreePagesEx (AlignedMemBase, TRUNCATE_TO_PAGES ((UINTN)MemLength), TRUE);
1061 } else {
1062 ConvertSmmMemoryMapEntry (EfiRuntimeServicesData, AlignedMemBase, TRUNCATE_TO_PAGES ((UINTN)MemLength), TRUE);
1063 }
1064
1065 CoreFreeMemoryMapStack ();
1066 }
1067
1068 /**
1069 This function returns a copy of the current memory map. The map is an array of
1070 memory descriptors, each of which describes a contiguous block of memory.
1071
1072 @param[in, out] MemoryMapSize A pointer to the size, in bytes, of the
1073 MemoryMap buffer. On input, this is the size of
1074 the buffer allocated by the caller. On output,
1075 it is the size of the buffer returned by the
1076 firmware if the buffer was large enough, or the
1077 size of the buffer needed to contain the map if
1078 the buffer was too small.
1079 @param[in, out] MemoryMap A pointer to the buffer in which firmware places
1080 the current memory map.
1081 @param[out] MapKey A pointer to the location in which firmware
1082 returns the key for the current memory map.
1083 @param[out] DescriptorSize A pointer to the location in which firmware
1084 returns the size, in bytes, of an individual
1085 EFI_MEMORY_DESCRIPTOR.
1086 @param[out] DescriptorVersion A pointer to the location in which firmware
1087 returns the version number associated with the
1088 EFI_MEMORY_DESCRIPTOR.
1089
1090 @retval EFI_SUCCESS The memory map was returned in the MemoryMap
1091 buffer.
1092 @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current
1093 buffer size needed to hold the memory map is
1094 returned in MemoryMapSize.
1095 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
1096
1097 **/
1098 EFI_STATUS
1099 EFIAPI
1100 SmmCoreGetMemoryMap (
1101 IN OUT UINTN *MemoryMapSize,
1102 IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
1103 OUT UINTN *MapKey,
1104 OUT UINTN *DescriptorSize,
1105 OUT UINT32 *DescriptorVersion
1106 )
1107 {
1108 UINTN Count;
1109 LIST_ENTRY *Link;
1110 MEMORY_MAP *Entry;
1111 UINTN Size;
1112 UINTN BufferSize;
1113
1114 Size = sizeof (EFI_MEMORY_DESCRIPTOR);
1115
1116 //
1117 // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will
1118 // prevent people from having pointer math bugs in their code.
1119 // now you have to use *DescriptorSize to make things work.
1120 //
1121 Size += sizeof(UINT64) - (Size % sizeof (UINT64));
1122
1123 if (DescriptorSize != NULL) {
1124 *DescriptorSize = Size;
1125 }
1126
1127 if (DescriptorVersion != NULL) {
1128 *DescriptorVersion = EFI_MEMORY_DESCRIPTOR_VERSION;
1129 }
1130
1131 Count = GetSmmMemoryMapEntryCount ();
1132 BufferSize = Size * Count;
1133 if (*MemoryMapSize < BufferSize) {
1134 *MemoryMapSize = BufferSize;
1135 return EFI_BUFFER_TOO_SMALL;
1136 }
1137
1138 *MemoryMapSize = BufferSize;
1139 if (MemoryMap == NULL) {
1140 return EFI_INVALID_PARAMETER;
1141 }
1142
1143 ZeroMem (MemoryMap, BufferSize);
1144 Link = gMemoryMap.ForwardLink;
1145 while (Link != &gMemoryMap) {
1146 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
1147 Link = Link->ForwardLink;
1148
1149 MemoryMap->Type = Entry->Type;
1150 MemoryMap->PhysicalStart = Entry->Start;
1151 MemoryMap->NumberOfPages = RShiftU64 (Entry->End - Entry->Start + 1, EFI_PAGE_SHIFT);
1152
1153 MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, Size);
1154 }
1155
1156 return EFI_SUCCESS;
1157 }