Received: by 2002:ac0:a594:0:0:0:0:0 with SMTP id m20-v6csp3274412imm; Fri, 25 May 2018 02:53:14 -0700 (PDT) X-Google-Smtp-Source: AB8JxZr+jaCMO/IM0kZmo4mzkM2HxnlEeiGKlHREWlUt//eDXdjq+RAwqC3izU+MjMA9/V+zCPTU X-Received: by 2002:a17:902:7686:: with SMTP id m6-v6mr1899244pll.340.1527241994836; Fri, 25 May 2018 02:53:14 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1527241994; cv=none; d=google.com; s=arc-20160816; b=DwgD4NqCker+wPZ89gy/toP7vDCSzhtqG3EMcRVyQCdLEl3Q9hN1DoU+LoeHO4D91p kyrkGX1gVoCbm98tdl44A3oxbM6Jf4OOE5E8odsG85NLQZCv3aQj/ywQRm9YGIlIto7z MgwwzsEgT4vs5VapdGBLU6q/S7uxLqmTcUmIJAQJqZqk6/ExNTNhoVcQq84AUfmAlkb7 GusOSMiOvfrMjl/Zgzn7tUekf1zII78Z0tThQzXW/9C5MAu1EQuBJTcoxxoZGUX/nCaM w7ogvP0GUtMZSj2CKY4DF63QJ7MzMcVfTogVLYagkX/NvWOZdx+ou41icA7bjZOWXgAl O5Xg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:arc-authentication-results; bh=Y3uSVuHfKlHNO2VCwDB9vCVHuZAn/Xs1lIvH6In5c2g=; b=KfWcPN5FMFECtapGpbF65GnbxZZH3+8mzDG4qK0cgKacSKWiuR8JJerFDQzeidNVIN Yldy8HzKrYZI5wrHZJUL2C86QP8GaYoYBo4U77r9HlGtuU44fUGRayNVscLH8t29Z7dl EsxMHGdFH/SGHo7ez3KK7+zvw4bqhXVaxVyhe2IRGsukGTTniiQCjZ2RvyQ3DBtE1dYG HezLypEyawGKksVQt+Gt3nONA9Sr3d5mLkj+MsLONq3kRoU9aeesQ36sckeF0MFQW9og /VQvSsqi5X6t7NeyOWAPLiCJqsp5o2H6jsSCmlkGdT4I5Egqc9/8afNkmr0JM9SMVCnC 8Ehg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id j28-v6si23567401pfe.337.2018.05.25.02.53.00; Fri, 25 May 2018 02:53:14 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S966288AbeEYJvB (ORCPT + 99 others); Fri, 25 May 2018 05:51:01 -0400 Received: from usa-sjc-mx-foss1.foss.arm.com ([217.140.101.70]:57670 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S966147AbeEYJuz (ORCPT ); Fri, 25 May 2018 05:50:55 -0400 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id D62101688; Fri, 25 May 2018 02:50:54 -0700 (PDT) Received: from e112298-lin.cambridge.arm.com (usa-sjc-imap-foss1.foss.arm.com [10.72.51.249]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 8B17D3F25D; Fri, 25 May 2018 02:50:52 -0700 (PDT) From: Julien Thierry To: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org, daniel.thompson@linaro.org, joel@joelfernandes.org, marc.zyngier@arm.com, mark.rutland@arm.com, christoffer.dall@arm.com, james.morse@arm.com, catalin.marinas@arm.com, will.deacon@arm.com, Julien Thierry , Russell King , Thomas Gleixner , Jason Cooper Subject: [PATCH v4 24/26] irqchip/gic-v3: Add base support for pseudo-NMI Date: Fri, 25 May 2018 10:49:30 +0100 Message-Id: <1527241772-48007-25-git-send-email-julien.thierry@arm.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1527241772-48007-1-git-send-email-julien.thierry@arm.com> References: <1527241772-48007-1-git-send-email-julien.thierry@arm.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Provide a higher priority to be used for pseudo-NMIs. When such an interrupt is received, enter the NMI state and prevent other NMIs to be raised. When returning from a pseudo-NMI, skip preemption and tracing if the interrupted context has interrupts disabled. Signed-off-by: Julien Thierry Cc: Russell King Cc: Catalin Marinas Cc: Will Deacon Cc: Thomas Gleixner Cc: Jason Cooper Cc: Marc Zyngier --- arch/arm/include/asm/arch_gicv3.h | 6 ++++++ arch/arm64/include/asm/arch_gicv3.h | 6 ++++++ arch/arm64/kernel/entry.S | 43 +++++++++++++++++++++++++++++++++++++ drivers/irqchip/irq-gic-v3.c | 41 +++++++++++++++++++++++++++++++++++ 4 files changed, 96 insertions(+) diff --git a/arch/arm/include/asm/arch_gicv3.h b/arch/arm/include/asm/arch_gicv3.h index b39d620..1ed0476 100644 --- a/arch/arm/include/asm/arch_gicv3.h +++ b/arch/arm/include/asm/arch_gicv3.h @@ -374,5 +374,11 @@ static inline void gic_start_pmr_masking(void) WARN_ON(true); } +static inline void gic_set_nmi_active(void) +{ + /* Should not get called */ + WARN_ON(true); +} + #endif /* !__ASSEMBLY__ */ #endif /* !__ASM_ARCH_GICV3_H */ diff --git a/arch/arm64/include/asm/arch_gicv3.h b/arch/arm64/include/asm/arch_gicv3.h index 23c88ac0..3196cf1 100644 --- a/arch/arm64/include/asm/arch_gicv3.h +++ b/arch/arm64/include/asm/arch_gicv3.h @@ -166,5 +166,11 @@ static inline void gic_start_pmr_masking(void) asm volatile ("msr daifclr, #2" : : : "memory"); } +/* Notify an NMI is active, blocking other NMIs */ +static inline void gic_set_nmi_active(void) +{ + asm volatile ("msr daifset, #2" : : : "memory"); +} + #endif /* __ASSEMBLY__ */ #endif /* __ASM_ARCH_GICV3_H */ diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index f56f27e..0d0c829 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -391,6 +391,16 @@ alternative_insn eret, nop, ARM64_UNMAP_KERNEL_AT_EL0 mov sp, x19 .endm + /* Should be checked on return from irq handlers */ + .macro branch_if_was_nmi, tmp, target + alternative_if ARM64_HAS_IRQ_PRIO_MASKING + mrs \tmp, daif + alternative_else + mov \tmp, #0 + alternative_endif + tbnz \tmp, #7, \target // Exiting an NMI + .endm + /* * These are the registers used in the syscall handler, and allow us to * have in theory up to 7 arguments to a function - x0 to x6. @@ -611,12 +621,30 @@ ENDPROC(el1_sync) el1_irq: kernel_entry 1 enable_da_f + #ifdef CONFIG_TRACE_IRQFLAGS +#ifdef CONFIG_USE_ICC_SYSREGS_FOR_IRQFLAGS + ldr x20, [sp, #S_PMR_SAVE] + /* Irqs were disabled, don't trace */ + tbz x20, ICC_PMR_EL1_EN_SHIFT, 1f +#endif bl trace_hardirqs_off +1: #endif irq_handler +#ifdef CONFIG_USE_ICC_SYSREGS_FOR_IRQFLAGS + /* + * Irqs were disabled, we have an nmi. + * We might have interrupted a context with interrupt disabled that set + * NEED_RESCHED flag. + * Skip preemption and irq tracing if needed. + */ + tbz x20, ICC_PMR_EL1_EN_SHIFT, untraced_irq_exit + branch_if_was_nmi x0, skip_preempt +#endif + #ifdef CONFIG_PREEMPT ldr w24, [tsk, #TSK_TI_PREEMPT] // get preempt count cbnz w24, 1f // preempt count != 0 @@ -625,9 +653,13 @@ el1_irq: bl el1_preempt 1: #endif + +skip_preempt: #ifdef CONFIG_TRACE_IRQFLAGS bl trace_hardirqs_on #endif + +untraced_irq_exit: kernel_exit 1 ENDPROC(el1_irq) @@ -858,6 +890,9 @@ el0_irq_naked: #ifdef CONFIG_TRACE_IRQFLAGS bl trace_hardirqs_on #endif + + branch_if_was_nmi x2, nmi_ret_to_user + b ret_to_user ENDPROC(el0_irq) @@ -1353,3 +1388,11 @@ alternative_else_nop_endif ENDPROC(__sdei_asm_handler) NOKPROBE(__sdei_asm_handler) #endif /* CONFIG_ARM_SDE_INTERFACE */ + +/* + * NMI return path to EL0 + */ +nmi_ret_to_user: + ldr x1, [tsk, #TSK_TI_FLAGS] + b finish_ret_to_user +ENDPROC(nmi_ret_to_user) diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index b144f73..4be5996 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -41,6 +41,8 @@ #include "irq-gic-common.h" +#define GICD_INT_NMI_PRI 0xa0 + struct redist_region { void __iomem *redist_base; phys_addr_t phys_base; @@ -253,6 +255,12 @@ static inline bool arch_uses_gic_prios(void) return IS_ENABLED(CONFIG_USE_ICC_SYSREGS_FOR_IRQFLAGS); } +static inline bool gic_supports_nmi(void) +{ + return arch_uses_gic_prios() + && static_branch_likely(&have_non_secure_prio_view); +} + static int gic_irq_set_irqchip_state(struct irq_data *d, enum irqchip_irq_state which, bool val) { @@ -371,6 +379,20 @@ static u64 gic_mpidr_to_affinity(unsigned long mpidr) return aff; } +static void do_handle_nmi(unsigned int hwirq, struct pt_regs *regs) +{ + struct pt_regs *old_regs = set_irq_regs(regs); + unsigned int irq; + + nmi_enter(); + + irq = irq_find_mapping(gic_data.domain, hwirq); + generic_handle_irq(irq); + + nmi_exit(); + set_irq_regs(old_regs); +} + static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs) { u32 irqnr; @@ -386,6 +408,23 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs if (likely(irqnr > 15 && irqnr < 1020) || irqnr >= 8192) { int err; + if (gic_supports_nmi() + && unlikely(gic_read_rpr() == GICD_INT_NMI_PRI)) { + /* + * We need to prevent other NMIs to occur even after a + * priority drop. + * We keep I flag set until cpsr is restored from + * kernel_exit. + */ + gic_set_nmi_active(); + + if (static_branch_likely(&supports_deactivate_key)) + gic_write_eoir(irqnr); + + do_handle_nmi(irqnr, regs); + return; + } + if (static_branch_likely(&supports_deactivate_key)) gic_write_eoir(irqnr); else if (!arch_uses_gic_prios()) @@ -1183,6 +1222,8 @@ static int __init gic_init_bases(void __iomem *dist_base, if (arch_uses_gic_prios()) { if (!gic_has_group0() || gic_dist_security_disabled()) static_branch_enable(&have_non_secure_prio_view); + else + pr_warn("SCR_EL3.FIQ set, cannot enable use of pseudo-NMIs\n"); } return 0; -- 1.9.1