public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Wang, Jian J" <jian.j.wang@intel.com>
To: "Dong, Eric" <eric.dong@intel.com>,
	"edk2-devel@lists.01.org" <edk2-devel@lists.01.org>
Cc: "Zeng, Star" <star.zeng@intel.com>,
	"Yao, Jiewen" <jiewen.yao@intel.com>,
	 "Kinney, Michael D" <michael.d.kinney@intel.com>,
	"Wolman, Ayellet" <ayellet.wolman@intel.com>
Subject: Re: [PATCH 2/5] MdeModulePkg/PiSmmCore: Implement heap guard feature for SMM mode
Date: Fri, 13 Oct 2017 06:15:07 +0000	[thread overview]
Message-ID: <D827630B58408649ACB04F44C510003624CA1B30@SHSMSX103.ccr.corp.intel.com> (raw)
In-Reply-To: <ED077930C258884BBCB450DB737E66224AA1A43F@SHSMSX151.ccr.corp.intel.com>

Ok. I'll change it to follow required coding style. Thanks for catching it.

> -----Original Message-----
> From: Dong, Eric
> Sent: Friday, October 13, 2017 9:27 AM
> To: Wang, Jian J <jian.j.wang@intel.com>; edk2-devel@lists.01.org
> Cc: Zeng, Star <star.zeng@intel.com>; Yao, Jiewen <jiewen.yao@intel.com>;
> Kinney, Michael D <michael.d.kinney@intel.com>; Wolman, Ayellet
> <ayellet.wolman@intel.com>
> Subject: RE: [PATCH 2/5] MdeModulePkg/PiSmmCore: Implement heap guard
> feature for SMM mode
> 
> Hi Jian,
> 
> I think below code not follow EDKII coding style, EDKII requires definition and
> assignment in different code.
> 
> +  UINTN                   LevelShift[GUARDED_HEAP_MAP_TABLE_DEPTH]
> +                            = GUARDED_HEAP_MAP_TABLE_DEPTH_SHIFTS;
> +  UINTN                   LevelMask[GUARDED_HEAP_MAP_TABLE_DEPTH]
> +                            = GUARDED_HEAP_MAP_TABLE_DEPTH_MASKS;
> 
> Thanks,
> Eric
> > -----Original Message-----
> > From: Wang, Jian J
> > Sent: Wednesday, October 11, 2017 11:18 AM
> > To: edk2-devel@lists.01.org
> > Cc: Zeng, Star <star.zeng@intel.com>; Dong, Eric <eric.dong@intel.com>; Yao,
> > Jiewen <jiewen.yao@intel.com>; Kinney, Michael D
> > <michael.d.kinney@intel.com>; Wolman, Ayellet
> > <ayellet.wolman@intel.com>
> > Subject: [PATCH 2/5] MdeModulePkg/PiSmmCore: Implement heap guard
> > feature for SMM mode
> >
> > This feature makes use of paging mechanism to add a hidden (not present)
> > page just before and after the allocated memory block. If the code tries
> > to access memory outside of the allocated part, page fault exception will
> > be triggered.
> >
> > This feature is controlled by three PCDs:
> >
> >     gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPropertyMask
> >     gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPoolType
> >     gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPageType
> >
> > BIT2 and BIT3 of PcdHeapGuardPropertyMask can be used to enable or
> > disable
> > memory guard for SMM page and pool respectively. PcdHeapGuardPoolType
> > and/or
> > PcdHeapGuardPageType are used to enable or disable guard for specific type
> > of memory. For example, we can turn on guard only for EfiBootServicesData
> > and EfiRuntimeServicesData by setting the PCD with value 0x50.
> >
> > Pool memory is not ususally integer multiple of one page, and is more likely
> > less than a page. There's no way to monitor the overflow at both top and
> > bottom of pool memory. BIT7 of PcdHeapGuardPropertyMask is used to
> > control
> > how to position the head of pool memory so that it's easier to catch memory
> > overflow in memory growing direction or in decreasing direction.
> >
> > Cc: Star Zeng <star.zeng@intel.com>
> > Cc: Eric Dong <eric.dong@intel.com>
> > Cc: Jiewen Yao <jiewen.yao@intel.com>
> > Cc: Michael Kinney <michael.d.kinney@intel.com>
> > Cc: Ayellet Wolman <ayellet.wolman@intel.com>
> > Suggested-by: Ayellet Wolman <ayellet.wolman@intel.com>
> > Contributed-under: TianoCore Contribution Agreement 1.1
> > Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
> > ---
> >  MdeModulePkg/Core/PiSmmCore/Misc/HeapGuard.c | 1438
> > ++++++++++++++++++++++++++
> >  MdeModulePkg/Core/PiSmmCore/Misc/HeapGuard.h |  395 +++++++
> >  MdeModulePkg/Core/PiSmmCore/Misc/PageTable.c |  704
> > +++++++++++++
> >  MdeModulePkg/Core/PiSmmCore/Misc/PageTable.h |  174 ++++
> >  MdeModulePkg/Core/PiSmmCore/Page.c           |   51 +-
> >  MdeModulePkg/Core/PiSmmCore/PiSmmCore.c      |   12 +-
> >  MdeModulePkg/Core/PiSmmCore/PiSmmCore.h      |   80 +-
> >  MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf    |    8 +
> >  MdeModulePkg/Core/PiSmmCore/Pool.c           |   77 +-
> >  9 files changed, 2911 insertions(+), 28 deletions(-)
> >  create mode 100644 MdeModulePkg/Core/PiSmmCore/Misc/HeapGuard.c
> >  create mode 100644 MdeModulePkg/Core/PiSmmCore/Misc/HeapGuard.h
> >  create mode 100644 MdeModulePkg/Core/PiSmmCore/Misc/PageTable.c
> >  create mode 100644 MdeModulePkg/Core/PiSmmCore/Misc/PageTable.h
> >
> > diff --git a/MdeModulePkg/Core/PiSmmCore/Misc/HeapGuard.c
> > b/MdeModulePkg/Core/PiSmmCore/Misc/HeapGuard.c
> > new file mode 100644
> > index 0000000000..c64eaea5d1
> > --- /dev/null
> > +++ b/MdeModulePkg/Core/PiSmmCore/Misc/HeapGuard.c
> > @@ -0,0 +1,1438 @@
> > +/** @file
> > +  UEFI Heap Guard functions.
> > +
> > +Copyright (c) 2017, 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 "HeapGuard.h"
> > +
> > +//
> > +// Pointer to table tracking the Guarded memory with bitmap, in which  '1'
> > +// is used to indicate memory guarded. '0' might be free memory or Guard
> > +// page itself, depending on status of memory adjacent to it.
> > +//
> > +GLOBAL_REMOVE_IF_UNREFERENCED UINT64 *mGuardedMemoryMap =
> > NULL;
> > +
> > +//
> > +// Current depth level of map table pointed by mGuardedMemoryMap.
> > +// mMapLevel must be initialized at least by 1. It will be automatically
> > +// updated according to the address of memory just tracked.
> > +//
> > +GLOBAL_REMOVE_IF_UNREFERENCED UINTN  mMapLevel = 1;
> > +
> > +//
> > +// SMM status flag
> > +//
> > +BOOLEAN mIsSmmCpuMode = FALSE;
> > +
> > +/**
> > +  Set corresponding bits in bitmap table to 1 according to the address
> > +
> > +  @param[in]  Address     Start address to set for
> > +  @param[in]  BitNumber   Number of bits to set
> > +  @param[in]  BitMap      Pointer to bitmap which covers the Address
> > +
> > +  @return VOID
> > +**/
> > +STATIC
> > +VOID
> > +SetBits (
> > +  IN EFI_PHYSICAL_ADDRESS    Address,
> > +  IN UINTN                   BitNumber,
> > +  IN UINT64                  *BitMap
> > +  )
> > +{
> > +  UINTN           Lsbs;
> > +  UINTN           Qwords;
> > +  UINTN           Msbs;
> > +  UINTN           StartBit;
> > +  UINTN           EndBit;
> > +
> > +  StartBit  = (UINTN)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address);
> > +  EndBit    = (StartBit + BitNumber - 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
> > +
> > +  if ((StartBit + BitNumber) > GUARDED_HEAP_MAP_ENTRY_BITS) {
> > +    Msbs    = (GUARDED_HEAP_MAP_ENTRY_BITS - StartBit) %
> > +              GUARDED_HEAP_MAP_ENTRY_BITS;
> > +    Lsbs    = (EndBit + 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
> > +    Qwords  = (BitNumber - Msbs) / GUARDED_HEAP_MAP_ENTRY_BITS;
> > +  } else {
> > +    Msbs    = BitNumber;
> > +    Lsbs    = 0;
> > +    Qwords  = 0;
> > +  }
> > +
> > +  if (Msbs > 0) {
> > +    *BitMap |= LShiftU64 (LShiftU64 (1, Msbs) - 1, StartBit);
> > +    BitMap  += 1;
> > +  }
> > +
> > +  if (Qwords > 0) {
> > +    SetMem64 ((VOID *)BitMap, Qwords *
> > GUARDED_HEAP_MAP_ENTRY_BYTES,
> > +              (UINT64)-1);
> > +    BitMap += Qwords;
> > +  }
> > +
> > +  if (Lsbs > 0) {
> > +    *BitMap |= (LShiftU64 (1, Lsbs) - 1);
> > +  }
> > +}
> > +
> > +/**
> > +  Set corresponding bits in bitmap table to 0 according to the address
> > +
> > +  @param[in]  Address     Start address to set for
> > +  @param[in]  BitNumber   Number of bits to set
> > +  @param[in]  BitMap      Pointer to bitmap which covers the Address
> > +
> > +  @return VOID
> > +**/
> > +STATIC
> > +VOID
> > +ClearBits (
> > +  IN EFI_PHYSICAL_ADDRESS    Address,
> > +  IN UINTN                   BitNumber,
> > +  IN UINT64                  *BitMap
> > +  )
> > +{
> > +  UINTN           Lsbs;
> > +  UINTN           Qwords;
> > +  UINTN           Msbs;
> > +  UINTN           StartBit;
> > +  UINTN           EndBit;
> > +
> > +  StartBit  = (UINTN)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address);
> > +  EndBit    = (StartBit + BitNumber - 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
> > +
> > +  if ((StartBit + BitNumber) > GUARDED_HEAP_MAP_ENTRY_BITS) {
> > +    Msbs    = (GUARDED_HEAP_MAP_ENTRY_BITS - StartBit) %
> > +              GUARDED_HEAP_MAP_ENTRY_BITS;
> > +    Lsbs    = (EndBit + 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
> > +    Qwords  = (BitNumber - Msbs) / GUARDED_HEAP_MAP_ENTRY_BITS;
> > +  } else {
> > +    Msbs    = BitNumber;
> > +    Lsbs    = 0;
> > +    Qwords  = 0;
> > +  }
> > +
> > +  if (Msbs > 0) {
> > +    *BitMap &= ~LShiftU64 (LShiftU64 (1, Msbs) - 1, StartBit);
> > +    BitMap  += 1;
> > +  }
> > +
> > +  if (Qwords > 0) {
> > +    SetMem64 ((VOID *)BitMap, Qwords *
> > GUARDED_HEAP_MAP_ENTRY_BYTES, 0);
> > +    BitMap += Qwords;
> > +  }
> > +
> > +  if (Lsbs > 0) {
> > +    *BitMap &= ~(LShiftU64 (1, Lsbs) - 1);
> > +  }
> > +}
> > +
> > +/**
> > +  Get corresponding bits in bitmap table according to the address
> > +
> > +  The value of bit 0 corresponds to the status of memory at given Address.
> > +  No more than 64 bits can be retrieved in one call.
> > +
> > +  @param[in]  Address     Start address to retrieve bits for
> > +  @param[in]  BitNumber   Number of bits to get
> > +  @param[in]  BitMap      Pointer to bitmap which covers the Address
> > +
> > +  @return An integer containing the bits information
> > +**/
> > +STATIC
> > +UINT64
> > +GetBits (
> > +  IN EFI_PHYSICAL_ADDRESS    Address,
> > +  IN UINTN                   BitNumber,
> > +  IN UINT64                  *BitMap
> > +  )
> > +{
> > +  UINTN           StartBit;
> > +  UINTN           EndBit;
> > +  UINTN           Lsbs;
> > +  UINTN           Msbs;
> > +  UINT64          Result;
> > +
> > +  ASSERT (BitNumber <= GUARDED_HEAP_MAP_ENTRY_BITS);
> > +
> > +  StartBit  = (UINTN)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address);
> > +  EndBit    = (StartBit + BitNumber - 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
> > +
> > +  if ((StartBit + BitNumber) > GUARDED_HEAP_MAP_ENTRY_BITS) {
> > +    Msbs = GUARDED_HEAP_MAP_ENTRY_BITS - StartBit;
> > +    Lsbs = (EndBit + 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
> > +  } else {
> > +    Msbs = BitNumber;
> > +    Lsbs = 0;
> > +  }
> > +
> > +  Result    = RShiftU64 ((*BitMap), StartBit) & (LShiftU64 (1, Msbs) - 1);
> > +  if (Lsbs > 0) {
> > +    BitMap  += 1;
> > +    Result  |= LShiftU64 ((*BitMap) & (LShiftU64 (1, Lsbs) - 1), Msbs);
> > +  }
> > +
> > +  return Result;
> > +}
> > +
> > +/**
> > +  Helper function to allocate pages without Guard for internal uses
> > +
> > +  @param[in]  Pages       Page number
> > +
> > +  @return Address of memory allocated
> > +**/
> > +VOID *
> > +PageAlloc (
> > +  IN UINTN  Pages
> > +  )
> > +{
> > +  EFI_STATUS              Status;
> > +  EFI_PHYSICAL_ADDRESS    Memory;
> > +
> > +  Status = SmmInternalAllocatePages (AllocateAnyPages,
> > EfiRuntimeServicesData,
> > +                                     Pages, &Memory, FALSE);
> > +  if (EFI_ERROR (Status)) {
> > +    Memory = 0;
> > +  }
> > +
> > +  return (VOID *)(UINTN)Memory;
> > +}
> > +
> > +/**
> > +  Locate the pointer of bitmap from the guarded memory bitmap tables,
> > which
> > +  covers the given Address.
> > +
> > +  @param[in]  Address       Start address to search the bitmap for
> > +  @param[in]  AllocMapUnit  Flag to indicate memory allocation for the table
> > +  @param[out] BitMap        Pointer to bitmap which covers the Address
> > +
> > +  @return The bit number from given Address to the end of current map
> > table
> > +**/
> > +UINTN
> > +FindGuardedMemoryMap (
> > +  IN  EFI_PHYSICAL_ADDRESS    Address,
> > +  IN  BOOLEAN                 AllocMapUnit,
> > +  OUT UINT64                  **BitMap
> > +  )
> > +{
> > +  UINTN                   Level;
> > +  UINTN                   LevelShift[GUARDED_HEAP_MAP_TABLE_DEPTH]
> > +                            = GUARDED_HEAP_MAP_TABLE_DEPTH_SHIFTS;
> > +  UINTN                   LevelMask[GUARDED_HEAP_MAP_TABLE_DEPTH]
> > +                            = GUARDED_HEAP_MAP_TABLE_DEPTH_MASKS;
> > +  UINT64                  **GuardMap;
> > +  UINT64                  *MapMemory;
> > +  UINTN                   Index;
> > +  UINTN                   Size;
> > +  UINTN                   BitsToUnitEnd;
> > +
> > +  //
> > +  // Adjust current map table depth according to the address to access
> > +  //
> > +  while (mMapLevel < GUARDED_HEAP_MAP_TABLE_DEPTH
> > +         &&
> > +         RShiftU64 (
> > +           Address,
> > +           LevelShift[GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel - 1]
> > +           ) != 0) {
> > +
> > +    if (mGuardedMemoryMap != NULL) {
> > +      Size = (LevelMask[GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel -
> > 1] + 1)
> > +             * GUARDED_HEAP_MAP_ENTRY_BYTES;
> > +      MapMemory = PageAlloc (EFI_SIZE_TO_PAGES (Size));
> > +      ASSERT (MapMemory != NULL);
> > +
> > +      SetMem ((VOID *)MapMemory, Size, 0);
> > +
> > +      *(UINT64 **)MapMemory = mGuardedMemoryMap;
> > +      mGuardedMemoryMap     = MapMemory;
> > +    }
> > +
> > +    mMapLevel++;
> > +
> > +  }
> > +
> > +  GuardMap = &mGuardedMemoryMap;
> > +  for (Level = GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel;
> > +       Level < GUARDED_HEAP_MAP_TABLE_DEPTH;
> > +       ++Level) {
> > +
> > +    if (*GuardMap == NULL) {
> > +      if (!AllocMapUnit) {
> > +        GuardMap = NULL;
> > +        break;
> > +      }
> > +
> > +      Size = (LevelMask[Level] + 1) * GUARDED_HEAP_MAP_ENTRY_BYTES;
> > +      MapMemory = PageAlloc (EFI_SIZE_TO_PAGES (Size));
> > +      ASSERT (MapMemory != NULL);
> > +
> > +      SetMem ((VOID *)MapMemory, Size, 0);
> > +      *GuardMap = (UINT64 *)MapMemory;
> > +    }
> > +
> > +    Index     = (UINTN)RShiftU64 (Address, LevelShift[Level]);
> > +    Index     &= LevelMask[Level];
> > +    GuardMap  = (UINT64 **)((*GuardMap) + Index);
> > +
> > +  }
> > +
> > +  BitsToUnitEnd = GUARDED_HEAP_MAP_BITS -
> > GUARDED_HEAP_MAP_BIT_INDEX (Address);
> > +  *BitMap       = (UINT64 *)GuardMap;
> > +
> > +  return BitsToUnitEnd;
> > +}
> > +
> > +/**
> > +  Set corresponding bits in bitmap table to 1 according to given memory
> > range
> > +
> > +  @param[in]  Address       Memory address to guard from
> > +  @param[in]  NumberOfPages Number of pages to guard
> > +
> > +  @return VOID
> > +**/
> > +VOID
> > +EFIAPI
> > +SetGuardedMemoryBits (
> > +  IN EFI_PHYSICAL_ADDRESS    Address,
> > +  IN UINTN                   NumberOfPages
> > +  )
> > +{
> > +  UINT64            *BitMap;
> > +  UINTN             Bits;
> > +  UINTN             BitsToUnitEnd;
> > +
> > +  while (NumberOfPages > 0) {
> > +    BitsToUnitEnd = FindGuardedMemoryMap (Address, TRUE, &BitMap);
> > +    ASSERT (BitMap != NULL);
> > +
> > +    if (NumberOfPages > BitsToUnitEnd) {
> > +      // Cross map unit
> > +      Bits = BitsToUnitEnd;
> > +    } else {
> > +      Bits  = NumberOfPages;
> > +    }
> > +
> > +    SetBits (Address, Bits, BitMap);
> > +
> > +    NumberOfPages -= Bits;
> > +    Address       += EFI_PAGES_TO_SIZE (Bits);
> > +  }
> > +}
> > +
> > +/**
> > +  Clear corresponding bits in bitmap table according to given memory range
> > +
> > +  @param[in]  Address       Memory address to unset from
> > +  @param[in]  NumberOfPages Number of pages to unset guard
> > +
> > +  @return VOID
> > +**/
> > +VOID
> > +EFIAPI
> > +ClearGuardedMemoryBits (
> > +  IN EFI_PHYSICAL_ADDRESS    Address,
> > +  IN UINTN                   NumberOfPages
> > +  )
> > +{
> > +  UINT64            *BitMap;
> > +  UINTN             Bits;
> > +  UINTN             BitsToUnitEnd;
> > +
> > +  while (NumberOfPages > 0) {
> > +    BitsToUnitEnd = FindGuardedMemoryMap (Address, TRUE, &BitMap);
> > +    ASSERT (BitMap != NULL);
> > +
> > +    if (NumberOfPages > BitsToUnitEnd) {
> > +      // Cross map unit
> > +      Bits = BitsToUnitEnd;
> > +    } else {
> > +      Bits  = NumberOfPages;
> > +    }
> > +
> > +    ClearBits (Address, Bits, BitMap);
> > +
> > +    NumberOfPages -= Bits;
> > +    Address       += EFI_PAGES_TO_SIZE (Bits);
> > +  }
> > +}
> > +
> > +/**
> > +  Retrieve corresponding bits in bitmap table according to given memory
> > range
> > +
> > +  @param[in]  Address       Memory address to retrieve from
> > +  @param[in]  NumberOfPages Number of pages to retrieve
> > +
> > +  @return VOID
> > +**/
> > +UINTN
> > +GetGuardedMemoryBits (
> > +  IN EFI_PHYSICAL_ADDRESS    Address,
> > +  IN UINTN                   NumberOfPages
> > +  )
> > +{
> > +  UINT64            *BitMap;
> > +  UINTN             Bits;
> > +  UINTN             Result;
> > +  UINTN             Shift;
> > +  UINTN             BitsToUnitEnd;
> > +
> > +  ASSERT (NumberOfPages <= GUARDED_HEAP_MAP_ENTRY_BITS);
> > +
> > +  Result = 0;
> > +  Shift  = 0;
> > +  while (NumberOfPages > 0) {
> > +    BitsToUnitEnd = FindGuardedMemoryMap (Address, FALSE, &BitMap);
> > +
> > +    if (NumberOfPages > BitsToUnitEnd) {
> > +      // Cross map unit
> > +      Bits  = BitsToUnitEnd;
> > +    } else {
> > +      Bits  = NumberOfPages;
> > +    }
> > +
> > +    if (BitMap != NULL) {
> > +      Result |= LShiftU64 (GetBits (Address, Bits, BitMap), Shift);
> > +    }
> > +
> > +    Shift         += Bits;
> > +    NumberOfPages -= Bits;
> > +    Address       += EFI_PAGES_TO_SIZE (Bits);
> > +  }
> > +
> > +  return Result;
> > +}
> > +
> > +/**
> > +  Get bit value in bitmap table for the given address
> > +
> > +  @param[in]  Address     The address to retrieve for
> > +
> > +  @return 1 or 0
> > +**/
> > +UINTN
> > +EFIAPI
> > +GetGuardMapBit (
> > +  IN EFI_PHYSICAL_ADDRESS    Address
> > +  )
> > +{
> > +  UINT64        *GuardMap;
> > +
> > +  FindGuardedMemoryMap (Address, FALSE, &GuardMap);
> > +  if (GuardMap != NULL) {
> > +    if (RShiftU64 (*GuardMap,
> > +                   GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address)) & 1) {
> > +      return 1;
> > +    }
> > +  }
> > +
> > +  return 0;
> > +}
> > +
> > +/**
> > +  Set the bit in bitmap table for the given address
> > +
> > +  @param[in]  Address     The address to set for
> > +
> > +  @return VOID
> > +**/
> > +VOID
> > +EFIAPI
> > +SetGuardMapBit (
> > +  IN EFI_PHYSICAL_ADDRESS    Address
> > +  )
> > +{
> > +  UINT64        *GuardMap;
> > +  UINT64        BitMask;
> > +
> > +  FindGuardedMemoryMap (Address, TRUE, &GuardMap);
> > +  if (GuardMap != NULL) {
> > +    BitMask = LShiftU64 (1, GUARDED_HEAP_MAP_ENTRY_BIT_INDEX
> > (Address));
> > +    *GuardMap |= BitMask;
> > +  }
> > +}
> > +
> > +/**
> > +  Clear the bit in bitmap table for the given address
> > +
> > +  @param[in]  Address     The address to clear for
> > +
> > +  @return VOID
> > +**/
> > +VOID
> > +EFIAPI
> > +ClearGuardMapBit (
> > +  IN EFI_PHYSICAL_ADDRESS    Address
> > +  )
> > +{
> > +  UINT64        *GuardMap;
> > +  UINTN         BitMask;
> > +
> > +  FindGuardedMemoryMap (Address, TRUE, &GuardMap);
> > +  if (GuardMap != NULL) {
> > +    BitMask = LShiftU64 (1, GUARDED_HEAP_MAP_ENTRY_BIT_INDEX
> > (Address));
> > +    *GuardMap &= ~BitMask;
> > +  }
> > +}
> > +
> > +/**
> > +  Check to see if the page at the given address is a Guard page or not
> > +
> > +  @param[in]  Address     The address to check for
> > +
> > +  @return TRUE  The page at Address is a Guard page
> > +  @return FALSE The page at Address is not a Guard page
> > +**/
> > +BOOLEAN
> > +EFIAPI
> > +IsGuardPage (
> > +  IN EFI_PHYSICAL_ADDRESS    Address
> > +  )
> > +{
> > +  UINTN       BitMap;
> > +
> > +  BitMap = GetGuardedMemoryBits (Address - EFI_PAGE_SIZE, 3);
> > +  return (BitMap == 0b001 || BitMap == 0b100 || BitMap == 0b101);
> > +}
> > +
> > +/**
> > +  Check to see if the page at the given address is a head Guard page or not
> > +
> > +  @param[in]  Address     The address to check for
> > +
> > +  @return TRUE  The page at Address is a head Guard page
> > +  @return FALSE The page at Address is not a head Guard page
> > +**/
> > +BOOLEAN
> > +EFIAPI
> > +IsHeadGuard (
> > +  IN EFI_PHYSICAL_ADDRESS    Address
> > +  )
> > +{
> > +  return (GetGuardedMemoryBits (Address, 2) == 0b10);
> > +}
> > +
> > +/**
> > +  Check to see if the page at the given address is a tail Guard page or not
> > +
> > +  @param[in]  Address     The address to check for
> > +
> > +  @return TRUE  The page at Address is a tail Guard page
> > +  @return FALSE The page at Address is not a tail Guard page
> > +**/
> > +BOOLEAN
> > +EFIAPI
> > +IsTailGuard (
> > +  IN EFI_PHYSICAL_ADDRESS    Address
> > +  )
> > +{
> > +  return (GetGuardedMemoryBits (Address - EFI_PAGE_SIZE, 2) == 0b01);
> > +}
> > +
> > +/**
> > +  Check to see if the page at the given address is guarded or not
> > +
> > +  @param[in]  Address     The address to check for
> > +
> > +  @return TRUE  The page at Address is guarded
> > +  @return FALSE The page at Address is not guarded
> > +**/
> > +BOOLEAN
> > +EFIAPI
> > +IsMemoryGuarded (
> > +  IN EFI_PHYSICAL_ADDRESS    Address
> > +  )
> > +{
> > +  return (GetGuardMapBit (Address) == 1);
> > +}
> > +
> > +/**
> > +  Set the page at the given address to be a Guard page.
> > +
> > +  This is done by changing the page table attribute to be NOT PRSENT.
> > +
> > +  @param[in]  Address     Page address to Guard at
> > +
> > +  @return VOID
> > +**/
> > +VOID
> > +EFIAPI
> > +SetGuardPage (
> > +  IN  EFI_PHYSICAL_ADDRESS      BaseAddress
> > +  )
> > +{
> > +  if (mIsSmmCpuMode) {
> > +    SmmSetMemoryAttributes (BaseAddress, EFI_PAGE_SIZE,
> > EFI_MEMORY_RP);
> > +  }
> > +}
> > +
> > +/**
> > +  Unset the Guard page at the given address to the normal memory.
> > +
> > +  This is done by changing the page table attribute to be PRSENT.
> > +
> > +  @param[in]  Address     Page address to Guard at
> > +
> > +  @return VOID
> > +**/
> > +VOID
> > +EFIAPI
> > +UnsetGuardPage (
> > +  IN  EFI_PHYSICAL_ADDRESS      BaseAddress
> > +  )
> > +{
> > +  if (mIsSmmCpuMode) {
> > +    SmmClearMemoryAttributes (BaseAddress, EFI_PAGE_SIZE,
> > EFI_MEMORY_RP);
> > +  }
> > +}
> > +
> > +/**
> > +  Check to see if the memory at the given address should be guarded or not
> > +
> > +  @param[in]  MemoryType      Memory type to check
> > +  @param[in]  AllocateType    Allocation type to check
> > +  @param[in]  PageOrPool      Indicate a page allocation or pool allocation
> > +
> > +
> > +  @return TRUE  The given type of memory should be guarded
> > +  @return FALSE The given type of memory should not be guarded
> > +**/
> > +BOOLEAN
> > +IsMemoryTypeToGuard (
> > +  IN EFI_MEMORY_TYPE        MemoryType,
> > +  IN EFI_ALLOCATE_TYPE      AllocateType,
> > +  IN UINT8                  PageOrPool
> > +  )
> > +{
> > +  UINT64 TestBit;
> > +  UINT64 ConfigBit;
> > +
> > +  if ((PcdGet8 (PcdHeapGuardPropertyMask) & PageOrPool) == 0 ||
> > +      AllocateType == AllocateAddress) {
> > +    return FALSE;
> > +  }
> > +
> > +  ConfigBit = 0;
> > +  if (PageOrPool & GUARD_HEAP_TYPE_POOL) {
> > +    ConfigBit |= PcdGet64 (PcdHeapGuardPoolType);
> > +  }
> > +
> > +  if (PageOrPool & GUARD_HEAP_TYPE_PAGE) {
> > +    ConfigBit |= PcdGet64 (PcdHeapGuardPageType);
> > +  }
> > +
> > +  if (MemoryType == EfiRuntimeServicesData ||
> > +      MemoryType == EfiRuntimeServicesCode) {
> > +    TestBit = LShiftU64 (1, MemoryType);
> > +  } else if (MemoryType == EfiMaxMemoryType) {
> > +    TestBit = (UINT64)-1;
> > +  } else {
> > +    TestBit = 0;
> > +  }
> > +
> > +  return ((ConfigBit & TestBit) != 0);
> > +}
> > +
> > +/**
> > +  Check to see if the pool at the given address should be guarded or not
> > +
> > +  @param[in]  MemoryType      Pool type to check
> > +
> > +
> > +  @return TRUE  The given type of pool should be guarded
> > +  @return FALSE The given type of pool should not be guarded
> > +**/
> > +BOOLEAN
> > +IsPoolTypeToGuard (
> > +  IN EFI_MEMORY_TYPE        MemoryType
> > +  )
> > +{
> > +  return IsMemoryTypeToGuard (MemoryType, AllocateAnyPages,
> > +                              GUARD_HEAP_TYPE_POOL);
> > +}
> > +
> > +/**
> > +  Check to see if the page at the given address should be guarded or not
> > +
> > +  @param[in]  MemoryType      Page type to check
> > +  @param[in]  AllocateType    Allocation type to check
> > +
> > +  @return TRUE  The given type of page should be guarded
> > +  @return FALSE The given type of page should not be guarded
> > +**/
> > +BOOLEAN
> > +IsPageTypeToGuard (
> > +  IN EFI_MEMORY_TYPE        MemoryType,
> > +  IN EFI_ALLOCATE_TYPE      AllocateType
> > +  )
> > +{
> > +  return IsMemoryTypeToGuard (MemoryType, AllocateType,
> > GUARD_HEAP_TYPE_PAGE);
> > +}
> > +
> > +/**
> > +  Check to see if the heap guard is enabled for page and/or pool allocation
> > +
> > +  @return TRUE/FALSE
> > +**/
> > +BOOLEAN
> > +IsHeapGuardEnabled (
> > +  VOID
> > +  )
> > +{
> > +  return IsMemoryTypeToGuard (EfiMaxMemoryType, AllocateAnyPages,
> > +                              GUARD_HEAP_TYPE_POOL|GUARD_HEAP_TYPE_PAGE);
> > +}
> > +
> > +/**
> > +  Set head Guard and tail Guard for the given memory range
> > +
> > +  @param[in]  Memory          Base address of memory to set guard for
> > +  @param[in]  NumberOfPages   Memory size in pages
> > +
> > +  @return VOID
> > +**/
> > +VOID
> > +SetGuardForMemory (
> > +  IN EFI_PHYSICAL_ADDRESS   Memory,
> > +  IN UINTN                  NumberOfPages
> > +  )
> > +{
> > +  EFI_PHYSICAL_ADDRESS    GuardPage;
> > +
> > +  //
> > +  // Set tail Guard
> > +  //
> > +  GuardPage = Memory + EFI_PAGES_TO_SIZE (NumberOfPages);
> > +  if (!IsGuardPage (GuardPage)) {
> > +    SetGuardPage (GuardPage);
> > +  }
> > +
> > +  // Set head Guard
> > +  GuardPage = Memory - EFI_PAGES_TO_SIZE (1);
> > +  if (!IsGuardPage (GuardPage)) {
> > +    SetGuardPage (GuardPage);
> > +  }
> > +
> > +  //
> > +  // Mark the memory range as Guarded
> > +  //
> > +  SetGuardedMemoryBits (Memory, NumberOfPages);
> > +}
> > +
> > +/**
> > +  Unset head Guard and tail Guard for the given memory range
> > +
> > +  @param[in]  Memory          Base address of memory to unset guard for
> > +  @param[in]  NumberOfPages   Memory size in pages
> > +
> > +  @return VOID
> > +**/
> > +VOID
> > +UnsetGuardForMemory (
> > +  IN EFI_PHYSICAL_ADDRESS   Memory,
> > +  IN UINTN                  NumberOfPages
> > +  )
> > +{
> > +  EFI_PHYSICAL_ADDRESS  GuardPage;
> > +
> > +  if (NumberOfPages == 0) {
> > +    return;
> > +  }
> > +
> > +  //
> > +  // Head Guard must be one page before, if any.
> > +  //
> > +  GuardPage = Memory - EFI_PAGES_TO_SIZE (1);
> > +  if (IsHeadGuard (GuardPage)) {
> > +    if (!IsMemoryGuarded (GuardPage - EFI_PAGES_TO_SIZE (1))) {
> > +      //
> > +      // If the head Guard is not a tail Guard of adjacent memory block,
> > +      // unset it.
> > +      //
> > +      UnsetGuardPage (GuardPage);
> > +    }
> > +  } else if (IsMemoryGuarded (GuardPage)) {
> > +    //
> > +    // Pages before memory to free are still in Guard. It's a partial free
> > +    // case. Turn first page of memory block to free into a new Guard.
> > +    //
> > +    SetGuardPage (Memory);
> > +  }
> > +
> > +  //
> > +  // Tail Guard must be the page after this memory block to free, if any.
> > +  //
> > +  GuardPage = Memory + EFI_PAGES_TO_SIZE (NumberOfPages);
> > +  if (IsTailGuard (GuardPage)) {
> > +    if (!IsMemoryGuarded (GuardPage + EFI_PAGES_TO_SIZE (1))) {
> > +      //
> > +      // If the tail Guard is not a head Guard of adjacent memory block,
> > +      // free it; otherwise, keep it.
> > +      //
> > +      UnsetGuardPage (GuardPage);
> > +    }
> > +  } else if (IsMemoryGuarded (GuardPage)) {
> > +    //
> > +    // Pages after memory to free are still in Guard. It's a partial free
> > +    // case. We need to keep one page to be a head Guard.
> > +    //
> > +    SetGuardPage (GuardPage - EFI_PAGES_TO_SIZE (1));
> > +  }
> > +
> > +  //
> > +  // No matter what, we just clear the mark of the Guarded memory.
> > +  //
> > +  ClearGuardedMemoryBits(Memory, NumberOfPages);
> > +}
> > +
> > +/**
> > +  Adjust address of free memory according to existing and/or required
> > Guard
> > +
> > +  This function will check if there're existing Guard pages of adjacent
> > +  memory blocks, and try to use it as the Guard page of the memory to be
> > +  allocated.
> > +
> > +  @param[in]  Start           Start address of free memory block
> > +  @param[in]  Size            Size of free memory block
> > +  @param[in]  SizeRequested   Size of memory to allocate
> > +
> > +  @return The end address of memory block found
> > +  @return 0 if no enough space for the required size of memory and its
> > Guard
> > +**/
> > +UINT64
> > +AdjustMemoryS (
> > +  IN UINT64                  Start,
> > +  IN UINT64                  Size,
> > +  IN UINT64                  SizeRequested
> > +  )
> > +{
> > +  UINT64  Target;
> > +
> > +  Target = Start + Size - SizeRequested;
> > +
> > +  //
> > +  // At least one more page needed for Guard page.
> > +  //
> > +  if (Size < (SizeRequested + EFI_PAGES_TO_SIZE (1))) {
> > +    return 0;
> > +  }
> > +
> > +  if (!IsGuardPage (Start + Size)) {
> > +    // No Guard at tail to share. One more page is needed.
> > +    Target -= EFI_PAGES_TO_SIZE (1);
> > +  }
> > +
> > +  // Out of range?
> > +  if (Target < Start) {
> > +    return 0;
> > +  }
> > +
> > +  // At the edge?
> > +  if (Target == Start) {
> > +    if (!IsGuardPage (Target - EFI_PAGES_TO_SIZE (1))) {
> > +      // No enough space for a new head Guard if no Guard at head to share.
> > +      return 0;
> > +    }
> > +  }
> > +
> > +  // OK, we have enough pages for memory and its Guards. Return the End
> > of the
> > +  // free space.
> > +  return Target + SizeRequested - 1;
> > +}
> > +
> > +/**
> > +  Adjust the start address and number of pages to free according to Guard
> > +
> > +  The purpose of this function is to keep the shared Guard page with
> > adjacent
> > +  memory block if it's still in guard, or free it if no more sharing. Another
> > +  is to reserve pages as Guard pages in partial page free situation.
> > +
> > +  @param[in/out]  Memory          Base address of memory to free
> > +  @param[in/out]  NumberOfPages   Size of memory to free
> > +
> > +  @return VOID
> > +**/
> > +VOID
> > +AdjustMemoryF (
> > +  IN OUT EFI_PHYSICAL_ADDRESS    *Memory,
> > +  IN OUT UINTN                   *NumberOfPages
> > +  )
> > +{
> > +  EFI_PHYSICAL_ADDRESS  Start;
> > +  EFI_PHYSICAL_ADDRESS  MemoryToTest;
> > +  UINTN                 PagesToFree;
> > +
> > +  if (Memory == NULL || NumberOfPages == NULL || *NumberOfPages ==
> > 0) {
> > +    return;
> > +  }
> > +
> > +  Start = *Memory;
> > +  PagesToFree = *NumberOfPages;
> > +
> > +  //
> > +  // Head Guard must be one page before, if any.
> > +  //
> > +  MemoryToTest = Start - EFI_PAGES_TO_SIZE (1);
> > +  if (IsHeadGuard (MemoryToTest)) {
> > +    if (!IsMemoryGuarded (MemoryToTest - EFI_PAGES_TO_SIZE (1))) {
> > +      //
> > +      // If the head Guard is not a tail Guard of adjacent memory block,
> > +      // free it; otherwise, keep it.
> > +      //
> > +      Start       -= EFI_PAGES_TO_SIZE (1);
> > +      PagesToFree += 1;
> > +    }
> > +  } else if (IsMemoryGuarded (MemoryToTest)) {
> > +    //
> > +    // Pages before memory to free are still in Guard. It's a partial free
> > +    // case. We need to keep one page to be a tail Guard.
> > +    //
> > +    Start       += EFI_PAGES_TO_SIZE (1);
> > +    PagesToFree -= 1;
> > +  }
> > +
> > +  //
> > +  // Tail Guard must be the page after this memory block to free, if any.
> > +  //
> > +  MemoryToTest = Start + EFI_PAGES_TO_SIZE (PagesToFree);
> > +  if (IsTailGuard (MemoryToTest)) {
> > +    if (!IsMemoryGuarded (MemoryToTest + EFI_PAGES_TO_SIZE (1))) {
> > +      //
> > +      // If the tail Guard is not a head Guard of adjacent memory block,
> > +      // free it; otherwise, keep it.
> > +      //
> > +      PagesToFree += 1;
> > +    }
> > +  } else if (IsMemoryGuarded (MemoryToTest)) {
> > +    //
> > +    // Pages after memory to free are still in Guard. It's a partial free
> > +    // case. We need to keep one page to be a head Guard.
> > +    //
> > +    PagesToFree -= 1;
> > +  }
> > +
> > +  *Memory         = Start;
> > +  *NumberOfPages  = PagesToFree;
> > +}
> > +
> > +/**
> > +  Adjust the base and number of pages to really allocate according to Guard
> > +
> > +  @param[in/out]  Memory          Base address of free memory
> > +  @param[in/out]  NumberOfPages   Size of memory to allocate
> > +
> > +  @return VOID
> > +**/
> > +VOID
> > +AdjustMemoryA (
> > +  IN OUT EFI_PHYSICAL_ADDRESS    *Memory,
> > +  IN OUT UINTN                   *NumberOfPages
> > +  )
> > +{
> > +  //
> > +  // FindFreePages() has already taken the Guard into account. It's safe to
> > +  // adjust the start address and/or number of pages here, to make sure
> > that
> > +  // the Guards are also "allocated".
> > +  //
> > +  if (!IsGuardPage (*Memory + EFI_PAGES_TO_SIZE (*NumberOfPages))) {
> > +    // No tail Guard, add one.
> > +    *NumberOfPages += 1;
> > +  }
> > +
> > +  if (!IsGuardPage (*Memory - EFI_PAGE_SIZE)) {
> > +    // No head Guard, add one.
> > +    *Memory        -= EFI_PAGE_SIZE;
> > +    *NumberOfPages += 1;
> > +  }
> > +}
> > +
> > +/**
> > +  Adjust the pool head position to make sure the Guard page is adjavent to
> > +  pool tail or pool head.
> > +
> > +  @param[in]  Memory    Base address of memory allocated
> > +  @param[in]  NoPages   Number of pages actually allocated
> > +  @param[in]  Size      Size of memory requested
> > +                        (plus pool head/tail overhead)
> > +
> > +  @return Address of pool head
> > +**/
> > +VOID *
> > +AdjustPoolHeadA (
> > +  IN EFI_PHYSICAL_ADDRESS    Memory,
> > +  IN UINTN                   NoPages,
> > +  IN UINTN                   Size
> > +  )
> > +{
> > +  if ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) != 0) {
> > +    //
> > +    // Pool head is put near the head Guard
> > +    //
> > +    return (VOID *)(UINTN)Memory;
> > +  }
> > +
> > +  //
> > +  // Pool head is put near the tail Guard
> > +  //
> > +  return (VOID *)(UINTN)(Memory + EFI_PAGES_TO_SIZE (NoPages) - Size);
> > +}
> > +
> > +/**
> > +  Get the page base address according to pool head address
> > +
> > +  @param[in]  Memory    Head address of pool to free
> > +
> > +  @return Address of pool head
> > +**/
> > +VOID *
> > +AdjustPoolHeadF (
> > +  IN EFI_PHYSICAL_ADDRESS    Memory
> > +  )
> > +{
> > +  if ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) != 0) {
> > +    //
> > +    // Pool head is put near the head Guard
> > +    //
> > +    return (VOID *)(UINTN)Memory;
> > +  }
> > +
> > +  //
> > +  // Pool head is put near the tail Guard
> > +  //
> > +  return (VOID *)(UINTN)(Memory & ~EFI_PAGE_MASK);
> > +}
> > +
> > +/**
> > +  Helper function of memory allocation with Guard pages
> > +
> > +  @param  FreePageList           The free page node.
> > +  @param  NumberOfPages          Number of pages to be allocated.
> > +  @param  MaxAddress             Request to allocate memory below this
> > address.
> > +  @param  MemoryType             Type of memory requested.
> > +
> > +  @return Memory address of allocated pages.
> > +**/
> > +UINTN
> > +InternalAllocMaxAddressWithGuard (
> > +  IN OUT LIST_ENTRY           *FreePageList,
> > +  IN     UINTN                NumberOfPages,
> > +  IN     UINTN                MaxAddress,
> > +  IN     EFI_MEMORY_TYPE      MemoryType
> > +
> > +  )
> > +{
> > +  LIST_ENTRY      *Node;
> > +  FREE_PAGE_LIST  *Pages;
> > +  UINTN           PagesToAlloc;
> > +  UINTN           HeadGuard;
> > +  UINTN           TailGuard;
> > +  UINTN           Address;
> > +
> > +  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) {
> > +
> > +      //
> > +      // We may need 1 or 2 more pages for Guard. Check it out.
> > +      //
> > +      PagesToAlloc = NumberOfPages;
> > +      TailGuard = (UINTN)Pages + EFI_PAGES_TO_SIZE (Pages-
> > >NumberOfPages);
> > +      if (!IsGuardPage (TailGuard)) {
> > +        //
> > +        // Add one if no Guard at the end of current free memory block.
> > +        //
> > +        PagesToAlloc += 1;
> > +        TailGuard     = 0;
> > +      }
> > +
> > +      HeadGuard = (UINTN)Pages +
> > +                  EFI_PAGES_TO_SIZE (Pages->NumberOfPages - PagesToAlloc) -
> > +                  EFI_PAGE_SIZE;
> > +      if (!IsGuardPage (HeadGuard)) {
> > +        //
> > +        // Add one if no Guard at the page before the address to allocate
> > +        //
> > +        PagesToAlloc += 1;
> > +        HeadGuard     = 0;
> > +      }
> > +
> > +      if (Pages->NumberOfPages < PagesToAlloc) {
> > +        // Not enough space to allocate memory with Guards? Try next block.
> > +        continue;
> > +      }
> > +
> > +      Address = InternalAllocPagesOnOneNode (Pages, PagesToAlloc,
> > MaxAddress);
> > +      ConvertSmmMemoryMapEntry(MemoryType, Address, PagesToAlloc,
> > FALSE);
> > +      CoreFreeMemoryMapStack();
> > +      if (!HeadGuard) {
> > +        // Don't pass the Guard page to user.
> > +        Address += EFI_PAGE_SIZE;
> > +      }
> > +      SetGuardForMemory (Address, NumberOfPages);
> > +      return Address;
> > +    }
> > +  }
> > +
> > +  return (UINTN)(-1);
> > +}
> > +
> > +/**
> > +  Helper function of memory free with Guard 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
> > +SmmInternalFreePagesExWithGuard (
> > +  IN EFI_PHYSICAL_ADDRESS  Memory,
> > +  IN UINTN                 NumberOfPages,
> > +  IN BOOLEAN               AddRegion
> > +  )
> > +{
> > +  EFI_PHYSICAL_ADDRESS    MemoryToFree;
> > +  UINTN                   PagesToFree;
> > +
> > +  MemoryToFree  = Memory;
> > +  PagesToFree   = NumberOfPages;
> > +
> > +  AdjustMemoryF (&MemoryToFree, &PagesToFree);
> > +  UnsetGuardForMemory (Memory, NumberOfPages);
> > +
> > +  return SmmInternalFreePagesEx (MemoryToFree, PagesToFree,
> > AddRegion);
> > +}
> > +
> > +/**
> > +  Set all Guard pages which cannot be set during the non-SMM mode time
> > +**/
> > +VOID
> > +SetAllGuardPages (
> > +  VOID
> > +  )
> > +{
> > +  UINT64    Entries[GUARDED_HEAP_MAP_TABLE_DEPTH]
> > +              = GUARDED_HEAP_MAP_TABLE_DEPTH_MASKS;
> > +  UINT64    Shifts[GUARDED_HEAP_MAP_TABLE_DEPTH]
> > +              = GUARDED_HEAP_MAP_TABLE_DEPTH_SHIFTS;
> > +  UINT64    *Tables[GUARDED_HEAP_MAP_TABLE_DEPTH];
> > +  UINT64    Addresses[GUARDED_HEAP_MAP_TABLE_DEPTH];
> > +  UINT64    Indices[GUARDED_HEAP_MAP_TABLE_DEPTH];
> > +  UINT64    TableEntry;
> > +  UINT64    Address;
> > +  UINT64    GuardPage;
> > +  INTN      Level;
> > +  UINTN     Index;
> > +  BOOLEAN   OnGuarding;
> > +
> > +  SetMem64 (Tables, sizeof(Tables), 0);
> > +  SetMem64 (Addresses, sizeof(Addresses), 0);
> > +  SetMem64 (Indices, sizeof(Indices), 0);
> > +
> > +  Level         = GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel;
> > +  Tables[Level] = mGuardedMemoryMap;
> > +  Address       = 0;
> > +  OnGuarding    = FALSE;
> > +
> > +  DEBUG_CODE (
> > +    DumpGuardedMemoryBitmap ();
> > +  );
> > +
> > +  while (TRUE) {
> > +    if (Indices[Level] > Entries[Level]) {
> > +      Tables[Level] = 0;
> > +      Level        -= 1;
> > +    } else {
> > +
> > +      TableEntry  = Tables[Level][Indices[Level]];
> > +      Address     = Addresses[Level];
> > +
> > +      if (TableEntry == 0) {
> > +
> > +        OnGuarding = FALSE;
> > +
> > +      } else if (Level < GUARDED_HEAP_MAP_TABLE_DEPTH - 1) {
> > +
> > +        Level            += 1;
> > +        Tables[Level]     = (UINT64 *)TableEntry;
> > +        Addresses[Level]  = Address;
> > +        Indices[Level]    = 0;
> > +
> > +        continue;
> > +
> > +      } else {
> > +
> > +        Index = 0;
> > +        while (Index < GUARDED_HEAP_MAP_ENTRY_BITS) {
> > +          if ((TableEntry & 1) == 1) {
> > +            if (OnGuarding) {
> > +              GuardPage = 0;
> > +            } else {
> > +              GuardPage = Address - EFI_PAGE_SIZE;
> > +            }
> > +            OnGuarding = TRUE;
> > +          } else {
> > +            if (OnGuarding) {
> > +              GuardPage = Address;
> > +            } else {
> > +              GuardPage = 0;
> > +            }
> > +            OnGuarding = FALSE;
> > +          }
> > +
> > +          if (GuardPage != 0) {
> > +            SetGuardPage (GuardPage);
> > +          }
> > +
> > +          if (TableEntry == 0) {
> > +            break;
> > +          }
> > +
> > +          TableEntry = RShiftU64 (TableEntry, 1);
> > +          Address   += EFI_PAGE_SIZE;
> > +          Index     += 1;
> > +        }
> > +      }
> > +    }
> > +
> > +    if (Level < (GUARDED_HEAP_MAP_TABLE_DEPTH - (INTN)mMapLevel)) {
> > +      break;
> > +    }
> > +
> > +    Indices[Level] += 1;
> > +    Address = (Level == 0) ? 0 : Addresses[Level - 1];
> > +    Addresses[Level] = Address | LShiftU64(Indices[Level], Shifts[Level]);
> > +
> > +  }
> > +}
> > +
> > +/**
> > +  Hook function used to set all Guard pages after entering SMM mode
> > +**/
> > +VOID
> > +SmmEntryPointMemoryManagementHook (
> > +  VOID
> > +  )
> > +{
> > +  EFI_STATUS  Status;
> > +  VOID        *SmmCpu;
> > +
> > +  if (!mIsSmmCpuMode) {
> > +    Status = SmmLocateProtocol (&gEfiSmmCpuProtocolGuid, NULL,
> > &SmmCpu);
> > +    if (!EFI_ERROR(Status)) {
> > +      mIsSmmCpuMode = TRUE;
> > +      SetAllGuardPages ();
> > +    }
> > +  }
> > +}
> > +
> > +/**
> > +  Helper function to convert a UINT64 value in binary to a string
> > +
> > +  @param[in]  Value       Value of a UINT64 integer
> > +  @param[in]  BinString   String buffer to contain the conversion result
> > +
> > +  @return VOID
> > +**/
> > +VOID
> > +Uint64ToBinString (
> > +  IN  UINT64      Value,
> > +  OUT CHAR8       *BinString
> > +  )
> > +{
> > +  UINTN Index;
> > +
> > +  if (BinString == NULL) {
> > +    return;
> > +  }
> > +
> > +  for (Index = 64; Index > 0; --Index) {
> > +    BinString[Index - 1] = '0' + (Value & 1);
> > +    Value = RShiftU64 (Value, 1);
> > +  }
> > +  BinString[64] = '\0';
> > +}
> > +
> > +/**
> > +  Dump the guarded memory bit map
> > +
> > +  @return VOID
> > +**/
> > +VOID
> > +EFIAPI
> > +DumpGuardedMemoryBitmap (
> > +  VOID
> > +  )
> > +{
> > +  UINT64    Entries[GUARDED_HEAP_MAP_TABLE_DEPTH]
> > +              = GUARDED_HEAP_MAP_TABLE_DEPTH_MASKS;
> > +  UINT64    Shifts[GUARDED_HEAP_MAP_TABLE_DEPTH]
> > +              = GUARDED_HEAP_MAP_TABLE_DEPTH_SHIFTS;
> > +  UINT64    *Tables[GUARDED_HEAP_MAP_TABLE_DEPTH];
> > +  UINT64    Addresses[GUARDED_HEAP_MAP_TABLE_DEPTH];
> > +  UINT64    Indices[GUARDED_HEAP_MAP_TABLE_DEPTH];
> > +  UINT64    TableEntry;
> > +  UINT64    Address;
> > +  INTN      Level;
> > +  UINTN     RepeatZero;
> > +  CHAR8     String[GUARDED_HEAP_MAP_ENTRY_BITS + 1];
> > +  CHAR8     *Ruler1 = "               3               2"
> > +                      "               1               0";
> > +  CHAR8     *Ruler2 = "FEDCBA9876543210FEDCBA9876543210"
> > +                      "FEDCBA9876543210FEDCBA9876543210";
> > +
> > +  if (mGuardedMemoryMap == NULL) {
> > +    return;
> > +  }
> > +
> > +  DEBUG ((DEBUG_INFO, "============================="
> > +                      " Guarded Memory Bitmap "
> > +                      "==============================\r\n"));
> > +  DEBUG ((DEBUG_INFO, "                  %a\r\n", Ruler1));
> > +  DEBUG ((DEBUG_INFO, "                  %a\r\n", Ruler2));
> > +
> > +
> > +  SetMem64 (Tables, sizeof(Tables), 0);
> > +  SetMem64 (Addresses, sizeof(Addresses), 0);
> > +  SetMem64 (Indices, sizeof(Indices), 0);
> > +
> > +  Level         = GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel;
> > +  Tables[Level] = mGuardedMemoryMap;
> > +  Address       = 0;
> > +  RepeatZero    = 0;
> > +
> > +  while (TRUE) {
> > +    if (Indices[Level] > Entries[Level]) {
> > +
> > +      Tables[Level] = 0;
> > +      Level        -= 1;
> > +      RepeatZero    = 0;
> > +
> > +      DEBUG ((
> > +        DEBUG_INFO,
> > +        "========================================="
> > +        "=========================================\r\n"
> > +        ));
> > +
> > +    } else {
> > +
> > +      TableEntry  = Tables[Level][Indices[Level]];
> > +      Address     = Addresses[Level];
> > +
> > +      if (TableEntry == 0) {
> > +
> > +        if (Level == GUARDED_HEAP_MAP_TABLE_DEPTH - 1) {
> > +          if (RepeatZero == 0) {
> > +            Uint64ToBinString(TableEntry, String);
> > +            DEBUG ((DEBUG_INFO, "%016lx: %a\r\n", Address, String));
> > +          } else if (RepeatZero == 1) {
> > +            DEBUG ((DEBUG_INFO, "...             : ...\r\n"));
> > +          }
> > +          RepeatZero += 1;
> > +        }
> > +
> > +      } else if (Level < GUARDED_HEAP_MAP_TABLE_DEPTH - 1) {
> > +
> > +        Level            += 1;
> > +        Tables[Level]     = (UINT64 *)TableEntry;
> > +        Addresses[Level]  = Address;
> > +        Indices[Level]    = 0;
> > +        RepeatZero        = 0;
> > +
> > +        continue;
> > +
> > +      } else {
> > +
> > +        RepeatZero = 0;
> > +        Uint64ToBinString(TableEntry, String);
> > +        DEBUG ((DEBUG_INFO, "%016lx: %a\r\n", Address, String));
> > +
> > +      }
> > +    }
> > +
> > +    if (Level < (GUARDED_HEAP_MAP_TABLE_DEPTH - (INTN)mMapLevel)) {
> > +      break;
> > +    }
> > +
> > +    Indices[Level] += 1;
> > +    Address = (Level == 0) ? 0 : Addresses[Level - 1];
> > +    Addresses[Level] = Address | LShiftU64(Indices[Level], Shifts[Level]);
> > +
> > +  }
> > +}
> > +
> > +/**
> > +  Debug function used to verify if the Guard page is well set or not
> > +
> > +  @param[in]  BaseAddress     Address of memory to check
> > +  @param[in]  NumberOfPages   Size of memory in pages
> > +
> > +  @return TRUE    The head Guard and tail Guard are both well set
> > +  @return FALSE   The head Guard and/or tail Guard are not well set
> > +**/
> > +BOOLEAN
> > +VerifyMemoryGuard (
> > +  IN  EFI_PHYSICAL_ADDRESS      BaseAddress,
> > +  IN  UINTN                     NumberOfPages
> > +  )
> > +{
> > +  UINT64                *PageEntry;
> > +  PAGE_ATTRIBUTE        Attribute;
> > +  EFI_PHYSICAL_ADDRESS  Address;
> > +
> > +  if (!mIsSmmCpuMode) {
> > +    return TRUE;
> > +  }
> > +
> > +  Address = BaseAddress - EFI_PAGE_SIZE;
> > +  PageEntry = GetPageTableEntry (Address, &Attribute);
> > +  if (PageEntry == NULL || Attribute != Page4K) {
> > +    DEBUG ((DEBUG_ERROR, "Head Guard is not set at: %016lx!!!\r\n",
> > Address));
> > +    DumpGuardedMemoryBitmap ();
> > +    return FALSE;
> > +  }
> > +
> > +  if ((*PageEntry & IA32_PG_P) != 0) {
> > +    DEBUG ((DEBUG_ERROR, "Head Guard is not set at: %016lx
> > (%016lX)!!!\r\n",
> > +            Address, *PageEntry));
> > +    *(UINT8 *) Address = 0;
> > +    DumpGuardedMemoryBitmap ();
> > +    return FALSE;
> > +  }
> > +
> > +  Address = BaseAddress + EFI_PAGES_TO_SIZE (NumberOfPages);
> > +  PageEntry = GetPageTableEntry (Address, &Attribute);
> > +  if (PageEntry == NULL || Attribute != Page4K) {
> > +    DEBUG ((DEBUG_ERROR, "Tail Guard is not set at: %016lx!!!\r\n",
> > Address));
> > +    DumpGuardedMemoryBitmap ();
> > +    return FALSE;
> > +  }
> > +
> > +  if ((*PageEntry & IA32_PG_P) != 0) {
> > +    DEBUG ((DEBUG_ERROR, "Tail Guard is not set at: %016lx (%016lX)!!!\r\n",
> > +            Address, *PageEntry));
> > +    *(UINT8 *) Address = 0;
> > +    DumpGuardedMemoryBitmap ();
> > +    return FALSE;
> > +  }
> > +
> > +  return TRUE;
> > +}
> > +
> > diff --git a/MdeModulePkg/Core/PiSmmCore/Misc/HeapGuard.h
> > b/MdeModulePkg/Core/PiSmmCore/Misc/HeapGuard.h
> > new file mode 100644
> > index 0000000000..ecc10e83a7
> > --- /dev/null
> > +++ b/MdeModulePkg/Core/PiSmmCore/Misc/HeapGuard.h
> > @@ -0,0 +1,395 @@
> > +/** @file
> > +  Data structure and functions to allocate and free memory space.
> > +
> > +Copyright (c) 2017, 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.
> > +
> > +**/
> > +
> > +#ifndef _HEAPGUARD_H_
> > +#define _HEAPGUARD_H_
> > +
> > +#include "PiSmmCore.h"
> > +#include "PageTable.h"
> > +
> > +//
> > +// Following macros are used to define and access the guarded memory
> > bitmap
> > +// table.
> > +//
> > +// To simplify the access and reduce the memory used for this table, the
> > +// table is constructed in the similar way as page table structure but in
> > +// reverse direction, i.e. from bottom growing up to top.
> > +//
> > +//    - 1-bit tracks 1 page (4KB)
> > +//    - 1-UINT64 map entry tracks 256KB memory
> > +//    - 1K-UINT64 map table tracks 256MB memory
> > +//    - Five levels of tables can track any address of memory of 64-bit
> > +//      system, like below.
> > +//
> > +//       512   *   512   *   512   *   512    *    1K   *  64b *     4K
> > +//    111111111 111111111 111111111 111111111 1111111111 111111
> > 111111111111
> > +//    63        54        45        36        27         17     11         0
> > +//       9b        9b        9b        9b         10b      6b       12b
> > +//       L0   ->   L1   ->   L2   ->   L3   ->    L4   -> bits  ->  page
> > +//      1FF       1FF       1FF       1FF         3FF      3F       FFF
> > +//
> > +// L4 table has 1K * sizeof(UINT64) = 8K (2-page), which can track 256MB
> > +// memory. Each table of L0-L3 will be allocated when its memory address
> > +// range is to be tracked. Only 1-page will be allocated each time. This
> > +// can save memories used to establish this map table.
> > +//
> > +// For a normal configuration of system with 4G memory, two levels of
> > tables
> > +// can track the whole memory, because two levels (L3+L4) of map tables
> > have
> > +// already coverred 37-bit of memory address. And for a normal UEFI BIOS,
> > +// less than 128M memory would be consumed during boot. That means we
> > just
> > +// need
> > +//
> > +//          1-page (L3) + 2-page (L4)
> > +//
> > +// memory (3 pages) to track the memory allocation works. In this case,
> > +// there's no need to setup L0-L2 tables.
> > +//
> > +
> > +//
> > +// Each entry occupies 8B/64b. 1-page can hold 512 entries, which spans 9
> > +// bits in address. (512 = 1 << 9)
> > +//
> > +#define BYTE_LENGTH_SHIFT                   3             // (8 = 1 << 3)
> > +
> > +#define GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT  \
> > +        (EFI_PAGE_SHIFT - BYTE_LENGTH_SHIFT)
> > +
> > +#define GUARDED_HEAP_MAP_TABLE_DEPTH        5
> > +
> > +// Use UINT64_index + bit_index_of_UINT64 to locate the bit in may
> > +#define GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT    6             // (64 = 1 << 6)
> > +
> > +#define GUARDED_HEAP_MAP_ENTRY_BITS         \
> > +        (1 << GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT)
> > +
> > +#define GUARDED_HEAP_MAP_ENTRY_BYTES        \
> > +        (GUARDED_HEAP_MAP_ENTRY_BITS / 8)
> > +
> > +// L4 table address width: 64 - 9 * 4 - 6 - 12 = 10b
> > +#define GUARDED_HEAP_MAP_ENTRY_SHIFT              \
> > +        (GUARDED_HEAP_MAP_ENTRY_BITS              \
> > +         - GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT * 4 \
> > +         - GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT       \
> > +         - EFI_PAGE_SHIFT)
> > +
> > +// L4 table address mask: (1 << 10 - 1) = 0x3FF
> > +#define GUARDED_HEAP_MAP_ENTRY_MASK               \
> > +        ((1 << GUARDED_HEAP_MAP_ENTRY_SHIFT) - 1)
> > +
> > +// Size of each L4 table: (1 << 10) * 8 = 8KB = 2-page
> > +#define GUARDED_HEAP_MAP_SIZE                     \
> > +        ((1 << GUARDED_HEAP_MAP_ENTRY_SHIFT) *
> > GUARDED_HEAP_MAP_ENTRY_BYTES)
> > +
> > +// Memory size tracked by one L4 table: 8KB * 8 * 4KB = 256MB
> > +#define GUARDED_HEAP_MAP_UNIT_SIZE                \
> > +        (GUARDED_HEAP_MAP_SIZE * 8 * EFI_PAGE_SIZE)
> > +
> > +// L4 table entry number: 8KB / 8 = 1024
> > +#define GUARDED_HEAP_MAP_ENTRIES_PER_UNIT         \
> > +        (GUARDED_HEAP_MAP_SIZE / GUARDED_HEAP_MAP_ENTRY_BYTES)
> > +
> > +// L4 table entry indexing
> > +#define GUARDED_HEAP_MAP_ENTRY_INDEX(Address)                       \
> > +        (RShiftU64 (Address, EFI_PAGE_SHIFT                         \
> > +                             + GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT)    \
> > +         & GUARDED_HEAP_MAP_ENTRY_MASK)
> > +
> > +// L4 table entry bit indexing
> > +#define GUARDED_HEAP_MAP_ENTRY_BIT_INDEX(Address)       \
> > +        (RShiftU64 (Address, EFI_PAGE_SHIFT)            \
> > +         & ((1 << GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT) - 1))
> > +
> > +//
> > +// Total bits (pages) tracked by one L4 table (65536-bit)
> > +//
> > +#define GUARDED_HEAP_MAP_BITS                               \
> > +        (1 << (GUARDED_HEAP_MAP_ENTRY_SHIFT                 \
> > +               + GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT))
> > +
> > +//
> > +// Bit indexing inside the whole L4 table (0 - 65535)
> > +//
> > +#define GUARDED_HEAP_MAP_BIT_INDEX(Address)                     \
> > +        (RShiftU64 (Address, EFI_PAGE_SHIFT)                    \
> > +         & ((1 << (GUARDED_HEAP_MAP_ENTRY_SHIFT                 \
> > +                   + GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT)) - 1))
> > +
> > +//
> > +// Memory address bit width tracked by L4 table: 10 + 6 + 12 = 28
> > +//
> > +#define GUARDED_HEAP_MAP_TABLE_SHIFT                                      \
> > +        (GUARDED_HEAP_MAP_ENTRY_SHIFT +
> > GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT  \
> > +         + EFI_PAGE_SHIFT)
> > +
> > +//
> > +// Macro used to initialize the local array variable for map table traversing
> > +// {55, 46, 37, 28, 18}
> > +//
> > +#define GUARDED_HEAP_MAP_TABLE_DEPTH_SHIFTS                                 \
> > +  {                                                                         \
> > +    GUARDED_HEAP_MAP_TABLE_SHIFT +
> > GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT * 3,  \
> > +    GUARDED_HEAP_MAP_TABLE_SHIFT +
> > GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT * 2,  \
> > +    GUARDED_HEAP_MAP_TABLE_SHIFT +
> > GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT,      \
> > +    GUARDED_HEAP_MAP_TABLE_SHIFT,                                           \
> > +    EFI_PAGE_SHIFT + GUARDED_HEAP_MAP_ENTRY_BIT_SHIFT                       \
> > +  }
> > +
> > +//
> > +// Masks used to extract address range of each level of table
> > +// {0x1FF, 0x1FF, 0x1FF, 0x1FF, 0x3FF}
> > +//
> > +#define GUARDED_HEAP_MAP_TABLE_DEPTH_MASKS                                  \
> > +  {                                                                         \
> > +    (1 << GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT) - 1,                          \
> > +    (1 << GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT) - 1,                          \
> > +    (1 << GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT) - 1,                          \
> > +    (1 << GUARDED_HEAP_MAP_TABLE_ENTRY_SHIFT) - 1,                          \
> > +    (1 << GUARDED_HEAP_MAP_ENTRY_SHIFT) - 1                                 \
> > +  }
> > +
> > +//
> > +// Memory type to guard (matching the related PCD definition)
> > +//
> > +#define GUARD_HEAP_TYPE_POOL        BIT2
> > +#define GUARD_HEAP_TYPE_PAGE        BIT3
> > +
> > +typedef struct {
> > +  UINT32                TailMark;
> > +  UINT32                HeadMark;
> > +  EFI_PHYSICAL_ADDRESS  Address;
> > +  LIST_ENTRY            Link;
> > +} HEAP_GUARD_NODE;
> > +
> > +/**
> > +  Set head Guard and tail Guard for the given memory range
> > +
> > +  @param[in]  Memory          Base address of memory to set guard for
> > +  @param[in]  NumberOfPages   Memory size in pages
> > +
> > +  @return VOID
> > +**/
> > +VOID
> > +SetGuardForMemory (
> > +  IN EFI_PHYSICAL_ADDRESS   Memory,
> > +  IN UINTN                  NumberOfPages
> > +  );
> > +
> > +/**
> > +  Unset head Guard and tail Guard for the given memory range
> > +
> > +  @param[in]  Memory          Base address of memory to unset guard for
> > +  @param[in]  NumberOfPages   Memory size in pages
> > +
> > +  @return VOID
> > +**/
> > +VOID
> > +UnsetGuardForMemory (
> > +  IN EFI_PHYSICAL_ADDRESS   Memory,
> > +  IN UINTN                  NumberOfPages
> > +  );
> > +
> > +/**
> > +  Adjust the base and number of pages to really allocate according to Guard
> > +
> > +  @param[in/out]  Memory          Base address of free memory
> > +  @param[in/out]  NumberOfPages   Size of memory to allocate
> > +
> > +  @return VOID
> > +**/
> > +VOID
> > +AdjustMemoryA (
> > +  IN OUT EFI_PHYSICAL_ADDRESS    *Memory,
> > +  IN OUT UINTN                   *NumberOfPages
> > +  );
> > +
> > +/**
> > +  Adjust the start address and number of pages to free according to Guard
> > +
> > +  The purpose of this function is to keep the shared Guard page with
> > adjacent
> > +  memory block if it's still in guard, or free it if no more sharing. Another
> > +  is to reserve pages as Guard pages in partial page free situation.
> > +
> > +  @param[in/out]  Memory          Base address of memory to free
> > +  @param[in/out]  NumberOfPages   Size of memory to free
> > +
> > +  @return VOID
> > +**/
> > +VOID
> > +AdjustMemoryF (
> > +  IN OUT EFI_PHYSICAL_ADDRESS    *Memory,
> > +  IN OUT UINTN                   *NumberOfPages
> > +  );
> > +
> > +/**
> > +  Check to see if the pool at the given address should be guarded or not
> > +
> > +  @param[in]  MemoryType      Pool type to check
> > +
> > +
> > +  @return TRUE  The given type of pool should be guarded
> > +  @return FALSE The given type of pool should not be guarded
> > +**/
> > +BOOLEAN
> > +IsPoolTypeToGuard (
> > +  IN EFI_MEMORY_TYPE        MemoryType
> > +  );
> > +
> > +/**
> > +  Check to see if the page at the given address should be guarded or not
> > +
> > +  @param[in]  MemoryType      Page type to check
> > +  @param[in]  AllocateType    Allocation type to check
> > +
> > +  @return TRUE  The given type of page should be guarded
> > +  @return FALSE The given type of page should not be guarded
> > +**/
> > +BOOLEAN
> > +IsPageTypeToGuard (
> > +  IN EFI_MEMORY_TYPE        MemoryType,
> > +  IN EFI_ALLOCATE_TYPE      AllocateType
> > +  );
> > +
> > +/**
> > +  Check to see if the page at the given address is guarded or not
> > +
> > +  @param[in]  Address     The address to check for
> > +
> > +  @return TRUE  The page at Address is guarded
> > +  @return FALSE The page at Address is not guarded
> > +**/
> > +BOOLEAN
> > +EFIAPI
> > +IsMemoryGuarded (
> > +  IN EFI_PHYSICAL_ADDRESS    Address
> > +  );
> > +
> > +/**
> > +  Check to see if the page at the given address is a Guard page or not
> > +
> > +  @param[in]  Address     The address to check for
> > +
> > +  @return TRUE  The page at Address is a Guard page
> > +  @return FALSE The page at Address is not a Guard page
> > +**/
> > +BOOLEAN
> > +EFIAPI
> > +IsGuardPage (
> > +  IN EFI_PHYSICAL_ADDRESS    Address
> > +  );
> > +
> > +/**
> > +  Dump the guarded memory bit map
> > +
> > +  @return VOID
> > +**/
> > +VOID
> > +EFIAPI
> > +DumpGuardedMemoryBitmap (
> > +  VOID
> > +  );
> > +
> > +/**
> > +  Adjust the pool head position to make sure the Guard page is adjavent to
> > +  pool tail or pool head.
> > +
> > +  @param[in]  Memory    Base address of memory allocated
> > +  @param[in]  NoPages   Number of pages actually allocated
> > +  @param[in]  Size      Size of memory requested
> > +                        (plus pool head/tail overhead)
> > +
> > +  @return Address of pool head
> > +**/
> > +VOID *
> > +AdjustPoolHeadA (
> > +  IN EFI_PHYSICAL_ADDRESS    Memory,
> > +  IN UINTN                   NoPages,
> > +  IN UINTN                   Size
> > +  );
> > +
> > +/**
> > +  Get the page base address according to pool head address
> > +
> > +  @param[in]  Memory    Head address of pool to free
> > +
> > +  @return Address of pool head
> > +**/
> > +VOID *
> > +AdjustPoolHeadF (
> > +  IN EFI_PHYSICAL_ADDRESS    Memory
> > +  );
> > +
> > +/**
> > +  Helper function of memory allocation with Guard pages
> > +
> > +  @param  FreePageList           The free page node.
> > +  @param  NumberOfPages          Number of pages to be allocated.
> > +  @param  MaxAddress             Request to allocate memory below this
> > address.
> > +  @param  MemoryType             Type of memory requested.
> > +
> > +  @return Memory address of allocated pages.
> > +**/
> > +UINTN
> > +InternalAllocMaxAddressWithGuard (
> > +  IN OUT LIST_ENTRY           *FreePageList,
> > +  IN     UINTN                NumberOfPages,
> > +  IN     UINTN                MaxAddress,
> > +  IN     EFI_MEMORY_TYPE      MemoryType
> > +  );
> > +
> > +/**
> > +  Helper function of memory free with Guard 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
> > +SmmInternalFreePagesExWithGuard (
> > +  IN EFI_PHYSICAL_ADDRESS  Memory,
> > +  IN UINTN                 NumberOfPages,
> > +  IN BOOLEAN               AddRegion
> > +  );
> > +
> > +/**
> > +  Check to see if the heap guard is enabled for page and/or pool allocation
> > +
> > +  @return TRUE/FALSE
> > +**/
> > +BOOLEAN
> > +IsHeapGuardEnabled (
> > +  VOID
> > +  );
> > +
> > +/**
> > +  Debug function used to verify if the Guard page is well set or not
> > +
> > +  @param[in]  BaseAddress     Address of memory to check
> > +  @param[in]  NumberOfPages   Size of memory in pages
> > +
> > +  @return TRUE    The head Guard and tail Guard are both well set
> > +  @return FALSE   The head Guard and/or tail Guard are not well set
> > +**/
> > +BOOLEAN
> > +VerifyMemoryGuard (
> > +  IN  EFI_PHYSICAL_ADDRESS      BaseAddress,
> > +  IN  UINTN                     NumberOfPages
> > +  );
> > +
> > +extern BOOLEAN mOnGuarding;
> > +
> > +#endif
> > diff --git a/MdeModulePkg/Core/PiSmmCore/Misc/PageTable.c
> > b/MdeModulePkg/Core/PiSmmCore/Misc/PageTable.c
> > new file mode 100644
> > index 0000000000..d41b3e923f
> > --- /dev/null
> > +++ b/MdeModulePkg/Core/PiSmmCore/Misc/PageTable.c
> > @@ -0,0 +1,704 @@
> > +/** @file
> > +
> > +Copyright (c) 2016 - 2017, 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 "PageTable.h"
> > +
> > +#include <Library/CpuLib.h>
> > +
> > +UINT64 mAddressEncMask = 0;
> > +UINT8  mPhysicalAddressBits = 32;
> > +
> > +PAGE_ATTRIBUTE_TABLE mPageAttributeTable[] = {
> > +  {PageNone,       0,                         0},
> > +  {Page4K,  SIZE_4KB, PAGING_4K_ADDRESS_MASK_64},
> > +  {Page2M,  SIZE_2MB, PAGING_2M_ADDRESS_MASK_64},
> > +  {Page1G,  SIZE_1GB, PAGING_1G_ADDRESS_MASK_64},
> > +};
> > +
> > +/**
> > +  Calculate the maximum support address.
> > +
> > +  @return the maximum support address.
> > +**/
> > +UINT8
> > +CalculateMaximumSupportAddress (
> > +  VOID
> > +  )
> > +{
> > +  UINT32                                        RegEax;
> > +  UINT8                                         PhysicalAddressBits;
> > +  VOID                                          *Hob;
> > +
> > +  //
> > +  // Get physical address bits supported.
> > +  //
> > +  Hob = GetFirstHob (EFI_HOB_TYPE_CPU);
> > +  if (Hob != NULL) {
> > +    PhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace;
> > +  } else {
> > +    AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
> > +    if (RegEax >= 0x80000008) {
> > +      AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
> > +      PhysicalAddressBits = (UINT8) RegEax;
> > +    } else {
> > +      PhysicalAddressBits = 36;
> > +    }
> > +  }
> > +
> > +  //
> > +  // IA-32e paging translates 48-bit linear addresses to 52-bit physical
> > addresses.
> > +  //
> > +  ASSERT (PhysicalAddressBits <= 52);
> > +  if (PhysicalAddressBits > 48) {
> > +    PhysicalAddressBits = 48;
> > +  }
> > +  return PhysicalAddressBits;
> > +}
> > +
> > +/**
> > +  Return page table base.
> > +
> > +  @return page table base.
> > +**/
> > +UINTN
> > +GetPageTableBase (
> > +  VOID
> > +  )
> > +{
> > +  return (AsmReadCr3 () & PAGING_4K_ADDRESS_MASK_64);
> > +}
> > +
> > +/**
> > +  Return length according to page attributes.
> > +
> > +  @param[in]  PageAttributes   The page attribute of the page entry.
> > +
> > +  @return The length of page entry.
> > +**/
> > +UINTN
> > +PageAttributeToLength (
> > +  IN PAGE_ATTRIBUTE  PageAttribute
> > +  )
> > +{
> > +  if (PageAttribute <= Page1G) {
> > +    return (UINTN)mPageAttributeTable[PageAttribute].Length;
> > +  }
> > +  return 0;
> > +}
> > +
> > +/**
> > +  Return address mask according to page attributes.
> > +
> > +  @param[in]  PageAttributes   The page attribute of the page entry.
> > +
> > +  @return The address mask of page entry.
> > +**/
> > +UINTN
> > +PageAttributeToMask (
> > +  IN PAGE_ATTRIBUTE  PageAttribute
> > +  )
> > +{
> > +  if (PageAttribute <= Page1G) {
> > +    return (UINTN)mPageAttributeTable[PageAttribute].AddressMask;
> > +  }
> > +  return 0;
> > +}
> > +
> > +/**
> > +  Return page table entry to match the address.
> > +
> > +  @param[in]   Address          The address to be checked.
> > +  @param[out]  PageAttributes   The page attribute of the page entry.
> > +
> > +  @return The page entry.
> > +**/
> > +VOID *
> > +GetPageTableEntry (
> > +  IN  PHYSICAL_ADDRESS                  Address,
> > +  OUT PAGE_ATTRIBUTE                    *PageAttribute
> > +  )
> > +{
> > +  UINTN                 Index1;
> > +  UINTN                 Index2;
> > +  UINTN                 Index3;
> > +  UINTN                 Index4;
> > +  UINT64                *L1PageTable;
> > +  UINT64                *L2PageTable;
> > +  UINT64                *L3PageTable;
> > +  UINT64                *L4PageTable;
> > +
> > +  Index4 = ((UINTN)RShiftU64 (Address, 39)) & PAGING_PAE_INDEX_MASK;
> > +  Index3 = ((UINTN)Address >> 30) & PAGING_PAE_INDEX_MASK;
> > +  Index2 = ((UINTN)Address >> 21) & PAGING_PAE_INDEX_MASK;
> > +  Index1 = ((UINTN)Address >> 12) & PAGING_PAE_INDEX_MASK;
> > +
> > +  if (sizeof(UINTN) == sizeof(UINT64)) {
> > +    L4PageTable = (UINT64 *)GetPageTableBase ();
> > +    if (L4PageTable[Index4] == 0) {
> > +      *PageAttribute = PageNone;
> > +      return NULL;
> > +    }
> > +
> > +    L3PageTable = (UINT64 *)(UINTN)(L4PageTable[Index4] &
> > ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);
> > +  } else {
> > +    L3PageTable = (UINT64 *)GetPageTableBase ();
> > +  }
> > +  if (L3PageTable[Index3] == 0) {
> > +    *PageAttribute = PageNone;
> > +    return NULL;
> > +  }
> > +  if ((L3PageTable[Index3] & IA32_PG_PS) != 0) {
> > +    // 1G
> > +    *PageAttribute = Page1G;
> > +    return &L3PageTable[Index3];
> > +  }
> > +
> > +  L2PageTable = (UINT64 *)(UINTN)(L3PageTable[Index3] &
> > ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);
> > +  if (L2PageTable[Index2] == 0) {
> > +    *PageAttribute = PageNone;
> > +    return NULL;
> > +  }
> > +  if ((L2PageTable[Index2] & IA32_PG_PS) != 0) {
> > +    // 2M
> > +    *PageAttribute = Page2M;
> > +    return &L2PageTable[Index2];
> > +  }
> > +
> > +  // 4k
> > +  L1PageTable = (UINT64 *)(UINTN)(L2PageTable[Index2] &
> > ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);
> > +  if ((L1PageTable[Index1] == 0) && (Address != 0)) {
> > +    *PageAttribute = PageNone;
> > +    return NULL;
> > +  }
> > +  *PageAttribute = Page4K;
> > +  return &L1PageTable[Index1];
> > +}
> > +
> > +/**
> > +  Return memory attributes of page entry.
> > +
> > +  @param[in]  PageEntry        The page entry.
> > +
> > +  @return Memory attributes of page entry.
> > +**/
> > +UINT64
> > +GetAttributesFromPageEntry (
> > +  IN  UINT64                            *PageEntry
> > +  )
> > +{
> > +  UINT64  Attributes;
> > +  Attributes = 0;
> > +  if ((*PageEntry & IA32_PG_P) == 0) {
> > +    Attributes |= EFI_MEMORY_RP;
> > +  }
> > +  if ((*PageEntry & IA32_PG_RW) == 0) {
> > +    Attributes |= EFI_MEMORY_RO;
> > +  }
> > +  if ((*PageEntry & IA32_PG_NX) != 0) {
> > +    Attributes |= EFI_MEMORY_XP;
> > +  }
> > +  return Attributes;
> > +}
> > +
> > +/**
> > +  Modify memory attributes of page entry.
> > +
> > +  @param[in]   PageEntry        The page entry.
> > +  @param[in]   Attributes       The bit mask of attributes to modify for the
> > memory region.
> > +  @param[in]   IsSet            TRUE means to set attributes. FALSE means to
> > clear attributes.
> > +  @param[out]  IsModified       TRUE means page table modified. FALSE
> > means page table not modified.
> > +**/
> > +VOID
> > +ConvertPageEntryAttribute (
> > +  IN  UINT64                            *PageEntry,
> > +  IN  UINT64                            Attributes,
> > +  IN  BOOLEAN                           IsSet,
> > +  OUT BOOLEAN                           *IsModified
> > +  )
> > +{
> > +  UINT64  CurrentPageEntry;
> > +  UINT64  NewPageEntry;
> > +
> > +  CurrentPageEntry = *PageEntry;
> > +  NewPageEntry = CurrentPageEntry;
> > +  if ((Attributes & EFI_MEMORY_RP) != 0) {
> > +    if (IsSet) {
> > +      NewPageEntry &= ~(UINT64)IA32_PG_P;
> > +    } else {
> > +      NewPageEntry |= IA32_PG_P;
> > +    }
> > +  }
> > +  if ((Attributes & EFI_MEMORY_RO) != 0) {
> > +    if (IsSet) {
> > +      NewPageEntry &= ~(UINT64)IA32_PG_RW;
> > +    } else {
> > +      NewPageEntry |= IA32_PG_RW;
> > +    }
> > +  }
> > +  if ((Attributes & EFI_MEMORY_XP) != 0) {
> > +    if (IsSet) {
> > +      NewPageEntry |= IA32_PG_NX;
> > +    } else {
> > +      NewPageEntry &= ~IA32_PG_NX;
> > +    }
> > +  }
> > +
> > +  if (CurrentPageEntry != NewPageEntry) {
> > +    *PageEntry = NewPageEntry;
> > +    *IsModified = TRUE;
> > +    DEBUG ((DEBUG_INFO, "(SMM)ConvertPageEntryAttribute 0x%lx",
> > CurrentPageEntry));
> > +    DEBUG ((DEBUG_INFO, "->0x%lx\n", NewPageEntry));
> > +  } else {
> > +    *IsModified = FALSE;
> > +  }
> > +}
> > +
> > +/**
> > +  This function returns if there is need to split page entry.
> > +
> > +  @param[in]  BaseAddress      The base address to be checked.
> > +  @param[in]  Length           The length to be checked.
> > +  @param[in]  PageEntry        The page entry to be checked.
> > +  @param[in]  PageAttribute    The page attribute of the page entry.
> > +
> > +  @retval SplitAttributes on if there is need to split page entry.
> > +**/
> > +PAGE_ATTRIBUTE
> > +NeedSplitPage (
> > +  IN  PHYSICAL_ADDRESS                  BaseAddress,
> > +  IN  UINT64                            Length,
> > +  IN  UINT64                            *PageEntry,
> > +  IN  PAGE_ATTRIBUTE                    PageAttribute
> > +  )
> > +{
> > +  UINT64                PageEntryLength;
> > +
> > +  PageEntryLength = PageAttributeToLength (PageAttribute);
> > +
> > +  if (((BaseAddress & (PageEntryLength - 1)) == 0) && (Length >=
> > PageEntryLength)) {
> > +    return PageNone;
> > +  }
> > +
> > +  if (((BaseAddress & PAGING_2M_MASK) != 0) || (Length < SIZE_2MB)) {
> > +    return Page4K;
> > +  }
> > +
> > +  return Page2M;
> > +}
> > +
> > +/**
> > +  This function splits one page entry to small page entries.
> > +
> > +  @param[in]  PageEntry        The page entry to be splitted.
> > +  @param[in]  PageAttribute    The page attribute of the page entry.
> > +  @param[in]  SplitAttribute   How to split the page entry.
> > +
> > +  @retval RETURN_SUCCESS            The page entry is splitted.
> > +  @retval RETURN_UNSUPPORTED        The page entry does not support to
> > be splitted.
> > +  @retval RETURN_OUT_OF_RESOURCES   No resource to split page entry.
> > +**/
> > +RETURN_STATUS
> > +SplitPage (
> > +  IN  UINT64                            *PageEntry,
> > +  IN  PAGE_ATTRIBUTE                    PageAttribute,
> > +  IN  PAGE_ATTRIBUTE                    SplitAttribute
> > +  )
> > +{
> > +  UINT64   BaseAddress;
> > +  UINT64   *NewPageEntry;
> > +  UINTN    Index;
> > +
> > +  ASSERT (PageAttribute == Page2M || PageAttribute == Page1G);
> > +
> > +  if (PageAttribute == Page2M) {
> > +    //
> > +    // Split 2M to 4K
> > +    //
> > +    ASSERT (SplitAttribute == Page4K);
> > +    if (SplitAttribute == Page4K) {
> > +      NewPageEntry = PageAlloc (1);
> > +      DEBUG ((DEBUG_VERBOSE, "Split - 0x%x\n", NewPageEntry));
> > +      if (NewPageEntry == NULL) {
> > +        return RETURN_OUT_OF_RESOURCES;
> > +      }
> > +      BaseAddress = *PageEntry & PAGING_2M_ADDRESS_MASK_64;
> > +      for (Index = 0; Index < SIZE_4KB / sizeof(UINT64); Index++) {
> > +        NewPageEntry[Index] = (BaseAddress + SIZE_4KB * Index) |
> > mAddressEncMask | ((*PageEntry) & PAGE_PROGATE_BITS);
> > +      }
> > +      (*PageEntry) = (UINT64)(UINTN)NewPageEntry | mAddressEncMask |
> > PAGE_ATTRIBUTE_BITS;
> > +      return RETURN_SUCCESS;
> > +    } else {
> > +      return RETURN_UNSUPPORTED;
> > +    }
> > +  } else if (PageAttribute == Page1G) {
> > +    //
> > +    // Split 1G to 2M
> > +    // No need support 1G->4K directly, we should use 1G->2M, then 2M->4K
> > to get more compact page table.
> > +    //
> > +    ASSERT (SplitAttribute == Page2M || SplitAttribute == Page4K);
> > +    if ((SplitAttribute == Page2M || SplitAttribute == Page4K)) {
> > +      NewPageEntry = PageAlloc (1);
> > +      DEBUG ((DEBUG_VERBOSE, "Split - 0x%x\n", NewPageEntry));
> > +      if (NewPageEntry == NULL) {
> > +        return RETURN_OUT_OF_RESOURCES;
> > +      }
> > +      BaseAddress = *PageEntry & PAGING_1G_ADDRESS_MASK_64;
> > +      for (Index = 0; Index < SIZE_4KB / sizeof(UINT64); Index++) {
> > +        NewPageEntry[Index] = (BaseAddress + SIZE_2MB * Index) |
> > mAddressEncMask | IA32_PG_PS | ((*PageEntry) & PAGE_PROGATE_BITS);
> > +      }
> > +      (*PageEntry) = (UINT64)(UINTN)NewPageEntry | mAddressEncMask |
> > PAGE_ATTRIBUTE_BITS;
> > +      return RETURN_SUCCESS;
> > +    } else {
> > +      return RETURN_UNSUPPORTED;
> > +    }
> > +  } else {
> > +    return RETURN_UNSUPPORTED;
> > +  }
> > +}
> > +
> > +/**
> > +  This function modifies the page attributes for the memory region specified
> > by BaseAddress and
> > +  Length from their current attributes to the attributes specified by
> > Attributes.
> > +
> > +  Caller should make sure BaseAddress and Length is at page boundary.
> > +
> > +  @param[in]   BaseAddress      The physical address that is the start address
> > of a memory region.
> > +  @param[in]   Length           The size in bytes of the memory region.
> > +  @param[in]   Attributes       The bit mask of attributes to modify for the
> > memory region.
> > +  @param[in]   IsSet            TRUE means to set attributes. FALSE means to
> > clear attributes.
> > +  @param[out]  IsSplitted       TRUE means page table splitted. FALSE means
> > page table not splitted.
> > +  @param[out]  IsModified       TRUE means page table modified. FALSE
> > means page table not modified.
> > +
> > +  @retval RETURN_SUCCESS           The attributes were modified for the
> > memory region.
> > +  @retval RETURN_ACCESS_DENIED     The attributes for the memory
> > resource range specified by
> > +                                   BaseAddress and Length cannot be modified.
> > +  @retval RETURN_INVALID_PARAMETER Length is zero.
> > +                                   Attributes specified an illegal combination of attributes
> > that
> > +                                   cannot be set together.
> > +  @retval RETURN_OUT_OF_RESOURCES  There are not enough system
> > resources to modify the attributes of
> > +                                   the memory resource range.
> > +  @retval RETURN_UNSUPPORTED       The processor does not support one
> > or more bytes of the memory
> > +                                   resource range specified by BaseAddress and Length.
> > +                                   The bit mask of attributes is not support for the memory
> > resource
> > +                                   range specified by BaseAddress and Length.
> > +**/
> > +RETURN_STATUS
> > +EFIAPI
> > +ConvertMemoryPageAttributes (
> > +  IN  PHYSICAL_ADDRESS                  BaseAddress,
> > +  IN  UINT64                            Length,
> > +  IN  UINT64                            Attributes,
> > +  IN  BOOLEAN                           IsSet,
> > +  OUT BOOLEAN                           *IsSplitted,  OPTIONAL
> > +  OUT BOOLEAN                           *IsModified   OPTIONAL
> > +  )
> > +{
> > +  UINT64                            *PageEntry;
> > +  PAGE_ATTRIBUTE                    PageAttribute;
> > +  UINTN                             PageEntryLength;
> > +  PAGE_ATTRIBUTE                    SplitAttribute;
> > +  RETURN_STATUS                     Status;
> > +  BOOLEAN                           IsEntryModified;
> > +  EFI_PHYSICAL_ADDRESS              MaximumSupportMemAddress;
> > +
> > +  ASSERT (Attributes != 0);
> > +  ASSERT ((Attributes & ~(EFI_MEMORY_RP | EFI_MEMORY_RO |
> > EFI_MEMORY_XP)) == 0);
> > +
> > +  ASSERT ((BaseAddress & (SIZE_4KB - 1)) == 0);
> > +  ASSERT ((Length & (SIZE_4KB - 1)) == 0);
> > +
> > +  if (Length == 0) {
> > +    return RETURN_INVALID_PARAMETER;
> > +  }
> > +
> > +  MaximumSupportMemAddress =
> > (EFI_PHYSICAL_ADDRESS)(UINTN)(LShiftU64 (1, mPhysicalAddressBits) - 1);
> > +  if (BaseAddress > MaximumSupportMemAddress) {
> > +    return RETURN_UNSUPPORTED;
> > +  }
> > +  if (Length > MaximumSupportMemAddress) {
> > +    return RETURN_UNSUPPORTED;
> > +  }
> > +  if ((Length != 0) && (BaseAddress > MaximumSupportMemAddress -
> > (Length - 1))) {
> > +    return RETURN_UNSUPPORTED;
> > +  }
> > +
> > +//  DEBUG ((DEBUG_ERROR, "ConvertMemoryPageAttributes(%x) -
> >  %016lx, %016lx, %02lx\n", IsSet, BaseAddress, Length, Attributes));
> > +
> > +  if (IsSplitted != NULL) {
> > +    *IsSplitted = FALSE;
> > +  }
> > +  if (IsModified != NULL) {
> > +    *IsModified = FALSE;
> > +  }
> > +
> > +  //
> > +  // Below logic is to check 2M/4K page to make sure we do not waste
> > memory.
> > +  //
> > +  while (Length != 0) {
> > +    PageEntry = GetPageTableEntry (BaseAddress, &PageAttribute);
> > +    if (PageEntry == NULL) {
> > +      return RETURN_UNSUPPORTED;
> > +    }
> > +    PageEntryLength = PageAttributeToLength (PageAttribute);
> > +    SplitAttribute = NeedSplitPage (BaseAddress, Length, PageEntry,
> > PageAttribute);
> > +    if (SplitAttribute == PageNone) {
> > +      ConvertPageEntryAttribute (PageEntry, Attributes, IsSet,
> > &IsEntryModified);
> > +      if (IsEntryModified) {
> > +        if (IsModified != NULL) {
> > +          *IsModified = TRUE;
> > +        }
> > +      }
> > +      //
> > +      // Convert success, move to next
> > +      //
> > +      BaseAddress += PageEntryLength;
> > +      Length -= PageEntryLength;
> > +    } else {
> > +      Status = SplitPage (PageEntry, PageAttribute, SplitAttribute);
> > +      if (RETURN_ERROR (Status)) {
> > +        return RETURN_UNSUPPORTED;
> > +      }
> > +      if (IsSplitted != NULL) {
> > +        *IsSplitted = TRUE;
> > +      }
> > +      if (IsModified != NULL) {
> > +        *IsModified = TRUE;
> > +      }
> > +      //
> > +      // Just split current page
> > +      // Convert success in next around
> > +      //
> > +    }
> > +  }
> > +
> > +  return RETURN_SUCCESS;
> > +}
> > +
> > +/**
> > +  FlushTlb on current processor.
> > +
> > +  @param[in,out] Buffer  Pointer to private data buffer.
> > +**/
> > +VOID
> > +EFIAPI
> > +FlushTlbOnCurrentProcessor (
> > +  IN OUT VOID  *Buffer
> > +  )
> > +{
> > +  CpuFlushTlb ();
> > +}
> > +
> > +/**
> > +  FlushTlb for all processors.
> > +**/
> > +VOID
> > +FlushTlbForAll (
> > +  VOID
> > +  )
> > +{
> > +  UINTN       Index;
> > +
> > +  FlushTlbOnCurrentProcessor (NULL);
> > +
> > +  if (gSmmCoreSmst.SmmStartupThisAp == NULL) {
> > +    DEBUG ((DEBUG_WARN, "Cannot flush TLB for APs\r\n"));
> > +    return;
> > +  }
> > +
> > +  for (Index = 0; Index < gSmmCoreSmst.NumberOfCpus; Index++) {
> > +    if (Index != gSmmCoreSmst.CurrentlyExecutingCpu) {
> > +      // Force to start up AP in blocking mode,
> > +      gSmmCoreSmst.SmmStartupThisAp (FlushTlbOnCurrentProcessor, Index,
> > NULL);
> > +      // Do not check return status, because AP might not be present in some
> > corner cases.
> > +    }
> > +  }
> > +}
> > +
> > +/**
> > +  This function sets the attributes for the memory region specified by
> > BaseAddress and
> > +  Length from their current attributes to the attributes specified by
> > Attributes.
> > +
> > +  @param[in]   BaseAddress      The physical address that is the start address
> > of a memory region.
> > +  @param[in]   Length           The size in bytes of the memory region.
> > +  @param[in]   Attributes       The bit mask of attributes to set for the
> > memory region.
> > +  @param[out]  IsSplitted       TRUE means page table splitted. FALSE means
> > page table not splitted.
> > +
> > +  @retval EFI_SUCCESS           The attributes were set for the memory region.
> > +  @retval EFI_ACCESS_DENIED     The attributes for the memory resource
> > range specified by
> > +                                BaseAddress and Length cannot be modified.
> > +  @retval EFI_INVALID_PARAMETER Length is zero.
> > +                                Attributes specified an illegal combination of attributes that
> > +                                cannot be set together.
> > +  @retval EFI_OUT_OF_RESOURCES  There are not enough system
> > resources to modify the attributes of
> > +                                the memory resource range.
> > +  @retval EFI_UNSUPPORTED       The processor does not support one or
> > more bytes of the memory
> > +                                resource range specified by BaseAddress and Length.
> > +                                The bit mask of attributes is not support for the memory
> > resource
> > +                                range specified by BaseAddress and Length.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +SmmSetMemoryAttributesEx (
> > +  IN  EFI_PHYSICAL_ADDRESS                       BaseAddress,
> > +  IN  UINT64                                     Length,
> > +  IN  UINT64                                     Attributes,
> > +  OUT BOOLEAN                                    *IsSplitted  OPTIONAL
> > +  )
> > +{
> > +  EFI_STATUS  Status;
> > +  BOOLEAN     IsModified;
> > +
> > +  Status = ConvertMemoryPageAttributes (BaseAddress, Length, Attributes,
> > TRUE, IsSplitted, &IsModified);
> > +  if (!EFI_ERROR(Status)) {
> > +    if (IsModified) {
> > +      //
> > +      // Flush TLB as last step
> > +      //
> > +      FlushTlbForAll();
> > +    }
> > +  }
> > +
> > +  return Status;
> > +}
> > +
> > +/**
> > +  This function clears the attributes for the memory region specified by
> > BaseAddress and
> > +  Length from their current attributes to the attributes specified by
> > Attributes.
> > +
> > +  @param[in]   BaseAddress      The physical address that is the start address
> > of a memory region.
> > +  @param[in]   Length           The size in bytes of the memory region.
> > +  @param[in]   Attributes       The bit mask of attributes to clear for the
> > memory region.
> > +  @param[out]  IsSplitted       TRUE means page table splitted. FALSE means
> > page table not splitted.
> > +
> > +  @retval EFI_SUCCESS           The attributes were cleared for the memory
> > region.
> > +  @retval EFI_ACCESS_DENIED     The attributes for the memory resource
> > range specified by
> > +                                BaseAddress and Length cannot be modified.
> > +  @retval EFI_INVALID_PARAMETER Length is zero.
> > +                                Attributes specified an illegal combination of attributes that
> > +                                cannot be set together.
> > +  @retval EFI_OUT_OF_RESOURCES  There are not enough system
> > resources to modify the attributes of
> > +                                the memory resource range.
> > +  @retval EFI_UNSUPPORTED       The processor does not support one or
> > more bytes of the memory
> > +                                resource range specified by BaseAddress and Length.
> > +                                The bit mask of attributes is not support for the memory
> > resource
> > +                                range specified by BaseAddress and Length.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +SmmClearMemoryAttributesEx (
> > +  IN  EFI_PHYSICAL_ADDRESS                       BaseAddress,
> > +  IN  UINT64                                     Length,
> > +  IN  UINT64                                     Attributes,
> > +  OUT BOOLEAN                                    *IsSplitted  OPTIONAL
> > +  )
> > +{
> > +  EFI_STATUS  Status;
> > +  BOOLEAN     IsModified;
> > +
> > +  Status = ConvertMemoryPageAttributes (BaseAddress, Length, Attributes,
> > FALSE, IsSplitted, &IsModified);
> > +  if (!EFI_ERROR(Status)) {
> > +    if (IsModified) {
> > +      //
> > +      // Flush TLB as last step
> > +      //
> > +      FlushTlbForAll();
> > +    }
> > +  }
> > +
> > +  return Status;
> > +}
> > +
> > +/**
> > +  This function sets the attributes for the memory region specified by
> > BaseAddress and
> > +  Length from their current attributes to the attributes specified by
> > Attributes.
> > +
> > +  @param[in]  BaseAddress      The physical address that is the start address
> > of a memory region.
> > +  @param[in]  Length           The size in bytes of the memory region.
> > +  @param[in]  Attributes       The bit mask of attributes to set for the memory
> > region.
> > +
> > +  @retval EFI_SUCCESS           The attributes were set for the memory region.
> > +  @retval EFI_ACCESS_DENIED     The attributes for the memory resource
> > range specified by
> > +                                BaseAddress and Length cannot be modified.
> > +  @retval EFI_INVALID_PARAMETER Length is zero.
> > +                                Attributes specified an illegal combination of attributes that
> > +                                cannot be set together.
> > +  @retval EFI_OUT_OF_RESOURCES  There are not enough system
> > resources to modify the attributes of
> > +                                the memory resource range.
> > +  @retval EFI_UNSUPPORTED       The processor does not support one or
> > more bytes of the memory
> > +                                resource range specified by BaseAddress and Length.
> > +                                The bit mask of attributes is not support for the memory
> > resource
> > +                                range specified by BaseAddress and Length.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +SmmSetMemoryAttributes (
> > +  IN  EFI_PHYSICAL_ADDRESS                       BaseAddress,
> > +  IN  UINT64                                     Length,
> > +  IN  UINT64                                     Attributes
> > +  )
> > +{
> > +  return SmmSetMemoryAttributesEx (BaseAddress, Length, Attributes,
> > NULL);
> > +}
> > +
> > +/**
> > +  This function clears the attributes for the memory region specified by
> > BaseAddress and
> > +  Length from their current attributes to the attributes specified by
> > Attributes.
> > +
> > +  @param[in]  BaseAddress      The physical address that is the start address
> > of a memory region.
> > +  @param[in]  Length           The size in bytes of the memory region.
> > +  @param[in]  Attributes       The bit mask of attributes to clear for the
> > memory region.
> > +
> > +  @retval EFI_SUCCESS           The attributes were cleared for the memory
> > region.
> > +  @retval EFI_ACCESS_DENIED     The attributes for the memory resource
> > range specified by
> > +                                BaseAddress and Length cannot be modified.
> > +  @retval EFI_INVALID_PARAMETER Length is zero.
> > +                                Attributes specified an illegal combination of attributes that
> > +                                cannot be set together.
> > +  @retval EFI_OUT_OF_RESOURCES  There are not enough system
> > resources to modify the attributes of
> > +                                the memory resource range.
> > +  @retval EFI_UNSUPPORTED       The processor does not support one or
> > more bytes of the memory
> > +                                resource range specified by BaseAddress and Length.
> > +                                The bit mask of attributes is not support for the memory
> > resource
> > +                                range specified by BaseAddress and Length.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +SmmClearMemoryAttributes (
> > +  IN  EFI_PHYSICAL_ADDRESS                       BaseAddress,
> > +  IN  UINT64                                     Length,
> > +  IN  UINT64                                     Attributes
> > +  )
> > +{
> > +  return SmmClearMemoryAttributesEx (BaseAddress, Length, Attributes,
> > NULL);
> > +}
> > +
> > +/**
> > +  Initialize the Page Table lib.
> > +**/
> > +VOID
> > +InitializePageTableLib (
> > +  VOID
> > +  )
> > +{
> > +  mAddressEncMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask)
> > & PAGING_1G_ADDRESS_MASK_64;
> > +  mPhysicalAddressBits = CalculateMaximumSupportAddress ();
> > +  DEBUG ((DEBUG_INFO, "mAddressEncMask      = 0x%lx\r\n",
> > mAddressEncMask));
> > +  DEBUG ((DEBUG_INFO, "mPhysicalAddressBits = %d\r\n",
> > mPhysicalAddressBits));
> > +  return ;
> > +}
> > +
> > diff --git a/MdeModulePkg/Core/PiSmmCore/Misc/PageTable.h
> > b/MdeModulePkg/Core/PiSmmCore/Misc/PageTable.h
> > new file mode 100644
> > index 0000000000..61a64af370
> > --- /dev/null
> > +++ b/MdeModulePkg/Core/PiSmmCore/Misc/PageTable.h
> > @@ -0,0 +1,174 @@
> > +/** @file
> > +  Page table management header file.
> > +
> > +  Copyright (c) 2017, 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.
> > +
> > +**/
> > +
> > +#ifndef _PAGE_TABLE_LIB_H_
> > +#define _PAGE_TABLE_LIB_H_
> > +
> > +///
> > +/// Page Table Entry
> > +///
> > +#define IA32_PG_P                   BIT0
> > +#define IA32_PG_RW                  BIT1
> > +#define IA32_PG_U                   BIT2
> > +#define IA32_PG_WT                  BIT3
> > +#define IA32_PG_CD                  BIT4
> > +#define IA32_PG_A                   BIT5
> > +#define IA32_PG_D                   BIT6
> > +#define IA32_PG_PS                  BIT7
> > +#define IA32_PG_PAT_2M              BIT12
> > +#define IA32_PG_PAT_4K              IA32_PG_PS
> > +#define IA32_PG_PMNT                BIT62
> > +#define IA32_PG_NX                  BIT63
> > +
> > +#define PAGE_ATTRIBUTE_BITS         (IA32_PG_D | IA32_PG_A |
> > IA32_PG_U | IA32_PG_RW | IA32_PG_P)
> > +//
> > +// Bits 1, 2, 5, 6 are reserved in the IA32 PAE PDPTE
> > +// X64 PAE PDPTE does not have such restriction
> > +//
> > +#define IA32_PAE_PDPTE_ATTRIBUTE_BITS    (IA32_PG_P)
> > +
> > +#define PAGE_PROGATE_BITS           (IA32_PG_NX | PAGE_ATTRIBUTE_BITS)
> > +
> > +#define PAGING_4K_MASK  0xFFF
> > +#define PAGING_2M_MASK  0x1FFFFF
> > +#define PAGING_1G_MASK  0x3FFFFFFF
> > +
> > +#define PAGING_PAE_INDEX_MASK  0x1FF
> > +
> > +#define PAGING_4K_ADDRESS_MASK_64 0x000FFFFFFFFFF000ull
> > +#define PAGING_2M_ADDRESS_MASK_64 0x000FFFFFFFE00000ull
> > +#define PAGING_1G_ADDRESS_MASK_64 0x000FFFFFC0000000ull
> > +
> > +#define SMRR_MAX_ADDRESS       BASE_4GB
> > +
> > +typedef enum {
> > +  PageNone = 0,
> > +  Page4K,
> > +  Page2M,
> > +  Page1G,
> > +} PAGE_ATTRIBUTE;
> > +
> > +typedef struct {
> > +  PAGE_ATTRIBUTE   Attribute;
> > +  UINT64           Length;
> > +  UINT64           AddressMask;
> > +} PAGE_ATTRIBUTE_TABLE;
> > +
> > +/**
> > +  Helper function to allocate pages without Guard for internal uses
> > +
> > +  @param[in]  Pages       Page number
> > +
> > +  @return Address of memory allocated
> > +**/
> > +VOID *
> > +PageAlloc (
> > +  IN UINTN  Pages
> > +  );
> > +
> > +/**
> > +  This function sets the attributes for the memory region specified by
> > BaseAddress and
> > +  Length from their current attributes to the attributes specified by
> > Attributes.
> > +
> > +  @param[in]   BaseAddress      The physical address that is the start address
> > of a memory region.
> > +  @param[in]   Length           The size in bytes of the memory region.
> > +  @param[in]   Attributes       The bit mask of attributes to set for the
> > memory region.
> > +  @param[out]  IsSplitted       TRUE means page table splitted. FALSE means
> > page table not splitted.
> > +
> > +  @retval EFI_SUCCESS           The attributes were set for the memory region.
> > +  @retval EFI_ACCESS_DENIED     The attributes for the memory resource
> > range specified by
> > +                                BaseAddress and Length cannot be modified.
> > +  @retval EFI_INVALID_PARAMETER Length is zero.
> > +                                Attributes specified an illegal combination of attributes that
> > +                                cannot be set together.
> > +  @retval EFI_OUT_OF_RESOURCES  There are not enough system
> > resources to modify the attributes of
> > +                                the memory resource range.
> > +  @retval EFI_UNSUPPORTED       The processor does not support one or
> > more bytes of the memory
> > +                                resource range specified by BaseAddress and Length.
> > +                                The bit mask of attributes is not support for the memory
> > resource
> > +                                range specified by BaseAddress and Length.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +SmmSetMemoryAttributes (
> > +  IN  EFI_PHYSICAL_ADDRESS                       BaseAddress,
> > +  IN  UINT64                                     Length,
> > +  IN  UINT64                                     Attributes
> > +  );
> > +
> > +/**
> > +  This function clears the attributes for the memory region specified by
> > BaseAddress and
> > +  Length from their current attributes to the attributes specified by
> > Attributes.
> > +
> > +  @param[in]   BaseAddress      The physical address that is the start address
> > of a memory region.
> > +  @param[in]   Length           The size in bytes of the memory region.
> > +  @param[in]   Attributes       The bit mask of attributes to clear for the
> > memory region.
> > +  @param[out]  IsSplitted       TRUE means page table splitted. FALSE means
> > page table not splitted.
> > +
> > +  @retval EFI_SUCCESS           The attributes were cleared for the memory
> > region.
> > +  @retval EFI_ACCESS_DENIED     The attributes for the memory resource
> > range specified by
> > +                                BaseAddress and Length cannot be modified.
> > +  @retval EFI_INVALID_PARAMETER Length is zero.
> > +                                Attributes specified an illegal combination of attributes that
> > +                                cannot be set together.
> > +  @retval EFI_OUT_OF_RESOURCES  There are not enough system
> > resources to modify the attributes of
> > +                                the memory resource range.
> > +  @retval EFI_UNSUPPORTED       The processor does not support one or
> > more bytes of the memory
> > +                                resource range specified by BaseAddress and Length.
> > +                                The bit mask of attributes is not support for the memory
> > resource
> > +                                range specified by BaseAddress and Length.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +SmmClearMemoryAttributes (
> > +  IN  EFI_PHYSICAL_ADDRESS                       BaseAddress,
> > +  IN  UINT64                                     Length,
> > +  IN  UINT64                                     Attributes
> > +  );
> > +
> > +/**
> > +  Initialize the Page Table lib.
> > +**/
> > +VOID
> > +InitializePageTableLib (
> > +  VOID
> > +  );
> > +
> > +/**
> > +  Return page table base.
> > +
> > +  @return page table base.
> > +**/
> > +UINTN
> > +GetPageTableBase (
> > +  VOID
> > +  );
> > +
> > +/**
> > +  Return page table entry to match the address.
> > +
> > +  @param[in]   Address          The address to be checked.
> > +  @param[out]  PageAttributes   The page attribute of the page entry.
> > +
> > +  @return The page entry.
> > +**/
> > +VOID *
> > +GetPageTableEntry (
> > +  IN  PHYSICAL_ADDRESS                  Address,
> > +  OUT PAGE_ATTRIBUTE                    *PageAttribute
> > +  );
> > +
> > +#endif
> > diff --git a/MdeModulePkg/Core/PiSmmCore/Page.c
> > b/MdeModulePkg/Core/PiSmmCore/Page.c
> > index 4154c2e6a1..29d1311f5a 100644
> > --- a/MdeModulePkg/Core/PiSmmCore/Page.c
> > +++ b/MdeModulePkg/Core/PiSmmCore/Page.c
> > @@ -64,6 +64,8 @@ LIST_ENTRY   mFreeMemoryMapEntryList =
> > INITIALIZE_LIST_HEAD_VARIABLE (mFreeMemor
> >    @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.
> > @@ -77,7 +79,8 @@ SmmInternalAllocatePagesEx (
> >    IN  EFI_MEMORY_TYPE       MemoryType,
> >    IN  UINTN                 NumberOfPages,
> >    OUT EFI_PHYSICAL_ADDRESS  *Memory,
> > -  IN  BOOLEAN               AddRegion
> > +  IN  BOOLEAN               AddRegion,
> > +  IN  BOOLEAN               NeedGuard
> >    );
> >
> >  /**
> > @@ -112,7 +115,8 @@ AllocateMemoryMapEntry (
> >                 EfiRuntimeServicesData,
> >                 EFI_SIZE_TO_PAGES (RUNTIME_PAGE_ALLOCATION_GRANULARITY),
> >                 &Mem,
> > -               TRUE
> > +               TRUE,
> > +               FALSE
> >                 );
> >      ASSERT_EFI_ERROR (Status);
> >      if(!EFI_ERROR (Status)) {
> > @@ -688,6 +692,8 @@ InternalAllocAddress (
> >    @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.
> > @@ -701,7 +707,8 @@ SmmInternalAllocatePagesEx (
> >    IN  EFI_MEMORY_TYPE       MemoryType,
> >    IN  UINTN                 NumberOfPages,
> >    OUT EFI_PHYSICAL_ADDRESS  *Memory,
> > -  IN  BOOLEAN               AddRegion
> > +  IN  BOOLEAN               AddRegion,
> > +  IN  BOOLEAN               NeedGuard
> >    )
> >  {
> >    UINTN  RequestedAddress;
> > @@ -723,6 +730,21 @@ SmmInternalAllocatePagesEx (
> >      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,
> > @@ -766,6 +788,8 @@ SmmInternalAllocatePagesEx (
> >    @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.
> > @@ -779,10 +803,12 @@ SmmInternalAllocatePages (
> >    IN  EFI_ALLOCATE_TYPE     Type,
> >    IN  EFI_MEMORY_TYPE       MemoryType,
> >    IN  UINTN                 NumberOfPages,
> > -  OUT EFI_PHYSICAL_ADDRESS  *Memory
> > +  OUT EFI_PHYSICAL_ADDRESS  *Memory,
> > +  IN  BOOLEAN               NeedGuard
> >    )
> >  {
> > -  return SmmInternalAllocatePagesEx (Type, MemoryType, NumberOfPages,
> > Memory, FALSE);
> > +  return SmmInternalAllocatePagesEx (Type, MemoryType,
> > NumberOfPages, Memory,
> > +                                     FALSE, NeedGuard);
> >  }
> >
> >  /**
> > @@ -811,8 +837,11 @@ SmmAllocatePages (
> >    )
> >  {
> >    EFI_STATUS  Status;
> > +  BOOLEAN     NeedGuard;
> >
> > -  Status = SmmInternalAllocatePages (Type, MemoryType, NumberOfPages,
> > Memory);
> > +  NeedGuard = IsPageTypeToGuard (MemoryType, Type);
> > +  Status = SmmInternalAllocatePages (Type, MemoryType, NumberOfPages,
> > Memory,
> > +                                     NeedGuard);
> >    if (!EFI_ERROR (Status)) {
> >      SmmCoreUpdateProfile (
> >        (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),
> > @@ -941,9 +970,13 @@ EFI_STATUS
> >  EFIAPI
> >  SmmInternalFreePages (
> >    IN EFI_PHYSICAL_ADDRESS  Memory,
> > -  IN UINTN                 NumberOfPages
> > +  IN UINTN                 NumberOfPages,
> > +  IN BOOLEAN               IsGuarded
> >    )
> >  {
> > +  if (IsGuarded) {
> > +    return SmmInternalFreePagesExWithGuard (Memory, NumberOfPages,
> > FALSE);
> > +  }
> >    return SmmInternalFreePagesEx (Memory, NumberOfPages, FALSE);
> >  }
> >
> > @@ -966,8 +999,10 @@ SmmFreePages (
> >    )
> >  {
> >    EFI_STATUS  Status;
> > +  BOOLEAN     IsGuarded;
> >
> > -  Status = SmmInternalFreePages (Memory, NumberOfPages);
> > +  IsGuarded = IsHeapGuardEnabled () && IsMemoryGuarded (Memory);
> > +  Status = SmmInternalFreePages (Memory, NumberOfPages, IsGuarded);
> >    if (!EFI_ERROR (Status)) {
> >      SmmCoreUpdateProfile (
> >        (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),
> > diff --git a/MdeModulePkg/Core/PiSmmCore/PiSmmCore.c
> > b/MdeModulePkg/Core/PiSmmCore/PiSmmCore.c
> > index 9e4390e15a..b4609c2fed 100644
> > --- a/MdeModulePkg/Core/PiSmmCore/PiSmmCore.c
> > +++ b/MdeModulePkg/Core/PiSmmCore/PiSmmCore.c
> > @@ -451,6 +451,11 @@ SmmEntryPoint (
> >    //
> >    PlatformHookBeforeSmmDispatch ();
> >
> > +  //
> > +  // Call memory management hook function
> > +  //
> > +  SmmEntryPointMemoryManagementHook ();
> > +
> >    //
> >    // If a legacy boot has occured, then make sure gSmmCorePrivate is not
> > accessed
> >    //
> > @@ -644,7 +649,12 @@ SmmMain (
> >    //
> >    gSmmCorePrivate->Smst          = &gSmmCoreSmst;
> >    gSmmCorePrivate->SmmEntryPoint = SmmEntryPoint;
> > -
> > +
> > +  //
> > +  // Initialize page table operations
> > +  //
> > +  InitializePageTableLib();
> > +
> >    //
> >    // No need to initialize memory service.
> >    // It is done in constructor of PiSmmCoreMemoryAllocationLib(),
> > diff --git a/MdeModulePkg/Core/PiSmmCore/PiSmmCore.h
> > b/MdeModulePkg/Core/PiSmmCore/PiSmmCore.h
> > index b6f815c68d..8c61fdcf0c 100644
> > --- a/MdeModulePkg/Core/PiSmmCore/PiSmmCore.h
> > +++ b/MdeModulePkg/Core/PiSmmCore/PiSmmCore.h
> > @@ -59,6 +59,7 @@
> >  #include <Library/SmmMemLib.h>
> >
> >  #include "PiSmmCorePrivateData.h"
> > +#include "Misc/HeapGuard.h"
> >
> >  //
> >  // Used to build a table of SMI Handlers that the SMM Core registers
> > @@ -317,6 +318,7 @@ SmmAllocatePages (
> >    @param  NumberOfPages          The number of pages to allocate
> >    @param  Memory                 A pointer to receive the base allocated memory
> >                                   address
> > +  @param  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.
> > @@ -330,7 +332,8 @@ SmmInternalAllocatePages (
> >    IN      EFI_ALLOCATE_TYPE         Type,
> >    IN      EFI_MEMORY_TYPE           MemoryType,
> >    IN      UINTN                     NumberOfPages,
> > -  OUT     EFI_PHYSICAL_ADDRESS      *Memory
> > +  OUT     EFI_PHYSICAL_ADDRESS      *Memory,
> > +  IN      BOOLEAN                   NeedGuard
> >    );
> >
> >  /**
> > @@ -356,6 +359,8 @@ SmmFreePages (
> >
> >    @param  Memory                 Base address of memory being freed
> >    @param  NumberOfPages          The number of pages to free
> > +  @param  IsGuarded              Flag to indicate if the memory is 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.
> > @@ -366,7 +371,8 @@ EFI_STATUS
> >  EFIAPI
> >  SmmInternalFreePages (
> >    IN      EFI_PHYSICAL_ADDRESS      Memory,
> > -  IN      UINTN                     NumberOfPages
> > +  IN      UINTN                     NumberOfPages,
> > +  IN      BOOLEAN                   IsGuarded
> >    );
> >
> >  /**
> > @@ -1231,4 +1237,74 @@ typedef enum {
> >
> >  extern LIST_ENTRY
> > mSmmPoolLists[SmmPoolTypeMax][MAX_POOL_INDEX];
> >
> > +/**
> > +  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
> > +  );
> > +
> > +/**
> > +  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
> > +  );
> > +
> > +/**
> > +  Internal function.  Moves any memory descriptors that are on the
> > +  temporary descriptor stack to heap.
> > +
> > +**/
> > +VOID
> > +CoreFreeMemoryMapStack (
> > +  VOID
> > +  );
> > +
> > +/**
> > +  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
> > +  );
> > +
> > +/**
> > +  Hook function used to set all Guard pages after entering SMM mode
> > +**/
> > +VOID
> > +SmmEntryPointMemoryManagementHook (
> > +  VOID
> > +  );
> > +
> >  #endif
> > diff --git a/MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
> > b/MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
> > index 49ae6fbb57..e505b165bc 100644
> > --- a/MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
> > +++ b/MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf
> > @@ -40,6 +40,8 @@
> >    SmramProfileRecord.c
> >    MemoryAttributesTable.c
> >    SmiHandlerProfile.c
> > +  Misc/HeapGuard.c
> > +  Misc/PageTable.c
> >
> >  [Packages]
> >    MdePkg/MdePkg.dec
> > @@ -65,6 +67,7 @@
> >    HobLib
> >    SmmMemLib
> >    DxeServicesLib
> > +  CpuLib
> >
> >  [Protocols]
> >    gEfiDxeSmmReadyToLockProtocolGuid             ## UNDEFINED #
> > SmiHandlerRegister
> > @@ -88,6 +91,7 @@
> >    gEfiSmmGpiDispatch2ProtocolGuid               ## SOMETIMES_CONSUMES
> >    gEfiSmmIoTrapDispatch2ProtocolGuid            ## SOMETIMES_CONSUMES
> >    gEfiSmmUsbDispatch2ProtocolGuid               ## SOMETIMES_CONSUMES
> > +  gEfiSmmCpuProtocolGuid                        ## SOMETIMES_CONSUMES
> >
> >  [Pcd]
> >
> > gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressSmmCodePageNum
> > ber     ## SOMETIMES_CONSUMES
> > @@ -96,6 +100,10 @@
> >    gEfiMdeModulePkgTokenSpaceGuid.PcdMemoryProfilePropertyMask
> > ## CONSUMES
> >    gEfiMdeModulePkgTokenSpaceGuid.PcdMemoryProfileDriverPath
> > ## CONSUMES
> >    gEfiMdeModulePkgTokenSpaceGuid.PcdSmiHandlerProfilePropertyMask
> > ## CONSUMES
> > +  gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPageType                   ##
> > CONSUMES
> > +  gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPoolType                   ##
> > CONSUMES
> > +  gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPropertyMask
> > ## CONSUMES
> > +
> > gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrM
> > ask    ## CONSUMES
> >
> >  [Guids]
> >    gAprioriGuid                                  ## SOMETIMES_CONSUMES   ## File
> > diff --git a/MdeModulePkg/Core/PiSmmCore/Pool.c
> > b/MdeModulePkg/Core/PiSmmCore/Pool.c
> > index 36317563c4..1f9213ea6e 100644
> > --- a/MdeModulePkg/Core/PiSmmCore/Pool.c
> > +++ b/MdeModulePkg/Core/PiSmmCore/Pool.c
> > @@ -144,7 +144,9 @@ InternalAllocPoolByIndex (
> >    Status = EFI_SUCCESS;
> >    Hdr = NULL;
> >    if (PoolIndex == MAX_POOL_INDEX) {
> > -    Status = SmmInternalAllocatePages (AllocateAnyPages, PoolType,
> > EFI_SIZE_TO_PAGES (MAX_POOL_SIZE << 1), &Address);
> > +    Status = SmmInternalAllocatePages (AllocateAnyPages, PoolType,
> > +                                       EFI_SIZE_TO_PAGES (MAX_POOL_SIZE << 1),
> > +                                       &Address, FALSE);
> >      if (EFI_ERROR (Status)) {
> >        return EFI_OUT_OF_RESOURCES;
> >      }
> > @@ -243,6 +245,9 @@ SmmInternalAllocatePool (
> >    EFI_STATUS            Status;
> >    EFI_PHYSICAL_ADDRESS  Address;
> >    UINTN                 PoolIndex;
> > +  BOOLEAN               HasPoolTail;
> > +  BOOLEAN               NeedGuard;
> > +  UINTN                 NoPages;
> >
> >    Address = 0;
> >
> > @@ -251,25 +256,45 @@ SmmInternalAllocatePool (
> >      return EFI_INVALID_PARAMETER;
> >    }
> >
> > +  NeedGuard   = IsPoolTypeToGuard (PoolType);
> > +  HasPoolTail = !(NeedGuard &&
> > +                  ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0));
> > +
> >    //
> >    // Adjust the size by the pool header & tail overhead
> >    //
> >    Size += POOL_OVERHEAD;
> > -  if (Size > MAX_POOL_SIZE) {
> > -    Size = EFI_SIZE_TO_PAGES (Size);
> > -    Status = SmmInternalAllocatePages (AllocateAnyPages, PoolType, Size,
> > &Address);
> > +  if (Size > MAX_POOL_SIZE || NeedGuard) {
> > +    if (!HasPoolTail) {
> > +      Size -= sizeof (POOL_TAIL);
> > +    }
> > +
> > +    NoPages = EFI_SIZE_TO_PAGES (Size);
> > +    Status = SmmInternalAllocatePages (AllocateAnyPages, PoolType,
> > NoPages,
> > +                                       &Address, NeedGuard);
> >      if (EFI_ERROR (Status)) {
> >        return Status;
> >      }
> >
> > +    if (NeedGuard) {
> > +      ASSERT (VerifyMemoryGuard(Address, NoPages) == TRUE);
> > +      DEBUG ((DEBUG_INFO, "SmmInternalAllocatePool: %lx ->", Address));
> > +      Address = (EFI_PHYSICAL_ADDRESS)AdjustPoolHeadA (Address,
> > NoPages, Size);
> > +      DEBUG ((DEBUG_INFO, " %lx %d %x\r\n", Address, NoPages, Size));
> > +    }
> > +
> >      PoolHdr = (POOL_HEADER*)(UINTN)Address;
> >      PoolHdr->Signature = POOL_HEAD_SIGNATURE;
> > -    PoolHdr->Size = EFI_PAGES_TO_SIZE (Size);
> > +    PoolHdr->Size = Size; //EFI_PAGES_TO_SIZE (NoPages)
> >      PoolHdr->Available = FALSE;
> >      PoolHdr->Type = PoolType;
> > -    PoolTail = HEAD_TO_TAIL(PoolHdr);
> > -    PoolTail->Signature = POOL_TAIL_SIGNATURE;
> > -    PoolTail->Size = PoolHdr->Size;
> > +
> > +    if (HasPoolTail) {
> > +      PoolTail = HEAD_TO_TAIL (PoolHdr);
> > +      PoolTail->Signature = POOL_TAIL_SIGNATURE;
> > +      PoolTail->Size = PoolHdr->Size;
> > +    }
> > +
> >      *Buffer = PoolHdr + 1;
> >      return Status;
> >    }
> > @@ -341,28 +366,45 @@ SmmInternalFreePool (
> >  {
> >    FREE_POOL_HEADER  *FreePoolHdr;
> >    POOL_TAIL         *PoolTail;
> > +  BOOLEAN           HasPoolTail;
> > +  BOOLEAN           MemoryGuarded;
> >
> >    if (Buffer == NULL) {
> >      return EFI_INVALID_PARAMETER;
> >    }
> >
> > +  MemoryGuarded = IsHeapGuardEnabled () &&
> > +                  IsMemoryGuarded ((EFI_PHYSICAL_ADDRESS)(UINTN)Buffer);
> > +  HasPoolTail   = !(MemoryGuarded &&
> > +                    ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0));
> > +
> >    FreePoolHdr = (FREE_POOL_HEADER*)((POOL_HEADER*)Buffer - 1);
> >    ASSERT (FreePoolHdr->Header.Signature == POOL_HEAD_SIGNATURE);
> >    ASSERT (!FreePoolHdr->Header.Available);
> > -  PoolTail = HEAD_TO_TAIL(&FreePoolHdr->Header);
> > -  ASSERT (PoolTail->Signature == POOL_TAIL_SIGNATURE);
> > -  ASSERT (FreePoolHdr->Header.Size == PoolTail->Size);
> > -
> >    if (FreePoolHdr->Header.Signature != POOL_HEAD_SIGNATURE) {
> >      return EFI_INVALID_PARAMETER;
> >    }
> >
> > -  if (PoolTail->Signature != POOL_TAIL_SIGNATURE) {
> > -    return EFI_INVALID_PARAMETER;
> > +  if (HasPoolTail) {
> > +    PoolTail = HEAD_TO_TAIL (&FreePoolHdr->Header);
> > +    ASSERT (PoolTail->Signature == POOL_TAIL_SIGNATURE);
> > +    ASSERT (FreePoolHdr->Header.Size == PoolTail->Size);
> > +    if (PoolTail->Signature != POOL_TAIL_SIGNATURE) {
> > +      return EFI_INVALID_PARAMETER;
> > +    }
> > +
> > +    if (FreePoolHdr->Header.Size != PoolTail->Size) {
> > +      return EFI_INVALID_PARAMETER;
> > +    }
> >    }
> >
> > -  if (FreePoolHdr->Header.Size != PoolTail->Size) {
> > -    return EFI_INVALID_PARAMETER;
> > +  if (MemoryGuarded) {
> > +    Buffer = AdjustPoolHeadF
> > ((EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr);
> > +    return SmmInternalFreePages (
> > +             (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer,
> > +             EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size),
> > +             TRUE
> > +             );
> >    }
> >
> >    if (FreePoolHdr->Header.Size > MAX_POOL_SIZE) {
> > @@ -370,7 +412,8 @@ SmmInternalFreePool (
> >      ASSERT ((FreePoolHdr->Header.Size & EFI_PAGE_MASK) == 0);
> >      return SmmInternalFreePages (
> >               (EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr,
> > -             EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size)
> > +             EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size),
> > +             FALSE
> >               );
> >    }
> >    return InternalFreePoolByIndex (FreePoolHdr, PoolTail);
> > --
> > 2.14.1.windows.1



  reply	other threads:[~2017-10-13  6:11 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-10-11  3:18 [PATCH 0/5] Implement heap guard feature Jian J Wang
2017-10-11  3:18 ` [PATCH 1/5] MdeModulePkg/DxeCore: Implement heap guard feature for UEFI Jian J Wang
2017-10-11  3:18 ` [PATCH 2/5] MdeModulePkg/PiSmmCore: Implement heap guard feature for SMM mode Jian J Wang
2017-10-13  1:27   ` Dong, Eric
2017-10-13  6:15     ` Wang, Jian J [this message]
2017-10-11  3:18 ` [PATCH 3/5] MdeModulePkg/MdeModulePkg.dec, .uni: Add heap guard related PCDs and string tokens Jian J Wang
2017-10-11  3:18 ` [PATCH 4/5] UefiCpuPkg/CpuDxe: Reduce debug message Jian J Wang
2017-10-11  3:18 ` [PATCH 5/5] UefiCpuPkg/PiSmmCpuDxeSmm: Disable page table protection Jian J Wang
2017-10-13  1:24   ` Dong, Eric
2017-10-13  6:14     ` Wang, Jian J

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=D827630B58408649ACB04F44C510003624CA1B30@SHSMSX103.ccr.corp.intel.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox