@@ -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 */
@@ -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)