From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by mx.groups.io with SMTP id smtpd.web10.7066.1682066249739051879 for ; Fri, 21 Apr 2023 01:37:31 -0700 Authentication-Results: mx.groups.io; dkim=fail reason="unable to parse pub key" header.i=@intel.com header.s=intel header.b=f6azx/+n; spf=pass (domain: intel.com, ip: 192.55.52.88, mailfrom: dun.tan@intel.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1682066251; x=1713602251; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=jHpXEaxNZ6lFA/CTIK2R9F9v6Ajbx6CpY80MHD20MQE=; b=f6azx/+nXAfLU4giQZ/kn1n7k+UxNlUNfj4GUjkZv4o5W7CPqahmqpwv EO2Hhgd2ZYUu1VuYQp9Na7Jks69IGtID+fVayQhiBAnozNyP8cTHLT2Vk n0oj0lIjue9EdmLFEBXA8Xm1IUBQIUm0qZBmqUYatEOnDGi90GzTqc00X KBtID50O/UTpJyBzReBChfFlsDTqYhEVNmlr/BXZPbJvn9MftxlptzJos Sigs5b7QLOAvCHzhj333YlDQBvF6TmMXNNR2/6d7kEmfJKnpQZrXMtq73 gfzayCZ4sNj3ACB+XMBE8orj8ZN0yLD4ZnldY/NaUaaBfbOlWQqAB6ZP5 g==; X-IronPort-AV: E=McAfee;i="6600,9927,10686"; a="373869787" X-IronPort-AV: E=Sophos;i="5.99,214,1677571200"; d="scan'208";a="373869787" Received: from orsmga006.jf.intel.com ([10.7.209.51]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Apr 2023 01:37:11 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10686"; a="669650496" X-IronPort-AV: E=Sophos;i="5.99,214,1677571200"; d="scan'208";a="669650496" Received: from shwdeopenlab702.ccr.corp.intel.com ([10.239.55.92]) by orsmga006-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Apr 2023 01:37:10 -0700 From: "duntan" To: devel@edk2.groups.io Cc: Eric Dong , Ray Ni , Rahul Kumar , Gerd Hoffmann Subject: [Patch V3 10/11] UefiCpuPkg: Refinement to code about updating smm page table Date: Fri, 21 Apr 2023 16:36:27 +0800 Message-Id: <20230421083628.1408-11-dun.tan@intel.com> X-Mailer: git-send-email 2.31.1.windows.1 In-Reply-To: <20230421083628.1408-1-dun.tan@intel.com> References: <20230421083628.1408-1-dun.tan@intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit This commit is code refinement to current smm runtime pagetable update code. In InitPaging() function, sort mProtectionMemRange or mSmmCpuSmramRanges at first. If PcdCpuSmmProfileEnable is TRUE, use ConvertMemoryPageAttributes() API to map the range in mProtectionMemRange to the attrbute recorded in the attribute field of mProtectionMemRange, map the range outside mProtectionMemRange as non-present. If PcdCpuSmmProfileEnable is FALSE, set the ranges not in mSmmCpuSmramRanges as NX. Signed-off-by: Dun Tan Cc: Eric Dong Cc: Ray Ni Cc: Rahul Kumar Cc: Gerd Hoffmann --- UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h | 37 +++++++++++++++++++++++++++++++++++++ UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.c | 352 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 2 files changed, 164 insertions(+), 225 deletions(-) diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h index 258955119c..37366d6803 100644 --- a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h @@ -713,6 +713,43 @@ SmmBlockingStartupThisAp ( IN OUT VOID *ProcArguments OPTIONAL ); +/** + This function modifies the page attributes for the memory region specified by BaseAddress and + Length from their current attributes to the attributes specified by Attributes. + + Caller should make sure BaseAddress and Length is at page boundary. + + @param[in] PageTableBase The page table base. + @param[in] BaseAddress The physical address that is the start address of a memory region. + @param[in] Length The size in bytes of the memory region. + @param[in] Attributes The bit mask of attributes to modify for the memory region. + @param[in] IsSet TRUE means to set attributes. FALSE means to clear attributes. + @param[out] IsModified TRUE means page table modified. FALSE means page table not modified. + + @retval RETURN_SUCCESS The attributes were modified for the memory region. + @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by + BaseAddress and Length cannot be modified. + @retval RETURN_INVALID_PARAMETER Length is zero. + Attributes specified an illegal combination of attributes that + cannot be set together. + @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of + the memory resource range. + @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the memory + resource range specified by BaseAddress and Length. + The bit mask of attributes is not support for the memory resource + range specified by BaseAddress and Length. +**/ +RETURN_STATUS +ConvertMemoryPageAttributes ( + IN UINTN PageTableBase, + IN PAGING_MODE PagingMode, + IN PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 Attributes, + IN BOOLEAN IsSet, + OUT BOOLEAN *IsModified OPTIONAL + ); + /** This function sets the attributes for the memory region specified by BaseAddress and Length from their current attributes to the attributes specified by Attributes. diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.c b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.c index 5625ba0cac..0fc0985837 100644 --- a/UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.c +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.c @@ -546,262 +546,164 @@ InitProtectedMemRange ( } /** - Update page table according to protected memory ranges and the 4KB-page mapped memory ranges. + Function to compare 2 MEMORY_PROTECTION_RANGE based on range base. + + @param[in] Buffer1 pointer to Device Path poiner to compare + @param[in] Buffer2 pointer to second DevicePath pointer to compare + @retval 0 Buffer1 equal to Buffer2 + @retval <0 Buffer1 is less than Buffer2 + @retval >0 Buffer1 is greater than Buffer2 **/ -VOID -InitPaging ( - VOID +INTN +EFIAPI +ProtectionRangeCompare ( + IN CONST VOID *Buffer1, + IN CONST VOID *Buffer2 ) { - UINT64 Pml5Entry; - UINT64 Pml4Entry; - UINT64 *Pml5; - UINT64 *Pml4; - UINT64 *Pdpt; - UINT64 *Pd; - UINT64 *Pt; - UINTN Address; - UINTN Pml5Index; - UINTN Pml4Index; - UINTN PdptIndex; - UINTN PdIndex; - UINTN PtIndex; - UINTN NumberOfPdptEntries; - UINTN NumberOfPml4Entries; - UINTN NumberOfPml5Entries; - UINTN SizeOfMemorySpace; - BOOLEAN Nx; - IA32_CR4 Cr4; - BOOLEAN Enable5LevelPaging; - BOOLEAN WpEnabled; - BOOLEAN CetEnabled; + if (((MEMORY_PROTECTION_RANGE *)Buffer1)->Range.Base > ((MEMORY_PROTECTION_RANGE *)Buffer2)->Range.Base) { + return 1; + } else if (((MEMORY_PROTECTION_RANGE *)Buffer1)->Range.Base < ((MEMORY_PROTECTION_RANGE *)Buffer2)->Range.Base) { + return -1; + } - Cr4.UintN = AsmReadCr4 (); - Enable5LevelPaging = (BOOLEAN)(Cr4.Bits.LA57 == 1); + return 0; +} - if (sizeof (UINTN) == sizeof (UINT64)) { - if (!Enable5LevelPaging) { - Pml5Entry = (UINTN)mSmmProfileCr3 | IA32_PG_P; - Pml5 = &Pml5Entry; - } else { - Pml5 = (UINT64 *)(UINTN)mSmmProfileCr3; - } +/** + Function to compare 2 EFI_SMRAM_DESCRIPTOR based on CpuStart. - SizeOfMemorySpace = HighBitSet64 (gPhyMask) + 1; - ASSERT (SizeOfMemorySpace <= 52); + @param[in] Buffer1 pointer to Device Path poiner to compare + @param[in] Buffer2 pointer to second DevicePath pointer to compare - // - // Calculate the table entries of PML5E, PML4E and PDPTE. - // - NumberOfPml5Entries = 1; - if (SizeOfMemorySpace > 48) { - if (Enable5LevelPaging) { - NumberOfPml5Entries = (UINTN)LShiftU64 (1, SizeOfMemorySpace - 48); - } + @retval 0 Buffer1 equal to Buffer2 + @retval <0 Buffer1 is less than Buffer2 + @retval >0 Buffer1 is greater than Buffer2 +**/ +INTN +EFIAPI +CpuSmramRangeCompare ( + IN CONST VOID *Buffer1, + IN CONST VOID *Buffer2 + ) +{ + if (((EFI_SMRAM_DESCRIPTOR *)Buffer1)->CpuStart > ((EFI_SMRAM_DESCRIPTOR *)Buffer2)->CpuStart) { + return 1; + } else if (((EFI_SMRAM_DESCRIPTOR *)Buffer1)->CpuStart < ((EFI_SMRAM_DESCRIPTOR *)Buffer2)->CpuStart) { + return -1; + } - SizeOfMemorySpace = 48; - } + return 0; +} - NumberOfPml4Entries = 1; - if (SizeOfMemorySpace > 39) { - NumberOfPml4Entries = (UINTN)LShiftU64 (1, SizeOfMemorySpace - 39); - SizeOfMemorySpace = 39; - } +/** + Update page table according to protected memory ranges and the 4KB-page mapped memory ranges. - NumberOfPdptEntries = 1; - ASSERT (SizeOfMemorySpace > 30); - NumberOfPdptEntries = (UINTN)LShiftU64 (1, SizeOfMemorySpace - 30); +**/ +VOID +InitPaging ( + VOID + ) +{ + RETURN_STATUS Status; + UINTN Index; + UINTN PageTable; + UINT64 Base; + UINT64 Length; + UINT64 Limit; + UINT64 PreviousAddress; + UINT64 MemoryAttrMask; + VOID *Buffer; + BOOLEAN WpEnabled; + BOOLEAN CetEnabled; + + PageTable = AsmReadCr3 (); + if (sizeof (UINTN) == sizeof (UINT32)) { + Limit = BASE_4GB; } else { - Pml4Entry = (UINTN)mSmmProfileCr3 | IA32_PG_P; - Pml4 = &Pml4Entry; - Pml5Entry = (UINTN)Pml4 | IA32_PG_P; - Pml5 = &Pml5Entry; - NumberOfPml5Entries = 1; - NumberOfPml4Entries = 1; - NumberOfPdptEntries = 4; + Limit = (IsRestrictedMemoryAccess ()) ? LShiftU64 (1, mPhysicalAddressBits) : BASE_4GB; } DisableReadOnlyPageWriteProtect (&WpEnabled, &CetEnabled); // - // Go through page table and change 2MB-page into 4KB-page. + // [0, 4k] may be non-present. // - for (Pml5Index = 0; Pml5Index < NumberOfPml5Entries; Pml5Index++) { - if ((Pml5[Pml5Index] & IA32_PG_P) == 0) { - // - // If PML5 entry does not exist, skip it - // - continue; - } + PreviousAddress = ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT1) != 0) ? BASE_4KB : 0; - Pml4 = (UINT64 *)(UINTN)(Pml5[Pml5Index] & PHYSICAL_ADDRESS_MASK); - for (Pml4Index = 0; Pml4Index < NumberOfPml4Entries; Pml4Index++) { - if ((Pml4[Pml4Index] & IA32_PG_P) == 0) { - // - // If PML4 entry does not exist, skip it - // - continue; + DEBUG ((DEBUG_INFO, "Patch page table start ...\n")); + if (FeaturePcdGet (PcdCpuSmmProfileEnable)) { + // + // Sort the mProtectionMemRange + // + Buffer = AllocateZeroPool (sizeof (MEMORY_PROTECTION_RANGE)); + ASSERT (Buffer != NULL); + QuickSort (mProtectionMemRange, mProtectionMemRangeCount, sizeof (MEMORY_PROTECTION_RANGE), (BASE_SORT_COMPARE)ProtectionRangeCompare, Buffer); + for (Index = 0; Index < mProtectionMemRangeCount; Index++) { + MemoryAttrMask = 0; + if ((mProtectionMemRange[Index].Nx == 1) && mXdSupported) { + MemoryAttrMask |= EFI_MEMORY_XP; } - Pdpt = (UINT64 *)(UINTN)(Pml4[Pml4Index] & ~mAddressEncMask & PHYSICAL_ADDRESS_MASK); - for (PdptIndex = 0; PdptIndex < NumberOfPdptEntries; PdptIndex++, Pdpt++) { - if ((*Pdpt & IA32_PG_P) == 0) { - // - // If PDPT entry does not exist, skip it - // - continue; - } - - if ((*Pdpt & IA32_PG_PS) != 0) { - // - // This is 1G entry, skip it - // - continue; - } - - Pd = (UINT64 *)(UINTN)(*Pdpt & ~mAddressEncMask & PHYSICAL_ADDRESS_MASK); - if (Pd == 0) { - continue; - } - - for (PdIndex = 0; PdIndex < SIZE_4KB / sizeof (*Pd); PdIndex++, Pd++) { - if ((*Pd & IA32_PG_P) == 0) { - // - // If PD entry does not exist, skip it - // - continue; - } - - Address = (UINTN)LShiftU64 ( - LShiftU64 ( - LShiftU64 ((Pml5Index << 9) + Pml4Index, 9) + PdptIndex, - 9 - ) + PdIndex, - 21 - ); - - // - // If it is 2M page, check IsAddressSplit() - // - if (((*Pd & IA32_PG_PS) != 0) && IsAddressSplit (Address)) { - // - // Based on current page table, create 4KB page table for split area. - // - ASSERT (Address == (*Pd & PHYSICAL_ADDRESS_MASK)); - - Pt = AllocatePageTableMemory (1); - ASSERT (Pt != NULL); + if (mProtectionMemRange[Index].Present == 0) { + MemoryAttrMask = EFI_MEMORY_RP; + } - // Split it - for (PtIndex = 0; PtIndex < SIZE_4KB / sizeof (*Pt); PtIndex++) { - Pt[PtIndex] = Address + ((PtIndex << 12) | mAddressEncMask | PAGE_ATTRIBUTE_BITS); - } // end for PT + Base = mProtectionMemRange[Index].Range.Base; + Length = mProtectionMemRange[Index].Range.Top - Base; + if (MemoryAttrMask != 0) { + Status = ConvertMemoryPageAttributes (PageTable, mPagingMode, Base, Length, MemoryAttrMask, TRUE, NULL); + ASSERT_RETURN_ERROR (Status); + } - *Pd = (UINT64)(UINTN)Pt | mAddressEncMask | PAGE_ATTRIBUTE_BITS; - } // end if IsAddressSplit - } // end for PD - } // end for PDPT - } // end for PML4 - } // end for PML5 + if (Base > PreviousAddress) { + // + // Mark the ranges not in mProtectionMemRange as non-present. + // + MemoryAttrMask = EFI_MEMORY_RP; + Status = ConvertMemoryPageAttributes (PageTable, mPagingMode, PreviousAddress, Base - PreviousAddress, MemoryAttrMask, TRUE, NULL); + ASSERT_RETURN_ERROR (Status); + } - // - // Go through page table and set several page table entries to absent or execute-disable. - // - DEBUG ((DEBUG_INFO, "Patch page table start ...\n")); - for (Pml5Index = 0; Pml5Index < NumberOfPml5Entries; Pml5Index++) { - if ((Pml5[Pml5Index] & IA32_PG_P) == 0) { - // - // If PML5 entry does not exist, skip it - // - continue; + PreviousAddress = Base + Length; } - Pml4 = (UINT64 *)(UINTN)(Pml5[Pml5Index] & PHYSICAL_ADDRESS_MASK); - for (Pml4Index = 0; Pml4Index < NumberOfPml4Entries; Pml4Index++) { - if ((Pml4[Pml4Index] & IA32_PG_P) == 0) { + // + // This assignment is for setting the last remaining range + // + MemoryAttrMask = EFI_MEMORY_RP; + } else { + // + // Sort the mSmmCpuSmramRanges + // + Buffer = AllocateZeroPool (sizeof (EFI_SMRAM_DESCRIPTOR)); + ASSERT (Buffer != NULL); + QuickSort (mSmmCpuSmramRanges, mSmmCpuSmramRangeCount, sizeof (EFI_SMRAM_DESCRIPTOR), (BASE_SORT_COMPARE)CpuSmramRangeCompare, Buffer); + MemoryAttrMask = EFI_MEMORY_XP; + for (Index = 0; Index < mSmmCpuSmramRangeCount; Index++) { + Base = mSmmCpuSmramRanges[Index].CpuStart; + if ((Base > PreviousAddress) && mXdSupported) { // - // If PML4 entry does not exist, skip it + // Mark the ranges not in mSmmCpuSmramRanges as NX. // - continue; + Status = ConvertMemoryPageAttributes (PageTable, mPagingMode, PreviousAddress, Base - PreviousAddress, MemoryAttrMask, TRUE, NULL); + ASSERT_RETURN_ERROR (Status); } - Pdpt = (UINT64 *)(UINTN)(Pml4[Pml4Index] & ~mAddressEncMask & PHYSICAL_ADDRESS_MASK); - for (PdptIndex = 0; PdptIndex < NumberOfPdptEntries; PdptIndex++, Pdpt++) { - if ((*Pdpt & IA32_PG_P) == 0) { - // - // If PDPT entry does not exist, skip it - // - continue; - } - - if ((*Pdpt & IA32_PG_PS) != 0) { - // - // This is 1G entry, set NX bit and skip it - // - if (mXdSupported) { - *Pdpt = *Pdpt | IA32_PG_NX; - } - - continue; - } + PreviousAddress = mSmmCpuSmramRanges[Index].CpuStart + mSmmCpuSmramRanges[Index].PhysicalSize; + } + } - Pd = (UINT64 *)(UINTN)(*Pdpt & ~mAddressEncMask & PHYSICAL_ADDRESS_MASK); - if (Pd == 0) { - continue; - } + FreePool (Buffer); - for (PdIndex = 0; PdIndex < SIZE_4KB / sizeof (*Pd); PdIndex++, Pd++) { - if ((*Pd & IA32_PG_P) == 0) { - // - // If PD entry does not exist, skip it - // - continue; - } - - Address = (UINTN)LShiftU64 ( - LShiftU64 ( - LShiftU64 ((Pml5Index << 9) + Pml4Index, 9) + PdptIndex, - 9 - ) + PdIndex, - 21 - ); - - if ((*Pd & IA32_PG_PS) != 0) { - // 2MB page - - if (!IsAddressValid (Address, &Nx)) { - // - // Patch to remove Present flag and RW flag - // - *Pd = *Pd & (INTN)(INT32)(~PAGE_ATTRIBUTE_BITS); - } - - if (Nx && mXdSupported) { - *Pd = *Pd | IA32_PG_NX; - } - } else { - // 4KB page - Pt = (UINT64 *)(UINTN)(*Pd & ~mAddressEncMask & PHYSICAL_ADDRESS_MASK); - if (Pt == 0) { - continue; - } - - for (PtIndex = 0; PtIndex < SIZE_4KB / sizeof (*Pt); PtIndex++, Pt++) { - if (!IsAddressValid (Address, &Nx)) { - *Pt = *Pt & (INTN)(INT32)(~PAGE_ATTRIBUTE_BITS); - } - - if (Nx && mXdSupported) { - *Pt = *Pt | IA32_PG_NX; - } - - Address += SIZE_4KB; - } // end for PT - } // end if PS - } // end for PD - } // end for PDPT - } // end for PML4 - } // end for PML5 + if (PreviousAddress < Limit) { + // + // Set the last remaining range to EFI_MEMORY_RP/EFI_MEMORY_XP. + // This path applies to both SmmProfile enable/disable case. + // + Status = ConvertMemoryPageAttributes (PageTable, mPagingMode, PreviousAddress, Limit - PreviousAddress, MemoryAttrMask, TRUE, NULL); + ASSERT_RETURN_ERROR (Status); + } EnableReadOnlyPageWriteProtect (WpEnabled, CetEnabled); -- 2.39.1.windows.1