From patchwork Fri Nov 25 19:39:06 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Martin X-Patchwork-Id: 17908 Received: (qmail 7474 invoked by alias); 25 Nov 2016 19:41:20 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 7394 invoked by uid 89); 25 Nov 2016 19:41:19 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-4.9 required=5.0 tests=BAYES_00, RP_MATCHES_RCVD, SPF_PASS autolearn=ham version=3.3.2 spammy=saved, 3709, 4118, 2986 X-Spam-User: qpsmtpd, 2 recipients X-HELO: foss.arm.com From: Dave Martin To: linux-arm-kernel@lists.infradead.org Cc: Florian Weimer , libc-alpha@sourceware.org, gdb@sourceware.org Subject: [RFC PATCH 18/29] arm64/sve: signal: Restore FPSIMD/SVE state in rt_sigreturn Date: Fri, 25 Nov 2016 19:39:06 +0000 Message-Id: <1480102762-23647-19-git-send-email-Dave.Martin@arm.com> In-Reply-To: <1480102762-23647-1-git-send-email-Dave.Martin@arm.com> References: <1480102762-23647-1-git-send-email-Dave.Martin@arm.com> This patch adds the missing logic to restore the SVE state in rt_sigreturn. Because the FPSIMD and SVE state alias, this code replaces the existing fpsimd restore code when there is SVE state to restore. For Zn[127:0], the saved FPSIMD state in Vn takes precedence. Since __task_fpsimd_to_sve() is used to merge the FPSIMD and SVE state back together, and only for this purpose, we don't want it to zero out the SVE state -- hence delete the memset() from there. Signed-off-by: Dave Martin --- arch/arm64/kernel/fpsimd.c | 4 --- arch/arm64/kernel/signal.c | 87 ++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 76 insertions(+), 15 deletions(-) diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c index 4ef2e37..b1a8d3e 100644 --- a/arch/arm64/kernel/fpsimd.c +++ b/arch/arm64/kernel/fpsimd.c @@ -266,9 +266,6 @@ static void task_sve_to_fpsimd(struct task_struct *task __always_unused) { } void fpsimd_signal_preserve_current_state(void) { - WARN_ONCE(elf_hwcap & HWCAP_SVE, - "SVE state save/restore around signals doesn't work properly, expect userspace corruption!\n"); - fpsimd_preserve_current_state(); task_sve_to_fpsimd(current); } @@ -301,7 +298,6 @@ static void __task_fpsimd_to_sve(struct task_struct *task, unsigned int vq) struct fpsimd_state *fst = &task->thread.fpsimd_state; unsigned int i; - memset(sst, 0, sizeof(*sst)); for (i = 0; i < 32; ++i) sst->zregs[i][0] = fst->vregs[i]; } diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c index 038e7338..2697d09 100644 --- a/arch/arm64/kernel/signal.c +++ b/arch/arm64/kernel/signal.c @@ -211,6 +211,11 @@ static int restore_fpsimd_context(struct fpsimd_context __user *ctx) } +struct user_ctxs { + struct fpsimd_context __user *fpsimd; + struct sve_context __user *sve; +}; + #ifdef CONFIG_ARM64_SVE static int preserve_sve_context(struct sve_context __user *ctx) @@ -240,19 +245,68 @@ static int preserve_sve_context(struct sve_context __user *ctx) return err ? -EFAULT : 0; } +static int __restore_sve_fpsimd_context(struct user_ctxs *user, + unsigned int vl, unsigned int vq) +{ + int err; + struct fpsimd_sve_state(vq) *task_sve_regs = + __task_sve_state(current); + struct fpsimd_state fpsimd; + + if (vl != sve_get_vl()) + return -EINVAL; + + BUG_ON(SVE_SIG_REGS_SIZE(vq) > sizeof(*task_sve_regs)); + BUG_ON(round_up(SVE_SIG_REGS_SIZE(vq), 16) < sizeof(*task_sve_regs)); + BUG_ON(SVE_SIG_FFR_OFFSET(vq) - SVE_SIG_REGS_OFFSET != + (char *)&task_sve_regs->ffr - (char *)task_sve_regs); + err = __copy_from_user(task_sve_regs, + (char __user const *)user->sve + + SVE_SIG_REGS_OFFSET, + SVE_SIG_REGS_SIZE(vq)); + if (err) + return err; + + /* copy the FP and status/control registers */ + /* restore_sigframe() already checked that user->fpsimd != NULL. */ + err = __copy_from_user(fpsimd.vregs, user->fpsimd->vregs, + sizeof(fpsimd.vregs)); + __get_user_error(fpsimd.fpsr, &user->fpsimd->fpsr, err); + __get_user_error(fpsimd.fpcr, &user->fpsimd->fpcr, err); + + /* load the hardware registers from the fpsimd_state structure */ + if (!err) + fpsimd_update_current_state(&fpsimd); + + return err; +} + +static int restore_sve_fpsimd_context(struct user_ctxs *user) +{ + int err; + u16 vl, vq; + + err = __get_user(vl, &user->sve->vl); + if (err) + return err; + + if (!sve_vl_valid(vl)) + return -EINVAL; + + vq = sve_vq_from_vl(vl); + + return __restore_sve_fpsimd_context(user, vl, vq); +} + #else /* ! CONFIG_ARM64_SVE */ -/* Turn any non-optimised out attempt to use this into a link error: */ +/* Turn any non-optimised out attempts to use these into a link error: */ extern int preserve_sve_context(void __user *ctx); +extern int restore_sve_fpsimd_context(struct user_ctxs *user); #endif /* ! CONFIG_ARM64_SVE */ -struct user_ctxs { - struct fpsimd_context __user *fpsimd; - struct sve_context __user *sve; -}; - static int parse_user_sigframe(struct user_ctxs *user, struct rt_sigframe __user *sf) { @@ -316,6 +370,9 @@ static int parse_user_sigframe(struct user_ctxs *user, if (!IS_ENABLED(CONFIG_ARM64_SVE)) goto invalid; + if (!(elf_hwcap & HWCAP_SVE)) + goto invalid; + if (user->sve) goto invalid; @@ -375,9 +432,6 @@ static int parse_user_sigframe(struct user_ctxs *user, } done: - if (!user->fpsimd) - goto invalid; - return 0; invalid: @@ -411,8 +465,19 @@ static int restore_sigframe(struct pt_regs *regs, if (err == 0) err = parse_user_sigframe(&user, sf); - if (err == 0) - err = restore_fpsimd_context(user.fpsimd); + if (err == 0) { + if (!user.fpsimd) + return -EINVAL; + + if (user.sve) { + if (!IS_ENABLED(CONFIG_ARM64_SVE) || + !(elf_hwcap & HWCAP_SVE)) + return -EINVAL; + + err = restore_sve_fpsimd_context(&user); + } else + err = restore_fpsimd_context(user.fpsimd); + } return err; }