Browse Source

microblaze: fix handling of multiple pending signals

We need to keep building sigframes until no pending signals remain.
Wrap do_notify_resume() calls into loops; do _not_ allow syscall
restart logics to trigger after the first iteration.

Incidentally, comments about pending signals that should (somehow)
be in r18 are pure BS.  Doesn't work that way and cannot work that
way, sorry...

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Al Viro 13 years ago
parent
commit
e9f9252667
2 changed files with 42 additions and 29 deletions
  1. 11 2
      arch/microblaze/kernel/entry-nommu.S
  2. 31 27
      arch/microblaze/kernel/entry.S

+ 11 - 2
arch/microblaze/kernel/entry-nommu.S

@@ -124,6 +124,7 @@ ret_from_intr:
 	lwi	r11, r1, PT_MODE
 	lwi	r11, r1, PT_MODE
 	bneid	r11, no_intr_resched
 	bneid	r11, no_intr_resched
 
 
+3:
 	lwi	r6, r31, TS_THREAD_INFO	/* get thread info */
 	lwi	r6, r31, TS_THREAD_INFO	/* get thread info */
 	lwi	r19, r6, TI_FLAGS	/* get flags in thread info */
 	lwi	r19, r6, TI_FLAGS	/* get flags in thread info */
 				/* do an extra work if any bits are set */
 				/* do an extra work if any bits are set */
@@ -132,11 +133,13 @@ ret_from_intr:
 	beqi	r11, 1f
 	beqi	r11, 1f
 	bralid	r15, schedule
 	bralid	r15, schedule
 	nop
 	nop
+	bri	3b
 1:	andi	r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME
 1:	andi	r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME
 	beqid	r11, no_intr_resched
 	beqid	r11, no_intr_resched
 	addk	r5, r1, r0
 	addk	r5, r1, r0
 	bralid	r15, do_notify_resume
 	bralid	r15, do_notify_resume
 	addk	r6, r0, r0
 	addk	r6, r0, r0
+	bri	3b
 
 
 no_intr_resched:
 no_intr_resched:
 	/* Disable interrupts, we are now committed to the state restore */
 	/* Disable interrupts, we are now committed to the state restore */
@@ -486,18 +489,24 @@ ENTRY(ret_from_kernel_thread)
 work_pending:
 work_pending:
 	lwi	r11, r1, PT_MODE
 	lwi	r11, r1, PT_MODE
 	bneid	r11, 2f
 	bneid	r11, 2f
+3:
 	enable_irq
 	enable_irq
-
 	andi	r11, r19, _TIF_NEED_RESCHED
 	andi	r11, r19, _TIF_NEED_RESCHED
 	beqi	r11, 1f
 	beqi	r11, 1f
 	bralid	r15, schedule
 	bralid	r15, schedule
 	nop
 	nop
+	bri	4f
 1:	andi	r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME
 1:	andi	r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME
 	beqi	r11, no_work_pending
 	beqi	r11, no_work_pending
 	addk	r5, r30, r0
 	addk	r5, r30, r0
 	bralid	r15, do_notify_resume
 	bralid	r15, do_notify_resume
 	addik	r6, r0, 1
 	addik	r6, r0, 1
-	bri	no_work_pending
+	addk	r30, r0, r0	/* no restarts from now on */
+4:
+	disable_irq
+	lwi	r6, r31, TS_THREAD_INFO /* get thread info */
+	lwi	r19, r6, TI_FLAGS /* get flags in thread info */
+	bri	3b
 
 
 ENTRY(ret_to_user)
 ENTRY(ret_to_user)
 	disable_irq
 	disable_irq

+ 31 - 27
arch/microblaze/kernel/entry.S

@@ -402,26 +402,27 @@ C_ENTRY(ret_from_trap):
 	 * trigger rescheduling. */
 	 * trigger rescheduling. */
 	/* get thread info from current task */
 	/* get thread info from current task */
 	lwi	r11, CURRENT_TASK, TS_THREAD_INFO;
 	lwi	r11, CURRENT_TASK, TS_THREAD_INFO;
-	lwi	r11, r11, TI_FLAGS;		/* get flags in thread info */
-	andi	r11, r11, _TIF_NEED_RESCHED;
+	lwi	r19, r11, TI_FLAGS;		/* get flags in thread info */
+	andi	r11, r19, _TIF_NEED_RESCHED;
 	beqi	r11, 5f;
 	beqi	r11, 5f;
 
 
 	bralid	r15, schedule;	/* Call scheduler */
 	bralid	r15, schedule;	/* Call scheduler */
 	nop;				/* delay slot */
 	nop;				/* delay slot */
