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.russ...@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;
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to