From 9d0d2c74617560e64b92c485526e4d279fc6fb5f Mon Sep 17 00:00:00 2001 From: uwe Date: Sun, 23 Nov 2003 23:13:11 +0000 Subject: [PATCH] Implement siginfo for sh3. --- lib/libc/arch/sh3/Makefile.inc | 6 +- .../arch/sh3/sys/__sigaction14_sigtramp.c | 25 ++- lib/libc/arch/sh3/sys/__sigtramp2.S | 59 +++++++ sys/arch/sh3/include/frame.h | 34 +++- sys/arch/sh3/include/signal.h | 9 +- sys/arch/sh3/sh3/exception.c | 61 +++++-- sys/arch/sh3/sh3/sh3_machdep.c | 154 ++++++++++++++---- 7 files changed, 293 insertions(+), 55 deletions(-) create mode 100644 lib/libc/arch/sh3/sys/__sigtramp2.S diff --git a/lib/libc/arch/sh3/Makefile.inc b/lib/libc/arch/sh3/Makefile.inc index 82cc6162f234..3c9f4dba2755 100644 --- a/lib/libc/arch/sh3/Makefile.inc +++ b/lib/libc/arch/sh3/Makefile.inc @@ -1,11 +1,11 @@ -# $NetBSD: Makefile.inc,v 1.3 2002/07/10 04:29:08 thorpej Exp $ +# $NetBSD: Makefile.inc,v 1.4 2003/11/23 23:13:11 uwe Exp $ KMINCLUDES= arch/sh3/SYS.h -CPPFLAGS+= -DSOFTFLOAT +CPPFLAGS+= -DSOFTFLOAT # -DSOFTFLOAT_NEED_FIXUNS .include #KMSRCS= bcmp.S bzero.S ffs.S strcat.S strcmp.S strcpy.S strlen.S \ # htonl.S htons.S ntohl.S ntohs.S -SRCS+= __sigaction14_sigtramp.c __sigtramp1.S +SRCS+= __sigaction14_sigtramp.c __sigtramp1.S __sigtramp2.S diff --git a/lib/libc/arch/sh3/sys/__sigaction14_sigtramp.c b/lib/libc/arch/sh3/sys/__sigaction14_sigtramp.c index b5a2be20affc..58101f89699c 100644 --- a/lib/libc/arch/sh3/sys/__sigaction14_sigtramp.c +++ b/lib/libc/arch/sh3/sys/__sigaction14_sigtramp.c @@ -1,7 +1,7 @@ -/* $NetBSD: __sigaction14_sigtramp.c,v 1.2 2003/01/18 11:14:02 thorpej Exp $ */ +/* $NetBSD: __sigaction14_sigtramp.c,v 1.3 2003/11/23 23:13:11 uwe Exp $ */ /*- - * Copyright (c) 2002 The NetBSD Foundation, Inc. + * Copyright (c) 2003 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation @@ -40,6 +40,7 @@ #include #include +#include #include "extern.h" @@ -49,12 +50,24 @@ int __libc_sigaction14(int sig, const struct sigaction *act, struct sigaction *oact) { extern int __sigtramp_sigcontext_1[]; + extern int __sigtramp_siginfo_2[]; + int rv; /* - * Right here we should select the SA_SIGINFO trampoline - * if SA_SIGINFO is set in the sigaction. + * We select the compatibility SIGCONTEXT trampoline if SA_SIGINFO + * is not set in the sigaction. */ + if (act && (act->sa_flags & SA_SIGINFO) == 0) { + rv = __sigaction_sigtramp(sig, act, oact, + __sigtramp_sigcontext_1, 1); + /* + * EINVAL might indicate that trampoline version 1 is + * not supported by the kernel; fall back on native + * SIGINFO trampoline. + */ + if (rv >= 0 || errno != EINVAL) + return rv; + } - return (__sigaction_sigtramp(sig, act, oact, - __sigtramp_sigcontext_1, 1)); + return __sigaction_sigtramp(sig, act, oact, __sigtramp_siginfo_2, 2); } diff --git a/lib/libc/arch/sh3/sys/__sigtramp2.S b/lib/libc/arch/sh3/sys/__sigtramp2.S new file mode 100644 index 000000000000..33aaec181d23 --- /dev/null +++ b/lib/libc/arch/sh3/sys/__sigtramp2.S @@ -0,0 +1,59 @@ +/* $NetBSD: __sigtramp2.S,v 1.1 2003/11/23 23:13:11 uwe Exp $ */ + +/*- + * Copyright (c) 2003 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "SYS.h" + +/* + * The SH signal trampoline is invoked only to return from + * the signal; the kernel calls the signal handler directly. + * + * On entry, stack looks like: + * + * siginfo structure + * sp-> ucontext structure + * + * NB: This order is different from what other ports use (siginfo at + * the top of the stack), because we want to avoid wasting two + * instructions to skip to the ucontext. Not that this order really + * matters, but I think this inconsistency deserves an explanation. + */ +NENTRY(__sigtramp_siginfo_2) + mov r15, r4 /* get pointer to ucontext */ + SYSTRAP(setcontext) /* and call setcontext() */ + mov r0, r4 /* exit with errno */ + SYSTRAP(exit) /* if sigreturn fails */ diff --git a/sys/arch/sh3/include/frame.h b/sys/arch/sh3/include/frame.h index 557f8d3ea732..fd1b70106300 100644 --- a/sys/arch/sh3/include/frame.h +++ b/sys/arch/sh3/include/frame.h @@ -1,4 +1,4 @@ -/* $NetBSD: frame.h,v 1.11 2003/08/07 16:29:28 agc Exp $ */ +/* $NetBSD: frame.h,v 1.12 2003/11/23 23:13:11 uwe Exp $ */ /*- * Copyright (c) 1990 The Regents of the University of California. @@ -128,12 +128,38 @@ struct switchframe { }; /* - * Signal frame + * Signal frame. + * + * NB: The order of sf_uc and sf_si is different from what other ports + * use (siginfo at the top of the stack), because we want to avoid + * wasting two instructions in __sigtramp_siginfo_2 to skip to the + * ucontext. Not that this order really matters, but I think this + * inconsistency deserves an explanation. */ -struct sigframe { - struct sigcontext sf_sc; +struct sigframe_siginfo { +#if 0 /* in registers on entry to signal trampoline */ + int sf_signum; /* r4 - "signum" argument for handler */ + siginfo_t *sf_sip; /* r5 - "sip" argument for handler */ + ucontext_t *sf_ucp; /* r6 - "ucp" argument for handler */ +#endif + ucontext_t sf_uc; /* actual saved ucontext */ + siginfo_t sf_si; /* actual saved siginfo */ }; +#if defined(COMPAT_16) && defined(_KERNEL) +/* + * Old signal frame format. + */ +struct sigframe_sigcontext { +#if 0 /* in registers on entry to signal trampoline */ + int sf_signum; /* r4 - "signum" argument for handler */ + int sf_code; /* r5 - "code" argument for handler */ + struct sigcontext *sf_scp; /* r6 - "scp" argument for handler */ +#endif + struct sigcontext sf_sc; /* actual saved context */ +}; +#endif + /* * Scheduler activations upcall frame */ diff --git a/sys/arch/sh3/include/signal.h b/sys/arch/sh3/include/signal.h index c5d2dd0ce266..9cfb5885316c 100644 --- a/sys/arch/sh3/include/signal.h +++ b/sys/arch/sh3/include/signal.h @@ -1,4 +1,4 @@ -/* $NetBSD: signal.h,v 1.7 2003/08/07 16:29:29 agc Exp $ */ +/* $NetBSD: signal.h,v 1.8 2003/11/23 23:13:11 uwe Exp $ */ /* * Copyright (c) 1982, 1986, 1989, 1991 Regents of the University of California. @@ -38,6 +38,13 @@ typedef int sig_atomic_t; +#define __HAVE_SIGINFO +#ifdef COMPAT_16 +#define SIGTRAMP_VALID(vers) ((unsigned)(vers) <= 2) +#else +#define SIGTRAMP_VALID(vers) ((vers) == 2) +#endif + #if defined(_NETBSD_SOURCE) /* diff --git a/sys/arch/sh3/sh3/exception.c b/sys/arch/sh3/sh3/exception.c index 7d608489789e..32f5c44b9abd 100644 --- a/sys/arch/sh3/sh3/exception.c +++ b/sys/arch/sh3/sh3/exception.c @@ -1,4 +1,4 @@ -/* $NetBSD: exception.c,v 1.15 2003/10/31 03:28:13 simonb Exp $ */ +/* $NetBSD: exception.c,v 1.16 2003/11/23 23:13:11 uwe Exp $ */ /*- * Copyright (c) 1990 The Regents of the University of California. @@ -79,7 +79,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: exception.c,v 1.15 2003/10/31 03:28:13 simonb Exp $"); +__KERNEL_RCSID(0, "$NetBSD: exception.c,v 1.16 2003/11/23 23:13:11 uwe Exp $"); #include "opt_ddb.h" #include "opt_kgdb.h" @@ -153,6 +153,7 @@ general_exception(struct lwp *l, struct trapframe *tf) { int expevt = tf->tf_expevt; boolean_t usermode = !KERNELMODE(tf->tf_ssr); + ksiginfo_t ksi; uvmexp.traps++; @@ -169,12 +170,17 @@ general_exception(struct lwp *l, struct trapframe *tf) /* Check for debugger break */ if (_reg_read_4(SH_(TRA)) == (_SH_TRA_BREAK << 2)) { tf->tf_spc -= 2; /* back to the breakpoint address */ - trapsignal(l, SIGTRAP, tf->tf_expevt); + KSI_INIT_TRAP(&ksi); + ksi.ksi_signo = SIGTRAP; + ksi.ksi_code = TRAP_BRKPT; + ksi.ksi_addr = (void *)tf->tf_spc; + goto trapsignal; } else { syscall(l, tf); return; } break; + case EXPEVT_ADDR_ERR_LD: /*FALLTHROUGH*/ case EXPEVT_ADDR_ERR_ST: @@ -187,18 +193,29 @@ general_exception(struct lwp *l, struct trapframe *tf) case EXPEVT_ADDR_ERR_LD | EXP_USER: /*FALLTHROUGH*/ case EXPEVT_ADDR_ERR_ST | EXP_USER: - trapsignal(l, SIGSEGV, tf->tf_expevt); - break; + KSI_INIT_TRAP(&ksi); + /* XXX: for kernel access attempt this should be a SIGSEGV */ + ksi.ksi_signo = SIGBUS; + ksi.ksi_code = BUS_ADRALN; + ksi.ksi_addr = (void *)tf->tf_spc; /* XXX: use TEA */ + goto trapsignal; case EXPEVT_RES_INST | EXP_USER: /*FALLTHROUGH*/ case EXPEVT_SLOT_INST | EXP_USER: - trapsignal(l, SIGILL, tf->tf_expevt); - break; + KSI_INIT_TRAP(&ksi); + ksi.ksi_signo = SIGILL; + ksi.ksi_code = ILL_ILLOPC; /* XXX: could be ILL_PRVOPC */ + ksi.ksi_addr = (void *)tf->tf_spc; + goto trapsignal; case EXPEVT_BREAK | EXP_USER: - trapsignal(l, SIGTRAP, tf->tf_expevt); - break; + KSI_INIT_TRAP(&ksi); + ksi.ksi_signo = SIGTRAP; + ksi.ksi_code = TRAP_BRKPT; /* XXX: ??? */ + ksi.ksi_addr = (void *)tf->tf_spc; + goto trapsignal; + default: goto do_panic; } @@ -207,6 +224,14 @@ general_exception(struct lwp *l, struct trapframe *tf) userret(l); return; + trapsignal: + ksi.ksi_trap = tf->tf_expevt; + KERNEL_PROC_LOCK(l); + trapsignal(l, &ksi); + KERNEL_PROC_UNLOCK(l); + userret(l); + return; + do_panic: #ifdef DDB if (kdb_trap(expevt, 0, tf)) @@ -387,6 +412,7 @@ do { \ } while(/*CONSTCOND*/0) struct vm_map *map; pmap_t pmap; + ksiginfo_t ksi; boolean_t usermode; int err, track, ftype; char *panic_msg; @@ -417,7 +443,10 @@ do { \ TLB_ASSERT((int)va > 0, "kernel virtual protection fault (load)"); if (usermode) { - trapsignal(l, SIGSEGV, tf->tf_expevt); + KSI_INIT_TRAP(&ksi); + ksi.ksi_signo = SIGSEGV; + ksi.ksi_code = SEGV_MAPERR; + ksi.ksi_addr = (void *)va; goto user_fault; } else { TLB_ASSERT(l && l->l_md.md_pcb->pcb_onfault != NULL, @@ -509,7 +538,13 @@ do { \ /* Page not found. */ if (usermode) { - trapsignal(l, err == ENOMEM ? SIGKILL : SIGSEGV, tf->tf_expevt); + KSI_INIT_TRAP(&ksi); + if (err == ENOMEM) + ksi.ksi_signo = SIGKILL; + else { + ksi.ksi_signo = SIGSEGV; + ksi.ksi_code = SEGV_MAPERR; + } goto user_fault; } else { TLB_ASSERT(l->l_md.md_pcb->pcb_onfault, @@ -519,6 +554,10 @@ do { \ return; user_fault: + ksi.ksi_trap = tf->tf_expevt + KERNEL_PROC_LOCK(l); + trapsignal(l, &ksi); + KERNEL_PROC_UNLOCK(l); userret(l); ast(l, tf); return; diff --git a/sys/arch/sh3/sh3/sh3_machdep.c b/sys/arch/sh3/sh3/sh3_machdep.c index 4e105446c0cb..015678b5489b 100644 --- a/sys/arch/sh3/sh3/sh3_machdep.c +++ b/sys/arch/sh3/sh3/sh3_machdep.c @@ -1,4 +1,4 @@ -/* $NetBSD: sh3_machdep.c,v 1.52 2003/09/26 12:02:56 simonb Exp $ */ +/* $NetBSD: sh3_machdep.c,v 1.53 2003/11/23 23:13:11 uwe Exp $ */ /*- * Copyright (c) 1996, 1997, 1998, 2002 The NetBSD Foundation, Inc. @@ -72,7 +72,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: sh3_machdep.c,v 1.52 2003/09/26 12:02:56 simonb Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sh3_machdep.c,v 1.53 2003/11/23 23:13:11 uwe Exp $"); #include "opt_kgdb.h" #include "opt_memsize.h" @@ -406,8 +406,28 @@ cpu_upcall(struct lwp *l, int type, int nevents, int ninterrupted, void *sas, } /* - * Send an interrupt to process. - * + * Get the base address of the signal frame either on the lwp's stack + * or on the signal stack and set *onstack accordingly. Caller then + * just subtracts the size of appropriate struct sigframe_foo. + */ +static void * +getframe(struct lwp *l, int sig, int *onstack) +{ + struct proc *p = l->l_proc; + struct sigaltstack *sigstk= &p->p_sigctx.ps_sigstk; + + /* Do we need to jump onto the signal stack? */ + *onstack = (sigstk->ss_flags & (SS_DISABLE | SS_ONSTACK)) == 0 + && (SIGACTION(p, sig).sa_flags & SA_ONSTACK) != 0; + + if (*onstack) + return ((char *)sigstk->ss_sp + sigstk->ss_size); + else + return ((void *)l->l_md.md_regs->tf_r15); +} + +#ifdef COMPAT_16 +/* * Stack is set up to allow sigcode stored * in u. to call routine, followed by kcall * to sigreturn routine below. After sigreturn @@ -415,31 +435,20 @@ cpu_upcall(struct lwp *l, int type, int nevents, int ninterrupted, void *sas, * frame pointer, it returns to the user * specified pc, psl. */ -void -sendsig(int sig, const sigset_t *mask, u_long code) +static void +sendsig_sigcontext(const ksiginfo_t *ksi, const sigset_t *mask) { struct lwp *l = curlwp; struct proc *p = l->l_proc; struct sigacts *ps = p->p_sigacts; - struct trapframe *tf; - struct sigframe *fp, frame; - int onstack; + struct trapframe *tf = l->l_md.md_regs; + int sig = ksi->ksi_info._signo; sig_t catcher = SIGACTION(p, sig).sa_handler; + struct sigframe_sigcontext *fp, frame; + int onstack; - tf = l->l_md.md_regs; - - /* Do we need to jump onto the signal stack? */ - onstack = - (p->p_sigctx.ps_sigstk.ss_flags & (SS_DISABLE | SS_ONSTACK)) == 0 && - (SIGACTION(p, sig).sa_flags & SA_ONSTACK) != 0; - - /* Allocate space for the signal handler context. */ - if (onstack) - fp = (struct sigframe *)((caddr_t)p->p_sigctx.ps_sigstk.ss_sp + - p->p_sigctx.ps_sigstk.ss_size); - else - fp = (struct sigframe *)tf->tf_r15; - fp--; + fp = getframe(l, sig, &onstack); + --fp; /* Save register context. */ frame.sf_sc.sc_ssr = tf->tf_ssr; @@ -483,11 +492,9 @@ sendsig(int sig, const sigset_t *mask, u_long code) * directly, only returning via the trampoline. */ switch (ps->sa_sigdesc[sig].sd_vers) { -#if 1 /* COMPAT_16 */ case 0: /* legacy on-stack sigtramp */ tf->tf_pr = (int)p->p_sigctx.ps_sigcode; break; -#endif /* COMPAT_16 */ case 1: tf->tf_pr = (int)ps->sa_sigdesc[sig].sd_tramp; @@ -495,20 +502,94 @@ sendsig(int sig, const sigset_t *mask, u_long code) default: /* Don't know what trampoline version; kill it. */ + printf("sendsig_sigcontext: bad version %d\n", + ps->sa_sigdesc[sig].sd_vers); sigexit(l, SIGILL); } tf->tf_r4 = sig; - tf->tf_r5 = code; + tf->tf_r5 = ksi->ksi_code; tf->tf_r6 = (int)&fp->sf_sc; - tf->tf_spc = (int)catcher; + tf->tf_spc = (int)catcher; tf->tf_r15 = (int)fp; - /* Remember that we're now on the signal stack. */ + /* Remember if we're now on the signal stack. */ + if (onstack) + p->p_sigctx.ps_sigstk.ss_flags |= SS_ONSTACK; +} +#endif /* COMPAT_16 */ + +static void +sendsig_siginfo(const ksiginfo_t *ksi, const sigset_t *mask) +{ + struct lwp *l = curlwp; + struct proc *p = l->l_proc; + struct sigacts *ps = p->p_sigacts; + struct trapframe *tf = l->l_md.md_regs; + int sig = ksi->ksi_signo; + sig_t catcher = SIGACTION(p, sig).sa_handler; + struct sigframe_siginfo *fp, frame; + int onstack; + + switch (ps->sa_sigdesc[sig].sd_vers) { + case 0: /* handled by sendsig_sigcontext */ + case 1: /* handled by sendsig_sigcontext */ + default: /* unknown version */ + printf("sendsig_siginfo: bad version %d\n", + ps->sa_sigdesc[sig].sd_vers); + sigexit(l, SIGILL); + case 2: + break; + } + + fp = getframe(l, sig, &onstack); + --fp; + + frame.sf_si._info = ksi->ksi_info; + frame.sf_uc.uc_link = NULL; + frame.sf_uc.uc_sigmask = *mask; + frame.sf_uc.uc_flags = _UC_SIGMASK; + frame.sf_uc.uc_flags |= (p->p_sigctx.ps_sigstk.ss_flags & SS_ONSTACK) + ? _UC_SETSTACK : _UC_CLRSTACK; + memset(&frame.sf_uc.uc_stack, 0, sizeof(frame.sf_uc.uc_stack)); + cpu_getmcontext(l, &frame.sf_uc.uc_mcontext, &frame.sf_uc.uc_flags); + + if (copyout(&frame, fp, sizeof(frame)) != 0) { + /* + * Process has trashed its stack; give it an illegal + * instruction to halt it in its tracks. + */ + sigexit(l, SIGILL); + /* NOTREACHED */ + } + + tf->tf_r4 = sig; /* "signum" argument for handler */ + tf->tf_r5 = (int)&fp->sf_si; /* "sip" argument for handler */ + tf->tf_r6 = (int)&fp->sf_uc; /* "ucp" argument for handler */ + tf->tf_spc = (int)catcher; + tf->tf_r15 = (int)fp; + tf->tf_pr = (int)ps->sa_sigdesc[sig].sd_tramp; + + /* Remember if we're now on the signal stack. */ if (onstack) p->p_sigctx.ps_sigstk.ss_flags |= SS_ONSTACK; } +/* + * Send an interrupt to process. + */ +void +sendsig(const ksiginfo_t *ksi, const sigset_t *mask) +{ +#ifdef COMPAT_16 + if (curproc->p_sigacts->sa_sigdesc[ksi->ksi_signo].sd_vers < 2) + sendsig_sigcontext(ksi, mask); + else +#endif + sendsig_siginfo(ksi, mask); +} + +#ifdef COMPAT_16 /* * System call to cleanup state after a signal * has been taken. Reset signal mask and @@ -520,9 +601,9 @@ sendsig(int sig, const sigset_t *mask, u_long code) * a machine fault. */ int -sys___sigreturn14(struct lwp *l, void *v, register_t *retval) +compat_16_sys___sigreturn14(struct lwp *l, void *v, register_t *retval) { - struct sys___sigreturn14_args /* { + struct compat_16_sys___sigreturn14_args /* { syscallarg(struct sigcontext *) sigcntxp; } */ *uap = v; struct sigcontext *scp, context; @@ -576,6 +657,7 @@ sys___sigreturn14(struct lwp *l, void *v, register_t *retval) return (EJUSTRETURN); } +#endif /* COMPAT_16 */ void cpu_getmcontext(l, mcp, flags) @@ -660,6 +742,18 @@ cpu_setmcontext(l, mcp, flags) tf->tf_r15 = gr[_REG_R15]; } +#if 0 + /* XXX: FPU context is currently not handled by the kernel. */ + if (flags & _UC_FPU) { + /* TODO */; + } +#endif + + if (flags & _UC_SETSTACK) + l->l_proc->p_sigctx.ps_sigstk.ss_flags |= SS_ONSTACK; + if (flags & _UC_CLRSTACK) + l->l_proc->p_sigctx.ps_sigstk.ss_flags &= ~SS_ONSTACK; + return (0); }