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(®, argp, sizeof(reg))) + return -EFAULT; + if (ioctl == KVM_SET_ONE_REG) + return kvm_arm_set_reg(vcpu, ®); + else + return kvm_arm_get_reg(vcpu, ®); + } 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, ¶ms); + if (!index_to_params(id, ¶ms)) + return NULL; table = get_target_table(vcpu->arch.target, &num); r = find_reg(¶ms, 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) + return -EFAULT; + return 0; +} + +static int reg_to_user(void __user *uaddr, const void *val, u64 id) +{ + /* This Just Works because we are little endian. */ + if (copy_to_user(uaddr, val, KVM_REG_SIZE(id)) != 0) + return -EFAULT; + return 0; +} + +static int get_invariant_cp15(u64 id, void __user *uaddr) { struct coproc_params params; const struct coproc_reg *r; - index_to_params(index, ¶ms); + if (!index_to_params(id, ¶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, id); } -static int set_invariant_cp15(u32 index, u64 val) +static int set_invariant_cp15(u64 id, 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(id, ¶ms)) + return -ENOENT; r = find_reg(¶ms, invariant_cp15, ARRAY_SIZE(invariant_cp15)); if (!r) return -ENOENT; + err = reg_from_user(&val, uaddr, id); + if (err) + return err; + /* This is what we mean by invariant: you can't change it. */ if (r->val != val) return -EINVAL; @@ -718,95 +763,30 @@ 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_arm_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); + r = index_to_coproc_reg(vcpu, reg->id); if (!r) - return get_invariant_cp15(index, val); + return get_invariant_cp15(reg->id, uaddr); - *val = vcpu->arch.cp15[r->reg]; - if (r->is_64) - *val |= ((u64)vcpu->arch.cp15[r->reg+1]) << 32; - return 0; + /* Note: copies two regs if size is 64 bit. */ + return reg_to_user(uaddr, &vcpu->arch.cp15[r->reg], reg->id); } -static int set_msr(struct kvm_vcpu *vcpu, u32 index, u64 val) +int kvm_arm_set_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); + r = index_to_coproc_reg(vcpu, reg->id); if (!r) - return set_invariant_cp15(index, val); + return set_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; -} - -/** - * 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) -{ - u32 i, index; - u64 val; - u64 __user *uval; - int ret; - - 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; -} - -/** - * 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; - - 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 reg_from_user(&vcpu->arch.cp15[r->reg], uaddr, reg->id); } static int cmp_reg(const struct coproc_reg *i1, const struct coproc_reg *i2) @@ -825,29 +805,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 = KVM_REG_ARM | (15 << KVM_REG_ARM_COPROC_SHIFT); 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_SHIFT); + val |= (reg->CRm << KVM_REG_ARM_CRM_SHIFT); } 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_SHIFT); + val |= (reg->Op2 << KVM_REG_ARM_32_OPC2_SHIFT); + val |= (reg->CRm << KVM_REG_ARM_CRM_SHIFT); + val |= (reg->CRn << KVM_REG_ARM_32_CRN_SHIFT); } 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; @@ -860,7 +835,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; @@ -909,7 +884,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); } /** @@ -917,7 +892,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; _______________________________________________ kvmarm mailing list kvmarm@xxxxxxxxxxxxxxxxxxxxx https://lists.cs.columbia.edu/cucslists/listinfo/kvmarm