trap.c revision 171670
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 171670 2007-07-31 06:23:26Z marcel $");
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
152170291Sattilio	PCPU_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
352170291Sattilio	PCPU_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
417167352Smohans	td->td_syscalls++;
418167352Smohans
41998001Sjhb	if (error == 0) {
42098001Sjhb		td->td_retval[0] = 0;
42198001Sjhb		td->td_retval[1] = frame->fixreg[FIRSTARG + 1];
42296255Sbenno
42398001Sjhb		STOPEVENT(p, S_SCE, narg);
42477957Sbenno
425160764Sjhb		PTRACESTOP_SC(p, td, S_PT_SCE);
426160764Sjhb
427162361Srwatson		AUDIT_SYSCALL_ENTER(code, td);
42898001Sjhb		error = (*callp->sy_call)(td, params);
429162361Srwatson		AUDIT_SYSCALL_EXIT(error, td);
430131867Sgrehan
431131867Sgrehan		CTR3(KTR_SYSC, "syscall: p=%s %s ret=%x", p->p_comm,
432131867Sgrehan		     syscallnames[code], td->td_retval[0]);
43398001Sjhb	}
43496938Sbenno	switch (error) {
43596938Sbenno	case 0:
436171670Smarcel		if (frame->fixreg[0] == SYS___syscall &&
437171670Smarcel		    code != SYS_freebsd6_lseek && code != SYS_lseek) {
438103607Sgrehan			/*
439103607Sgrehan			 * 64-bit return, 32-bit syscall. Fixup byte order
440103607Sgrehan			 */
441103607Sgrehan			frame->fixreg[FIRSTARG] = 0;
442103607Sgrehan			frame->fixreg[FIRSTARG + 1] = td->td_retval[0];
443103607Sgrehan		} else {
444103607Sgrehan			frame->fixreg[FIRSTARG] = td->td_retval[0];
445103607Sgrehan			frame->fixreg[FIRSTARG + 1] = td->td_retval[1];
446103607Sgrehan		}
44796938Sbenno		/* XXX: Magic number */
44896938Sbenno		frame->cr &= ~0x10000000;
44996255Sbenno		break;
45096938Sbenno	case ERESTART:
45196938Sbenno		/*
45296938Sbenno		 * Set user's pc back to redo the system call.
45396938Sbenno		 */
45496938Sbenno		frame->srr0 -= 4;
45596255Sbenno		break;
45696938Sbenno	case EJUSTRETURN:
45796938Sbenno		/* nothing to do */
45896938Sbenno		break;
45996938Sbenno	default:
46096938Sbenno		if (p->p_sysent->sv_errsize) {
46196938Sbenno			if (error >= p->p_sysent->sv_errsize)
46296938Sbenno				error = -1;	/* XXX */
46396938Sbenno			else
46496938Sbenno				error = p->p_sysent->sv_errtbl[error];
46596255Sbenno		}
46696938Sbenno		frame->fixreg[FIRSTARG] = error;
46796938Sbenno		/* XXX: Magic number: Carry Flag Equivalent? */
46896938Sbenno		frame->cr |= 0x10000000;
46996938Sbenno		break;
47077957Sbenno	}
47177957Sbenno
472160773Sjhb	/*
473160773Sjhb	 * Check for misbehavior.
474160773Sjhb	 */
475160773Sjhb	WITNESS_WARN(WARN_PANIC, NULL, "System call %s returning",
476160773Sjhb	    (code >= 0 && code < SYS_MAXSYSCALL) ? syscallnames[code] : "???");
477160773Sjhb	KASSERT(td->td_critnest == 0,
478160773Sjhb	    ("System call %s returning in a critical section",
479160773Sjhb	    (code >= 0 && code < SYS_MAXSYSCALL) ? syscallnames[code] : "???"));
480160773Sjhb	KASSERT(td->td_locks == 0,
481160773Sjhb	    ("System call %s returning with %d locks held",
482160773Sjhb	    (code >= 0 && code < SYS_MAXSYSCALL) ? syscallnames[code] : "???",
483160773Sjhb	    td->td_locks));
484160773Sjhb
48596938Sbenno#ifdef	KTRACE
48698001Sjhb	if (KTRPOINT(td, KTR_SYSRET))
48798001Sjhb		ktrsysret(code, error, td->td_retval[0]);
48896255Sbenno#endif
48986067Smp
49096255Sbenno	/*
49196938Sbenno	 * Does the comment in the i386 code about errno apply here?
49296255Sbenno	 */
49396938Sbenno	STOPEVENT(p, S_SCX, code);
494160764Sjhb
495160764Sjhb	PTRACESTOP_SC(p, td, S_PT_SCX);
49677957Sbenno}
49777957Sbenno
49896938Sbennostatic int
49996938Sbennotrap_pfault(struct trapframe *frame, int user)
50077957Sbenno{
50196938Sbenno	vm_offset_t	eva, va;
50296938Sbenno	struct		thread *td;
50396938Sbenno	struct		proc *p;
50496938Sbenno	vm_map_t	map;
50596938Sbenno	vm_prot_t	ftype;
50696938Sbenno	int		rv;
50796938Sbenno	u_int		user_sr;
50877957Sbenno
50996938Sbenno	td = curthread;
51096906Sbenno	p = td->td_proc;
51196938Sbenno	if (frame->exc == EXC_ISI) {
51296938Sbenno		eva = frame->srr0;
51396938Sbenno		ftype = VM_PROT_READ | VM_PROT_EXECUTE;
51496938Sbenno	} else {
51596938Sbenno		eva = frame->dar;
51696938Sbenno		if (frame->dsisr & DSISR_STORE)
517103607Sgrehan			ftype = VM_PROT_WRITE;
51896938Sbenno		else
51996938Sbenno			ftype = VM_PROT_READ;
52096938Sbenno	}
52196906Sbenno
52296938Sbenno	if (user) {
52396938Sbenno		map = &p->p_vmspace->vm_map;
52496938Sbenno	} else {
52596938Sbenno		if ((eva >> ADDR_SR_SHFT) == USER_SR) {
52696938Sbenno			if (p->p_vmspace == NULL)
52796938Sbenno				return (SIGSEGV);
528131698Sgrehan
52996938Sbenno			__asm ("mfsr %0, %1"
53096938Sbenno			    : "=r"(user_sr)
53196938Sbenno			    : "K"(USER_SR));
53296938Sbenno			eva &= ADDR_PIDX | ADDR_POFF;
53396938Sbenno			eva |= user_sr << ADDR_SR_SHFT;
53496938Sbenno			map = &p->p_vmspace->vm_map;
53596938Sbenno		} else {
53696938Sbenno			map = kernel_map;
53796938Sbenno		}
53896938Sbenno	}
53996938Sbenno	va = trunc_page(eva);
54077957Sbenno
54196938Sbenno	if (map != kernel_map) {
54296938Sbenno		/*
54396938Sbenno		 * Keep swapout from messing with us during this
54496938Sbenno		 *	critical time.
54596938Sbenno		 */
54696255Sbenno		PROC_LOCK(p);
54796938Sbenno		++p->p_lock;
54896255Sbenno		PROC_UNLOCK(p);
54996938Sbenno
55096938Sbenno		/* Fault in the user page: */
55196938Sbenno		rv = vm_fault(map, va, ftype,
55296938Sbenno		      (ftype & VM_PROT_WRITE) ? VM_FAULT_DIRTY
55396938Sbenno					      : VM_FAULT_NORMAL);
55496938Sbenno
55596938Sbenno		PROC_LOCK(p);
55696938Sbenno		--p->p_lock;
55796938Sbenno		PROC_UNLOCK(p);
55896938Sbenno	} else {
55996938Sbenno		/*
56096938Sbenno		 * Don't have to worry about process locking or stacks in the
56196938Sbenno		 * kernel.
56296938Sbenno		 */
56396938Sbenno		rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL);
56496255Sbenno	}
56596938Sbenno
56696938Sbenno	if (rv == KERN_SUCCESS)
56796938Sbenno		return (0);
56896938Sbenno
56996938Sbenno	if (!user && handle_onfault(frame))
57096938Sbenno		return (0);
57196938Sbenno
57296938Sbenno	return (SIGSEGV);
57377957Sbenno}
57477957Sbenno
57596255Sbennostatic __inline void
57696906Sbennosetusr(u_int content)
57796255Sbenno{
57896255Sbenno	__asm __volatile ("isync; mtsr %0,%1; isync"
57996255Sbenno		      :: "n"(USER_SR), "r"(content));
58096255Sbenno}
58196255Sbenno
58277957Sbennoint
58396906Sbennobadaddr(void *addr, size_t size)
58477957Sbenno{
58596906Sbenno	return (badaddr_read(addr, size, NULL));
58677957Sbenno}
58777957Sbenno
58877957Sbennoint
58996906Sbennobadaddr_read(void *addr, size_t size, int *rptr)
59077957Sbenno{
59196906Sbenno	struct thread	*td;
59296906Sbenno	faultbuf	env;
59396906Sbenno	int		x;
59477957Sbenno
59577957Sbenno	/* Get rid of any stale machine checks that have been waiting.  */
59677957Sbenno	__asm __volatile ("sync; isync");
59777957Sbenno
59896255Sbenno	td = PCPU_GET(curthread);
59996255Sbenno
60077957Sbenno	if (setfault(env)) {
60196255Sbenno		td->td_pcb->pcb_onfault = 0;
60277957Sbenno		__asm __volatile ("sync");
60377957Sbenno		return 1;
60477957Sbenno	}
60577957Sbenno
60677957Sbenno	__asm __volatile ("sync");
60777957Sbenno
60877957Sbenno	switch (size) {
60977957Sbenno	case 1:
61077957Sbenno		x = *(volatile int8_t *)addr;
61177957Sbenno		break;
61277957Sbenno	case 2:
61377957Sbenno		x = *(volatile int16_t *)addr;
61477957Sbenno		break;
61577957Sbenno	case 4:
61677957Sbenno		x = *(volatile int32_t *)addr;
61777957Sbenno		break;
61877957Sbenno	default:
61977957Sbenno		panic("badaddr: invalid size (%d)", size);
62077957Sbenno	}
62177957Sbenno
62277957Sbenno	/* Make sure we took the machine check, if we caused one. */
62377957Sbenno	__asm __volatile ("sync; isync");
62477957Sbenno
62596255Sbenno	td->td_pcb->pcb_onfault = 0;
62677957Sbenno	__asm __volatile ("sync");	/* To be sure. */
62777957Sbenno
62877957Sbenno	/* Use the value to avoid reorder. */
62977957Sbenno	if (rptr)
63077957Sbenno		*rptr = x;
63177957Sbenno
63296906Sbenno	return (0);
63377957Sbenno}
63477957Sbenno
63577957Sbenno/*
63677957Sbenno * For now, this only deals with the particular unaligned access case
63777957Sbenno * that gcc tends to generate.  Eventually it should handle all of the
63877957Sbenno * possibilities that can happen on a 32-bit PowerPC in big-endian mode.
63977957Sbenno */
64077957Sbenno
64177957Sbennostatic int
64296906Sbennofix_unaligned(struct thread *td, struct trapframe *frame)
64377957Sbenno{
64496906Sbenno	struct thread	*fputhread;
64596906Sbenno	int		indicator, reg;
64696906Sbenno	double		*fpr;
64777957Sbenno
64896906Sbenno	indicator = EXC_ALI_OPCODE_INDICATOR(frame->dsisr);
64996906Sbenno
65077957Sbenno	switch (indicator) {
65177957Sbenno	case EXC_ALI_LFD:
65277957Sbenno	case EXC_ALI_STFD:
65396906Sbenno		reg = EXC_ALI_RST(frame->dsisr);
65496906Sbenno		fpr = &td->td_pcb->pcb_fpu.fpr[reg];
65596906Sbenno		fputhread = PCPU_GET(fputhread);
65677957Sbenno
65796906Sbenno		/* Juggle the FPU to ensure that we've initialized
65896906Sbenno		 * the FPRs, and that their current state is in
65996906Sbenno		 * the PCB.
66096906Sbenno		 */
66196906Sbenno		if (fputhread != td) {
66296906Sbenno			if (fputhread)
66396906Sbenno				save_fpu(fputhread);
66496906Sbenno			enable_fpu(td);
66596906Sbenno		}
66696906Sbenno		save_fpu(td);
66777957Sbenno
66896906Sbenno		if (indicator == EXC_ALI_LFD) {
66996906Sbenno			if (copyin((void *)frame->dar, fpr,
67096906Sbenno			    sizeof(double)) != 0)
67196906Sbenno				return -1;
67296906Sbenno			enable_fpu(td);
67396906Sbenno		} else {
67496906Sbenno			if (copyout(fpr, (void *)frame->dar,
67596906Sbenno			    sizeof(double)) != 0)
67696906Sbenno				return -1;
67777957Sbenno		}
67896906Sbenno		return 0;
67977957Sbenno		break;
68077957Sbenno	}
68177957Sbenno
68277957Sbenno	return -1;
68377957Sbenno}
684