]> xenbits.xensource.com Git - xen.git/commitdiff
x86/HVM: cancel emulation when register state got altered
authorJan Beulich <jbeulich@suse.com>
Thu, 23 Apr 2020 07:51:18 +0000 (09:51 +0200)
committerJan Beulich <jbeulich@suse.com>
Thu, 23 Apr 2020 07:51:18 +0000 (09:51 +0200)
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@citrix.com>
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Paul Durrant <pdurrant@amzn.com>
xen/arch/x86/domctl.c
xen/arch/x86/hvm/domain.c
xen/arch/x86/hvm/emulate.c
xen/arch/x86/hvm/hvm.c
xen/arch/x86/hvm/vlapic.c
xen/include/asm-x86/hvm/emulate.h
xen/include/asm-x86/hvm/hvm.h

index add70126b9a119a59b181d42a19efb5508ad42cd..03dffa5ecf0c538d673907cf6ef97fed6705880b 100644 (file)
@@ -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);
             }
 
index 5d5a746a25d47302f8fad9670b81c0eadf86f7d7..8e3375265cb1113f7751c517f0e536641755bae8 100644 (file)
@@ -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 *v, const vcpu_hvm_context_t *ctx)
 
     paging_update_paging_modes(v);
 
+    hvmemul_cancel(v);
+
     v->is_initialised = 1;
     set_bit(_VPF_down, &v->pause_flags);
 
index d717277b2fe72b5365efce8f7bcc0eeaca117b3c..a4185c68cb30bdebb22add5018ad1ca3abe82c4a 100644 (file)
@@ -121,6 +121,23 @@ static const struct hvm_io_handler ioreq_server_handler = {
     .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)
index 45959d34126918f4de5bbd6b90d1582d9e89c050..34b39e27df2244292bdc7f75b3a164eff54de44a 100644 (file)
@@ -478,6 +478,14 @@ u64 hvm_get_guest_tsc_fixed(struct vcpu *v, uint64_t at_tsc)
     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);
@@ -1163,6 +1171,8 @@ static int hvm_load_cpu_ctxt(struct domain *d, hvm_domain_context_t *h)
     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);
index 26726a4312ab3afb1ea29d54268815bf14b5f115..7b5c6330339fd982023c9d7c2cb8cf91d2f158a7 100644 (file)
@@ -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 vcpu *target, uint32_t icr)
         BUG();
     }
 
+    hvmemul_cancel(target);
+
     vcpu_unpause(target);
 }
 
index 2bdddef730f2872a8b0982e64c9fc972adb4ecb1..a2ad7ff1aaf24818a913b5b41495845d629aed79 100644 (file)
@@ -77,6 +77,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);
index f283c7d187c8a5c3dfe578255180a815224b9125..1eb377dd8219011505ef92734698aacbff91290f 100644 (file)
@@ -277,6 +277,8 @@ void hvm_get_segment_register(struct vcpu *v, enum x86_segment seg,
 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);
@@ -545,12 +547,6 @@ static inline unsigned int hvm_get_insn_bytes(struct vcpu *v, uint8_t *buf)
             ? 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
@@ -681,7 +677,6 @@ static inline bool altp2m_vcpu_emulate_ve(struct vcpu *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);