All of lore.kernel.org
 help / color / mirror / Atom feed
From: Rusty Russell <rusty.russell@linaro.org>
To: Rusty Russell <rusty.russell@linaro.org>,
	Avi Kivity <avi@redhat.com>,
	Christoffer Dall <c.dall@virtualopensystems.com>,
	Alexander Graf <agraf@suse.de>,
	Peter Maydell <peter.maydell@linaro.org>
Cc: kvmarm@lists.cs.columbia.edu, kvm-devel <kvm@vger.kernel.org>
Subject: [RFC 2/5] KVM: ARM: use KVM_SET_ONE_REG/KVM_GET_ONE_REG.
Date: Wed, 29 Aug 2012 09:16:37 +0930	[thread overview]
Message-ID: <87y5ky8tr6.fsf@rustcorp.com.au> (raw)
In-Reply-To: <877gsia8rm.fsf@rustcorp.com.au>

Instead of overloading x86's KVM_GET_MSRS/KVM_SET_MSRS.  The only basic
difference is that the ids are 64 bit.

Signed-off-by: Rusty Russell <rusty.russell@linaro.org>

diff --git a/arch/arm/include/asm/kvm.h b/arch/arm/include/asm/kvm.h
index d040a2a..9838456 100644
--- a/arch/arm/include/asm/kvm.h
+++ b/arch/arm/include/asm/kvm.h
@@ -85,35 +85,21 @@ struct kvm_sync_regs {
 struct kvm_arch_memory_slot {
 };
 
-/* Based on x86, but we use KVM_GET_VCPU_MSR_INDEX_LIST. */
-struct kvm_msr_entry {
-	__u32 index;
-	__u32 reserved;
-	__u64 data;
-};
-
-/* for KVM_GET_MSRS and KVM_SET_MSRS */
-struct kvm_msrs {
-	__u32 nmsrs; /* number of msrs in entries */
-	__u32 pad;
-
-	struct kvm_msr_entry entries[0];
-};
-
 /* for KVM_VCPU_GET_MSR_INDEX_LIST */
 struct kvm_msr_list {
-	__u32 nmsrs; /* number of msrs in entries */
-	__u32 indices[0];
+	__u64 nmsrs; /* number of msrs in entries */
+	__u64 indices[0];
 };
 
-/* If you need to interpret the index values, here's the key. */
-#define KVM_ARM_MSR_COPROC_MASK		0xFFFF0000
-#define KVM_ARM_MSR_64_BIT_MASK		0x00008000
-#define KVM_ARM_MSR_64_OPC1_MASK	0x000000F0
-#define KVM_ARM_MSR_64_CRM_MASK		0x0000000F
-#define KVM_ARM_MSR_32_CRM_MASK		0x0000000F
-#define KVM_ARM_MSR_32_OPC2_MASK	0x00000070
-#define KVM_ARM_MSR_32_CRN_MASK		0x00000780
-#define KVM_ARM_MSR_32_OPC1_MASK	0x00003800
+/* If you need to interpret the index values, here are the bit offsets. */
+#define KVM_REG_ARM_COPROC_START	16	/* Mask: 0xFFFF0000 */
+#define KVM_REG_ARM_32_OPC2_START	0	/* Mask: 0x00000007 */
+#define KVM_REG_ARM_32_OPC2_LEN		3
+#define KVM_REG_ARM_OPC1_START		3	/* Mask: 0x00000078 */
+#define KVM_REG_ARM_OPC1_LEN		4
+#define KVM_REG_ARM_CRM_START		7	/* Mask: 0x00000780 */
+#define KVM_REG_ARM_CRM_LEN		4
+#define KVM_REG_ARM_32_CRN_START	11	/* Mask: 0x00007800 */
+#define KVM_REG_ARM_32_CRN_LEN		4
 
 #endif /* __ARM_KVM_H__ */
diff --git a/arch/arm/include/asm/kvm_coproc.h b/arch/arm/include/asm/kvm_coproc.h
index 894574c..899b3d3 100644
--- a/arch/arm/include/asm/kvm_coproc.h
+++ b/arch/arm/include/asm/kvm_coproc.h
@@ -28,11 +28,7 @@ int kvm_handle_cp14_access(struct kvm_vcpu *vcpu, struct kvm_run *run);
 int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run);
 int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run);
 