+	bri	1b
 
 
 	/* Maybe handle a signal */
 	/* Maybe handle a signal */
-5:	/* get thread info from current task*/
-	lwi	r11, CURRENT_TASK, TS_THREAD_INFO;
-	lwi	r11, r11, TI_FLAGS;	/* get flags in thread info */
-	andi	r11, r11, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
-	beqi	r11, 1f;		/* Signals to handle, handle them */
+5:	
+	andi	r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
+	beqi	r11, 4f;		/* Signals to handle, handle them */
 
 
 	addik	r5, r1, 0;		/* Arg 1: struct pt_regs *regs */
 	addik	r5, r1, 0;		/* Arg 1: struct pt_regs *regs */
 	bralid	r15, do_notify_resume;	/* Handle any signals */
 	bralid	r15, do_notify_resume;	/* Handle any signals */
 	add	r6, r30, r0;		/* Arg 2: int in_syscall */
 	add	r6, r30, r0;		/* Arg 2: int in_syscall */
+	add	r30, r0, r0		/* no more restarts */
+	bri	1b
 
 
 /* Finally, return to user state.  */
 /* Finally, return to user state.  */
-1:	set_bip;			/*  Ints masked for state restore */
+4:	set_bip;			/*  Ints masked for state restore */
 	swi	CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
 	swi	CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
 	VM_OFF;
 	VM_OFF;
 	tophys(r1,r1);
 	tophys(r1,r1);
@@ -573,20 +574,20 @@ C_ENTRY(ret_from_exc):
 
 
 	/* We're returning to user mode, so check for various conditions that
 	/* We're returning to user mode, so check for various conditions that
 	   trigger rescheduling. */
 	   trigger rescheduling. */
+1:
 	lwi	r11, CURRENT_TASK, TS_THREAD_INFO;	/* get thread info */
 	lwi	r11, CURRENT_TASK, TS_THREAD_INFO;	/* get thread info */
-	lwi	r11, r11, TI_FLAGS;	/* get flags in thread info */
-	andi	r11, r11, _TIF_NEED_RESCHED;
+	lwi	r19, r11, TI_FLAGS;	/* get flags in thread info */
+	andi	r11, r19, _TIF_NEED_RESCHED;
 	beqi	r11, 5f;
 	beqi	r11, 5f;
 
 
 /* Call the scheduler before returning from a syscall/trap. */
 /* Call the scheduler before returning from a syscall/trap. */
 	bralid	r15, schedule;	/* Call scheduler */
 	bralid	r15, schedule;	/* Call scheduler */
 	nop;				/* delay slot */
 	nop;				/* delay slot */
+	bri	1b
 
 
 	/* Maybe handle a signal */
 	/* Maybe handle a signal */
-5:	lwi	r11, CURRENT_TASK, TS_THREAD_INFO;	/* get thread info */
-	lwi	r11, r11, TI_FLAGS;	/* get flags in thread info */
-	andi	r11, r11, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
-	beqi	r11, 1f;		/* Signals to handle, handle them */
+5:	andi	r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
+	beqi	r11, 4f;		/* Signals to handle, handle them */
 
 
 	/*
 	/*
 	 * Handle a signal return; Pending signals should be in r18.
 	 * Handle a signal return; Pending signals should be in r18.
@@ -602,9 +603,10 @@ C_ENTRY(ret_from_exc):
 	addik	r5, r1, 0;		/* Arg 1: struct pt_regs *regs */
 	addik	r5, r1, 0;		/* Arg 1: struct pt_regs *regs */
 	bralid	r15, do_notify_resume;	/* Handle any signals */
 	bralid	r15, do_notify_resume;	/* Handle any signals */
 	addi	r6, r0, 0;		/* Arg 2: int in_syscall */
 	addi	r6, r0, 0;		/* Arg 2: int in_syscall */
+	bri	1b
 
 
 /* Finally, return to user state.  */
 /* Finally, return to user state.  */
-1:	set_bip;			/* Ints masked for state restore */
+4:	set_bip;			/* Ints masked for state restore */
 	swi	CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
 	swi	CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
 	VM_OFF;
 	VM_OFF;
 	tophys(r1,r1);
 	tophys(r1,r1);
@@ -684,22 +686,23 @@ ret_from_irq:
 	lwi	r11, r1, PT_MODE;
 	lwi	r11, r1, PT_MODE;
 	bnei	r11, 2f;
 	bnei	r11, 2f;
 
 
