From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by spool.mail.gandi.net (Postfix) with ESMTPS id 2C3C8AC0D11 for ; Thu, 30 Nov 2023 06:29:55 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=jQ6y3dpEbKamsbjILoZwg5dM92g1VqqZsDYSqFs1nUA=; c=relaxed/simple; d=groups.io; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References:MIME-Version:Precedence:List-Subscribe:List-Help:Sender:List-Id:Mailing-List:Delivered-To:Reply-To:List-Unsubscribe-Post:List-Unsubscribe:Content-Transfer-Encoding; s=20140610; t=1701325793; v=1; b=BggRQa71fOCyDdEdu7Pfh+dyEO4Tb1dPLDo+C4ADKWgJFVdS50dvJVG3/7Nbb2jBGomn7Gsd aByZDKJ09Xr+adLgvzlqkYcH94c8TtaMun5UuauR/sq8Y6T1PLtaPrSjLvgTTpdabXZlea3MWLq vhYpp8Ue60B48cGTKSlJuKEk= X-Received: by 127.0.0.2 with SMTP id xtChYY7687511xdCi1YwL8fT; Wed, 29 Nov 2023 22:29:53 -0800 X-Received: from mgamail.intel.com (mgamail.intel.com [134.134.136.126]) by mx.groups.io with SMTP id smtpd.web10.66739.1701325790007373240 for ; Wed, 29 Nov 2023 22:29:53 -0800 X-IronPort-AV: E=McAfee;i="6600,9927,10909"; a="378304846" X-IronPort-AV: E=Sophos;i="6.04,237,1695711600"; d="scan'208";a="378304846" X-Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 29 Nov 2023 22:29:52 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10909"; a="860095445" X-IronPort-AV: E=Sophos;i="6.04,237,1695711600"; d="scan'208";a="860095445" X-Received: from shwdesfp01.ccr.corp.intel.com ([10.239.158.151]) by fmsmga003-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 29 Nov 2023 22:29:51 -0800 From: "Zhiguang Liu" To: devel@edk2.groups.io Cc: Zhiguang Liu , Ray Ni , Rahul Kumar , Gerd Hoffmann , Laszlo Ersek Subject: [edk2-devel] [PATCH v2 3/3] UefiCpuPkg/CpuMpPei: Use CpuPageTableLib to set memory attribute. Date: Thu, 30 Nov 2023 14:29:09 +0800 Message-Id: <20231130062909.2003-3-zhiguang.liu@intel.com> In-Reply-To: <20231130062909.2003-1-zhiguang.liu@intel.com> References: <20231130062909.2003-1-zhiguang.liu@intel.com> MIME-Version: 1.0 Precedence: Bulk List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,zhiguang.liu@intel.com List-Unsubscribe-Post: List-Unsubscribe=One-Click List-Unsubscribe: X-Gm-Message-State: tTmSqrXXiKXzGTzGTsFB7xzSx7686176AA= Content-Transfer-Encoding: 8bit X-GND-Status: LEGIT Authentication-Results: spool.mail.gandi.net; dkim=pass header.d=groups.io header.s=20140610 header.b=BggRQa71; dmarc=fail reason="SPF not aligned (relaxed), DKIM not aligned (relaxed)" header.from=intel.com (policy=none); spf=pass (spool.mail.gandi.net: domain of bounce@groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce@groups.io Currently, there are code to set memory attribute in CpuMpPei module. However, the code doesn't handle the case of 5 level paging. Use the CpuPageTableLib to set memory attribute for two purpose: 1. Add 5 level paging support 2. Clean up code Cc: Ray Ni Cc: Rahul Kumar Cc: Gerd Hoffmann Cc: Laszlo Ersek Signed-off-by: Zhiguang Liu --- UefiCpuPkg/CpuMpPei/CpuPaging.c | 317 +++++++------------------------- 1 file changed, 69 insertions(+), 248 deletions(-) diff --git a/UefiCpuPkg/CpuMpPei/CpuPaging.c b/UefiCpuPkg/CpuMpPei/CpuPaging.c index b7ddb0005b..2dd7237141 100644 --- a/UefiCpuPkg/CpuMpPei/CpuPaging.c +++ b/UefiCpuPkg/CpuMpPei/CpuPaging.c @@ -15,50 +15,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include "CpuMpPei.h" - -#define IA32_PG_P BIT0 -#define IA32_PG_RW BIT1 -#define IA32_PG_U BIT2 -#define IA32_PG_A BIT5 -#define IA32_PG_D BIT6 -#define IA32_PG_PS BIT7 -#define IA32_PG_NX BIT63 - -#define PAGE_ATTRIBUTE_BITS (IA32_PG_RW | IA32_PG_P) -#define PAGE_PROGATE_BITS (IA32_PG_D | IA32_PG_A | IA32_PG_NX | IA32_PG_U | \ - PAGE_ATTRIBUTE_BITS) - -#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 PAGING_512G_ADDRESS_MASK_64 0x000FFF8000000000ull - -typedef enum { - PageNone = 0, - PageMin = 1, - Page4K = PageMin, - Page2M = 2, - Page1G = 3, - Page512G = 4, - PageMax = Page512G -} PAGE_ATTRIBUTE; - -typedef struct { - PAGE_ATTRIBUTE Attribute; - UINT64 Length; - UINT64 AddressMask; - UINTN AddressBitOffset; - UINTN AddressBitLength; -} PAGE_ATTRIBUTE_TABLE; - -PAGE_ATTRIBUTE_TABLE mPageAttributeTable[] = { - { PageNone, 0, 0, 0, 0 }, - { Page4K, SIZE_4KB, PAGING_4K_ADDRESS_MASK_64, 12, 9 }, - { Page2M, SIZE_2MB, PAGING_2M_ADDRESS_MASK_64, 21, 9 }, - { Page1G, SIZE_1GB, PAGING_1G_ADDRESS_MASK_64, 30, 9 }, - { Page512G, SIZE_512GB, PAGING_512G_ADDRESS_MASK_64, 39, 9 }, -}; +#define PAGING_4K_ADDRESS_MASK_64 0x000FFFFFFFFFF000ull EFI_PEI_NOTIFY_DESCRIPTOR mPostMemNotifyList[] = { { @@ -117,237 +74,101 @@ AllocatePageTableMemory ( return Address; } -/** - Get the type of top level page table. - - @retval Page512G PML4 paging. - @retval Page1G PAE paging. - -**/ -PAGE_ATTRIBUTE -GetPageTableTopLevelType ( - VOID - ) -{ - MSR_IA32_EFER_REGISTER MsrEfer; - - MsrEfer.Uint64 = AsmReadMsr64 (MSR_CORE_IA32_EFER); - - return (MsrEfer.Bits.LMA == 1) ? Page512G : Page1G; -} - -/** - Return page table entry matching 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 - ) -{ - INTN Level; - UINTN Index; - UINT64 *PageTable; - UINT64 AddressEncMask; - - AddressEncMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask); - PageTable = (UINT64 *)(UINTN)(AsmReadCr3 () & PAGING_4K_ADDRESS_MASK_64); - for (Level = (INTN)GetPageTableTopLevelType (); Level > 0; --Level) { - Index = (UINTN)RShiftU64 (Address, mPageAttributeTable[Level].AddressBitOffset); - Index &= PAGING_PAE_INDEX_MASK; - - // - // No mapping? - // - if (PageTable[Index] == 0) { - *PageAttribute = PageNone; - return NULL; - } - - // - // Page memory? - // - if (((PageTable[Index] & IA32_PG_PS) != 0) || (Level == PageMin)) { - *PageAttribute = (PAGE_ATTRIBUTE)Level; - return &PageTable[Index]; - } - - // - // Page directory or table - // - PageTable = (UINT64 *)(UINTN)(PageTable[Index] & - ~AddressEncMask & - PAGING_4K_ADDRESS_MASK_64); - } - - *PageAttribute = PageNone; - return NULL; -} - -/** - This function splits one page entry to smaller 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. - @param[in] Recursively Do the split recursively or not. - - @retval RETURN_SUCCESS The page entry is splitted. - @retval RETURN_INVALID_PARAMETER If target page attribute is invalid - @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, - IN BOOLEAN Recursively - ) -{ - UINT64 BaseAddress; - UINT64 *NewPageEntry; - UINTN Index; - UINT64 AddressEncMask; - PAGE_ATTRIBUTE SplitTo; - - if ((SplitAttribute == PageNone) || (SplitAttribute >= PageAttribute)) { - ASSERT (SplitAttribute != PageNone); - ASSERT (SplitAttribute < PageAttribute); - return RETURN_INVALID_PARAMETER; - } - - NewPageEntry = AllocatePageTableMemory (1); - if (NewPageEntry == NULL) { - ASSERT (NewPageEntry != NULL); - return RETURN_OUT_OF_RESOURCES; - } - - // - // One level down each step to achieve more compact page table. - // - SplitTo = PageAttribute - 1; - AddressEncMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) & - mPageAttributeTable[SplitTo].AddressMask; - BaseAddress = *PageEntry & - ~PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) & - mPageAttributeTable[PageAttribute].AddressMask; - for (Index = 0; Index < SIZE_4KB / sizeof (UINT64); Index++) { - NewPageEntry[Index] = BaseAddress | AddressEncMask | - ((*PageEntry) & PAGE_PROGATE_BITS); - - if (SplitTo != PageMin) { - NewPageEntry[Index] |= IA32_PG_PS; - } - - if (Recursively && (SplitTo > SplitAttribute)) { - SplitPage (&NewPageEntry[Index], SplitTo, SplitAttribute, Recursively); - } - - BaseAddress += mPageAttributeTable[SplitTo].Length; - } - - (*PageEntry) = (UINT64)(UINTN)NewPageEntry | AddressEncMask | PAGE_ATTRIBUTE_BITS; - - return RETURN_SUCCESS; -} - /** This function modifies the page attributes for the memory region specified - by BaseAddress and Length from their current attributes to the attributes - specified by Attributes. + by BaseAddress and Length to not present. Caller should make sure BaseAddress and Length is at page boundary. @param[in] BaseAddress Start address of a memory region. @param[in] Length Size in bytes of the memory region. - @param[in] Attributes Bit mask of attributes to modify. - - @retval RETURN_SUCCESS The attributes were modified for the memory - region. - @retval RETURN_INVALID_PARAMETER Length is zero; or, - Attributes specified an illegal combination - of attributes that cannot be set together; or - Addressis not 4KB aligned. + + @retval RETURN_SUCCESS The memory region is changed to not present. @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes. @retval RETURN_UNSUPPORTED Cannot modify the attributes of given memory. **/ RETURN_STATUS -EFIAPI -ConvertMemoryPageAttributes ( +ConvertMemoryPageToNotPresent ( IN PHYSICAL_ADDRESS BaseAddress, - IN UINT64 Length, - IN UINT64 Attributes + IN UINT64 Length ) { - UINT64 *PageEntry; - PAGE_ATTRIBUTE PageAttribute; - RETURN_STATUS Status; - EFI_PHYSICAL_ADDRESS MaximumAddress; - - if ((Length == 0) || - ((BaseAddress & (SIZE_4KB - 1)) != 0) || - ((Length & (SIZE_4KB - 1)) != 0)) - { - ASSERT (Length > 0); - ASSERT ((BaseAddress & (SIZE_4KB - 1)) == 0); - ASSERT ((Length & (SIZE_4KB - 1)) == 0); - - return RETURN_INVALID_PARAMETER; - } - - MaximumAddress = (EFI_PHYSICAL_ADDRESS)MAX_UINT32; - if ((BaseAddress > MaximumAddress) || - (Length > MaximumAddress) || - (BaseAddress > MaximumAddress - (Length - 1))) - { - return RETURN_UNSUPPORTED; - } - - // - // Below logic is to check 2M/4K page to make sure we do not waste memory. - // - while (Length != 0) { - PageEntry = GetPageTableEntry (BaseAddress, &PageAttribute); - if (PageEntry == NULL) { - return RETURN_UNSUPPORTED; - } + EFI_STATUS Status; + UINTN PageTable; + EFI_PHYSICAL_ADDRESS Buffer; + UINTN BufferSize; + IA32_MAP_ATTRIBUTE MapAttribute; + IA32_MAP_ATTRIBUTE MapMask; + PAGING_MODE PagingMode; + IA32_CR4 Cr4; + BOOLEAN Page5LevelSupport; + UINT32 RegEax; + BOOLEAN Page1GSupport; + CPUID_EXTENDED_CPU_SIG_EDX RegEdx; + + if (sizeof (UINTN) == sizeof (UINT64)) { + // + // Check Page5Level Support or not. + // + Cr4.UintN = AsmReadCr4 (); + Page5LevelSupport = (Cr4.Bits.LA57 ? TRUE : FALSE); - if (PageAttribute != Page4K) { - Status = SplitPage (PageEntry, PageAttribute, Page4K, FALSE); - if (RETURN_ERROR (Status)) { - return Status; + // + // Check Page1G Support or not. + // + Page1GSupport = FALSE; + AsmCpuid (CPUID_EXTENDED_FUNCTION, &RegEax, NULL, NULL, NULL); + if (RegEax >= CPUID_EXTENDED_CPU_SIG) { + AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, NULL, &RegEdx.Uint32); + if (RegEdx.Bits.Page1GB != 0) { + Page1GSupport = TRUE; } - - // - // Do it again until the page is 4K. - // - continue; } // - // Just take care of 'present' bit for Stack Guard. + // Decide Paging Mode according Page5LevelSupport & Page1GSupport. // - if ((Attributes & IA32_PG_P) != 0) { - *PageEntry |= (UINT64)IA32_PG_P; + if (Page5LevelSupport) { + PagingMode = Page1GSupport ? Paging5Level1GB : Paging5Level; } else { - *PageEntry &= ~((UINT64)IA32_PG_P); + PagingMode = Page1GSupport ? Paging4Level1GB : Paging4Level; } + } else { + PagingMode = PagingPae; + } + + MapAttribute.Uint64 = 0; + MapMask.Uint64 = 0; + MapMask.Bits.Present = 1; + PageTable = AsmReadCr3 () & PAGING_4K_ADDRESS_MASK_64; + BufferSize = 0; + // + // Get required buffer size for the pagetable that will be created. + // + Status = PageTableMap (&PageTable, PagingMode, 0, &BufferSize, BaseAddress, Length, &MapAttribute, &MapMask, NULL); + if (Status == EFI_BUFFER_TOO_SMALL) { // - // Convert success, move to next + // Allocate required Buffer. // - BaseAddress += SIZE_4KB; - Length -= SIZE_4KB; + Status = PeiServicesAllocatePages ( + EfiBootServicesData, + EFI_SIZE_TO_PAGES (BufferSize), + &Buffer + ); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + Status = PageTableMap (&PageTable, PagingMode, (VOID *)(UINTN)Buffer, &BufferSize, BaseAddress, Length, &MapAttribute, &MapMask, NULL); } - return RETURN_SUCCESS; + ASSERT_EFI_ERROR (Status); + AsmWriteCr3 (PageTable); + return Status; } /** @@ -516,7 +337,7 @@ SetupStackGuardPage ( // // Set Guard page at stack base address. // - ConvertMemoryPageAttributes (StackBase, EFI_PAGE_SIZE, 0); + ConvertMemoryPageToNotPresent (StackBase, EFI_PAGE_SIZE); DEBUG (( DEBUG_INFO, "Stack Guard set at %lx [cpu%lu]!\n", @@ -599,7 +420,7 @@ MemoryDiscoveredPpiNotifyCallback ( // Enable #PF exception, so if the code access SPI after disable NEM, it will generate // the exception to avoid potential vulnerability. // - ConvertMemoryPageAttributes (MigratedFvInfo->FvOrgBase, MigratedFvInfo->FvLength, 0); + ConvertMemoryPageToNotPresent (MigratedFvInfo->FvOrgBase, MigratedFvInfo->FvLength); Hob.Raw = GET_NEXT_HOB (Hob); Hob.Raw = GetNextGuidHob (&gEdkiiMigratedFvInfoGuid, Hob.Raw); -- 2.31.1.windows.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#111891): https://edk2.groups.io/g/devel/message/111891 Mute This Topic: https://groups.io/mt/102889280/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=-