mirror of
				https://github.com/acidanthera/audk.git
				synced 2025-10-31 11:13:53 +01:00 
			
		
		
		
	The functions that are never called have been removed. They are IsImageInsideSmram,FindImageRecord,SmmRemoveImageRecord, SmmMemoryAttributesTableConsistencyCheck,DumpSmmMemoryMapEntry, SmmMemoryMapConsistencyCheckRange,SmmMemoryMapConsistencyCheck, DumpSmmMemoryMap,ClearGuardMapBit,SetGuardMapBit,AdjustMemoryA, AdjustMemoryS,IsHeadGuard and IsTailGuard. FindImageRecord() is called by SmmRemoveImageRecord(); however, nothing calls SmmRemoveImageRecord(). SmmMemoryMapConsistencyCheckRange() is called by SmmMemoryMapConsistencyCheck(); however, nothing calls SmmMemoryMapConsistencyCheck(). https://bugzilla.tianocore.org/show_bug.cgi?id=1062 v2:append the following to the commit message. - FindImageRecord() is called by SmmRemoveImageRecord(); however, nothing calls SmmRemoveImageRecord(). - SmmMemoryMapConsistencyCheckRange() is called by SmmMemoryMapConsistencyCheck(); however, nothing calls SmmMemoryMapConsistencyCheck(). Cc: Star Zeng <star.zeng@intel.com> Cc: Eric Dong <eric.dong@intel.com> Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: shenglei <shenglei.zhang@intel.com> Reviewed-by: Jian J Wang <jian.j.wang@intel.com> Reviewed-by: Laszlo Ersek <lersek@redhat.com> Reviewed-by: Star Zeng <star.zeng@intel.com>
		
			
				
	
	
		
			1039 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1039 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   SMM Memory page management functions.
 | |
| 
 | |
|   Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
 | |
|   This program and the accompanying materials are licensed and made available
 | |
|   under the terms and conditions of the BSD License which accompanies this
 | |
|   distribution.  The full text of the license may be found at
 | |
|   http://opensource.org/licenses/bsd-license.php
 | |
| 
 | |
|   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | |
|   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "PiSmmCore.h"
 | |
| #include <Library/SmmServicesTableLib.h>
 | |
| 
 | |
| #define TRUNCATE_TO_PAGES(a)  ((a) >> EFI_PAGE_SHIFT)
 | |
| 
 | |
| LIST_ENTRY  mSmmMemoryMap = INITIALIZE_LIST_HEAD_VARIABLE (mSmmMemoryMap);
 | |
| 
 | |
| //
 | |
| // For GetMemoryMap()
 | |
| //
 | |
| 
 | |
| #define MEMORY_MAP_SIGNATURE   SIGNATURE_32('m','m','a','p')
 | |
| typedef struct {
 | |
|   UINTN           Signature;
 | |
|   LIST_ENTRY      Link;
 | |
| 
 | |
|   BOOLEAN         FromStack;
 | |
|   EFI_MEMORY_TYPE Type;
 | |
|   UINT64          Start;
 | |
|   UINT64          End;
 | |
| 
 | |
| } MEMORY_MAP;
 | |
| 
 | |
| LIST_ENTRY        gMemoryMap  = INITIALIZE_LIST_HEAD_VARIABLE (gMemoryMap);
 | |
| 
 | |
| 
 | |
| #define MAX_MAP_DEPTH 6
 | |
| 
 | |
| ///
 | |
| /// mMapDepth - depth of new descriptor stack
 | |
| ///
 | |
| UINTN         mMapDepth = 0;
 | |
| ///
 | |
| /// mMapStack - space to use as temp storage to build new map descriptors
 | |
| ///
 | |
| MEMORY_MAP    mMapStack[MAX_MAP_DEPTH];
 | |
| UINTN         mFreeMapStack = 0;
 | |
| ///
 | |
| /// This list maintain the free memory map list
 | |
| ///
 | |
| LIST_ENTRY   mFreeMemoryMapEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mFreeMemoryMapEntryList);
 | |
| 
 | |
| /**
 | |
|   Allocates pages from the memory map.
 | |
| 
 | |
|   @param[in]   Type                   The type of allocation to perform.
 | |
|   @param[in]   MemoryType             The type of memory to turn the allocated pages
 | |
|                                       into.
 | |
|   @param[in]   NumberOfPages          The number of pages to allocate.
 | |
|   @param[out]  Memory                 A pointer to receive the base allocated memory
 | |
|                                       address.
 | |
|   @param[in]   AddRegion              If this memory is new added region.
 | |
|   @param[in]   NeedGuard              Flag to indicate Guard page is needed
 | |
|                                       or not
 | |
| 
 | |
|   @retval EFI_INVALID_PARAMETER  Parameters violate checking rules defined in spec.
 | |
|   @retval EFI_NOT_FOUND          Could not allocate pages match the requirement.
 | |
|   @retval EFI_OUT_OF_RESOURCES   No enough pages to allocate.
 | |
|   @retval EFI_SUCCESS            Pages successfully allocated.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| SmmInternalAllocatePagesEx (
 | |
|   IN  EFI_ALLOCATE_TYPE     Type,
 | |
|   IN  EFI_MEMORY_TYPE       MemoryType,
 | |
|   IN  UINTN                 NumberOfPages,
 | |
|   OUT EFI_PHYSICAL_ADDRESS  *Memory,
 | |
|   IN  BOOLEAN               AddRegion,
 | |
|   IN  BOOLEAN               NeedGuard
 | |
|   );
 | |
| 
 | |
| /**
 | |
|   Internal function.  Deque a descriptor entry from the mFreeMemoryMapEntryList.
 | |
|   If the list is emtry, then allocate a new page to refuel the list.
 | |
|   Please Note this algorithm to allocate the memory map descriptor has a property
 | |
|   that the memory allocated for memory entries always grows, and will never really be freed.
 | |
| 
 | |
|   @return The Memory map descriptor dequed from the mFreeMemoryMapEntryList
 | |
| 
 | |
| **/
 | |
