From: Roger Pau Monné Date: Tue, 24 Jun 2014 08:15:29 +0000 (+0200) Subject: x86: fix reboot/shutdown with running HVM guests X-Git-Tag: 4.2.5-rc2~14 X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=aeb9d2c7cc13bddd416c4aae7e2c10710b51fc7f;p=xen.git x86: fix reboot/shutdown with running HVM guests If there's a guest using VMX/SVM when the hypervisor shuts down, it can lead to the following crash due to VMX/SVM functions being called after hvm_cpu_down has been called. In order to prevent that, check in {svm/vmx}_ctxt_switch_from that the cpu virtualization extensions are still enabled. (XEN) Domain 0 shutdown: rebooting machine. (XEN) Assertion 'read_cr0() & X86_CR0_TS' failed at vmx.c:644 (XEN) ----[ Xen-4.5-unstable x86_64 debug=y Tainted: C ]---- (XEN) CPU: 0 (XEN) RIP: e008:[] vmx_ctxt_switch_from+0x1e/0x14c ... (XEN) Xen call trace: (XEN) [] vmx_ctxt_switch_from+0x1e/0x14c (XEN) [] __context_switch+0x127/0x462 (XEN) [] __sync_local_execstate+0x6a/0x8b (XEN) [] sync_local_execstate+0x9/0xb (XEN) [] map_domain_page+0x88/0x4de (XEN) [] map_vtd_domain_page+0xd/0xf (XEN) [] io_apic_read_remap_rte+0x158/0x29f (XEN) [] iommu_read_apic_from_ire+0x27/0x29 (XEN) [] io_apic_read+0x17/0x65 (XEN) [] __ioapic_read_entry+0x38/0x61 (XEN) [] clear_IO_APIC_pin+0x1a/0xf3 (XEN) [] clear_IO_APIC+0x2d/0x60 (XEN) [] disable_IO_APIC+0xd/0x81 (XEN) [] smp_send_stop+0x58/0x68 (XEN) [] machine_restart+0x80/0x20a (XEN) [] __machine_restart+0xb/0xf (XEN) [] smp_call_function_interrupt+0x99/0xc0 (XEN) [] call_function_interrupt+0x33/0x43 (XEN) [] do_IRQ+0x9e/0x63a (XEN) [] common_interrupt+0x5f/0x70 (XEN) [] mwait_idle+0x29c/0x2f7 (XEN) [] idle_loop+0x58/0x76 (XEN) (XEN) (XEN) **************************************** (XEN) Panic on CPU 0: (XEN) Assertion 'read_cr0() & X86_CR0_TS' failed at vmx.c:644 (XEN) **************************************** Suggested-by: Jan Beulich Signed-off-by: Roger Pau Monné Reviewed-by: Boris Ostrovsky master commit: 39ede234d1fd683430ffb1784d6d35b096f16457 master date: 2014-06-05 17:53:35 +0200 --- diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c index cbdc58a564..0d999b8a25 100644 --- a/xen/arch/x86/hvm/svm/svm.c +++ b/xen/arch/x86/hvm/svm/svm.c @@ -865,6 +865,14 @@ static void svm_ctxt_switch_from(struct vcpu *v) { int cpu = smp_processor_id(); + /* + * Return early if trying to do a context switch without SVM enabled, + * this can happen when the hypervisor shuts down with HVM guests + * still running. + */ + if ( unlikely((read_efer() & EFER_SVME) == 0) ) + return; + svm_fpu_leave(v); svm_save_dr(v); diff --git a/xen/arch/x86/hvm/vmx/vmcs.c b/xen/arch/x86/hvm/vmx/vmcs.c index b09e8d7965..0217328dec 100644 --- a/xen/arch/x86/hvm/vmx/vmcs.c +++ b/xen/arch/x86/hvm/vmx/vmcs.c @@ -71,7 +71,7 @@ bool_t cpu_has_vmx_ins_outs_instr_info __read_mostly; static DEFINE_PER_CPU_READ_MOSTLY(struct vmcs_struct *, vmxon_region); static DEFINE_PER_CPU(struct vmcs_struct *, current_vmcs); static DEFINE_PER_CPU(struct list_head, active_vmcs_list); -static DEFINE_PER_CPU(bool_t, vmxon); +DEFINE_PER_CPU(bool_t, vmxon); static u32 vmcs_revision_id __read_mostly; diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index ec85b8d135..946dee3f1a 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -659,6 +659,14 @@ static void vmx_fpu_leave(struct vcpu *v) static void vmx_ctxt_switch_from(struct vcpu *v) { + /* + * Return early if trying to do a context switch without VMX enabled, + * this can happen when the hypervisor shuts down with HVM guests + * still running. + */ + if ( unlikely(!this_cpu(vmxon)) ) + return; + vmx_fpu_leave(v); vmx_save_guest_msrs(v); vmx_restore_host_msrs(); diff --git a/xen/include/asm-x86/hvm/vmx/vmcs.h b/xen/include/asm-x86/hvm/vmx/vmcs.h index ad11057a38..067982ab80 100644 --- a/xen/include/asm-x86/hvm/vmx/vmcs.h +++ b/xen/include/asm-x86/hvm/vmx/vmcs.h @@ -398,6 +398,8 @@ int vmx_add_guest_msr(u32 msr); int vmx_add_host_load_msr(u32 msr); void vmx_vmcs_switch(struct vmcs_struct *from, struct vmcs_struct *to); +DECLARE_PER_CPU(bool_t, vmxon); + #endif /* ASM_X86_HVM_VMX_VMCS_H__ */ /*