-int kvm_arm_get_msrs(struct kvm_vcpu *vcpu,
-		     struct kvm_msr_entry __user *entries, u32 num);
-int kvm_arm_set_msrs(struct kvm_vcpu *vcpu,
-		     struct kvm_msr_entry __user *entries, u32 num);
 unsigned long kvm_arm_num_guest_msrs(struct kvm_vcpu *vcpu);
-int kvm_arm_copy_msrindices(struct kvm_vcpu *vcpu, u32 __user *uindices);
+int kvm_arm_copy_msrindices(struct kvm_vcpu *vcpu, u64 __user *uindices);
 void kvm_coproc_table_init(void);
 #endif /* __ARM_KVM_COPROC_H__ */
diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index 1c0fa75..7548c95 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -25,6 +25,7 @@
 #define KVM_MEMORY_SLOTS 32
 #define KVM_PRIVATE_MEM_SLOTS 4
 #define KVM_COALESCED_MMIO_PAGE_OFFSET 1
+#define KVM_HAVE_ONE_REG
 
 #define NUM_FEATURES 0
 
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index 4248aa1..55a2995 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -726,20 +726,6 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
 			return -E2BIG;
 		return kvm_arm_copy_msrindices(vcpu, user_msr_list->indices);
 	}
-	case KVM_GET_MSRS: {
-		struct kvm_msrs msrs;
-		struct kvm_msrs __user *umsrs = argp;
-		if (copy_from_user(&msrs, umsrs, sizeof(msrs)) != 0)
-			return -EFAULT;
-		return kvm_arm_get_msrs(vcpu, umsrs->entries, msrs.nmsrs);
-	}
-	case KVM_SET_MSRS: {
-		struct kvm_msrs msrs;
-		struct kvm_msrs __user *umsrs = argp;
-		if (copy_from_user(&msrs, umsrs, sizeof(msrs)) != 0)
-			return -EFAULT;
-		return kvm_arm_set_msrs(vcpu, umsrs->entries, msrs.nmsrs);
-	}
 	default:
 		return -EINVAL;
 	}
diff --git a/arch/arm/kvm/coproc.c b/arch/arm/kvm/coproc.c
index 824e5a3..99de71b 100644
--- a/arch/arm/kvm/coproc.c
+++ b/arch/arm/kvm/coproc.c
@@ -568,41 +568,53 @@ int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run)
  *****************************************************************************/
 
 /* Given a simple mask, get those bits. */
-static inline u32 get_bits(u32 index, u32 mask)
+static inline u32 get_bits(u32 index, u32 start, u32 len)
 {
-	return (index & mask) >> (ffs(mask) - 1);
+	return (index >> start) & ((1 << len)-1);
 }
 
