From patchwork Thu Oct 15 17:05:36 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Kiszka X-Patchwork-Id: 54062 Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id n9FH9jCa028342 for ; Thu, 15 Oct 2009 17:09:46 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1758617AbZJORHu (ORCPT ); Thu, 15 Oct 2009 13:07:50 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1759463AbZJORHt (ORCPT ); Thu, 15 Oct 2009 13:07:49 -0400 Received: from thoth.sbs.de ([192.35.17.2]:24511 "EHLO thoth.sbs.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1758617AbZJORHr (ORCPT ); Thu, 15 Oct 2009 13:07:47 -0400 Received: from mail3.siemens.de (localhost [127.0.0.1]) by thoth.sbs.de (8.12.11.20060308/8.12.11) with ESMTP id n9FH6uEO005931; Thu, 15 Oct 2009 19:06:57 +0200 Received: from [139.25.109.167] (mchn012c.mchp.siemens.de [139.25.109.167] (may be forged)) by mail3.siemens.de (8.12.11.20060308/8.12.11) with ESMTP id n9FH6uso026322; Thu, 15 Oct 2009 19:06:56 +0200 From: Jan Kiszka Subject: [PATCH v2 4/4] KVM: x86: Add VCPU substate for NMI states To: Avi Kivity , Marcelo Tosatti Cc: kvm@vger.kernel.org Date: Thu, 15 Oct 2009 19:05:36 +0200 Message-ID: <20091015170536.5076.56790.stgit@mchn012c.ww002.siemens.net> In-Reply-To: <20091015170535.5076.91206.stgit@mchn012c.ww002.siemens.net> References: <20091015170535.5076.91206.stgit@mchn012c.ww002.siemens.net> User-Agent: StGIT/0.14.3 MIME-Version: 1.0 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org diff --git a/Documentation/kvm/api.txt b/Documentation/kvm/api.txt index bee5bbd..e483edb 100644 --- a/Documentation/kvm/api.txt +++ b/Documentation/kvm/api.txt @@ -848,3 +848,15 @@ Deprecates: KVM_GET/SET_CPUID2 Architectures: x86 Payload: struct kvm_lapic Deprecates: KVM_GET/SET_LAPIC + +6.8 KVM_X86_VCPU_STATE_NMI + +Architectures: x86 +Payload: struct kvm_nmi_state +Deprecates: - + +struct kvm_nmi_state { + __u8 pending; + __u8 masked; + __u8 pad1[6]; +}; diff --git a/arch/x86/include/asm/kvm.h b/arch/x86/include/asm/kvm.h index 326615a..6ad4448 100644 --- a/arch/x86/include/asm/kvm.h +++ b/arch/x86/include/asm/kvm.h @@ -256,5 +256,12 @@ struct kvm_reinject_control { #define KVM_X86_VCPU_STATE_MSRS 1000 #define KVM_X86_VCPU_STATE_CPUID 1001 #define KVM_X86_VCPU_STATE_LAPIC 1002 +#define KVM_X86_VCPU_STATE_NMI 1003 + +struct kvm_nmi_state { + __u8 pending; + __u8 masked; + __u8 pad1[6]; +}; #endif /* _ASM_X86_KVM_H */ diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 179a919..b6b2db4 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -513,6 +513,8 @@ struct kvm_x86_ops { unsigned char *hypercall_addr); void (*set_irq)(struct kvm_vcpu *vcpu); void (*set_nmi)(struct kvm_vcpu *vcpu); + bool (*get_nmi_mask)(struct kvm_vcpu *vcpu); + void (*set_nmi_mask)(struct kvm_vcpu *vcpu, bool masked); void (*queue_exception)(struct kvm_vcpu *vcpu, unsigned nr, bool has_error_code, u32 error_code); int (*interrupt_allowed)(struct kvm_vcpu *vcpu); diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 170b2d9..a16ee6e 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -2498,6 +2498,26 @@ static int svm_nmi_allowed(struct kvm_vcpu *vcpu) !(svm->vcpu.arch.hflags & HF_NMI_MASK); } +static bool svm_get_nmi_mask(struct kvm_vcpu *vcpu) +{ + struct vcpu_svm *svm = to_svm(vcpu); + + return !!(svm->vcpu.arch.hflags & HF_NMI_MASK); +} + +static void svm_set_nmi_mask(struct kvm_vcpu *vcpu, bool masked) +{ + struct vcpu_svm *svm = to_svm(vcpu); + + if (masked) { + svm->vcpu.arch.hflags |= HF_NMI_MASK; + svm->vmcb->control.intercept |= (1UL << INTERCEPT_IRET); + } else { + svm->vcpu.arch.hflags &= ~HF_NMI_MASK; + svm->vmcb->control.intercept &= ~(1UL << INTERCEPT_IRET); + } +} + static int svm_interrupt_allowed(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); @@ -2945,6 +2965,8 @@ static struct kvm_x86_ops svm_x86_ops = { .queue_exception = svm_queue_exception, .interrupt_allowed = svm_interrupt_allowed, .nmi_allowed = svm_nmi_allowed, + .get_nmi_mask = svm_get_nmi_mask, + .set_nmi_mask = svm_set_nmi_mask, .enable_nmi_window = enable_nmi_window, .enable_irq_window = enable_irq_window, .update_cr8_intercept = update_cr8_intercept, diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 364263a..6e032e4 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -2655,6 +2655,34 @@ static int vmx_nmi_allowed(struct kvm_vcpu *vcpu) GUEST_INTR_STATE_NMI)); } +static bool vmx_get_nmi_mask(struct kvm_vcpu *vcpu) +{ + if (!cpu_has_virtual_nmis()) + return to_vmx(vcpu)->soft_vnmi_blocked; + else + return !!(vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & + GUEST_INTR_STATE_NMI); +} + +static void vmx_set_nmi_mask(struct kvm_vcpu *vcpu, bool masked) +{ + struct vcpu_vmx *vmx = to_vmx(vcpu); + + if (!cpu_has_virtual_nmis()) { + if (vmx->soft_vnmi_blocked != masked) { + vmx->soft_vnmi_blocked = masked; + vmx->vnmi_blocked_time = 0; + } + } else { + if (masked) + vmcs_set_bits(GUEST_INTERRUPTIBILITY_INFO, + GUEST_INTR_STATE_NMI); + else + vmcs_clear_bits(GUEST_INTERRUPTIBILITY_INFO, + GUEST_INTR_STATE_NMI); + } +} + static int vmx_interrupt_allowed(struct kvm_vcpu *vcpu) { return (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) && @@ -4006,6 +4034,8 @@ static struct kvm_x86_ops vmx_x86_ops = { .queue_exception = vmx_queue_exception, .interrupt_allowed = vmx_interrupt_allowed, .nmi_allowed = vmx_nmi_allowed, + .get_nmi_mask = vmx_get_nmi_mask, + .set_nmi_mask = vmx_set_nmi_mask, .enable_nmi_window = enable_nmi_window, .enable_irq_window = enable_irq_window, .update_cr8_intercept = update_cr8_intercept, diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 46fad88..e7ce505 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -4686,6 +4686,19 @@ out_free_lapic: kfree(lapic); break; } + case KVM_X86_VCPU_STATE_NMI: { + struct kvm_nmi_state nmi; + + vcpu_load(vcpu); + nmi.pending = vcpu->arch.nmi_pending; + nmi.masked = kvm_x86_ops->get_nmi_mask(vcpu); + vcpu_put(vcpu); + r = -EFAULT; + if (copy_to_user(argp, &nmi, sizeof(struct kvm_nmi_state))) + break; + r = 0; + break; + } default: r = -EINVAL; } @@ -4733,6 +4746,19 @@ out_free_lapic: kfree(lapic); break; } + case KVM_X86_VCPU_STATE_NMI: { + struct kvm_nmi_state nmi; + + r = -EFAULT; + if (copy_from_user(&nmi, argp, sizeof(struct kvm_nmi_state))) + break; + vcpu_load(vcpu); + vcpu->arch.nmi_pending = nmi.pending; + kvm_x86_ops->set_nmi_mask(vcpu, nmi.masked); + vcpu_put(vcpu); + r = 0; + break; + } default: r = -EINVAL; }