Module Name: src Committed By: reinoud Date: Sat Jan 21 22:09:57 UTC 2012
Modified Files: src/sys/arch/usermode/dev: clock.c cpu.c if_veth.c ld_thunkbus.c ttycons.c src/sys/arch/usermode/include: intr.h src/sys/arch/usermode/usermode: intr.c trap.c Log Message: Complete rewrite of the signal and spl framework for NetBSD/usermode Signals are now moved from the sigaltstack ASAP and stacked on a replacement stack for each processes. Preemption now works though could be enhanced a bit more To generate a diff of this commit: cvs rdiff -u -r1.25 -r1.26 src/sys/arch/usermode/dev/clock.c cvs rdiff -u -r1.68 -r1.69 src/sys/arch/usermode/dev/cpu.c cvs rdiff -u -r1.4 -r1.5 src/sys/arch/usermode/dev/if_veth.c cvs rdiff -u -r1.29 -r1.30 src/sys/arch/usermode/dev/ld_thunkbus.c cvs rdiff -u -r1.17 -r1.18 src/sys/arch/usermode/dev/ttycons.c cvs rdiff -u -r1.6 -r1.7 src/sys/arch/usermode/include/intr.h cvs rdiff -u -r1.14 -r1.15 src/sys/arch/usermode/usermode/intr.c cvs rdiff -u -r1.60 -r1.61 src/sys/arch/usermode/usermode/trap.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/usermode/dev/clock.c diff -u src/sys/arch/usermode/dev/clock.c:1.25 src/sys/arch/usermode/dev/clock.c:1.26 --- src/sys/arch/usermode/dev/clock.c:1.25 Sat Jan 14 21:42:51 2012 +++ src/sys/arch/usermode/dev/clock.c Sat Jan 21 22:09:56 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: clock.c,v 1.25 2012/01/14 21:42:51 reinoud Exp $ */ +/* $NetBSD: clock.c,v 1.26 2012/01/21 22:09:56 reinoud Exp $ */ /*- * Copyright (c) 2007 Jared D. McNeill <jmcne...@invisible.ca> @@ -29,7 +29,7 @@ #include "opt_hz.h" #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.25 2012/01/14 21:42:51 reinoud Exp $"); +__KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.26 2012/01/21 22:09:56 reinoud Exp $"); #include <sys/param.h> #include <sys/proc.h> @@ -50,11 +50,14 @@ __KERNEL_RCSID(0, "$NetBSD: clock.c,v 1. static int clock_match(device_t, cfdata_t, void *); static void clock_attach(device_t, device_t, void *); -static void clock_signal(int sig, siginfo_t *info, void *ctx); static unsigned int clock_getcounter(struct timecounter *); static int clock_todr_gettime(struct todr_chip_handle *, struct timeval *); +extern void setup_clock_intr(void); +void clock_intr(void *priv); + + struct clock_softc { device_t sc_dev; struct todr_chip_handle sc_todr; @@ -72,6 +75,7 @@ static struct timecounter clock_timecoun }; timer_t clock_timerid; +int clock_running = 0; CFATTACH_DECL_NEW(clock, sizeof(struct clock_softc), clock_match, clock_attach, NULL, NULL); @@ -90,7 +94,6 @@ clock_match(device_t parent, cfdata_t ma static void clock_attach(device_t parent, device_t self, void *opaque) { - static struct sigaction sa; struct clock_softc *sc = device_private(self); aprint_naive("\n"); @@ -101,21 +104,15 @@ clock_attach(device_t parent, device_t s sc->sc_todr.todr_gettime = clock_todr_gettime; todr_attach(&sc->sc_todr); - memset(&sa, 0, sizeof(sa)); - thunk_sigemptyset(&sa.sa_mask); - sa.sa_sigaction = clock_signal; - sa.sa_flags = SA_RESTART | SA_ONSTACK; - if (thunk_sigaction(SIGALRM, &sa, NULL) == -1) - panic("couldn't register SIGALRM handler : %d", - thunk_geterrno()); - clock_timerid = thunk_timer_attach(); - clock_timecounter.tc_quality = 1000; tc_init(&clock_timecounter); + + setup_clock_intr(); + clock_running = 1; } -static void +void clock_intr(void *priv) { struct clockframe cf; @@ -126,13 +123,6 @@ clock_intr(void *priv) } } -static void -clock_signal(int sig, siginfo_t *info, void *ctx) -{ - curcpu()->ci_idepth++; - spl_intr(IPL_SOFTCLOCK, clock_intr, NULL); - curcpu()->ci_idepth--; -} static unsigned int clock_getcounter(struct timecounter *tc) Index: src/sys/arch/usermode/dev/cpu.c diff -u src/sys/arch/usermode/dev/cpu.c:1.68 src/sys/arch/usermode/dev/cpu.c:1.69 --- src/sys/arch/usermode/dev/cpu.c:1.68 Wed Jan 18 19:17:02 2012 +++ src/sys/arch/usermode/dev/cpu.c Sat Jan 21 22:09:56 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: cpu.c,v 1.68 2012/01/18 19:17:02 reinoud Exp $ */ +/* $NetBSD: cpu.c,v 1.69 2012/01/21 22:09:56 reinoud Exp $ */ /*- * Copyright (c) 2007 Jared D. McNeill <jmcne...@invisible.ca> @@ -30,7 +30,7 @@ #include "opt_hz.h" #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.68 2012/01/18 19:17:02 reinoud Exp $"); +__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.69 2012/01/21 22:09:56 reinoud Exp $"); #include <sys/param.h> #include <sys/conf.h> @@ -244,12 +244,13 @@ cpu_switchto(lwp_t *oldlwp, lwp_t *newlw thunk_makecontext(&sc->sc_ucp, (void (*)(void)) cpu_switchto_atomic, 2, oldlwp, newlwp, NULL); - if (!oldpcb) { - thunk_setcontext(&sc->sc_ucp); - /* never returns */ - } else { + KASSERT(sc); + if (oldpcb) { thunk_swapcontext(&oldpcb->pcb_ucp, &sc->sc_ucp); /* returns here */ + } else { + thunk_setcontext(&sc->sc_ucp); + /* never returns */ } #ifdef CPU_DEBUG @@ -374,8 +375,10 @@ cpu_lwp_fork(struct lwp *l1, struct lwp /* get l2 its own stack */ pcb2->pcb_ucp.uc_stack.ss_sp = pcb2->sys_stack; pcb2->pcb_ucp.uc_stack.ss_size = pcb2->sys_stack_top - pcb2->sys_stack; - pcb2->pcb_ucp.uc_flags = _UC_STACK | _UC_CPU | _UC_SIGMASK; pcb2->pcb_ucp.uc_link = &pcb2->pcb_userret_ucp; + + thunk_sigemptyset(&pcb2->pcb_ucp.uc_sigmask); + pcb2->pcb_ucp.uc_flags = _UC_STACK | _UC_CPU | _UC_SIGMASK; thunk_makecontext(&pcb2->pcb_ucp, (void (*)(void)) cpu_lwp_trampoline, 3, &pcb2->pcb_ucp, func, arg); @@ -412,7 +415,9 @@ cpu_startup(void) /* init lwp0 */ memset(&lwp0pcb, 0, sizeof(lwp0pcb)); thunk_getcontext(&lwp0pcb.pcb_ucp); + thunk_sigemptyset(&lwp0pcb.pcb_ucp.uc_sigmask); lwp0pcb.pcb_ucp.uc_flags = _UC_STACK | _UC_CPU | _UC_SIGMASK; + uvm_lwp_setuarea(&lwp0, (vaddr_t) &lwp0pcb); memcpy(&lwp0pcb.pcb_userret_ucp, &lwp0pcb.pcb_ucp, sizeof(ucontext_t)); Index: src/sys/arch/usermode/dev/if_veth.c diff -u src/sys/arch/usermode/dev/if_veth.c:1.4 src/sys/arch/usermode/dev/if_veth.c:1.5 --- src/sys/arch/usermode/dev/if_veth.c:1.4 Sun Jan 15 10:51:12 2012 +++ src/sys/arch/usermode/dev/if_veth.c Sat Jan 21 22:09:56 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: if_veth.c,v 1.4 2012/01/15 10:51:12 jmcneill Exp $ */ +/* $NetBSD: if_veth.c,v 1.5 2012/01/21 22:09:56 reinoud Exp $ */ /*- * Copyright (c) 2011 Jared D. McNeill <jmcne...@invisible.ca> @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_veth.c,v 1.4 2012/01/15 10:51:12 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_veth.c,v 1.5 2012/01/21 22:09:56 reinoud Exp $"); #include <sys/param.h> #include <sys/proc.h> @@ -189,10 +189,7 @@ veth_rx(void *priv) { struct veth_softc *sc = priv; - curcpu()->ci_idepth++; - spl_intr(IPL_NET, softint_schedule, sc->sc_rx_intr); - curcpu()->ci_idepth--; - + softint_schedule(sc->sc_rx_intr); return 0; } Index: src/sys/arch/usermode/dev/ld_thunkbus.c diff -u src/sys/arch/usermode/dev/ld_thunkbus.c:1.29 src/sys/arch/usermode/dev/ld_thunkbus.c:1.30 --- src/sys/arch/usermode/dev/ld_thunkbus.c:1.29 Mon Jan 9 21:01:31 2012 +++ src/sys/arch/usermode/dev/ld_thunkbus.c Sat Jan 21 22:09:57 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: ld_thunkbus.c,v 1.29 2012/01/09 21:01:31 reinoud Exp $ */ +/* $NetBSD: ld_thunkbus.c,v 1.30 2012/01/21 22:09:57 reinoud Exp $ */ /*- * Copyright (c) 2011 Jared D. McNeill <jmcne...@invisible.ca> @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ld_thunkbus.c,v 1.29 2012/01/09 21:01:31 reinoud Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ld_thunkbus.c,v 1.30 2012/01/21 22:09:57 reinoud Exp $"); #include <sys/param.h> #include <sys/proc.h> @@ -145,9 +145,7 @@ ld_aio_sig(void *arg) struct ld_softc *ld = arg; struct ld_thunkbus_softc *sc = (struct ld_thunkbus_softc *)ld; - curcpu()->ci_idepth++; - spl_intr(IPL_BIO, softint_schedule, sc->sc_ih); - curcpu()->ci_idepth--; + softint_schedule(sc->sc_ih); return 0; } @@ -250,7 +248,7 @@ ld_thunkbus_ldstart(struct ld_softc *ld, /* let the softint do the work */ sc->busy = true; - spl_intr(IPL_BIO, softint_schedule, sc->sc_ih); + softint_schedule(sc->sc_ih); return 0; } Index: src/sys/arch/usermode/dev/ttycons.c diff -u src/sys/arch/usermode/dev/ttycons.c:1.17 src/sys/arch/usermode/dev/ttycons.c:1.18 --- src/sys/arch/usermode/dev/ttycons.c:1.17 Tue Dec 27 20:59:45 2011 +++ src/sys/arch/usermode/dev/ttycons.c Sat Jan 21 22:09:57 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: ttycons.c,v 1.17 2011/12/27 20:59:45 jmcneill Exp $ */ +/* $NetBSD: ttycons.c,v 1.18 2012/01/21 22:09:57 reinoud Exp $ */ /*- * Copyright (c) 2007 Jared D. McNeill <jmcne...@invisible.ca> @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ttycons.c,v 1.17 2011/12/27 20:59:45 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ttycons.c,v 1.18 2012/01/21 22:09:57 reinoud Exp $"); #include <sys/param.h> #include <sys/conf.h> @@ -103,9 +103,9 @@ static int ttycons_param(struct tty *, s static int ttycons_intr(void *); static void ttycons_softintr(void *); -static void ttycons_ctrlc(int); +static sigfunc_t ttycons_ctrlc; static void ttycons_softctrlc(void *); -static void ttycons_ctrlz(int); +static sigfunc_t ttycons_ctrlz; static void ttycons_softctrlz(void *); static int @@ -154,8 +154,9 @@ ttycons_attach(device_t parent, device_t panic("couldn't establish ttycons ctrlz handler\n"); sigio_intr_establish(ttycons_intr, sc); - thunk_signal(SIGINT, ttycons_ctrlc); - thunk_signal(SIGTSTP, ttycons_ctrlz); + signal_intr_establish(SIGINT, ttycons_ctrlc); + signal_intr_establish(SIGTSTP, ttycons_ctrlz); + if (thunk_set_stdin_sigio(true) != 0) panic("couldn't enable stdin async mode"); } @@ -361,9 +362,7 @@ ttycons_intr(void *priv) { struct ttycons_softc *sc = priv; - curcpu()->ci_idepth++; - spl_intr(IPL_SERIAL, softint_schedule, sc->sc_rd_sih); - curcpu()->ci_idepth--; + softint_schedule(sc->sc_rd_sih); return 0; } @@ -383,17 +382,20 @@ ttycons_softintr(void *priv) } } + +/* + * handle SIGINT signal from trap.c + * + * argument 'pc' and 'va' are not used. + */ static void -ttycons_ctrlc(int sig) +ttycons_ctrlc(vaddr_t from_userland, vaddr_t pc, vaddr_t va) { struct ttycons_softc *sc; - curcpu()->ci_idepth++; sc = device_lookup_private(&ttycons_cd, minor(cn_tab->cn_dev)); - if (sc) { - spl_intr(IPL_SERIAL, softint_schedule, sc->sc_ctrlc_sih); - } - curcpu()->ci_idepth--; + if (sc) + softint_schedule(sc->sc_ctrlc_sih); } @@ -408,18 +410,19 @@ ttycons_softctrlc(void *priv) t->t_linesw->l_rint(ch, t); } +/* + * handle SIGTSTP signal from trap.c + * + * argument 'pc' and 'va' are not used. + */ static void -ttycons_ctrlz(int sig) +ttycons_ctrlz(vaddr_t from_userland, vaddr_t pc, vaddr_t va) { struct ttycons_softc *sc; - curcpu()->ci_idepth++; sc = device_lookup_private(&ttycons_cd, minor(cn_tab->cn_dev)); - if (sc) { - spl_intr(IPL_SERIAL, softint_schedule, sc->sc_ctrlz_sih); - } - curcpu()->ci_idepth--; - + if (sc) + softint_schedule(sc->sc_ctrlz_sih); } static void Index: src/sys/arch/usermode/include/intr.h diff -u src/sys/arch/usermode/include/intr.h:1.6 src/sys/arch/usermode/include/intr.h:1.7 --- src/sys/arch/usermode/include/intr.h:1.6 Mon Dec 26 22:04:35 2011 +++ src/sys/arch/usermode/include/intr.h Sat Jan 21 22:09:57 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: intr.h,v 1.6 2011/12/26 22:04:35 jmcneill Exp $ */ +/* $NetBSD: intr.h,v 1.7 2012/01/21 22:09:57 reinoud Exp $ */ /*- * Copyright (c) 2007 Jared D. McNeill <jmcne...@invisible.ca> @@ -32,9 +32,7 @@ #include <machine/intrdefs.h> #include <sys/siginfo.h> -void sigio_signal_handler(int, siginfo_t *, void *); -void * sigio_intr_establish(int (*)(void *), void *); - +/* spl */ void splinit(void); int splraise(int); void spllower(int); @@ -43,6 +41,13 @@ void spl_intr(int x, void (*func)(void * #define spl0() spllower(IPL_NONE) #define splx(x) spllower(x) +/* traps */ +typedef void (sigfunc_t)(vaddr_t from_userland, vaddr_t pc, vaddr_t va); +extern void setup_signal_handlers(void); +extern void signal_intr_establish(int sig, sigfunc_t f); +extern void *sigio_intr_establish(int (*)(void *), void *); + +/* spl implementation */ typedef uint8_t ipl_t; typedef struct { ipl_t _ipl; @@ -62,4 +67,6 @@ splraiseipl(ipl_cookie_t icookie) #include <sys/spl.h> +/* for trap.c */ + #endif /* !_ARCH_USERMODE_INCLUDE_INTR_H */ Index: src/sys/arch/usermode/usermode/intr.c diff -u src/sys/arch/usermode/usermode/intr.c:1.14 src/sys/arch/usermode/usermode/intr.c:1.15 --- src/sys/arch/usermode/usermode/intr.c:1.14 Mon Jan 9 22:20:53 2012 +++ src/sys/arch/usermode/usermode/intr.c Sat Jan 21 22:09:57 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: intr.c,v 1.14 2012/01/09 22:20:53 reinoud Exp $ */ +/* $NetBSD: intr.c,v 1.15 2012/01/21 22:09:57 reinoud Exp $ */ /*- * Copyright (c) 2011 Jared D. McNeill <jmcne...@invisible.ca> @@ -27,72 +27,19 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: intr.c,v 1.14 2012/01/09 22:20:53 reinoud Exp $"); +__KERNEL_RCSID(0, "$NetBSD: intr.c,v 1.15 2012/01/21 22:09:57 reinoud Exp $"); #include <sys/types.h> #include <machine/intr.h> #include <machine/thunk.h> -struct intr_handler { - int (*func)(void *); - void *arg; -}; - -#define SIGIO_MAX_HANDLERS 8 - -static struct intr_handler sigio_intr_handler[SIGIO_MAX_HANDLERS]; - -//#define INTR_USE_SIGPROCMASK - -#define MAX_QUEUED_EVENTS 128 - -static int usermode_x = IPL_NONE; - -#ifdef INTR_USE_SIGPROCMASK -static bool block_sigalrm = false; -#endif - - -struct spl_intr_event { - void (*func)(void *); - void *arg; -}; - -struct spl_intr_event spl_intrs[IPL_HIGH+1][MAX_QUEUED_EVENTS]; -int spl_intr_wr[IPL_HIGH+1]; -int spl_intr_rd[IPL_HIGH+1]; +int usermode_x = IPL_NONE; void splinit(void) { - int i; - for (i = 0; i <= IPL_HIGH; i++) { - spl_intr_rd[i] = 1; - spl_intr_wr[i] = 1; - } -} - -void -spl_intr(int x, void (*func)(void *), void *arg) -{ - struct spl_intr_event *spli; - - if (x >= usermode_x) { - func(arg); - return; - } - -// dprintf_debug("spl_intr: queue %d when %d\n", x, usermode_x); - spli = &spl_intrs[x][spl_intr_wr[x]]; - spli->func = func; - spli->arg = arg; - - spl_intr_wr[x] = (spl_intr_wr[x] + 1) % MAX_QUEUED_EVENTS; - if (spl_intr_wr[x] == spl_intr_rd[x]) { - thunk_printf("%s: spl list %d full!\n", __func__, x); - panic("%s: spl list %d full!\n", __func__, x); - } + /* nothing */ } int @@ -100,16 +47,8 @@ splraise(int x) { int oldx = usermode_x; - if (x > usermode_x) { + if (x > usermode_x) usermode_x = x; - } - -#ifdef INTR_USE_SIGPROCMASK - if (x >= IPL_SCHED && !block_sigalrm) { - thunk_sigblock(SIGALRM); - block_sigalrm = true; - } -#endif return oldx; } @@ -117,62 +56,7 @@ splraise(int x) void spllower(int x) { - struct spl_intr_event *spli; - int y; - - /* `eat' interrupts that came by until we got back to x */ - if (usermode_x > x) { -//restart: - for (y = usermode_x; y >= x; y--) { - while (spl_intr_rd[y] != spl_intr_wr[y]) { -// dprintf_debug("spl y %d firing\n", y); - spli = &spl_intrs[y][spl_intr_rd[y]]; - if (!spli->func) - panic("%s: spli->func is NULL for ipl %d, rd %d, wr %d\n", - __func__, y, spl_intr_rd[y], spl_intr_wr[y]); - spli->func(spli->arg); - spl_intr_rd[y] = (spl_intr_rd[y] + 1) % MAX_QUEUED_EVENTS; -// goto restart; - } - } + if (usermode_x > x) usermode_x = x; - } - -#ifdef INTR_USE_SIGPROCMASK - if (x < IPL_SCHED && block_sigalrm) { - thunk_sigunblock(SIGALRM); - block_sigalrm = false; - } -#endif } -void -sigio_signal_handler(int sig, siginfo_t *info, void *ctx) -{ - struct intr_handler *sih; - unsigned int n; - - for (n = 0; n < SIGIO_MAX_HANDLERS; n++) { - sih = &sigio_intr_handler[n]; - if (sih->func) - sih->func(sih->arg); - } -} - -void * -sigio_intr_establish(int (*func)(void *), void *arg) -{ - struct intr_handler *sih; - unsigned int n; - - for (n = 0; n < SIGIO_MAX_HANDLERS; n++) { - sih = &sigio_intr_handler[n]; - if (sih->func == NULL) { - sih->func = func; - sih->arg = arg; - return sih; - } - } - - panic("increase SIGIO_MAX_HANDLERS"); -} Index: src/sys/arch/usermode/usermode/trap.c diff -u src/sys/arch/usermode/usermode/trap.c:1.60 src/sys/arch/usermode/usermode/trap.c:1.61 --- src/sys/arch/usermode/usermode/trap.c:1.60 Wed Jan 18 12:39:45 2012 +++ src/sys/arch/usermode/usermode/trap.c Sat Jan 21 22:09:57 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: trap.c,v 1.60 2012/01/18 12:39:45 reinoud Exp $ */ +/* $NetBSD: trap.c,v 1.61 2012/01/21 22:09:57 reinoud Exp $ */ /*- * Copyright (c) 2011 Reinoud Zandijk <rein...@netbsd.org> @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.60 2012/01/18 12:39:45 reinoud Exp $"); +__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.61 2012/01/21 22:09:57 reinoud Exp $"); #include <sys/types.h> #include <sys/param.h> @@ -46,24 +46,49 @@ __KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.6 #include <machine/intr.h> #include <machine/thunk.h> +/* define maximum signal number */ +#ifndef NSIG +#define NSIG 64 +#endif /* forwards and externals */ void setup_signal_handlers(void); void stop_all_signal_handlers(void); -static void mem_access_handler(int sig, siginfo_t *info, void *ctx); -static void illegal_instruction_handler(int sig, siginfo_t *info, void *ctx); -extern int errno; +static sigfunc_t pagefault; +static sigfunc_t illegal_instruction; +static sigfunc_t alarm; +static sigfunc_t sigio; + +/* raw signal handlers */ +static stack_t sigstk; +ucontext_t jump_ucp; -static void pagefault(vaddr_t from_userland, vaddr_t pc, vaddr_t va); -static void illegal_instruction(vaddr_t from_userland); +sigfunc_t *sig_funcs[NSIG]; -bool pmap_fault(pmap_t pmap, vaddr_t va, vm_prot_t *atype); +/* segv, bus */ +extern bool pmap_fault(pmap_t pmap, vaddr_t va, vm_prot_t *atype); -static stack_t sigstk; +/* alarm */ +void setup_clock_intr(void); +extern void clock_intr(void *priv); +extern int clock_running; +void *alrm_ih; + +/* sigio handlers */ +struct intr_handler { + int (*func)(void *); + void *arg; +}; +#define SIGIO_MAX_HANDLERS 8 +static struct intr_handler sigio_intr_handler[SIGIO_MAX_HANDLERS]; + +/* misc */ int astpending = 0; + +/* XXX why is it here ? */ void startlwp(void *arg) { @@ -74,8 +99,14 @@ startlwp(void *arg) void setup_signal_handlers(void) { - static struct sigaction sa; + int i; + /* + * Set up the alternative signal stack. This prevents signals to be + * pushed on the NetBSD/usermode userland's stack with all desastrous + * effects. Especially ld.so and friends have such tiny stacks that + * its not feasable. + */ if ((sigstk.ss_sp = thunk_malloc(SIGSTKSZ)) == NULL) panic("can't allocate signal stack space\n"); sigstk.ss_size = SIGSTKSZ; @@ -84,65 +115,103 @@ setup_signal_handlers(void) panic("can't set alternate stacksize: %d", thunk_geterrno()); - /* SIGBUS and SIGSEGV need to be reentrant hence the SA_NODEFER */ - sa.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK | SA_NODEFER; - sa.sa_sigaction = mem_access_handler; - thunk_sigemptyset(&sa.sa_mask); - if (thunk_sigaction(SIGSEGV, &sa, NULL) == -1) - panic("couldn't register SIGSEGV handler: %d", - thunk_geterrno()); - if (thunk_sigaction(SIGBUS, &sa, NULL) == -1) - panic("couldn't register SIGBUS handler: %d", thunk_geterrno()); - - sa.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK; - sa.sa_sigaction = illegal_instruction_handler; - thunk_sigemptyset(&sa.sa_mask); - if (thunk_sigaction(SIGILL, &sa, NULL) == -1) - panic("couldn't register SIGILL handler: %d", thunk_geterrno()); + for (i = 0; i < NSIG; i++) + sig_funcs[i] = NULL; - sa.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK; - sa.sa_sigaction = sigio_signal_handler; - thunk_sigemptyset(&sa.sa_mask); - if (thunk_sigaction(SIGIO, &sa, NULL) == -1) - panic("couldn't register SIGIO handler: %d", thunk_geterrno()); + /* HUP */ + /* INT */ /* ttycons ^C */ + /* QUIT */ + signal_intr_establish(SIGILL, illegal_instruction); + /* TRAP */ + /* ABRT */ + /* SIGEMT */ + /* SIGFPE XXX! */ + /* KILL */ + signal_intr_establish(SIGBUS, pagefault); + signal_intr_establish(SIGSEGV, pagefault); + /* SYS */ + /* PIPE */ + signal_intr_establish(SIGALRM, alarm); + /* TERM */ + /* URG */ + /* STOP */ + /* TSTP */ /* ttycons ^Z */ + /* CONT */ + /* CHLD */ + /* GTTIN */ + /* TTOU */ + signal_intr_establish(SIGIO, sigio); + /* XCPU */ + /* XFSZ */ + /* VTALRM */ + /* PROF */ + /* WINCH */ + /* INFO */ + /* USR1 */ + /* USR2 */ + /* PWR */ } +/* XXX yes this is blunt */ void stop_all_signal_handlers(void) { - thunk_sigblock(SIGALRM); - thunk_sigblock(SIGIO); - thunk_sigblock(SIGILL); - thunk_sigblock(SIGSEGV); - thunk_sigblock(SIGBUS); + int i; + for (i = 0; i < NSIG; i++) + if (sig_funcs[i]) + thunk_sigblock(i); } -/* ast and userret */ void -userret(struct lwp *l) +setup_clock_intr(void) { - /* invoke MI userret code */ - mi_userret(l); + /* setup soft interrupt handler */ + alrm_ih = softint_establish(SOFTINT_CLOCK, + clock_intr, NULL); +} + + +/* ast and userret */ +static void +ast(struct lwp *l) +{ + struct pcb *pcb; - while (astpending) { - astpending = 0; + if (!astpending) + return; + + astpending = 0; + curcpu()->ci_data.cpu_ntrap++; - curcpu()->ci_data.cpu_ntrap++; #if 0 - /* profiling */ - if (l->l_pflag & LP_OWEUPC) { - l->l_pflag &= ~LP_OWEUPC; - ADDUPROF(l); - } + /* profiling */ + if (l->l_pflag & LP_OWEUPC) { + l->l_pflag &= ~LP_OWEUPC; + ADDUPROF(l); + } #endif - /* allow a forced task switch */ - if (l->l_cpu->ci_want_resched) - preempt(); - mi_userret(l); + /* allow a forced task switch */ + if (curcpu()->ci_want_resched) { + curcpu()->ci_want_resched = 0; + preempt(); + /* returns here! */ } + KASSERT(l == curlwp); KASSERT(l); + pcb = lwp_getpcb(l); KASSERT(pcb); + mi_userret(l); +} + + +void +userret(struct lwp *l) +{ + /* invoke MI userret code */ + mi_userret(l); + + ast(l); } @@ -175,11 +244,8 @@ print_mem_access_siginfo(int sig, siginf #endif #if 0 - printf("memaccess error, pc %p, va %p, " - "sys_stack %p, sp %p, stack top %p\n", - (void *) pc, (void *) va, - (void *) pcb->sys_stack, (void *) sp, - (void *) pcb->sys_stack_top); + thunk_printf("memaccess error, pc %p, va %p, sp %p\n", + (void *) pc, (void *) va, (void *) sp); #endif } @@ -220,6 +286,10 @@ print_illegal_instruction_siginfo(int si thunk_printf("%02x ", *((uint8_t *) info->si_addr + i)); thunk_printf("\n"); #endif + +#if 0 + thunk_printf("sigill\n"); +#endif } #else /* DEBUG */ #define print_mem_access_siginfo(s, i, c, p, v, sp) @@ -227,40 +297,47 @@ print_illegal_instruction_siginfo(int si #endif /* DEBUG */ -/* signal handler switching to a pagefault context */ static void -mem_access_handler(int sig, siginfo_t *info, void *ctx) +handle_signal(int sig, siginfo_t *info, void *ctx) { + sigfunc_t *f; ucontext_t *ucp = ctx; struct lwp *l; struct pcb *pcb; vaddr_t va, sp, pc, fp; int from_userland; - assert((info->si_signo == SIGSEGV) || (info->si_signo == SIGBUS)); + if (sig == SIGBUS || sig == SIGSEGV || sig == SIGILL) { + if (info->si_code == SI_NOINFO) + panic("received signal %d with no info", + info->si_signo); + } - if (info->si_code == SI_NOINFO) - panic("received signal %d with no info", - info->si_signo); + f = sig_funcs[sig]; + KASSERT(f); - l = curlwp; - pcb = lwp_getpcb(l); + l = curlwp; KASSERT(l); + pcb = lwp_getpcb(l); KASSERT(pcb); - /* get address of faulted memory access and make it page aligned */ + /* get address of possible faulted memory access and page aligne it */ va = (vaddr_t) info->si_addr; va = trunc_page(va); - /* get PC address of faulted memory instruction */ + /* get PC address of possibly faulted instruction */ pc = md_get_pc(ctx); - /* setup for pagefault context */ + /* nest it on the stack */ sp = md_get_sp(ctx); - print_mem_access_siginfo(sig, info, ctx, pc, va, sp); + if (sig == SIGBUS || sig == SIGSEGV) + print_mem_access_siginfo(sig, info, ctx, pc, va, sp); + if (sig == SIGILL) + print_illegal_instruction_siginfo(sig, info, ctx, pc, va, sp); /* if we're running on a stack of our own, use the system stack */ from_userland = 0; - if ((sp < (vaddr_t) pcb->sys_stack) || (sp > (vaddr_t) pcb->sys_stack_top)) { + if ((sp < (vaddr_t) pcb->sys_stack) || + (sp > (vaddr_t) pcb->sys_stack_top)) { sp = (vaddr_t) pcb->sys_stack_top - sizeof(register_t); fp = (vaddr_t) &pcb->pcb_userret_ucp; if (pc < kmem_user_end) @@ -276,79 +353,38 @@ mem_access_handler(int sig, siginfo_t *i } memcpy((void *) fp, ucp, sizeof(ucontext_t)); + memcpy(&jump_ucp, ucp, sizeof(ucontext_t)); - /* create context for pagefault */ - pcb->pcb_ucp.uc_stack.ss_sp = (void *) pcb->sys_stack; - pcb->pcb_ucp.uc_stack.ss_size = sp - (vaddr_t) pcb->sys_stack; - pcb->pcb_ucp.uc_link = (void *) fp; /* link to old frame on stack */ - - pcb->pcb_ucp.uc_flags = _UC_STACK | _UC_CPU; - thunk_makecontext(&pcb->pcb_ucp, (void (*)(void)) pagefault, + /* create context */ + jump_ucp.uc_stack.ss_sp = (void *) pcb->sys_stack; + jump_ucp.uc_stack.ss_size = sp - (vaddr_t) pcb->sys_stack; + jump_ucp.uc_link = (void *) fp; /* link to old frame on stack */ + + thunk_sigemptyset(&jump_ucp.uc_sigmask); + jump_ucp.uc_flags = _UC_STACK | _UC_CPU | _UC_SIGMASK; + thunk_makecontext(&jump_ucp, + (void (*)(void)) f, 3, (void *) from_userland, (void *) pc, (void *) va); - /* switch to the new pagefault entry on return from signal */ - memcpy(ctx, &pcb->pcb_ucp, sizeof(ucontext_t)); + /* switch to the new context on return from signal */ + thunk_setcontext(&jump_ucp); +// memcpy(ctx, &pcb->pcb_ucp, sizeof(ucontext_t)); } -/* signal handler switching to a illegal instruction context */ -static void -illegal_instruction_handler(int sig, siginfo_t *info, void *ctx) +void +signal_intr_establish(int sig, sigfunc_t f) { - ucontext_t *ucp = ctx; - struct lwp *l; - struct pcb *pcb; - vaddr_t sp, pc, fp; - int from_userland; - - assert(info->si_signo == SIGILL); - - l = curlwp; - pcb = lwp_getpcb(l); - - /* get PC address of faulted instruction */ - pc = md_get_pc(ctx); - - /* setup for illegal_instruction context */ - sp = md_get_sp(ctx); - - print_illegal_instruction_siginfo(sig, info, ctx, pc, 0, sp); - - /* if we're running on a stack of our own, use the system stack */ - from_userland = 0; - if ((sp < (vaddr_t) pcb->sys_stack) || - (sp > (vaddr_t) pcb->sys_stack_top)) { - sp = (vaddr_t) pcb->sys_stack_top - sizeof(register_t); - fp = (vaddr_t) &pcb->pcb_userret_ucp; - - KASSERT(pc < kmem_user_end); - from_userland = 1; - } else { - panic("illegal instruction inside kernel?"); -#if 0 - /* stack grows down */ - fp = sp - sizeof(ucontext_t) - sizeof(register_t); /* slack */ - sp = fp - sizeof(register_t); /* slack */ - - /* sanity check before copying */ - if (fp - 2*PAGE_SIZE < (vaddr_t) pcb->sys_stack) - panic("%s: out of system stack", __func__); -#endif - } - - memcpy((void *) fp, ucp, sizeof(ucontext_t)); + static struct sigaction sa; - /* create context for illegal instruction */ - pcb->pcb_ucp.uc_stack.ss_sp = (void *) pcb->sys_stack; - pcb->pcb_ucp.uc_stack.ss_size = sp - (vaddr_t) pcb->sys_stack; - pcb->pcb_ucp.uc_link = (void *) fp; /* link to old frame on stack */ - - pcb->pcb_ucp.uc_flags = _UC_STACK | _UC_CPU; - thunk_makecontext(&pcb->pcb_ucp, (void (*)(void)) illegal_instruction, - 1, (void *) from_userland, NULL, NULL); + sig_funcs[sig] = f; - /* switch to the new illegal instruction entry on return from signal */ - memcpy(ctx, &pcb->pcb_ucp, sizeof(ucontext_t)); + sa.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK; + sa.sa_sigaction = (void *) handle_signal; + thunk_sigfillset(&sa.sa_mask); + if (thunk_sigaction(sig, &sa, NULL) == -1) + panic("couldn't register SIG%d handler: %d", sig, + thunk_geterrno()); } @@ -377,18 +413,17 @@ pagefault(vaddr_t from_userland, vaddr_t lwp_errno = thunk_geterrno(); vm_map = &vm->vm_map; - from_kernel = (pc >= kmem_k_start); + from_kernel = (pc >= kmem_k_start) && (!from_userland); if (from_kernel && (va >= VM_MIN_KERNEL_ADDRESS)) vm_map = kernel_map; #if 0 - thunk_printf("pagefault : pc %p, va %p\n", - (void *) pc, (void *) va); + thunk_printf("%s: l %p, pcb %p\n", __func__, l, pcb); + thunk_printf("\tpc %p, va %p\n", (void *) pc, (void *) va); #endif /* can pmap handle it? on its own? (r/m) emulation */ if (pmap_fault(vm_map->pmap, va, &atype)) { -// thunk_printf("pagefault leave (pmap)\n"); /* no use doing anything else here */ goto out_quick; } @@ -416,8 +451,8 @@ pagefault(vaddr_t from_userland, vaddr_t } /* something got wrong */ - thunk_printf("%s: uvm fault %d, pc %p, from_kernel %d\n", - __func__, error, (void *) pc, from_kernel); + thunk_printf("%s: uvm fault %d, pc %p, va %p, from_kernel %d\n", + __func__, error, (void *) pc, (void *) va, from_kernel); /* check if its from copyin/copyout */ if (onfault) { @@ -437,6 +472,7 @@ pagefault(vaddr_t from_userland, vaddr_t /* send signal */ thunk_printf("giving signal to userland\n"); + KASSERT(from_userland); KSI_INIT_TRAP(&ksi); ksi.ksi_signo = SIGSEGV; ksi.ksi_trap = 0; /* XXX */ @@ -468,28 +504,32 @@ out_quick: /* - * Context for handing illegal instruction from the sigill handler + * handle an illegal instruction. + * + * arguments 'pc' and 'va' are ignored here */ static void -illegal_instruction(vaddr_t from_userland) +illegal_instruction(vaddr_t from_userland, vaddr_t pc, vaddr_t va) { struct lwp *l = curlwp; struct pcb *pcb = lwp_getpcb(l); ucontext_t *ucp = &pcb->pcb_userret_ucp; ksiginfo_t ksi; -// thunk_printf("illegal instruction\n"); +// thunk_printf("%s: l %p, pcb %p\n", __func__, l, pcb); + + KASSERT(from_userland); + /* if its a syscall ... */ if (md_syscall_check_opcode(ucp)) { syscall(); -// thunk_printf("illegal instruction leave\n"); - KASSERT(from_userland); userret(l); return; } thunk_printf("%s: giving SIGILL (TRAP)\n", __func__); + KASSERT(from_userland); KSI_INIT_TRAP(&ksi); ksi.ksi_signo = SIGILL; ksi.ksi_trap = 0; /* XXX */ @@ -502,7 +542,75 @@ illegal_instruction(vaddr_t from_userlan #else trapsignal(l, &ksi); #endif - KASSERT(from_userland); userret(l); } + +/* + * handle alarm, a clock ticker. + * + * arguments 'pc' and 'va' are ignored here + */ +static void +alarm(vaddr_t from_userland, vaddr_t pc, vaddr_t va) +{ + struct lwp *l = curlwp; + struct pcb *pcb = lwp_getpcb(l); KASSERT(pcb); + + if (!clock_running) + return; +// thunk_printf("%s: l %p, pcb %p\n", __func__, l, pcb); + + softint_schedule(alrm_ih); + + KASSERT(l == curlwp); + if (from_userland) + userret(l); +} + + +/* + * handle sigio, a mux for all io operations. + * + * arguments 'pc' and 'va' are ignored here + */ +static void +sigio(vaddr_t from_userland, vaddr_t pc, vaddr_t va) +{ + struct lwp *l = curlwp; + struct pcb *pcb = lwp_getpcb(l); KASSERT(pcb); + struct intr_handler *sih; + unsigned int n; + +// thunk_printf("%s: l %p, pcb %p\n", __func__, l, pcb); + for (n = 0; n < SIGIO_MAX_HANDLERS; n++) { + sih = &sigio_intr_handler[n]; + if (sih->func) + sih->func(sih->arg); + } + + KASSERT(l == curlwp); + if (from_userland) + userret(l); /* or ast? */ +} + + +/* sigio register function */ +void * +sigio_intr_establish(int (*func)(void *), void *arg) +{ + struct intr_handler *sih; + unsigned int n; + + for (n = 0; n < SIGIO_MAX_HANDLERS; n++) { + sih = &sigio_intr_handler[n]; + if (sih->func == NULL) { + sih->func = func; + sih->arg = arg; + return sih; + } + } + + panic("increase SIGIO_MAX_HANDLERS"); +} +