From patchwork Thu Sep 4 16:03:35 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Thompson X-Patchwork-Id: 4846901 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id E13199F390 for ; Thu, 4 Sep 2014 16:08:30 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 3F48B20265 for ; Thu, 4 Sep 2014 16:08:29 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id CD58F20251 for ; Thu, 4 Sep 2014 16:08:27 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1XPZWX-0008Qq-WC; Thu, 04 Sep 2014 16:04:38 +0000 Received: from mail-wi0-f175.google.com ([209.85.212.175]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1XPZWF-00088d-SU for linux-arm-kernel@lists.infradead.org; Thu, 04 Sep 2014 16:04:21 +0000 Received: by mail-wi0-f175.google.com with SMTP id ho1so1384629wib.2 for ; Thu, 04 Sep 2014 09:03:54 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=FPvE7s5NocZvG3qMm+bVMOEHqHXPyb2LVfkse+LCqz8=; b=HAjR2OrbXAVmlfXIKDOle2dkQAhmGY+9nItJMA6lKWEjNXixwZSX1UuYBuU9EkXvx8 1NCNglQWHi1J4AjtZFoxiG41wI2X3FsPS90odZ1Ch1fVyaz5oC8CA74PnrkFg0TKmKKj 3//pHRCh/wloJgwYV6tjSPweRS1mpfw02J+gkVkjrTfUFXuX4I8KjmERNMejCgInhzPy 6ebY+YXqMKPZAXdR35lNUZXYXBnuPA7EIV9K0P9EQD07w2foudGMpj/yux5Xlzg42TMz IDpQb6y/fxCYteqIpVWTgemOhpjChxJEJBm6cLh0tiXjiOpld2iS6Udvf1iGi3SV2fM6 1kwA== X-Gm-Message-State: ALoCoQlq/XWod9wz1Nlf3+t8YfTHUC8etQt/bMTbxtpTrldUrfbzYN+FHbZ0MxfhGxs3Rfjac1JH X-Received: by 10.194.174.202 with SMTP id bu10mr7448753wjc.70.1409846634700; Thu, 04 Sep 2014 09:03:54 -0700 (PDT) Received: from sundance.lan (cpc4-aztw19-0-0-cust157.18-1.cable.virginm.net. [82.33.25.158]) by mx.google.com with ESMTPSA id m9sm19841199wjz.35.2014.09.04.09.03.53 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 04 Sep 2014 09:03:53 -0700 (PDT) From: Daniel Thompson To: Russell King Subject: [PATCH v1 1/6] arm: fiq: Replace default FIQ handler Date: Thu, 4 Sep 2014 17:03:35 +0100 Message-Id: <1409846620-14542-2-git-send-email-daniel.thompson@linaro.org> X-Mailer: git-send-email 1.9.3 In-Reply-To: <1409846620-14542-1-git-send-email-daniel.thompson@linaro.org> References: <1409662853-29313-1-git-send-email-daniel.thompson@linaro.org> <1409846620-14542-1-git-send-email-daniel.thompson@linaro.org> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140904_090420_248012_1083E55C X-CRM114-Status: GOOD ( 21.39 ) X-Spam-Score: -0.7 (/) Cc: Daniel Thompson , linaro-kernel@lists.linaro.org, patches@linaro.org, Catalin Marinas , Nicolas Pitre , linux-kernel@vger.kernel.org, John Stultz , Thomas Gleixner , Sumit Semwal , linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-3.5 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_NONE, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This patch introduces a new default FIQ handler that is structured in a similar way to the existing ARM exception handler and result in the FIQ being handled by C code running on the SVC stack (despite this code run in the FIQ handler is subject to severe limitations with respect to locking making normal interaction with the kernel impossible). This default handler allows concepts that on x86 would be handled using NMIs to be realized on ARM. Credit: This patch is a near complete re-write of a patch originally provided by Anton Vorontsov. Today only a couple of small fragments survive, however without Anton's work to build from this patch would not exist. Signed-off-by: Daniel Thompson Cc: Russell King Cc: Nicolas Pitre Cc: Catalin Marinas --- arch/arm/kernel/entry-armv.S | 110 +++++++++++++++++++++++++++++++++++++++---- arch/arm/kernel/setup.c | 8 +++- arch/arm/kernel/traps.c | 26 ++++++++-- 3 files changed, 130 insertions(+), 14 deletions(-) diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 36276cd..03dc0e0 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -146,7 +146,7 @@ ENDPROC(__und_invalid) #define SPFIX(code...) #endif - .macro svc_entry, stack_hole=0 + .macro svc_entry, stack_hole=0, call_trace=1 UNWIND(.fnstart ) UNWIND(.save {r0 - pc} ) sub sp, sp, #(S_FRAME_SIZE + \stack_hole - 4) @@ -183,10 +183,35 @@ ENDPROC(__und_invalid) stmia r7, {r2 - r6} #ifdef CONFIG_TRACE_IRQFLAGS + .if \call_trace bl trace_hardirqs_off + .endif #endif .endm +@ +@ svc_exit_via_fiq - similar to svc_exit but switches to FIQ mode before exit +@ +@ This macro acts in a similar manner to svc_exit but switches to FIQ +@ mode to restore the final part of the register state. +@ +@ We cannot use the normal svc_exit procedure because that would +@ clobber spsr_svc (FIQ could be delivered during the first few instructions +@ of vector_swi meaning its contents have not been saved anywhere). +@ + .macro svc_exit_via_fiq, rpsr + + mov r0, sp + ldmib r0, {r1 - r14} @ abort is deadly from here onward (it will + @ clobber state restored below) + msr cpsr_c, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT + add r8, r0, #S_PC + ldr r9, [r0, #S_PSR] + msr spsr_cxsf, r9 + ldr r0, [r0, #S_R0] + ldmia r8, {pc}^ + .endm + .align 5 __dabt_svc: svc_entry @@ -295,6 +320,15 @@ __pabt_svc: ENDPROC(__pabt_svc) .align 5 +__fiq_svc: + svc_entry 0, 0 + mov r0, sp @ struct pt_regs *regs + bl handle_fiq_as_nmi + svc_exit_via_fiq r5 + UNWIND(.fnend ) +ENDPROC(__fiq_svc) + + .align 5 .LCcralign: .word cr_alignment #ifdef MULTI_DABORT @@ -305,6 +339,38 @@ ENDPROC(__pabt_svc) .word fp_enter /* + * Abort mode handlers + */ + +@ +@ Taking a FIQ in abort mode is similar to taking a FIQ in SVC mode +@ and reuses the same macros. However in abort mode we must also +@ save/restore lr_abt and spsr_abt to make nested aborts safe. +@ + .align 5 +__fiq_abt: + svc_entry 0, 0 + + msr cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT + mov r0, lr @ Save lr_abt + mrs r1, spsr @ Save spsr_abt, abort is now safe + msr cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT + push {r0 - r1} + + sub r0, sp, #8 @ struct pt_regs *regs + bl handle_fiq_as_nmi + + pop {r0 - r1} + msr cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT + mov lr, r0 @ Restore lr_abt, abort is unsafe + msr spsr_cxsf, r1 @ Restore spsr_abt + msr cpsr_c, #SVC_MODE | PSR_I_BIT | PSR_F_BIT + + svc_exit_via_fiq r5 + UNWIND(.fnend ) +ENDPROC(__fiq_svc) + +/* * User mode handlers * * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE @@ -683,6 +749,18 @@ ENTRY(ret_from_exception) ENDPROC(__pabt_usr) ENDPROC(ret_from_exception) + .align 5 +__fiq_usr: + usr_entry + kuser_cmpxchg_check + mov r0, sp @ struct pt_regs *regs + bl handle_fiq_as_nmi + get_thread_info tsk + mov why, #0 + b ret_to_user_from_irq + UNWIND(.fnend ) +ENDPROC(__fiq_usr) + /* * Register switch for ARMv3 and ARMv4 processors * r0 = previous task_struct, r1 = previous thread_info, r2 = next thread_info @@ -1118,17 +1196,29 @@ vector_addrexcptn: b vector_addrexcptn /*============================================================================= - * Undefined FIQs + * FIQ "NMI" handler *----------------------------------------------------------------------------- - * Enter in FIQ mode, spsr = ANY CPSR, lr = ANY PC - * MUST PRESERVE SVC SPSR, but need to switch to SVC mode to show our msg. - * Basically to switch modes, we *HAVE* to clobber one register... brain - * damage alert! I don't think that we can execute any code in here in any - * other mode than FIQ... Ok you can switch to another mode, but you can't - * get out of that mode without clobbering one register. + * Handle a FIQ using the SVC stack allowing FIQ act like NMI on x86 + * systems. */ -vector_fiq: - subs pc, lr, #4 + vector_stub fiq, FIQ_MODE, 4 + + .long __fiq_usr @ 0 (USR_26 / USR_32) + .long __fiq_svc @ 1 (FIQ_26 / FIQ_32) + .long __fiq_svc @ 2 (IRQ_26 / IRQ_32) + .long __fiq_svc @ 3 (SVC_26 / SVC_32) + .long __fiq_svc @ 4 + .long __fiq_svc @ 5 + .long __fiq_svc @ 6 + .long __fiq_abt @ 7 + .long __fiq_svc @ 8 + .long __fiq_svc @ 9 + .long __fiq_svc @ a + .long __fiq_svc @ b + .long __fiq_svc @ c + .long __fiq_svc @ d + .long __fiq_svc @ e + .long __fiq_svc @ f .globl vector_fiq_offset .equ vector_fiq_offset, vector_fiq diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 84db893d..c031063 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -133,6 +133,7 @@ struct stack { u32 irq[3]; u32 abt[3]; u32 und[3]; + u32 fiq[3]; } ____cacheline_aligned; #ifndef CONFIG_CPU_V7M @@ -470,7 +471,10 @@ void notrace cpu_init(void) "msr cpsr_c, %5\n\t" "add r14, %0, %6\n\t" "mov sp, r14\n\t" - "msr cpsr_c, %7" + "msr cpsr_c, %7\n\t" + "add r14, %0, %8\n\t" + "mov sp, r14\n\t" + "msr cpsr_c, %9" : : "r" (stk), PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE), @@ -479,6 +483,8 @@ void notrace cpu_init(void) "I" (offsetof(struct stack, abt[0])), PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE), "I" (offsetof(struct stack, und[0])), + PLC (PSR_F_BIT | PSR_I_BIT | FIQ_MODE), + "I" (offsetof(struct stack, fiq[0])), PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE) : "r14"); #endif diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index c8e4bb7..7912a9e 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -460,10 +461,29 @@ die_sig: arm_notify_die("Oops - undefined instruction", regs, &info, 0, 6); } -asmlinkage void do_unexp_fiq (struct pt_regs *regs) +/* + * Handle FIQ similarly to NMI on x86 systems. + * + * The runtime environment for NMIs is extremely restrictive + * (NMIs can pre-empt critical sections meaning almost all locking is + * forbidden) meaning this default FIQ handling must only be used in + * circumstances where non-maskability improves robustness, such as + * watchdog or debug logic. + * + * This handler is not appropriate for general purpose use in drivers + * platform code and can be overrideen using set_fiq_handler. + */ +asmlinkage void __exception_irq_entry handle_fiq_as_nmi(struct pt_regs *regs) { - printk("Hmm. Unexpected FIQ received, but trying to continue\n"); - printk("You may have a hardware problem...\n"); +#ifdef CONFIG_FIQ + struct pt_regs *old_regs = set_irq_regs(regs); + + nmi_enter(); + /* nop for now */ + nmi_exit(); + + set_irq_regs(old_regs); +#endif } /*