-static void index_to_params(u32 index, struct coproc_params *params)
+static bool index_to_params(u64 index, struct coproc_params *params)
 {
-	if (get_bits(index, KVM_ARM_MSR_64_BIT_MASK)) {
+	switch (index & KVM_REG_SIZE_MASK) {
+	case KVM_REG_SIZE_U32:
+		params->is_64bit = false;
+		params->CRn = get_bits(index, KVM_REG_ARM_32_CRN_START,
+				       KVM_REG_ARM_32_CRN_LEN);
+		params->CRm = get_bits(index, KVM_REG_ARM_CRM_START,
+				       KVM_REG_ARM_CRM_LEN);
+		params->Op1 = get_bits(index, KVM_REG_ARM_OPC1_START,
+				       KVM_REG_ARM_OPC1_LEN);
+		params->Op2 = get_bits(index, KVM_REG_ARM_32_OPC2_START,
+				       KVM_REG_ARM_32_OPC2_LEN);
+		return true;
+	case KVM_REG_SIZE_U64:
 		params->is_64bit = true;
-		params->CRm = get_bits(index, KVM_ARM_MSR_64_CRM_MASK);
-		params->Op1 = get_bits(index, KVM_ARM_MSR_64_OPC1_MASK);
+		params->CRm = get_bits(index, KVM_REG_ARM_CRM_START,
+				       KVM_REG_ARM_CRM_LEN);
+		params->Op1 = get_bits(index, KVM_REG_ARM_OPC1_START,
+				       KVM_REG_ARM_OPC1_LEN);
 		params->Op2 = 0;
 		params->CRn = 0;
-	} else {
-		params->is_64bit = false;
-		params->CRn = get_bits(index, KVM_ARM_MSR_32_CRN_MASK);
-		params->CRm = get_bits(index, KVM_ARM_MSR_32_CRM_MASK);
-		params->Op1 = get_bits(index, KVM_ARM_MSR_32_OPC1_MASK);
-		params->Op2 = get_bits(index, KVM_ARM_MSR_32_OPC2_MASK);
+		return true;
+	default:
+		return false;
 	}
 }
 
 /* Decode an index value, and find the cp15 coproc_reg entry. */
 static const struct coproc_reg *index_to_coproc_reg(struct kvm_vcpu *vcpu,
-						    u32 index)
+						    u64 index)
 {
 	size_t num;
 	const struct coproc_reg *table, *r;
 	struct coproc_params params;
 
 	/* We only do cp15 for now. */
-	if (get_bits(index, KVM_ARM_MSR_COPROC_MASK != 15))
+	if (get_bits(index, KVM_REG_ARM_COPROC_START, 16) != 15)
 		return NULL;
 
-	index_to_params(index, &params);
+	if (!index_to_params(index, &params))
+		return NULL;
 
 	table = get_target_table(vcpu->arch.target, &num);
 	r = find_reg(&params, table, num);
@@ -689,30 +701,54 @@ static struct coproc_reg invariant_cp15[] = {
 	{ CRn( 0), CRm( 0), Op1( 1), Op2( 7), is32, NULL, get_AIDR },
 };
 
-static int get_invariant_cp15(u32 index, u64 *val)
+static int reg_from_user(void *val, const void __user *uaddr, u64 index)
+{
+	/* This Just Works because we are little endian. */
+	if (copy_from_user(val, uaddr, KVM_REG_LEN(index)) != 0)
+		return -EFAULT;
+	return 0;
+}
+
+static int reg_to_user(void __user *uaddr, const void *val, u64 index)
+{
+	/* This Just Works because we are little endian. */
+	if (copy_to_user(uaddr, val, KVM_REG_LEN(index)) != 0)
+		return -EFAULT;
+	return 0;
+}
+
+static int get_invariant_cp15(u64 index, void __user *uaddr)
 {
 	struct coproc_params params;
 	const struct coproc_reg *r;
 
-	index_to_params(index, &params);
+	if (!index_to_params(index, &params))
+		return -ENOENT;
+
 	r = find_reg(&params, invariant_cp15, ARRAY_SIZE(invariant_cp15));
 	if (!r)
 		return -ENOENT;
 
-	*val = r->val;
-	return 0;
+	return reg_to_user(uaddr, &r->val, index);
 }
 
-static int set_invariant_cp15(u32 index, u64 val)
+static int set_invariant_cp15(u64 index, void __user *uaddr)
 {
 	struct coproc_params params;
 	const struct coproc_reg *r;
+	int err;
+	u64 val = 0; /* Make sure high bits are 0 for 32-bit regs */
 
-	index_to_params(index, &params);
+	if (!index_to_params(index, &params))
+		return -ENOENT;
 	r = find_reg(&params, invariant_cp15, ARRAY_SIZE(invariant_cp15));
 	if (!r)
 		return -ENOENT;
 
+	err = reg_from_user(&val, uaddr, index);
+	if (err)
+		return err;
+
 	/* This is what we mean by invariant: you can't change it. */
 	if (r->val != val)
 		return -EINVAL;
@@ -720,95 +756,36 @@ static int set_invariant_cp15(u32 index, u64 val)
 	return 0;
 }
 
-static int get_msr(struct kvm_vcpu *vcpu, u32 index, u64 *val)
+int kvm_arch_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 {
 	const struct coproc_reg *r;
+	void __user *uaddr = (void __user *)(long)reg->addr;
 
-	r = index_to_coproc_reg(vcpu, index);
-	if (!r)
-		return get_invariant_cp15(index, val);
-
-	*val = vcpu->arch.cp15[r->reg];
-	if (r->is_64)
-		*val |= ((u64)vcpu->arch.cp15[r->reg+1]) << 32;
-	return 0;
-}
-
-static int set_msr(struct kvm_vcpu *vcpu, u32 index, u64 val)
-{
-	const struct coproc_reg *r;
+	if ((reg->id & KVM_REG_ARCH_MASK) != KVM_REG_ARM)
+		return -EINVAL;
 
-	r = index_to_coproc_reg(vcpu, index);
+	r = index_to_coproc_reg(vcpu, reg->id);
 	if (!r)
-		return set_invariant_cp15(index, val);
+		return get_invariant_cp15(reg->id, uaddr);
 
-	vcpu->arch.cp15[r->reg] = val;
-	if (r->is_64)
-		vcpu->arch.cp15[r->reg+1] = (val >> 32);
-	return 0;
-}
-
-/* Return user adddress to get/set value from. */
-static u64 __user *get_umsr(struct kvm_msr_entry __user *uentry, u32 *idx)
-{
-	struct kvm_msr_entry entry;
-
-	if (copy_from_user(&entry, uentry, sizeof(entry)))
-		return NULL;
-	*idx = entry.index;
-	return &uentry->data;
+	/* Note: copies two regs if size is 64 bit. */
+	return reg_to_user(uaddr, &vcpu->arch.cp15[r->reg], reg->id);
 }
 
-/**
- * kvm_arm_get_msrs - copy one or more special registers to userspace.
- * @vcpu: the vcpu
- * @entries: the array of entries
- * @num: the number of entries
- */
-int kvm_arm_get_msrs(struct kvm_vcpu *vcpu,
-		     struct kvm_msr_entry __user *entries, u32 num)
+int kvm_arch_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 {
-	u32 i, index;
-	u64 val;
-	u64 __user *uval;
-	int ret;
+	const struct coproc_reg *r;
+	void __user *uaddr = (void __user *)(long)reg->addr;
 
-	for (i = 0; i < num; i++) {
-		uval = get_umsr(&entries[i], &index);
-		if (!uval)
-			return -EFAULT;
-		if ((ret = get_msr(vcpu, index, &val)) != 0)
-			return ret;
-		if (put_user(val, uval))
-			return -EFAULT;
-	}
-	return 0;
-}
+	if ((reg->id & KVM_REG_ARCH_MASK) != KVM_REG_ARM)
+		return -EINVAL;
 
-/**
- * kvm_arm_set_msrs - copy one or more special registers from userspace.
- * @vcpu: the vcpu
- * @entries: the array of entries
- * @num: the number of entries
- */
-int kvm_arm_set_msrs(struct kvm_vcpu *vcpu,
-		     struct kvm_msr_entry __user *entries, u32 num)
-{
-	u32 i, index;
-	u64 val;
-	u64 __user *uval;
-	int ret;
+	r = index_to_coproc_reg(vcpu, reg->id);
+	if (!r)
+		return set_invariant_cp15(reg->id, uaddr);
 
-	for (i = 0; i < num; i++) {
-		uval = get_umsr(&entries[i], &index);
-		if (!uval)
-			return -EFAULT;
-		if (copy_from_user(&val, uval, sizeof(val)) != 0)
-			return -EFAULT;
-		if ((ret = set_msr(vcpu, index, val)) != 0)
-			return ret;
-	}
-	return 0;
+	/* Note: copies two regs if size is 64 bit */
+	return copy_from_user(&vcpu->arch.cp15[r->reg], uaddr, reg->id);
 }
 
 static int cmp_reg(const struct coproc_reg *i1, const struct coproc_reg *i2)
@@ -827,29 +804,24 @@ static int cmp_reg(const struct coproc_reg *i1, const struct coproc_reg *i2)
 	return i1->Op2 - i2->Op2;
 }
 
