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, ¶ms); + if (!index_to_params(index, ¶ms)) + return NULL; table = get_target_table(vcpu->arch.target, &num); r = find_reg(¶ms, 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, ¶ms); + if (!index_to_params(index, ¶ms)) + return -ENOENT; + r = find_reg(¶ms, 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, ¶ms); + if (!index_to_params(index, ¶ms)) + return -ENOENT; r = find_reg(¶ms, 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 majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html