Factor demux_c15_get_val() and demux_c15_set_val() out of demux_c15_get() and demux_c15_set() so kernel callers can read and write demultiplexed coprocessor registers without going through userspace pointers.
Signed-off-by: Pasha Tatashin <[email protected]> --- arch/arm64/kvm/sys_regs.c | 48 +++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 44aae52c473d..b873ccf1ab14 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -5496,10 +5496,9 @@ id_to_sys_reg_desc(struct kvm_vcpu *vcpu, u64 id, return r; } -static int demux_c15_get(struct kvm_vcpu *vcpu, u64 id, void __user *uaddr) +static int demux_c15_get_val(struct kvm_vcpu *vcpu, u64 id, u32 *val) { - u32 val; - u32 __user *uval = uaddr; + u32 idx; /* Fail if we have unknown bits set. */ if (id & ~(KVM_REG_ARCH_MASK|KVM_REG_SIZE_MASK|KVM_REG_ARM_COPROC_MASK @@ -5510,21 +5509,34 @@ static int demux_c15_get(struct kvm_vcpu *vcpu, u64 id, void __user *uaddr) case KVM_REG_ARM_DEMUX_ID_CCSIDR: if (KVM_REG_SIZE(id) != 4) return -ENOENT; - val = (id & KVM_REG_ARM_DEMUX_VAL_MASK) + idx = (id & KVM_REG_ARM_DEMUX_VAL_MASK) >> KVM_REG_ARM_DEMUX_VAL_SHIFT; - if (val >= CSSELR_MAX) + if (idx >= CSSELR_MAX) return -ENOENT; - return put_user(get_ccsidr(vcpu, val), uval); + *val = get_ccsidr(vcpu, idx); + return 0; default: return -ENOENT; } } -static int demux_c15_set(struct kvm_vcpu *vcpu, u64 id, void __user *uaddr) +static int demux_c15_get(struct kvm_vcpu *vcpu, u64 id, void __user *uaddr) { - u32 val, newval; u32 __user *uval = uaddr; + u32 val; + int ret; + + ret = demux_c15_get_val(vcpu, id, &val); + if (!ret) + ret = put_user(val, uval); + + return ret; +} + +static int demux_c15_set_val(struct kvm_vcpu *vcpu, u64 id, u32 newval) +{ + u32 idx; /* Fail if we have unknown bits set. */ if (id & ~(KVM_REG_ARCH_MASK|KVM_REG_SIZE_MASK|KVM_REG_ARM_COPROC_MASK @@ -5535,20 +5547,28 @@ static int demux_c15_set(struct kvm_vcpu *vcpu, u64 id, void __user *uaddr) case KVM_REG_ARM_DEMUX_ID_CCSIDR: if (KVM_REG_SIZE(id) != 4) return -ENOENT; - val = (id & KVM_REG_ARM_DEMUX_VAL_MASK) + idx = (id & KVM_REG_ARM_DEMUX_VAL_MASK) >> KVM_REG_ARM_DEMUX_VAL_SHIFT; - if (val >= CSSELR_MAX) + if (idx >= CSSELR_MAX) return -ENOENT; - if (get_user(newval, uval)) - return -EFAULT; - - return set_ccsidr(vcpu, val, newval); + return set_ccsidr(vcpu, idx, newval); default: return -ENOENT; } } +static int demux_c15_set(struct kvm_vcpu *vcpu, u64 id, void __user *uaddr) +{ + u32 __user *uval = uaddr; + u32 newval; + + if (get_user(newval, uval)) + return -EFAULT; + + return demux_c15_set_val(vcpu, id, newval); +} + static u64 kvm_one_reg_to_id(const struct kvm_one_reg *reg) { switch(reg->id) { -- 2.55.0.1082.g2b9226bbc0-goog

