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