From patchwork Thu Jan 12 11:26:04 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Martin X-Patchwork-Id: 18879 Received: (qmail 2213 invoked by alias); 12 Jan 2017 11:36:56 -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 1108 invoked by uid 89); 12 Jan 2017 11:36:48 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-5.1 required=5.0 tests=BAYES_00, RP_MATCHES_RCVD, SPF_PASS autolearn=ham version=3.3.2 spammy=Hx-languages-length:3123, Hx-spam-relays-external:ESMTPA X-Spam-User: qpsmtpd, 2 recipients X-HELO: foss.arm.com From: Dave Martin To: linux-arm-kernel@lists.infradead.org Cc: Ard Biesheuvel , Marc Zyngier , Alan Hayward , Christoffer Dall , linux-arch@vger.kernel.org, libc-alpha@sourceware.org, Florian Weimer , Joseph Myers , Szabolcs Nagy , Torvald Riegel , gdb@sourceware.org, Yao Qi Subject: [RFC PATCH 05/10] arm64/sve: Wire up vector length control prctl() calls Date: Thu, 12 Jan 2017 11:26:04 +0000 Message-Id: <1484220369-23970-6-git-send-email-Dave.Martin@arm.com> In-Reply-To: <1484220369-23970-1-git-send-email-Dave.Martin@arm.com> References: <1484220369-23970-1-git-send-email-Dave.Martin@arm.com> This patch provides implementation for the PR_SVE_SET_VL and PR_SVE_GET_VL prctls, which allow a task to set and query its vector length and associated control flags (although no flags are defined in this patch). Currently any thread can set its VL, allowing a mix of VLs within a single process -- this behaviour will be refined in susequent patches. Signed-off-by: Dave Martin --- arch/arm64/include/asm/fpsimd.h | 2 ++ arch/arm64/kernel/fpsimd.c | 65 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 65 insertions(+), 2 deletions(-) diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h index 22d09c0..1ec2363 100644 --- a/arch/arm64/include/asm/fpsimd.h +++ b/arch/arm64/include/asm/fpsimd.h @@ -103,6 +103,8 @@ extern void sve_save_state(void *state, u32 *pfpsr); extern void sve_load_state(void const *state, u32 const *pfpsr, unsigned long vq_minus_1); extern unsigned int sve_get_vl(void); +extern int sve_set_vector_length(struct task_struct *task, + unsigned long vl, unsigned long flags); /* * FPSIMD/SVE synchronisation helpers for ptrace: diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c index 54d7ed0..5f2c24a 100644 --- a/arch/arm64/kernel/fpsimd.c +++ b/arch/arm64/kernel/fpsimd.c @@ -493,17 +493,78 @@ void fpsimd_sync_from_fpsimd_zeropad(struct task_struct *task) __fpsimd_sync_from_fpsimd_zeropad(task, sve_vq_from_vl(vl)); } +int sve_set_vector_length(struct task_struct *task, + unsigned long vl, unsigned long flags) +{ + BUG_ON(task == current && preemptible()); + + if (flags) + return -EINVAL; /* No flags defined yet */ + + if (!sve_vl_valid(vl)) + return -EINVAL; + + if (vl > sve_max_vl) { + BUG_ON(!sve_vl_valid(sve_max_vl)); + vl = sve_max_vl; + } + + /* + * To ensure the FPSIMD bits of the SVE vector registers are preserved, + * write any live register state back to task_struct, and convert to a + * non-SVE thread. + */ + if (vl != task->thread.sve_vl) { + if (task == current && + !test_and_set_thread_flag(TIF_FOREIGN_FPSTATE)) + task_fpsimd_save(current); + + if (test_and_clear_tsk_thread_flag(task, TIF_SVE)) + task_sve_to_fpsimd(task); + + /* + * To avoid surprises, also zero out the SVE regs storage. + * This means that the P-regs, FFR and high bits of Z-regs + * will read as zero on next access: + */ + clear_sve_regs(task); + } + + task->thread.sve_vl = vl; + + fpsimd_flush_task_state(task); + + return 0; +} + /* PR_SVE_SET_VL */ int sve_set_task_vl(struct task_struct *task, unsigned long vector_length, unsigned long flags) { - return -EINVAL; + int ret; + + if (!(elf_hwcap & HWCAP_SVE)) + return -EINVAL; + + BUG_ON(task != current); + + preempt_disable(); + ret = sve_set_vector_length(current, vector_length, flags); + preempt_enable(); + + if (ret) + return ret; + + return task->thread.sve_vl; } /* PR_SVE_GET_VL */ int sve_get_task_vl(struct task_struct *task) { - return -EINVAL; + if (!(elf_hwcap & HWCAP_SVE)) + return -EINVAL; + + return task->thread.sve_vl; } #endif /* CONFIG_ARM64_SVE */