Re: [PATCH 2/4] KVM: ARM: use KVM_SET_ONE_REG/KVM_GET_ONE_REG.

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

 



On Thu, Sep 13, 2012 at 11:12 AM, Alexander Graf <agraf@xxxxxxx> wrote:
> On 09/11/2012 07:48 AM, Rusty Russell wrote:
>>
>> Instead of overloading x86's KVM_GET_MSRS/KVM_SET_MSRS.  The only basic
>> difference is that the ids are 64 bit.
>>
>> This means we share the interface with PPC and S/390, though we don't
>> actually share the code (yet?).
>>
>> Signed-off-by: Rusty Russell <rusty.russell@xxxxxxxxxx>
>>
>> diff --git a/Documentation/virtual/kvm/api.txt
>> b/Documentation/virtual/kvm/api.txt
>> index d730b93..b09438b 100644
>> --- a/Documentation/virtual/kvm/api.txt
>> +++ b/Documentation/virtual/kvm/api.txt
>> @@ -1745,6 +1745,15 @@ registers, find a list below:
>>           |                       |
>>     PPC   | KVM_REG_PPC_HIOR      | 64
>>   +ARM registers are mapped using the lower 32 bits.  The upper 16 of that
>> +is the coprocessor number, or other ID:
>> +
>> +ARM 32-bit CP15 registers have the following id bit patterns:
>> +  0x4002 0000 000F <zero:1> <crn:4> <crm:4> <opc1:4> <opc2:3>
>> +
>> +ARM 64-bit CP15 registers have the following id bit patterns:
>> +  0x4003 0000 000F <zero:1> <zero:4> <crm:4> <opc1:4> <zero:3>
>> +
>>     4.69 KVM_GET_ONE_REG
>>   diff --git a/arch/arm/include/asm/kvm.h b/arch/arm/include/asm/kvm.h
>> index d040a2a..d2a65e4 100644
>> --- a/arch/arm/include/asm/kvm.h
>> +++ b/arch/arm/include/asm/kvm.h
>> @@ -85,35 +85,22 @@ 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 is the key: */
>> +#define KVM_REG_ARM_COPROC_MASK                0x000000000FFF0000
>> +#define KVM_REG_ARM_COPROC_SHIFT       16
>> +#define KVM_REG_ARM_32_OPC2_MASK       0x0000000000000007
>> +#define KVM_REG_ARM_32_OPC2_SHIFT      0
>> +#define KVM_REG_ARM_OPC1_MASK          0x0000000000000078
>> +#define KVM_REG_ARM_OPC1_SHIFT         3
>> +#define KVM_REG_ARM_CRM_MASK           0x0000000000000780
>> +#define KVM_REG_ARM_CRM_SHIFT          7
>> +#define KVM_REG_ARM_32_CRN_MASK                0x0000000000007800
>> +#define KVM_REG_ARM_32_CRN_SHIFT       11
>>     #endif /* __ARM_KVM_H__ */
>> diff --git a/arch/arm/include/asm/kvm_coproc.h
>> b/arch/arm/include/asm/kvm_coproc.h
>> index 894574c..d9c2f45 100644
>> --- a/arch/arm/include/asm/kvm_coproc.h
>> +++ b/arch/arm/include/asm/kvm_coproc.h
>> @@ -28,11 +28,10 @@ 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);
>> +
>> +int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg
>> *reg);
>> +int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg
>> *reg);
>>   #endif /* __ARM_KVM_COPROC_H__ */
>> diff --git a/arch/arm/include/asm/kvm_host.h
>> b/arch/arm/include/asm/kvm_host.h
>> index fd93d37..896e13f 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
>>     #include <asm/kvm_vgic.h>
>>   diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
>> index 4a01b42..271ea92 100644
>> --- a/arch/arm/kvm/arm.c
>> +++ b/arch/arm/kvm/arm.c
>> @@ -201,6 +201,7 @@ int kvm_dev_ioctl_check_extension(long ext)
>>   #endif
>>         case KVM_CAP_USER_MEMORY:
>>         case KVM_CAP_DESTROY_MEMORY_REGION_WORKS:
>> +       case KVM_CAP_ONE_REG:
>>                 r = 1;
>>                 break;
>>         case KVM_CAP_COALESCED_MMIO:
>> @@ -768,6 +769,16 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
>>                 return kvm_vcpu_set_target(vcpu, &init);
>>         }
>> +       case KVM_SET_ONE_REG:
>> +       case KVM_GET_ONE_REG: {
>> +               struct kvm_one_reg reg;
>> +               if (copy_from_user(&reg, argp, sizeof(reg)))
>> +                       return -EFAULT;
>> +               if (ioctl == KVM_SET_ONE_REG)
>> +                       return kvm_arm_set_reg(vcpu, &reg);
>> +               else
>> +                       return kvm_arm_get_reg(vcpu, &reg);
>> +       }
>>         case KVM_VCPU_GET_MSR_INDEX_LIST: {
>>                 struct kvm_msr_list __user *user_msr_list = argp;
>>                 struct kvm_msr_list msr_list;
>> @@ -783,20 +794,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);
>> -       }
>>   #ifdef CONFIG_KVM_ARM_VGIC
>>         case KVM_IRQ_LINE: {
>>                 struct kvm_irq_level irq_event;
>> diff --git a/arch/arm/kvm/coproc.c b/arch/arm/kvm/coproc.c
>> index 72a3f64..5a0a7e0 100644
>> --- a/arch/arm/kvm/coproc.c
>> +++ b/arch/arm/kvm/coproc.c
>> @@ -565,42 +565,63 @@ int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct
>> kvm_run *run)
>>    * Userspace API
>>
>> *****************************************************************************/
>>   -/* Given a simple mask, get those bits. */
>> -static inline u32 get_bits(u32 index, u32 mask)
>> -{
>> -       return (index & mask) >> (ffs(mask) - 1);
>> -}
>> +static bool index_to_params(u64 id, struct coproc_params *params)
>> +{
>> +       switch (id & KVM_REG_SIZE_MASK) {
>> +       case KVM_REG_SIZE_U32:
>> +               /* Any unused index bits means it's not valid. */
>> +               if (id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK
>> +                          | KVM_REG_ARM_COPROC_MASK
>> +                          | KVM_REG_ARM_32_CRN_MASK
>> +                          | KVM_REG_ARM_CRM_MASK
>> +                          | KVM_REG_ARM_OPC1_MASK
>> +                          | KVM_REG_ARM_32_OPC2_MASK))
>> +                       return false;
>>   -static void index_to_params(u32 index, struct coproc_params *params)
>> -{
>> -       if (get_bits(index, KVM_ARM_MSR_64_BIT_MASK)) {
>> +               params->is_64bit = false;
>> +               params->CRn = ((id & KVM_REG_ARM_32_CRN_MASK)
>> +                              >> KVM_REG_ARM_32_CRN_SHIFT);
>> +               params->CRm = ((id & KVM_REG_ARM_CRM_MASK)
>> +                              >> KVM_REG_ARM_CRM_SHIFT);
>> +               params->Op1 = ((id & KVM_REG_ARM_OPC1_MASK)
>> +                              >> KVM_REG_ARM_OPC1_SHIFT);
>> +               params->Op2 = ((id & KVM_REG_ARM_32_OPC2_MASK)
>> +                              >> KVM_REG_ARM_32_OPC2_SHIFT);
>> +               return true;
>> +       case KVM_REG_SIZE_U64:
>> +               /* Any unused index bits means it's not valid. */
>> +               if (id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK
>> +                             | KVM_REG_ARM_COPROC_MASK
>> +                             | KVM_REG_ARM_CRM_MASK
>> +                             | KVM_REG_ARM_OPC1_MASK))
>> +                       return false;
>>                 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 = ((id & KVM_REG_ARM_CRM_MASK)
>> +                              >> KVM_REG_ARM_CRM_SHIFT);
>> +               params->Op1 = ((id & KVM_REG_ARM_OPC1_MASK)
>> +                              >> KVM_REG_ARM_OPC1_SHIFT);
>>                 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 id)
>>   {
>>         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 ((id & KVM_REG_ARM_COPROC_MASK) >> KVM_REG_ARM_COPROC_SHIFT !=
>> 15)
>>                 return NULL;
>>   -     index_to_params(index, &params);
>> +       if (!index_to_params(id, &params))
>> +               return NULL;
>>         table = get_target_table(vcpu->arch.target, &num);
>>         r = find_reg(&params, table, num);
>> @@ -687,30 +708,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 id)
>> +{
>> +       /* This Just Works because we are little endian. */
>> +       if (copy_from_user(val, uaddr, KVM_REG_SIZE(id)) != 0)
>
>
if you look at index_to_coproc_reg that calls index_to_params, which
only accepts 32-bit or 64-bits inputs, and sets the is_64bit on the
coproc_params struct, this is verified in the call to find_reg, so I
think it's good.

-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