[PATCH v3 30/32] powerpc/64: system call reconcile interrupts
From: Nicholas Piggin <npiggin@gmail.com>
Date: 2020-02-25 18:57:27
Subsystem:
linux for powerpc (32-bit and 64-bit), the rest · Maintainers:
Madhavan Srinivasan, Michael Ellerman, Linus Torvalds
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> --- arch/powerpc/kernel/entry_64.S | 11 +++++++++++ arch/powerpc/kernel/syscall_64.c | 28 +++++++++++++--------------- 2 files changed, 24 insertions(+), 15 deletions(-)
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index 6d5464f83c05..8406812c9734 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S@@ -113,6 +113,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
diff --git a/arch/powerpc/kernel/syscall_64.c b/arch/powerpc/kernel/syscall_64.c
index 08e0bebbd3b6..32601a572ff0 100644
--- a/arch/powerpc/kernel/syscall_64.c
+++ b/arch/powerpc/kernel/syscall_64.c@@ -19,13 +19,19 @@ extern void __noreturn tabort_syscall(unsigned long nip, unsigned long msr); 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));
@@ -33,8 +39,10 @@ notrace long system_call_exception(long r3, long r4, long r5, long r6, long r7, BUG_ON(regs->softe != IRQS_ENABLED); if (IS_ENABLED(CONFIG_PPC_TRANSACTIONAL_MEM) && - unlikely(regs->msr & MSR_TS_T)) + unlikely(regs->msr & MSR_TS_T)) { + local_irq_enable(); tabort_syscall(regs->nip, regs->msr); + } account_cpu_user_entry();
@@ -50,16 +58,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
@@ -68,7 +66,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)) {
--
2.23.0