1 2 /* 3 * Copyright (c) 2006 The DragonFly Project. All rights reserved. 4 * 5 * This code is derived from software contributed to The DragonFly Project 6 * by Matthew Dillon <dillon@backplane.com> 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in 16 * the documentation and/or other materials provided with the 17 * distribution. 18 * 3. Neither the name of The DragonFly Project nor the names of its 19 * contributors may be used to endorse or promote products derived 20 * from this software without specific, prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 26 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 32 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include "opt_ddb.h" 37 #include <sys/types.h> 38 #include <sys/systm.h> 39 #include <sys/reboot.h> 40 #include <sys/kernel.h> 41 #include <sys/kthread.h> 42 #include <ddb/ddb.h> 43 44 #include <sys/thread2.h> 45 46 #include <machine/trap.h> 47 #include <machine/md_var.h> 48 #include <machine/segments.h> 49 #include <machine/cpu.h> 50 #include <machine/smp.h> 51 52 #include <err.h> 53 #include <signal.h> 54 #include <stdio.h> 55 #include <unistd.h> 56 57 int _ucodesel = GSEL(GUCODE_SEL, SEL_UPL); 58 int _udatasel = GSEL(GUDATA_SEL, SEL_UPL); 59 60 static void exc_segfault(int signo, siginfo_t *info, void *ctx); 61 #ifdef DDB 62 static void exc_debugger(int signo, siginfo_t *info, void *ctx); 63 #endif 64 65 /* 66 * IPIs are 'fast' interrupts, so we deal with them directly from our 67 * signal handler. 68 * 69 * WARNING: Signals are not physically disabled here so we have to enter 70 * our critical section before bumping gd_intr_nesting_level or another 71 * interrupt can come along and get really confused. 72 */ 73 static 74 void 75 ipisig(int nada, siginfo_t *info, void *ctxp) 76 { 77 globaldata_t gd = mycpu; 78 thread_t td = gd->gd_curthread; 79 80 if (td->td_critcount == 0) { 81 ++td->td_critcount; 82 ++gd->gd_intr_nesting_level; 83 lwkt_process_ipiq(); 84 --gd->gd_intr_nesting_level; 85 --td->td_critcount; 86 } else { 87 need_ipiq(); 88 } 89 } 90 91 /* 92 * Unconditionally stop or restart a cpu. 93 * 94 * Note: cpu_mask_all_signals() masks all signals except SIGXCPU itself. 95 * SIGXCPU itself is blocked on entry to stopsig() by the signal handler 96 * itself. 97 * 98 * WARNING: Signals are not physically disabled here so we have to enter 99 * our critical section before bumping gd_intr_nesting_level or another 100 * interrupt can come along and get really confused. 101 */ 102 static 103 void 104 stopsig(int nada, siginfo_t *info, void *ctxp) 105 { 106 globaldata_t gd = mycpu; 107 thread_t td = gd->gd_curthread; 108 sigset_t ss; 109 110 sigemptyset(&ss); 111 sigaddset(&ss, SIGALRM); 112 sigaddset(&ss, SIGIO); 113 sigaddset(&ss, SIGQUIT); 114 sigaddset(&ss, SIGUSR1); 115 sigaddset(&ss, SIGUSR2); 116 sigaddset(&ss, SIGTERM); 117 sigaddset(&ss, SIGWINCH); 118 119 ++td->td_critcount; 120 ++gd->gd_intr_nesting_level; 121 while (CPUMASK_TESTMASK(stopped_cpus, gd->gd_cpumask)) { 122 sigsuspend(&ss); 123 } 124 --gd->gd_intr_nesting_level; 125 --td->td_critcount; 126 } 127 128 #if 0 129 130 /* 131 * SIGIO is used by cothreads to signal back into the virtual kernel. 132 */ 133 static 134 void 135 iosig(int nada, siginfo_t *info, void *ctxp) 136 { 137 signalintr(4); 138 } 139 140 #endif 141 142 static 143 void 144 infosig(int nada, siginfo_t *info, void *ctxp) 145 { 146 ucontext_t *ctx = ctxp; 147 char buf[256]; 148 149 snprintf(buf, sizeof(buf), "lwp %d pc=%p sp=%p\n", 150 (int)lwp_gettid(), 151 (void *)(intptr_t)ctx->uc_mcontext.mc_rip, 152 (void *)(intptr_t)ctx->uc_mcontext.mc_rsp); 153 write(2, buf, strlen(buf)); 154 } 155 156 void 157 init_exceptions(void) 158 { 159 struct sigaction sa; 160 161 bzero(&sa, sizeof(sa)); 162 sa.sa_sigaction = exc_segfault; 163 sa.sa_flags |= SA_SIGINFO | SA_NODEFER; 164 sigemptyset(&sa.sa_mask); 165 sigaction(SIGBUS, &sa, NULL); 166 sigaction(SIGSEGV, &sa, NULL); 167 sigaction(SIGTRAP, &sa, NULL); 168 sigaction(SIGFPE, &sa, NULL); 169 170 sa.sa_flags &= ~SA_NODEFER; 171 172 #ifdef DDB 173 sa.sa_sigaction = exc_debugger; 174 sigaction(SIGQUIT, &sa, NULL); 175 #endif 176 sa.sa_sigaction = ipisig; 177 sigaction(SIGUSR1, &sa, NULL); 178 sa.sa_sigaction = stopsig; 179 sigaction(SIGXCPU, &sa, NULL); 180 #if 0 181 sa.sa_sigaction = iosig; 182 sigaction(SIGIO, &sa, NULL); 183 #endif 184 sa.sa_sigaction = infosig; 185 sigaction(SIGINFO, &sa, NULL); 186 } 187 188 /* 189 * This function handles a segmentation fault. 190 * 191 * XXX We assume that trapframe is a subset of ucontext. It is as of 192 * this writing. 193 */ 194 static void 195 exc_segfault(int signo, siginfo_t *info, void *ctxp) 196 { 197 ucontext_t *ctx = ctxp; 198 199 #if 0 200 kprintf("CAUGHT SIG %d RIP %08lx ERR %08lx TRAPNO %ld " 201 "err %ld addr %08lx\n", 202 signo, 203 ctx->uc_mcontext.mc_rip, 204 ctx->uc_mcontext.mc_err, 205 ctx->uc_mcontext.mc_trapno & 0xFFFF, 206 ctx->uc_mcontext.mc_trapno >> 16, 207 ctx->uc_mcontext.mc_addr); 208 #endif 209 kern_trap((struct trapframe *)&ctx->uc_mcontext.mc_rdi); 210 splz(); 211 } 212 213 #ifdef DDB 214 215 static void 216 exc_debugger(int signo, siginfo_t *info, void *ctxp) 217 { 218 ucontext_t *ctx = ctxp; 219 220 kprintf("CAUGHT SIG %d RIP %08lx RSP %08lx TD %p\n", 221 signo, 222 ctx->uc_mcontext.mc_rip, 223 ctx->uc_mcontext.mc_rsp, 224 curthread); 225 Debugger("interrupt from console"); 226 } 227 228 #endif 229