Add support for getting/setting MSRs, CPUID tree, and the LACPIC via the new VCPU state interface. Also in this case we convert the existing IOCTLs to use the new infrastructure internally. The MSR interface has to be extended to pass back the number of processed MSRs via the header structure instead of the return code as the latter is not available with the new IOCTL. The semantic of the original KVM_GET/SET_MSRS is not affected by this change. Signed-off-by: Jan Kiszka <jan.kiszka@xxxxxxxxxxx> --- Documentation/kvm/api.txt | 18 ++++ arch/x86/include/asm/kvm.h | 8 +- arch/x86/kvm/x86.c | 209 ++++++++++++++++++++++++++++---------------- 3 files changed, 156 insertions(+), 79 deletions(-) diff --git a/Documentation/kvm/api.txt b/Documentation/kvm/api.txt index 7c0be8d..bee5bbd 100644 --- a/Documentation/kvm/api.txt +++ b/Documentation/kvm/api.txt @@ -830,3 +830,21 @@ Deprecates: KVM_GET/SET_MP_STATE struct kvm_mp_state { __u32 mp_state; /* KVM_MP_STATE_* */ }; + +6.5 KVM_X86_VCPU_STATE_MSRS + +Architectures: x86 +Payload: struct kvm_msrs (see KVM_GET_MSRS) +Deprecates: KVM_GET/SET_MSRS + +6.6 KVM_X86_VCPU_STATE_CPUID + +Architectures: x86 +Payload: struct kvm_cpuid2 +Deprecates: KVM_GET/SET_CPUID2 + +6.7 KVM_X86_VCPU_STATE_LAPIC + +Architectures: x86 +Payload: struct kvm_lapic +Deprecates: KVM_GET/SET_LAPIC diff --git a/arch/x86/include/asm/kvm.h b/arch/x86/include/asm/kvm.h index f02e87a..326615a 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_STATE_MSRS 1000 +#define KVM_X86_VCPU_STATE_CPUID 1001 +#define KVM_X86_VCPU_STATE_LAPIC 1002 + #endif /* _ASM_X86_KVM_H */ diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 685215b..46fad88 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1182,11 +1182,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; @@ -1207,15 +1207,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); @@ -1792,55 +1799,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_STATE_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_STATE_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; } @@ -1850,60 +1838,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_STATE_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_STATE_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; }; @@ -1912,10 +1880,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; @@ -1925,7 +1893,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; } @@ -1934,15 +1902,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; } @@ -4677,13 +4643,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_STATE_MSRS: + r = msr_io(vcpu, argp, kvm_get_msr, 1, 1); + break; + case KVM_X86_VCPU_STATE_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_STATE_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_STATE_MSRS: + r = msr_io(vcpu, argp, do_set_msr, 0, 1); + break; + case KVM_X86_VCPU_STATE_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_STATE_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) -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html