From patchwork Tue Oct 13 16:06:48 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Kiszka X-Patchwork-Id: 53445 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 n9DGJhpw005889 for ; Tue, 13 Oct 2009 16:19:43 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933938AbZJMQJW (ORCPT ); Tue, 13 Oct 2009 12:09:22 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S933940AbZJMQJV (ORCPT ); Tue, 13 Oct 2009 12:09:21 -0400 Received: from goliath.siemens.de ([192.35.17.28]:15211 "EHLO goliath.siemens.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1760052AbZJMQJS (ORCPT ); Tue, 13 Oct 2009 12:09:18 -0400 Received: from mail3.siemens.de (localhost [127.0.0.1]) by goliath.siemens.de (8.12.11.20060308/8.12.11) with ESMTP id n9DG8SoH017608; Tue, 13 Oct 2009 18:08:28 +0200 Received: from [139.25.109.167] (mchn012c.ww002.siemens.net [139.25.109.167] (may be forged)) by mail3.siemens.de (8.12.11.20060308/8.12.11) with ESMTP id n9DG8SBG015665; Tue, 13 Oct 2009 18:08:28 +0200 From: Jan Kiszka Subject: [PATCH 3/4] KVM: x86: Add support for KVM_GET/SET_VCPU_STATE To: Avi Kivity , Marcelo Tosatti Cc: kvm@vger.kernel.org Date: Tue, 13 Oct 2009 18:06:48 +0200 Message-ID: <20091013160648.27006.44792.stgit@mchn012c.ww002.siemens.net> In-Reply-To: <20091013160647.27006.58598.stgit@mchn012c.ww002.siemens.net> References: <20091013160647.27006.58598.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/arch/x86/include/asm/kvm.h b/arch/x86/include/asm/kvm.h index f02e87a..1b184c3 100644 --- a/arch/x86/include/asm/kvm.h +++ b/arch/x86/include/asm/kvm.h @@ -150,7 +150,7 @@ struct kvm_msr_entry { /* for KVM_GET_MSRS and KVM_SET_MSRS */ struct kvm_msrs { __u32 nmsrs; /* number of msrs in entries */ - __u32 pad; + __u32 nprocessed; /* return value: successfully processed entries */ struct kvm_msr_entry entries[0]; }; @@ -251,4 +251,10 @@ struct kvm_reinject_control { __u8 pit_reinject; __u8 reserved[31]; }; + +/* for KVM_GET/SET_VCPU_STATE */ +#define KVM_X86_VCPU_MSRS 1000 +#define KVM_X86_VCPU_CPUID 1001 +#define KVM_X86_VCPU_LAPIC 1002 + #endif /* _ASM_X86_KVM_H */ diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 839b1c5..733e2d3 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1179,11 +1179,11 @@ static int __msr_io(struct kvm_vcpu *vcpu, struct kvm_msrs *msrs, static int msr_io(struct kvm_vcpu *vcpu, struct kvm_msrs __user *user_msrs, int (*do_msr)(struct kvm_vcpu *vcpu, unsigned index, u64 *data), - int writeback) + int writeback, int write_nprocessed) { struct kvm_msrs msrs; struct kvm_msr_entry *entries; - int r, n; + int r; unsigned size; r = -EFAULT; @@ -1204,15 +1204,22 @@ static int msr_io(struct kvm_vcpu *vcpu, struct kvm_msrs __user *user_msrs, if (copy_from_user(entries, user_msrs->entries, size)) goto out_free; - r = n = __msr_io(vcpu, &msrs, entries, do_msr); + r = __msr_io(vcpu, &msrs, entries, do_msr); if (r < 0) goto out_free; + msrs.nprocessed = r; + r = -EFAULT; + if (write_nprocessed && + copy_to_user(&user_msrs->nprocessed, &msrs.nprocessed, + sizeof(msrs.nprocessed))) + goto out_free; + if (writeback && copy_to_user(user_msrs->entries, entries, size)) goto out_free; - r = n; + r = msrs.nprocessed; out_free: vfree(entries); @@ -1785,55 +1792,36 @@ long kvm_arch_vcpu_ioctl(struct file *filp, { struct kvm_vcpu *vcpu = filp->private_data; void __user *argp = (void __user *)arg; + struct kvm_vcpu_substate substate; int r; - struct kvm_lapic_state *lapic = NULL; switch (ioctl) { - case KVM_GET_LAPIC: { - lapic = kzalloc(sizeof(struct kvm_lapic_state), GFP_KERNEL); - - r = -ENOMEM; - if (!lapic) - goto out; - r = kvm_vcpu_ioctl_get_lapic(vcpu, lapic); - if (r) - goto out; - r = -EFAULT; - if (copy_to_user(argp, lapic, sizeof(struct kvm_lapic_state))) - goto out; - r = 0; + case KVM_GET_LAPIC: + substate.type = KVM_X86_VCPU_LAPIC; + substate.offset = 0; + r = kvm_arch_vcpu_get_substate(vcpu, argp, &substate); break; - } - case KVM_SET_LAPIC: { - lapic = kmalloc(sizeof(struct kvm_lapic_state), GFP_KERNEL); - r = -ENOMEM; - if (!lapic) - goto out; - r = -EFAULT; - if (copy_from_user(lapic, argp, sizeof(struct kvm_lapic_state))) - goto out; - r = kvm_vcpu_ioctl_set_lapic(vcpu, lapic); - if (r) - goto out; - r = 0; + case KVM_SET_LAPIC: + substate.type = KVM_X86_VCPU_LAPIC; + substate.offset = 0; + r = kvm_arch_vcpu_set_substate(vcpu, argp, &substate); break; - } case KVM_INTERRUPT: { struct kvm_interrupt irq; r = -EFAULT; if (copy_from_user(&irq, argp, sizeof irq)) - goto out; + break; r = kvm_vcpu_ioctl_interrupt(vcpu, &irq); if (r) - goto out; + break; r = 0; break; } case KVM_NMI: { r = kvm_vcpu_ioctl_nmi(vcpu); if (r) - goto out; + break; r = 0; break; } @@ -1843,60 +1831,40 @@ long kvm_arch_vcpu_ioctl(struct file *filp, r = -EFAULT; if (copy_from_user(&cpuid, cpuid_arg, sizeof cpuid)) - goto out; + break; r = kvm_vcpu_ioctl_set_cpuid(vcpu, &cpuid, cpuid_arg->entries); if (r) - goto out; + break; break; } - case KVM_SET_CPUID2: { - struct kvm_cpuid2 __user *cpuid_arg = argp; - struct kvm_cpuid2 cpuid; - - r = -EFAULT; - if (copy_from_user(&cpuid, cpuid_arg, sizeof cpuid)) - goto out; - r = kvm_vcpu_ioctl_set_cpuid2(vcpu, &cpuid, - cpuid_arg->entries); - if (r) - goto out; + case KVM_GET_CPUID2: + substate.type = KVM_X86_VCPU_CPUID; + substate.offset = 0; + r = kvm_arch_vcpu_get_substate(vcpu, argp, &substate); break; - } - case KVM_GET_CPUID2: { - struct kvm_cpuid2 __user *cpuid_arg = argp; - struct kvm_cpuid2 cpuid; - - r = -EFAULT; - if (copy_from_user(&cpuid, cpuid_arg, sizeof cpuid)) - goto out; - r = kvm_vcpu_ioctl_get_cpuid2(vcpu, &cpuid, - cpuid_arg->entries); - if (r) - goto out; - r = -EFAULT; - if (copy_to_user(cpuid_arg, &cpuid, sizeof cpuid)) - goto out; - r = 0; + case KVM_SET_CPUID2: + substate.type = KVM_X86_VCPU_CPUID; + substate.offset = 0; + r = kvm_arch_vcpu_set_substate(vcpu, argp, &substate); break; - } case KVM_GET_MSRS: - r = msr_io(vcpu, argp, kvm_get_msr, 1); + r = msr_io(vcpu, argp, kvm_get_msr, 1, 0); break; case KVM_SET_MSRS: - r = msr_io(vcpu, argp, do_set_msr, 0); + r = msr_io(vcpu, argp, do_set_msr, 0, 0); break; case KVM_TPR_ACCESS_REPORTING: { struct kvm_tpr_access_ctl tac; r = -EFAULT; if (copy_from_user(&tac, argp, sizeof tac)) - goto out; + break; r = vcpu_ioctl_tpr_access_reporting(vcpu, &tac); if (r) - goto out; + break; r = -EFAULT; if (copy_to_user(argp, &tac, sizeof tac)) - goto out; + break; r = 0; break; }; @@ -1905,10 +1873,10 @@ long kvm_arch_vcpu_ioctl(struct file *filp, r = -EINVAL; if (!irqchip_in_kernel(vcpu->kvm)) - goto out; + break; r = -EFAULT; if (copy_from_user(&va, argp, sizeof va)) - goto out; + break; r = 0; kvm_lapic_set_vapic_addr(vcpu, va.vapic_addr); break; @@ -1918,7 +1886,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp, r = -EFAULT; if (copy_from_user(&mcg_cap, argp, sizeof mcg_cap)) - goto out; + break; r = kvm_vcpu_ioctl_x86_setup_mce(vcpu, mcg_cap); break; } @@ -1927,15 +1895,13 @@ long kvm_arch_vcpu_ioctl(struct file *filp, r = -EFAULT; if (copy_from_user(&mce, argp, sizeof mce)) - goto out; + break; r = kvm_vcpu_ioctl_x86_set_mce(vcpu, &mce); break; } default: r = -EINVAL; } -out: - kfree(lapic); return r; } @@ -4665,13 +4631,100 @@ EXPORT_SYMBOL_GPL(kvm_put_guest_fpu); int kvm_arch_vcpu_get_substate(struct kvm_vcpu *vcpu, uint8_t __user *arg_base, struct kvm_vcpu_substate *substate) { - return -EINVAL; + void __user *argp = (void __user *)arg_base + substate->offset; + int r; + + switch (substate->type) { + case KVM_X86_VCPU_MSRS: + r = msr_io(vcpu, argp, kvm_get_msr, 1, 1); + break; + case KVM_X86_VCPU_CPUID: { + struct kvm_cpuid2 __user *cpuid_arg = argp; + struct kvm_cpuid2 cpuid; + + r = -EFAULT; + if (copy_from_user(&cpuid, cpuid_arg, + sizeof(struct kvm_cpuid2))) + break; + r = kvm_vcpu_ioctl_get_cpuid2(vcpu, &cpuid, + cpuid_arg->entries); + if (r) + break; + r = -EFAULT; + if (copy_to_user(cpuid_arg, &cpuid, sizeof(struct kvm_cpuid2))) + break; + r = 0; + break; + } + case KVM_X86_VCPU_LAPIC: { + struct kvm_lapic_state *lapic; + + lapic = kzalloc(sizeof(struct kvm_lapic_state), GFP_KERNEL); + r = -ENOMEM; + if (!lapic) + break; + r = kvm_vcpu_ioctl_get_lapic(vcpu, lapic); + if (r) + goto out_free_lapic; + r = -EFAULT; + if (copy_to_user(argp, lapic, sizeof(struct kvm_lapic_state))) + goto out_free_lapic; + r = 0; +out_free_lapic: + kfree(lapic); + break; + } + default: + r = -EINVAL; + } + return r; } int kvm_arch_vcpu_set_substate(struct kvm_vcpu *vcpu, uint8_t __user *arg_base, struct kvm_vcpu_substate *substate) { - return -EINVAL; + void __user *argp = (void __user *)arg_base + substate->offset; + int r; + + switch (substate->type) { + case KVM_X86_VCPU_MSRS: + r = msr_io(vcpu, argp, do_set_msr, 0, 1); + break; + case KVM_X86_VCPU_CPUID: { + struct kvm_cpuid2 __user *cpuid_arg = argp; + struct kvm_cpuid2 cpuid; + + r = -EFAULT; + if (copy_from_user(&cpuid, cpuid_arg, + sizeof(struct kvm_cpuid2))) + break; + r = kvm_vcpu_ioctl_set_cpuid2(vcpu, &cpuid, + cpuid_arg->entries); + break; + } + case KVM_X86_VCPU_LAPIC: { + struct kvm_lapic_state *lapic; + + lapic = kmalloc(sizeof(struct kvm_lapic_state), GFP_KERNEL); + r = -ENOMEM; + if (!lapic) + break; + r = -EFAULT; + if (copy_from_user(lapic, argp, + sizeof(struct kvm_lapic_state))) + goto out_free_lapic; + r = kvm_vcpu_ioctl_set_lapic(vcpu, lapic); + if (r) + goto out_free_lapic; + r = 0; +out_free_lapic: + kfree(lapic); + break; + } + default: + r = -EINVAL; + } + return r; } void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu)