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

[Xen-devel] [PATCH v5 1/4] x86/HVM: cancel emulation when register state got altered



Re-execution (after having received data from a device model) relies on
the same register state still being in place as it was when the request
was first sent to the device model. Therefore vCPU state changes
effected by remote sources need to result in no attempt of re-execution.
Instead the returned data is to simply be ignored.

Note that any such asynchronous state changes happen with the vCPU at
least paused (potentially down and/or not marked ->is_initialised), so
there's no issue with fiddling with register state behind the actively
running emulator's back. Hence the new function doesn't need to
synchronize with the core emulation logic.

Suggested-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
---
v5: New.

--- a/xen/arch/x86/domctl.c
+++ b/xen/arch/x86/domctl.c
@@ -21,6 +21,7 @@
 #include <xen/iocap.h>
 #include <xen/paging.h>
 #include <asm/irq.h>
+#include <asm/hvm/emulate.h>
 #include <asm/hvm/hvm.h>
 #include <asm/hvm/support.h>
 #include <asm/processor.h>
@@ -1147,11 +1148,16 @@ long arch_do_domctl(
             else
             {
                 vcpu_pause(v);
+
                 v->arch.xcr0 = _xcr0;
                 v->arch.xcr0_accum = _xcr0_accum;
                 v->arch.nonlazy_xstate_used = _xcr0_accum & XSTATE_NONLAZY;
                 compress_xsave_states(v, _xsave_area,
                                       evc->size - PV_XSAVE_HDR_SIZE);
+
+                if ( is_hvm_domain(d) )
+                    hvmemul_cancel(v);
+
                 vcpu_unpause(v);
             }
 
--- a/xen/arch/x86/hvm/domain.c
+++ b/xen/arch/x86/hvm/domain.c
@@ -22,6 +22,8 @@
 #include <xen/paging.h>
 #include <xen/sched.h>
 
+#include <asm/hvm/emulate.h>
+
 #include <public/hvm/hvm_vcpu.h>
 
 static int check_segment(struct segment_register *reg, enum x86_segment seg)
@@ -323,6 +325,8 @@ int arch_set_info_hvm_guest(struct vcpu
 
     paging_update_paging_modes(v);
 
+    hvmemul_cancel(v);
+
     v->is_initialised = 1;
     set_bit(_VPF_down, &v->pause_flags);
 
--- a/xen/arch/x86/hvm/emulate.c
+++ b/xen/arch/x86/hvm/emulate.c
@@ -121,6 +121,23 @@ static const struct hvm_io_handler ioreq
     .ops = &ioreq_server_ops
 };
 
+/*
+ * Drop all records of in-flight emulation. This is needed whenever a vCPU's
+ * register state may have changed behind the emulator's back.
+ */
+void hvmemul_cancel(struct vcpu *v)
+{
+    struct hvm_vcpu_io *vio = &v->arch.hvm.hvm_io;
+
+    vio->io_req.state = STATE_IOREQ_NONE;
+    vio->io_completion = HVMIO_no_completion;
+    vio->mmio_cache_count = 0;
+    vio->mmio_insn_bytes = 0;
+    vio->mmio_access = (struct npfec){};
+    vio->mmio_retry = false;
+    vio->g2m_ioport = NULL;
+}
+
 static int hvmemul_do_io(
     bool_t is_mmio, paddr_t addr, unsigned long *reps, unsigned int size,
     uint8_t dir, bool_t df, bool_t data_is_addr, uintptr_t data)
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -477,6 +477,14 @@ u64 hvm_get_guest_tsc_fixed(struct vcpu
     return tsc + v->arch.hvm.cache_tsc_offset;
 }
 
+void hvm_set_info_guest(struct vcpu *v)
+{
+    if ( hvm_funcs.set_info_guest )
+        alternative_vcall(hvm_funcs.set_info_guest, v);
+
+    hvmemul_cancel(v);
+}
+
 void hvm_migrate_timers(struct vcpu *v)
 {
     rtc_migrate_timers(v);
@@ -1162,6 +1170,8 @@ static int hvm_load_cpu_ctxt(struct doma
     v->arch.dr6   = ctxt.dr6;
     v->arch.dr7   = ctxt.dr7;
 
+    hvmemul_cancel(v);
+
     /* Auxiliary processors should be woken immediately. */
     v->is_initialised = 1;
     clear_bit(_VPF_down, &v->pause_flags);
--- a/xen/arch/x86/hvm/vlapic.c
+++ b/xen/arch/x86/hvm/vlapic.c
@@ -33,6 +33,7 @@
 #include <asm/apic.h>
 #include <asm/io_apic.h>
 #include <asm/vpmu.h>
+#include <asm/hvm/emulate.h>
 #include <asm/hvm/hvm.h>
 #include <asm/hvm/io.h>
 #include <asm/hvm/support.h>
@@ -306,6 +307,8 @@ static void vlapic_init_sipi_one(struct
         BUG();
     }
 
+    hvmemul_cancel(target);
+
     vcpu_unpause(target);
 }
 
--- a/xen/include/asm-x86/hvm/emulate.h
+++ b/xen/include/asm-x86/hvm/emulate.h
@@ -76,6 +76,7 @@ void hvm_emulate_init_per_insn(
     unsigned int insn_bytes);
 void hvm_emulate_writeback(
     struct hvm_emulate_ctxt *hvmemul_ctxt);
+void hvmemul_cancel(struct vcpu *v);
 struct segment_register *hvmemul_get_seg_reg(
     enum x86_segment seg,
     struct hvm_emulate_ctxt *hvmemul_ctxt);
--- a/xen/include/asm-x86/hvm/hvm.h
+++ b/xen/include/asm-x86/hvm/hvm.h
@@ -278,6 +278,8 @@ void hvm_get_segment_register(struct vcp
 void hvm_set_segment_register(struct vcpu *v, enum x86_segment seg,
                               struct segment_register *reg);
 
+void hvm_set_info_guest(struct vcpu *v);
+
 bool hvm_set_guest_bndcfgs(struct vcpu *v, u64 val);
 
 int hvm_vmexit_cpuid(struct cpu_user_regs *regs, unsigned int inst_len);
@@ -546,12 +548,6 @@ static inline unsigned int hvm_get_insn_
             ? alternative_call(hvm_funcs.get_insn_bytes, v, buf) : 0);
 }
 
-static inline void hvm_set_info_guest(struct vcpu *v)
-{
-    if ( hvm_funcs.set_info_guest )
-        alternative_vcall(hvm_funcs.set_info_guest, v);
-}
-
 static inline void hvm_invalidate_regs_fields(struct cpu_user_regs *regs)
 {
 #ifndef NDEBUG
@@ -682,7 +678,6 @@ static inline bool altp2m_vcpu_emulate_v
  */
 int hvm_guest_x86_mode(struct vcpu *v);
 unsigned long hvm_get_shadow_gs_base(struct vcpu *v);
-void hvm_set_info_guest(struct vcpu *v);
 void hvm_cpuid_policy_changed(struct vcpu *v);
 void hvm_set_tsc_offset(struct vcpu *v, uint64_t offset, uint64_t at_tsc);
 bool hvm_get_guest_bndcfgs(struct vcpu *v, uint64_t *val);


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.