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

Sorry if I'm asking the obvious. How do you make sure that 32 bit 
registers are always accessed with 32bit reg ids?


Alex

_______________________________________________
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