patch-2.1.106 linux/arch/alpha/kernel/signal.c
Next file: linux/arch/alpha/mm/fault.c
Previous file: linux/arch/alpha/kernel/process.c
Back to the patch index
Back to the overall index
- Lines: 439
- Date:
Tue Jun 9 13:34:01 1998
- Orig file:
v2.1.105/linux/arch/alpha/kernel/signal.c
- Orig date:
Fri Jan 30 11:28:05 1998
diff -u --recursive --new-file v2.1.105/linux/arch/alpha/kernel/signal.c linux/arch/alpha/kernel/signal.c
@@ -203,6 +203,12 @@
}
}
+asmlinkage int
+sys_sigaltstack(const stack_t *uss, stack_t *uoss)
+{
+ return do_sigaltstack(uss, uoss, rdusp());
+}
+
/*
* Do a signal return; undo the signal stack.
*/
@@ -225,67 +231,65 @@
#define INSN_LDI_R0 0x201f0000
#define INSN_CALLSYS 0x00000083
-
-static void
+static long
restore_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
struct switch_stack *sw)
{
unsigned long usp;
- int i;
+ long i, err = 0;
- __get_user(regs->pc, &sc->sc_pc);
+ err |= __get_user(regs->pc, &sc->sc_pc);
sw->r26 = (unsigned long) ret_from_sys_call;
- __get_user(regs->r0, sc->sc_regs+0);
- __get_user(regs->r1, sc->sc_regs+1);
- __get_user(regs->r2, sc->sc_regs+2);
- __get_user(regs->r3, sc->sc_regs+3);
- __get_user(regs->r4, sc->sc_regs+4);
- __get_user(regs->r5, sc->sc_regs+5);
- __get_user(regs->r6, sc->sc_regs+6);
- __get_user(regs->r7, sc->sc_regs+7);
- __get_user(regs->r8, sc->sc_regs+8);
- __get_user(sw->r9, sc->sc_regs+9);
- __get_user(sw->r10, sc->sc_regs+10);
- __get_user(sw->r11, sc->sc_regs+11);
- __get_user(sw->r12, sc->sc_regs+12);
- __get_user(sw->r13, sc->sc_regs+13);
- __get_user(sw->r14, sc->sc_regs+14);
- __get_user(sw->r15, sc->sc_regs+15);
- __get_user(regs->r16, sc->sc_regs+16);
- __get_user(regs->r17, sc->sc_regs+17);
- __get_user(regs->r18, sc->sc_regs+18);
- __get_user(regs->r19, sc->sc_regs+19);
- __get_user(regs->r20, sc->sc_regs+20);
- __get_user(regs->r21, sc->sc_regs+21);
- __get_user(regs->r22, sc->sc_regs+22);
- __get_user(regs->r23, sc->sc_regs+23);
- __get_user(regs->r24, sc->sc_regs+24);
- __get_user(regs->r25, sc->sc_regs+25);
- __get_user(regs->r26, sc->sc_regs+26);
- __get_user(regs->r27, sc->sc_regs+27);
- __get_user(regs->r28, sc->sc_regs+28);
- __get_user(regs->gp, sc->sc_regs+29);
- __get_user(usp, sc->sc_regs+30);
+ err |= __get_user(regs->r0, sc->sc_regs+0);
+ err |= __get_user(regs->r1, sc->sc_regs+1);
+ err |= __get_user(regs->r2, sc->sc_regs+2);
+ err |= __get_user(regs->r3, sc->sc_regs+3);
+ err |= __get_user(regs->r4, sc->sc_regs+4);
+ err |= __get_user(regs->r5, sc->sc_regs+5);
+ err |= __get_user(regs->r6, sc->sc_regs+6);
+ err |= __get_user(regs->r7, sc->sc_regs+7);
+ err |= __get_user(regs->r8, sc->sc_regs+8);
+ err |= __get_user(sw->r9, sc->sc_regs+9);
+ err |= __get_user(sw->r10, sc->sc_regs+10);
+ err |= __get_user(sw->r11, sc->sc_regs+11);
+ err |= __get_user(sw->r12, sc->sc_regs+12);
+ err |= __get_user(sw->r13, sc->sc_regs+13);
+ err |= __get_user(sw->r14, sc->sc_regs+14);
+ err |= __get_user(sw->r15, sc->sc_regs+15);
+ err |= __get_user(regs->r16, sc->sc_regs+16);
+ err |= __get_user(regs->r17, sc->sc_regs+17);
+ err |= __get_user(regs->r18, sc->sc_regs+18);
+ err |= __get_user(regs->r19, sc->sc_regs+19);
+ err |= __get_user(regs->r20, sc->sc_regs+20);
+ err |= __get_user(regs->r21, sc->sc_regs+21);
+ err |= __get_user(regs->r22, sc->sc_regs+22);
+ err |= __get_user(regs->r23, sc->sc_regs+23);
+ err |= __get_user(regs->r24, sc->sc_regs+24);
+ err |= __get_user(regs->r25, sc->sc_regs+25);
+ err |= __get_user(regs->r26, sc->sc_regs+26);
+ err |= __get_user(regs->r27, sc->sc_regs+27);
+ err |= __get_user(regs->r28, sc->sc_regs+28);
+ err |= __get_user(regs->gp, sc->sc_regs+29);
+ err |= __get_user(usp, sc->sc_regs+30);
wrusp(usp);
for (i = 0; i < 31; i++)
- __get_user(sw->fp[i], sc->sc_fpregs+i);
- __get_user(sw->fp[31], &sc->sc_fpcr);
+ err |= __get_user(sw->fp[i], sc->sc_fpregs+i);
+ err |= __get_user(sw->fp[31], &sc->sc_fpcr);
+
+ return err;
}
asmlinkage void
do_sigreturn(struct sigframe *frame, struct pt_regs *regs,
struct switch_stack *sw)
{
- unsigned long ps;
sigset_t set;
/* Verify that it's a good sigcontext before using it */
if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
goto give_sigsegv;
- if (__get_user(ps, &frame->sc.sc_ps) || ps != 8)
- goto give_sigsegv;
if (__get_user(set.sig[0], &frame->sc.sc_mask)
|| (_NSIG_WORDS > 1
&& __copy_from_user(&set.sig[1], &frame->extramask,
@@ -298,7 +302,8 @@
recalc_sigpending(current);
spin_unlock_irq(¤t->sigmask_lock);
- restore_sigcontext(&frame->sc, regs, sw);
+ if (restore_sigcontext(&frame->sc, regs, sw))
+ goto give_sigsegv;
/* Send SIGTRAP if we're single-stepping: */
if (ptrace_cancel_bpt (current))
@@ -306,22 +311,19 @@
return;
give_sigsegv:
- lock_kernel();
- do_exit(SIGSEGV);
+ force_sig(SIGSEGV, current);
}
asmlinkage void
do_rt_sigreturn(struct rt_sigframe *frame, struct pt_regs *regs,
struct switch_stack *sw)
{
- unsigned long ps;
sigset_t set;
+ stack_t st;
/* Verify that it's a good sigcontext before using it */
if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
goto give_sigsegv;
- if (__get_user(ps, &frame->uc.uc_mcontext.sc_ps) || ps != 8)
- goto give_sigsegv;
if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
goto give_sigsegv;
@@ -331,7 +333,14 @@
recalc_sigpending(current);
spin_unlock_irq(¤t->sigmask_lock);
- restore_sigcontext(&frame->uc.uc_mcontext, regs, sw);
+ if (restore_sigcontext(&frame->uc.uc_mcontext, regs, sw))
+ goto give_sigsegv;
+
+ if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st)))
+ goto give_sigsegv;
+ /* It is more difficult to avoid calling this function than to
+ call it and ignore errors. */
+ do_sigaltstack(&st, NULL, rdusp());
/* Send SIGTRAP if we're single-stepping: */
if (ptrace_cancel_bpt (current))
@@ -339,8 +348,7 @@
return;
give_sigsegv:
- lock_kernel();
- do_exit(SIGSEGV);
+ force_sig(SIGSEGV, current);
}
@@ -348,99 +356,113 @@
* Set up a signal frame.
*/
-static void
+static inline void *
+get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
+{
+ if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! on_sig_stack(sp))
+ sp = current->sas_ss_sp + current->sas_ss_size;
+
+ return (void *)((sp - frame_size) & -32ul);
+}
+
+static long
setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
struct switch_stack *sw, unsigned long mask, unsigned long sp)
{
- long i;
+ long i, err = 0;
- __put_user(0, &sc->sc_onstack);
- __put_user(mask, &sc->sc_mask);
- __put_user(regs->pc, &sc->sc_pc);
- __put_user(8, &sc->sc_ps);
-
- __put_user(regs->r0 , sc->sc_regs+0);
- __put_user(regs->r1 , sc->sc_regs+1);
- __put_user(regs->r2 , sc->sc_regs+2);
- __put_user(regs->r3 , sc->sc_regs+3);
- __put_user(regs->r4 , sc->sc_regs+4);
- __put_user(regs->r5 , sc->sc_regs+5);
- __put_user(regs->r6 , sc->sc_regs+6);
- __put_user(regs->r7 , sc->sc_regs+7);
- __put_user(regs->r8 , sc->sc_regs+8);
- __put_user(sw->r9 , sc->sc_regs+9);
- __put_user(sw->r10 , sc->sc_regs+10);
- __put_user(sw->r11 , sc->sc_regs+11);
- __put_user(sw->r12 , sc->sc_regs+12);
- __put_user(sw->r13 , sc->sc_regs+13);
- __put_user(sw->r14 , sc->sc_regs+14);
- __put_user(sw->r15 , sc->sc_regs+15);
- __put_user(regs->r16, sc->sc_regs+16);
- __put_user(regs->r17, sc->sc_regs+17);
- __put_user(regs->r18, sc->sc_regs+18);
- __put_user(regs->r19, sc->sc_regs+19);
- __put_user(regs->r20, sc->sc_regs+20);
- __put_user(regs->r21, sc->sc_regs+21);
- __put_user(regs->r22, sc->sc_regs+22);
- __put_user(regs->r23, sc->sc_regs+23);
- __put_user(regs->r24, sc->sc_regs+24);
- __put_user(regs->r25, sc->sc_regs+25);
- __put_user(regs->r26, sc->sc_regs+26);
- __put_user(regs->r27, sc->sc_regs+27);
- __put_user(regs->r28, sc->sc_regs+28);
- __put_user(regs->gp , sc->sc_regs+29);
- __put_user(sp, sc->sc_regs+30);
- __put_user(0, sc->sc_regs+31);
+ err |= __put_user(on_sig_stack((unsigned long)sc), &sc->sc_onstack);
+ err |= __put_user(mask, &sc->sc_mask);
+ err |= __put_user(regs->pc, &sc->sc_pc);
+ err |= __put_user(8, &sc->sc_ps);
+
+ err |= __put_user(regs->r0 , sc->sc_regs+0);
+ err |= __put_user(regs->r1 , sc->sc_regs+1);
+ err |= __put_user(regs->r2 , sc->sc_regs+2);
+ err |= __put_user(regs->r3 , sc->sc_regs+3);
+ err |= __put_user(regs->r4 , sc->sc_regs+4);
+ err |= __put_user(regs->r5 , sc->sc_regs+5);
+ err |= __put_user(regs->r6 , sc->sc_regs+6);
+ err |= __put_user(regs->r7 , sc->sc_regs+7);
+ err |= __put_user(regs->r8 , sc->sc_regs+8);
+ err |= __put_user(sw->r9 , sc->sc_regs+9);
+ err |= __put_user(sw->r10 , sc->sc_regs+10);
+ err |= __put_user(sw->r11 , sc->sc_regs+11);
+ err |= __put_user(sw->r12 , sc->sc_regs+12);
+ err |= __put_user(sw->r13 , sc->sc_regs+13);
+ err |= __put_user(sw->r14 , sc->sc_regs+14);
+ err |= __put_user(sw->r15 , sc->sc_regs+15);
+ err |= __put_user(regs->r16, sc->sc_regs+16);
+ err |= __put_user(regs->r17, sc->sc_regs+17);
+ err |= __put_user(regs->r18, sc->sc_regs+18);
+ err |= __put_user(regs->r19, sc->sc_regs+19);
+ err |= __put_user(regs->r20, sc->sc_regs+20);
+ err |= __put_user(regs->r21, sc->sc_regs+21);
+ err |= __put_user(regs->r22, sc->sc_regs+22);
+ err |= __put_user(regs->r23, sc->sc_regs+23);
+ err |= __put_user(regs->r24, sc->sc_regs+24);
+ err |= __put_user(regs->r25, sc->sc_regs+25);
+ err |= __put_user(regs->r26, sc->sc_regs+26);
+ err |= __put_user(regs->r27, sc->sc_regs+27);
+ err |= __put_user(regs->r28, sc->sc_regs+28);
+ err |= __put_user(regs->gp , sc->sc_regs+29);
+ err |= __put_user(sp, sc->sc_regs+30);
+ err |= __put_user(0, sc->sc_regs+31);
for (i = 0; i < 31; i++)
- __put_user(sw->fp[i], sc->sc_fpregs+i);
- __put_user(0, sc->sc_fpregs+31);
- __put_user(sw->fp[31], &sc->sc_fpcr);
-
- __put_user(regs->trap_a0, &sc->sc_traparg_a0);
- __put_user(regs->trap_a1, &sc->sc_traparg_a1);
- __put_user(regs->trap_a2, &sc->sc_traparg_a2);
+ err |= __put_user(sw->fp[i], sc->sc_fpregs+i);
+ err |= __put_user(0, sc->sc_fpregs+31);
+ err |= __put_user(sw->fp[31], &sc->sc_fpcr);
+
+ err |= __put_user(regs->trap_a0, &sc->sc_traparg_a0);
+ err |= __put_user(regs->trap_a1, &sc->sc_traparg_a1);
+ err |= __put_user(regs->trap_a2, &sc->sc_traparg_a2);
+
+ return err;
}
static void
setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
struct pt_regs *regs, struct switch_stack * sw)
{
- unsigned long oldsp;
+ unsigned long oldsp, r26, err = 0;
struct sigframe *frame;
oldsp = rdusp();
- frame = (struct sigframe *)((oldsp - sizeof(*frame)) & -32);
-
- /* XXX: Check here if we would need to switch stacks.. */
+ frame = get_sigframe(ka, oldsp, sizeof(*frame));
if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
goto give_sigsegv;
- setup_sigcontext(&frame->sc, regs, sw, set->sig[0], oldsp);
+ err |= setup_sigcontext(&frame->sc, regs, sw, set->sig[0], oldsp);
if (_NSIG_WORDS > 1) {
- __copy_to_user(frame->extramask, &set->sig[1],
- sizeof(frame->extramask));
+ err |= __copy_to_user(frame->extramask, &set->sig[1],
+ sizeof(frame->extramask));
}
/* Set up to return from userspace. If provided, use a stub
already in userspace. */
if (ka->ka_restorer) {
- regs->r26 = (unsigned long) ka->ka_restorer;
+ r26 = (unsigned long) ka->ka_restorer;
} else {
- __put_user(INSN_MOV_R30_R16, frame->retcode+0);
- __put_user(INSN_LDI_R0+__NR_sigreturn, frame->retcode+1);
- __put_user(INSN_CALLSYS, frame->retcode+2);
+ err |= __put_user(INSN_MOV_R30_R16, frame->retcode+0);
+ err |= __put_user(INSN_LDI_R0+__NR_sigreturn, frame->retcode+1);
+ err |= __put_user(INSN_CALLSYS, frame->retcode+2);
imb();
- regs->r26 = (unsigned long) frame->retcode;
+ r26 = (unsigned long) frame->retcode;
}
+ /* Check that everything was written properly. */
+ if (err)
+ goto give_sigsegv;
+
/* "Return" to the handler */
+ regs->r26 = r26;
regs->r27 = regs->pc = (unsigned long) ka->sa.sa_handler;
regs->r16 = sig; /* a0: signal number */
regs->r17 = 0; /* a1: exception code */
regs->r18 = (unsigned long) &frame->sc; /* a2: sigcontext pointer */
wrusp((unsigned long) frame);
-
+
#if DEBUG_SIG
printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
current->comm, current->pid, frame, regs->pc, regs->r26);
@@ -449,47 +471,54 @@
return;
give_sigsegv:
- lock_kernel();
- do_exit(SIGSEGV);
+ if (sig == SIGSEGV)
+ ka->sa.sa_handler = SIG_DFL;
+ force_sig(SIGSEGV, current);
}
static void
setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
sigset_t *set, struct pt_regs *regs, struct switch_stack * sw)
{
- unsigned long oldsp;
+ unsigned long oldsp, r26, err = 0;
struct rt_sigframe *frame;
oldsp = rdusp();
- frame = (struct rt_sigframe *)((oldsp - sizeof(*frame)) & -32);
-
- /* XXX: Check here if we would need to switch stacks.. */
+ frame = get_sigframe(ka, oldsp, sizeof(*frame));
if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
goto give_sigsegv;
- __copy_to_user(&frame->info, info, sizeof(siginfo_t));
+ err |= __copy_to_user(&frame->info, info, sizeof(siginfo_t));
- /* Zero all bits of the ucontext besides the sigcontext. */
- __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));
-
- /* Copy in the bits we actually use. */
- __put_user(set->sig[0], &frame->uc.uc_osf_sigmask);
- setup_sigcontext(&frame->uc.uc_mcontext, regs, sw, set->sig[0], oldsp);
- __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+ /* Create the ucontext. */
+ err |= __put_user(0, &frame->uc.uc_flags);
+ err |= __put_user(0, &frame->uc.uc_link);
+ err |= __put_user(set->sig[0], &frame->uc.uc_osf_sigmask);
+ err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
+ err |= __put_user(sas_ss_flags(oldsp), &frame->uc.uc_stack.ss_flags);
+ err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+ err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, sw,
+ set->sig[0], oldsp);
+ err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
/* Set up to return from userspace. If provided, use a stub
already in userspace. */
if (ka->ka_restorer) {
- regs->r26 = (unsigned long) ka->ka_restorer;
+ r26 = (unsigned long) ka->ka_restorer;
} else {
- __put_user(INSN_MOV_R30_R16, frame->retcode+0);
- __put_user(INSN_LDI_R0+__NR_rt_sigreturn, frame->retcode+1);
- __put_user(INSN_CALLSYS, frame->retcode+2);
+ err |= __put_user(INSN_MOV_R30_R16, frame->retcode+0);
+ err |= __put_user(INSN_LDI_R0+__NR_rt_sigreturn,
+ frame->retcode+1);
+ err |= __put_user(INSN_CALLSYS, frame->retcode+2);
imb();
- regs->r26 = (unsigned long) frame->retcode;
+ r26 = (unsigned long) frame->retcode;
}
+ if (err)
+ goto give_sigsegv;
+
/* "Return" to the handler */
+ regs->r26 = r26;
regs->r27 = regs->pc = (unsigned long) ka->sa.sa_handler;
regs->r16 = sig; /* a0: signal number */
regs->r17 = (unsigned long) &frame->info; /* a1: siginfo pointer */
@@ -504,8 +533,9 @@
return;
give_sigsegv:
- lock_kernel();
- do_exit(SIGSEGV);
+ if (sig == SIGSEGV)
+ ka->sa.sa_handler = SIG_DFL;
+ force_sig(SIGSEGV, current);
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov