patch-2.1.113 linux/arch/m68k/kernel/signal.c
Next file: linux/arch/m68k/kernel/sys_m68k.c
Previous file: linux/arch/m68k/kernel/setup.c
Back to the patch index
Back to the overall index
- Lines: 602
- Date:
Thu Jul 30 11:08:19 1998
- Orig file:
v2.1.112/linux/arch/m68k/kernel/signal.c
- Orig date:
Tue Jun 23 10:01:21 1998
diff -u --recursive --new-file v2.1.112/linux/arch/m68k/kernel/signal.c linux/arch/m68k/kernel/signal.c
@@ -147,6 +147,12 @@
return ret;
}
+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.
@@ -177,31 +183,33 @@
static unsigned char fpu_version = 0; /* version number of fpu, set by setup_frame */
-static inline void restore_fpu_state(struct sigcontext *sc)
+static inline int restore_fpu_state(struct sigcontext *sc)
{
+ int err = 1;
+
if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) {
/* Verify the frame format. */
if (!CPU_IS_060 && (sc->sc_fpstate[0] != fpu_version))
- goto badframe;
+ goto out;
if (CPU_IS_020_OR_030) {
if (m68k_fputype & FPU_68881 &&
!(sc->sc_fpstate[1] == 0x18 || sc->sc_fpstate[1] == 0xb4))
- goto badframe;
+ goto out;
if (m68k_fputype & FPU_68882 &&
!(sc->sc_fpstate[1] == 0x38 || sc->sc_fpstate[1] == 0xd4))
- goto badframe;
+ goto out;
} else if (CPU_IS_040) {
if (!(sc->sc_fpstate[1] == 0x00 ||
sc->sc_fpstate[1] == 0x28 ||
sc->sc_fpstate[1] == 0x60))
- goto badframe;
+ goto out;
} else if (CPU_IS_060) {
if (!(sc->sc_fpstate[3] == 0x00 ||
sc->sc_fpstate[3] == 0x60 ||
sc->sc_fpstate[3] == 0xe0))
- goto badframe;
+ goto out;
} else
- goto badframe;
+ goto out;
__asm__ volatile (".chip 68k/68881\n\t"
"fmovemx %0,%/fp0-%/fp1\n\t"
@@ -213,10 +221,10 @@
__asm__ volatile (".chip 68k/68881\n\t"
"frestore %0\n\t"
".chip 68k" : : "m" (*sc->sc_fpstate));
- return;
+ err = 0;
-badframe:
- do_exit(SIGSEGV);
+out:
+ return err;
}
#define FPCONTEXT_SIZE 216
@@ -224,42 +232,43 @@
#define uc_formatvec uc_filler[FPCONTEXT_SIZE/4]
#define uc_extra uc_filler[FPCONTEXT_SIZE/4+1]
-static inline void rt_restore_fpu_state(struct ucontext *uc)
+static inline int rt_restore_fpu_state(struct ucontext *uc)
{
unsigned char fpstate[FPCONTEXT_SIZE];
int context_size = CPU_IS_060 ? 8 : 0;
fpregset_t fpregs;
+ int err = 1;
if (__get_user(*(long *)fpstate, (long *)&uc->uc_fpstate))
- goto badframe;
+ goto out;
if (CPU_IS_060 ? fpstate[2] : fpstate[0]) {
if (!CPU_IS_060)
context_size = fpstate[1];
/* Verify the frame format. */
if (!CPU_IS_060 && (fpstate[0] != fpu_version))
- goto badframe;
+ goto out;
if (CPU_IS_020_OR_030) {
if (m68k_fputype & FPU_68881 &&
!(context_size == 0x18 || context_size == 0xb4))
- goto badframe;
+ goto out;
if (m68k_fputype & FPU_68882 &&
!(context_size == 0x38 || context_size == 0xd4))
- goto badframe;
+ goto out;
} else if (CPU_IS_040) {
if (!(context_size == 0x00 ||
context_size == 0x28 ||
context_size == 0x60))
- goto badframe;
+ goto out;
} else if (CPU_IS_060) {
if (!(fpstate[3] == 0x00 ||
fpstate[3] == 0x60 ||
fpstate[3] == 0xe0))
- goto badframe;
+ goto out;
} else
- goto badframe;
+ goto out;
if (__copy_from_user(&fpregs, &uc->uc_mcontext.fpregs,
sizeof(fpregs)))
- goto badframe;
+ goto out;
__asm__ volatile (".chip 68k/68881\n\t"
"fmovemx %0,%/fp0-%/fp7\n\t"
"fmoveml %1,%/fpcr/%/fpsr/%/fpiar\n\t"
@@ -271,21 +280,23 @@
if (context_size &&
__copy_from_user(fpstate + 4, (long *)&uc->uc_fpstate + 1,
context_size))
- goto badframe;
+ goto out;
__asm__ volatile (".chip 68k/68881\n\t"
"frestore %0\n\t"
".chip 68k" : : "m" (*fpstate));
- return;
+ err = 0;
-badframe:
- do_exit(SIGSEGV);
+out:
+ return err;
}
static inline int
-restore_sigcontext(struct pt_regs *regs, struct sigcontext *usc, void *fp)
+restore_sigcontext(struct pt_regs *regs, struct sigcontext *usc, void *fp,
+ int *pd0)
{
int fsize, formatvec;
struct sigcontext context;
+ int err;
/* get previous context */
if (copy_from_user(&context, usc, sizeof(context)))
@@ -303,7 +314,7 @@
regs->format = formatvec >> 12;
regs->vector = formatvec & 0xfff;
- restore_fpu_state(&context);
+ err = restore_fpu_state(&context);
fsize = frame_extra_sizes[regs->format];
if (fsize < 0) {
@@ -356,49 +367,55 @@
goto badframe;
}
- return context.sc_d0;
+ *pd0 = context.sc_d0;
+ return err;
badframe:
- do_exit(SIGSEGV);
+ return 1;
}
static inline int
rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw,
- struct ucontext *uc)
+ struct ucontext *uc, int *pd0)
{
int fsize, temp;
greg_t *gregs = uc->uc_mcontext.gregs;
+ unsigned long usp;
+ int err;
- __get_user(temp, &uc->uc_mcontext.version);
+ err = __get_user(temp, &uc->uc_mcontext.version);
if (temp != MCONTEXT_VERSION)
goto badframe;
/* restore passed registers */
- __get_user(regs->d0, &gregs[0]);
- __get_user(regs->d1, &gregs[1]);
- __get_user(regs->d2, &gregs[2]);
- __get_user(regs->d3, &gregs[3]);
- __get_user(regs->d4, &gregs[4]);
- __get_user(regs->d5, &gregs[5]);
- __get_user(sw->d6, &gregs[6]);
- __get_user(sw->d7, &gregs[7]);
- __get_user(regs->a0, &gregs[8]);
- __get_user(regs->a1, &gregs[9]);
- __get_user(regs->a2, &gregs[10]);
- __get_user(sw->a3, &gregs[11]);
- __get_user(sw->a4, &gregs[12]);
- __get_user(sw->a5, &gregs[13]);
- __get_user(sw->a6, &gregs[14]);
- __get_user(temp, &gregs[15]);
- wrusp(temp);
- __get_user(regs->pc, &gregs[16]);
- __get_user(temp, &gregs[17]);
+ err |= __get_user(regs->d0, &gregs[0]);
+ err |= __get_user(regs->d1, &gregs[1]);
+ err |= __get_user(regs->d2, &gregs[2]);
+ err |= __get_user(regs->d3, &gregs[3]);
+ err |= __get_user(regs->d4, &gregs[4]);
+ err |= __get_user(regs->d5, &gregs[5]);
+ err |= __get_user(sw->d6, &gregs[6]);
+ err |= __get_user(sw->d7, &gregs[7]);
+ err |= __get_user(regs->a0, &gregs[8]);
+ err |= __get_user(regs->a1, &gregs[9]);
+ err |= __get_user(regs->a2, &gregs[10]);
+ err |= __get_user(sw->a3, &gregs[11]);
+ err |= __get_user(sw->a4, &gregs[12]);
+ err |= __get_user(sw->a5, &gregs[13]);
+ err |= __get_user(sw->a6, &gregs[14]);
+ err |= __get_user(usp, &gregs[15]);
+ wrusp(usp);
+ err |= __get_user(regs->pc, &gregs[16]);
+ err |= __get_user(temp, &gregs[17]);
regs->sr = (regs->sr & 0xff00) | (temp & 0xff);
regs->orig_d0 = -1; /* disable syscall checks */
- __get_user(temp, &uc->uc_formatvec);
+ err |= __get_user(temp, &uc->uc_formatvec);
regs->format = temp >> 12;
regs->vector = temp & 0xfff;
- rt_restore_fpu_state(uc);
+ err |= rt_restore_fpu_state(uc);
+
+ if (do_sigaltstack(&uc->uc_stack, NULL, usp) == -EFAULT)
+ goto badframe;
fsize = frame_extra_sizes[regs->format];
if (fsize < 0) {
@@ -449,10 +466,11 @@
goto badframe;
}
- return regs->d0;
+ *pd0 = regs->d0;
+ return err;
badframe:
- do_exit(SIGSEGV);
+ return 1;
}
asmlinkage int do_sigreturn(unsigned long __unused)
@@ -462,6 +480,7 @@
unsigned long usp = rdusp();
struct sigframe *frame = (struct sigframe *)(usp - 24);
sigset_t set;
+ int d0;
if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
goto badframe;
@@ -475,10 +494,13 @@
current->blocked = set;
recalc_sigpending(current);
- return restore_sigcontext(regs, &frame->sc, frame + 1);
+ if (restore_sigcontext(regs, &frame->sc, frame + 1, &d0))
+ goto badframe;
+ return d0;
badframe:
- do_exit(SIGSEGV);
+ force_sig(SIGSEGV, current);
+ return 0;
}
asmlinkage int do_rt_sigreturn(unsigned long __unused)
@@ -488,6 +510,7 @@
unsigned long usp = rdusp();
struct rt_sigframe *frame = (struct rt_sigframe *)(usp - 4);
sigset_t set;
+ int d0;
if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
goto badframe;
@@ -498,10 +521,13 @@
current->blocked = set;
recalc_sigpending(current);
- return rt_restore_ucontext(regs, sw, &frame->uc);
+ if (rt_restore_ucontext(regs, sw, &frame->uc, &d0))
+ goto badframe;
+ return d0;
badframe:
- do_exit(SIGSEGV);
+ force_sig(SIGSEGV, current);
+ return 0;
}
/*
@@ -535,17 +561,18 @@
}
}
-static inline void rt_save_fpu_state(struct ucontext *uc, struct pt_regs *regs)
+static inline int rt_save_fpu_state(struct ucontext *uc, struct pt_regs *regs)
{
unsigned char fpstate[FPCONTEXT_SIZE];
int context_size = CPU_IS_060 ? 8 : 0;
+ int err = 0;
__asm__ volatile (".chip 68k/68881\n\t"
"fsave %0\n\t"
".chip 68k"
: : "m" (*fpstate) : "memory");
- __put_user(*(long *)fpstate, (long *)&uc->uc_fpstate);
+ err |= __put_user(*(long *)fpstate, (long *)&uc->uc_fpstate);
if (CPU_IS_060 ? fpstate[2] : fpstate[0]) {
fpregset_t fpregs;
if (!CPU_IS_060)
@@ -566,11 +593,13 @@
: "m" (*fpregs.f_fpregs),
"m" (fpregs.f_pcr)
: "memory");
- copy_to_user(&uc->uc_mcontext.fpregs, &fpregs, sizeof(fpregs));
+ err |= copy_to_user(&uc->uc_mcontext.fpregs, &fpregs,
+ sizeof(fpregs));
}
if (context_size)
- copy_to_user((long *)&uc->uc_fpstate + 1, fpstate + 4,
- context_size);
+ err |= copy_to_user((long *)&uc->uc_fpstate + 1, fpstate + 4,
+ context_size);
+ return err;
}
static void setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
@@ -588,32 +617,34 @@
save_fpu_state(sc, regs);
}
-static inline void rt_setup_ucontext(struct ucontext *uc, struct pt_regs *regs)
+static inline int rt_setup_ucontext(struct ucontext *uc, struct pt_regs *regs)
{
struct switch_stack *sw = (struct switch_stack *)regs - 1;
greg_t *gregs = uc->uc_mcontext.gregs;
+ int err = 0;
- __put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version);
- __put_user(regs->d0, &gregs[0]);
- __put_user(regs->d1, &gregs[1]);
- __put_user(regs->d2, &gregs[2]);
- __put_user(regs->d3, &gregs[3]);
- __put_user(regs->d4, &gregs[4]);
- __put_user(regs->d5, &gregs[5]);
- __put_user(sw->d6, &gregs[6]);
- __put_user(sw->d7, &gregs[7]);
- __put_user(regs->a0, &gregs[8]);
- __put_user(regs->a1, &gregs[9]);
- __put_user(regs->a2, &gregs[10]);
- __put_user(sw->a3, &gregs[11]);
- __put_user(sw->a4, &gregs[12]);
- __put_user(sw->a5, &gregs[13]);
- __put_user(sw->a6, &gregs[14]);
- __put_user(rdusp(), &gregs[15]);
- __put_user(regs->pc, &gregs[16]);
- __put_user(regs->sr, &gregs[17]);
- __put_user((regs->format << 12) | regs->vector, &uc->uc_formatvec);
- rt_save_fpu_state(uc, regs);
+ err |= __put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version);
+ err |= __put_user(regs->d0, &gregs[0]);
+ err |= __put_user(regs->d1, &gregs[1]);
+ err |= __put_user(regs->d2, &gregs[2]);
+ err |= __put_user(regs->d3, &gregs[3]);
+ err |= __put_user(regs->d4, &gregs[4]);
+ err |= __put_user(regs->d5, &gregs[5]);
+ err |= __put_user(sw->d6, &gregs[6]);
+ err |= __put_user(sw->d7, &gregs[7]);
+ err |= __put_user(regs->a0, &gregs[8]);
+ err |= __put_user(regs->a1, &gregs[9]);
+ err |= __put_user(regs->a2, &gregs[10]);
+ err |= __put_user(sw->a3, &gregs[11]);
+ err |= __put_user(sw->a4, &gregs[12]);
+ err |= __put_user(sw->a5, &gregs[13]);
+ err |= __put_user(sw->a6, &gregs[14]);
+ err |= __put_user(rdusp(), &gregs[15]);
+ err |= __put_user(regs->pc, &gregs[16]);
+ err |= __put_user(regs->sr, &gregs[17]);
+ err |= __put_user((regs->format << 12) | regs->vector, &uc->uc_formatvec);
+ err |= rt_save_fpu_state(uc, regs);
+ return err;
}
static inline void push_cache (unsigned long vaddr)
@@ -708,60 +739,72 @@
}
}
+static inline void *
+get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
+{
+ unsigned long usp;
+
+ /* Default to using normal stack. */
+ usp = rdusp();
+
+ /* This is the X/Open sanctioned signal stack switching. */
+ if (ka->sa.sa_flags & SA_ONSTACK) {
+ if (!on_sig_stack(usp))
+ usp = current->sas_ss_sp + current->sas_ss_size;
+ }
+ return (void *)((usp - frame_size) & -8UL);
+}
+
static void setup_frame (int sig, struct k_sigaction *ka,
sigset_t *set, struct pt_regs *regs)
{
struct sigframe *frame;
int fsize = frame_extra_sizes[regs->format];
struct sigcontext context;
+ int err = 0;
if (fsize < 0) {
#ifdef DEBUG
printk ("setup_frame: Unknown frame format %#x\n",
regs->format);
#endif
- goto segv_and_exit;
+ goto give_sigsegv;
}
- frame = (struct sigframe *)((rdusp() - sizeof(*frame) - fsize) & -8);
-
- if (!(current->flags & PF_ONSIGSTK) && (ka->sa.sa_flags & SA_ONSTACK)) {
- frame = (struct sigframe *)(((unsigned long)ka->sa.sa_restorer
- - sizeof(*frame) - fsize) & -8);
- current->flags |= PF_ONSIGSTK;
- }
+ frame = get_sigframe(ka, regs, sizeof(*frame) + fsize);
if (fsize) {
- if (copy_to_user (frame + 1, regs + 1, fsize))
- goto segv_and_exit;
+ err |= copy_to_user (frame + 1, regs + 1, fsize);
regs->stkadj = fsize;
}
- __put_user((current->exec_domain
- && current->exec_domain->signal_invmap
- && sig < 32
- ? current->exec_domain->signal_invmap[sig]
- : sig),
- &frame->sig);
+ err |= __put_user((current->exec_domain
+ && current->exec_domain->signal_invmap
+ && sig < 32
+ ? current->exec_domain->signal_invmap[sig]
+ : sig),
+ &frame->sig);
- __put_user(regs->vector, &frame->code);
- __put_user(&frame->sc, &frame->psc);
+ err |= __put_user(regs->vector, &frame->code);
+ err |= __put_user(&frame->sc, &frame->psc);
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));
setup_sigcontext(&context, regs, set->sig[0]);
- if (copy_to_user (&frame->sc, &context, sizeof(context)))
- goto segv_and_exit;
+ err |= copy_to_user (&frame->sc, &context, sizeof(context));
/* Set up to return from userspace. */
- __put_user(frame->retcode, &frame->pretcode);
+ err |= __put_user(frame->retcode, &frame->pretcode);
/* addaw #20,sp */
- __put_user(0xdefc0014, (long *)(frame->retcode + 0));
+ err |= __put_user(0xdefc0014, (long *)(frame->retcode + 0));
/* moveq #,d0; trap #0 */
- __put_user(0x70004e40 + (__NR_sigreturn << 16),
- (long *)(frame->retcode + 4));
+ err |= __put_user(0x70004e40 + (__NR_sigreturn << 16),
+ (long *)(frame->retcode + 4));
+
+ if (err)
+ goto give_sigsegv;
push_cache ((unsigned long) &frame->retcode);
@@ -791,8 +834,10 @@
}
return;
-segv_and_exit:
- do_exit(SIGSEGV);
+give_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,
@@ -800,48 +845,53 @@
{
struct rt_sigframe *frame;
int fsize = frame_extra_sizes[regs->format];
+ int err = 0;
if (fsize < 0) {
#ifdef DEBUG
printk ("setup_frame: Unknown frame format %#x\n",
regs->format);
#endif
- goto segv_and_exit;
+ goto give_sigsegv;
}
- frame = (struct rt_sigframe *)((rdusp() - sizeof(*frame)) & -8);
-
- /* XXX: Check here if we need to switch stacks.. */
+ frame = get_sigframe(ka, regs, sizeof(*frame));
if (fsize) {
- if (copy_to_user (&frame->uc.uc_extra, regs + 1, fsize))
- goto segv_and_exit;
+ err |= copy_to_user (&frame->uc.uc_extra, regs + 1, fsize);
regs->stkadj = fsize;
}
- __put_user((current->exec_domain
- && current->exec_domain->signal_invmap
- && sig < 32
- ? current->exec_domain->signal_invmap[sig]
- : sig),
- &frame->sig);
- __put_user(&frame->info, &frame->pinfo);
- __put_user(&frame->uc, &frame->puc);
- __copy_to_user(&frame->info, info, sizeof(*info));
-
- /* Clear all the bits of the ucontext we don't use. */
- clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));
-
- rt_setup_ucontext(&frame->uc, regs);
- if (copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set)))
- goto segv_and_exit;
+ err |= __put_user((current->exec_domain
+ && current->exec_domain->signal_invmap
+ && sig < 32
+ ? current->exec_domain->signal_invmap[sig]
+ : sig),
+ &frame->sig);
+ err |= __put_user(&frame->info, &frame->pinfo);
+ err |= __put_user(&frame->uc, &frame->puc);
+ err |= __copy_to_user(&frame->info, info, sizeof(*info));
+
+ /* Create the ucontext. */
+ err |= __put_user(0, &frame->uc.uc_flags);
+ err |= __put_user(0, &frame->uc.uc_link);
+ err |= __put_user((void *)current->sas_ss_sp,
+ &frame->uc.uc_stack.ss_sp);
+ err |= __put_user(sas_ss_flags(rdusp()),
+ &frame->uc.uc_stack.ss_flags);
+ err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+ err |= rt_setup_ucontext(&frame->uc, regs);
+ err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set));
/* Set up to return from userspace. */
- __put_user(frame->retcode, &frame->pretcode);
+ err |= __put_user(frame->retcode, &frame->pretcode);
/* movel #,d0; trap #0 */
- __put_user(0x203c, (short *)(frame->retcode + 0));
- __put_user(__NR_rt_sigreturn, (long *)(frame->retcode + 2));
- __put_user(0x4e40, (short *)(frame->retcode + 6));
+ err |= __put_user(0x203c, (short *)(frame->retcode + 0));
+ err |= __put_user(__NR_rt_sigreturn, (long *)(frame->retcode + 2));
+ err |= __put_user(0x4e40, (short *)(frame->retcode + 6));
+
+ if (err)
+ goto give_sigsegv;
push_cache ((unsigned long) &frame->retcode);
@@ -871,8 +921,10 @@
}
return;
-segv_and_exit:
- do_exit(SIGSEGV);
+give_sigsegv:
+ if (sig == SIGSEGV)
+ ka->sa.sa_handler = SIG_DFL;
+ force_sig(SIGSEGV, current);
}
static inline void
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov