All of lore.kernel.org
 help / color / mirror / Atom feed
From: Binbin Wu <binbin.wu@linux.intel.com>
To: kvm@vger.kernel.org
Cc: seanjc@google.com, pbonzini@redhat.com, chao.gao@intel.com,
	robert.hu@linux.intel.com, robert.hoo.linux@gmail.com,
	binbin.wu@linux.intel.com
Subject: [kvm-unit-tests PATCH v7 4/5] x86: Add test cases for LAM_{U48,U57}
Date: Mon,  1 Jul 2024 15:30:09 +0800	[thread overview]
Message-ID: <20240701073010.91417-5-binbin.wu@linux.intel.com> (raw)
In-Reply-To: <20240701073010.91417-1-binbin.wu@linux.intel.com>

This unit test covers:
1. CR3 LAM bits toggles.
2. Memory/MMIO access with user mode address containing LAM metadata.

Signed-off-by: Binbin Wu <binbin.wu@linux.intel.com>
Reviewed-by: Chao Gao <chao.gao@intel.com>
---
v7:
- Rename lam_{u48,u57}_active() to is_lam_{u48,u57}_enabled(), and move them to
  processor.h (Sean)
- Get lam status based on the address and vCPU state. (Sean)
- Test LAM userspace address in kernel mode directly to simplify the interface
  of test_ptr() since LAM identifies a address as kernel or user only based on
  the address itself.
- Add comments about the virtualization hole of CR3 LAM bits.
---
 lib/x86/processor.h | 12 ++++++++
 x86/lam.c           | 69 ++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 80 insertions(+), 1 deletion(-)

diff --git a/lib/x86/processor.h b/lib/x86/processor.h
index a38f87ed..c2cafb01 100644
--- a/lib/x86/processor.h
+++ b/lib/x86/processor.h
@@ -77,7 +77,9 @@ static inline u64 set_la_non_canonical(u64 src, u64 mask)
 
 #define X86_CR3_PCID_MASK	GENMASK(11, 0)
 #define X86_CR3_LAM_U57_BIT	(61)
+#define X86_CR3_LAM_U57		BIT_ULL(X86_CR3_LAM_U57_BIT)
 #define X86_CR3_LAM_U48_BIT	(62)
+#define X86_CR3_LAM_U48		BIT_ULL(X86_CR3_LAM_U48_BIT)
 
 #define X86_CR4_VME_BIT		(0)
 #define X86_CR4_VME		BIT(X86_CR4_VME_BIT)
@@ -988,4 +990,14 @@ static inline bool is_lam_sup_enabled(void)
 	return !!(read_cr4() & X86_CR4_LAM_SUP);
 }
 
+static inline bool is_lam_u48_enabled(void)
+{
+	return (read_cr3() & (X86_CR3_LAM_U48 | X86_CR3_LAM_U57)) == X86_CR3_LAM_U48;
+}
+
+static inline bool is_lam_u57_enabled(void)
+{
+	return !!(read_cr3() & X86_CR3_LAM_U57);
+}
+
 #endif
diff --git a/x86/lam.c b/x86/lam.c
index 2f95b6c9..40b8ecdd 100644
--- a/x86/lam.c
+++ b/x86/lam.c
@@ -67,7 +67,14 @@ static bool get_lam_mask(u64 address, u64* lam_mask)
 		return true;
 	}
 
-	/* TODO: Get LAM mask for userspace address. */
+	if(is_lam_u48_enabled()) {
+		*lam_mask = LAM48_MASK;
+		return true;
+	}
+
+	if(is_lam_u57_enabled())
+		return true;
+
 	return false;
 }
 
@@ -88,6 +95,17 @@ static void test_ptr(u64* ptr, bool is_mmio)
 	report(fault != lam_active, "Expected access to tagged address for %s %s LAM to %s",
 	       is_mmio ? "MMIO" : "memory", lam_active ? "with" : "without",
 	       lam_active ? "succeed" : "#GP");
+
+	/*
+	 * This test case is only triggered when LAM_U57 is active and 4-level
+	 * paging is used. For the case, bit[56:47] aren't all 0 triggers #GP.
+	 */
+	if (lam_active && (lam_mask == LAM57_MASK) && !is_la57_enabled()) {
+		ptr = (u64 *)set_la_non_canonical((u64)ptr, LAM48_MASK);
+		fault = test_for_exception(GP_VECTOR, do_mov, ptr);
+		report(fault, "Expected access to non-LAM-canonical address for %s to #GP",
+		       is_mmio ? "MMIO" : "memory");
+	}
 }
 
 /* invlpg with tagged address is same as NOP, no #GP expected. */