| MEMORY_MAP *
 | |
| AllocateMemoryMapEntry (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   EFI_PHYSICAL_ADDRESS   Mem;
 | |
|   EFI_STATUS             Status;
 | |
|   MEMORY_MAP*            FreeDescriptorEntries;
 | |
|   MEMORY_MAP*            Entry;
 | |
|   UINTN                  Index;
 | |
| 
 | |
|   //DEBUG((DEBUG_INFO, "AllocateMemoryMapEntry\n"));
 | |
| 
 | |
|   if (IsListEmpty (&mFreeMemoryMapEntryList)) {
 | |
|     //DEBUG((DEBUG_INFO, "mFreeMemoryMapEntryList is empty\n"));
 | |
|     //
 | |
|     // The list is empty, to allocate one page to refuel the list
 | |
|     //
 | |
|     Status = SmmInternalAllocatePagesEx (
 | |
|                AllocateAnyPages,
 | |
|                EfiRuntimeServicesData,
 | |
|                EFI_SIZE_TO_PAGES (RUNTIME_PAGE_ALLOCATION_GRANULARITY),
 | |
|                &Mem,
 | |
|                TRUE,
 | |
|                FALSE
 | |
|                );
 | |
|     ASSERT_EFI_ERROR (Status);
 | |
|     if(!EFI_ERROR (Status)) {
 | |
|       FreeDescriptorEntries = (MEMORY_MAP *)(UINTN)Mem;
 | |
|       //DEBUG((DEBUG_INFO, "New FreeDescriptorEntries - 0x%x\n", FreeDescriptorEntries));
 | |
|       //
 | |
|       // Enque the free memmory map entries into the list
 | |
|       //
 | |
|       for (Index = 0; Index< RUNTIME_PAGE_ALLOCATION_GRANULARITY / sizeof(MEMORY_MAP); Index++) {
 | |
|         FreeDescriptorEntries[Index].Signature = MEMORY_MAP_SIGNATURE;
 | |
|         InsertTailList (&mFreeMemoryMapEntryList, &FreeDescriptorEntries[Index].Link);
 | |
|       }
 | |
|     } else {
 | |
|       return NULL;
 | |
|     }
 | |
|   }
 | |
|   //
 | |
|   // dequeue the first descriptor from the list
 | |
|   //
 | |
|   Entry = CR (mFreeMemoryMapEntryList.ForwardLink, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
 | |
|   RemoveEntryList (&Entry->Link);
 | |
| 
 | |
|   return Entry;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Internal function.  Moves any memory descriptors that are on the
 | |
|   temporary descriptor stack to heap.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| CoreFreeMemoryMapStack (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   MEMORY_MAP      *Entry;
 | |
| 
 | |
|   //
 | |
|   // If already freeing the map stack, then return
 | |
|   //
 | |
|   if (mFreeMapStack != 0) {
 | |
|     ASSERT (FALSE);
 | |
|     return ;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Move the temporary memory descriptor stack into pool
 | |
|   //
 | |
|   mFreeMapStack += 1;
 | |
| 
 | |
|   while (mMapDepth != 0) {
 | |
|     //
 | |
|     // Deque an memory map entry from mFreeMemoryMapEntryList
 | |
|     //
 | |
|     Entry = AllocateMemoryMapEntry ();
 | |
|     ASSERT (Entry);
 | |
| 
 | |
|     //
 | |
|     // Update to proper entry
 | |
|     //
 | |
|     mMapDepth -= 1;
 | |
| 
 | |
|     if (mMapStack[mMapDepth].Link.ForwardLink != NULL) {
 | |
| 
 | |
|       CopyMem (Entry , &mMapStack[mMapDepth], sizeof (MEMORY_MAP));
 | |
|       Entry->FromStack = FALSE;
 | |
| 
 | |
|       //
 | |
|       // Move this entry to general memory
 | |
|       //
 | |
|       InsertTailList (&mMapStack[mMapDepth].Link, &Entry->Link);
 | |
|       RemoveEntryList (&mMapStack[mMapDepth].Link);
 | |
|       mMapStack[mMapDepth].Link.ForwardLink = NULL;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   mFreeMapStack -= 1;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Insert new entry from memory map.
 | |
| 
 | |
|   @param[in]  Link       The old memory map entry to be linked.
 | |
|   @param[in]  Start      The start address of new memory map entry.
 | |
|   @param[in]  End        The end address of new memory map entry.
 | |
|   @param[in]  Type       The type of new memory map entry.
 | |
|   @param[in]  Next       If new entry is inserted to the next of old entry.
 | |
|   @param[in]  AddRegion  If this memory is new added region.
 | |
| **/
 | |
| VOID
 | |
| InsertNewEntry (
 | |
|   IN LIST_ENTRY      *Link,
 | |
|   IN UINT64          Start,
 | |
|   IN UINT64          End,
 | |
|   IN EFI_MEMORY_TYPE Type,
 | |
|   IN BOOLEAN         Next,
 | |
|   IN BOOLEAN         AddRegion
 | |
|   )
 | |
| {
 | |
|   MEMORY_MAP  *Entry;
 | |
| 
 | |
|   Entry = &mMapStack[mMapDepth];
 | |
|   mMapDepth += 1;
 | |
|   ASSERT (mMapDepth < MAX_MAP_DEPTH);
 | |
|   Entry->FromStack = TRUE;
 | |
| 
 | |
|   Entry->Signature = MEMORY_MAP_SIGNATURE;
 | |
|   Entry->Type = Type;
 | |
|   Entry->Start = Start;
 | |
|   Entry->End = End;
 | |
|   if (Next) {
 | |
|     InsertHeadList (Link, &Entry->Link);
 | |
|   } else {
 | |
|     InsertTailList (Link, &Entry->Link);
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Remove old entry from memory map.
 | |
| 
 | |
|   @param[in] Entry Memory map entry to be removed.
 | |
| **/
 | |
| VOID
 | |
| RemoveOldEntry (
 | |
|   IN MEMORY_MAP  *Entry
 | |
|   )
 | |
| {
 | |
|   RemoveEntryList (&Entry->Link);
 | |
|   Entry->Link.ForwardLink = NULL;
 | |
| 
 | |
|   if (!Entry->FromStack) {
 | |
|     InsertTailList (&mFreeMemoryMapEntryList, &Entry->Link);
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Update SMM memory map entry.
 | |
| 
 | |
|   @param[in]  Type                   The type of allocation to perform.
 | |
|   @param[in]  Memory                 The base of memory address.
 | |
|   @param[in]  NumberOfPages          The number of pages to allocate.
 | |
|   @param[in]  AddRegion              If this memory is new added region.
 | |
| **/
 | |
| VOID
 | |
| ConvertSmmMemoryMapEntry (
 | |
|   IN EFI_MEMORY_TYPE       Type,
 | |
|   IN EFI_PHYSICAL_ADDRESS  Memory,
 | |
|   IN UINTN                 NumberOfPages,
 | |
|   IN BOOLEAN               AddRegion
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY               *Link;
 | |
|   MEMORY_MAP               *Entry;
 | |
|   MEMORY_MAP               *NextEntry;
 | |
|   LIST_ENTRY               *NextLink;
 | |
|   MEMORY_MAP               *PreviousEntry;
 | |
|   LIST_ENTRY               *PreviousLink;
 | |
|   EFI_PHYSICAL_ADDRESS     Start;
 | |
|   EFI_PHYSICAL_ADDRESS     End;
 | |
| 
 | |
|   Start = Memory;
 | |
|   End = Memory + EFI_PAGES_TO_SIZE(NumberOfPages) - 1;
 | |
| 
 | |
|   //
 | |
|   // Exclude memory region
 | |
|   //
 | |
|   Link = gMemoryMap.ForwardLink;
 | |
|   while (Link != &gMemoryMap) {
 | |
|     Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
 | |
|     Link  = Link->ForwardLink;
 | |
| 
 | |
|     //
 | |
|     // ---------------------------------------------------
 | |
|     // |  +----------+   +------+   +------+   +------+  |
 | |
|     // ---|gMemoryMep|---|Entry1|---|Entry2|---|Entry3|---
 | |
|     //    +----------+ ^ +------+   +------+   +------+
 | |
|     //                 |
 | |
|     //              +------+
 | |
|     //              |EntryX|
 | |
|     //              +------+
 | |
|     //
 | |
|     if (Entry->Start > End) {
 | |
|       if ((Entry->Start == End + 1) && (Entry->Type == Type)) {
 | |
|         Entry->Start = Start;
 | |
|         return ;
 | |
|       }
 | |
|       InsertNewEntry (
 | |
|         &Entry->Link,
 | |
|         Start,
 | |
|         End,
 | |
|         Type,
 | |
|         FALSE,
 | |
|         AddRegion
 | |
|         );
 | |
|       return ;
 | |
|     }
 | |
| 
 | |
|     if ((Entry->Start <= Start) && (Entry->End >= End)) {
 | |
|       if (Entry->Type != Type) {
 | |
|         if (Entry->Start < Start) {
 | |
|           //
 | |
|           // ---------------------------------------------------
 | |
|           // |  +----------+   +------+   +------+   +------+  |
 | |
|           // ---|gMemoryMep|---|Entry1|---|EntryX|---|Entry3|---
 | |
|           //    +----------+   +------+ ^ +------+   +------+
 | |
|           //                            |
 | |
|           //                         +------+
 | |
|           //                         |EntryA|
 | |
|           //                         +------+
 | |
|           //
 | |
|           InsertNewEntry (
 | |
|             &Entry->Link,
 | |
|             Entry->Start,
 | |
|             Start - 1,
 | |
|             Entry->Type,
 | |
|             FALSE,
 | |
|             AddRegion
 | |
|             );
 | |
|         }
 | |
|         if (Entry->End > End) {
 | |
|           //
 | |
|           // ---------------------------------------------------
 | |
|           // |  +----------+   +------+   +------+   +------+  |
 | |
|           // ---|gMemoryMep|---|Entry1|---|EntryX|---|Entry3|---
 | |
|           //    +----------+   +------+   +------+ ^ +------+
 | |
|           //                                       |
 | |
|           //                                    +------+
 | |
|           //                                    |EntryZ|
 | |
|           //                                    +------+
 | |
|           //
 | |
|           InsertNewEntry (
 | |
|             &Entry->Link,
 | |
|             End + 1,
 | |
|             Entry->End,
 | |
|             Entry->Type,
 | |
|             TRUE,
 | |
|             AddRegion
 | |
|             );
 | |
|         }
 | |
|         //
 | |
|         // Update this node
 | |
|         //
 | |
|         Entry->Start = Start;
 | |
|         Entry->End = End;
 | |
|         Entry->Type = Type;
 | |
| 
 | |
|         //
 | |
|         // Check adjacent
 | |
|         //
 | |
|         NextLink = Entry->Link.ForwardLink;
 | |
|         if (NextLink != &gMemoryMap) {
 | |
|           NextEntry = CR (NextLink, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
 | |
|           //
 | |
|           // ---------------------------------------------------
 | |
|           // |  +----------+   +------+   +-----------------+  |
 | |
|           // ---|gMemoryMep|---|Entry1|---|EntryX     Entry3|---
 | |
|           //    +----------+   +------+   +-----------------+
 | |
|           //
 | |
|           if ((Entry->Type == NextEntry->Type) && (Entry->End + 1 == NextEntry->Start)) {
 | |
|             Entry->End = NextEntry->End;
 | |
|             RemoveOldEntry (NextEntry);
 | |
|           }
 | |
|         }
 | |
|         PreviousLink = Entry->Link.BackLink;
 | |
|         if (PreviousLink != &gMemoryMap) {
 | |
|           PreviousEntry = CR (PreviousLink, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
 | |
|           //
 | |
|           // ---------------------------------------------------
 | |
|           // |  +----------+   +-----------------+   +------+  |
 | |
|           // ---|gMemoryMep|---|Entry1     EntryX|---|Entry3|---
 | |
|           //    +----------+   +-----------------+   +------+
 | |
|           //
 | |
|           if ((PreviousEntry->Type == Entry->Type) && (PreviousEntry->End + 1 == Entry->Start)) {
 | |
|             PreviousEntry->End = Entry->End;
 | |
|             RemoveOldEntry (Entry);
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|       return ;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // ---------------------------------------------------
 | |
|   // |  +----------+   +------+   +------+   +------+  |
 | |
|   // ---|gMemoryMep|---|Entry1|---|Entry2|---|Entry3|---
 | |
|   //    +----------+   +------+   +------+   +------+ ^
 | |
|   //                                                  |
 | |
|   //                                               +------+
 | |
|   //                                               |EntryX|
 | |
|   //                                               +------+
 | |
|   //
 | |
|   Link = gMemoryMap.BackLink;
 | |
|   if (Link != &gMemoryMap) {
 | |
|     Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
 | |
|     if ((Entry->End + 1 == Start) && (Entry->Type == Type)) {
 | |
|       Entry->End = End;
 | |
|       return ;
 | |
|     }
 | |
|   }
 | |
|   InsertNewEntry (
 | |
|     &gMemoryMap,
 | |
|     Start,
 | |
|     End,
 | |
|     Type,
 | |
|     FALSE,
 | |
|     AddRegion
 | |
|     );
 | |
|   return ;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Return the count of Smm memory map entry.
 | |
| 
 | |
|   @return The count of Smm memory map entry.
 | |
| **/
 | |
| UINTN
 | |
| GetSmmMemoryMapEntryCount (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY               *Link;
 | |
|   UINTN                    Count;
 | |
| 
 | |
|   Count = 0;
 | |
|   Link = gMemoryMap.ForwardLink;
 | |
|   while (Link != &gMemoryMap) {
 | |
|     Link  = Link->ForwardLink;
 | |
|     Count++;
 | |
|   }
 | |
|   return Count;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Internal Function. Allocate n pages from given free page node.
 | |
| 
 | |
|   @param  Pages                  The free page node.
 | |
|   @param  NumberOfPages          Number of pages to be allocated.
 | |
|   @param  MaxAddress             Request to allocate memory below this address.
 | |
| 
 | |
|   @return Memory address of allocated pages.
 | |
| 
 | |
| **/
 | |
| UINTN
 | |
| InternalAllocPagesOnOneNode (
 | |
|   IN OUT FREE_PAGE_LIST  *Pages,
 | |
|   IN     UINTN           NumberOfPages,
 | |
|   IN     UINTN           MaxAddress
 | |
|   )
 | |
| {
 | |
|   UINTN           Top;
 | |
|   UINTN           Bottom;
 | |
|   FREE_PAGE_LIST  *Node;
 | |
| 
 | |
|   Top = TRUNCATE_TO_PAGES (MaxAddress + 1 - (UINTN)Pages);
 | |
|   if (Top > Pages->NumberOfPages) {
 | |
|     Top = Pages->NumberOfPages;
 | |
|   }
 | |
|   Bottom = Top - NumberOfPages;
 | |
| 
 | |
|   if (Top < Pages->NumberOfPages) {
 | |
|     Node = (FREE_PAGE_LIST*)((UINTN)Pages + EFI_PAGES_TO_SIZE (Top));
 | |
|     Node->NumberOfPages = Pages->NumberOfPages - Top;
 | |
|     InsertHeadList (&Pages->Link, &Node->Link);
 | |
|   }
 | |
| 
 | |
|   if (Bottom > 0) {
 | |
|     Pages->NumberOfPages = Bottom;
 | |
|   } else {
 | |
|     RemoveEntryList (&Pages->Link);
 | |
|   }
 | |
| 
 | |
|   return (UINTN)Pages + EFI_PAGES_TO_SIZE (Bottom);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Internal Function. Allocate n pages from free page list below MaxAddress.
 | |
| 
 | |
|   @param  FreePageList           The free page node.
 | |
|   @param  NumberOfPages          Number of pages to be allocated.
 | |
|   @param  MaxAddress             Request to allocate memory below this address.
 | |
| 
 | |
|   @return Memory address of allocated pages.
 | |
| 
 | |
| **/
 | |
| UINTN
 | |
| InternalAllocMaxAddress (
 | |
|   IN OUT LIST_ENTRY  *FreePageList,
 | |
|   IN     UINTN       NumberOfPages,
 | |
|   IN     UINTN       MaxAddress
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY      *Node;
 | |
|   FREE_PAGE_LIST  *Pages;
 | |
| 
 | |
|   for (Node = FreePageList->BackLink; Node != FreePageList; Node = Node->BackLink) {
 | |
|     Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);
 | |
|     if (Pages->NumberOfPages >= NumberOfPages &&
 | |
|         (UINTN)Pages + EFI_PAGES_TO_SIZE (NumberOfPages) - 1 <= MaxAddress) {
 | |
|       return InternalAllocPagesOnOneNode (Pages, NumberOfPages, MaxAddress);
 | |
|     }
 | |
|   }
 | |
|   return (UINTN)(-1);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Internal Function. Allocate n pages from free page list at given address.
 | |
| 
 | |
|   @param  FreePageList           The free page node.
 | |
|   @param  NumberOfPages          Number of pages to be allocated.
 | |
|   @param  MaxAddress             Request to allocate memory below this address.
 | |
| 
 | |
|   @return Memory address of allocated pages.
 | |
| 
 | |
| **/
 | |
| UINTN
 | |
| InternalAllocAddress (
 | |
|   IN OUT LIST_ENTRY  *FreePageList,
 | |
|   IN     UINTN       NumberOfPages,
 | |
|   IN     UINTN       Address
 | |
|   )
 | |
| {
 | |
|   UINTN           EndAddress;
 | |
|   LIST_ENTRY      *Node;
 | |
|   FREE_PAGE_LIST  *Pages;
 | |
| 
 | |
|   if ((Address & EFI_PAGE_MASK) != 0) {
 | |
|     return ~Address;
 | |
|   }
 | |
| 
 | |
|   EndAddress = Address + EFI_PAGES_TO_SIZE (NumberOfPages);
 | |
|   for (Node = FreePageList->BackLink; Node!= FreePageList; Node = Node->BackLink) {
 | |
|     Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);
 | |
|     if ((UINTN)Pages <= Address) {
 | |
|       if ((UINTN)Pages + EFI_PAGES_TO_SIZE (Pages->NumberOfPages) < EndAddress) {
 | |
|         break;
 | |
|       }
 | |
|       return InternalAllocPagesOnOneNode (Pages, NumberOfPages, EndAddress);
 | |
|     }
 | |
|   }
 | |
|   return ~Address;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Allocates pages from the memory map.
 | |
| 
 | |
|   @param[in]   Type                   The type of allocation to perform.
 | |
|   @param[in]   MemoryType             The type of memory to turn the allocated pages
 | |
|                                       into.
 | |
|   @param[in]   NumberOfPages          The number of pages to allocate.
 | |
|   @param[out]  Memory                 A pointer to receive the base allocated memory
 | |
|                                       address.
 | |
|   @param[in]   AddRegion              If this memory is new added region.
 | |
|   @param[in]   NeedGuard              Flag to indicate Guard page is needed
 | |
|                                       or not
 | |
| 
 | |
|   @retval EFI_INVALID_PARAMETER  Parameters violate checking rules defined in spec.
 | |
|   @retval EFI_NOT_FOUND          Could not allocate pages match the requirement.
 | |
|   @retval EFI_OUT_OF_RESOURCES   No enough pages to allocate.
 | |
|   @retval EFI_SUCCESS            Pages successfully allocated.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| SmmInternalAllocatePagesEx (
 | |
|   IN  EFI_ALLOCATE_TYPE     Type,
 | |
|   IN  EFI_MEMORY_TYPE       MemoryType,
 | |
|   IN  UINTN                 NumberOfPages,
 | |
|   OUT EFI_PHYSICAL_ADDRESS  *Memory,
 | |
|   IN  BOOLEAN               AddRegion,
 | |
|   IN  BOOLEAN               NeedGuard
 | |
|   )
 | |
| {
 | |
|   UINTN  RequestedAddress;
 | |
| 
 | |
|   if (MemoryType != EfiRuntimeServicesCode &&
 | |
|       MemoryType != EfiRuntimeServicesData) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if (NumberOfPages > TRUNCATE_TO_PAGES ((UINTN)-1) + 1) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // We don't track memory type in SMM
 | |
|   //
 | |
|   RequestedAddress = (UINTN)*Memory;
 | |
|   switch (Type) {
 | |
|     case AllocateAnyPages:
 | |
|       RequestedAddress = (UINTN)(-1);
 | |
|     case AllocateMaxAddress:
 | |
|       if (NeedGuard) {
 | |
|         *Memory = InternalAllocMaxAddressWithGuard (
 | |
|                       &mSmmMemoryMap,
 | |
|                       NumberOfPages,
 | |
|                       RequestedAddress,
 | |
|                       MemoryType
 | |
|                       );
 | |
|         if (*Memory == (UINTN)-1) {
 | |
|           return EFI_OUT_OF_RESOURCES;
 | |
|         } else {
 | |
|           ASSERT (VerifyMemoryGuard (*Memory, NumberOfPages) == TRUE);
 | |
|           return EFI_SUCCESS;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       *Memory = InternalAllocMaxAddress (
 | |
|                   &mSmmMemoryMap,
 | |
|                   NumberOfPages,
 | |
|                   RequestedAddress
 | |
|                   );
 | |
|       if (*Memory == (UINTN)-1) {
 | |
|         return EFI_OUT_OF_RESOURCES;
 | |
|       }
 | |
|       break;
 | |
|     case AllocateAddress:
 | |
|       *Memory = InternalAllocAddress (
 | |
|                   &mSmmMemoryMap,
 | |
|                   NumberOfPages,
 | |
|                   RequestedAddress
 | |
|                   );
 | |
|       if (*Memory != RequestedAddress) {
 | |
|         return EFI_NOT_FOUND;
 | |
|       }
 | |
|       break;
 | |
|     default:
 | |
|       return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Update SmmMemoryMap here.
 | |
|   //
 | |
|   ConvertSmmMemoryMapEntry (MemoryType, *Memory, NumberOfPages, AddRegion);
 | |
|   if (!AddRegion) {
 | |
|     CoreFreeMemoryMapStack();
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Allocates pages from the memory map.
 | |
| 
 | |
|   @param[in]   Type                   The type of allocation to perform.
 | |
|   @param[in]   MemoryType             The type of memory to turn the allocated pages
 | |
|                                       into.
 | |
|   @param[in]   NumberOfPages          The number of pages to allocate.
 | |
|   @param[out]  Memory                 A pointer to receive the base allocated memory
 | |
|                                       address.
 | |
|   @param[in]   NeedGuard              Flag to indicate Guard page is needed
 | |
|                                       or not
 | |
| 
 | |
|   @retval EFI_INVALID_PARAMETER  Parameters violate checking rules defined in spec.
 | |
|   @retval EFI_NOT_FOUND          Could not allocate pages match the requirement.
 | |
|   @retval EFI_OUT_OF_RESOURCES   No enough pages to allocate.
 | |
|   @retval EFI_SUCCESS            Pages successfully allocated.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| SmmInternalAllocatePages (
 | |
|   IN  EFI_ALLOCATE_TYPE     Type,
 | |
|   IN  EFI_MEMORY_TYPE       MemoryType,
 | |
|   IN  UINTN                 NumberOfPages,
 | |
|   OUT EFI_PHYSICAL_ADDRESS  *Memory,
 | |
|   IN  BOOLEAN               NeedGuard
 | |
|   )
 | |
| {
 | |
|   return SmmInternalAllocatePagesEx (Type, MemoryType, NumberOfPages, Memory,
 | |
|                                      FALSE, NeedGuard);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Allocates pages from the memory map.
 | |
| 
 | |
|   @param  Type                   The type of allocation to perform.
 | |
|   @param  MemoryType             The type of memory to turn the allocated pages
 | |
|                                  into.
 | |
|   @param  NumberOfPages          The number of pages to allocate.
 | |
|   @param  Memory                 A pointer to receive the base allocated memory
 | |
|                                  address.
 | |
| 
 | |
|   @retval EFI_INVALID_PARAMETER  Parameters violate checking rules defined in spec.
 | |
|   @retval EFI_NOT_FOUND          Could not allocate pages match the requirement.
 | |
|   @retval EFI_OUT_OF_RESOURCES   No enough pages to allocate.
 | |
|   @retval EFI_SUCCESS            Pages successfully allocated.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| SmmAllocatePages (
 | |
|   IN  EFI_ALLOCATE_TYPE     Type,
 | |
|   IN  EFI_MEMORY_TYPE       MemoryType,
 | |
|   IN  UINTN                 NumberOfPages,
 | |
|   OUT EFI_PHYSICAL_ADDRESS  *Memory
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   BOOLEAN     NeedGuard;
 | |
| 
 | |
|   NeedGuard = IsPageTypeToGuard (MemoryType, Type);
 | |
|   Status = SmmInternalAllocatePages (Type, MemoryType, NumberOfPages, Memory,
 | |
|                                      NeedGuard);
 | |
|   if (!EFI_ERROR (Status)) {
 | |
|     SmmCoreUpdateProfile (
 | |
|       (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),
 | |
|       MemoryProfileActionAllocatePages,
 | |
|       MemoryType,
 | |
|       EFI_PAGES_TO_SIZE (NumberOfPages),
 | |
|       (VOID *) (UINTN) *Memory,
 | |
|       NULL
 | |
|       );
 | |
|   }
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Internal Function. Merge two adjacent nodes.
 | |
| 
 | |
|   @param  First             The first of two nodes to merge.
 | |
| 
 | |
|   @return Pointer to node after merge (if success) or pointer to next node (if fail).
 | |
| 
 | |
| **/
 | |
| FREE_PAGE_LIST *
 | |
| InternalMergeNodes (
 | |
|   IN FREE_PAGE_LIST  *First
 | |
|   )
 | |
| {
 | |
|   FREE_PAGE_LIST  *Next;
 | |
| 
 | |
|   Next = BASE_CR (First->Link.ForwardLink, FREE_PAGE_LIST, Link);
 | |
|   ASSERT (
 | |
|     TRUNCATE_TO_PAGES ((UINTN)Next - (UINTN)First) >= First->NumberOfPages);
 | |
| 
 | |
|   if (TRUNCATE_TO_PAGES ((UINTN)Next - (UINTN)First) == First->NumberOfPages) {
 | |
|     First->NumberOfPages += Next->NumberOfPages;
 | |
|     RemoveEntryList (&Next->Link);
 | |
|     Next = First;
 | |
|   }
 | |
|   return Next;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Frees previous allocated pages.
 | |
| 
 | |
|   @param[in]  Memory                 Base address of memory being freed.
 | |
|   @param[in]  NumberOfPages          The number of pages to free.
 | |
|   @param[in]  AddRegion              If this memory is new added region.
 | |
| 
 | |
|   @retval EFI_NOT_FOUND          Could not find the entry that covers the range.
 | |
|   @retval EFI_INVALID_PARAMETER  Address not aligned, Address is zero or NumberOfPages is zero.
 | |
|   @return EFI_SUCCESS            Pages successfully freed.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| SmmInternalFreePagesEx (
 | |
|   IN EFI_PHYSICAL_ADDRESS  Memory,
 | |
|   IN UINTN                 NumberOfPages,
 | |
|   IN BOOLEAN               AddRegion
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY      *Node;
 | |
|   FREE_PAGE_LIST  *Pages;
 | |
| 
 | |
|   if (((Memory & EFI_PAGE_MASK) != 0) || (Memory == 0) || (NumberOfPages == 0)) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   Pages = NULL;
 | |
|   Node = mSmmMemoryMap.ForwardLink;
 | |
|   while (Node != &mSmmMemoryMap) {
 | |
|     Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);
 | |
|     if (Memory < (UINTN)Pages) {
 | |
|       break;
 | |
|     }
 | |
|     Node = Node->ForwardLink;
 | |
|   }
 | |
| 
 | |
|   if (Node != &mSmmMemoryMap &&
 | |
|       Memory + EFI_PAGES_TO_SIZE (NumberOfPages) > (UINTN)Pages) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if (Node->BackLink != &mSmmMemoryMap) {
 | |
|     Pages = BASE_CR (Node->BackLink, FREE_PAGE_LIST, Link);
 | |
|     if ((UINTN)Pages + EFI_PAGES_TO_SIZE (Pages->NumberOfPages) > Memory) {
 | |
|       return EFI_INVALID_PARAMETER;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   Pages = (FREE_PAGE_LIST*)(UINTN)Memory;
 | |
|   Pages->NumberOfPages = NumberOfPages;
 | |
|   InsertTailList (Node, &Pages->Link);
 | |
| 
 | |
|   if (Pages->Link.BackLink != &mSmmMemoryMap) {
 | |
|     Pages = InternalMergeNodes (
 | |
|               BASE_CR (Pages->Link.BackLink, FREE_PAGE_LIST, Link)
 | |
|               );
 | |
|   }
 | |
| 
 | |
|   if (Node != &mSmmMemoryMap) {
 | |
|     InternalMergeNodes (Pages);
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Update SmmMemoryMap here.
 | |
|   //
 | |
|   ConvertSmmMemoryMapEntry (EfiConventionalMemory, Memory, NumberOfPages, AddRegion);
 | |
|   if (!AddRegion) {
 | |
|     CoreFreeMemoryMapStack();
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Frees previous allocated pages.
 | |
| 
 | |
|   @param[in]  Memory                 Base address of memory being freed.
 | |
|   @param[in]  NumberOfPages          The number of pages to free.
 | |
|   @param[in]  IsGuarded              Is the memory to free guarded or not.
 | |
| 
 | |
|   @retval EFI_NOT_FOUND          Could not find the entry that covers the range.
 | |
|   @retval EFI_INVALID_PARAMETER  Address not aligned, Address is zero or NumberOfPages is zero.
 | |
|   @return EFI_SUCCESS            Pages successfully freed.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| SmmInternalFreePages (
 | |
|   IN EFI_PHYSICAL_ADDRESS  Memory,
 | |
|   IN UINTN                 NumberOfPages,
 | |
|   IN BOOLEAN               IsGuarded
 | |
|   )
 | |
| {
 | |
|   if (IsGuarded) {
 | |
|     return SmmInternalFreePagesExWithGuard (Memory, NumberOfPages, FALSE);
 | |
|   }
 | |
|   return SmmInternalFreePagesEx (Memory, NumberOfPages, FALSE);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Frees previous allocated pages.
 | |
| 
 | |
|   @param  Memory                 Base address of memory being freed.
 | |
|   @param  NumberOfPages          The number of pages to free.
 | |
| 
 | |
|   @retval EFI_NOT_FOUND          Could not find the entry that covers the range.
 | |
|   @retval EFI_INVALID_PARAMETER  Address not aligned, Address is zero or NumberOfPages is zero.
 | |
|   @return EFI_SUCCESS            Pages successfully freed.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| SmmFreePages (
 | |
|   IN EFI_PHYSICAL_ADDRESS  Memory,
 | |
|   IN UINTN                 NumberOfPages
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   BOOLEAN     IsGuarded;
 | |
| 
 | |
|   IsGuarded = IsHeapGuardEnabled () && IsMemoryGuarded (Memory);
 | |
|   Status = SmmInternalFreePages (Memory, NumberOfPages, IsGuarded);
 | |
|   if (!EFI_ERROR (Status)) {
 | |
|     SmmCoreUpdateProfile (
 | |
|       (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),
 | |
|       MemoryProfileActionFreePages,
 | |
|       EfiMaxMemoryType,
 | |
|       EFI_PAGES_TO_SIZE (NumberOfPages),
 | |
|       (VOID *) (UINTN) Memory,
 | |
|       NULL
 | |
|       );
 | |
|   }
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Add free SMRAM region for use by memory service.
 | |
| 
 | |
|   @param  MemBase                Base address of memory region.
 | |
|   @param  MemLength              Length of the memory region.
 | |
|   @param  Type                   Memory type.
 | |
|   @param  Attributes             Memory region state.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| SmmAddMemoryRegion (
 | |
|   IN  EFI_PHYSICAL_ADDRESS  MemBase,
 | |
|   IN  UINT64                MemLength,
 | |
|   IN  EFI_MEMORY_TYPE       Type,
 | |
|   IN  UINT64                Attributes
 | |
|   )
 | |
| {
 | |
|   UINTN  AlignedMemBase;
 | |
| 
 | |
|   //
 | |
|   // Add EfiRuntimeServicesData for memory regions that is already allocated, needs testing, or needs ECC initialization
 | |
|   //
 | |
|   if ((Attributes & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {
 | |
|     Type = EfiRuntimeServicesData;
 | |
|   } else {
 | |
|     Type = EfiConventionalMemory;
 | |
|   }
 | |
| 
 | |
|   DEBUG ((DEBUG_INFO, "SmmAddMemoryRegion\n"));
 | |
|   DEBUG ((DEBUG_INFO, "  MemBase    - 0x%lx\n", MemBase));
 | |
|   DEBUG ((DEBUG_INFO, "  MemLength  - 0x%lx\n", MemLength));
 | |
|   DEBUG ((DEBUG_INFO, "  Type       - 0x%x\n", Type));
 | |
|   DEBUG ((DEBUG_INFO, "  Attributes - 0x%lx\n", Attributes));
 | |
| 
 | |
|   //
 | |
|   // Align range on an EFI_PAGE_SIZE boundary
 | |
|   //
 | |
|   AlignedMemBase = (UINTN)(MemBase + EFI_PAGE_MASK) & ~EFI_PAGE_MASK;
 | |
|   MemLength -= AlignedMemBase - MemBase;
 | |
|   if (Type == EfiConventionalMemory) {
 | |
|     SmmInternalFreePagesEx (AlignedMemBase, TRUNCATE_TO_PAGES ((UINTN)MemLength), TRUE);
 | |
|   } else {
 | |
|     ConvertSmmMemoryMapEntry (EfiRuntimeServicesData, AlignedMemBase, TRUNCATE_TO_PAGES ((UINTN)MemLength), TRUE);
 | |
|   }
 | |
| 
 | |
|   CoreFreeMemoryMapStack ();
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function returns a copy of the current memory map. The map is an array of
 | |
|   memory descriptors, each of which describes a contiguous block of memory.
 | |
| 
 | |
|   @param[in, out]  MemoryMapSize          A pointer to the size, in bytes, of the
 | |
|                                           MemoryMap buffer. On input, this is the size of
 | |
|                                           the buffer allocated by the caller.  On output,
 | |
|                                           it is the size of the buffer returned by the
 | |
|                                           firmware  if the buffer was large enough, or the
 | |
|                                           size of the buffer needed  to contain the map if
 | |
|                                           the buffer was too small.
 | |
|   @param[in, out]  MemoryMap              A pointer to the buffer in which firmware places
 | |
|                                           the current memory map.
 | |
|   @param[out]      MapKey                 A pointer to the location in which firmware
 | |
|                                           returns the key for the current memory map.
 | |
|   @param[out]      DescriptorSize         A pointer to the location in which firmware
 | |
|                                           returns the size, in bytes, of an individual
 | |
|                                           EFI_MEMORY_DESCRIPTOR.
 | |
|   @param[out]      DescriptorVersion      A pointer to the location in which firmware
 | |
|                                           returns the version number associated with the
 | |
|                                           EFI_MEMORY_DESCRIPTOR.
 | |
| 
 | |
|   @retval EFI_SUCCESS            The memory map was returned in the MemoryMap
 | |
|                                  buffer.
 | |
|   @retval EFI_BUFFER_TOO_SMALL   The MemoryMap buffer was too small. The current
 | |
|                                  buffer size needed to hold the memory map is
 | |
|                                  returned in MemoryMapSize.
 | |
|   @retval EFI_INVALID_PARAMETER  One of the parameters has an invalid value.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| SmmCoreGetMemoryMap (
 | |
|   IN OUT UINTN                  *MemoryMapSize,
 | |
|   IN OUT EFI_MEMORY_DESCRIPTOR  *MemoryMap,
 | |
|   OUT UINTN                     *MapKey,
 | |
|   OUT UINTN                     *DescriptorSize,
 | |
|   OUT UINT32                    *DescriptorVersion
 | |
|   )
 | |
| {
 | |
|   UINTN                    Count;
 | |
|   LIST_ENTRY               *Link;
 | |
|   MEMORY_MAP               *Entry;
 | |
|   UINTN                    Size;
 | |
|   UINTN                    BufferSize;
 | |
| 
 | |
|   Size = sizeof (EFI_MEMORY_DESCRIPTOR);
 | |
| 
 | |
|   //
 | |
|   // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will
 | |
|   // prevent people from having pointer math bugs in their code.
 | |
|   // now you have to use *DescriptorSize to make things work.
 | |
|   //
 | |
|   Size += sizeof(UINT64) - (Size % sizeof (UINT64));
 | |
| 
 | |
|   if (DescriptorSize != NULL) {
 | |
|     *DescriptorSize = Size;
 | |
|   }
 | |
| 
 | |
|   if (DescriptorVersion != NULL) {
 | |
|     *DescriptorVersion = EFI_MEMORY_DESCRIPTOR_VERSION;
 | |
|   }
 | |
| 
 | |
|   Count = GetSmmMemoryMapEntryCount ();
 | |
|   BufferSize = Size * Count;
 | |
|   if (*MemoryMapSize < BufferSize) {
 | |
|     *MemoryMapSize = BufferSize;
 | |
|     return EFI_BUFFER_TOO_SMALL;
 | |
|   }
 | |
| 
 | |
|   *MemoryMapSize = BufferSize;
 | |
|   if (MemoryMap == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   ZeroMem (MemoryMap, BufferSize);
 | |
|   Link = gMemoryMap.ForwardLink;
 | |
|   while (Link != &gMemoryMap) {
 | |
|     Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
 | |
|     Link  = Link->ForwardLink;
 | |
| 
 | |
|     MemoryMap->Type           = Entry->Type;
 | |
|     MemoryMap->PhysicalStart  = Entry->Start;
 | |
|     MemoryMap->NumberOfPages  = RShiftU64 (Entry->End - Entry->Start + 1, EFI_PAGE_SHIFT);
 | |
| 
 | |
|     MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, Size);
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 |