trap.c revision 173600
1139825Simp/*-
277957Sbenno * Copyright (C) 1995, 1996 Wolfgang Solfrank.
377957Sbenno * Copyright (C) 1995, 1996 TooLs GmbH.
477957Sbenno * All rights reserved.
577957Sbenno *
677957Sbenno * Redistribution and use in source and binary forms, with or without
777957Sbenno * modification, are permitted provided that the following conditions
877957Sbenno * are met:
977957Sbenno * 1. Redistributions of source code must retain the above copyright
1077957Sbenno *    notice, this list of conditions and the following disclaimer.
1177957Sbenno * 2. Redistributions in binary form must reproduce the above copyright
1277957Sbenno *    notice, this list of conditions and the following disclaimer in the
1377957Sbenno *    documentation and/or other materials provided with the distribution.
1477957Sbenno * 3. All advertising materials mentioning features or use of this software
1577957Sbenno *    must display the following acknowledgement:
1677957Sbenno *	This product includes software developed by TooLs GmbH.
1777957Sbenno * 4. The name of TooLs GmbH may not be used to endorse or promote products
1877957Sbenno *    derived from this software without specific prior written permission.
1977957Sbenno *
2077957Sbenno * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
2177957Sbenno * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2277957Sbenno * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2377957Sbenno * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2477957Sbenno * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
2577957Sbenno * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
2677957Sbenno * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
2777957Sbenno * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
2877957Sbenno * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
2977957Sbenno * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3077957Sbenno *
3196255Sbenno * $NetBSD: trap.c,v 1.58 2002/03/04 04:07:35 dbj Exp $
3277957Sbenno */
3377957Sbenno
34113038Sobrien#include <sys/cdefs.h>
35113038Sobrien__FBSDID("$FreeBSD: head/sys/powerpc/aim/trap.c 173600 2007-11-14 06:21:24Z julian $");
3677957Sbenno
3777957Sbenno#include "opt_ktrace.h"
3877957Sbenno
3977957Sbenno#include <sys/param.h>
40132074Sgrehan#include <sys/kdb.h>
4196938Sbenno#include <sys/proc.h>
4296938Sbenno#include <sys/ktr.h>
4386067Smp#include <sys/lock.h>
4486067Smp#include <sys/mutex.h>
4596938Sbenno#include <sys/pioctl.h>
46160764Sjhb#include <sys/ptrace.h>
4777957Sbenno#include <sys/reboot.h>
4877957Sbenno#include <sys/syscall.h>
4996938Sbenno#include <sys/sysent.h>
5096255Sbenno#include <sys/systm.h>
5196906Sbenno#include <sys/uio.h>
52143633Sgrehan#include <sys/signalvar.h>
5386067Smp#ifdef KTRACE
5477957Sbenno#include <sys/ktrace.h>
5586067Smp#endif
5696938Sbenno#include <sys/vmmeter.h>
5777957Sbenno
58162361Srwatson#include <security/audit/audit.h>
59162361Srwatson
6077957Sbenno#include <vm/vm.h>
6186067Smp#include <vm/pmap.h>
6286067Smp#include <vm/vm_extern.h>
6396255Sbenno#include <vm/vm_param.h>
6477957Sbenno#include <vm/vm_kern.h>
6586067Smp#include <vm/vm_map.h>
6696255Sbenno#include <vm/vm_page.h>
6777957Sbenno
6877957Sbenno#include <machine/cpu.h>
6996255Sbenno#include <machine/db_machdep.h>
7096255Sbenno#include <machine/fpu.h>
7177957Sbenno#include <machine/frame.h>
7277957Sbenno#include <machine/pcb.h>
7396255Sbenno#include <machine/pmap.h>
7477957Sbenno#include <machine/psl.h>
7577957Sbenno#include <machine/trap.h>
7696255Sbenno#include <machine/spr.h>
7796255Sbenno#include <machine/sr.h>
7877957Sbenno
7996938Sbennostatic void	trap_fatal(struct trapframe *frame);
8096938Sbennostatic void	printtrap(u_int vector, struct trapframe *frame, int isfatal,
8196938Sbenno		    int user);
8296938Sbennostatic int	trap_pfault(struct trapframe *frame, int user);
8396938Sbennostatic int	fix_unaligned(struct thread *td, struct trapframe *frame);
8496938Sbennostatic int	handle_onfault(struct trapframe *frame);
8596938Sbennostatic void	syscall(struct trapframe *frame);
8696938Sbenno
8796906Sbennostatic __inline void	setusr(u_int);
8877957Sbenno
8996906Sbennoint	setfault(faultbuf);		/* defined in locore.S */
9096906Sbenno
9196255Sbenno/* Why are these not defined in a header? */
9296906Sbennoint	badaddr(void *, size_t);
9396906Sbennoint	badaddr_read(void *, size_t, int *);
9486067Smp
9596499Sbennoextern char	*syscallnames[];
9696499Sbenno
9796938Sbennostruct powerpc_exception {
9896938Sbenno	u_int	vector;
9996938Sbenno	char	*name;
10096938Sbenno};
10196938Sbenno
10296938Sbennostatic struct powerpc_exception powerpc_exceptions[] = {
10396938Sbenno	{ 0x0100, "system reset" },
10496938Sbenno	{ 0x0200, "machine check" },
10596938Sbenno	{ 0x0300, "data storage interrupt" },
10696938Sbenno	{ 0x0400, "instruction storage interrupt" },
10796938Sbenno	{ 0x0500, "external interrupt" },
10896938Sbenno	{ 0x0600, "alignment" },
10996938Sbenno	{ 0x0700, "program" },
11096938Sbenno	{ 0x0800, "floating-point unavailable" },
11196938Sbenno	{ 0x0900, "decrementer" },
11296938Sbenno	{ 0x0c00, "system call" },
11396938Sbenno	{ 0x0d00, "trace" },
11496938Sbenno	{ 0x0e00, "floating-point assist" },
11596938Sbenno	{ 0x0f00, "performance monitoring" },
11696938Sbenno	{ 0x0f20, "altivec unavailable" },
11796938Sbenno	{ 0x1000, "instruction tlb miss" },
11896938Sbenno	{ 0x1100, "data load tlb miss" },
11996938Sbenno	{ 0x1200, "data store tlb miss" },
12096938Sbenno	{ 0x1300, "instruction breakpoint" },
121131698Sgrehan	{ 0x1400, "system management" },
12296938Sbenno	{ 0x1600, "altivec assist" },
12396938Sbenno	{ 0x1700, "thermal management" },
12496938Sbenno	{ 0x2000, "run mode/trace" },
12596938Sbenno	{ 0x3000, NULL }
12696938Sbenno};
12796938Sbenno
12896938Sbennostatic const char *
12996938Sbennotrapname(u_int vector)
13096938Sbenno{
13196938Sbenno	struct	powerpc_exception *pe;
13296938Sbenno
13396938Sbenno	for (pe = powerpc_exceptions; pe->vector != 0x3000; pe++) {
13496938Sbenno		if (pe->vector == vector)
13596938Sbenno			return (pe->name);
13696938Sbenno	}
13796938Sbenno
13896938Sbenno	return ("unknown");
13996938Sbenno}
14096938Sbenno
14196255Sbennovoid
14296906Sbennotrap(struct trapframe *frame)
14386067Smp{
144112429Sgrehan	struct thread	*td;
14596906Sbenno	struct proc	*p;
14696938Sbenno	int		sig, type, user;
147155455Sphk	u_int		ucode;
148151316Sdavidxu	ksiginfo_t	ksi;
14986067Smp
150170291Sattilio	PCPU_INC(cnt.v_trap);
15196938Sbenno
15296906Sbenno	td = PCPU_GET(curthread);
15396906Sbenno	p = td->td_proc;
15486067Smp
15596938Sbenno	type = ucode = frame->exc;
15696938Sbenno	sig = 0;
15796938Sbenno	user = frame->srr1 & PSL_PR;
15886067Smp
15996938Sbenno	CTR3(KTR_TRAP, "trap: %s type=%s (%s)", p->p_comm,
16096938Sbenno	    trapname(type), user ? "user" : "kernel");
16186067Smp
16296938Sbenno	if (user) {
163155455Sphk		td->td_pticks = 0;
16496938Sbenno		td->td_frame = frame;
16596938Sbenno		if (td->td_ucred != p->p_ucred)
16696938Sbenno			cred_update_thread(td);
16786067Smp
16896938Sbenno		/* User Mode Traps */
16996938Sbenno		switch (type) {
17096938Sbenno		case EXC_RUNMODETRC:
17196938Sbenno		case EXC_TRC:
17296938Sbenno			frame->srr1 &= ~PSL_SE;
17396938Sbenno			sig = SIGTRAP;
17496938Sbenno			break;
17577957Sbenno
17696938Sbenno		case EXC_DSI:
17796938Sbenno		case EXC_ISI:
17896938Sbenno			sig = trap_pfault(frame, 1);
17996938Sbenno			break;
18096938Sbenno
18196938Sbenno		case EXC_SC:
18296938Sbenno			syscall(frame);
18396938Sbenno			break;
18496938Sbenno
18596938Sbenno		case EXC_FPU:
186112429Sgrehan			KASSERT((td->td_pcb->pcb_flags & PCB_FPU) != PCB_FPU,
187112429Sgrehan			    ("FPU already enabled for thread"));
18896938Sbenno			enable_fpu(td);
18996938Sbenno			break;
19096938Sbenno
19196938Sbenno#ifdef	ALTIVEC
19296938Sbenno		case EXC_VEC:
19396938Sbenno			if ((vecthread = PCPU_GET(vecthread)) != NULL) {
19496938Sbenno				KASSERT(vecthread != td,
19596938Sbenno				    ("altivec already enabled"));
19696938Sbenno				save_vec(vecthread);
19796938Sbenno			}
19896938Sbenno			PCPU_SET(vecthread, td);
19996938Sbenno			td->td_pcb->pcb_veccpu = PCPU_GET(cpuid);
20096938Sbenno			enable_vec(td);
20196938Sbenno			frame->srr1 |= PSL_VEC;
20296938Sbenno			break;
203148568Sgrehan#else
204148568Sgrehan		case EXC_VEC:
205148568Sgrehan		case EXC_VECAST:
206148568Sgrehan			sig = SIGILL;
207148568Sgrehan			break;
20896938Sbenno#endif /* ALTIVEC */
20996938Sbenno
21096938Sbenno		case EXC_ALI:
21196938Sbenno			if (fix_unaligned(td, frame) != 0)
21296938Sbenno				sig = SIGBUS;
21377957Sbenno			else
21496938Sbenno				frame->srr0 += 4;
21596938Sbenno			break;
21696938Sbenno
21796938Sbenno		case EXC_PGM:
21896938Sbenno			/* XXX temporarily */
21996938Sbenno			/* XXX: Magic Number? */
22096938Sbenno			if (frame->srr1 & 0x0002000)
22196938Sbenno				sig = SIGTRAP;
22296938Sbenno 			else
22396938Sbenno				sig = SIGILL;
22496938Sbenno			break;
22596938Sbenno
22696938Sbenno		default:
22796938Sbenno			trap_fatal(frame);
22877957Sbenno		}
22996938Sbenno	} else {
23096938Sbenno		/* Kernel Mode Traps */
23196938Sbenno
23296938Sbenno		KASSERT(cold || td->td_ucred != NULL,
23396938Sbenno		    ("kernel trap doesn't have ucred"));
23496938Sbenno		switch (type) {
23596938Sbenno		case EXC_DSI:
23696938Sbenno			if (trap_pfault(frame, 0) == 0)
23796938Sbenno 				return;
23896938Sbenno			break;
23996938Sbenno		case EXC_MCHK:
24096938Sbenno			if (handle_onfault(frame))
24196938Sbenno 				return;
24296938Sbenno			break;
24396938Sbenno		default:
244132994Sgrehan			break;
24596255Sbenno		}
246132994Sgrehan		trap_fatal(frame);
24786067Smp	}
24896938Sbenno
24996938Sbenno#ifdef	ALTIVEC
25096938Sbenno	if (td != PCPU_GET(vecthread) ||
25196938Sbenno	    td->td_pcb->pcb_veccpu != PCPU_GET(cpuid))
25296938Sbenno		frame->srr1 &= ~PSL_VEC;
25396938Sbenno#endif /* ALTIVEC */
25496938Sbenno
25596938Sbenno	if (sig != 0) {
25696938Sbenno		if (p->p_sysent->sv_transtrap != NULL)
25796938Sbenno			sig = (p->p_sysent->sv_transtrap)(sig, type);
258151316Sdavidxu		ksiginfo_init_trap(&ksi);
259151316Sdavidxu		ksi.ksi_signo = sig;
260151316Sdavidxu		ksi.ksi_code = (int) ucode; /* XXX, not POSIX */
261151316Sdavidxu		/* ksi.ksi_addr = ? */
262151316Sdavidxu		ksi.ksi_trapno = type;
263151316Sdavidxu		trapsignal(td, &ksi);
26496938Sbenno	}
26596938Sbenno
266155455Sphk	userret(td, frame);
26796938Sbenno	mtx_assert(&Giant, MA_NOTOWNED);
26896938Sbenno}
26996938Sbenno
27096938Sbennostatic void
27196938Sbennotrap_fatal(struct trapframe *frame)
27296938Sbenno{
27396938Sbenno
27496938Sbenno	printtrap(frame->exc, frame, 1, (frame->srr1 & PSL_PR));
275132074Sgrehan#ifdef KDB
276132074Sgrehan	if ((debugger_on_panic || kdb_active) &&
277132074Sgrehan	    kdb_trap(frame->exc, 0, frame))
27896938Sbenno		return;
27996938Sbenno#endif
28096938Sbenno	panic("%s trap", trapname(frame->exc));
28196938Sbenno}
28296938Sbenno
28396938Sbennostatic void
28496938Sbennoprinttrap(u_int vector, struct trapframe *frame, int isfatal, int user)
28596938Sbenno{
28696938Sbenno
28796938Sbenno	printf("\n");
28896938Sbenno	printf("%s %s trap:\n", isfatal ? "fatal" : "handled",
28996938Sbenno	    user ? "user" : "kernel");
29096938Sbenno	printf("\n");
29196938Sbenno	printf("   exception       = 0x%x (%s)\n", vector >> 8,
29296938Sbenno	    trapname(vector));
29396938Sbenno	switch (vector) {
29496938Sbenno	case EXC_DSI:
29596938Sbenno		printf("   virtual address = 0x%x\n", frame->dar);
29696255Sbenno		break;
29796255Sbenno	case EXC_ISI:
29896938Sbenno		printf("   virtual address = 0x%x\n", frame->srr0);
29996255Sbenno		break;
30096938Sbenno	}
30197347Sbenno	printf("   srr0            = 0x%x\n", frame->srr0);
30297347Sbenno	printf("   srr1            = 0x%x\n", frame->srr1);
30396938Sbenno	printf("   curthread       = %p\n", curthread);
30496938Sbenno	if (curthread != NULL)
30596938Sbenno		printf("          pid = %d, comm = %s\n",
306173600Sjulian		    curthread->td_proc->p_pid, curthread->td_name);
30796938Sbenno	printf("\n");
30896938Sbenno}
30986067Smp
31096938Sbenno/*
31196938Sbenno * Handles a fatal fault when we have onfault state to recover.  Returns
31296938Sbenno * non-zero if there was onfault recovery state available.
31396938Sbenno */
31496938Sbennostatic int
31596938Sbennohandle_onfault(struct trapframe *frame)
31696938Sbenno{
31796938Sbenno	struct		thread *td;
31896938Sbenno	faultbuf	*fb;
31986067Smp
32096938Sbenno	td = curthread;
32196938Sbenno	fb = td->td_pcb->pcb_onfault;
32296938Sbenno	if (fb != NULL) {
32396938Sbenno		frame->srr0 = (*fb)[0];
32496938Sbenno		frame->fixreg[1] = (*fb)[1];
32596938Sbenno		frame->fixreg[2] = (*fb)[2];
326131867Sgrehan		frame->fixreg[3] = 1;
32796938Sbenno		frame->cr = (*fb)[3];
32896938Sbenno		bcopy(&(*fb)[4], &frame->fixreg[13],
32996938Sbenno		    19 * sizeof(register_t));
33096938Sbenno		return (1);
33196938Sbenno	}
33296938Sbenno	return (0);
33396938Sbenno}
33486067Smp
33596938Sbennovoid
33696938Sbennosyscall(struct trapframe *frame)
33796938Sbenno{
33896938Sbenno	caddr_t		params;
33996938Sbenno	struct		sysent *callp;
34096938Sbenno	struct		thread *td;
34196938Sbenno	struct		proc *p;
34296938Sbenno	int		error, n;
34396938Sbenno	size_t		narg;
34496938Sbenno	register_t	args[10];
34596938Sbenno	u_int		code;
34686067Smp
34796938Sbenno	td = PCPU_GET(curthread);
34896938Sbenno	p = td->td_proc;
34986067Smp
350170291Sattilio	PCPU_INC(cnt.v_syscall);
351131698Sgrehan
352163709Sjb#ifdef KSE
353131698Sgrehan	if (p->p_flag & P_SA)
354134571Sjulian		thread_user_enter(td);
355163709Sjb#endif
356131698Sgrehan
35796938Sbenno	code = frame->fixreg[0];
35896938Sbenno	params = (caddr_t)(frame->fixreg + FIRSTARG);
35996938Sbenno	n = NARGREG;
360131698Sgrehan
36196938Sbenno	if (p->p_sysent->sv_prepsyscall) {
36296938Sbenno		/*
36396938Sbenno		 * The prep code is MP aware.
36496938Sbenno		 */
36596938Sbenno		(*p->p_sysent->sv_prepsyscall)(frame, args, &code, &params);
36696938Sbenno	} else if (code == SYS_syscall) {
36796938Sbenno		/*
36896938Sbenno		 * code is first argument,
36996938Sbenno		 * followed by actual args.
37096938Sbenno		 */
371103607Sgrehan		code = *(u_int *) params;
372103607Sgrehan		params += sizeof(register_t);
37396938Sbenno		n -= 1;
37496938Sbenno	} else if (code == SYS___syscall) {
37596938Sbenno		/*
37696938Sbenno		 * Like syscall, but code is a quad,
37796938Sbenno		 * so as to maintain quad alignment
37896938Sbenno		 * for the rest of the args.
37996938Sbenno		 */
380103607Sgrehan		params += sizeof(register_t);
381103607Sgrehan		code = *(u_int *) params;
382103607Sgrehan		params += sizeof(register_t);
38396938Sbenno		n -= 2;
38496938Sbenno	}
38596452Sbenno
38696938Sbenno 	if (p->p_sysent->sv_mask)
38796938Sbenno 		code &= p->p_sysent->sv_mask;
38886067Smp
38996938Sbenno 	if (code >= p->p_sysent->sv_size)
39096938Sbenno 		callp = &p->p_sysent->sv_table[0];
39196938Sbenno  	else
39296938Sbenno 		callp = &p->p_sysent->sv_table[code];
39386067Smp
394160801Sjhb	narg = callp->sy_narg;
39596255Sbenno
396103607Sgrehan	if (narg > n) {
39796938Sbenno		bcopy(params, args, n * sizeof(register_t));
39896938Sbenno		error = copyin(MOREARGS(frame->fixreg[1]), args + n,
399103607Sgrehan			       (narg - n) * sizeof(register_t));
40098001Sjhb		params = (caddr_t)args;
40198001Sjhb	} else
40298001Sjhb		error = 0;
40398001Sjhb
404131867Sgrehan	CTR5(KTR_SYSC, "syscall: p=%s %s(%x %x %x)", p->p_comm,
405131867Sgrehan	     syscallnames[code],
406131867Sgrehan	     frame->fixreg[FIRSTARG],
407131867Sgrehan	     frame->fixreg[FIRSTARG+1],
408131867Sgrehan	     frame->fixreg[FIRSTARG+2]);
409131867Sgrehan
41077957Sbenno#ifdef	KTRACE
41198001Sjhb	if (KTRPOINT(td, KTR_SYSCALL))
412103607Sgrehan		ktrsyscall(code, narg, (register_t *)params);
41377957Sbenno#endif
41477957Sbenno
415167352Smohans	td->td_syscalls++;
416167352Smohans
41798001Sjhb	if (error == 0) {
41898001Sjhb		td->td_retval[0] = 0;
41998001Sjhb		td->td_retval[1] = frame->fixreg[FIRSTARG + 1];
42096255Sbenno
42198001Sjhb		STOPEVENT(p, S_SCE, narg);
42277957Sbenno
423160764Sjhb		PTRACESTOP_SC(p, td, S_PT_SCE);
424160764Sjhb
425162361Srwatson		AUDIT_SYSCALL_ENTER(code, td);
42698001Sjhb		error = (*callp->sy_call)(td, params);
427162361Srwatson		AUDIT_SYSCALL_EXIT(error, td);
428131867Sgrehan
429131867Sgrehan		CTR3(KTR_SYSC, "syscall: p=%s %s ret=%x", p->p_comm,
430131867Sgrehan		     syscallnames[code], td->td_retval[0]);
43198001Sjhb	}
43296938Sbenno	switch (error) {
43396938Sbenno	case 0:
434171670Smarcel		if (frame->fixreg[0] == SYS___syscall &&
435171670Smarcel		    code != SYS_freebsd6_lseek && code != SYS_lseek) {
436103607Sgrehan			/*
437103607Sgrehan			 * 64-bit return, 32-bit syscall. Fixup byte order
438103607Sgrehan			 */
439103607Sgrehan			frame->fixreg[FIRSTARG] = 0;
440103607Sgrehan			frame->fixreg[FIRSTARG + 1] = td->td_retval[0];
441103607Sgrehan		} else {
442103607Sgrehan			frame->fixreg[FIRSTARG] = td->td_retval[0];
443103607Sgrehan			frame->fixreg[FIRSTARG + 1] = td->td_retval[1];
444103607Sgrehan		}
44596938Sbenno		/* XXX: Magic number */
44696938Sbenno		frame->cr &= ~0x10000000;
44796255Sbenno		break;
44896938Sbenno	case ERESTART:
44996938Sbenno		/*
45096938Sbenno		 * Set user's pc back to redo the system call.
45196938Sbenno		 */
45296938Sbenno		frame->srr0 -= 4;
45396255Sbenno		break;
45496938Sbenno	case EJUSTRETURN:
45596938Sbenno		/* nothing to do */
45696938Sbenno		break;
45796938Sbenno	default:
45896938Sbenno		if (p->p_sysent->sv_errsize) {
45996938Sbenno			if (error >= p->p_sysent->sv_errsize)
46096938Sbenno				error = -1;	/* XXX */
46196938Sbenno			else
46296938Sbenno				error = p->p_sysent->sv_errtbl[error];
46396255Sbenno		}
46496938Sbenno		frame->fixreg[FIRSTARG] = error;
46596938Sbenno		/* XXX: Magic number: Carry Flag Equivalent? */
46696938Sbenno		frame->cr |= 0x10000000;
46796938Sbenno		break;
46877957Sbenno	}
46977957Sbenno
470160773Sjhb	/*
471160773Sjhb	 * Check for misbehavior.
472160773Sjhb	 */
473160773Sjhb	WITNESS_WARN(WARN_PANIC, NULL, "System call %s returning",
474160773Sjhb	    (code >= 0 && code < SYS_MAXSYSCALL) ? syscallnames[code] : "???");
475160773Sjhb	KASSERT(td->td_critnest == 0,
476160773Sjhb	    ("System call %s returning in a critical section",
477160773Sjhb	    (code >= 0 && code < SYS_MAXSYSCALL) ? syscallnames[code] : "???"));
478160773Sjhb	KASSERT(td->td_locks == 0,
479160773Sjhb	    ("System call %s returning with %d locks held",
480160773Sjhb	    (code >= 0 && code < SYS_MAXSYSCALL) ? syscallnames[code] : "???",
481160773Sjhb	    td->td_locks));
482160773Sjhb
48396938Sbenno#ifdef	KTRACE
48498001Sjhb	if (KTRPOINT(td, KTR_SYSRET))
48598001Sjhb		ktrsysret(code, error, td->td_retval[0]);
48696255Sbenno#endif
48786067Smp
48896255Sbenno	/*
48996938Sbenno	 * Does the comment in the i386 code about errno apply here?
49096255Sbenno	 */
49196938Sbenno	STOPEVENT(p, S_SCX, code);
492160764Sjhb
493160764Sjhb	PTRACESTOP_SC(p, td, S_PT_SCX);
49477957Sbenno}
49577957Sbenno
49696938Sbennostatic int
49796938Sbennotrap_pfault(struct trapframe *frame, int user)
49877957Sbenno{
49996938Sbenno	vm_offset_t	eva, va;
50096938Sbenno	struct		thread *td;
50196938Sbenno	struct		proc *p;
50296938Sbenno	vm_map_t	map;
50396938Sbenno	vm_prot_t	ftype;
50496938Sbenno	int		rv;
50596938Sbenno	u_int		user_sr;
50677957Sbenno
50796938Sbenno	td = curthread;
50896906Sbenno	p = td->td_proc;
50996938Sbenno	if (frame->exc == EXC_ISI) {
51096938Sbenno		eva = frame->srr0;
51196938Sbenno		ftype = VM_PROT_READ | VM_PROT_EXECUTE;
51296938Sbenno	} else {
51396938Sbenno		eva = frame->dar;
51496938Sbenno		if (frame->dsisr & DSISR_STORE)
515103607Sgrehan			ftype = VM_PROT_WRITE;
51696938Sbenno		else
51796938Sbenno			ftype = VM_PROT_READ;
51896938Sbenno	}
51996906Sbenno
52096938Sbenno	if (user) {
52196938Sbenno		map = &p->p_vmspace->vm_map;
52296938Sbenno	} else {
52396938Sbenno		if ((eva >> ADDR_SR_SHFT) == USER_SR) {
52496938Sbenno			if (p->p_vmspace == NULL)
52596938Sbenno				return (SIGSEGV);
526131698Sgrehan
52796938Sbenno			__asm ("mfsr %0, %1"
52896938Sbenno			    : "=r"(user_sr)
52996938Sbenno			    : "K"(USER_SR));
53096938Sbenno			eva &= ADDR_PIDX | ADDR_POFF;
53196938Sbenno			eva |= user_sr << ADDR_SR_SHFT;
53296938Sbenno			map = &p->p_vmspace->vm_map;
53396938Sbenno		} else {
53496938Sbenno			map = kernel_map;
53596938Sbenno		}
53696938Sbenno	}
53796938Sbenno	va = trunc_page(eva);
53877957Sbenno
53996938Sbenno	if (map != kernel_map) {
54096938Sbenno		/*
54196938Sbenno		 * Keep swapout from messing with us during this
54296938Sbenno		 *	critical time.
54396938Sbenno		 */
54496255Sbenno		PROC_LOCK(p);
54596938Sbenno		++p->p_lock;
54696255Sbenno		PROC_UNLOCK(p);
54796938Sbenno
54896938Sbenno		/* Fault in the user page: */
54996938Sbenno		rv = vm_fault(map, va, ftype,
55096938Sbenno		      (ftype & VM_PROT_WRITE) ? VM_FAULT_DIRTY
55196938Sbenno					      : VM_FAULT_NORMAL);
55296938Sbenno
55396938Sbenno		PROC_LOCK(p);
55496938Sbenno		--p->p_lock;
55596938Sbenno		PROC_UNLOCK(p);
55696938Sbenno	} else {
55796938Sbenno		/*
55896938Sbenno		 * Don't have to worry about process locking or stacks in the
55996938Sbenno		 * kernel.
56096938Sbenno		 */
56196938Sbenno		rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL);
56296255Sbenno	}
56396938Sbenno
56496938Sbenno	if (rv == KERN_SUCCESS)
56596938Sbenno		return (0);
56696938Sbenno
56796938Sbenno	if (!user && handle_onfault(frame))
56896938Sbenno		return (0);
56996938Sbenno
57096938Sbenno	return (SIGSEGV);
57177957Sbenno}
57277957Sbenno
57396255Sbennostatic __inline void
57496906Sbennosetusr(u_int content)
57596255Sbenno{
57696255Sbenno	__asm __volatile ("isync; mtsr %0,%1; isync"
57796255Sbenno		      :: "n"(USER_SR), "r"(content));
57896255Sbenno}
57996255Sbenno
58077957Sbennoint
58196906Sbennobadaddr(void *addr, size_t size)
58277957Sbenno{
58396906Sbenno	return (badaddr_read(addr, size, NULL));
58477957Sbenno}
58577957Sbenno
58677957Sbennoint
58796906Sbennobadaddr_read(void *addr, size_t size, int *rptr)
58877957Sbenno{
58996906Sbenno	struct thread	*td;
59096906Sbenno	faultbuf	env;
59196906Sbenno	int		x;
59277957Sbenno
59377957Sbenno	/* Get rid of any stale machine checks that have been waiting.  */
59477957Sbenno	__asm __volatile ("sync; isync");
59577957Sbenno
59696255Sbenno	td = PCPU_GET(curthread);
59796255Sbenno
59877957Sbenno	if (setfault(env)) {
59996255Sbenno		td->td_pcb->pcb_onfault = 0;
60077957Sbenno		__asm __volatile ("sync");
60177957Sbenno		return 1;
60277957Sbenno	}
60377957Sbenno
60477957Sbenno	__asm __volatile ("sync");
60577957Sbenno
60677957Sbenno	switch (size) {
60777957Sbenno	case 1:
60877957Sbenno		x = *(volatile int8_t *)addr;
60977957Sbenno		break;
61077957Sbenno	case 2:
61177957Sbenno		x = *(volatile int16_t *)addr;
61277957Sbenno		break;
61377957Sbenno	case 4:
61477957Sbenno		x = *(volatile int32_t *)addr;
61577957Sbenno		break;
61677957Sbenno	default:
61777957Sbenno		panic("badaddr: invalid size (%d)", size);
61877957Sbenno	}
61977957Sbenno
62077957Sbenno	/* Make sure we took the machine check, if we caused one. */
62177957Sbenno	__asm __volatile ("sync; isync");
62277957Sbenno
62396255Sbenno	td->td_pcb->pcb_onfault = 0;
62477957Sbenno	__asm __volatile ("sync");	/* To be sure. */
62577957Sbenno
62677957Sbenno	/* Use the value to avoid reorder. */
62777957Sbenno	if (rptr)
62877957Sbenno		*rptr = x;
62977957Sbenno
63096906Sbenno	return (0);
63177957Sbenno}
63277957Sbenno
63377957Sbenno/*
63477957Sbenno * For now, this only deals with the particular unaligned access case
63577957Sbenno * that gcc tends to generate.  Eventually it should handle all of the
63677957Sbenno * possibilities that can happen on a 32-bit PowerPC in big-endian mode.
63777957Sbenno */
63877957Sbenno
63977957Sbennostatic int
64096906Sbennofix_unaligned(struct thread *td, struct trapframe *frame)
64177957Sbenno{
64296906Sbenno	struct thread	*fputhread;
64396906Sbenno	int		indicator, reg;
64496906Sbenno	double		*fpr;
64577957Sbenno
64696906Sbenno	indicator = EXC_ALI_OPCODE_INDICATOR(frame->dsisr);
64796906Sbenno
64877957Sbenno	switch (indicator) {
64977957Sbenno	case EXC_ALI_LFD:
65077957Sbenno	case EXC_ALI_STFD:
65196906Sbenno		reg = EXC_ALI_RST(frame->dsisr);
65296906Sbenno		fpr = &td->td_pcb->pcb_fpu.fpr[reg];
65396906Sbenno		fputhread = PCPU_GET(fputhread);
65477957Sbenno
65596906Sbenno		/* Juggle the FPU to ensure that we've initialized
65696906Sbenno		 * the FPRs, and that their current state is in
65796906Sbenno		 * the PCB.
65896906Sbenno		 */
65996906Sbenno		if (fputhread != td) {
66096906Sbenno			if (fputhread)
66196906Sbenno				save_fpu(fputhread);
66296906Sbenno			enable_fpu(td);
66396906Sbenno		}
66496906Sbenno		save_fpu(td);
66577957Sbenno
66696906Sbenno		if (indicator == EXC_ALI_LFD) {
66796906Sbenno			if (copyin((void *)frame->dar, fpr,
66896906Sbenno			    sizeof(double)) != 0)
66996906Sbenno				return -1;
67096906Sbenno			enable_fpu(td);
67196906Sbenno		} else {
67296906Sbenno			if (copyout(fpr, (void *)frame->dar,
67396906Sbenno			    sizeof(double)) != 0)
67496906Sbenno				return -1;
67577957Sbenno		}
67696906Sbenno		return 0;
67777957Sbenno		break;
67877957Sbenno	}
67977957Sbenno
68077957Sbenno	return -1;
68177957Sbenno}
682