+1:
 	lwi	r11, CURRENT_TASK, TS_THREAD_INFO;
 	lwi	r11, CURRENT_TASK, TS_THREAD_INFO;
-	lwi	r11, r11, TI_FLAGS; /* MS: get flags from thread info */
-	andi	r11, r11, _TIF_NEED_RESCHED;
+	lwi	r19, r11, TI_FLAGS; /* MS: get flags from thread info */
+	andi	r11, r19, _TIF_NEED_RESCHED;
 	beqi	r11, 5f
 	beqi	r11, 5f
 	bralid	r15, schedule;
 	bralid	r15, schedule;
 	nop; /* delay slot */
 	nop; /* delay slot */
+	bri	1b
 
 
     /* Maybe handle a signal */
     /* Maybe handle a signal */
-5:	lwi	r11, CURRENT_TASK, TS_THREAD_INFO; /* MS: get thread info */
-	lwi	r11, r11, TI_FLAGS; /* get flags in thread info */
-	andi	r11, r11, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
+5:	andi	r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
 	beqid	r11, no_intr_resched
 	beqid	r11, no_intr_resched
 /* Handle a signal return; Pending signals should be in r18. */
 /* Handle a signal return; Pending signals should be in r18. */
 	addik	r5, r1, 0; /* Arg 1: struct pt_regs *regs */
 	addik	r5, r1, 0; /* Arg 1: struct pt_regs *regs */
 	bralid	r15, do_notify_resume;	/* Handle any signals */
 	bralid	r15, do_notify_resume;	/* Handle any signals */
 	addi	r6, r0, 0; /* Arg 2: int in_syscall */
 	addi	r6, r0, 0; /* Arg 2: int in_syscall */
+	bri	1b
 
 
 /* Finally, return to user state. */
 /* Finally, return to user state. */
 no_intr_resched:
 no_intr_resched:
@@ -817,28 +820,29 @@ dbtrap_call: /* Return point for kernel/user entry + 8 because of rtsd r15, 8 */
 	lwi	r11, r1, PT_MODE;
 	lwi	r11, r1, PT_MODE;
 	bnei	r11, 2f;
 	bnei	r11, 2f;
 /* MS: Return to user space - gdb */
 /* MS: Return to user space - gdb */
+1:
 	/* Get current task ptr into r11 */
 	/* Get current task ptr into r11 */
 	lwi	r11, CURRENT_TASK, TS_THREAD_INFO;	/* get thread info */
 	lwi	r11, CURRENT_TASK, TS_THREAD_INFO;	/* get thread info */
-	lwi	r11, r11, TI_FLAGS;	/* get flags in thread info */
-	andi	r11, r11, _TIF_NEED_RESCHED;
+	lwi	r19, r11, TI_FLAGS;	/* get flags in thread info */
+	andi	r11, r19, _TIF_NEED_RESCHED;
 	beqi	r11, 5f;
 	beqi	r11, 5f;
 
 
 	/* Call the scheduler before returning from a syscall/trap. */
 	/* Call the scheduler before returning from a syscall/trap. */
 	bralid	r15, schedule;	/* Call scheduler */
 	bralid	r15, schedule;	/* Call scheduler */
 	nop;				/* delay slot */
 	nop;				/* delay slot */
+	bri	1b
 
 
 	/* Maybe handle a signal */
 	/* Maybe handle a signal */
-5:	lwi	r11, CURRENT_TASK, TS_THREAD_INFO;	/* get thread info */
-	lwi	r11, r11, TI_FLAGS;	/* get flags in thread info */
-	andi	r11, r11, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
-	beqi	r11, 1f;		/* Signals to handle, handle them */
+5:	andi	r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
+	beqi	r11, 4f;		/* Signals to handle, handle them */
 
 
 	addik	r5, r1, 0;		/* Arg 1: struct pt_regs *regs */
 	addik	r5, r1, 0;		/* Arg 1: struct pt_regs *regs */
 	bralid	r15, do_notify_resume;	/* Handle any signals */
 	bralid	r15, do_notify_resume;	/* Handle any signals */
 	addi  r6, r0, 0;	/* Arg 2: int in_syscall */
 	addi  r6, r0, 0;	/* Arg 2: int in_syscall */
+	bri	1b
 
 
 /* Finally, return to user state.  */
 /* Finally, return to user state.  */
-1:	swi	CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
+4:	swi	CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
 	VM_OFF;
 	VM_OFF;
 	tophys(r1,r1);
 	tophys(r1,r1);
 	/* MS: Restore all regs */
 	/* MS: Restore all regs */