Re: [RFC 2/5] KVM: ARM: use KVM_SET_ONE_REG/KVM_GET_ONE_REG.

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

 



On Tue, Aug 28, 2012 at 4:46 PM, Rusty Russell <rusty.russell@xxxxxxxxxx> wrote:
> 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@xxxxxxxxxx>
>
> 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;

why do we still call this stuff MSR? Shouldn't we move away from that
term to something more generic?

-Christoffer
_______________________________________________
kvmarm mailing list
kvmarm@xxxxxxxxxxxxxxxxxxxxx
https://lists.cs.columbia.edu/cucslists/listinfo/kvmarm


[Index of Archives]     [Linux KVM]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux