[kvm-unit-tests PATCH 2/3] nVMX: Use ASM_TRY() for VMREAD and VMWRITE page fault tests

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Use ASM_TRY() in the VMREAD and VMWRITE page fault tests to fix a bug
where gcc-12 completely optimizes out handler_called.  Because the flag
isn't tagged volatile and the compiler is unaware that an exception may
occur, gcc-12 thinks the value can only ever be 0.

Note, exception fixup effectively performs an exact RIP check, and using
LAHF to save RFLAGS drops the fixed RFLAGS bit.

Opportunistically drop the 'noinline' as removing the global label makes
the functions safe to inline/duplicate.

Signed-off-by: Sean Christopherson <seanjc@xxxxxxxxxx>
---
 x86/vmx.c | 135 ++++++++++++++++++++----------------------------------
 1 file changed, 49 insertions(+), 86 deletions(-)

diff --git a/x86/vmx.c b/x86/vmx.c
index a13f2c9..0ae134d 100644
--- a/x86/vmx.c
+++ b/x86/vmx.c
@@ -387,25 +387,7 @@ static void test_vmwrite_vmread(void)
 	free_page(vmcs);
 }
 
-ulong finish_fault;
-u8 sentinel;
-bool handler_called;
-
-static void pf_handler(struct ex_regs *regs)
-{
-	/*
-	 * check that RIP was not improperly advanced and that the
-	 * flags value was preserved.
-	 */
-	report(regs->rip < finish_fault, "RIP has not been advanced!");
-	report(((u8)regs->rflags == ((sentinel | 2) & 0xd7)),
-	       "The low byte of RFLAGS was preserved!");
-	regs->rip = finish_fault;
-	handler_called = true;
-
-}
-
-static void prep_flags_test_env(void **vpage, struct vmcs **vmcs, handler *old)
+static void prep_flags_test_env(void **vpage, struct vmcs **vmcs)
 {
 	/*
 	 * get an unbacked address that will cause a #PF
@@ -421,107 +403,88 @@ static void prep_flags_test_env(void **vpage, struct vmcs **vmcs, handler *old)
 	(*vmcs)->hdr.revision_id = basic.revision;
 	assert(!vmcs_clear(*vmcs));
 	assert(!make_vmcs_current(*vmcs));
-
-	*old = handle_exception(PF_VECTOR, &pf_handler);
 }
 
-static noinline void test_read_sentinel(void)
+static void test_read_sentinel(u8 sentinel)
 {
-	void *vpage;
+	unsigned long flags = sentinel;
+	unsigned int vector;
 	struct vmcs *vmcs;
-	handler old;
+	void *vpage;
 
-	prep_flags_test_env(&vpage, &vmcs, &old);
+	prep_flags_test_env(&vpage, &vmcs);
 
 	/*
-	 * set the proper label
+	 * Execute VMREAD with a not-PRESENT memory operand, and verify a #PF
+	 * occurred and RFLAGS were not modified.
 	 */
-	extern char finish_read_fault;
+	asm volatile ("sahf\n\t"
+		      ASM_TRY("1f")
+		      "vmread %[enc], %[val]\n\t"
+		      "1: lahf"
+		      : [val] "=m" (*(u64 *)vpage),
+			[flags] "+a" (flags)
+		      : [enc] "r" ((u64)GUEST_SEL_SS)
+		      : "cc");
 
-	finish_fault = (ulong)&finish_read_fault;
+	vector = exception_vector();
+	report(vector == PF_VECTOR,
+	       "Expected #PF on VMREAD, got exception 0x%x", vector);
 
-	/*
-	 * execute the vmread instruction that will cause a #PF
-	 */
-	handler_called = false;
-	asm volatile ("movb %[byte], %%ah\n\t"
-		      "sahf\n\t"
-		      "vmread %[enc], %[val]; finish_read_fault:"
-		      : [val] "=m" (*(u64 *)vpage)
-		      : [byte] "Krm" (sentinel),
-		      [enc] "r" ((u64)GUEST_SEL_SS)
-		      : "cc", "ah");
-	report(handler_called, "The #PF handler was invoked");
-
-	/*
-	 * restore the old #PF handler
-	 */
-	handle_exception(PF_VECTOR, old);
+	report((u8)flags == sentinel,
+	       "Expected RFLAGS 0x%x, got 0x%x", sentinel, (u8)flags);
 }
 
 static void test_vmread_flags_touch(void)
 {
 	/*
-	 * set up the sentinel value in the flags register. we
-	 * choose these two values because they candy-stripe
-	 * the 5 flags that sahf sets.
+	 * Test with two values to candy-stripe the 5 flags stored/loaded by
+	 * SAHF/LAHF.
 	 */
-	sentinel = 0x91;
-	test_read_sentinel();
-
-	sentinel = 0x45;
-	test_read_sentinel();
+	test_read_sentinel(0x91);
+	test_read_sentinel(0x45);
 }
 
-static noinline void test_write_sentinel(void)
+static void test_write_sentinel(u8 sentinel)
 {
-	void *vpage;
+	unsigned long flags = sentinel;
+	unsigned int vector;
 	struct vmcs *vmcs;
-	handler old;
+	void *vpage;
 
-	prep_flags_test_env(&vpage, &vmcs, &old);
+	prep_flags_test_env(&vpage, &vmcs);
 
 	/*
-	 * set the proper label
+	 * Execute VMWRITE with a not-PRESENT memory operand, and verify a #PF
+	 * occurred and RFLAGS were not modified.
 	 */
-	extern char finish_write_fault;
+	asm volatile ("sahf\n\t"
+		      ASM_TRY("1f")
+		      "vmwrite %[val], %[enc]\n\t"
+		      "1: lahf"
+		      : [val] "=m" (*(u64 *)vpage),
+			[flags] "+a" (flags)
+		      : [enc] "r" ((u64)GUEST_SEL_SS)
+		      : "cc");
 
-	finish_fault = (ulong)&finish_write_fault;
+	vector = exception_vector();
+	report(vector == PF_VECTOR,
+	       "Expected #PF on VMWRITE, got exception '0x%x'\n", vector);
 
-	/*
-	 * execute the vmwrite instruction that will cause a #PF
-	 */
-	handler_called = false;
-	asm volatile ("movb %[byte], %%ah\n\t"
-		      "sahf\n\t"
-		      "vmwrite %[val], %[enc]; finish_write_fault:"
-		      : [val] "=m" (*(u64 *)vpage)
-		      : [byte] "Krm" (sentinel),
-		      [enc] "r" ((u64)GUEST_SEL_SS)
-		      : "cc", "ah");
-	report(handler_called, "The #PF handler was invoked");
-
-	/*
-	 * restore the old #PF handler
-	 */
-	handle_exception(PF_VECTOR, old);
+	report((u8)flags == sentinel,
+	       "Expected RFLAGS 0x%x, got 0x%x", sentinel, (u8)flags);
 }
 
 static void test_vmwrite_flags_touch(void)
 {
 	/*
-	 * set up the sentinel value in the flags register. we
-	 * choose these two values because they candy-stripe
-	 * the 5 flags that sahf sets.
+	 * Test with two values to candy-stripe the 5 flags stored/loaded by
+	 * SAHF/LAHF.
 	 */
-	sentinel = 0x91;
-	test_write_sentinel();
-
-	sentinel = 0x45;
-	test_write_sentinel();
+	test_write_sentinel(0x91);
+	test_write_sentinel(0x45);
 }
 
-
 static void test_vmcs_high(void)
 {
 	struct vmcs *vmcs = alloc_page();
-- 
2.38.0.rc1.362.ged0d419d3c-goog




[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux