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 * $DragonFly: src/sys/platform/vkernel/i386/exception.c,v 1.11 2008/04/28 07:05:09 dillon Exp $ 36 */ 37 38 #include "opt_ddb.h" 39 #include <sys/types.h> 40 #include <sys/systm.h> 41 #include <sys/reboot.h> 42 #include <sys/kernel.h> 43 #include <sys/kthread.h> 44 #include <sys/reboot.h> 45 #include <ddb/ddb.h> 46 47 #include <sys/thread2.h> 48 49 #include <machine/trap.h> 50 #include <machine/md_var.h> 51 #include <machine/segments.h> 52 #include <machine/cpu.h> 53 #include <machine/smp.h> 54 55 #include <err.h> 56 #include <signal.h> 57 #include <stdio.h> 58 #include <unistd.h> 59 60 int _ucodesel = GSEL(GUCODE_SEL, SEL_UPL); 61 int _udatasel = GSEL(GUDATA_SEL, SEL_UPL); 62 63 static void exc_segfault(int signo, siginfo_t *info, void *ctx); 64 #ifdef DDB 65 static void exc_debugger(int signo, siginfo_t *info, void *ctx); 66 #endif 67 68 #ifdef SMP 69 70 /* 71 * IPIs are 'fast' interrupts, so we deal with them directly from our 72 * signal handler. 73 * 74 * WARNING: Signals are not physically disabled here so we have to enter 75 * our critical section before bumping gd_intr_nesting_level or another 76 * interrupt can come along and get really confused. 77 */ 78 static 79 void 80 ipisig(int nada, siginfo_t *info, void *ctxp) 81 { 82 globaldata_t gd = mycpu; 83 thread_t td = gd->gd_curthread; 84 85 if (td->td_critcount == 0) { 86 ++td->td_critcount; 87 ++gd->gd_intr_nesting_level; 88 lwkt_process_ipiq(); 89 --gd->gd_intr_nesting_level; 90 --td->td_critcount; 91 } else { 92 need_ipiq(); 93 } 94 } 95 96 /* 97 * Unconditionally stop or restart a cpu. 98 * 99 * Note: cpu_mask_all_signals() masks all signals except SIGXCPU itself. 100 * SIGXCPU itself is blocked on entry to stopsig() by the signal handler 101 * itself. 102 * 103 * WARNING: Signals are not physically disabled here so we have to enter 104 * our critical section before bumping gd_intr_nesting_level or another 105 * interrupt can come along and get really confused. 106 */ 107 static 108 void 109 stopsig(int nada, siginfo_t *info, void *ctxp) 110 { 111 globaldata_t gd = mycpu; 112 thread_t td = gd->gd_curthread; 113 sigset_t ss; 114 115 sigemptyset(&ss); 116 sigaddset(&ss, SIGALRM); 117 sigaddset(&ss, SIGIO); 118 sigaddset(&ss, SIGQUIT); 119 sigaddset(&ss, SIGUSR1); 120 sigaddset(&ss, SIGUSR2); 121 sigaddset(&ss, SIGTERM); 122 sigaddset(&ss, SIGWINCH); 123 124 ++td->td_critcount; 125 ++gd->gd_intr_nesting_level; 126 while (stopped_cpus & gd->gd_cpumask) { 127 sigsuspend(&ss); 128 } 129 --gd->gd_intr_nesting_level; 130 --td->td_critcount; 131 } 132 133 #endif 134 135 #if 0 136 137 /* 138 * SIGIO is used by cothreads to signal back into the virtual kernel. 139 */ 140 static 141 void 142 iosig(int nada, siginfo_t *info, void *ctxp) 143 { 144 signalintr(4); 145 } 146 147 #endif 148 149 static 150 void 151 infosig(int nada, siginfo_t *info, void *ctxp) 152 { 153 ucontext_t *ctx = ctxp; 154 char buf[256]; 155 156 snprintf(buf, sizeof(buf), "lwp %d pc=%p sp=%p\n", 157 (int)lwp_gettid(), 158 (void *)(intptr_t)ctx->uc_mcontext.mc_rip, 159 (void *)(intptr_t)ctx->uc_mcontext.mc_rsp); 160 write(2, buf, strlen(buf)); 161 } 162 163 void 164 init_exceptions(void) 165 { 166 struct sigaction sa; 167 168 bzero(&sa, sizeof(sa)); 169 sa.sa_sigaction = exc_segfault; 170 sa.sa_flags |= SA_SIGINFO | SA_NODEFER; 171 sigemptyset(&sa.sa_mask); 172 sigaction(SIGBUS, &sa, NULL); 173 sigaction(SIGSEGV, &sa, NULL); 174 sigaction(SIGTRAP, &sa, NULL); 175 sigaction(SIGFPE, &sa, NULL); 176 177 sa.sa_flags &= ~SA_NODEFER; 178 179 #ifdef DDB 180 sa.sa_sigaction = exc_debugger; 181 sigaction(SIGQUIT, &sa, NULL); 182 #endif 183 #ifdef SMP 184 sa.sa_sigaction = ipisig; 185 sigaction(SIGUSR1, &sa, NULL); 186 sa.sa_sigaction = stopsig; 187 sigaction(SIGXCPU, &sa, NULL); 188 #endif 189 #if 0 190 sa.sa_sigaction = iosig; 191 sigaction(SIGIO, &sa, NULL); 192 #endif 193 sa.sa_sigaction = infosig; 194 sigaction(SIGINFO, &sa, NULL); 195 } 196 197 /* 198 * This function handles a segmentation fault. 199 * 200 * XXX We assume that trapframe is a subset of ucontext. It is as of 201 * this writing. 202 */ 203 static void 204 exc_segfault(int signo, siginfo_t *info, void *ctxp) 205 { 206 ucontext_t *ctx = ctxp; 207 208 #if 0 209 kprintf("CAUGHT SIG %d RIP %08lx ERR %08lx TRAPNO %ld " 210 "err %ld addr %08lx\n", 211 signo, 212 ctx->uc_mcontext.mc_rip, 213 ctx->uc_mcontext.mc_err, 214 ctx->uc_mcontext.mc_trapno & 0xFFFF, 215 ctx->uc_mcontext.mc_trapno >> 16, 216 ctx->uc_mcontext.mc_addr); 217 #endif 218 kern_trap((struct trapframe *)&ctx->uc_mcontext.mc_rdi); 219 splz(); 220 } 221 222 #ifdef DDB 223 224 static void 225 exc_debugger(int signo, siginfo_t *info, void *ctx) 226 { 227 Debugger("interrupt from console"); 228 } 229 230 #endif 231