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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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>
---

 arch/x86/include/asm/kvm.h |    8 +-
 arch/x86/kvm/x86.c         |  209 ++++++++++++++++++++++++++++----------------
 2 files changed, 138 insertions(+), 79 deletions(-)

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)

--
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

[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux