xref: /dflybsd-src/sys/platform/vkernel64/x86_64/exception.c (revision e8b1691fcb2521b46aa00c13aac55876097c6758)
10e6594a8SSascha Wildner 
20e6594a8SSascha Wildner /*
30e6594a8SSascha Wildner  * Copyright (c) 2006 The DragonFly Project.  All rights reserved.
40e6594a8SSascha Wildner  *
50e6594a8SSascha Wildner  * This code is derived from software contributed to The DragonFly Project
60e6594a8SSascha Wildner  * by Matthew Dillon <dillon@backplane.com>
70e6594a8SSascha Wildner  *
80e6594a8SSascha Wildner  * Redistribution and use in source and binary forms, with or without
90e6594a8SSascha Wildner  * modification, are permitted provided that the following conditions
100e6594a8SSascha Wildner  * are met:
110e6594a8SSascha Wildner  *
120e6594a8SSascha Wildner  * 1. Redistributions of source code must retain the above copyright
130e6594a8SSascha Wildner  *    notice, this list of conditions and the following disclaimer.
140e6594a8SSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
150e6594a8SSascha Wildner  *    notice, this list of conditions and the following disclaimer in
160e6594a8SSascha Wildner  *    the documentation and/or other materials provided with the
170e6594a8SSascha Wildner  *    distribution.
180e6594a8SSascha Wildner  * 3. Neither the name of The DragonFly Project nor the names of its
190e6594a8SSascha Wildner  *    contributors may be used to endorse or promote products derived
200e6594a8SSascha Wildner  *    from this software without specific, prior written permission.
210e6594a8SSascha Wildner  *
220e6594a8SSascha Wildner  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
230e6594a8SSascha Wildner  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
240e6594a8SSascha Wildner  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
250e6594a8SSascha Wildner  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
260e6594a8SSascha Wildner  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
270e6594a8SSascha Wildner  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
280e6594a8SSascha Wildner  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
290e6594a8SSascha Wildner  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
300e6594a8SSascha Wildner  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
310e6594a8SSascha Wildner  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
320e6594a8SSascha Wildner  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
330e6594a8SSascha Wildner  * SUCH DAMAGE.
340e6594a8SSascha Wildner  */
350e6594a8SSascha Wildner 
360e6594a8SSascha Wildner #include "opt_ddb.h"
370e6594a8SSascha Wildner #include <sys/types.h>
380e6594a8SSascha Wildner #include <sys/systm.h>
390e6594a8SSascha Wildner #include <sys/reboot.h>
400e6594a8SSascha Wildner #include <sys/kernel.h>
410e6594a8SSascha Wildner #include <sys/kthread.h>
420e6594a8SSascha Wildner #include <ddb/ddb.h>
430e6594a8SSascha Wildner 
440e6594a8SSascha Wildner #include <sys/thread2.h>
45193c5c43SAntonio Huete Jimenez #include <sys/lwp.h>
460e6594a8SSascha Wildner 
470e6594a8SSascha Wildner #include <machine/trap.h>
480e6594a8SSascha Wildner #include <machine/md_var.h>
490e6594a8SSascha Wildner #include <machine/segments.h>
500e6594a8SSascha Wildner #include <machine/cpu.h>
510e6594a8SSascha Wildner #include <machine/smp.h>
520e6594a8SSascha Wildner 
530e6594a8SSascha Wildner #include <err.h>
540e6594a8SSascha Wildner #include <signal.h>
558f8555f8SMatthew Dillon #include <stdio.h>
560e6594a8SSascha Wildner #include <unistd.h>
570e6594a8SSascha Wildner 
580e6594a8SSascha Wildner int _ucodesel = GSEL(GUCODE_SEL, SEL_UPL);
590e6594a8SSascha Wildner int _udatasel = GSEL(GUDATA_SEL, SEL_UPL);
600e6594a8SSascha Wildner 
610e6594a8SSascha Wildner static void exc_segfault(int signo, siginfo_t *info, void *ctx);
620e6594a8SSascha Wildner #ifdef DDB
630e6594a8SSascha Wildner static void exc_debugger(int signo, siginfo_t *info, void *ctx);
640e6594a8SSascha Wildner #endif
650e6594a8SSascha Wildner 
660e6594a8SSascha Wildner /*
670e6594a8SSascha Wildner  * IPIs are 'fast' interrupts, so we deal with them directly from our
680e6594a8SSascha Wildner  * signal handler.
690e6594a8SSascha Wildner  *
700e6594a8SSascha Wildner  * WARNING: Signals are not physically disabled here so we have to enter
710e6594a8SSascha Wildner  * our critical section before bumping gd_intr_nesting_level or another
720e6594a8SSascha Wildner  * interrupt can come along and get really confused.
730e6594a8SSascha Wildner  */
740e6594a8SSascha Wildner static
750e6594a8SSascha Wildner void
ipisig(int nada,siginfo_t * info,void * ctxp)760e6594a8SSascha Wildner ipisig(int nada, siginfo_t *info, void *ctxp)
770e6594a8SSascha Wildner {
78f9235b6dSMatthew Dillon 	globaldata_t gd = mycpu;
79f9235b6dSMatthew Dillon 	thread_t td = gd->gd_curthread;
808c6462e6SMatthew Dillon 	int save;
81f9235b6dSMatthew Dillon 
828c6462e6SMatthew Dillon 	save = errno;
83f9235b6dSMatthew Dillon 	if (td->td_critcount == 0) {
84*e8b1691fSMatthew Dillon 		crit_enter_quick(td);
85c91894e0SMatthew Dillon 		++gd->gd_cnt.v_ipi;
86f9235b6dSMatthew Dillon 		++gd->gd_intr_nesting_level;
8798c1338cSSascha Wildner 		atomic_swap_int(&gd->gd_npoll, 0);
880e6594a8SSascha Wildner 		lwkt_process_ipiq();
89f9235b6dSMatthew Dillon 		--gd->gd_intr_nesting_level;
90*e8b1691fSMatthew Dillon 		crit_exit_quick(td);
910e6594a8SSascha Wildner 	} else {
920e6594a8SSascha Wildner 		need_ipiq();
930e6594a8SSascha Wildner 	}
948c6462e6SMatthew Dillon 	errno = save;
950e6594a8SSascha Wildner }
960e6594a8SSascha Wildner 
970e6594a8SSascha Wildner /*
980e6594a8SSascha Wildner  * Unconditionally stop or restart a cpu.
990e6594a8SSascha Wildner  *
1000e6594a8SSascha Wildner  * Note: cpu_mask_all_signals() masks all signals except SIGXCPU itself.
1010e6594a8SSascha Wildner  * SIGXCPU itself is blocked on entry to stopsig() by the signal handler
1020e6594a8SSascha Wildner  * itself.
1030e6594a8SSascha Wildner  *
1040e6594a8SSascha Wildner  * WARNING: Signals are not physically disabled here so we have to enter
1050e6594a8SSascha Wildner  * our critical section before bumping gd_intr_nesting_level or another
1060e6594a8SSascha Wildner  * interrupt can come along and get really confused.
1070e6594a8SSascha Wildner  */
1080e6594a8SSascha Wildner static
1090e6594a8SSascha Wildner void
stopsig(int nada,siginfo_t * info,void * ctxp)1100e6594a8SSascha Wildner stopsig(int nada, siginfo_t *info, void *ctxp)
1110e6594a8SSascha Wildner {
112f9235b6dSMatthew Dillon 	globaldata_t gd = mycpu;
113f9235b6dSMatthew Dillon 	thread_t td = gd->gd_curthread;
1140e6594a8SSascha Wildner 	sigset_t ss;
1158c6462e6SMatthew Dillon 	int save;
1160e6594a8SSascha Wildner 
1178c6462e6SMatthew Dillon 	save = errno;
1180e6594a8SSascha Wildner 	sigemptyset(&ss);
1190e6594a8SSascha Wildner 	sigaddset(&ss, SIGALRM);
1200e6594a8SSascha Wildner 	sigaddset(&ss, SIGIO);
121c91894e0SMatthew Dillon 	sigaddset(&ss, SIGURG);
1220e6594a8SSascha Wildner 	sigaddset(&ss, SIGQUIT);
1230e6594a8SSascha Wildner 	sigaddset(&ss, SIGUSR1);
1240e6594a8SSascha Wildner 	sigaddset(&ss, SIGUSR2);
1250e6594a8SSascha Wildner 	sigaddset(&ss, SIGTERM);
1260e6594a8SSascha Wildner 	sigaddset(&ss, SIGWINCH);
1270e6594a8SSascha Wildner 
128*e8b1691fSMatthew Dillon 	crit_enter_quick(td);
129f9235b6dSMatthew Dillon 	++gd->gd_intr_nesting_level;
130c07315c4SMatthew Dillon 	while (CPUMASK_TESTMASK(stopped_cpus, gd->gd_cpumask)) {
1310e6594a8SSascha Wildner 		sigsuspend(&ss);
1320e6594a8SSascha Wildner 	}
133f9235b6dSMatthew Dillon 	--gd->gd_intr_nesting_level;
134*e8b1691fSMatthew Dillon 	crit_exit_quick(td);
1358c6462e6SMatthew Dillon 
1368c6462e6SMatthew Dillon 	errno = save;
1370e6594a8SSascha Wildner }
1380e6594a8SSascha Wildner 
1390e6594a8SSascha Wildner /*
1400e6594a8SSascha Wildner  * SIGIO is used by cothreads to signal back into the virtual kernel.
1410e6594a8SSascha Wildner  */
1420e6594a8SSascha Wildner static
1430e6594a8SSascha Wildner void
kqueuesig(int nada,siginfo_t * info,void * ctxp)144c91894e0SMatthew Dillon kqueuesig(int nada, siginfo_t *info, void *ctxp)
1450e6594a8SSascha Wildner {
146c91894e0SMatthew Dillon 	globaldata_t gd = mycpu;
147c91894e0SMatthew Dillon 	thread_t td = gd->gd_curthread;
1488c6462e6SMatthew Dillon 	int save;
149c91894e0SMatthew Dillon 
1508c6462e6SMatthew Dillon 	save = errno;
151c91894e0SMatthew Dillon 	if (td->td_critcount == 0) {
152*e8b1691fSMatthew Dillon 		crit_enter_quick(td);
153c91894e0SMatthew Dillon 		++gd->gd_intr_nesting_level;
154a4d95680SMatthew Dillon 		cpu_ccfence();
155c91894e0SMatthew Dillon 		kqueue_intr(NULL);
156a4d95680SMatthew Dillon 		cpu_ccfence();
157c91894e0SMatthew Dillon 		--gd->gd_intr_nesting_level;
158*e8b1691fSMatthew Dillon 		crit_exit_quick(td);
159c91894e0SMatthew Dillon 	} else {
160c91894e0SMatthew Dillon 		need_kqueue();
161c91894e0SMatthew Dillon 	}
1628c6462e6SMatthew Dillon 	errno = save;
1630e6594a8SSascha Wildner }
1640e6594a8SSascha Wildner 
165c91894e0SMatthew Dillon static
166c91894e0SMatthew Dillon void
timersig(int nada,siginfo_t * info,void * ctxp)167c91894e0SMatthew Dillon timersig(int nada, siginfo_t *info, void *ctxp)
168c91894e0SMatthew Dillon {
169c91894e0SMatthew Dillon 	globaldata_t gd = mycpu;
170c91894e0SMatthew Dillon 	thread_t td = gd->gd_curthread;
1718c6462e6SMatthew Dillon 	int save;
172c91894e0SMatthew Dillon 
1738c6462e6SMatthew Dillon 	save = errno;
174c91894e0SMatthew Dillon 	if (td->td_critcount == 0) {
175*e8b1691fSMatthew Dillon 		crit_enter_quick(td);
176c91894e0SMatthew Dillon 		++gd->gd_intr_nesting_level;
177a4d95680SMatthew Dillon 		cpu_ccfence();
178c91894e0SMatthew Dillon 		vktimer_intr(NULL);
179a4d95680SMatthew Dillon 		cpu_ccfence();
180c91894e0SMatthew Dillon 		--gd->gd_intr_nesting_level;
181*e8b1691fSMatthew Dillon 		crit_exit_quick(td);
182c91894e0SMatthew Dillon 	} else {
183c91894e0SMatthew Dillon 		need_timer();
184c91894e0SMatthew Dillon 	}
1858c6462e6SMatthew Dillon 	errno = save;
186c91894e0SMatthew Dillon }
187c91894e0SMatthew Dillon 
188c91894e0SMatthew Dillon static
189c91894e0SMatthew Dillon void
cosig(int nada,siginfo_t * info,void * ctxp)190c91894e0SMatthew Dillon cosig(int nada, siginfo_t *info, void *ctxp)
191c91894e0SMatthew Dillon {
1928c6462e6SMatthew Dillon 	int save;
1938c6462e6SMatthew Dillon 
1948c6462e6SMatthew Dillon 	save = errno;
195c91894e0SMatthew Dillon 	/* handles critical section checks */
196c91894e0SMatthew Dillon 	signalintr(1);
1978c6462e6SMatthew Dillon 	errno = save;
198c91894e0SMatthew Dillon }
1990e6594a8SSascha Wildner 
2008f8555f8SMatthew Dillon static
2018f8555f8SMatthew Dillon void
infosig(int nada,siginfo_t * info,void * ctxp)2028f8555f8SMatthew Dillon infosig(int nada, siginfo_t *info, void *ctxp)
2038f8555f8SMatthew Dillon {
2048f8555f8SMatthew Dillon 	ucontext_t *ctx = ctxp;
2058f8555f8SMatthew Dillon 	char buf[256];
2068c6462e6SMatthew Dillon 	int save;
2078f8555f8SMatthew Dillon 
2088c6462e6SMatthew Dillon 	save = errno;
2098f8555f8SMatthew Dillon 	snprintf(buf, sizeof(buf), "lwp %d pc=%p sp=%p\n",
210193c5c43SAntonio Huete Jimenez 		(lwpid_t)lwp_gettid(),
2118f8555f8SMatthew Dillon 		(void *)(intptr_t)ctx->uc_mcontext.mc_rip,
2128f8555f8SMatthew Dillon 		(void *)(intptr_t)ctx->uc_mcontext.mc_rsp);
2138f8555f8SMatthew Dillon 	write(2, buf, strlen(buf));
2148c6462e6SMatthew Dillon 	errno = save;
2158f8555f8SMatthew Dillon }
2168f8555f8SMatthew Dillon 
2170e6594a8SSascha Wildner void
init_exceptions(void)2180e6594a8SSascha Wildner init_exceptions(void)
2190e6594a8SSascha Wildner {
2200e6594a8SSascha Wildner 	struct sigaction sa;
2210e6594a8SSascha Wildner 
2220e6594a8SSascha Wildner 	bzero(&sa, sizeof(sa));
2230e6594a8SSascha Wildner 	sa.sa_sigaction = exc_segfault;
2240e6594a8SSascha Wildner 	sa.sa_flags |= SA_SIGINFO | SA_NODEFER;
2250e6594a8SSascha Wildner 	sigemptyset(&sa.sa_mask);
2260e6594a8SSascha Wildner 	sigaction(SIGBUS, &sa, NULL);
2270e6594a8SSascha Wildner 	sigaction(SIGSEGV, &sa, NULL);
2280e6594a8SSascha Wildner 	sigaction(SIGTRAP, &sa, NULL);
2290e6594a8SSascha Wildner 	sigaction(SIGFPE, &sa, NULL);
2300e6594a8SSascha Wildner 
231aa56bc86SMatthew Dillon 	sa.sa_flags &= ~SA_NODEFER;
232aa56bc86SMatthew Dillon 
2330e6594a8SSascha Wildner #ifdef DDB
2340e6594a8SSascha Wildner 	sa.sa_sigaction = exc_debugger;
2350e6594a8SSascha Wildner 	sigaction(SIGQUIT, &sa, NULL);
2360e6594a8SSascha Wildner #endif
2370e6594a8SSascha Wildner 	sa.sa_sigaction = ipisig;
2380e6594a8SSascha Wildner 	sigaction(SIGUSR1, &sa, NULL);
239c91894e0SMatthew Dillon 
2400e6594a8SSascha Wildner 	sa.sa_sigaction = stopsig;
2410e6594a8SSascha Wildner 	sigaction(SIGXCPU, &sa, NULL);
242c91894e0SMatthew Dillon 
243c91894e0SMatthew Dillon 	sa.sa_sigaction = kqueuesig;
2440e6594a8SSascha Wildner 	sigaction(SIGIO, &sa, NULL);
245c91894e0SMatthew Dillon 
246c91894e0SMatthew Dillon 	sa.sa_sigaction = timersig;
247c91894e0SMatthew Dillon 	sigaction(SIGURG, &sa, NULL);
248c91894e0SMatthew Dillon 
249c91894e0SMatthew Dillon 	sa.sa_sigaction = cosig;
250c91894e0SMatthew Dillon 	sigaction(SIGALRM, &sa, NULL);
251c91894e0SMatthew Dillon 
2528f8555f8SMatthew Dillon 	sa.sa_sigaction = infosig;
2538f8555f8SMatthew Dillon 	sigaction(SIGINFO, &sa, NULL);
2540e6594a8SSascha Wildner }
2550e6594a8SSascha Wildner 
2560e6594a8SSascha Wildner /*
2570e6594a8SSascha Wildner  * This function handles a segmentation fault.
2580e6594a8SSascha Wildner  *
2590e6594a8SSascha Wildner  * XXX We assume that trapframe is a subset of ucontext.  It is as of
2600e6594a8SSascha Wildner  *     this writing.
2610e6594a8SSascha Wildner  */
2620e6594a8SSascha Wildner static void
exc_segfault(int signo,siginfo_t * info,void * ctxp)2630e6594a8SSascha Wildner exc_segfault(int signo, siginfo_t *info, void *ctxp)
2640e6594a8SSascha Wildner {
2650e6594a8SSascha Wildner 	ucontext_t *ctx = ctxp;
2668c6462e6SMatthew Dillon 	int save;
2670e6594a8SSascha Wildner 
2688c6462e6SMatthew Dillon 	save = errno;
26973e24181SMatthew Dillon #if 0
270b9d01986SMatthew Dillon 	kprintf("CAUGHT SIG %d RIP %08lx ERR %08lx TRAPNO %ld "
271b9d01986SMatthew Dillon 		"err %ld addr %08lx\n",
272b9d01986SMatthew Dillon 		signo,
273b9d01986SMatthew Dillon 		ctx->uc_mcontext.mc_rip,
2740e6594a8SSascha Wildner 		ctx->uc_mcontext.mc_err,
2750e6594a8SSascha Wildner 		ctx->uc_mcontext.mc_trapno & 0xFFFF,
276b9d01986SMatthew Dillon 		ctx->uc_mcontext.mc_trapno >> 16,
277b9d01986SMatthew Dillon 		ctx->uc_mcontext.mc_addr);
2780e6594a8SSascha Wildner #endif
2790e6594a8SSascha Wildner 	kern_trap((struct trapframe *)&ctx->uc_mcontext.mc_rdi);
2800e6594a8SSascha Wildner 	splz();
2818c6462e6SMatthew Dillon 	errno = save;
2820e6594a8SSascha Wildner }
2830e6594a8SSascha Wildner 
2840e6594a8SSascha Wildner #ifdef DDB
2850e6594a8SSascha Wildner 
2860e6594a8SSascha Wildner static void
exc_debugger(int signo,siginfo_t * info,void * ctxp)28758f6b4c1SMatthew Dillon exc_debugger(int signo, siginfo_t *info, void *ctxp)
2880e6594a8SSascha Wildner {
28958f6b4c1SMatthew Dillon 	ucontext_t *ctx = ctxp;
2908c6462e6SMatthew Dillon 	int save;
29158f6b4c1SMatthew Dillon 
2928c6462e6SMatthew Dillon 	save = errno;
29358f6b4c1SMatthew Dillon 	kprintf("CAUGHT SIG %d RIP %08lx RSP %08lx TD %p\n",
29458f6b4c1SMatthew Dillon 		signo,
29558f6b4c1SMatthew Dillon 		ctx->uc_mcontext.mc_rip,
29658f6b4c1SMatthew Dillon 		ctx->uc_mcontext.mc_rsp,
29758f6b4c1SMatthew Dillon 		curthread);
2980e6594a8SSascha Wildner 	Debugger("interrupt from console");
2998c6462e6SMatthew Dillon 	errno = save;
3000e6594a8SSascha Wildner }
3010e6594a8SSascha Wildner 
3020e6594a8SSascha Wildner #endif
303