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(®, 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) 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