From: "Dong, Eric" <eric.dong@intel.com>
To: "Wang, Jian J" <jian.j.wang@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 01:27:23 +0000 [thread overview]
Message-ID: <ED077930C258884BBCB450DB737E66224AA1A43F@SHSMSX151.ccr.corp.intel.com> (raw)
In-Reply-To: <20171011031824.17060-3-jian.j.wang@intel.com>
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 1:23 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 [this message]
2017-10-13 6:15 ` Wang, Jian J
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=ED077930C258884BBCB450DB737E66224AA1A43F@SHSMSX151.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