From patchwork Tue Aug 19 16:45:53 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Thompson X-Patchwork-Id: 35627 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-vc0-f198.google.com (mail-vc0-f198.google.com [209.85.220.198]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id B68F5202DD for ; Tue, 19 Aug 2014 16:46:40 +0000 (UTC) Received: by mail-vc0-f198.google.com with SMTP id le20sf20543160vcb.9 for ; Tue, 19 Aug 2014 09:46:40 -0700 (PDT) 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=0ftSDbQ6JjW1DRAqMR8ASXZslx8RdnZ0ycvj8SqjHhU=; b=QOFyuW0n1ekEQywxJFgHMTesG4WyLX8N+zgKsCKX4rgbS27wovLspYnU2UG8boyZTM K0nM1bzDf5TUkLJZNxatSMDDxsg4I4nzHmNqcsSR1/lwButuc/EE1GJtiKTTaSxFAKZs pY19DMuHJGQwXORjTnsqBMJGU6owWP6tjic/EjaurkDOFt0k7pklw2wH9MhVMfgTGKdv 6P2YW0q5T8C+gGfvt+lrUQ+pRjBJf5kB7R/yMKeKPIRsHQw/Vj6AEtytaIXgt5r9N3lD gEF2dMZo664ppTMPa2s5olsgEUUxosT/ZgPFEAtWDy1SVMehw7lFjNj2/GhVxWlbp/3h j66Q== X-Gm-Message-State: ALoCoQl2VkBCt3LTttct9tE/1xX2+X/UWoUC6USI9kfkAZh8yK3z5O9FyUr3rj69QCZUXh/ywQH1 X-Received: by 10.236.21.132 with SMTP id r4mr10881395yhr.2.1408466800443; Tue, 19 Aug 2014 09:46:40 -0700 (PDT) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.140.98.212 with SMTP id o78ls2828307qge.55.gmail; Tue, 19 Aug 2014 09:46:40 -0700 (PDT) X-Received: by 10.52.5.201 with SMTP id u9mr1093316vdu.85.1408466800364; Tue, 19 Aug 2014 09:46:40 -0700 (PDT) Received: from mail-vc0-f172.google.com (mail-vc0-f172.google.com [209.85.220.172]) by mx.google.com with ESMTPS id dz10si9117484vdb.57.2014.08.19.09.46.40 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 19 Aug 2014 09:46:40 -0700 (PDT) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.220.172 as permitted sender) client-ip=209.85.220.172; Received: by mail-vc0-f172.google.com with SMTP id im17so7736812vcb.31 for ; Tue, 19 Aug 2014 09:46:40 -0700 (PDT) X-Received: by 10.221.5.137 with SMTP id og9mr31456063vcb.18.1408466800259; Tue, 19 Aug 2014 09:46:40 -0700 (PDT) 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.221.37.5 with SMTP id tc5csp254333vcb; Tue, 19 Aug 2014 09:46:39 -0700 (PDT) X-Received: by 10.194.209.210 with SMTP id mo18mr12645853wjc.118.1408466798869; Tue, 19 Aug 2014 09:46:38 -0700 (PDT) Received: from mail-wg0-f42.google.com (mail-wg0-f42.google.com [74.125.82.42]) by mx.google.com with ESMTPS id uw5si31887277wjc.58.2014.08.19.09.46.38 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 19 Aug 2014 09:46:38 -0700 (PDT) Received-SPF: pass (google.com: domain of daniel.thompson@linaro.org designates 74.125.82.42 as permitted sender) client-ip=74.125.82.42; Received: by mail-wg0-f42.google.com with SMTP id l18so6574286wgh.1 for ; Tue, 19 Aug 2014 09:46:38 -0700 (PDT) X-Received: by 10.180.19.35 with SMTP id b3mr8071182wie.52.1408466797599; Tue, 19 Aug 2014 09:46:37 -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 gc8sm36225wic.3.2014.08.19.09.46.35 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 19 Aug 2014 09:46:36 -0700 (PDT) From: Daniel Thompson To: Russell King Cc: Daniel Thompson , linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, kgdb-bugreport@lists.sourceforge.net, patches@linaro.org, linaro-kernel@lists.linaro.org, John Stultz , Anton Vorontsov , Colin Cross , kernel-team@android.com, Rob Herring , Linus Walleij , Ben Dooks , Catalin Marinas , Dave Martin , Fabio Estevam , Frederic Weisbecker , Nicolas Pitre Subject: [PATCH v10 03/19] arm: fiq: Replace default FIQ handler Date: Tue, 19 Aug 2014 17:45:53 +0100 Message-Id: <1408466769-20004-4-git-send-email-daniel.thompson@linaro.org> X-Mailer: git-send-email 1.9.3 In-Reply-To: <1408466769-20004-1-git-send-email-daniel.thompson@linaro.org> References: <1408369264-14242-1-git-send-email-daniel.thompson@linaro.org> <1408466769-20004-1-git-send-email-daniel.thompson@linaro.org> X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: daniel.thompson@linaro.org X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.220.172 as permitted sender) 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 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/include/asm/fiq.h | 1 + arch/arm/kernel/entry-armv.S | 129 +++++++++++++++++++++++++++++++++++++++---- arch/arm/kernel/fiq.c | 17 ++++++ arch/arm/kernel/setup.c | 8 ++- 4 files changed, 144 insertions(+), 11 deletions(-) diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h index a25c952..175bfed 100644 --- a/arch/arm/include/asm/fiq.h +++ b/arch/arm/include/asm/fiq.h @@ -54,6 +54,7 @@ extern void disable_fiq(int fiq); extern int ack_fiq(int fiq); extern void eoi_fiq(int fiq); extern bool has_fiq(int fiq); +extern int register_fiq_nmi_notifier(struct notifier_block *nb); extern void fiq_register_mapping(int irq, struct fiq_chip *chip); /* helpers defined in fiqasm.S: */ diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 36276cd..ef64333 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -79,6 +79,15 @@ #endif .endm + .macro fiq_handler + ldr r1, =.LChandle_fiq + mov r0, sp + adr lr, BSYM(9998f) + ldr pc, [r1] +9998: + .endm + + #ifdef CONFIG_KPROBES .section .kprobes.text,"ax",%progbits #else @@ -146,7 +155,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 +192,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 +329,14 @@ __pabt_svc: ENDPROC(__pabt_svc) .align 5 +__fiq_svc: + svc_entry 0, 0 + fiq_handler + svc_exit_via_fiq r5 + UNWIND(.fnend ) +ENDPROC(__fiq_svc) + + .align 5 .LCcralign: .word cr_alignment #ifdef MULTI_DABORT @@ -303,6 +345,43 @@ ENDPROC(__pabt_svc) #endif .LCfp: .word fp_enter +.LChandle_fiq: +#ifdef CONFIG_FIQ + .word fiq_nmi_handler +#else + .word do_unexp_fiq +#endif + +/* + * 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} + + fiq_handler + + 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 @@ -683,6 +762,17 @@ ENTRY(ret_from_exception) ENDPROC(__pabt_usr) ENDPROC(ret_from_exception) + .align 5 +__fiq_usr: + usr_entry + kuser_cmpxchg_check + fiq_handler + 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 +1208,36 @@ 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. 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 inappropriate for high performance (fast) interrupt + * servicing and can be overridden using set_fiq_handler. */ -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/fiq.c b/arch/arm/kernel/fiq.c index 3ccaa8c..b2bd1c7 100644 --- a/arch/arm/kernel/fiq.c +++ b/arch/arm/kernel/fiq.c @@ -46,6 +46,7 @@ #include #include +#include #include #include #include @@ -64,6 +65,7 @@ static unsigned long no_fiq_insn; static int fiq_start = -1; static RADIX_TREE(fiq_data_tree, GFP_KERNEL); static DEFINE_MUTEX(fiq_data_mutex); +static ATOMIC_NOTIFIER_HEAD(fiq_nmi_chain); /* Default reacquire function * - we always relinquish FIQ control @@ -216,6 +218,21 @@ bool has_fiq(int fiq) } EXPORT_SYMBOL(has_fiq); +int register_fiq_nmi_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_register(&fiq_nmi_chain, nb); +} + +asmlinkage void __exception_irq_entry fiq_nmi_handler(struct pt_regs *regs) +{ + struct pt_regs *old_regs = set_irq_regs(regs); + + nmi_enter(); + atomic_notifier_call_chain(&fiq_nmi_chain, (unsigned long)regs, NULL); + nmi_exit(); + set_irq_regs(old_regs); +} + EXPORT_SYMBOL(set_fiq_handler); EXPORT_SYMBOL(__set_fiq_regs); /* defined in fiqasm.S */ EXPORT_SYMBOL(__get_fiq_regs); /* defined in fiqasm.S */ 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