microblaze: fix handling of multiple pending signals
authorAl Viro <viro@zeniv.linux.org.uk>
Sun, 29 Apr 2012 08:43:50 +0000 (04:43 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Sun, 3 Feb 2013 23:16:02 +0000 (18:16 -0500)
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>
arch/microblaze/kernel/entry-nommu.S
arch/microblaze/kernel/entry.S

index 96f97f8..7e394fc 100644 (file)
@@ -124,6 +124,7 @@ ret_from_intr:
        lwi     r11, r1, PT_MODE
        bneid   r11, no_intr_resched
 
+3:
        lwi     r6, r31, TS_THREAD_INFO /* get thread info */
        lwi     r19, r6, TI_FLAGS       /* get flags in thread info */
                                /* do an extra work if any bits are set */
@@ -132,11 +133,13 @@ ret_from_intr:
        beqi    r11, 1f
        bralid  r15, schedule
        nop
+       bri     3b
 1:     andi    r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME
        beqid   r11, no_intr_resched
        addk    r5, r1, r0
        bralid  r15, do_notify_resume
        addk    r6, r0, r0
+       bri     3b
 
 no_intr_resched:
        /* Disable interrupts, we are now committed to the state restore */
@@ -486,18 +489,24 @@ ENTRY(ret_from_kernel_thread)
 work_pending:
        lwi     r11, r1, PT_MODE
        bneid   r11, 2f
+3:
        enable_irq
-
        andi    r11, r19, _TIF_NEED_RESCHED
        beqi    r11, 1f
        bralid  r15, schedule
        nop
+       bri     4f
 1:     andi    r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME
        beqi    r11, no_work_pending
        addk    r5, r30, r0
        bralid  r15, do_notify_resume
        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)
        disable_irq
index 18908d2..85b6b5d 100644 (file)
@@ -402,26 +402,27 @@ C_ENTRY(ret_from_trap):
         * trigger rescheduling. */
        /* 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_NEED_RESCHED;
+       lwi     r19, r11, TI_FLAGS;             /* get flags in thread info */
+       andi    r11, r19, _TIF_NEED_RESCHED;
        beqi    r11, 5f;
 
        bralid  r15, schedule;  /* Call scheduler */
        nop;                            /* delay slot */
+       bri     1b
 
        /* 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 */
        bralid  r15, do_notify_resume;  /* Handle any signals */
        add     r6, r30, r0;            /* Arg 2: int in_syscall */
+       add     r30, r0, r0             /* no more restarts */
+       bri     1b
 
 /* 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 */
        VM_OFF;
        tophys(r1,r1);
@@ -573,20 +574,20 @@ C_ENTRY(ret_from_exc):
 
        /* We're returning to user mode, so check for various conditions that
           trigger rescheduling. */
+1:
        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;
 
 /* Call the scheduler before returning from a syscall/trap. */
        bralid  r15, schedule;  /* Call scheduler */
        nop;                            /* delay slot */
+       bri     1b
 
        /* 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.
@@ -602,9 +603,10 @@ C_ENTRY(ret_from_exc):
        addik   r5, r1, 0;              /* Arg 1: struct pt_regs *regs */
        bralid  r15, do_notify_resume;  /* Handle any signals */
        addi    r6, r0, 0;              /* Arg 2: int in_syscall */
+       bri     1b
 
 /* 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 */
        VM_OFF;
        tophys(r1,r1);
@@ -684,22 +686,23 @@ ret_from_irq:
        lwi     r11, r1, PT_MODE;
        bnei    r11, 2f;
 
+1:
        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
        bralid  r15, schedule;
        nop; /* delay slot */
+       bri     1b
 
     /* 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
 /* Handle a signal return; Pending signals should be in r18. */
        addik   r5, r1, 0; /* Arg 1: struct pt_regs *regs */
        bralid  r15, do_notify_resume;  /* Handle any signals */
        addi    r6, r0, 0; /* Arg 2: int in_syscall */
+       bri     1b
 
 /* Finally, return to user state. */
 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;
        bnei    r11, 2f;
 /* MS: Return to user space - gdb */
+1:
        /* Get current task ptr into r11 */
        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;
 
        /* Call the scheduler before returning from a syscall/trap. */
        bralid  r15, schedule;  /* Call scheduler */
        nop;                            /* delay slot */
+       bri     1b
 
        /* 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 */
        bralid  r15, do_notify_resume;  /* Handle any signals */
        addi  r6, r0, 0;        /* Arg 2: int in_syscall */
+       bri     1b
 
 /* 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;
        tophys(r1,r1);
        /* MS: Restore all regs */