Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c58ce2b1 authored by Tiejun Chen's avatar Tiejun Chen Committed by Benjamin Herrenschmidt
Browse files

ppc64: fix missing to check all bits of _TIF_USER_WORK_MASK in preempt



In entry_64.S version of ret_from_except_lite, you'll notice that
in the !preempt case, after we've checked MSR_PR we test for any
TIF flag in _TIF_USER_WORK_MASK to decide whether to go to do_work
or not. However, in the preempt case, we do a convoluted trick to
test SIGPENDING only if PR was set and always test NEED_RESCHED ...
but we forget to test any other bit of _TIF_USER_WORK_MASK !!! So
that means that with preempt, we completely fail to test for things
like single step, syscall tracing, etc...

This should be fixed as the following path:

 - Test PR. If not set, go to resume_kernel, else continue.

 - If go resume_kernel, to do that original do_work.

 - If else, then always test for _TIF_USER_WORK_MASK to decide to do
that original user_work, else restore directly.

Signed-off-by: default avatarTiejun Chen <tiejun.chen@windriver.com>
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
parent 82b2521d
Loading
Loading
Loading
Loading
+40 −57
Original line number Diff line number Diff line
@@ -558,27 +558,54 @@ _GLOBAL(ret_from_except_lite)
	mtmsrd	r10,1		  /* Update machine state */
#endif /* CONFIG_PPC_BOOK3E */

#ifdef CONFIG_PREEMPT
	clrrdi	r9,r1,THREAD_SHIFT	/* current_thread_info() */
	li	r0,_TIF_NEED_RESCHED	/* bits to check */
	ld	r3,_MSR(r1)
	ld	r4,TI_FLAGS(r9)
	/* Move MSR_PR bit in r3 to _TIF_SIGPENDING position in r0 */
	rlwimi	r0,r3,32+TIF_SIGPENDING-MSR_PR_LG,_TIF_SIGPENDING
	and.	r0,r4,r0	/* check NEED_RESCHED and maybe SIGPENDING */
	bne	do_work

#else /* !CONFIG_PREEMPT */
	ld	r3,_MSR(r1)	/* Returning to user mode? */
	andi.	r3,r3,MSR_PR
	beq	restore		/* if not, just restore regs and return */
	beq	resume_kernel

	/* Check current_thread_info()->flags */
	andi.	r0,r4,_TIF_USER_WORK_MASK
	beq	restore

	andi.	r0,r4,_TIF_NEED_RESCHED
	beq	1f
	bl	.restore_interrupts
	bl	.schedule
	b	.ret_from_except_lite

1:	bl	.save_nvgprs
	bl	.restore_interrupts
	addi	r3,r1,STACK_FRAME_OVERHEAD
	bl	.do_notify_resume
	b	.ret_from_except

resume_kernel:
#ifdef CONFIG_PREEMPT
	/* Check if we need to preempt */
	andi.	r0,r4,_TIF_NEED_RESCHED
	beq+	restore
	/* Check that preempt_count() == 0 and interrupts are enabled */
	lwz	r8,TI_PREEMPT(r9)
	cmpwi	cr1,r8,0
	ld	r0,SOFTE(r1)
	cmpdi	r0,0
	crandc	eq,cr1*4+eq,eq
	bne	restore

	/*
	 * Here we are preempting the current task. We want to make
	 * sure we are soft-disabled first
	 */
	SOFT_DISABLE_INTS(r3,r4)
1:	bl	.preempt_schedule_irq

	/* Re-test flags and eventually loop */
	clrrdi	r9,r1,THREAD_SHIFT
	ld	r4,TI_FLAGS(r9)
	andi.	r0,r4,_TIF_USER_WORK_MASK
	bne	do_work
#endif /* !CONFIG_PREEMPT */
	andi.	r0,r4,_TIF_NEED_RESCHED
	bne	1b
#endif /* CONFIG_PREEMPT */

	.globl	fast_exc_return_irq
fast_exc_return_irq:
@@ -759,50 +786,6 @@ restore_check_irq_replay:
#endif /* CONFIG_PPC_BOOK3E */
1:	b	.ret_from_except /* What else to do here ? */
 


3:
do_work:
#ifdef CONFIG_PREEMPT
	andi.	r0,r3,MSR_PR	/* Returning to user mode? */
	bne	user_work
	/* Check that preempt_count() == 0 and interrupts are enabled */
	lwz	r8,TI_PREEMPT(r9)
	cmpwi	cr1,r8,0
	ld	r0,SOFTE(r1)
	cmpdi	r0,0
	crandc	eq,cr1*4+eq,eq
	bne	restore

	/*
	 * Here we are preempting the current task. We want to make
	 * sure we are soft-disabled first
	 */
	SOFT_DISABLE_INTS(r3,r4)
1:	bl	.preempt_schedule_irq

	/* Re-test flags and eventually loop */
	clrrdi	r9,r1,THREAD_SHIFT
	ld	r4,TI_FLAGS(r9)
	andi.	r0,r4,_TIF_NEED_RESCHED
	bne	1b
	b	restore

user_work:
#endif /* CONFIG_PREEMPT */

	andi.	r0,r4,_TIF_NEED_RESCHED
	beq	1f
	bl	.restore_interrupts
	bl	.schedule
	b	.ret_from_except_lite

1:	bl	.save_nvgprs
	bl	.restore_interrupts
	addi	r3,r1,STACK_FRAME_OVERHEAD
	bl	.do_notify_resume
	b	.ret_from_except

unrecov_restore:
	addi	r3,r1,STACK_FRAME_OVERHEAD
	bl	.unrecoverable_exception