powerpc/64/syscall: Reconcile interrupts
authorNicholas Piggin <npiggin@gmail.com>
Tue, 25 Feb 2020 17:35:39 +0000 (03:35 +1000)
committerMichael Ellerman <mpe@ellerman.id.au>
Wed, 1 Apr 2020 02:42:14 +0000 (13:42 +1100)
This reconciles interrupts in the system call case like all other
interrupts. This allows system_call_common to be shared with the scv
system call implementation in a subsequent patch.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20200225173541.1549955-31-npiggin@gmail.com
arch/powerpc/kernel/entry_64.S
arch/powerpc/kernel/syscall_64.c

index 95905ed..63f0a44 100644 (file)
@@ -119,6 +119,17 @@ END_BTB_FLUSH_SECTION
        ld      r11,exception_marker@toc(r2)
        std     r11,-16(r10)            /* "regshere" marker */
 
+       /*
+        * RECONCILE_IRQ_STATE without calling trace_hardirqs_off(), which
+        * would clobber syscall parameters. Also we always enter with IRQs
+        * enabled and nothing pending. system_call_exception() will call
+        * trace_hardirqs_off().
+        */
+       li      r11,IRQS_ALL_DISABLED
+       li      r12,PACA_IRQ_HARD_DIS
+       stb     r11,PACAIRQSOFTMASK(r13)
+       stb     r12,PACAIRQHAPPENED(r13)
+
        /* Calling convention has r9 = orig r0, r10 = regs */
        mr      r9,r0
        bl      system_call_exception
index a986eff..cf06eb4 100644 (file)
 
 typedef long (*syscall_fn)(long, long, long, long, long, long);
 
-/* Has to run notrace because it is entered "unreconciled" */
-notrace long system_call_exception(long r3, long r4, long r5, long r6, long r7, long r8,
-                          unsigned long r0, struct pt_regs *regs)
+/* Has to run notrace because it is entered not completely "reconciled" */
+notrace long system_call_exception(long r3, long r4, long r5,
+                                  long r6, long r7, long r8,
+                                  unsigned long r0, struct pt_regs *regs)
 {
        unsigned long ti_flags;
        syscall_fn f;
 
+       if (IS_ENABLED(CONFIG_PPC_IRQ_SOFT_MASK_DEBUG))
+               BUG_ON(irq_soft_mask_return() != IRQS_ALL_DISABLED);
+
+       trace_hardirqs_off(); /* finish reconciling */
+
        if (IS_ENABLED(CONFIG_PPC_BOOK3S))
                BUG_ON(!(regs->msr & MSR_RI));
        BUG_ON(!(regs->msr & MSR_PR));
@@ -45,16 +51,6 @@ notrace long system_call_exception(long r3, long r4, long r5, long r6, long r7,
        kuap_check_amr();
 
        /*
-        * A syscall should always be called with interrupts enabled
-        * so we just unconditionally hard-enable here. When some kind
-        * of irq tracing is used, we additionally check that condition
-        * is correct
-        */
-       if (IS_ENABLED(CONFIG_PPC_IRQ_SOFT_MASK_DEBUG)) {
-               WARN_ON(irq_soft_mask_return() != IRQS_ENABLED);
-               WARN_ON(local_paca->irq_happened);
-       }
-       /*
         * This is not required for the syscall exit path, but makes the
         * stack frame look nicer. If this was initialised in the first stack
         * frame, or if the unwinder was taught the first stack frame always
@@ -62,7 +58,7 @@ notrace long system_call_exception(long r3, long r4, long r5, long r6, long r7,
         */
        regs->softe = IRQS_ENABLED;
 
-       __hard_irq_enable();
+       local_irq_enable();
 
        ti_flags = current_thread_info()->flags;
        if (unlikely(ti_flags & _TIF_SYSCALL_DOTRACE)) {