Cc: Wu Hao <hao.a.wu@intel.com> Cc: Star Zeng <star.zeng@intel.com> Cc: Eric Dong <eric.dong@intel.com> Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Jian J Wang <jian.j.wang@intel.com> Reviewed-by: Hao Wu <hao.a.wu@intel.com>
		
			
				
	
	
		
			1158 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1158 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  SMM Memory page management functions.
 | 
						|
 | 
						|
  Copyright (c) 2009 - 2016, 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);
 | 
						|
  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;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Dump Smm memory map entry.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
DumpSmmMemoryMapEntry (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  LIST_ENTRY               *Link;
 | 
						|
  MEMORY_MAP               *Entry;
 | 
						|
  EFI_PHYSICAL_ADDRESS     Last;
 | 
						|
 | 
						|
  Last = 0;
 | 
						|
  DEBUG ((DEBUG_INFO, "DumpSmmMemoryMapEntry:\n"));
 | 
						|
  Link = gMemoryMap.ForwardLink;
 | 
						|
  while (Link != &gMemoryMap) {
 | 
						|
    Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
 | 
						|
    Link  = Link->ForwardLink;
 | 
						|
 | 
						|
    if ((Last != 0) && (Last != (UINT64)-1)) {
 | 
						|
      if (Last + 1 != Entry->Start) {
 | 
						|
        Last = (UINT64)-1;
 | 
						|
      } else {
 | 
						|
        Last = Entry->End;
 | 
						|
      }
 | 
						|
    } else if (Last == 0) {
 | 
						|
      Last = Entry->End;
 | 
						|
    }
 | 
						|
 | 
						|
    DEBUG ((DEBUG_INFO, "Entry (Link - 0x%x)\n", &Entry->Link));
 | 
						|
    DEBUG ((DEBUG_INFO, "  Signature         - 0x%x\n", Entry->Signature));
 | 
						|
    DEBUG ((DEBUG_INFO, "  Link.ForwardLink  - 0x%x\n", Entry->Link.ForwardLink));
 | 
						|
    DEBUG ((DEBUG_INFO, "  Link.BackLink     - 0x%x\n", Entry->Link.BackLink));
 | 
						|
    DEBUG ((DEBUG_INFO, "  Type              - 0x%x\n", Entry->Type));
 | 
						|
    DEBUG ((DEBUG_INFO, "  Start             - 0x%016lx\n", Entry->Start));
 | 
						|
    DEBUG ((DEBUG_INFO, "  End               - 0x%016lx\n", Entry->End));
 | 
						|
  }
 | 
						|
 | 
						|
  ASSERT (Last != (UINT64)-1);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Dump Smm memory map.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
DumpSmmMemoryMap (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  LIST_ENTRY      *Node;
 | 
						|
  FREE_PAGE_LIST  *Pages;
 | 
						|
 | 
						|
  DEBUG ((DEBUG_INFO, "DumpSmmMemoryMap\n"));
 | 
						|
 | 
						|
  Pages = NULL;
 | 
						|
  Node = mSmmMemoryMap.ForwardLink;
 | 
						|
  while (Node != &mSmmMemoryMap) {
 | 
						|
    Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);
 | 
						|
    DEBUG ((DEBUG_INFO, "Pages - 0x%x\n", Pages));
 | 
						|
    DEBUG ((DEBUG_INFO, "Pages->NumberOfPages - 0x%x\n", Pages->NumberOfPages));
 | 
						|
    Node = Node->ForwardLink;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Check if a Smm base~length is in Smm memory map.
 | 
						|
 | 
						|
  @param[in] Base   The base address of Smm memory to be checked.
 | 
						|
  @param[in] Length THe length of Smm memory to be checked.
 | 
						|
 | 
						|
  @retval TRUE  Smm base~length is in smm memory map.
 | 
						|
  @retval FALSE Smm base~length is in smm memory map.
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
SmmMemoryMapConsistencyCheckRange (
 | 
						|
  IN EFI_PHYSICAL_ADDRESS Base,
 | 
						|
  IN UINTN                Length
 | 
						|
  )
 | 
						|
{
 | 
						|
  LIST_ENTRY               *Link;
 | 
						|
  MEMORY_MAP               *Entry;
 | 
						|
  BOOLEAN                  Result;
 | 
						|
 | 
						|
  Result = FALSE;
 | 
						|
  Link = gMemoryMap.ForwardLink;
 | 
						|
  while (Link != &gMemoryMap) {
 | 
						|
    Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);
 | 
						|
    Link  = Link->ForwardLink;
 | 
						|
 | 
						|
    if (Entry->Type != EfiConventionalMemory) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
    if (Entry->Start == Base && Entry->End == Base + Length - 1) {
 | 
						|
      Result = TRUE;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return Result;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Check the consistency of Smm memory map.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
SmmMemoryMapConsistencyCheck (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  LIST_ENTRY      *Node;
 | 
						|
  FREE_PAGE_LIST  *Pages;
 | 
						|
  BOOLEAN         Result;
 | 
						|
 | 
						|
  Pages = NULL;
 | 
						|
  Node = mSmmMemoryMap.ForwardLink;
 | 
						|
  while (Node != &mSmmMemoryMap) {
 | 
						|
    Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);
 | 
						|
    Result = SmmMemoryMapConsistencyCheckRange ((EFI_PHYSICAL_ADDRESS)(UINTN)Pages, (UINTN)EFI_PAGES_TO_SIZE(Pages->NumberOfPages));
 | 
						|
    ASSERT (Result);
 | 
						|
    Node = Node->ForwardLink;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  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;
 | 
						|
}
 |