arm64: Skip irqflags tracing for NMI in IRQs disabled context
[sfrench/cifs-2.6.git] / arch / arm64 / kernel / entry.S
index 763f03dc4d9e75cbef3ceb085ea7fe70d16a78d5..6bf7e12f9a2b21b4c6dd5653ef0caea4a4453828 100644 (file)
@@ -249,6 +249,12 @@ alternative_else_nop_endif
        msr     sp_el0, tsk
        .endif
 
+       /* Save pmr */
+alternative_if ARM64_HAS_IRQ_PRIO_MASKING
+       mrs_s   x20, SYS_ICC_PMR_EL1
+       str     x20, [sp, #S_PMR_SAVE]
+alternative_else_nop_endif
+
        /*
         * Registers that may be useful after this macro is invoked:
         *
@@ -269,6 +275,14 @@ alternative_else_nop_endif
        /* No need to restore UAO, it will be restored from SPSR_EL1 */
        .endif
 
+       /* Restore pmr */
+alternative_if ARM64_HAS_IRQ_PRIO_MASKING
+       ldr     x20, [sp, #S_PMR_SAVE]
+       msr_s   SYS_ICC_PMR_EL1, x20
+       /* Ensure priority change is seen by redistributor */
+       dsb     sy
+alternative_else_nop_endif
+
        ldp     x21, x22, [sp, #S_PC]           // load ELR, SPSR
        .if     \el == 0
        ct_user_enter
@@ -392,17 +406,7 @@ alternative_insn eret, nop, ARM64_UNMAP_KERNEL_AT_EL0
        mov     sp, x19
        .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.
- *
- * x7 is reserved for the system call number in 32-bit mode.
- */
-wsc_nr .req    w25             // number of system calls
-xsc_nr .req    x25             // number of system calls (zero-extended)
-wscno  .req    w26             // syscall number
-xscno  .req    x26             // syscall number (zero-extended)
-stbl   .req    x27             // syscall table pointer
+/* GPRs used by entry code */
 tsk    .req    x28             // current thread_info
 
 /*
@@ -613,32 +617,52 @@ el1_irq:
        kernel_entry 1
        enable_da_f
 #ifdef CONFIG_TRACE_IRQFLAGS
+#ifdef CONFIG_ARM64_PSEUDO_NMI
+alternative_if ARM64_HAS_IRQ_PRIO_MASKING
+       ldr     x20, [sp, #S_PMR_SAVE]
+alternative_else
+       mov     x20, #GIC_PRIO_IRQON
+alternative_endif
+       cmp     x20, #GIC_PRIO_IRQOFF
+       /* Irqs were disabled, don't trace */
+       b.ls    1f
+#endif
        bl      trace_hardirqs_off
+1:
 #endif
 
        irq_handler
 
 #ifdef CONFIG_PREEMPT
        ldr     x24, [tsk, #TSK_TI_PREEMPT]     // get preempt count
-       cbnz    x24, 1f                         // preempt count != 0
-       bl      el1_preempt
+alternative_if ARM64_HAS_IRQ_PRIO_MASKING
+       /*
+        * DA_F were cleared at start of handling. If anything is set in DAIF,
+        * we come back from an NMI, so skip preemption
+        */
+       mrs     x0, daif
+       orr     x24, x24, x0
+alternative_else_nop_endif
+       cbnz    x24, 1f                         // preempt count != 0 || NMI return path
+       bl      preempt_schedule_irq            // irq en/disable is done inside
 1:
 #endif
 #ifdef CONFIG_TRACE_IRQFLAGS
+#ifdef CONFIG_ARM64_PSEUDO_NMI
+       /*
+        * if IRQs were disabled when we received the interrupt, we have an NMI
+        * and we are not re-enabling interrupt upon eret. Skip tracing.
+        */
+       cmp     x20, #GIC_PRIO_IRQOFF
+       b.ls    1f
+#endif
        bl      trace_hardirqs_on
+1:
 #endif
+
        kernel_exit 1
 ENDPROC(el1_irq)
 
-#ifdef CONFIG_PREEMPT
-el1_preempt:
-       mov     x24, lr
-1:     bl      preempt_schedule_irq            // irq en/disable is done inside
-       ldr     x0, [tsk, #TSK_TI_FLAGS]        // get new tasks TI_FLAGS
-       tbnz    x0, #TIF_NEED_RESCHED, 1b       // needs rescheduling?
-       ret     x24
-#endif
-
 /*
  * EL0 mode handlers.
  */