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 #include <sys/lwp.h> 46 47 #include <machine/trap.h> 48 #include <machine/md_var.h> 49 #include <machine/segments.h> 50 #include <machine/cpu.h> 51 #include <machine/smp.h> 52 53 #include <err.h> 54 #include <signal.h> 55 #include <stdio.h> 56 #include <unistd.h> 57 58 int _ucodesel = GSEL(GUCODE_SEL, SEL_UPL); 59 int _udatasel = GSEL(GUDATA_SEL, SEL_UPL); 60 61 static void exc_segfault(int signo, siginfo_t *info, void *ctx); 62 #ifdef DDB 63 static void exc_debugger(int signo, siginfo_t *info, void *ctx); 64 #endif 65 66 /* 67 * IPIs are 'fast' interrupts, so we deal with them directly from our 68 * signal handler. 69 * 70 * WARNING: Signals are not physically disabled here so we have to enter 71 * our critical section before bumping gd_intr_nesting_level or another 72 * interrupt can come along and get really confused. 73 */ 74 static 75 void 76 ipisig(int nada, siginfo_t *info, void *ctxp) 77 { 78 globaldata_t gd = mycpu; 79 thread_t td = gd->gd_curthread; 80 int save; 81 82 save = errno; 83 if (td->td_critcount == 0) { 84 crit_enter_raw(td); 85 ++gd->gd_cnt.v_ipi; 86 ++gd->gd_intr_nesting_level; 87 atomic_swap_int(&gd->gd_npoll, 0); 88 lwkt_process_ipiq(); 89 --gd->gd_intr_nesting_level; 90 crit_exit_raw(td); 91 } else { 92 need_ipiq(); 93 } 94 errno = save; 95 } 96 97 /* 98 * Unconditionally stop or restart a cpu. 99 * 100 * Note: cpu_mask_all_signals() masks all signals except SIGXCPU itself. 101 * SIGXCPU itself is blocked on entry to stopsig() by the signal handler 102 * itself. 103 * 104 * WARNING: Signals are not physically disabled here so we have to enter 105 * our critical section before bumping gd_intr_nesting_level or another 106 * interrupt can come along and get really confused. 107 */ 108 static 109 void 110 stopsig(int nada, siginfo_t *info, void *ctxp) 111 { 112 globaldata_t gd = mycpu; 113 thread_t td = gd->gd_curthread; 114 sigset_t ss; 115 int save; 116 117 save = errno; 118 sigemptyset(&ss); 119 sigaddset(&ss, SIGALRM); 120 sigaddset(&ss, SIGIO); 121 sigaddset(&ss, SIGURG); 122 sigaddset(&ss, SIGQUIT); 123 sigaddset(&ss, SIGUSR1); 124 sigaddset(&ss, SIGUSR2); 125 sigaddset(&ss, SIGTERM); 126 sigaddset(&ss, SIGWINCH); 127 128 crit_enter_raw(td); 129 ++gd->gd_intr_nesting_level; 130 while (CPUMASK_TESTMASK(stopped_cpus, gd->gd_cpumask)) { 131 sigsuspend(&ss); 132 } 133 --gd->gd_intr_nesting_level; 134 crit_exit_raw(td); 135 136 errno = save; 137 } 138 139 /* 140 * SIGIO is used by cothreads to signal back into the virtual kernel. 141 */ 142 static 143 void 144 kqueuesig(int nada, siginfo_t *info, void *ctxp) 145 { 146 globaldata_t gd = mycpu; 147 thread_t td = gd->gd_curthread; 148 int save; 149 150 save = errno; 151 if (td->td_critcount == 0) { 152 crit_enter_raw(td); 153 ++gd->gd_intr_nesting_level; 154 cpu_ccfence(); 155 kqueue_intr(NULL); 156 cpu_ccfence(); 157 --gd->gd_intr_nesting_level; 158 crit_exit_raw(td); 159 } else { 160 need_kqueue(); 161 } 162 errno = save; 163 } 164 165 static 166 void 167 timersig(int nada, siginfo_t *info, void *ctxp) 168 { 169 globaldata_t gd = mycpu; 170 thread_t td = gd->gd_curthread; 171 int save; 172 173 save = errno; 174 if (td->td_critcount == 0) { 175 crit_enter_raw(td); 176 ++gd->gd_intr_nesting_level; 177 cpu_ccfence(); 178 vktimer_intr(NULL); 179 cpu_ccfence(); 180 --gd->gd_intr_nesting_level; 181 crit_exit_raw(td); 182 } else { 183 need_timer(); 184 } 185 errno = save; 186 } 187 188 static 189 void 190 cosig(int nada, siginfo_t *info, void *ctxp) 191 { 192 int save; 193 194 save = errno; 195 /* handles critical section checks */ 196 signalintr(1); 197 errno = save; 198 } 199 200 static 201 void 202 infosig(int nada, siginfo_t *info, void *ctxp) 203 { 204 ucontext_t *ctx = ctxp; 205 char buf[256]; 206 int save; 207 208 save = errno; 209 snprintf(buf, sizeof(buf), "lwp %d pc=%p sp=%p\n", 210 (lwpid_t)lwp_gettid(), 211 (void *)(intptr_t)ctx->uc_mcontext.mc_rip, 212 (void *)(intptr_t)ctx->uc_mcontext.mc_rsp); 213 write(2, buf, strlen(buf)); 214 errno = save; 215 } 216 217 void 218 init_exceptions(void) 219 { 220 struct sigaction sa; 221 222 bzero(&sa, sizeof(sa)); 223 sa.sa_sigaction = exc_segfault; 224 sa.sa_flags |= SA_SIGINFO | SA_NODEFER; 225 sigemptyset(&sa.sa_mask); 226 sigaction(SIGBUS, &sa, NULL); 227 sigaction(SIGSEGV, &sa, NULL); 228 sigaction(SIGTRAP, &sa, NULL); 229 sigaction(SIGFPE, &sa, NULL); 230 231 sa.sa_flags &= ~SA_NODEFER; 232 233 #ifdef DDB 234 sa.sa_sigaction = exc_debugger; 235 sigaction(SIGQUIT, &sa, NULL); 236 #endif 237 sa.sa_sigaction = ipisig; 238 sigaction(SIGUSR1, &sa, NULL); 239 240 sa.sa_sigaction = stopsig; 241 sigaction(SIGXCPU, &sa, NULL); 242 243 sa.sa_sigaction = kqueuesig; 244 sigaction(SIGIO, &sa, NULL); 245 246 sa.sa_sigaction = timersig; 247 sigaction(SIGURG, &sa, NULL); 248 249 sa.sa_sigaction = cosig; 250 sigaction(SIGALRM, &sa, NULL); 251 252 sa.sa_sigaction = infosig; 253 sigaction(SIGINFO, &sa, NULL); 254 } 255 256 /* 257 * This function handles a segmentation fault. 258 * 259 * XXX We assume that trapframe is a subset of ucontext. It is as of 260 * this writing. 261 */ 262 static void 263 exc_segfault(int signo, siginfo_t *info, void *ctxp) 264 { 265 ucontext_t *ctx = ctxp; 266 int save; 267 268 save = errno; 269 #if 0 270 kprintf("CAUGHT SIG %d RIP %08lx ERR %08lx TRAPNO %ld " 271 "err %ld addr %08lx\n", 272 signo, 273 ctx->uc_mcontext.mc_rip, 274 ctx->uc_mcontext.mc_err, 275 ctx->uc_mcontext.mc_trapno & 0xFFFF, 276 ctx->uc_mcontext.mc_trapno >> 16, 277 ctx->uc_mcontext.mc_addr); 278 #endif 279 kern_trap((struct trapframe *)&ctx->uc_mcontext.mc_rdi); 280 splz(); 281 errno = save; 282 } 283 284 #ifdef DDB 285 286 static void 287 exc_debugger(int signo, siginfo_t *info, void *ctxp) 288 { 289 ucontext_t *ctx = ctxp; 290 int save; 291 292 save = errno; 293 kprintf("CAUGHT SIG %d RIP %08lx RSP %08lx TD %p\n", 294 signo, 295 ctx->uc_mcontext.mc_rip, 296 ctx->uc_mcontext.mc_rsp, 297 curthread); 298 Debugger("interrupt from console"); 299 errno = save; 300 } 301 302 #endif 303