From patchwork Mon Mar 20 13:18:42 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ard Biesheuvel X-Patchwork-Id: 13181227 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 26810C7618D for ; Mon, 20 Mar 2023 13:20:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=BDCrs/gb22iw4UhLVRV3/lzR9lwZ4w8Q3B2M4FS8+kQ=; b=jmpfzLtZgObl9N SK1vad/HrCAXlzaF6WKAynYThzWBzmgOv6nJR8AEUuLYGbEThil4SHqvVUImUNTWEnfgAb8XMkLi1 9pyCL3lw61Tjrrtx662KIyYh/yj8Qw7tdPSn2fXU/Z/94aerQP2i1N4T2QhhZFkkaFMP7WkVvVm0x K7WFeSptf+BnNZcGAOvzvoWcX2mggfDfAt54WjIPKRMm6SIXsr5SErlzaBjN2zUUXBMoLfrZAweoD rgJy49d84tWDBNleDz1gn2HGNqUP+nBnJaDTBTZmX7KIkLnChp2olL19R1mzzm2USH8/qfByKa9fP 5ns+b3JTK9IyEdBWhIuw==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.96 #2 (Red Hat Linux)) id 1peFQN-0096Ej-33; Mon, 20 Mar 2023 13:19:43 +0000 Received: from ams.source.kernel.org ([145.40.68.75]) by bombadil.infradead.org with esmtps (Exim 4.96 #2 (Red Hat Linux)) id 1peFPt-0095wt-2j for linux-arm-kernel@lists.infradead.org; Mon, 20 Mar 2023 13:19:16 +0000 Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id 82A07B80E43; Mon, 20 Mar 2023 13:19:12 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id A9032C4339E; Mon, 20 Mar 2023 13:19:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1679318351; bh=oEDiohdIK94iSSzVWQy4CXAx+KzobQnkjmq1Vj77TNQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=l/L0TK+5WjCwgyIvu1fGDiRpGaBXBR/UNJn7y15v77HcdOLdxrfyDxh1ent1s97j4 nayuLHVrr7IwFUjDH/Z44EllxE5vOOaHW4Bd4bMNWvqssDmWrubDIQ/vPUENLUTWAp wbWfvqcL8uKIscXNqAZXqoC1x120gbjDtRCrj3kUTzn9d/7jWblFPhShUMxK2Q9/2T rM001F4NJQgH8wrF8gpwlBOawSBEYmSLVYlsUeczPa7aB9KJiOIa5wOOtu+FCQflGZ uZvFgx8J0PiHpoSDiDGccV/2uBGW+jRxoBWZ9ggVXT2PF0TePeNt7Iv/aQWIxdTOkc THQDmgBXwenTw== From: Ard Biesheuvel To: linux-arm-kernel@lists.infradead.org, linux@armlinux.org.uk Cc: Ard Biesheuvel , Frederic Weisbecker , Guenter Roeck , Peter Zijlstra , Linus Walleij , Arnd Bergmann Subject: [PATCH v4 09/12] ARM: vfp: Use undef hook for handling VFP exceptions Date: Mon, 20 Mar 2023 14:18:42 +0100 Message-Id: <20230320131845.3138015-10-ardb@kernel.org> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20230320131845.3138015-1-ardb@kernel.org> References: <20230320131845.3138015-1-ardb@kernel.org> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=8973; i=ardb@kernel.org; h=from:subject; bh=oEDiohdIK94iSSzVWQy4CXAx+KzobQnkjmq1Vj77TNQ=; b=owGbwMvMwCFmkMcZplerG8N4Wi2JIUUi1uCncEdwmt6EZSIFDFtubcnPMZnllVt57mveBBH9D Skyy7g7SlkYxDgYZMUUWQRm/3238/REqVrnWbIwc1iZQIYwcHEKwEQcHRgZFmtIpe1s69h//+77 mqcbd81+fyK3XO+4gGiOdZPiNoYlqYwMd18zls7j/Ptn3dds58P8gidmTl5g8JrtaN6lhZfmbj6 whxUA X-Developer-Key: i=ardb@kernel.org; a=openpgp; fpr=F43D03328115A198C90016883D200E9CA6329909 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20230320_061914_190702_0A4F17C5 X-CRM114-Status: GOOD ( 26.58 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Now that the VFP support code has been reimplemented as a C function that takes a struct pt_regs pointer and an opcode, we can use the existing undef_hook framework to deal with undef exceptions triggered by VFP instructions instead of having special handling in assembler. Signed-off-by: Ard Biesheuvel Reviewed-by: Linus Walleij --- arch/arm/kernel/entry-armv.S | 53 ---------------- arch/arm/vfp/Makefile | 2 +- arch/arm/vfp/entry.S | 31 ---------- arch/arm/vfp/vfpmodule.c | 65 ++++++++++---------- 4 files changed, 32 insertions(+), 119 deletions(-) diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index cae8e31ce2cbde41..b4586a3447822774 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -557,13 +557,6 @@ ENDPROC(__und_usr) * co-processor instructions. However, we have to watch out * for the ARM6/ARM7 SWI bug. * - * NEON is a special case that has to be handled here. Not all - * NEON instructions are co-processor instructions, so we have - * to make a special case of checking for them. Plus, there's - * five groups of them, so we have a table of mask/opcode pairs - * to check against, and if any match then we branch off into the - * NEON handler code. - * * Emulators may wish to make use of the following registers: * r0 = instruction opcode (32-bit ARM or two 16-bit Thumb) * r2 = PC value to resume execution after successful emulation @@ -575,25 +568,8 @@ ENDPROC(__und_usr) @ @ Fall-through from Thumb-2 __und_usr @ -#ifdef CONFIG_NEON - get_thread_info r10 @ get current thread - adr r6, .LCneon_thumb_opcodes - b 2f -#endif call_fpe: get_thread_info r10 @ get current thread -#ifdef CONFIG_NEON - adr r6, .LCneon_arm_opcodes -2: ldr r5, [r6], #4 @ mask value - ldr r7, [r6], #4 @ opcode bits matching in mask - cmp r5, #0 @ end mask? - beq 1f - and r8, r0, r5 - cmp r8, r7 @ NEON instruction? - bne 2b - b do_vfp @ let VFP handler handle this -1: -#endif tst r0, #0x08000000 @ only CDP/CPRT/LDC/STC have bit 27 tstne r0, #0x04000000 @ bit 26 set on both ARM and Thumb-2 reteq lr @@ -621,42 +597,13 @@ call_fpe: ret.w lr @ CP#7 ret.w lr @ CP#8 ret.w lr @ CP#9 -#ifdef CONFIG_VFP - W(b) do_vfp @ CP#10 (VFP) - W(b) do_vfp @ CP#11 (VFP) -#else ret.w lr @ CP#10 (VFP) ret.w lr @ CP#11 (VFP) -#endif ret.w lr @ CP#12 ret.w lr @ CP#13 ret.w lr @ CP#14 (Debug) ret.w lr @ CP#15 (Control) -#ifdef CONFIG_NEON - .align 6 - -.LCneon_arm_opcodes: - .word 0xfe000000 @ mask - .word 0xf2000000 @ opcode - - .word 0xff100000 @ mask - .word 0xf4000000 @ opcode - - .word 0x00000000 @ mask - .word 0x00000000 @ opcode - -.LCneon_thumb_opcodes: - .word 0xef000000 @ mask - .word 0xef000000 @ opcode - - .word 0xff100000 @ mask - .word 0xf9000000 @ opcode - - .word 0x00000000 @ mask - .word 0x00000000 @ opcode -#endif - do_fpe: add r10, r10, #TI_FPSTATE @ r10 = workspace ldr_va pc, fp_enter, tmp=r4 @ Call FP module USR entry point diff --git a/arch/arm/vfp/Makefile b/arch/arm/vfp/Makefile index 749901a72d6dc6c4..dfd64bc2b2fbdd06 100644 --- a/arch/arm/vfp/Makefile +++ b/arch/arm/vfp/Makefile @@ -8,4 +8,4 @@ # ccflags-y := -DDEBUG # asflags-y := -DDEBUG -obj-y += vfpmodule.o entry.o vfphw.o vfpsingle.o vfpdouble.o +obj-y += vfpmodule.o vfphw.o vfpsingle.o vfpdouble.o diff --git a/arch/arm/vfp/entry.S b/arch/arm/vfp/entry.S deleted file mode 100644 index 547c94c62cd3a66a..0000000000000000 --- a/arch/arm/vfp/entry.S +++ /dev/null @@ -1,31 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * linux/arch/arm/vfp/entry.S - * - * Copyright (C) 2004 ARM Limited. - * Written by Deep Blue Solutions Limited. - */ -#include -#include -#include -#include -#include -#include - -@ VFP entry point. -@ -@ r0 = instruction opcode (32-bit ARM or two 16-bit Thumb) -@ r2 = PC value to resume execution after successful emulation -@ r9 = normal "successful" return address -@ r10 = this threads thread_info structure -@ lr = unrecognised instruction return address -@ IRQs enabled. -@ -ENTRY(do_vfp) - mov r1, r0 @ pass trigger opcode via R1 - mov r0, sp @ pass struct pt_regs via R0 - bl vfp_support_entry @ dispatch the VFP exception - cmp r0, #0 @ handled successfully? - reteq r9 @ then use R9 as return address - ret lr @ pass to undef handler -ENDPROC(do_vfp) diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index 6db7d20c467ff843..5f65cf8375134af3 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c @@ -641,8 +641,6 @@ static int vfp_starting_cpu(unsigned int unused) return 0; } -#ifdef CONFIG_KERNEL_MODE_NEON - static int vfp_kmode_exception(struct pt_regs *regs, unsigned int instr) { /* @@ -666,14 +664,14 @@ static int vfp_kmode_exception(struct pt_regs *regs, unsigned int instr) } /* - * vfp_support_entry - Handle VFP exception from user mode + * vfp_support_entry - Handle VFP exception * * @regs: pt_regs structure holding the register state at exception entry * @trigger: The opcode of the instruction that triggered the exception * * Returns 0 if the exception was handled, or an error code otherwise. */ -asmlinkage int vfp_support_entry(struct pt_regs *regs, u32 trigger) +static int vfp_support_entry(struct pt_regs *regs, u32 trigger) { struct thread_info *ti = current_thread_info(); u32 fpexc; @@ -681,6 +679,9 @@ asmlinkage int vfp_support_entry(struct pt_regs *regs, u32 trigger) if (unlikely(!have_vfp)) return -ENODEV; + if (!user_mode(regs)) + return vfp_kmode_exception(regs, trigger); + local_bh_disable(); fpexc = fmrx(FPEXC); @@ -746,7 +747,6 @@ asmlinkage int vfp_support_entry(struct pt_regs *regs, u32 trigger) * replay the instruction that trapped. */ fmxr(FPEXC, fpexc); - regs->ARM_pc -= 4; } else { /* Check for synchronous or asynchronous exceptions */ if (!(fpexc & (FPEXC_EX | FPEXC_DEX))) { @@ -767,54 +767,47 @@ asmlinkage int vfp_support_entry(struct pt_regs *regs, u32 trigger) fpexc |= FPEXC_DEX; } } -bounce: VFP_bounce(trigger, fpexc, regs); +bounce: regs->ARM_pc += 4; + VFP_bounce(trigger, fpexc, regs); } local_bh_enable(); return 0; } -static struct undef_hook vfp_kmode_exception_hook[] = {{ +static struct undef_hook neon_support_hook[] = {{ .instr_mask = 0xfe000000, .instr_val = 0xf2000000, - .cpsr_mask = MODE_MASK | PSR_T_BIT, - .cpsr_val = SVC_MODE, - .fn = vfp_kmode_exception, + .cpsr_mask = PSR_T_BIT, + .cpsr_val = 0, + .fn = vfp_support_entry, }, { .instr_mask = 0xff100000, .instr_val = 0xf4000000, - .cpsr_mask = MODE_MASK | PSR_T_BIT, - .cpsr_val = SVC_MODE, - .fn = vfp_kmode_exception, + .cpsr_mask = PSR_T_BIT, + .cpsr_val = 0, + .fn = vfp_support_entry, }, { .instr_mask = 0xef000000, .instr_val = 0xef000000, - .cpsr_mask = MODE_MASK | PSR_T_BIT, - .cpsr_val = SVC_MODE | PSR_T_BIT, - .fn = vfp_kmode_exception, + .cpsr_mask = PSR_T_BIT, + .cpsr_val = PSR_T_BIT, + .fn = vfp_support_entry, }, { .instr_mask = 0xff100000, .instr_val = 0xf9000000, - .cpsr_mask = MODE_MASK | PSR_T_BIT, - .cpsr_val = SVC_MODE | PSR_T_BIT, - .fn = vfp_kmode_exception, -}, { - .instr_mask = 0x0c000e00, - .instr_val = 0x0c000a00, - .cpsr_mask = MODE_MASK, - .cpsr_val = SVC_MODE, - .fn = vfp_kmode_exception, + .cpsr_mask = PSR_T_BIT, + .cpsr_val = PSR_T_BIT, + .fn = vfp_support_entry, }}; -static int __init vfp_kmode_exception_hook_init(void) -{ - int i; +static struct undef_hook vfp_support_hook = { + .instr_mask = 0x0c000e00, + .instr_val = 0x0c000a00, + .fn = vfp_support_entry, +}; - for (i = 0; i < ARRAY_SIZE(vfp_kmode_exception_hook); i++) - register_undef_hook(&vfp_kmode_exception_hook[i]); - return 0; -} -subsys_initcall(vfp_kmode_exception_hook_init); +#ifdef CONFIG_KERNEL_MODE_NEON /* * Kernel-side NEON support functions @@ -919,8 +912,11 @@ static int __init vfp_init(void) * for NEON if the hardware has the MVFR registers. */ if (IS_ENABLED(CONFIG_NEON) && - (fmrx(MVFR1) & 0x000fff00) == 0x00011100) + (fmrx(MVFR1) & 0x000fff00) == 0x00011100) { elf_hwcap |= HWCAP_NEON; + for (int i = 0; i < ARRAY_SIZE(neon_support_hook); i++) + register_undef_hook(&neon_support_hook[i]); + } if (IS_ENABLED(CONFIG_VFPv3)) { u32 mvfr0 = fmrx(MVFR0); @@ -989,6 +985,7 @@ static int __init vfp_init(void) have_vfp = true; + register_undef_hook(&vfp_support_hook); thread_register_notifier(&vfp_notifier_block); vfp_pm_init();