From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=134.134.136.100; helo=mga07.intel.com; envelope-from=eric.dong@intel.com; receiver=edk2-devel@lists.01.org Received: from mga07.intel.com (mga07.intel.com [134.134.136.100]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id D436D21E781F9 for ; Thu, 12 Oct 2017 18:23:56 -0700 (PDT) Received: from orsmga003.jf.intel.com ([10.7.209.27]) by orsmga105.jf.intel.com with ESMTP; 12 Oct 2017 18:27:27 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.43,369,1503385200"; d="scan'208";a="1024685668" Received: from fmsmsx104.amr.corp.intel.com ([10.18.124.202]) by orsmga003.jf.intel.com with ESMTP; 12 Oct 2017 18:27:26 -0700 Received: from shsmsx103.ccr.corp.intel.com (10.239.4.69) by fmsmsx104.amr.corp.intel.com (10.18.124.202) with Microsoft SMTP Server (TLS) id 14.3.319.2; Thu, 12 Oct 2017 18:27:26 -0700 Received: from shsmsx151.ccr.corp.intel.com ([169.254.3.98]) by SHSMSX103.ccr.corp.intel.com ([169.254.4.213]) with mapi id 14.03.0319.002; Fri, 13 Oct 2017 09:27:24 +0800 From: "Dong, Eric" To: "Wang, Jian J" , "edk2-devel@lists.01.org" CC: "Zeng, Star" , "Yao, Jiewen" , "Kinney, Michael D" , "Wolman, Ayellet" Thread-Topic: [PATCH 2/5] MdeModulePkg/PiSmmCore: Implement heap guard feature for SMM mode Thread-Index: AQHTQj+nF6GMfcjJ6Eq14ENJQWJ2MKLg/5sw Date: Fri, 13 Oct 2017 01:27:23 +0000 Message-ID: References: <20171011031824.17060-1-jian.j.wang@intel.com> <20171011031824.17060-3-jian.j.wang@intel.com> In-Reply-To: <20171011031824.17060-3-jian.j.wang@intel.com> Accept-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-originating-ip: [10.239.127.40] MIME-Version: 1.0 Subject: Re: [PATCH 2/5] MdeModulePkg/PiSmmCore: Implement heap guard feature for SMM mode X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 13 Oct 2017 01:23:57 -0000 Content-Language: en-US Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable 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] + =3D GUARDED_HEAP_MAP_TABLE_DEPTH_SHIFTS; + UINTN LevelMask[GUARDED_HEAP_MAP_TABLE_DEPTH] + =3D 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 ; Dong, Eric ; Y= ao, > Jiewen ; Kinney, Michael D > ; Wolman, Ayellet > > Subject: [PATCH 2/5] MdeModulePkg/PiSmmCore: Implement heap guard > feature for SMM mode >=20 > 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. >=20 > This feature is controlled by three PCDs: >=20 > gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPropertyMask > gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPoolType > gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPageType >=20 > 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 typ= e > of memory. For example, we can turn on guard only for EfiBootServicesData > and EfiRuntimeServicesData by setting the PCD with value 0x50. >=20 > Pool memory is not ususally integer multiple of one page, and is more lik= ely > 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 memo= ry > overflow in memory growing direction or in decreasing direction. >=20 > Cc: Star Zeng > Cc: Eric Dong > Cc: Jiewen Yao > Cc: Michael Kinney > Cc: Ayellet Wolman > Suggested-by: Ayellet Wolman > Contributed-under: TianoCore Contribution Agreement 1.1 > Signed-off-by: Jian J Wang > --- > 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 >=20 > 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.
> +This program and the accompanying materials > +are licensed and made available under the terms and conditions of the BS= D > License > +which accompanies this distribution. The full text of the license may b= e > 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 =3D > 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 =3D 1; > + > +// > +// SMM status flag > +// > +BOOLEAN mIsSmmCpuMode =3D 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 =3D (UINTN)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address); > + EndBit =3D (StartBit + BitNumber - 1) % GUARDED_HEAP_MAP_ENTRY_BITS= ; > + > + if ((StartBit + BitNumber) > GUARDED_HEAP_MAP_ENTRY_BITS) { > + Msbs =3D (GUARDED_HEAP_MAP_ENTRY_BITS - StartBit) % > + GUARDED_HEAP_MAP_ENTRY_BITS; > + Lsbs =3D (EndBit + 1) % GUARDED_HEAP_MAP_ENTRY_BITS; > + Qwords =3D (BitNumber - Msbs) / GUARDED_HEAP_MAP_ENTRY_BITS; > + } else { > + Msbs =3D BitNumber; > + Lsbs =3D 0; > + Qwords =3D 0; > + } > + > + if (Msbs > 0) { > + *BitMap |=3D LShiftU64 (LShiftU64 (1, Msbs) - 1, StartBit); > + BitMap +=3D 1; > + } > + > + if (Qwords > 0) { > + SetMem64 ((VOID *)BitMap, Qwords * > GUARDED_HEAP_MAP_ENTRY_BYTES, > + (UINT64)-1); > + BitMap +=3D Qwords; > + } > + > + if (Lsbs > 0) { > + *BitMap |=3D (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 =3D (UINTN)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address); > + EndBit =3D (StartBit + BitNumber - 1) % GUARDED_HEAP_MAP_ENTRY_BITS= ; > + > + if ((StartBit + BitNumber) > GUARDED_HEAP_MAP_ENTRY_BITS) { > + Msbs =3D (GUARDED_HEAP_MAP_ENTRY_BITS - StartBit) % > + GUARDED_HEAP_MAP_ENTRY_BITS; > + Lsbs =3D (EndBit + 1) % GUARDED_HEAP_MAP_ENTRY_BITS; > + Qwords =3D (BitNumber - Msbs) / GUARDED_HEAP_MAP_ENTRY_BITS; > + } else { > + Msbs =3D BitNumber; > + Lsbs =3D 0; > + Qwords =3D 0; > + } > + > + if (Msbs > 0) { > + *BitMap &=3D ~LShiftU64 (LShiftU64 (1, Msbs) - 1, StartBit); > + BitMap +=3D 1; > + } > + > + if (Qwords > 0) { > + SetMem64 ((VOID *)BitMap, Qwords * > GUARDED_HEAP_MAP_ENTRY_BYTES, 0); > + BitMap +=3D Qwords; > + } > + > + if (Lsbs > 0) { > + *BitMap &=3D ~(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 Addres= s. > + 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 <=3D GUARDED_HEAP_MAP_ENTRY_BITS); > + > + StartBit =3D (UINTN)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address); > + EndBit =3D (StartBit + BitNumber - 1) % GUARDED_HEAP_MAP_ENTRY_BITS= ; > + > + if ((StartBit + BitNumber) > GUARDED_HEAP_MAP_ENTRY_BITS) { > + Msbs =3D GUARDED_HEAP_MAP_ENTRY_BITS - StartBit; > + Lsbs =3D (EndBit + 1) % GUARDED_HEAP_MAP_ENTRY_BITS; > + } else { > + Msbs =3D BitNumber; > + Lsbs =3D 0; > + } > + > + Result =3D RShiftU64 ((*BitMap), StartBit) & (LShiftU64 (1, Msbs) -= 1); > + if (Lsbs > 0) { > + BitMap +=3D 1; > + Result |=3D 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 =3D SmmInternalAllocatePages (AllocateAnyPages, > EfiRuntimeServicesData, > + Pages, &Memory, FALSE); > + if (EFI_ERROR (Status)) { > + Memory =3D 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 t= able > + @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] > + =3D GUARDED_HEAP_MAP_TABLE_DEPTH_SHIFTS; > + UINTN LevelMask[GUARDED_HEAP_MAP_TABLE_DEPTH] > + =3D 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] > + ) !=3D 0) { > + > + if (mGuardedMemoryMap !=3D NULL) { > + Size =3D (LevelMask[GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel - > 1] + 1) > + * GUARDED_HEAP_MAP_ENTRY_BYTES; > + MapMemory =3D PageAlloc (EFI_SIZE_TO_PAGES (Size)); > + ASSERT (MapMemory !=3D NULL); > + > + SetMem ((VOID *)MapMemory, Size, 0); > + > + *(UINT64 **)MapMemory =3D mGuardedMemoryMap; > + mGuardedMemoryMap =3D MapMemory; > + } > + > + mMapLevel++; > + > + } > + > + GuardMap =3D &mGuardedMemoryMap; > + for (Level =3D GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel; > + Level < GUARDED_HEAP_MAP_TABLE_DEPTH; > + ++Level) { > + > + if (*GuardMap =3D=3D NULL) { > + if (!AllocMapUnit) { > + GuardMap =3D NULL; > + break; > + } > + > + Size =3D (LevelMask[Level] + 1) * GUARDED_HEAP_MAP_ENTRY_BYTES; > + MapMemory =3D PageAlloc (EFI_SIZE_TO_PAGES (Size)); > + ASSERT (MapMemory !=3D NULL); > + > + SetMem ((VOID *)MapMemory, Size, 0); > + *GuardMap =3D (UINT64 *)MapMemory; > + } > + > + Index =3D (UINTN)RShiftU64 (Address, LevelShift[Level]); > + Index &=3D LevelMask[Level]; > + GuardMap =3D (UINT64 **)((*GuardMap) + Index); > + > + } > + > + BitsToUnitEnd =3D GUARDED_HEAP_MAP_BITS - > GUARDED_HEAP_MAP_BIT_INDEX (Address); > + *BitMap =3D (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 =3D FindGuardedMemoryMap (Address, TRUE, &BitMap); > + ASSERT (BitMap !=3D NULL); > + > + if (NumberOfPages > BitsToUnitEnd) { > + // Cross map unit > + Bits =3D BitsToUnitEnd; > + } else { > + Bits =3D NumberOfPages; > + } > + > + SetBits (Address, Bits, BitMap); > + > + NumberOfPages -=3D Bits; > + Address +=3D EFI_PAGES_TO_SIZE (Bits); > + } > +} > + > +/** > + Clear corresponding bits in bitmap table according to given memory ran= ge > + > + @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 =3D FindGuardedMemoryMap (Address, TRUE, &BitMap); > + ASSERT (BitMap !=3D NULL); > + > + if (NumberOfPages > BitsToUnitEnd) { > + // Cross map unit > + Bits =3D BitsToUnitEnd; > + } else { > + Bits =3D NumberOfPages; > + } > + > + ClearBits (Address, Bits, BitMap); > + > + NumberOfPages -=3D Bits; > + Address +=3D 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 <=3D GUARDED_HEAP_MAP_ENTRY_BITS); > + > + Result =3D 0; > + Shift =3D 0; > + while (NumberOfPages > 0) { > + BitsToUnitEnd =3D FindGuardedMemoryMap (Address, FALSE, &BitMap); > + > + if (NumberOfPages > BitsToUnitEnd) { > + // Cross map unit > + Bits =3D BitsToUnitEnd; > + } else { > + Bits =3D NumberOfPages; > + } > + > + if (BitMap !=3D NULL) { > + Result |=3D LShiftU64 (GetBits (Address, Bits, BitMap), Shift); > + } > + > + Shift +=3D Bits; > + NumberOfPages -=3D Bits; > + Address +=3D 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 !=3D 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 !=3D NULL) { > + BitMask =3D LShiftU64 (1, GUARDED_HEAP_MAP_ENTRY_BIT_INDEX > (Address)); > + *GuardMap |=3D 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 !=3D NULL) { > + BitMask =3D LShiftU64 (1, GUARDED_HEAP_MAP_ENTRY_BIT_INDEX > (Address)); > + *GuardMap &=3D ~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 =3D GetGuardedMemoryBits (Address - EFI_PAGE_SIZE, 3); > + return (BitMap =3D=3D 0b001 || BitMap =3D=3D 0b100 || BitMap =3D=3D 0b= 101); > +} > + > +/** > + 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) =3D=3D 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) =3D=3D 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) =3D=3D 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 n= ot > + > + @param[in] MemoryType Memory type to check > + @param[in] AllocateType Allocation type to check > + @param[in] PageOrPool Indicate a page allocation or pool allocat= ion > + > + > + @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) =3D=3D 0 || > + AllocateType =3D=3D AllocateAddress) { > + return FALSE; > + } > + > + ConfigBit =3D 0; > + if (PageOrPool & GUARD_HEAP_TYPE_POOL) { > + ConfigBit |=3D PcdGet64 (PcdHeapGuardPoolType); > + } > + > + if (PageOrPool & GUARD_HEAP_TYPE_PAGE) { > + ConfigBit |=3D PcdGet64 (PcdHeapGuardPageType); > + } > + > + if (MemoryType =3D=3D EfiRuntimeServicesData || > + MemoryType =3D=3D EfiRuntimeServicesCode) { > + TestBit =3D LShiftU64 (1, MemoryType); > + } else if (MemoryType =3D=3D EfiMaxMemoryType) { > + TestBit =3D (UINT64)-1; > + } else { > + TestBit =3D 0; > + } > + > + return ((ConfigBit & TestBit) !=3D 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 allocat= ion > + > + @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 =3D Memory + EFI_PAGES_TO_SIZE (NumberOfPages); > + if (!IsGuardPage (GuardPage)) { > + SetGuardPage (GuardPage); > + } > + > + // Set head Guard > + GuardPage =3D 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 =3D=3D 0) { > + return; > + } > + > + // > + // Head Guard must be one page before, if any. > + // > + GuardPage =3D 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 fr= ee > + // 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 =3D 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 fre= e > + // 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 =3D 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 -=3D EFI_PAGES_TO_SIZE (1); > + } > + > + // Out of range? > + if (Target < Start) { > + return 0; > + } > + > + // At the edge? > + if (Target =3D=3D Start) { > + if (!IsGuardPage (Target - EFI_PAGES_TO_SIZE (1))) { > + // No enough space for a new head Guard if no Guard at head to sha= re. > + 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 Guar= d > + > + 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. An= other > + 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 =3D=3D NULL || NumberOfPages =3D=3D NULL || *NumberOfPages = =3D=3D > 0) { > + return; > + } > + > + Start =3D *Memory; > + PagesToFree =3D *NumberOfPages; > + > + // > + // Head Guard must be one page before, if any. > + // > + MemoryToTest =3D 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 -=3D EFI_PAGES_TO_SIZE (1); > + PagesToFree +=3D 1; > + } > + } else if (IsMemoryGuarded (MemoryToTest)) { > + // > + // Pages before memory to free are still in Guard. It's a partial fr= ee > + // case. We need to keep one page to be a tail Guard. > + // > + Start +=3D EFI_PAGES_TO_SIZE (1); > + PagesToFree -=3D 1; > + } > + > + // > + // Tail Guard must be the page after this memory block to free, if any= . > + // > + MemoryToTest =3D 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 +=3D 1; > + } > + } else if (IsMemoryGuarded (MemoryToTest)) { > + // > + // Pages after memory to free are still in Guard. It's a partial fre= e > + // case. We need to keep one page to be a head Guard. > + // > + PagesToFree -=3D 1; > + } > + > + *Memory =3D Start; > + *NumberOfPages =3D PagesToFree; > +} > + > +/** > + Adjust the base and number of pages to really allocate according to Gu= ard > + > + @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 +=3D 1; > + } > + > + if (!IsGuardPage (*Memory - EFI_PAGE_SIZE)) { > + // No head Guard, add one. > + *Memory -=3D EFI_PAGE_SIZE; > + *NumberOfPages +=3D 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) !=3D 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) !=3D 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 =3D FreePageList->BackLink; Node !=3D FreePageList; > + Node =3D Node->BackLink) { > + Pages =3D BASE_CR (Node, FREE_PAGE_LIST, Link); > + if (Pages->NumberOfPages >=3D NumberOfPages && > + (UINTN)Pages + EFI_PAGES_TO_SIZE (NumberOfPages) - 1 <=3D > MaxAddress) { > + > + // > + // We may need 1 or 2 more pages for Guard. Check it out. > + // > + PagesToAlloc =3D NumberOfPages; > + TailGuard =3D (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 +=3D 1; > + TailGuard =3D 0; > + } > + > + HeadGuard =3D (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 allocat= e > + // > + PagesToAlloc +=3D 1; > + HeadGuard =3D 0; > + } > + > + if (Pages->NumberOfPages < PagesToAlloc) { > + // Not enough space to allocate memory with Guards? Try next blo= ck. > + continue; > + } > + > + Address =3D InternalAllocPagesOnOneNode (Pages, PagesToAlloc, > MaxAddress); > + ConvertSmmMemoryMapEntry(MemoryType, Address, PagesToAlloc, > FALSE); > + CoreFreeMemoryMapStack(); > + if (!HeadGuard) { > + // Don't pass the Guard page to user. > + Address +=3D 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 th= e > 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 =3D Memory; > + PagesToFree =3D 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] > + =3D GUARDED_HEAP_MAP_TABLE_DEPTH_MASKS; > + UINT64 Shifts[GUARDED_HEAP_MAP_TABLE_DEPTH] > + =3D 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 =3D GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel; > + Tables[Level] =3D mGuardedMemoryMap; > + Address =3D 0; > + OnGuarding =3D FALSE; > + > + DEBUG_CODE ( > + DumpGuardedMemoryBitmap (); > + ); > + > + while (TRUE) { > + if (Indices[Level] > Entries[Level]) { > + Tables[Level] =3D 0; > + Level -=3D 1; > + } else { > + > + TableEntry =3D Tables[Level][Indices[Level]]; > + Address =3D Addresses[Level]; > + > + if (TableEntry =3D=3D 0) { > + > + OnGuarding =3D FALSE; > + > + } else if (Level < GUARDED_HEAP_MAP_TABLE_DEPTH - 1) { > + > + Level +=3D 1; > + Tables[Level] =3D (UINT64 *)TableEntry; > + Addresses[Level] =3D Address; > + Indices[Level] =3D 0; > + > + continue; > + > + } else { > + > + Index =3D 0; > + while (Index < GUARDED_HEAP_MAP_ENTRY_BITS) { > + if ((TableEntry & 1) =3D=3D 1) { > + if (OnGuarding) { > + GuardPage =3D 0; > + } else { > + GuardPage =3D Address - EFI_PAGE_SIZE; > + } > + OnGuarding =3D TRUE; > + } else { > + if (OnGuarding) { > + GuardPage =3D Address; > + } else { > + GuardPage =3D 0; > + } > + OnGuarding =3D FALSE; > + } > + > + if (GuardPage !=3D 0) { > + SetGuardPage (GuardPage); > + } > + > + if (TableEntry =3D=3D 0) { > + break; > + } > + > + TableEntry =3D RShiftU64 (TableEntry, 1); > + Address +=3D EFI_PAGE_SIZE; > + Index +=3D 1; > + } > + } > + } > + > + if (Level < (GUARDED_HEAP_MAP_TABLE_DEPTH - (INTN)mMapLevel)) { > + break; > + } > + > + Indices[Level] +=3D 1; > + Address =3D (Level =3D=3D 0) ? 0 : Addresses[Level - 1]; > + Addresses[Level] =3D Address | LShiftU64(Indices[Level], Shifts[Leve= l]); > + > + } > +} > + > +/** > + Hook function used to set all Guard pages after entering SMM mode > +**/ > +VOID > +SmmEntryPointMemoryManagementHook ( > + VOID > + ) > +{ > + EFI_STATUS Status; > + VOID *SmmCpu; > + > + if (!mIsSmmCpuMode) { > + Status =3D SmmLocateProtocol (&gEfiSmmCpuProtocolGuid, NULL, > &SmmCpu); > + if (!EFI_ERROR(Status)) { > + mIsSmmCpuMode =3D 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 =3D=3D NULL) { > + return; > + } > + > + for (Index =3D 64; Index > 0; --Index) { > + BinString[Index - 1] =3D '0' + (Value & 1); > + Value =3D RShiftU64 (Value, 1); > + } > + BinString[64] =3D '\0'; > +} > + > +/** > + Dump the guarded memory bit map > + > + @return VOID > +**/ > +VOID > +EFIAPI > +DumpGuardedMemoryBitmap ( > + VOID > + ) > +{ > + UINT64 Entries[GUARDED_HEAP_MAP_TABLE_DEPTH] > + =3D GUARDED_HEAP_MAP_TABLE_DEPTH_MASKS; > + UINT64 Shifts[GUARDED_HEAP_MAP_TABLE_DEPTH] > + =3D 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 =3D " 3 2" > + " 1 0"; > + CHAR8 *Ruler2 =3D "FEDCBA9876543210FEDCBA9876543210" > + "FEDCBA9876543210FEDCBA9876543210"; > + > + if (mGuardedMemoryMap =3D=3D NULL) { > + return; > + } > + > + DEBUG ((DEBUG_INFO, "=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D" > + " Guarded Memory Bitmap " > + "=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D\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 =3D GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel; > + Tables[Level] =3D mGuardedMemoryMap; > + Address =3D 0; > + RepeatZero =3D 0; > + > + while (TRUE) { > + if (Indices[Level] > Entries[Level]) { > + > + Tables[Level] =3D 0; > + Level -=3D 1; > + RepeatZero =3D 0; > + > + DEBUG (( > + DEBUG_INFO, > + "=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D" > + "=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D\r\n" > + )); > + > + } else { > + > + TableEntry =3D Tables[Level][Indices[Level]]; > + Address =3D Addresses[Level]; > + > + if (TableEntry =3D=3D 0) { > + > + if (Level =3D=3D GUARDED_HEAP_MAP_TABLE_DEPTH - 1) { > + if (RepeatZero =3D=3D 0) { > + Uint64ToBinString(TableEntry, String); > + DEBUG ((DEBUG_INFO, "%016lx: %a\r\n", Address, String)); > + } else if (RepeatZero =3D=3D 1) { > + DEBUG ((DEBUG_INFO, "... : ...\r\n")); > + } > + RepeatZero +=3D 1; > + } > + > + } else if (Level < GUARDED_HEAP_MAP_TABLE_DEPTH - 1) { > + > + Level +=3D 1; > + Tables[Level] =3D (UINT64 *)TableEntry; > + Addresses[Level] =3D Address; > + Indices[Level] =3D 0; > + RepeatZero =3D 0; > + > + continue; > + > + } else { > + > + RepeatZero =3D 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] +=3D 1; > + Address =3D (Level =3D=3D 0) ? 0 : Addresses[Level - 1]; > + Addresses[Level] =3D Address | LShiftU64(Indices[Level], Shifts[Leve= l]); > + > + } > +} > + > +/** > + 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 =3D BaseAddress - EFI_PAGE_SIZE; > + PageEntry =3D GetPageTableEntry (Address, &Attribute); > + if (PageEntry =3D=3D NULL || Attribute !=3D Page4K) { > + DEBUG ((DEBUG_ERROR, "Head Guard is not set at: %016lx!!!\r\n", > Address)); > + DumpGuardedMemoryBitmap (); > + return FALSE; > + } > + > + if ((*PageEntry & IA32_PG_P) !=3D 0) { > + DEBUG ((DEBUG_ERROR, "Head Guard is not set at: %016lx > (%016lX)!!!\r\n", > + Address, *PageEntry)); > + *(UINT8 *) Address =3D 0; > + DumpGuardedMemoryBitmap (); > + return FALSE; > + } > + > + Address =3D BaseAddress + EFI_PAGES_TO_SIZE (NumberOfPages); > + PageEntry =3D GetPageTableEntry (Address, &Attribute); > + if (PageEntry =3D=3D NULL || Attribute !=3D Page4K) { > + DEBUG ((DEBUG_ERROR, "Tail Guard is not set at: %016lx!!!\r\n", > Address)); > + DumpGuardedMemoryBitmap (); > + return FALSE; > + } > + > + if ((*PageEntry & IA32_PG_P) !=3D 0) { > + DEBUG ((DEBUG_ERROR, "Tail Guard is not set at: %016lx (%016lX)!!!\r= \n", > + Address, *PageEntry)); > + *(UINT8 *) Address =3D 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.
> +This program and the accompanying materials > +are licensed and made available under the terms and conditions of the BS= D > License > +which accompanies this distribution. The full text of the license may b= e > 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 i= n > +// 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) =3D 8K (2-page), which can track 256= MB > +// 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 =3D 1 << 9) > +// > +#define BYTE_LENGTH_SHIFT 3 // (8 =3D 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 =3D 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 =3D 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) =3D 0x3FF > +#define GUARDED_HEAP_MAP_ENTRY_MASK \ > + ((1 << GUARDED_HEAP_MAP_ENTRY_SHIFT) - 1) > + > +// Size of each L4 table: (1 << 10) * 8 =3D 8KB =3D 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 =3D 256MB > +#define GUARDED_HEAP_MAP_UNIT_SIZE \ > + (GUARDED_HEAP_MAP_SIZE * 8 * EFI_PAGE_SIZE) > + > +// L4 table entry number: 8KB / 8 =3D 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 =3D 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 trave= rsing > +// {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 Gu= ard > + > + @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 Guar= d > + > + 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. An= other > + 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 th= e > 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 allocat= ion > + > + @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.
> +This program and the accompanying materials > +are licensed and made available under the terms and conditions of the BS= D > License > +which accompanies this distribution. The full text of the license may b= e > 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 > + > +UINT64 mAddressEncMask =3D 0; > +UINT8 mPhysicalAddressBits =3D 32; > + > +PAGE_ATTRIBUTE_TABLE mPageAttributeTable[] =3D { > + {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 =3D GetFirstHob (EFI_HOB_TYPE_CPU); > + if (Hob !=3D NULL) { > + PhysicalAddressBits =3D ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace; > + } else { > + AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL); > + if (RegEax >=3D 0x80000008) { > + AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL); > + PhysicalAddressBits =3D (UINT8) RegEax; > + } else { > + PhysicalAddressBits =3D 36; > + } > + } > + > + // > + // IA-32e paging translates 48-bit linear addresses to 52-bit physical > addresses. > + // > + ASSERT (PhysicalAddressBits <=3D 52); > + if (PhysicalAddressBits > 48) { > + PhysicalAddressBits =3D 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 <=3D 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 <=3D 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 =3D ((UINTN)RShiftU64 (Address, 39)) & PAGING_PAE_INDEX_MASK; > + Index3 =3D ((UINTN)Address >> 30) & PAGING_PAE_INDEX_MASK; > + Index2 =3D ((UINTN)Address >> 21) & PAGING_PAE_INDEX_MASK; > + Index1 =3D ((UINTN)Address >> 12) & PAGING_PAE_INDEX_MASK; > + > + if (sizeof(UINTN) =3D=3D sizeof(UINT64)) { > + L4PageTable =3D (UINT64 *)GetPageTableBase (); > + if (L4PageTable[Index4] =3D=3D 0) { > + *PageAttribute =3D PageNone; > + return NULL; > + } > + > + L3PageTable =3D (UINT64 *)(UINTN)(L4PageTable[Index4] & > ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64); > + } else { > + L3PageTable =3D (UINT64 *)GetPageTableBase (); > + } > + if (L3PageTable[Index3] =3D=3D 0) { > + *PageAttribute =3D PageNone; > + return NULL; > + } > + if ((L3PageTable[Index3] & IA32_PG_PS) !=3D 0) { > + // 1G > + *PageAttribute =3D Page1G; > + return &L3PageTable[Index3]; > + } > + > + L2PageTable =3D (UINT64 *)(UINTN)(L3PageTable[Index3] & > ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64); > + if (L2PageTable[Index2] =3D=3D 0) { > + *PageAttribute =3D PageNone; > + return NULL; > + } > + if ((L2PageTable[Index2] & IA32_PG_PS) !=3D 0) { > + // 2M > + *PageAttribute =3D Page2M; > + return &L2PageTable[Index2]; > + } > + > + // 4k > + L1PageTable =3D (UINT64 *)(UINTN)(L2PageTable[Index2] & > ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64); > + if ((L1PageTable[Index1] =3D=3D 0) && (Address !=3D 0)) { > + *PageAttribute =3D PageNone; > + return NULL; > + } > + *PageAttribute =3D 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 =3D 0; > + if ((*PageEntry & IA32_PG_P) =3D=3D 0) { > + Attributes |=3D EFI_MEMORY_RP; > + } > + if ((*PageEntry & IA32_PG_RW) =3D=3D 0) { > + Attributes |=3D EFI_MEMORY_RO; > + } > + if ((*PageEntry & IA32_PG_NX) !=3D 0) { > + Attributes |=3D 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 mean= s 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 =3D *PageEntry; > + NewPageEntry =3D CurrentPageEntry; > + if ((Attributes & EFI_MEMORY_RP) !=3D 0) { > + if (IsSet) { > + NewPageEntry &=3D ~(UINT64)IA32_PG_P; > + } else { > + NewPageEntry |=3D IA32_PG_P; > + } > + } > + if ((Attributes & EFI_MEMORY_RO) !=3D 0) { > + if (IsSet) { > + NewPageEntry &=3D ~(UINT64)IA32_PG_RW; > + } else { > + NewPageEntry |=3D IA32_PG_RW; > + } > + } > + if ((Attributes & EFI_MEMORY_XP) !=3D 0) { > + if (IsSet) { > + NewPageEntry |=3D IA32_PG_NX; > + } else { > + NewPageEntry &=3D ~IA32_PG_NX; > + } > + } > + > + if (CurrentPageEntry !=3D NewPageEntry) { > + *PageEntry =3D NewPageEntry; > + *IsModified =3D TRUE; > + DEBUG ((DEBUG_INFO, "(SMM)ConvertPageEntryAttribute 0x%lx", > CurrentPageEntry)); > + DEBUG ((DEBUG_INFO, "->0x%lx\n", NewPageEntry)); > + } else { > + *IsModified =3D 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 =3D PageAttributeToLength (PageAttribute); > + > + if (((BaseAddress & (PageEntryLength - 1)) =3D=3D 0) && (Length >=3D > PageEntryLength)) { > + return PageNone; > + } > + > + if (((BaseAddress & PAGING_2M_MASK) !=3D 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 =3D=3D Page2M || PageAttribute =3D=3D Page1G); > + > + if (PageAttribute =3D=3D Page2M) { > + // > + // Split 2M to 4K > + // > + ASSERT (SplitAttribute =3D=3D Page4K); > + if (SplitAttribute =3D=3D Page4K) { > + NewPageEntry =3D PageAlloc (1); > + DEBUG ((DEBUG_VERBOSE, "Split - 0x%x\n", NewPageEntry)); > + if (NewPageEntry =3D=3D NULL) { > + return RETURN_OUT_OF_RESOURCES; > + } > + BaseAddress =3D *PageEntry & PAGING_2M_ADDRESS_MASK_64; > + for (Index =3D 0; Index < SIZE_4KB / sizeof(UINT64); Index++) { > + NewPageEntry[Index] =3D (BaseAddress + SIZE_4KB * Index) | > mAddressEncMask | ((*PageEntry) & PAGE_PROGATE_BITS); > + } > + (*PageEntry) =3D (UINT64)(UINTN)NewPageEntry | mAddressEncMask | > PAGE_ATTRIBUTE_BITS; > + return RETURN_SUCCESS; > + } else { > + return RETURN_UNSUPPORTED; > + } > + } else if (PageAttribute =3D=3D Page1G) { > + // > + // Split 1G to 2M > + // No need support 1G->4K directly, we should use 1G->2M, then 2M->4= K > to get more compact page table. > + // > + ASSERT (SplitAttribute =3D=3D Page2M || SplitAttribute =3D=3D Page4K= ); > + if ((SplitAttribute =3D=3D Page2M || SplitAttribute =3D=3D Page4K)) = { > + NewPageEntry =3D PageAlloc (1); > + DEBUG ((DEBUG_VERBOSE, "Split - 0x%x\n", NewPageEntry)); > + if (NewPageEntry =3D=3D NULL) { > + return RETURN_OUT_OF_RESOURCES; > + } > + BaseAddress =3D *PageEntry & PAGING_1G_ADDRESS_MASK_64; > + for (Index =3D 0; Index < SIZE_4KB / sizeof(UINT64); Index++) { > + NewPageEntry[Index] =3D (BaseAddress + SIZE_2MB * Index) | > mAddressEncMask | IA32_PG_PS | ((*PageEntry) & PAGE_PROGATE_BITS); > + } > + (*PageEntry) =3D (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 speci= fied > 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 a= ddress > 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 mean= s to > clear attributes. > + @param[out] IsSplitted TRUE means page table splitted. FALSE me= ans > 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 modi= fied. > + @retval RETURN_INVALID_PARAMETER Length is zero. > + Attributes specified an illegal combi= nation 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 BaseAddre= ss and Length. > + The bit mask of attributes is not sup= port for the memory > resource > + range specified by BaseAddress and Le= ngth. > +**/ > +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 !=3D 0); > + ASSERT ((Attributes & ~(EFI_MEMORY_RP | EFI_MEMORY_RO | > EFI_MEMORY_XP)) =3D=3D 0); > + > + ASSERT ((BaseAddress & (SIZE_4KB - 1)) =3D=3D 0); > + ASSERT ((Length & (SIZE_4KB - 1)) =3D=3D 0); > + > + if (Length =3D=3D 0) { > + return RETURN_INVALID_PARAMETER; > + } > + > + MaximumSupportMemAddress =3D > (EFI_PHYSICAL_ADDRESS)(UINTN)(LShiftU64 (1, mPhysicalAddressBits) - 1); > + if (BaseAddress > MaximumSupportMemAddress) { > + return RETURN_UNSUPPORTED; > + } > + if (Length > MaximumSupportMemAddress) { > + return RETURN_UNSUPPORTED; > + } > + if ((Length !=3D 0) && (BaseAddress > MaximumSupportMemAddress - > (Length - 1))) { > + return RETURN_UNSUPPORTED; > + } > + > +// DEBUG ((DEBUG_ERROR, "ConvertMemoryPageAttributes(%x) - > %016lx, %016lx, %02lx\n", IsSet, BaseAddress, Length, Attributes)); > + > + if (IsSplitted !=3D NULL) { > + *IsSplitted =3D FALSE; > + } > + if (IsModified !=3D NULL) { > + *IsModified =3D FALSE; > + } > + > + // > + // Below logic is to check 2M/4K page to make sure we do not waste > memory. > + // > + while (Length !=3D 0) { > + PageEntry =3D GetPageTableEntry (BaseAddress, &PageAttribute); > + if (PageEntry =3D=3D NULL) { > + return RETURN_UNSUPPORTED; > + } > + PageEntryLength =3D PageAttributeToLength (PageAttribute); > + SplitAttribute =3D NeedSplitPage (BaseAddress, Length, PageEntry, > PageAttribute); > + if (SplitAttribute =3D=3D PageNone) { > + ConvertPageEntryAttribute (PageEntry, Attributes, IsSet, > &IsEntryModified); > + if (IsEntryModified) { > + if (IsModified !=3D NULL) { > + *IsModified =3D TRUE; > + } > + } > + // > + // Convert success, move to next > + // > + BaseAddress +=3D PageEntryLength; > + Length -=3D PageEntryLength; > + } else { > + Status =3D SplitPage (PageEntry, PageAttribute, SplitAttribute); > + if (RETURN_ERROR (Status)) { > + return RETURN_UNSUPPORTED; > + } > + if (IsSplitted !=3D NULL) { > + *IsSplitted =3D TRUE; > + } > + if (IsModified !=3D NULL) { > + *IsModified =3D 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 =3D=3D NULL) { > + DEBUG ((DEBUG_WARN, "Cannot flush TLB for APs\r\n")); > + return; > + } > + > + for (Index =3D 0; Index < gSmmCoreSmst.NumberOfCpus; Index++) { > + if (Index !=3D 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 a= ddress > 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 th= e > memory region. > + @param[out] IsSplitted TRUE means page table splitted. FALSE me= ans > page table not splitted. > + > + @retval EFI_SUCCESS The attributes were set for the memory r= egion. > + @retval EFI_ACCESS_DENIED The attributes for the memory resource > range specified by > + BaseAddress and Length cannot be modifie= d. > + @retval EFI_INVALID_PARAMETER Length is zero. > + Attributes specified an illegal combinat= ion 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 suppor= t for the memory > resource > + range specified by BaseAddress and Lengt= h. > + > +**/ > +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 =3D ConvertMemoryPageAttributes (BaseAddress, Length, Attribute= s, > 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 a= ddress > 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 me= ans > page table not splitted. > + > + @retval EFI_SUCCESS The attributes were cleared for the memo= ry > region. > + @retval EFI_ACCESS_DENIED The attributes for the memory resource > range specified by > + BaseAddress and Length cannot be modifie= d. > + @retval EFI_INVALID_PARAMETER Length is zero. > + Attributes specified an illegal combinat= ion 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 suppor= t for the memory > resource > + range specified by BaseAddress and Lengt= h. > + > +**/ > +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 =3D ConvertMemoryPageAttributes (BaseAddress, Length, Attribute= s, > 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 ad= dress > 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 r= egion. > + @retval EFI_ACCESS_DENIED The attributes for the memory resource > range specified by > + BaseAddress and Length cannot be modifie= d. > + @retval EFI_INVALID_PARAMETER Length is zero. > + Attributes specified an illegal combinat= ion 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 suppor= t for the memory > resource > + range specified by BaseAddress and Lengt= h. > + > +**/ > +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 ad= dress > 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 t= he > memory region. > + > + @retval EFI_SUCCESS The attributes were cleared for the memo= ry > region. > + @retval EFI_ACCESS_DENIED The attributes for the memory resource > range specified by > + BaseAddress and Length cannot be modifie= d. > + @retval EFI_INVALID_PARAMETER Length is zero. > + Attributes specified an illegal combinat= ion 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 suppor= t for the memory > resource > + range specified by BaseAddress and Lengt= h. > + > +**/ > +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 =3D PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) > & PAGING_1G_ADDRESS_MASK_64; > + mPhysicalAddressBits =3D CalculateMaximumSupportAddress (); > + DEBUG ((DEBUG_INFO, "mAddressEncMask =3D 0x%lx\r\n", > mAddressEncMask)); > + DEBUG ((DEBUG_INFO, "mPhysicalAddressBits =3D %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.
> + 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 =3D 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 a= ddress > 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 th= e > memory region. > + @param[out] IsSplitted TRUE means page table splitted. FALSE me= ans > page table not splitted. > + > + @retval EFI_SUCCESS The attributes were set for the memory r= egion. > + @retval EFI_ACCESS_DENIED The attributes for the memory resource > range specified by > + BaseAddress and Length cannot be modifie= d. > + @retval EFI_INVALID_PARAMETER Length is zero. > + Attributes specified an illegal combinat= ion 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 suppor= t for the memory > resource > + range specified by BaseAddress and Lengt= h. > + > +**/ > +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 a= ddress > 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 me= ans > page table not splitted. > + > + @retval EFI_SUCCESS The attributes were cleared for the memo= ry > region. > + @retval EFI_ACCESS_DENIED The attributes for the memory resource > range specified by > + BaseAddress and Length cannot be modifie= d. > + @retval EFI_INVALID_PARAMETER Length is zero. > + Attributes specified an illegal combinat= ion 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 suppor= t for the memory > resource > + range specified by BaseAddress and Lengt= h. > + > +**/ > +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 =3D > INITIALIZE_LIST_HEAD_VARIABLE (mFreeMemor > @param[out] Memory A pointer to receive the base allo= cated > memory > address. > @param[in] AddRegion If this memory is new added region= . > + @param[in] NeedGuard Flag to indicate Guard page is nee= ded > + or not >=20 > @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 > ); >=20 > /** > @@ -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 allo= cated > memory > address. > @param[in] AddRegion If this memory is new added region= . > + @param[in] NeedGuard Flag to indicate Guard page is nee= ded > + or not >=20 > @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 =3D (UINTN)(-1); > case AllocateMaxAddress: > + if (NeedGuard) { > + *Memory =3D InternalAllocMaxAddressWithGuard ( > + &mSmmMemoryMap, > + NumberOfPages, > + RequestedAddress, > + MemoryType > + ); > + if (*Memory =3D=3D (UINTN)-1) { > + return EFI_OUT_OF_RESOURCES; > + } else { > + ASSERT (VerifyMemoryGuard(*Memory, NumberOfPages) =3D=3D TRUE)= ; > + return EFI_SUCCESS; > + } > + } > + > *Memory =3D 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 allo= cated > memory > address. > + @param[in] NeedGuard Flag to indicate Guard page is nee= ded > + or not >=20 > @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); > } >=20 > /** > @@ -811,8 +837,11 @@ SmmAllocatePages ( > ) > { > EFI_STATUS Status; > + BOOLEAN NeedGuard; >=20 > - Status =3D SmmInternalAllocatePages (Type, MemoryType, NumberOfPages, > Memory); > + NeedGuard =3D IsPageTypeToGuard (MemoryType, Type); > + Status =3D 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); > } >=20 > @@ -966,8 +999,10 @@ SmmFreePages ( > ) > { > EFI_STATUS Status; > + BOOLEAN IsGuarded; >=20 > - Status =3D SmmInternalFreePages (Memory, NumberOfPages); > + IsGuarded =3D IsHeapGuardEnabled () && IsMemoryGuarded (Memory); > + Status =3D 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 (); >=20 > + // > + // 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 =3D &gSmmCoreSmst; > gSmmCorePrivate->SmmEntryPoint =3D 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 >=20 > #include "PiSmmCorePrivateData.h" > +#include "Misc/HeapGuard.h" >=20 > // > // 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 o= r not >=20 > @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 > ); >=20 > /** > @@ -356,6 +359,8 @@ SmmFreePages ( >=20 > @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 guard= ed > + or not >=20 > @retval EFI_NOT_FOUND Could not find the entry that covers th= e > 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 > ); >=20 > /** > @@ -1231,4 +1237,74 @@ typedef enum { >=20 > extern LIST_ENTRY > mSmmPoolLists[SmmPoolTypeMax][MAX_POOL_INDEX]; >=20 > +/** > + 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 th= e > 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 >=20 > [Packages] > MdePkg/MdePkg.dec > @@ -65,6 +67,7 @@ > HobLib > SmmMemLib > DxeServicesLib > + CpuLib >=20 > [Protocols] > gEfiDxeSmmReadyToLockProtocolGuid ## UNDEFINED # > SmiHandlerRegister > @@ -88,6 +91,7 @@ > gEfiSmmGpiDispatch2ProtocolGuid ## SOMETIMES_CONSUMES > gEfiSmmIoTrapDispatch2ProtocolGuid ## SOMETIMES_CONSUMES > gEfiSmmUsbDispatch2ProtocolGuid ## SOMETIMES_CONSUMES > + gEfiSmmCpuProtocolGuid ## SOMETIMES_CONSUMES >=20 > [Pcd] >=20 > 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 >=20 > [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 =3D EFI_SUCCESS; > Hdr =3D NULL; > if (PoolIndex =3D=3D MAX_POOL_INDEX) { > - Status =3D SmmInternalAllocatePages (AllocateAnyPages, PoolType, > EFI_SIZE_TO_PAGES (MAX_POOL_SIZE << 1), &Address); > + Status =3D 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; >=20 > Address =3D 0; >=20 > @@ -251,25 +256,45 @@ SmmInternalAllocatePool ( > return EFI_INVALID_PARAMETER; > } >=20 > + NeedGuard =3D IsPoolTypeToGuard (PoolType); > + HasPoolTail =3D !(NeedGuard && > + ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) =3D=3D 0)= ); > + > // > // Adjust the size by the pool header & tail overhead > // > Size +=3D POOL_OVERHEAD; > - if (Size > MAX_POOL_SIZE) { > - Size =3D EFI_SIZE_TO_PAGES (Size); > - Status =3D SmmInternalAllocatePages (AllocateAnyPages, PoolType, Siz= e, > &Address); > + if (Size > MAX_POOL_SIZE || NeedGuard) { > + if (!HasPoolTail) { > + Size -=3D sizeof (POOL_TAIL); > + } > + > + NoPages =3D EFI_SIZE_TO_PAGES (Size); > + Status =3D SmmInternalAllocatePages (AllocateAnyPages, PoolType, > NoPages, > + &Address, NeedGuard); > if (EFI_ERROR (Status)) { > return Status; > } >=20 > + if (NeedGuard) { > + ASSERT (VerifyMemoryGuard(Address, NoPages) =3D=3D TRUE); > + DEBUG ((DEBUG_INFO, "SmmInternalAllocatePool: %lx ->", Address)); > + Address =3D (EFI_PHYSICAL_ADDRESS)AdjustPoolHeadA (Address, > NoPages, Size); > + DEBUG ((DEBUG_INFO, " %lx %d %x\r\n", Address, NoPages, Size)); > + } > + > PoolHdr =3D (POOL_HEADER*)(UINTN)Address; > PoolHdr->Signature =3D POOL_HEAD_SIGNATURE; > - PoolHdr->Size =3D EFI_PAGES_TO_SIZE (Size); > + PoolHdr->Size =3D Size; //EFI_PAGES_TO_SIZE (NoPages) > PoolHdr->Available =3D FALSE; > PoolHdr->Type =3D PoolType; > - PoolTail =3D HEAD_TO_TAIL(PoolHdr); > - PoolTail->Signature =3D POOL_TAIL_SIGNATURE; > - PoolTail->Size =3D PoolHdr->Size; > + > + if (HasPoolTail) { > + PoolTail =3D HEAD_TO_TAIL (PoolHdr); > + PoolTail->Signature =3D POOL_TAIL_SIGNATURE; > + PoolTail->Size =3D PoolHdr->Size; > + } > + > *Buffer =3D PoolHdr + 1; > return Status; > } > @@ -341,28 +366,45 @@ SmmInternalFreePool ( > { > FREE_POOL_HEADER *FreePoolHdr; > POOL_TAIL *PoolTail; > + BOOLEAN HasPoolTail; > + BOOLEAN MemoryGuarded; >=20 > if (Buffer =3D=3D NULL) { > return EFI_INVALID_PARAMETER; > } >=20 > + MemoryGuarded =3D IsHeapGuardEnabled () && > + IsMemoryGuarded ((EFI_PHYSICAL_ADDRESS)(UINTN)Buffer); > + HasPoolTail =3D !(MemoryGuarded && > + ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) =3D=3D = 0)); > + > FreePoolHdr =3D (FREE_POOL_HEADER*)((POOL_HEADER*)Buffer - 1); > ASSERT (FreePoolHdr->Header.Signature =3D=3D POOL_HEAD_SIGNATURE); > ASSERT (!FreePoolHdr->Header.Available); > - PoolTail =3D HEAD_TO_TAIL(&FreePoolHdr->Header); > - ASSERT (PoolTail->Signature =3D=3D POOL_TAIL_SIGNATURE); > - ASSERT (FreePoolHdr->Header.Size =3D=3D PoolTail->Size); > - > if (FreePoolHdr->Header.Signature !=3D POOL_HEAD_SIGNATURE) { > return EFI_INVALID_PARAMETER; > } >=20 > - if (PoolTail->Signature !=3D POOL_TAIL_SIGNATURE) { > - return EFI_INVALID_PARAMETER; > + if (HasPoolTail) { > + PoolTail =3D HEAD_TO_TAIL (&FreePoolHdr->Header); > + ASSERT (PoolTail->Signature =3D=3D POOL_TAIL_SIGNATURE); > + ASSERT (FreePoolHdr->Header.Size =3D=3D PoolTail->Size); > + if (PoolTail->Signature !=3D POOL_TAIL_SIGNATURE) { > + return EFI_INVALID_PARAMETER; > + } > + > + if (FreePoolHdr->Header.Size !=3D PoolTail->Size) { > + return EFI_INVALID_PARAMETER; > + } > } >=20 > - if (FreePoolHdr->Header.Size !=3D PoolTail->Size) { > - return EFI_INVALID_PARAMETER; > + if (MemoryGuarded) { > + Buffer =3D AdjustPoolHeadF > ((EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr); > + return SmmInternalFreePages ( > + (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer, > + EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size), > + TRUE > + ); > } >=20 > if (FreePoolHdr->Header.Size > MAX_POOL_SIZE) { > @@ -370,7 +412,8 @@ SmmInternalFreePool ( > ASSERT ((FreePoolHdr->Header.Size & EFI_PAGE_MASK) =3D=3D 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