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


Reply via email to