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
next prev parent 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