From patchwork Fri Jun 25 07:57:03 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sheng Yang X-Patchwork-Id: 108007 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter.kernel.org (8.14.4/8.14.3) with ESMTP id o5P7wnvg027367 for ; Fri, 25 Jun 2010 07:58:49 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751679Ab0FYH6m (ORCPT ); Fri, 25 Jun 2010 03:58:42 -0400 Received: from mga14.intel.com ([143.182.124.37]:39148 "EHLO mga14.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751474Ab0FYH6k (ORCPT ); Fri, 25 Jun 2010 03:58:40 -0400 Received: from azsmga001.ch.intel.com ([10.2.17.19]) by azsmga102.ch.intel.com with ESMTP; 25 Jun 2010 00:58:40 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="4.53,480,1272870000"; d="scan'208";a="292920780" Received: from syang10-desktop.sh.intel.com (HELO syang10-desktop) ([10.239.36.189]) by azsmga001.ch.intel.com with ESMTP; 25 Jun 2010 00:58:18 -0700 Received: from yasker by syang10-desktop with local (Exim 4.71) (envelope-from ) id 1OS3ma-0006GK-Ci; Fri, 25 Jun 2010 15:57:04 +0800 From: Sheng Yang To: Avi Kivity , Marcelo Tosatti Cc: kvm@vger.kernel.org, Sheng Yang , "Yaozu (Eddie) Dong" Subject: [PATCH] KVM: VMX: Execute WBINVD to keep data consistency with assigned devices Date: Fri, 25 Jun 2010 15:57:03 +0800 Message-Id: <1277452623-24046-1-git-send-email-sheng@linux.intel.com> X-Mailer: git-send-email 1.7.0.4 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter.kernel.org [140.211.167.41]); Fri, 25 Jun 2010 07:58:49 +0000 (UTC) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index a57cdea..1c392c9 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -514,6 +514,8 @@ struct kvm_x86_ops { void (*set_supported_cpuid)(u32 func, struct kvm_cpuid_entry2 *entry); + void (*execute_wbinvd)(struct kvm_vcpu *vcpu); + const struct trace_print_flags *exit_reasons_str; }; @@ -571,6 +573,7 @@ void kvm_emulate_cpuid(struct kvm_vcpu *vcpu); int kvm_emulate_halt(struct kvm_vcpu *vcpu); int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address); int emulate_clts(struct kvm_vcpu *vcpu); +int emulate_wbinvd(struct kvm_vcpu *vcpu); void kvm_get_segment(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg); int kvm_load_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector, int seg); diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index abb8cec..085dcb7 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -3138,8 +3138,11 @@ twobyte_insn: emulate_clts(ctxt->vcpu); c->dst.type = OP_NONE; break; - case 0x08: /* invd */ case 0x09: /* wbinvd */ + emulate_wbinvd(ctxt->vcpu); + c->dst.type = OP_NONE; + break; + case 0x08: /* invd */ case 0x0d: /* GrpP (prefetch) */ case 0x18: /* Grp16 (prefetch/nop) */ c->dst.type = OP_NONE; diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 587b99d..6929da1 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -3424,6 +3424,10 @@ static bool svm_rdtscp_supported(void) return false; } +static void svm_execute_wbinvd(struct kvm_vcpu *vcpu) +{ +} + static void svm_fpu_deactivate(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); @@ -3508,6 +3512,8 @@ static struct kvm_x86_ops svm_x86_ops = { .rdtscp_supported = svm_rdtscp_supported, .set_supported_cpuid = svm_set_supported_cpuid, + + .execute_wbinvd = svm_execute_wbinvd, }; static int __init svm_init(void) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index e565689..063002c 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -412,6 +412,12 @@ static inline bool cpu_has_virtual_nmis(void) return vmcs_config.pin_based_exec_ctrl & PIN_BASED_VIRTUAL_NMIS; } +static inline bool cpu_has_wbinvd_exit(void) +{ + return vmcs_config.cpu_based_2nd_exec_ctrl & + SECONDARY_EXEC_WBINVD_EXITING; +} + static inline bool report_flexpriority(void) { return flexpriority_enabled; @@ -874,6 +880,11 @@ static void vmx_load_host_state(struct vcpu_vmx *vmx) preempt_enable(); } +static void wbinvd_ipi(void *opaque) +{ + wbinvd(); +} + /* * Switches to specified vcpu, until a matching vcpu_put(), but assumes * vcpu mutex is already taken. @@ -905,6 +916,12 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu) &per_cpu(vcpus_on_cpu, cpu)); local_irq_enable(); + /* Issue WBINVD in case guest has executed it */ + if (!cpu_has_wbinvd_exit() && vcpu->kvm->arch.iommu_domain && + vcpu->cpu != -1) + smp_call_function_single(vcpu->cpu, + wbinvd_ipi, NULL, 1); + vcpu->cpu = cpu; /* * Linux uses per-cpu TSS and GDT, so set these when switching @@ -3397,10 +3414,16 @@ static int handle_invlpg(struct kvm_vcpu *vcpu) return 1; } +static void vmx_execute_wbinvd(struct kvm_vcpu *vcpu) +{ + if (vcpu->kvm->arch.iommu_domain) + smp_call_function(wbinvd_ipi, NULL, 1); +} + static int handle_wbinvd(struct kvm_vcpu *vcpu) { skip_emulated_instruction(vcpu); - /* TODO: Add support for VT-d/pass-through device */ + vmx_execute_wbinvd(vcpu); return 1; } @@ -4350,6 +4373,8 @@ static struct kvm_x86_ops vmx_x86_ops = { .rdtscp_supported = vmx_rdtscp_supported, .set_supported_cpuid = vmx_set_supported_cpuid, + + .execute_wbinvd = vmx_execute_wbinvd, }; static int __init vmx_init(void) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index d0b9252..eba3a2b 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3650,6 +3650,12 @@ int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address) return X86EMUL_CONTINUE; } +int emulate_wbinvd(struct kvm_vcpu *vcpu) +{ + kvm_x86_ops->execute_wbinvd(vcpu); + return X86EMUL_CONTINUE; +} + int emulate_clts(struct kvm_vcpu *vcpu) { kvm_x86_ops->set_cr0(vcpu, kvm_read_cr0_bits(vcpu, ~X86_CR0_TS));