diff options
Diffstat (limited to 'arch/m68k/kernel/signal.c')
-rw-r--r-- | arch/m68k/kernel/signal.c | 104 |
1 files changed, 56 insertions, 48 deletions
diff --git a/arch/m68k/kernel/signal.c b/arch/m68k/kernel/signal.c index a2b9ce1d4..f35dd94c5 100644 --- a/arch/m68k/kernel/signal.c +++ b/arch/m68k/kernel/signal.c @@ -14,6 +14,10 @@ * 68060 fixes by Jesper Skov * * 1997-12-01 Modified for POSIX.1b signals by Andreas Schwab + * + * mathemu support by Roman Zippel + * (Note: fpstate in the signal context is completly ignored for the emulator + * and the internal floating point format is put on stack) */ /* @@ -156,6 +160,9 @@ sys_sigaltstack(const stack_t *uss, stack_t *uoss) /* * Do a signal return; undo the signal stack. + * + * Keep the return code on the stack quadword aligned! + * That makes the cache flush below easier. */ struct sigframe @@ -175,9 +182,9 @@ struct rt_sigframe int sig; struct siginfo *pinfo; void *puc; + char retcode[8]; struct siginfo info; struct ucontext uc; - char retcode[8]; }; @@ -187,6 +194,13 @@ static inline int restore_fpu_state(struct sigcontext *sc) { int err = 1; + if (FPU_IS_EMU) { + /* restore registers */ + memcpy(current->thread.fpcntl, sc->sc_fpcntl, 12); + memcpy(current->thread.fp, sc->sc_fpregs, 24); + return 0; + } + 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)) @@ -239,6 +253,18 @@ static inline int rt_restore_fpu_state(struct ucontext *uc) fpregset_t fpregs; int err = 1; + if (FPU_IS_EMU) { + /* restore fpu control register */ + if (__copy_from_user(current->thread.fpcntl, + &uc->uc_mcontext.fpregs.f_pcr, 12)) + goto out; + /* restore all other fpu register */ + if (__copy_from_user(current->thread.fp, + uc->uc_mcontext.fpregs.f_fpregs, 96)) + goto out; + return 0; + } + if (__get_user(*(long *)fpstate, (long *)&uc->uc_fpstate)) goto out; if (CPU_IS_060 ? fpstate[2] : fpstate[0]) { @@ -478,7 +504,7 @@ asmlinkage int do_sigreturn(unsigned long __unused) struct switch_stack *sw = (struct switch_stack *) &__unused; struct pt_regs *regs = (struct pt_regs *) (sw + 1); unsigned long usp = rdusp(); - struct sigframe *frame = (struct sigframe *)(usp - 24); + struct sigframe *frame = (struct sigframe *)(usp - 4); sigset_t set; int d0; @@ -536,6 +562,13 @@ badframe: static inline void save_fpu_state(struct sigcontext *sc, struct pt_regs *regs) { + if (FPU_IS_EMU) { + /* save registers */ + memcpy(sc->sc_fpcntl, current->thread.fpcntl, 12); + memcpy(sc->sc_fpregs, current->thread.fp, 24); + return; + } + __asm__ volatile (".chip 68k/68881\n\t" "fsave %0\n\t" ".chip 68k" @@ -567,6 +600,16 @@ static inline int rt_save_fpu_state(struct ucontext *uc, struct pt_regs *regs) int context_size = CPU_IS_060 ? 8 : 0; int err = 0; + if (FPU_IS_EMU) { + /* save fpu control register */ + err |= copy_to_user(&uc->uc_mcontext.fpregs.f_pcr, + current->thread.fpcntl, 12); + /* save all other fpu register */ + err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpregs, + current->thread.fp, 96); + return err; + } + __asm__ volatile (".chip 68k/68881\n\t" "fsave %0\n\t" ".chip 68k" @@ -677,25 +720,6 @@ static inline void push_cache (unsigned long vaddr) "cpushl %%bc,(%0)\n\t" ".chip 68k" : : "a" (temp)); - if (((vaddr + 8) ^ vaddr) & ~15) { - if (((vaddr + 8) ^ vaddr) & PAGE_MASK) - __asm__ __volatile__ (".chip 68040\n\t" - "nop\n\t" - "ptestr (%1)\n\t" - "movec %%mmusr,%0\n\t" - ".chip 68k" - : "=r" (temp) - : "a" (vaddr + 8)); - - temp &= PAGE_MASK; - temp |= (vaddr + 8) & ~PAGE_MASK; - - __asm__ __volatile__ (".chip 68040\n\t" - "nop\n\t" - "cpushl %%bc,(%0)\n\t" - ".chip 68k" - : : "a" (temp)); - } } else if (CPU_IS_060) { unsigned long temp; @@ -708,18 +732,6 @@ static inline void push_cache (unsigned long vaddr) "cpushl %%bc,(%0)\n\t" ".chip 68k" : : "a" (temp)); - if (((vaddr + 8) ^ vaddr) & ~15) { - if (((vaddr + 8) ^ vaddr) & PAGE_MASK) - __asm__ __volatile__ (".chip 68060\n\t" - "plpar (%0)\n\t" - ".chip 68k" - : "=a" (temp) - : "0" (vaddr + 8)); - __asm__ __volatile__ (".chip 68060\n\t" - "cpushl %%bc,(%0)\n\t" - ".chip 68k" - : : "a" (temp)); - } } else { /* @@ -797,11 +809,9 @@ static void setup_frame (int sig, struct k_sigaction *ka, /* Set up to return from userspace. */ err |= __put_user(frame->retcode, &frame->pretcode); - /* addaw #20,sp */ - err |= __put_user(0xdefc0014, (long *)(frame->retcode + 0)); /* moveq #,d0; trap #0 */ err |= __put_user(0x70004e40 + (__NR_sigreturn << 16), - (long *)(frame->retcode + 4)); + (long *)(frame->retcode)); if (err) goto give_sigsegv; @@ -881,10 +891,10 @@ static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info, /* Set up to return from userspace. */ err |= __put_user(frame->retcode, &frame->pretcode); - /* movel #,d0; trap #0 */ - 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)); + /* moveq #,d0; notb d0; trap #0 */ + err |= __put_user(0x70004600 + ((__NR_rt_sigreturn ^ 0xff) << 16), + (long *)(frame->retcode + 0)); + err |= __put_user(0x4e40, (short *)(frame->retcode + 4)); if (err) goto give_sigsegv; @@ -964,11 +974,10 @@ handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, if (ka->sa.sa_flags & SA_ONESHOT) ka->sa.sa_handler = SIG_DFL; - if (!(ka->sa.sa_flags & SA_NODEFER)) { - sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + if (!(ka->sa.sa_flags & SA_NODEFER)) sigaddset(¤t->blocked,sig); - recalc_sigpending(current); - } + recalc_sigpending(current); } /* @@ -985,7 +994,7 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs) siginfo_t info; struct k_sigaction *ka; - current->tss.esp0 = (unsigned long) regs; + current->thread.esp0 = (unsigned long) regs; if (!oldset) oldset = ¤t->blocked; @@ -1084,14 +1093,13 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs) case SIGQUIT: case SIGILL: case SIGTRAP: case SIGIOT: case SIGFPE: case SIGSEGV: - if (current->binfmt - && current->binfmt->core_dump - && current->binfmt->core_dump(signr, regs)) + if (do_coredump(signr, regs)) exit_code |= 0x80; /* FALLTHRU */ default: sigaddset(¤t->signal, signr); + recalc_sigpending(current); current->flags |= PF_SIGNALED; do_exit(exit_code); /* NOTREACHED */ |