From: Ada Couprie Diaz <ada.coupriediaz@arm.com> driver inclusion category: bugfix bugzilla: https://atomgit.com/openeuler/kernel/issues/10041 ---------------------------------------------------------------------- As we clear SCTLR_EL1.SPINTMASK when enabling FEAT_NMI, ALLINT masks IRQs and FIQs regardless of superpriority. Update irqflags.h and `regs_irqs_disabled()` to take it into account, so we properly keep track of the local IRQ masking state. We have documentation at the top of irqflags.h which explains the DAIF masking. Since the additional masking with NMIs is related and also covers the IF in DAIF, extend the comment to note what's going on with NMIs. Fixes: a5f61cc636f4 ("arm64: irqflags: use alternative branches for pseudo-NMI logic") Co-developed-by: Mark Brown <broonie@kernel.org> Signed-off-by: Mark Brown <broonie@kernel.org> Signed-off-by: Ada Couprie Diaz <ada.coupriediaz@arm.com> Signed-off-by: Vladimir Murzin <vladimir.murzin@arm.com> Signed-off-by: Qinxin Xia <xiaqinxin@huawei.com> Signed-off-by: Hongye Lin <linhongye@h-partners.com> --- arch/arm64/include/asm/irqflags.h | 21 +++++++++++++++++---- arch/arm64/include/asm/ptrace.h | 6 ++++-- arch/arm64/include/uapi/asm/ptrace.h | 1 + 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/arch/arm64/include/asm/irqflags.h b/arch/arm64/include/asm/irqflags.h index a9f117fb43c6..0477ecca2d8a 100644 --- a/arch/arm64/include/asm/irqflags.h +++ b/arch/arm64/include/asm/irqflags.h @@ -27,8 +27,8 @@ * masking both superpriority interrupts and IRQ/FIQ regardless of the * I and F settings. Since these superpriority interrupts are being * used as NMIs we do not include them in the interrupt masking here, - * anything that requires that NMIs be masked needs to explicitly do - * so. + * anything that requires that NMIs be masked needs to explicitly do so, + * but we do check for ALLINT masking IRQs/FIQs. */ static __always_inline bool __irqflags_uses_pmr(void) @@ -109,16 +109,29 @@ static __always_inline unsigned long __pmr_local_save_flags(void) */ static inline unsigned long arch_local_save_flags(void) { + unsigned long flags; + if (__irqflags_uses_pmr()) { return __pmr_local_save_flags(); } else { - return __daif_local_save_flags(); + flags = __daif_local_save_flags(); + if (system_uses_nmi() && + (read_sysreg_s(SYS_ALLINT) & ALLINT_ALLINT)) + flags |= PSR_ALLINT_BIT; + return flags; } } static __always_inline bool __daif_irqs_disabled_flags(unsigned long flags) { - return flags & PSR_I_BIT; + if (flags & PSR_I_BIT) + return true; + + /* SCTLR_EL1.SPINTMASK is clear, so ALLINT masks *all* IRQs/FIQs. */ + if (system_uses_nmi()) + return !!(flags & PSR_ALLINT_BIT); + + return false; } static __always_inline bool __pmr_irqs_disabled_flags(unsigned long flags) diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h index e5d22061c4d2..36f56c6036e8 100644 --- a/arch/arm64/include/asm/ptrace.h +++ b/arch/arm64/include/asm/ptrace.h @@ -243,8 +243,10 @@ static inline void forget_syscall(struct pt_regs *regs) (regs)->pmr_save == GIC_PRIO_IRQON : \ true) -#define interrupts_enabled(regs) \ - (!((regs)->pstate & PSR_I_BIT) && irqs_priority_unmasked(regs)) +#define interrupts_enabled(regs) \ + (!((regs)->pstate & PSR_I_BIT) && \ + !(system_uses_nmi() && ((regs)->pstate & PSR_ALLINT_BIT)) && \ + irqs_priority_unmasked(regs)) #define fast_interrupts_enabled(regs) \ (!(regs)->pstate & PSR_F_BIT) diff --git a/arch/arm64/include/uapi/asm/ptrace.h b/arch/arm64/include/uapi/asm/ptrace.h index 7fa2f7036aa7..2b61a53b8593 100644 --- a/arch/arm64/include/uapi/asm/ptrace.h +++ b/arch/arm64/include/uapi/asm/ptrace.h @@ -46,6 +46,7 @@ #define PSR_I_BIT 0x00000080 #define PSR_A_BIT 0x00000100 #define PSR_D_BIT 0x00000200 +#define PSR_ALLINT_BIT 0x00002000 #define PSR_BTYPE_MASK 0x00000c00 #define PSR_SSBS_BIT 0x00001000 #define PSR_PAN_BIT 0x00400000 -- 2.25.1