-/* Puts in the position indicated by mask (assumes val fits in mask) */
-static inline u32 set_bits(u32 val, u32 mask)
-{
-	return val << (ffs(mask)-1);
-}
-
-static u32 cp15_to_index(const struct coproc_reg *reg)
+static u64 cp15_to_index(const struct coproc_reg *reg)
 {
-	u32 val = set_bits(15, KVM_ARM_MSR_COPROC_MASK);
+	u64 val = (15 << KVM_REG_ARM_COPROC_START);
 	if (reg->is_64) {
-		val |= set_bits(1, KVM_ARM_MSR_64_BIT_MASK);
-		val |= set_bits(reg->Op1, KVM_ARM_MSR_64_OPC1_MASK);
-		val |= set_bits(reg->CRm, KVM_ARM_MSR_64_CRM_MASK);
+		val |= KVM_REG_SIZE_U64;
+		val |= (reg->Op1 << KVM_REG_ARM_OPC1_START);
+		val |= (reg->CRm << KVM_REG_ARM_CRM_START);
 	} else {
-		val |= set_bits(reg->Op1, KVM_ARM_MSR_32_OPC1_MASK);
-		val |= set_bits(reg->Op2, KVM_ARM_MSR_32_OPC2_MASK);
-		val |= set_bits(reg->CRm, KVM_ARM_MSR_32_CRM_MASK);
-		val |= set_bits(reg->CRn, KVM_ARM_MSR_32_CRN_MASK);
+		val |= KVM_REG_SIZE_U32;
+		val |= (reg->Op1 << KVM_REG_ARM_OPC1_START);
+		val |= (reg->Op2 << KVM_REG_ARM_32_OPC2_START);
+		val |= (reg->CRm << KVM_REG_ARM_CRM_START);
+		val |= (reg->CRn << KVM_REG_ARM_32_CRN_START);
 	}
 	return val;
 }
 
