trap.c revision 163709
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 163709 2006-10-26 21:42:22Z jb $");
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
7996938Sbennovoid		trap(struct trapframe *);
8096255Sbenno
8196938Sbennostatic void	trap_fatal(struct trapframe *frame);
8296938Sbennostatic void	printtrap(u_int vector, struct trapframe *frame, int isfatal,
8396938Sbenno		    int user);
8496938Sbennostatic int	trap_pfault(struct trapframe *frame, int user);
8596938Sbennostatic int	fix_unaligned(struct thread *td, struct trapframe *frame);
8696938Sbennostatic int	handle_onfault(struct trapframe *frame);
8796938Sbennostatic void	syscall(struct trapframe *frame);
8896938Sbenno
8996906Sbennostatic __inline void	setusr(u_int);
9077957Sbenno
9196906Sbennoint	setfault(faultbuf);		/* defined in locore.S */
9296906Sbenno
9396255Sbenno/* Why are these not defined in a header? */
9496906Sbennoint	badaddr(void *, size_t);
9596906Sbennoint	badaddr_read(void *, size_t, int *);
9686067Smp
9796499Sbennoextern char	*syscallnames[];
9896499Sbenno
9996938Sbennostruct powerpc_exception {
10096938Sbenno	u_int	vector;
10196938Sbenno	char	*name;
10296938Sbenno};
10396938Sbenno
10496938Sbennostatic struct powerpc_exception powerpc_exceptions[] = {
10596938Sbenno	{ 0x0100, "system reset" },
10696938Sbenno	{ 0x0200, "machine check" },
10796938Sbenno	{ 0x0300, "data storage interrupt" },
10896938Sbenno	{ 0x0400, "instruction storage interrupt" },
10996938Sbenno	{ 0x0500, "external interrupt" },
11096938Sbenno	{ 0x0600, "alignment" },
11196938Sbenno	{ 0x0700, "program" },
11296938Sbenno	{ 0x0800, "floating-point unavailable" },
11396938Sbenno	{ 0x0900, "decrementer" },
11496938Sbenno	{ 0x0c00, "system call" },
11596938Sbenno	{ 0x0d00, "trace" },
11696938Sbenno	{ 0x0e00, "floating-point assist" },
11796938Sbenno	{ 0x0f00, "performance monitoring" },
11896938Sbenno	{ 0x0f20, "altivec unavailable" },
11996938Sbenno	{ 0x1000, "instruction tlb miss" },
12096938Sbenno	{ 0x1100, "data load tlb miss" },
12196938Sbenno	{ 0x1200, "data store tlb miss" },
12296938Sbenno	{ 0x1300, "instruction breakpoint" },
123131698Sgrehan	{ 0x1400, "system management" },
12496938Sbenno	{ 0x1600, "altivec assist" },
12596938Sbenno	{ 0x1700, "thermal management" },
12696938Sbenno	{ 0x2000, "run mode/trace" },
12796938Sbenno	{ 0x3000, NULL }
12896938Sbenno};
12996938Sbenno
13096938Sbennostatic const char *
13196938Sbennotrapname(u_int vector)
13296938Sbenno{
13396938Sbenno	struct	powerpc_exception *pe;
13496938Sbenno
13596938Sbenno	for (pe = powerpc_exceptions; pe->vector != 0x3000; pe++) {
13696938Sbenno		if (pe->vector == vector)
13796938Sbenno			return (pe->name);
13896938Sbenno	}
13996938Sbenno
14096938Sbenno	return ("unknown");
14196938Sbenno}
14296938Sbenno
14396255Sbennovoid
14496906Sbennotrap(struct trapframe *frame)
14586067Smp{
146112429Sgrehan	struct thread	*td;
14796906Sbenno	struct proc	*p;
14896938Sbenno	int		sig, type, user;
149155455Sphk	u_int		ucode;
150151316Sdavidxu	ksiginfo_t	ksi;
15186067Smp
152144971Sjhb	PCPU_LAZY_INC(cnt.v_trap);
15396938Sbenno
15496906Sbenno	td = PCPU_GET(curthread);
15596906Sbenno	p = td->td_proc;
15686067Smp
15796938Sbenno	type = ucode = frame->exc;
15896938Sbenno	sig = 0;
15996938Sbenno	user = frame->srr1 & PSL_PR;
16086067Smp
16196938Sbenno	CTR3(KTR_TRAP, "trap: %s type=%s (%s)", p->p_comm,
16296938Sbenno	    trapname(type), user ? "user" : "kernel");
16386067Smp
16496938Sbenno	if (user) {
165155455Sphk		td->td_pticks = 0;
16696938Sbenno		td->td_frame = frame;
16796938Sbenno		if (td->td_ucred != p->p_ucred)
16896938Sbenno			cred_update_thread(td);
16986067Smp
17096938Sbenno		/* User Mode Traps */
17196938Sbenno		switch (type) {
17296938Sbenno		case EXC_RUNMODETRC:
17396938Sbenno		case EXC_TRC:
17496938Sbenno			frame->srr1 &= ~PSL_SE;
17596938Sbenno			sig = SIGTRAP;
17696938Sbenno			break;
17777957Sbenno
17896938Sbenno		case EXC_DSI:
17996938Sbenno		case EXC_ISI:
18096938Sbenno			sig = trap_pfault(frame, 1);
18196938Sbenno			break;
18296938Sbenno
18396938Sbenno		case EXC_SC:
18496938Sbenno			syscall(frame);
18596938Sbenno			break;
18696938Sbenno
18796938Sbenno		case EXC_FPU:
188112429Sgrehan			KASSERT((td->td_pcb->pcb_flags & PCB_FPU) != PCB_FPU,
189112429Sgrehan			    ("FPU already enabled for thread"));
19096938Sbenno			enable_fpu(td);
19196938Sbenno			break;
19296938Sbenno
19396938Sbenno#ifdef	ALTIVEC
19496938Sbenno		case EXC_VEC:
19596938Sbenno			if ((vecthread = PCPU_GET(vecthread)) != NULL) {
19696938Sbenno				KASSERT(vecthread != td,
19796938Sbenno				    ("altivec already enabled"));
19896938Sbenno				save_vec(vecthread);
19996938Sbenno			}
20096938Sbenno			PCPU_SET(vecthread, td);
20196938Sbenno			td->td_pcb->pcb_veccpu = PCPU_GET(cpuid);
20296938Sbenno			enable_vec(td);
20396938Sbenno			frame->srr1 |= PSL_VEC;
20496938Sbenno			break;
205148568Sgrehan#else
206148568Sgrehan		case EXC_VEC:
207148568Sgrehan		case EXC_VECAST:
208148568Sgrehan			sig = SIGILL;
209148568Sgrehan			break;
21096938Sbenno#endif /* ALTIVEC */
21196938Sbenno
21296938Sbenno		case EXC_ALI:
21396938Sbenno			if (fix_unaligned(td, frame) != 0)
21496938Sbenno				sig = SIGBUS;
21577957Sbenno			else
21696938Sbenno				frame->srr0 += 4;
21796938Sbenno			break;
21896938Sbenno
21996938Sbenno		case EXC_PGM:
22096938Sbenno			/* XXX temporarily */
22196938Sbenno			/* XXX: Magic Number? */
22296938Sbenno			if (frame->srr1 & 0x0002000)
22396938Sbenno				sig = SIGTRAP;
22496938Sbenno 			else
22596938Sbenno				sig = SIGILL;
22696938Sbenno			break;
22796938Sbenno
22896938Sbenno		default:
22996938Sbenno			trap_fatal(frame);
23077957Sbenno		}
23196938Sbenno	} else {
23296938Sbenno		/* Kernel Mode Traps */
23396938Sbenno
23496938Sbenno		KASSERT(cold || td->td_ucred != NULL,
23596938Sbenno		    ("kernel trap doesn't have ucred"));
23696938Sbenno		switch (type) {
23796938Sbenno		case EXC_DSI:
23896938Sbenno			if (trap_pfault(frame, 0) == 0)
23996938Sbenno 				return;
24096938Sbenno			break;
24196938Sbenno		case EXC_MCHK:
24296938Sbenno			if (handle_onfault(frame))
24396938Sbenno 				return;
24496938Sbenno			break;
24596938Sbenno		default:
246132994Sgrehan			break;
24796255Sbenno		}
248132994Sgrehan		trap_fatal(frame);
24986067Smp	}
25096938Sbenno
25196938Sbenno#ifdef	ALTIVEC
25296938Sbenno	if (td != PCPU_GET(vecthread) ||
25396938Sbenno	    td->td_pcb->pcb_veccpu != PCPU_GET(cpuid))
25496938Sbenno		frame->srr1 &= ~PSL_VEC;
25596938Sbenno#endif /* ALTIVEC */
25696938Sbenno
25796938Sbenno	if (sig != 0) {
25896938Sbenno		if (p->p_sysent->sv_transtrap != NULL)
25996938Sbenno			sig = (p->p_sysent->sv_transtrap)(sig, type);
260151316Sdavidxu		ksiginfo_init_trap(&ksi);
261151316Sdavidxu		ksi.ksi_signo = sig;
262151316Sdavidxu		ksi.ksi_code = (int) ucode; /* XXX, not POSIX */
263151316Sdavidxu		/* ksi.ksi_addr = ? */
264151316Sdavidxu		ksi.ksi_trapno = type;
265151316Sdavidxu		trapsignal(td, &ksi);
26696938Sbenno	}
26796938Sbenno
268155455Sphk	userret(td, frame);
26996938Sbenno	mtx_assert(&Giant, MA_NOTOWNED);
27096938Sbenno}
27196938Sbenno
27296938Sbennostatic void
27396938Sbennotrap_fatal(struct trapframe *frame)
27496938Sbenno{
27596938Sbenno
27696938Sbenno	printtrap(frame->exc, frame, 1, (frame->srr1 & PSL_PR));
277132074Sgrehan#ifdef KDB
278132074Sgrehan	if ((debugger_on_panic || kdb_active) &&
279132074Sgrehan	    kdb_trap(frame->exc, 0, frame))
28096938Sbenno		return;
28196938Sbenno#endif
28296938Sbenno	panic("%s trap", trapname(frame->exc));
28396938Sbenno}
28496938Sbenno
28596938Sbennostatic void
28696938Sbennoprinttrap(u_int vector, struct trapframe *frame, int isfatal, int user)
28796938Sbenno{
28896938Sbenno
28996938Sbenno	printf("\n");
29096938Sbenno	printf("%s %s trap:\n", isfatal ? "fatal" : "handled",
29196938Sbenno	    user ? "user" : "kernel");
29296938Sbenno	printf("\n");
29396938Sbenno	printf("   exception       = 0x%x (%s)\n", vector >> 8,
29496938Sbenno	    trapname(vector));
29596938Sbenno	switch (vector) {
29696938Sbenno	case EXC_DSI:
29796938Sbenno		printf("   virtual address = 0x%x\n", frame->dar);
29896255Sbenno		break;
29996255Sbenno	case EXC_ISI:
30096938Sbenno		printf("   virtual address = 0x%x\n", frame->srr0);
30196255Sbenno		break;
30296938Sbenno	}
30397347Sbenno	printf("   srr0            = 0x%x\n", frame->srr0);
30497347Sbenno	printf("   srr1            = 0x%x\n", frame->srr1);
30596938Sbenno	printf("   curthread       = %p\n", curthread);
30696938Sbenno	if (curthread != NULL)
30796938Sbenno		printf("          pid = %d, comm = %s\n",
30896938Sbenno		    curthread->td_proc->p_pid, curthread->td_proc->p_comm);
30996938Sbenno	printf("\n");
31096938Sbenno}
31186067Smp
31296938Sbenno/*
31396938Sbenno * Handles a fatal fault when we have onfault state to recover.  Returns
31496938Sbenno * non-zero if there was onfault recovery state available.
31596938Sbenno */
31696938Sbennostatic int
31796938Sbennohandle_onfault(struct trapframe *frame)
31896938Sbenno{
31996938Sbenno	struct		thread *td;
32096938Sbenno	faultbuf	*fb;
32186067Smp
32296938Sbenno	td = curthread;
32396938Sbenno	fb = td->td_pcb->pcb_onfault;
32496938Sbenno	if (fb != NULL) {
32596938Sbenno		frame->srr0 = (*fb)[0];
32696938Sbenno		frame->fixreg[1] = (*fb)[1];
32796938Sbenno		frame->fixreg[2] = (*fb)[2];
328131867Sgrehan		frame->fixreg[3] = 1;
32996938Sbenno		frame->cr = (*fb)[3];
33096938Sbenno		bcopy(&(*fb)[4], &frame->fixreg[13],
33196938Sbenno		    19 * sizeof(register_t));
33296938Sbenno		return (1);
33396938Sbenno	}
33496938Sbenno	return (0);
33596938Sbenno}
33686067Smp
33796938Sbennovoid
33896938Sbennosyscall(struct trapframe *frame)
33996938Sbenno{
34096938Sbenno	caddr_t		params;
34196938Sbenno	struct		sysent *callp;
34296938Sbenno	struct		thread *td;
34396938Sbenno	struct		proc *p;
34496938Sbenno	int		error, n;
34596938Sbenno	size_t		narg;
34696938Sbenno	register_t	args[10];
34796938Sbenno	u_int		code;
34886067Smp
34996938Sbenno	td = PCPU_GET(curthread);
35096938Sbenno	p = td->td_proc;
35186067Smp
352144971Sjhb	PCPU_LAZY_INC(cnt.v_syscall);
353131698Sgrehan
354163709Sjb#ifdef KSE
355131698Sgrehan	if (p->p_flag & P_SA)
356134571Sjulian		thread_user_enter(td);
357163709Sjb#endif
358131698Sgrehan
35996938Sbenno	code = frame->fixreg[0];
36096938Sbenno	params = (caddr_t)(frame->fixreg + FIRSTARG);
36196938Sbenno	n = NARGREG;
362131698Sgrehan
36396938Sbenno	if (p->p_sysent->sv_prepsyscall) {
36496938Sbenno		/*
36596938Sbenno		 * The prep code is MP aware.
36696938Sbenno		 */
36796938Sbenno		(*p->p_sysent->sv_prepsyscall)(frame, args, &code, &params);
36896938Sbenno	} else if (code == SYS_syscall) {
36996938Sbenno		/*
37096938Sbenno		 * code is first argument,
37196938Sbenno		 * followed by actual args.
37296938Sbenno		 */
373103607Sgrehan		code = *(u_int *) params;
374103607Sgrehan		params += sizeof(register_t);
37596938Sbenno		n -= 1;
37696938Sbenno	} else if (code == SYS___syscall) {
37796938Sbenno		/*
37896938Sbenno		 * Like syscall, but code is a quad,
37996938Sbenno		 * so as to maintain quad alignment
38096938Sbenno		 * for the rest of the args.
38196938Sbenno		 */
382103607Sgrehan		params += sizeof(register_t);
383103607Sgrehan		code = *(u_int *) params;
384103607Sgrehan		params += sizeof(register_t);
38596938Sbenno		n -= 2;
38696938Sbenno	}
38796452Sbenno
38896938Sbenno 	if (p->p_sysent->sv_mask)
38996938Sbenno 		code &= p->p_sysent->sv_mask;
39086067Smp
39196938Sbenno 	if (code >= p->p_sysent->sv_size)
39296938Sbenno 		callp = &p->p_sysent->sv_table[0];
39396938Sbenno  	else
39496938Sbenno 		callp = &p->p_sysent->sv_table[code];
39586067Smp
396160801Sjhb	narg = callp->sy_narg;
39796255Sbenno
398103607Sgrehan	if (narg > n) {
39996938Sbenno		bcopy(params, args, n * sizeof(register_t));
40096938Sbenno		error = copyin(MOREARGS(frame->fixreg[1]), args + n,
401103607Sgrehan			       (narg - n) * sizeof(register_t));
40298001Sjhb		params = (caddr_t)args;
40398001Sjhb	} else
40498001Sjhb		error = 0;
40598001Sjhb
406131867Sgrehan	CTR5(KTR_SYSC, "syscall: p=%s %s(%x %x %x)", p->p_comm,
407131867Sgrehan	     syscallnames[code],
408131867Sgrehan	     frame->fixreg[FIRSTARG],
409131867Sgrehan	     frame->fixreg[FIRSTARG+1],
410131867Sgrehan	     frame->fixreg[FIRSTARG+2]);
411131867Sgrehan
41277957Sbenno#ifdef	KTRACE
41398001Sjhb	if (KTRPOINT(td, KTR_SYSCALL))
414103607Sgrehan		ktrsyscall(code, narg, (register_t *)params);
41577957Sbenno#endif
41677957Sbenno
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:
434131698Sgrehan		if ((frame->fixreg[0] == SYS___syscall) &&
435103607Sgrehan		    (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