@@ -199,6 +217,54 @@ static void test_lam_sup(void)
 			    "use kvm.force_emulation_prefix=1 to enable\n");
 }
 
+static void test_lam_user(void)
+{
+	void* vaddr;
+	int vector;
+	unsigned long cr3 = read_cr3() & ~(X86_CR3_LAM_U48 | X86_CR3_LAM_U57);
+	bool has_lam = this_cpu_has(X86_FEATURE_LAM);
+
+	/*
+	 * The physical address of AREA_NORMAL is within 36 bits, so that using
+	 * identical mapping, the linear address will be considered as user mode
+	 * address from the view of LAM, and the metadata bits are not used as
+	 * address for both LAM48 and LAM57.
+	 */
+	vaddr = alloc_pages_flags(0, AREA_NORMAL);
+	_Static_assert((AREA_NORMAL_PFN & GENMASK(63, 47)) == 0UL,
+			"Identical mapping range check");
+
+	/*
+	 * Note, LAM doesn't have a global control bit to turn on/off LAM
+	 * completely, but purely depends on hardware's CPUID to determine it
+	 * can be enabled or not. That means, when EPT is on, even when KVM
+	 * doesn't expose LAM to guest, the guest can still set LAM control bits
+	 * in CR3 w/o causing problem. This is an unfortunate virtualization
+	 * hole. KVM doesn't choose to intercept CR3 in this case for
+	 * performance.
+	 * Only enable LAM CR3 bits when LAM feature is exposed.
+	 */
+	if (has_lam) {
+		vector = write_cr3_safe(cr3 | X86_CR3_LAM_U48);
+		report(!vector && is_lam_u48_enabled(), "Expected CR3.LAM_U48=1 to succeed");
+	}
+	/*
+	 * Physical memory & MMIO have already been identical mapped in
+	 * setup_mmu().
+	 */
+	test_ptr(vaddr, false);
+	test_ptr(phys_to_virt(IORAM_BASE_PHYS), true);
+
+	if (has_lam) {
+		vector = write_cr3_safe(cr3 | X86_CR3_LAM_U57);
+		report(!vector && is_lam_u57_enabled(), "Expected CR3.LAM_U57=1 to succeed");
+
+		/* If !has_lam, it has been tested above, no need to test again. */
+		test_ptr(vaddr, false);
+		test_ptr(phys_to_virt(IORAM_BASE_PHYS), true);
+	}
+}
+
 int main(int ac, char **av)
 {
 	setup_vm();
@@ -209,6 +275,7 @@ int main(int ac, char **av)
 		report_info("This CPU supports LAM feature\n");
 
 	test_lam_sup();
+	test_lam_user();
 
 	return report_summary();
 }
-- 
2.43.2


  parent reply	other threads:[~2024-07-01  7:29 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-07-01  7:30 [kvm-unit-tests PATCH v7 0/5] x86: Add test cases for LAM Binbin Wu
2024-07-01  7:30 ` [kvm-unit-tests PATCH v7 1/5] x86: Move struct invpcid_desc to processor.h Binbin Wu
2024-07-01  7:30 ` [kvm-unit-tests PATCH v7 2/5] x86: Allow setting of CR3 LAM bits if LAM supported Binbin Wu
2024-07-01  7:30 ` [kvm-unit-tests PATCH v7 3/5] x86: Add test case for LAM_SUP Binbin Wu
2024-07-01  7:30 ` Binbin Wu [this message]
2024-07-01  7:30 ` [kvm-unit-tests PATCH v7 5/5] x86: Add test case for INVVPID with LAM Binbin Wu
2024-09-25  1:22 ` [kvm-unit-tests PATCH v7 0/5] x86: Add test cases for LAM Binbin Wu
2025-02-24 17:23 ` Sean Christopherson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240701073010.91417-5-binbin.wu@linux.intel.com \
    --to=binbin.wu@linux.intel.com \
    --cc=chao.gao@intel.com \
    --cc=kvm@vger.kernel.org \
    --cc=pbonzini@redhat.com \
    --cc=robert.hoo.linux@gmail.com \
    --cc=robert.hu@linux.intel.com \
    --cc=seanjc@google.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.