-static bool copy_reg_to_user(const struct coproc_reg *reg, u32 __user **uind)
+static bool copy_reg_to_user(const struct coproc_reg *reg, u64 __user **uind)
 {
 	if (!*uind)
 		return true;
@@ -862,7 +834,7 @@ static bool copy_reg_to_user(const struct coproc_reg *reg, u32 __user **uind)
 }
 
 /* Assumed ordered tables, see kvm_coproc_table_init. */
-static int walk_msrs(struct kvm_vcpu *vcpu, u32 __user *uind)
+static int walk_msrs(struct kvm_vcpu *vcpu, u64 __user *uind)
 {
 	const struct coproc_reg *i1, *i2, *end1, *end2;
 	unsigned int total = 0;
@@ -911,7 +883,7 @@ static int walk_msrs(struct kvm_vcpu *vcpu, u32 __user *uind)
  */
 unsigned long kvm_arm_num_guest_msrs(struct kvm_vcpu *vcpu)
 {
-	return ARRAY_SIZE(invariant_cp15) + walk_msrs(vcpu, (u32 __user *)NULL);
+	return ARRAY_SIZE(invariant_cp15) + walk_msrs(vcpu, (u64 __user *)NULL);
 }
 
 /**
@@ -919,7 +891,7 @@ unsigned long kvm_arm_num_guest_msrs(struct kvm_vcpu *vcpu)
  *
  * This is for special registers, particularly cp15.
  */
-int kvm_arm_copy_msrindices(struct kvm_vcpu *vcpu, u32 __user *uindices)
+int kvm_arm_copy_msrindices(struct kvm_vcpu *vcpu, u64 __user *uindices)
 {
 	unsigned int i;
 	int err;

  parent reply	other threads:[~2012-08-28 23:49 UTC|newest]

Thread overview: 48+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-08-28 23:37 [RFC 0/5] Making KVM_GET_ONE_REG/KVM_SET_ONE_REG generic Rusty Russell
2012-08-28 23:45 ` [RFC 1/5] KVM: Move KVM_SET_ONE_REG/KVM_GET_ONE_REG to generic code Rusty Russell
2012-09-01  9:11   ` Avi Kivity
2012-09-01 10:18     ` Peter Maydell
2012-09-01 10:44       ` Avi Kivity
2012-08-28 23:46 ` Rusty Russell [this message]
2012-08-29 15:10   ` [RFC 2/5] KVM: ARM: use KVM_SET_ONE_REG/KVM_GET_ONE_REG Christoffer Dall
2012-08-28 23:47 ` [RFC 3/5] KVM: Add KVM_VCPU_GET_REG_LIST Rusty Russell
2012-08-29 15:13   ` Christoffer Dall
2012-08-28 23:47 ` [RFC 4/5] KVM: ARM: Use KVM_VCPU_GET_REG_LIST Rusty Russell
2012-08-29 15:14   ` Christoffer Dall
2012-08-28 23:48 ` [RFC 5/5] KVM: ARM: Access all registers via KVM_GET_ONE_REG/KVM_SET_ONE_REG Rusty Russell
2012-08-29 15:29   ` Christoffer Dall
2012-09-01  9:14     ` Avi Kivity
2012-08-29 15:36   ` Peter Maydell
2012-08-29 18:21     ` Rusty Russell
2012-09-01  9:16       ` Avi Kivity
2012-09-01 10:25         ` Peter Maydell
2012-09-01 19:40           ` Christoffer Dall
2012-09-04 13:09             ` Peter Maydell
2012-09-04 14:29               ` Christoffer Dall
2012-09-05  6:37                 ` Rusty Russell
2012-08-29 18:16   ` Rusty Russell
2012-08-29 16:30 ` [RFC 0/5] Making KVM_GET_ONE_REG/KVM_SET_ONE_REG generic Peter Maydell
2012-08-29 18:39   ` Rusty Russell
2012-09-01  9:21     ` Avi Kivity
2012-09-01 12:35       ` Rusty Russell
2012-09-03  9:20         ` Avi Kivity
2012-09-03 12:33           ` Rusty Russell
2012-09-03 12:49             ` Peter Maydell
2012-09-04 11:48             ` Avi Kivity
2012-09-04 13:59               ` Alexander Graf
2012-09-06 14:44                 ` Avi Kivity
2012-09-05  6:43               ` Rusty Russell
2012-09-01 12:28 ` Rusty Russell
2012-09-01 12:37   ` Rusty Russell
2012-09-04 13:31   ` Peter Maydell
2012-09-05  3:15     ` Alexander Graf
2012-09-05  6:48     ` Rusty Russell
2012-09-05  8:52       ` Peter Maydell
2012-09-06  1:44         ` Rusty Russell
2012-09-06  7:37           ` Peter Maydell
2012-09-06 14:48       ` Avi Kivity
2012-09-06 15:08         ` Alexander Graf
2012-09-06 15:16           ` Avi Kivity
2012-09-06 15:23             ` Peter Maydell
2012-09-06 15:35               ` Avi Kivity
2012-09-06 23:00                 ` Rusty Russell

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87y5ky8tr6.fsf@rustcorp.com.au \
    --to=rusty.russell@linaro.org \
    --cc=agraf@suse.de \
    --cc=avi@redhat.com \
    --cc=c.dall@virtualopensystems.com \
    --cc=kvm@vger.kernel.org \
    --cc=kvmarm@lists.cs.columbia.edu \
    --cc=peter.maydell@linaro.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.