Is this the 3/3 patch or is something missing? On Tue, Sep 11, 2012 at 2:07 AM, Rusty Russell <rusty.russell@xxxxxxxxxx> wrote: > The Cache Size Selection Register (CSSELR) selects the current Cache > Size ID Register (CCSIDR). You write which cache you are interested > in to CSSELR, and read the information out of CCSIDR. > > Which cache numbers are valid is known by reading the Cache Level ID > Register (CLIDR). > > To export this state to userspace, we add a KVM_REG_ARM_DEMUX > numberspace (17), which uses 8 bits to represent which register is > being demultiplexed (0 for CCSIDR), and the lower 8 bits to represent > this demultiplexing (in our case, the CSSELR value, which is 4 bits). > > Signed-off-by: Rusty Russell <rusty.russell@xxxxxxxxxx> > > diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt > index 4d22fdf..1e70024 100644 > --- a/Documentation/virtual/kvm/api.txt > +++ b/Documentation/virtual/kvm/api.txt > @@ -1761,6 +1761,9 @@ ARM 64-bit CP15 registers have the following id bit patterns: > ARM core registers have the following id format: > 0x4003 0000 0010 <offset in struct kvm_regs, divided by 4> > > +ARM CCSIDR registers are demultiplexed by CSSELR value: > + 0x4003 0000 0011 <CSSELR> then this is wrong right? shouldn't it be: + 0x4003 0000 0011 <dmux id:8> <selector:8> or + 0x4003 0000 0011 00 <CSSELR:8> ??? > + > 4.69 KVM_GET_ONE_REG > > Capability: KVM_CAP_ONE_REG > diff --git a/arch/arm/include/asm/kvm.h b/arch/arm/include/asm/kvm.h > index 3442ced..86184a4 100644 > --- a/arch/arm/include/asm/kvm.h > +++ b/arch/arm/include/asm/kvm.h > @@ -85,4 +85,12 @@ struct kvm_arch_memory_slot { > #define KVM_REG_ARM_CORE (0x0010 << KVM_REG_ARM_COPROC_SHIFT) > #define KVM_REG_ARM_CORE_REG(name) (offsetof(struct kvm_regs, name) / 4) > > +/* Some registers need more space to represent values. */ > +#define KVM_REG_ARM_DEMUX (0x0011 << KVM_REG_ARM_COPROC_SHIFT) > +#define KVM_REG_ARM_DEMUX_ID_MASK 0x000000000000FF00 > +#define KVM_REG_ARM_DEMUX_ID_SHIFT 8 > +#define KVM_REG_ARM_DEMUX_ID_CCSIDR (0x00 << KVM_REG_ARM_DEMUX_ID_SHIFT) > +#define KVM_REG_ARM_DEMUX_VAL_MASK 0x00000000000000FF > +#define KVM_REG_ARM_DEMUX_VAL_SHIFT 0 > + > #endif /* __ARM_KVM_H__ */ > diff --git a/arch/arm/kvm/coproc.c b/arch/arm/kvm/coproc.c > index b6abe2e..02b7077 100644 > --- a/arch/arm/kvm/coproc.c > +++ b/arch/arm/kvm/coproc.c > @@ -67,6 +67,12 @@ struct coproc_reg { > u64 val; > }; > > +/* 3 bits per cache level, as per CLIDR, but non-existent caches always 0 */ > +static u32 cache_levels; > + > +/* CSSELR values; used to index KVM_REG_ARM_DEMUX_ID_CCSIDR */ > +#define CSSELR_MAX 12 > + > static void print_cp_instr(const struct coproc_params *p) > { > /* Look, we even formatted it for you to paste into the table! */ > @@ -763,11 +767,111 @@ static int set_invariant_cp15(u64 id, void __user *uaddr) > return 0; > } > > +static bool is_valid_cache(u32 val) > +{ > + u32 ctype; > + > + if (val >= CSSELR_MAX) > + return -ENOENT; > + > + /* Bottom bit is Instruction or Data bit. Next 3 bits are level. */ > + ctype = cache_levels & (7 << ((val>>1) & ); this looks wrong, shouldn't this be + level = (val >> 1) & 7; + ctype = (cache_levels >> (level * 3)) & 7; ??? > + > + switch (ctype) { > + case 0: /* No cache */ > + return false; > + case 1: /* Instruction cache only */ > + return (val & 1); > + case 2: /* Data cache only */ > + case 4: /* Unified cache */ > + return !(val & 1); > + case 3: /* Separate instruction and data caches */ > + return true; > + default: /* Reserved: we can't know instruction or data. */ > + return false; > + } > +} > + > +/* Which cache CCSIDR represents depends on CSSELR value. */ > +static u32 get_ccsidr(u32 csselr) > +{ > + u32 ccsidr; > + > + /* Make sure noone else changes CSSELR during this! */ > + local_irq_disable(); > + /* Put value into CSSELR */ > + asm volatile("mcr p15, 2, %0, c0, c0, 0" : : "r" (csselr)); > + /* Read result out of CCSIDR */ > + asm volatile("mrc p15, 1, %0, c0, c0, 0" : "=r" (ccsidr)); > + local_irq_enable(); > + > + return ccsidr; > +} > + > +static int demux_c15_get(u64 id, void __user *uaddr) > +{ > + u32 val; > + u32 __user *uval = uaddr; > + > + /* Fail if we have unknown bits set. */ > + if (id & ~(KVM_REG_ARCH_MASK|KVM_REG_SIZE_MASK|KVM_REG_ARM_COPROC_MASK > + | ((1 << KVM_REG_ARM_COPROC_SHIFT)-1))) > + return -ENOENT; > + > + switch (id & KVM_REG_ARM_DEMUX_ID_MASK) { > + case KVM_REG_ARM_DEMUX_ID_CCSIDR: > + if (KVM_REG_SIZE(id) != 4) > + return -ENOENT; > + val = (id & KVM_REG_ARM_DEMUX_VAL_MASK) > + >> KVM_REG_ARM_DEMUX_VAL_SHIFT; > + if (!is_valid_cache(val)) > + return -ENOENT; > + > + return put_user(get_ccsidr(val), uval); > + default: > + return -ENOENT; > + } > +} > + > +static int demux_c15_set(u64 id, void __user *uaddr) > +{ > + u32 val, newval; > + u32 __user *uval = uaddr; > + > + /* Fail if we have unknown bits set. */ > + if (id & ~(KVM_REG_ARCH_MASK|KVM_REG_SIZE_MASK|KVM_REG_ARM_COPROC_MASK > + | ((1 << KVM_REG_ARM_COPROC_SHIFT)-1))) > + return -ENOENT; > + > + switch (id & KVM_REG_ARM_DEMUX_ID_MASK) { > + case KVM_REG_ARM_DEMUX_ID_CCSIDR: > + if (KVM_REG_SIZE(id) != 4) > + return -ENOENT; > + val = (id & KVM_REG_ARM_DEMUX_VAL_MASK) > + >> KVM_REG_ARM_DEMUX_VAL_SHIFT; > + if (!is_valid_cache(val)) > + return -ENOENT; > + > + if (get_user(newval, uval)) > + return -EFAULT; > + > + /* This is also invariant: you can't change it. */ > + if (newval != get_ccsidr(val)) > + return -EINVAL; > + return 0; > + default: > + return -ENOENT; > + } > +} > + > int kvm_arm_coproc_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; > > + if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_DEMUX) > + return demux_c15_get(reg->id, uaddr); > + > r = index_to_coproc_reg(vcpu, reg->id); > if (!r) > return get_invariant_cp15(reg->id, uaddr); > @@ -781,6 +886,9 @@ int kvm_arm_coproc_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; > > + if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_DEMUX) > + return demux_c15_set(reg->id, uaddr); > + > r = index_to_coproc_reg(vcpu, reg->id); > if (!r) > return set_invariant_cp15(reg->id, uaddr); > @@ -789,6 +897,33 @@ int kvm_arm_coproc_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) > return reg_from_user(&vcpu->arch.cp15[r->reg], uaddr, reg->id); > } > > +static unsigned int num_demux_regs(void) > +{ > + unsigned int i, count = 0; > + > + for (i = 0; i < CSSELR_MAX; i++) > + if (is_valid_cache(i)) > + count++; > + > + return count; > +} > + > +static int write_demux_regids(u64 __user *uindices) > +{ > + u64 val = KVM_REG_ARM | KVM_REG_SIZE_U32 | KVM_REG_ARM_DEMUX; > + unsigned int i; > + > + val |= KVM_REG_ARM_DEMUX_ID_CCSIDR; > + for (i = 0; i < CSSELR_MAX; i++) { > + if (!is_valid_cache(i)) > + continue; > + if (put_user(val | i, uindices)) > + return -EFAULT; > + uindices++; > + } > + return 0; > +} > + > static int cmp_reg(const struct coproc_reg *i1, const struct coproc_reg *i2) > { > BUG_ON(i1 == i2); > @@ -880,6 +1015,7 @@ static int walk_cp15(struct kvm_vcpu *vcpu, u64 __user *uind) > unsigned long kvm_arm_num_coproc_regs(struct kvm_vcpu *vcpu) > { > return ARRAY_SIZE(invariant_cp15) > + + num_demux_regs() > + walk_cp15(vcpu, (u64 __user *)NULL); > } > > @@ -896,9 +1032,11 @@ int kvm_arm_copy_coproc_indices(struct kvm_vcpu *vcpu, u64 __user *uindices) > } > > err = walk_cp15(vcpu, uindices); > - if (err > 0) > - err = 0; > - return err; > + if (err < 0) > + return err; > + uindices += err; > + > + return write_demux_regids(uindices); > } > > void kvm_coproc_table_init(void) > @@ -915,6 +1053,23 @@ void kvm_coproc_table_init(void) > /* We abuse the reset function to overwrite the table itself. */ > for (i = 0; i < ARRAY_SIZE(invariant_cp15); i++) > invariant_cp15[i].reset(NULL, &invariant_cp15[i]); > + > + /* > + * CLIDR format is awkward, so clean it up. See ARM B4.1.20: > + * > + * If software reads the Cache Type fields from Ctype1 > + * upwards, once it has seen a value of 0b000, no caches > + * exist at further-out levels of the hierarchy. So, for > + * example, if Ctype3 is the first Cache Type field with a > + * value of 0b000, the values of Ctype4 to Ctype7 must be > + * ignored. > + */ > + asm volatile("mrc p15, 1, %0, c0, c0, 1" : "=r" (cache_levels)); > + for (i = 0; i < 7; i++) > + if (((cache_levels >> (i*3)) & 7) == 0) > + break; > + /* Clear all higher bits. */ > + cache_levels &= (1 << (i*3))-1; > } > > /** _______________________________________________ kvmarm mailing list kvmarm@xxxxxxxxxxxxxxxxxxxxx https://lists.cs.columbia.edu/cucslists/listinfo/kvmarm