diff mbox

[3/4] KVM: x86: Add support for KVM_GET/SET_VCPU_STATE

Message ID 20091013160648.27006.44792.stgit@mchn012c.ww002.siemens.net (mailing list archive)
State New, archived
Headers show

Commit Message

Jan Kiszka Oct. 13, 2009, 4:06 p.m. UTC
None
diff mbox

Patch

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)