[kvm-unit-tests] x86: nVMX: Add tests of VMPTRLD and VMPTRST to MMIO addresses
diff mbox series

Message ID 20190913000045.19214-1-sean.j.christopherson@intel.com
State New
Headers show
Series
  • [kvm-unit-tests] x86: nVMX: Add tests of VMPTRLD and VMPTRST to MMIO addresses
Related show

Commit Message

Sean Christopherson Sept. 13, 2019, midnight UTC
KVM uses master abort semantics to handle MMIO accesses when emulating
VMX instructions.  Ensure this is the case, i.e. that KVM doesn't inject
a #PF, by emitting VMPTRLD and VMPTRST to the TXT private address space.

Use the TXT private space as the bogus MMIO address so that the tests
can also pass on bare metal.  If my recollection of TXT is correct,
accesses to private space when it is locked trigger master aborts.

Cc: Vitaly Kuznetsov <vkuznets@redhat.com>
Cc: Jim Mattson <jmattson@google.com>
Cc: Fuqian Huang <huangfq.daxian@gmail.com>
Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com>
---

This obviously assumes the associated KVM change[*] is applied.

[*] https://lkml.kernel.org/r/20190912235603.18954-1-sean.j.christopherson@intel.com

 x86/vmx.c | 15 +++++++++++++++
 x86/vmx.h | 20 ++++++++++++++++++++
 2 files changed, 35 insertions(+)

Patch
diff mbox series

diff --git a/x86/vmx.c b/x86/vmx.c
index 6079420..b14fc02 100644
--- a/x86/vmx.c
+++ b/x86/vmx.c
@@ -1374,6 +1374,8 @@  out:
 	return ret;
 }
 
+#define INTEL_TXT_PRIVATE_SPACE	0xfed20000
+
 static void test_vmptrld(void)
 {
 	struct vmcs *vmcs, *tmp_root;
@@ -1393,6 +1395,10 @@  static void test_vmptrld(void)
 	report("test vmptrld with vmcs address bits set beyond physical address width",
 	       make_vmcs_current(tmp_root) == 1);
 
+	/* Non-existent address, i.e. emulated MMIO */
+	report("test vmptrld with non-existent address (for operand)",
+	       vmptrld_raw((void *)INTEL_TXT_PRIVATE_SPACE) == 1);
+
 	/* Pass VMXON region */
 	assert(!vmcs_clear(vmcs));
 	assert(!make_vmcs_current(vmcs));
@@ -1414,6 +1420,15 @@  static void test_vmptrst(void)
 	init_vmcs(&vmcs1);
 	ret = vmcs_save(&vmcs2);
 	report("test vmptrst", (!ret) && (vmcs1 == vmcs2));
+
+	/*
+	 * Non-existent address, i.e. emulated MMIO.  Counter-intuitively, this
+	 * is expected to succeed as KVM handles unexpected MMIO accesses using
+	 * master abort semantics, i.e. drops the write but doesn't signal a
+	 * fault of any kind.
+	 */
+	report("test vmptrst with non-existent address (for operand)",
+	       vmptrst_raw((void *)INTEL_TXT_PRIVATE_SPACE) == 0);
 }
 
 struct vmx_ctl_msr {
diff --git a/x86/vmx.h b/x86/vmx.h
index 75abf9a..4ed4aba 100644
--- a/x86/vmx.h
+++ b/x86/vmx.h
@@ -685,6 +685,26 @@  static int vmx_off(void)
 	return ret;
 }
 
+static inline bool vmptrld_raw(void *ptr)
+{
+	bool ret;
+	u64 rflags = read_rflags() | X86_EFLAGS_CF | X86_EFLAGS_ZF;
+
+	asm volatile ("push %1; popf; vmptrld (%%rax); setbe %0"
+		      : "=q" (ret) : "q" (rflags), "a" (ptr) : "cc");
+	return ret;
+}
+
+static inline int vmptrst_raw(void *ptr)
+{
+	bool ret;
+	u64 rflags = read_rflags() | X86_EFLAGS_CF | X86_EFLAGS_ZF;
+
+	asm volatile ("push %1; popf; vmptrst (%%rax); setbe %0"
+		      : "=q" (ret) : "q" (rflags), "a" (ptr) : "cc");
+	return ret;
+}
+
 static inline int make_vmcs_current(struct vmcs *vmcs)
 {
 	bool ret;