From patchwork Fri Dec 20 16:48:43 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: vkamensky X-Patchwork-Id: 22685 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-pa0-f70.google.com (mail-pa0-f70.google.com [209.85.220.70]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id D0094202AE for ; Fri, 20 Dec 2013 16:49:21 +0000 (UTC) Received: by mail-pa0-f70.google.com with SMTP id fa1sf7230824pad.1 for ; Fri, 20 Dec 2013 08:49:21 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:delivered-to:from:to:cc:subject :date:message-id:in-reply-to:references:x-original-sender :x-original-authentication-results:precedence:mailing-list:list-id :list-post:list-help:list-archive:list-unsubscribe; bh=cz3JutXkUK+IW8ClPJR4QOOqAVCWBWnQg4cxdHbqwvs=; b=l1accHqePuelFei6rKZyzwOAMEFXEaux+ug6HrYXME4mYv/OLS6RFWP2QcwO2Gfk/H 1HDcFxyqYRJR5j1Ml+ce/EJCyZrmx1xBNtNVNW57gTVScsVbU5llqKO3vXQ7EO+lJSDu IN5029uZa7a+zcizir43PDPt9btOaqaglzYl/OZPKYqr2oedqsD1eyBhIMpxuMyszeRH IeJmDFJG77He/NoR5Vnjm2mWHHi0jCtfNJ87Py7QafI5OA3+utk5TbknCcHRvx9Vjx30 8fPbbelfVGvm6gOYt5XZeX3FRDimtB3duoi/6p02uBfLhiklg7EIRW627DpUJq9SA1uc mqkA== X-Gm-Message-State: ALoCoQlD4Sa4er4rqSavtMaWVDVYuTRg9t6Lo+YHWOlIMKZ+cYjQw/MmIkl/Ky3UnxVfyFzMJmep X-Received: by 10.66.172.79 with SMTP id ba15mr3951394pac.26.1387558160984; Fri, 20 Dec 2013 08:49:20 -0800 (PST) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.49.128.41 with SMTP id nl9ls810276qeb.56.gmail; Fri, 20 Dec 2013 08:49:20 -0800 (PST) X-Received: by 10.52.244.49 with SMTP id xd17mr624003vdc.26.1387558160805; Fri, 20 Dec 2013 08:49:20 -0800 (PST) Received: from mail-vc0-f177.google.com (mail-vc0-f177.google.com [209.85.220.177]) by mx.google.com with ESMTPS id uw4si1631795vec.39.2013.12.20.08.49.20 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Fri, 20 Dec 2013 08:49:20 -0800 (PST) Received-SPF: neutral (google.com: 209.85.220.177 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=209.85.220.177; Received: by mail-vc0-f177.google.com with SMTP id hq11so1511314vcb.22 for ; Fri, 20 Dec 2013 08:49:20 -0800 (PST) X-Received: by 10.58.146.71 with SMTP id ta7mr549387veb.23.1387558160677; Fri, 20 Dec 2013 08:49:20 -0800 (PST) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patches@linaro.org Received: by 10.59.13.131 with SMTP id ey3csp75247ved; Fri, 20 Dec 2013 08:49:20 -0800 (PST) X-Received: by 10.66.230.233 with SMTP id tb9mr9704664pac.38.1387558159676; Fri, 20 Dec 2013 08:49:19 -0800 (PST) Received: from mail-pd0-f182.google.com (mail-pd0-f182.google.com [209.85.192.182]) by mx.google.com with ESMTPS id jv8si5670913pbc.186.2013.12.20.08.49.19 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Fri, 20 Dec 2013 08:49:19 -0800 (PST) Received-SPF: neutral (google.com: 209.85.192.182 is neither permitted nor denied by best guess record for domain of victor.kamensky@linaro.org) client-ip=209.85.192.182; Received: by mail-pd0-f182.google.com with SMTP id v10so2728645pde.41 for ; Fri, 20 Dec 2013 08:49:19 -0800 (PST) X-Received: by 10.66.150.41 with SMTP id uf9mr9792932pab.108.1387558159214; Fri, 20 Dec 2013 08:49:19 -0800 (PST) Received: from kamensky-w530.hsd1.ca.comcast.net (c-24-6-79-41.hsd1.ca.comcast.net. [24.6.79.41]) by mx.google.com with ESMTPSA id nw11sm20120833pab.13.2013.12.20.08.49.17 for (version=TLSv1.2 cipher=AES128-GCM-SHA256 bits=128/128); Fri, 20 Dec 2013 08:49:18 -0800 (PST) From: Victor Kamensky To: linux-arm-kernel@lists.infradead.org, kvmarm@lists.cs.columbia.edu, marc.zyngier@arm.com, christoffer.dall@linaro.org, ben.dooks@codethink.co.uk Cc: rmk@arm.linux.org.uk, will.deacon@arm.com, Dave.Martin@arm.com, andre.przywara@linaro.org, taras.kondratiuk@linaro.org, patches@linaro.org, linaro-kernel@lists.linaro.org, Victor Kamensky Subject: [PATCH REPOST 3/5] ARM: kvm one_reg coproc set and get BE fixes Date: Fri, 20 Dec 2013 08:48:43 -0800 Message-Id: <1387558125-3460-4-git-send-email-victor.kamensky@linaro.org> X-Mailer: git-send-email 1.8.1.4 In-Reply-To: <1387558125-3460-1-git-send-email-victor.kamensky@linaro.org> References: <1387558125-3460-1-git-send-email-victor.kamensky@linaro.org> X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: victor.kamensky@linaro.org X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.220.177 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Precedence: list Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org List-ID: X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , This patch fixes issue of reading and writing ARM V7 registers values from/to user land. Existing code was designed to work only in LE case. struct kvm_one_reg ------------------ registers value passed through kvm_one_reg structure. It is used by KVM_SET_ONE_REG, KVM_GET_ONE_REG ioctls. Note by looking at structure itself we cannot tell what is size of register. Note that structure carries address of user memory, 'addr' where register should be read or written Setting register (from user-land to kvm) ---------------------------------------- kvm_arm_set_reg takes vcpu and pointer to struct kvm_one_reg which already read from user space kvm_arm_set_reg calls set_core_reg or kvm_arm_coproc_set_reg set_core_reg deals only with 4 bytes registers, it just reads 4 bytes from user space and store it properly into vcpu->arch.regs kvm_arm_coproc_set_reg deals with registers of different size. At certain point code reaches phase where it retrieves description of register by id and it knows register size, which could be either 4 or 8 bytes. Kernel code is ready to read values from user space, but destination type may vary. It could be pointer to 32 bit integer or it could be pointer to 64 bit integer. And all possible permutation of size and destination pointer are possible. Depending on destination pointer type, 4 bytes or 8 bytes, two new helper functions are introduced - reg_from_user32 and reg_from_user64. They are used instead of reg_from_user function which could work only in LE case. Size sizeof(*DstInt) Function used to read from user 4 4 reg_from_user32 8 4 reg_from_user32 - read two registers 4 8 reg_from_user64 - need special handling for BE 8 8 reg_from_user64 Getting register (to user-land from kvm) ---------------------------------------- Situation with reading registers is similar to writing. Integer pointer type of register to be copied could be 4 or 8 bytes. And size passed in struct kvm_one_reg could be 4 or 8. And any permutation is possible. Depending on src pointer type, 4 bytes or 8 bytes, two new helper functions are introduced - reg_from_user32 and reg_to_user64. They are used instead of reg_to_user function, which could work only in LE case. Size sizeof(*SrcInt) Function used to write to user 4 4 reg_to_user32 8 4 reg_to_user32 - writes two registers 4 8 reg_to_user64 - need special handleing for BE 8 8 reg_to_user64 Note code does assume that it can only deals with 4 or 8 byte registers. Signed-off-by: Victor Kamensky --- arch/arm/kvm/coproc.c | 94 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 69 insertions(+), 25 deletions(-) diff --git a/arch/arm/kvm/coproc.c b/arch/arm/kvm/coproc.c index 78c0885..64b2b94 100644 --- a/arch/arm/kvm/coproc.c +++ b/arch/arm/kvm/coproc.c @@ -634,17 +634,61 @@ static struct coproc_reg invariant_cp15[] = { { CRn( 0), CRm( 0), Op1( 1), Op2( 7), is32, NULL, get_AIDR }, }; -static int reg_from_user(void *val, const void __user *uaddr, u64 id) +static int reg_from_user64(u64 *val, const void __user *uaddr, u64 id) +{ + unsigned long regsize = KVM_REG_SIZE(id); + union { + u32 word; + u64 dword; + } tmp = {0}; + + if (copy_from_user(&tmp, uaddr, regsize) != 0) + return -EFAULT; + + switch (regsize) { + case 4: + *val = tmp.word; + break; + case 8: + *val = tmp.dword; + break; + } + return 0; +} + +/* Note it may really copy two u32 registers */ +static int reg_from_user32(u32 *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) return -EFAULT; return 0; } -static int reg_to_user(void __user *uaddr, const void *val, u64 id) +static int reg_to_user64(void __user *uaddr, const u64 *val, u64 id) +{ + unsigned long regsize = KVM_REG_SIZE(id); + union { + u32 word; + u64 dword; + } tmp; + + switch (regsize) { + case 4: + tmp.word = *val; + break; + case 8: + tmp.dword = *val; + break; + } + + if (copy_to_user(uaddr, &tmp, regsize) != 0) + return -EFAULT; + return 0; +} + +/* Note it may really copy two u32 registers */ +static int reg_to_user32(void __user *uaddr, const u32 *val, u64 id) { - /* This Just Works because we are little endian. */ if (copy_to_user(uaddr, val, KVM_REG_SIZE(id)) != 0) return -EFAULT; return 0; @@ -662,7 +706,7 @@ static int get_invariant_cp15(u64 id, void __user *uaddr) if (!r) return -ENOENT; - return reg_to_user(uaddr, &r->val, id); + return reg_to_user64(uaddr, &r->val, id); } static int set_invariant_cp15(u64 id, void __user *uaddr) @@ -678,7 +722,7 @@ static int set_invariant_cp15(u64 id, void __user *uaddr) if (!r) return -ENOENT; - err = reg_from_user(&val, uaddr, id); + err = reg_from_user64(&val, uaddr, id); if (err) return err; @@ -846,7 +890,7 @@ static int vfp_get_reg(const struct kvm_vcpu *vcpu, u64 id, void __user *uaddr) if (vfpid < num_fp_regs()) { if (KVM_REG_SIZE(id) != 8) return -ENOENT; - return reg_to_user(uaddr, &vcpu->arch.vfp_guest.fpregs[vfpid], + return reg_to_user64(uaddr, &vcpu->arch.vfp_guest.fpregs[vfpid], id); } @@ -856,22 +900,22 @@ static int vfp_get_reg(const struct kvm_vcpu *vcpu, u64 id, void __user *uaddr) switch (vfpid) { case KVM_REG_ARM_VFP_FPEXC: - return reg_to_user(uaddr, &vcpu->arch.vfp_guest.fpexc, id); + return reg_to_user32(uaddr, &vcpu->arch.vfp_guest.fpexc, id); case KVM_REG_ARM_VFP_FPSCR: - return reg_to_user(uaddr, &vcpu->arch.vfp_guest.fpscr, id); + return reg_to_user32(uaddr, &vcpu->arch.vfp_guest.fpscr, id); case KVM_REG_ARM_VFP_FPINST: - return reg_to_user(uaddr, &vcpu->arch.vfp_guest.fpinst, id); + return reg_to_user32(uaddr, &vcpu->arch.vfp_guest.fpinst, id); case KVM_REG_ARM_VFP_FPINST2: - return reg_to_user(uaddr, &vcpu->arch.vfp_guest.fpinst2, id); + return reg_to_user32(uaddr, &vcpu->arch.vfp_guest.fpinst2, id); case KVM_REG_ARM_VFP_MVFR0: val = fmrx(MVFR0); - return reg_to_user(uaddr, &val, id); + return reg_to_user32(uaddr, &val, id); case KVM_REG_ARM_VFP_MVFR1: val = fmrx(MVFR1); - return reg_to_user(uaddr, &val, id); + return reg_to_user32(uaddr, &val, id); case KVM_REG_ARM_VFP_FPSID: val = fmrx(FPSID); - return reg_to_user(uaddr, &val, id); + return reg_to_user32(uaddr, &val, id); default: return -ENOENT; } @@ -890,8 +934,8 @@ static int vfp_set_reg(struct kvm_vcpu *vcpu, u64 id, const void __user *uaddr) if (vfpid < num_fp_regs()) { if (KVM_REG_SIZE(id) != 8) return -ENOENT; - return reg_from_user(&vcpu->arch.vfp_guest.fpregs[vfpid], - uaddr, id); + return reg_from_user64(&vcpu->arch.vfp_guest.fpregs[vfpid], + uaddr, id); } /* FP control registers are all 32 bit. */ @@ -900,28 +944,28 @@ static int vfp_set_reg(struct kvm_vcpu *vcpu, u64 id, const void __user *uaddr) switch (vfpid) { case KVM_REG_ARM_VFP_FPEXC: - return reg_from_user(&vcpu->arch.vfp_guest.fpexc, uaddr, id); + return reg_from_user32(&vcpu->arch.vfp_guest.fpexc, uaddr, id); case KVM_REG_ARM_VFP_FPSCR: - return reg_from_user(&vcpu->arch.vfp_guest.fpscr, uaddr, id); + return reg_from_user32(&vcpu->arch.vfp_guest.fpscr, uaddr, id); case KVM_REG_ARM_VFP_FPINST: - return reg_from_user(&vcpu->arch.vfp_guest.fpinst, uaddr, id); + return reg_from_user32(&vcpu->arch.vfp_guest.fpinst, uaddr, id); case KVM_REG_ARM_VFP_FPINST2: - return reg_from_user(&vcpu->arch.vfp_guest.fpinst2, uaddr, id); + return reg_from_user32(&vcpu->arch.vfp_guest.fpinst2, uaddr, id); /* These are invariant. */ case KVM_REG_ARM_VFP_MVFR0: - if (reg_from_user(&val, uaddr, id)) + if (reg_from_user32(&val, uaddr, id)) return -EFAULT; if (val != fmrx(MVFR0)) return -EINVAL; return 0; case KVM_REG_ARM_VFP_MVFR1: - if (reg_from_user(&val, uaddr, id)) + if (reg_from_user32(&val, uaddr, id)) return -EFAULT; if (val != fmrx(MVFR1)) return -EINVAL; return 0; case KVM_REG_ARM_VFP_FPSID: - if (reg_from_user(&val, uaddr, id)) + if (reg_from_user32(&val, uaddr, id)) return -EFAULT; if (val != fmrx(FPSID)) return -EINVAL; @@ -968,7 +1012,7 @@ int kvm_arm_coproc_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) return get_invariant_cp15(reg->id, uaddr); /* Note: copies two regs if size is 64 bit. */ - return reg_to_user(uaddr, &vcpu->arch.cp15[r->reg], reg->id); + return reg_to_user32(uaddr, &vcpu->arch.cp15[r->reg], reg->id); } int kvm_arm_coproc_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) @@ -987,7 +1031,7 @@ int kvm_arm_coproc_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) return set_invariant_cp15(reg->id, uaddr); /* Note: copies two regs if size is 64 bit */ - return reg_from_user(&vcpu->arch.cp15[r->reg], uaddr, reg->id); + return reg_from_user32(&vcpu->arch.cp15[r->reg], uaddr, reg->id); } static unsigned int num_demux_regs(void)