csselr and ccsidr are treated as 64-bit values already elsewhere in the kernel. It also aligns well with the architecture extensions that allow 64-bit format for ccsidr. This patch upgrades the existing accesses to csselr and ccsidr from 32-bit to 64-bit in preparation to add support to those extensions. It also add dedicated KVM_REG_ARM_DEMUX_ID_EXT_CCSIDR demux register to handle 64-bit ccsidr in KVM. Cc: Christoffer Dall <christoffer.dall@xxxxxxxxxx> Cc: Marc Zyngier <marc.zyngier@xxxxxxx> Signed-off-by: Sudeep Holla <sudeep.holla@xxxxxxx> --- arch/arm64/include/uapi/asm/kvm.h | 1 + arch/arm64/kvm/sys_regs.c | 104 ++++++++++++++++++++++++++++---------- 2 files changed, 77 insertions(+), 28 deletions(-) v1->v2: - Added dependency on cpu_supports_ccsidr_64b_format(PATCH 1/3) - Added a new KVM_REG_ARM_DEMUX_ID_EXT_CCSIDR demux register id to support new 64bit CCSIDR diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h index 3051f86a9b5f..8aa18e65e6a5 100644 --- a/arch/arm64/include/uapi/asm/kvm.h +++ b/arch/arm64/include/uapi/asm/kvm.h @@ -161,6 +161,7 @@ struct kvm_arch_memory_slot { #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_ID_EXT_CCSIDR (0x01 << KVM_REG_ARM_DEMUX_ID_SHIFT) #define KVM_REG_ARM_DEMUX_VAL_MASK 0x00000000000000FF #define KVM_REG_ARM_DEMUX_VAL_SHIFT 0 diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 72656743b4cc..f9822ac6d9ab 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -58,15 +58,15 @@ */ /* 3 bits per cache level, as per CLIDR, but non-existent caches always 0 */ -static u32 cache_levels; +static u64 cache_levels; -/* CSSELR values; used to index KVM_REG_ARM_DEMUX_ID_CCSIDR */ +/* CSSELR values; used to index KVM_REG_ARM_DEMUX_ID_{EXT_,}CCSIDR */ #define CSSELR_MAX ((MAX_CACHE_LEVEL - 1) << 1) /* Which cache CCSIDR represents depends on CSSELR value. */ -static u32 get_ccsidr(u32 csselr) +static u64 get_ccsidr(u64 csselr) { - u32 ccsidr; + u64 ccsidr; /* Make sure noone else changes CSSELR during this! */ local_irq_disable(); @@ -1952,9 +1952,9 @@ static int set_invariant_sys_reg(u64 id, void __user *uaddr) return 0; } -static bool is_valid_cache(u32 val) +static bool is_valid_cache(u64 val) { - u32 level, ctype; + u64 level, ctype; if (val >= CSSELR_MAX) return false; @@ -1977,10 +1977,28 @@ static bool is_valid_cache(u32 val) } } +static int demux_ccsidr_validate_get(u64 id, int size, u64 *val) +{ + u64 cidx; + + if (KVM_REG_SIZE(id) != size) + return -ENOENT; + + cidx = (id & KVM_REG_ARM_DEMUX_VAL_MASK) + >> KVM_REG_ARM_DEMUX_VAL_SHIFT; + if (!is_valid_cache(cidx)) + return -ENOENT; + + *val = get_ccsidr(cidx); + return 0; +} + static int demux_c15_get(u64 id, void __user *uaddr) { - u32 val; - u32 __user *uval = uaddr; + int ret; + u64 val; + u32 __user *uval; + u64 __user *uval64; /* Fail if we have unknown bits set. */ if (id & ~(KVM_REG_ARCH_MASK|KVM_REG_SIZE_MASK|KVM_REG_ARM_COPROC_MASK @@ -1989,14 +2007,17 @@ static int demux_c15_get(u64 id, void __user *uaddr) 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); + ret = demux_ccsidr_validate_get(id, sizeof(*uval), &val); + if (ret) + return ret; + uval = uaddr; + return put_user(val, uval); + case KVM_REG_ARM_DEMUX_ID_EXT_CCSIDR: + ret = demux_ccsidr_validate_get(id, sizeof(*uval64), &val); + if (ret) + return ret; + uval64 = uaddr; + return put_user(val, uval64); default: return -ENOENT; } @@ -2004,8 +2025,10 @@ static int demux_c15_get(u64 id, void __user *uaddr) static int demux_c15_set(u64 id, void __user *uaddr) { - u32 val, newval; - u32 __user *uval = uaddr; + int ret; + u64 val, newval; + u32 __user *uval; + u64 __user *uval64; /* Fail if we have unknown bits set. */ if (id & ~(KVM_REG_ARCH_MASK|KVM_REG_SIZE_MASK|KVM_REG_ARM_COPROC_MASK @@ -2014,18 +2037,29 @@ static int demux_c15_set(u64 id, void __user *uaddr) 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; + ret = demux_ccsidr_validate_get(id, sizeof(*uval), &val); + if (ret) + return ret; + uval = uaddr; if (get_user(newval, uval)) return -EFAULT; /* This is also invariant: you can't change it. */ - if (newval != get_ccsidr(val)) + if (newval != val) + return -EINVAL; + return 0; + case KVM_REG_ARM_DEMUX_ID_EXT_CCSIDR: + ret = demux_ccsidr_validate_get(id, sizeof(*uval), &val); + if (ret) + return ret; + + uval64 = uaddr; + if (get_user(newval, uval64)) + return -EFAULT; + + /* This is also invariant: you can't change it. */ + if (newval != val) return -EINVAL; return 0; default: @@ -2086,12 +2120,10 @@ static unsigned int num_demux_regs(void) return count; } -static int write_demux_regids(u64 __user *uindices) +static int write_demux_ccsidr(u64 val, u64 __user *uindices) { - u64 val = KVM_REG_ARM64 | 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; @@ -2099,9 +2131,25 @@ static int write_demux_regids(u64 __user *uindices) return -EFAULT; uindices++; } + return 0; } +static int write_demux_regids(u64 __user *uindices) +{ + int ret; + u64 val = KVM_REG_ARM64 | KVM_REG_ARM_DEMUX; + + if (cpu_supports_ccsidr_64b_format()) + /* 64 bit extended CCSIDR */ + ret = write_demux_ccsidr(val | KVM_REG_ARM_DEMUX_ID_EXT_CCSIDR | + KVM_REG_SIZE_U64, uindices); + else + ret = write_demux_ccsidr(val | KVM_REG_ARM_DEMUX_ID_CCSIDR | + KVM_REG_SIZE_U32, uindices); + return ret; +} + static u64 sys_reg_to_index(const struct sys_reg_desc *reg) { return (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | -- 2.7.4 _______________________________________________ kvmarm mailing list kvmarm@xxxxxxxxxxxxxxxxxxxxx https://lists.cs.columbia.edu/mailman/listinfo/kvmarm