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