trap.c revision 97347
177957Sbenno/*
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
3477957Sbenno#ifndef lint
3577957Sbennostatic const char rcsid[] =
3677957Sbenno  "$FreeBSD: head/sys/powerpc/aim/trap.c 97347 2002-05-27 11:20:19Z benno $";
3777957Sbenno#endif /* not lint */
3877957Sbenno
3977957Sbenno#include "opt_ddb.h"
4077957Sbenno#include "opt_ktrace.h"
4177957Sbenno
4277957Sbenno#include <sys/param.h>
4396938Sbenno#include <sys/proc.h>
4496938Sbenno#include <sys/ktr.h>
4586067Smp#include <sys/lock.h>
4686067Smp#include <sys/mutex.h>
4796938Sbenno#include <sys/pioctl.h>
4877957Sbenno#include <sys/reboot.h>
4977957Sbenno#include <sys/syscall.h>
5096938Sbenno#include <sys/sysent.h>
5196255Sbenno#include <sys/systm.h>
5296906Sbenno#include <sys/uio.h>
5377957Sbenno#include <sys/user.h>
5486067Smp#ifdef KTRACE
5577957Sbenno#include <sys/ktrace.h>
5686067Smp#endif
5796938Sbenno#include <sys/vmmeter.h>
5877957Sbenno
5977957Sbenno#include <vm/vm.h>
6086067Smp#include <vm/pmap.h>
6186067Smp#include <vm/vm_extern.h>
6296255Sbenno#include <vm/vm_param.h>
6377957Sbenno#include <vm/vm_kern.h>
6486067Smp#include <vm/vm_map.h>
6596255Sbenno#include <vm/vm_page.h>
6677957Sbenno
6777957Sbenno#include <machine/cpu.h>
6896255Sbenno#include <machine/db_machdep.h>
6996255Sbenno#include <machine/fpu.h>
7077957Sbenno#include <machine/frame.h>
7177957Sbenno#include <machine/pcb.h>
7296255Sbenno#include <machine/pmap.h>
7377957Sbenno#include <machine/psl.h>
7477957Sbenno#include <machine/trap.h>
7596255Sbenno#include <machine/spr.h>
7696255Sbenno#include <machine/sr.h>
7777957Sbenno
7896255Sbenno/* These definitions should probably be somewhere else			XXX */
7977957Sbenno#define	FIRSTARG	3		/* first argument is in reg 3 */
8077957Sbenno#define	NARGREG		8		/* 8 args are in registers */
8177957Sbenno#define	MOREARGS(sp)	((caddr_t)((int)(sp) + 8)) /* more args go here */
8277957Sbenno
8396255Sbenno#ifndef MULTIPROCESSOR
8496255Sbennoextern int intr_depth;
8586067Smp#endif
8677957Sbenno
8796938Sbennovoid		trap(struct trapframe *);
8896255Sbenno
8996938Sbennostatic void	trap_fatal(struct trapframe *frame);
9096938Sbennostatic void	printtrap(u_int vector, struct trapframe *frame, int isfatal,
9196938Sbenno		    int user);
9296938Sbennostatic int	trap_pfault(struct trapframe *frame, int user);
9396938Sbennostatic int	fix_unaligned(struct thread *td, struct trapframe *frame);
9496938Sbennostatic int	handle_onfault(struct trapframe *frame);
9596938Sbennostatic void	syscall(struct trapframe *frame);
9696938Sbenno
9796906Sbennostatic __inline void	setusr(u_int);
9877957Sbenno
9996906Sbennoint	setfault(faultbuf);		/* defined in locore.S */
10096906Sbenno
10196255Sbenno/* Why are these not defined in a header? */
10296906Sbennoint	badaddr(void *, size_t);
10396906Sbennoint	badaddr_read(void *, size_t, int *);
10496906Sbennoint	kcopy(const void *, void *, size_t);
10586067Smp
10696906Sbenno#ifdef	WITNESS
10796499Sbennoextern char	*syscallnames[];
10896906Sbenno#endif
10996499Sbenno
11096938Sbennostruct powerpc_exception {
11196938Sbenno	u_int	vector;
11296938Sbenno	char	*name;
11396938Sbenno};
11496938Sbenno
11596938Sbennostatic struct powerpc_exception powerpc_exceptions[] = {
11696938Sbenno	{ 0x0100, "system reset" },
11796938Sbenno	{ 0x0200, "machine check" },
11896938Sbenno	{ 0x0300, "data storage interrupt" },
11996938Sbenno	{ 0x0400, "instruction storage interrupt" },
12096938Sbenno	{ 0x0500, "external interrupt" },
12196938Sbenno	{ 0x0600, "alignment" },
12296938Sbenno	{ 0x0700, "program" },
12396938Sbenno	{ 0x0800, "floating-point unavailable" },
12496938Sbenno	{ 0x0900, "decrementer" },
12596938Sbenno	{ 0x0c00, "system call" },
12696938Sbenno	{ 0x0d00, "trace" },
12796938Sbenno	{ 0x0e00, "floating-point assist" },
12896938Sbenno	{ 0x0f00, "performance monitoring" },
12996938Sbenno	{ 0x0f20, "altivec unavailable" },
13096938Sbenno	{ 0x1000, "instruction tlb miss" },
13196938Sbenno	{ 0x1100, "data load tlb miss" },
13296938Sbenno	{ 0x1200, "data store tlb miss" },
13396938Sbenno	{ 0x1300, "instruction breakpoint" },
13496938Sbenno	{ 0x1400, "system management" },
13596938Sbenno	{ 0x1600, "altivec assist" },
13696938Sbenno	{ 0x1700, "thermal management" },
13796938Sbenno	{ 0x2000, "run mode/trace" },
13896938Sbenno	{ 0x3000, NULL }
13996938Sbenno};
14096938Sbenno
14196938Sbennostatic const char *
14296938Sbennotrapname(u_int vector)
14396938Sbenno{
14496938Sbenno	struct	powerpc_exception *pe;
14596938Sbenno
14696938Sbenno	for (pe = powerpc_exceptions; pe->vector != 0x3000; pe++) {
14796938Sbenno		if (pe->vector == vector)
14896938Sbenno			return (pe->name);
14996938Sbenno	}
15096938Sbenno
15196938Sbenno	return ("unknown");
15296938Sbenno}
15396938Sbenno
15496255Sbennovoid
15596906Sbennotrap(struct trapframe *frame)
15686067Smp{
15796906Sbenno	struct thread	*td, *fputhread;
15896906Sbenno	struct proc	*p;
15996938Sbenno	int		sig, type, user;
16096938Sbenno	u_int		sticks, ucode;
16186067Smp
16296938Sbenno	atomic_add_int(&cnt.v_trap, 1);
16396938Sbenno
16496906Sbenno	td = PCPU_GET(curthread);
16596906Sbenno	p = td->td_proc;
16686067Smp
16796938Sbenno	type = ucode = frame->exc;
16896938Sbenno	sig = 0;
16996938Sbenno	user = frame->srr1 & PSL_PR;
17096938Sbenno	sticks = 0;
17186067Smp
17296938Sbenno	CTR3(KTR_TRAP, "trap: %s type=%s (%s)", p->p_comm,
17396938Sbenno	    trapname(type), user ? "user" : "kernel");
17486067Smp
17596938Sbenno	if (user) {
17696938Sbenno		sticks = td->td_kse->ke_sticks;
17796938Sbenno		td->td_frame = frame;
17896938Sbenno		if (td->td_ucred != p->p_ucred)
17996938Sbenno			cred_update_thread(td);
18086067Smp
18196938Sbenno		/* User Mode Traps */
18296938Sbenno		switch (type) {
18396938Sbenno		case EXC_RUNMODETRC:
18496938Sbenno		case EXC_TRC:
18596938Sbenno			frame->srr1 &= ~PSL_SE;
18696938Sbenno			sig = SIGTRAP;
18796938Sbenno			break;
18877957Sbenno
18996938Sbenno		case EXC_DSI:
19096938Sbenno		case EXC_ISI:
19196938Sbenno			sig = trap_pfault(frame, 1);
19296938Sbenno			break;
19396938Sbenno
19496938Sbenno		case EXC_SC:
19596938Sbenno			syscall(frame);
19696938Sbenno			break;
19796938Sbenno
19896938Sbenno		case EXC_FPU:
19996938Sbenno			if ((fputhread = PCPU_GET(fputhread)) != NULL) {
20096938Sbenno				KASSERT(fputhread != td,
20196938Sbenno				    ("floating-point already enabled"));
20296938Sbenno				save_fpu(fputhread);
20396255Sbenno			}
20496938Sbenno			PCPU_SET(fputhread, td);
20596938Sbenno			td->td_pcb->pcb_fpcpu = PCPU_GET(cpuid);
20696938Sbenno			enable_fpu(td);
20796938Sbenno			frame->srr1 |= PSL_FP;
20896938Sbenno			break;
20996938Sbenno
21096938Sbenno#ifdef	ALTIVEC
21196938Sbenno		case EXC_VEC:
21296938Sbenno			if ((vecthread = PCPU_GET(vecthread)) != NULL) {
21396938Sbenno				KASSERT(vecthread != td,
21496938Sbenno				    ("altivec already enabled"));
21596938Sbenno				save_vec(vecthread);
21696938Sbenno			}
21796938Sbenno			PCPU_SET(vecthread, td);
21896938Sbenno			td->td_pcb->pcb_veccpu = PCPU_GET(cpuid);
21996938Sbenno			enable_vec(td);
22096938Sbenno			frame->srr1 |= PSL_VEC;
22196938Sbenno			break;
22296938Sbenno#endif /* ALTIVEC */
22396938Sbenno
22496938Sbenno		case EXC_ALI:
22596938Sbenno			if (fix_unaligned(td, frame) != 0)
22696938Sbenno				sig = SIGBUS;
22777957Sbenno			else
22896938Sbenno				frame->srr0 += 4;
22996938Sbenno			break;
23096938Sbenno
23196938Sbenno		case EXC_PGM:
23296938Sbenno			/* XXX temporarily */
23396938Sbenno			/* XXX: Magic Number? */
23496938Sbenno			if (frame->srr1 & 0x0002000)
23596938Sbenno				sig = SIGTRAP;
23696938Sbenno 			else
23796938Sbenno				sig = SIGILL;
23896938Sbenno			break;
23996938Sbenno
24096938Sbenno		default:
24196938Sbenno			trap_fatal(frame);
24277957Sbenno		}
24396938Sbenno	} else {
24496938Sbenno		/* Kernel Mode Traps */
24596938Sbenno
24696938Sbenno		KASSERT(cold || td->td_ucred != NULL,
24796938Sbenno		    ("kernel trap doesn't have ucred"));
24896938Sbenno		switch (type) {
24996938Sbenno		case EXC_DSI:
25096938Sbenno			if (trap_pfault(frame, 0) == 0)
25196938Sbenno 				return;
25296938Sbenno			break;
25396938Sbenno		case EXC_MCHK:
25496938Sbenno			if (handle_onfault(frame))
25596938Sbenno 				return;
25696938Sbenno			break;
25796938Sbenno		default:
25896938Sbenno			trap_fatal(frame);
25996255Sbenno		}
26086067Smp	}
26196938Sbenno
26296938Sbenno	if (td != PCPU_GET(fputhread) ||
26396938Sbenno	    td->td_pcb->pcb_fpcpu != PCPU_GET(cpuid))
26496938Sbenno		frame->srr1 &= ~PSL_FP;
26596938Sbenno
26696938Sbenno#ifdef	ALTIVEC
26796938Sbenno	if (td != PCPU_GET(vecthread) ||
26896938Sbenno	    td->td_pcb->pcb_veccpu != PCPU_GET(cpuid))
26996938Sbenno		frame->srr1 &= ~PSL_VEC;
27096938Sbenno#endif /* ALTIVEC */
27196938Sbenno
27296938Sbenno	if (sig != 0) {
27396938Sbenno		if (p->p_sysent->sv_transtrap != NULL)
27496938Sbenno			sig = (p->p_sysent->sv_transtrap)(sig, type);
27596938Sbenno		trapsignal(p, sig, ucode);
27696938Sbenno	}
27796938Sbenno
27896938Sbenno	userret(td, frame, sticks);
27996938Sbenno	mtx_assert(&Giant, MA_NOTOWNED);
28096938Sbenno#ifdef	DIAGNOSTIC
28196938Sbenno	cred_free_thread(td);
28296938Sbenno#endif	/* DIAGNOSTIC */
28396938Sbenno}
28496938Sbenno
28596938Sbennostatic void
28696938Sbennotrap_fatal(struct trapframe *frame)
28796938Sbenno{
28896938Sbenno
28996938Sbenno	printtrap(frame->exc, frame, 1, (frame->srr1 & PSL_PR));
29096938Sbenno#ifdef DDB
29196938Sbenno	if ((debugger_on_panic || db_active) && kdb_trap(frame->exc, 0, frame))
29296938Sbenno		return;
29396938Sbenno#endif
29496938Sbenno	panic("%s trap", trapname(frame->exc));
29596938Sbenno}
29696938Sbenno
29796938Sbennostatic void
29896938Sbennoprinttrap(u_int vector, struct trapframe *frame, int isfatal, int user)
29996938Sbenno{
30096938Sbenno
30196938Sbenno	printf("\n");
30296938Sbenno	printf("%s %s trap:\n", isfatal ? "fatal" : "handled",
30396938Sbenno	    user ? "user" : "kernel");
30496938Sbenno	printf("\n");
30596938Sbenno	printf("   exception       = 0x%x (%s)\n", vector >> 8,
30696938Sbenno	    trapname(vector));
30796938Sbenno	switch (vector) {
30896938Sbenno	case EXC_DSI:
30996938Sbenno		printf("   virtual address = 0x%x\n", frame->dar);
31096255Sbenno		break;
31196255Sbenno	case EXC_ISI:
31296938Sbenno		printf("   virtual address = 0x%x\n", frame->srr0);
31396255Sbenno		break;
31496938Sbenno	}
31597347Sbenno	printf("   srr0            = 0x%x\n", frame->srr0);
31697347Sbenno	printf("   srr1            = 0x%x\n", frame->srr1);
31796938Sbenno	printf("   curthread       = %p\n", curthread);
31896938Sbenno	if (curthread != NULL)
31996938Sbenno		printf("          pid = %d, comm = %s\n",
32096938Sbenno		    curthread->td_proc->p_pid, curthread->td_proc->p_comm);
32196938Sbenno	printf("\n");
32296938Sbenno}
32386067Smp
32496938Sbenno/*
32596938Sbenno * Handles a fatal fault when we have onfault state to recover.  Returns
32696938Sbenno * non-zero if there was onfault recovery state available.
32796938Sbenno */
32896938Sbennostatic int
32996938Sbennohandle_onfault(struct trapframe *frame)
33096938Sbenno{
33196938Sbenno	struct		thread *td;
33296938Sbenno	faultbuf	*fb;
33386067Smp
33496938Sbenno	td = curthread;
33596938Sbenno	fb = td->td_pcb->pcb_onfault;
33696938Sbenno	if (fb != NULL) {
33796938Sbenno		frame->srr0 = (*fb)[0];
33896938Sbenno		frame->fixreg[1] = (*fb)[1];
33996938Sbenno		frame->fixreg[2] = (*fb)[2];
34096938Sbenno		frame->cr = (*fb)[3];
34196938Sbenno		bcopy(&(*fb)[4], &frame->fixreg[13],
34296938Sbenno		    19 * sizeof(register_t));
34396938Sbenno		return (1);
34496938Sbenno	}
34596938Sbenno	return (0);
34696938Sbenno}
34786067Smp
34896938Sbennovoid
34996938Sbennosyscall(struct trapframe *frame)
35096938Sbenno{
35196938Sbenno	caddr_t		params;
35296938Sbenno	struct		sysent *callp;
35396938Sbenno	struct		thread *td;
35496938Sbenno	struct		proc *p;
35596938Sbenno	int		error, n;
35696938Sbenno	size_t		narg;
35796938Sbenno	register_t	args[10];
35896938Sbenno	u_int		code;
35986067Smp
36096938Sbenno	td = PCPU_GET(curthread);
36196938Sbenno	p = td->td_proc;
36286067Smp
36396938Sbenno	atomic_add_int(&cnt.v_syscall, 1);
36496938Sbenno
36596938Sbenno	code = frame->fixreg[0];
36696938Sbenno	params = (caddr_t)(frame->fixreg + FIRSTARG);
36796938Sbenno	n = NARGREG;
36896938Sbenno
36996938Sbenno	if (p->p_sysent->sv_prepsyscall) {
37096938Sbenno		/*
37196938Sbenno		 * The prep code is MP aware.
37296938Sbenno		 */
37396938Sbenno		(*p->p_sysent->sv_prepsyscall)(frame, args, &code, &params);
37496938Sbenno	} else if (code == SYS_syscall) {
37596938Sbenno		/*
37696938Sbenno		 * code is first argument,
37796938Sbenno		 * followed by actual args.
37896938Sbenno		 */
37996938Sbenno		code = *params++;
38096938Sbenno		n -= 1;
38196938Sbenno	} else if (code == SYS___syscall) {
38296938Sbenno		/*
38396938Sbenno		 * Like syscall, but code is a quad,
38496938Sbenno		 * so as to maintain quad alignment
38596938Sbenno		 * for the rest of the args.
38696938Sbenno		 */
38796938Sbenno		params++;
38896938Sbenno		code = *params++;
38996938Sbenno		n -= 2;
39096938Sbenno	}
39196452Sbenno
39296938Sbenno 	if (p->p_sysent->sv_mask)
39396938Sbenno 		code &= p->p_sysent->sv_mask;
39486067Smp
39596938Sbenno 	if (code >= p->p_sysent->sv_size)
39696938Sbenno 		callp = &p->p_sysent->sv_table[0];
39796938Sbenno  	else
39896938Sbenno 		callp = &p->p_sysent->sv_table[code];
39986067Smp
40096938Sbenno	narg = callp->sy_narg & SYF_ARGMASK;
40196255Sbenno
40296938Sbenno	if (narg > n * sizeof(register_t)) {
40396938Sbenno		bcopy(params, args, n * sizeof(register_t));
40496938Sbenno		error = copyin(MOREARGS(frame->fixreg[1]), args + n,
40596938Sbenno			narg - n * sizeof(register_t));
40696938Sbenno		if (error) {
40777957Sbenno#ifdef	KTRACE
40896938Sbenno			/* Can't get all the arguments! */
40996938Sbenno			if (KTRPOINT(p, KTR_SYSCALL))
41096938Sbenno				ktrsyscall(p->p_tracep, code, narg, args);
41177957Sbenno#endif
41296938Sbenno			goto bad;
41396255Sbenno		}
41496938Sbenno		params = (caddr_t)args;
41596938Sbenno	}
41677957Sbenno
41796938Sbenno	/*
41896938Sbenno	 * Try to run the syscall without Giant if the syscall is MP safe.
41996938Sbenno	 */
42096938Sbenno	if ((callp->sy_narg & SYF_MPSAFE) == 0)
42196938Sbenno		mtx_lock(&Giant);
42277957Sbenno
42396938Sbenno#ifdef	KTRACE
42496938Sbenno	if (KTRPOINT(p, KTR_SYSCALL))
42596938Sbenno		ktrsyscall(p->p_tracep, code, narg, params);
42696255Sbenno#endif
42796938Sbenno	td->td_retval[0] = 0;
42896938Sbenno	td->td_retval[1] = frame->fixreg[FIRSTARG + 1];
42996255Sbenno
43096938Sbenno	STOPEVENT(p, S_SCE, narg);
43177957Sbenno
43296938Sbenno	error = (*callp->sy_call)(td, params);
43396938Sbenno	switch (error) {
43496938Sbenno	case 0:
43596938Sbenno		frame->fixreg[FIRSTARG] = td->td_retval[0];
43696938Sbenno		frame->fixreg[FIRSTARG + 1] = td->td_retval[1];
43796938Sbenno		/* XXX: Magic number */
43896938Sbenno		frame->cr &= ~0x10000000;
43996255Sbenno		break;
44096938Sbenno	case ERESTART:
44196938Sbenno		/*
44296938Sbenno		 * Set user's pc back to redo the system call.
44396938Sbenno		 */
44496938Sbenno		frame->srr0 -= 4;
44596255Sbenno		break;
44696938Sbenno	case EJUSTRETURN:
44796938Sbenno		/* nothing to do */
44896938Sbenno		break;
44996938Sbenno	default:
45096938Sbennobad:
45196938Sbenno		if (p->p_sysent->sv_errsize) {
45296938Sbenno			if (error >= p->p_sysent->sv_errsize)
45396938Sbenno				error = -1;	/* XXX */
45496938Sbenno			else
45596938Sbenno				error = p->p_sysent->sv_errtbl[error];
45696255Sbenno		}
45796938Sbenno		frame->fixreg[FIRSTARG] = error;
45896938Sbenno		/* XXX: Magic number: Carry Flag Equivalent? */
45996938Sbenno		frame->cr |= 0x10000000;
46096938Sbenno		break;
46177957Sbenno	}
46277957Sbenno
46396938Sbenno
46496938Sbenno#ifdef	KTRACE
46596938Sbenno	if (KTRPOINT(p, KTR_SYSRET))
46696938Sbenno		ktrsysret(p->p_tracep, code, error, td->td_retval[0]);
46796255Sbenno#endif
46886067Smp
46996938Sbenno	if ((callp->sy_narg & SYF_MPSAFE) == 0)
47096938Sbenno		mtx_unlock(&Giant);
47186067Smp
47296255Sbenno	/*
47396938Sbenno	 * Does the comment in the i386 code about errno apply here?
47496255Sbenno	 */
47596938Sbenno	STOPEVENT(p, S_SCX, code);
47686067Smp
47796938Sbenno#ifdef WITNESS
47896938Sbenno	if (witness_list(td)) {
47996938Sbenno		panic("system call %s returning with mutex(s) held\n",
48096938Sbenno		    syscallnames[code]);
48196938Sbenno	}
48296255Sbenno#endif
48396938Sbenno	mtx_assert(&sched_lock, MA_NOTOWNED);
48496938Sbenno	mtx_assert(&Giant, MA_NOTOWNED);
48577957Sbenno}
48677957Sbenno
48796938Sbennostatic int
48896938Sbennotrap_pfault(struct trapframe *frame, int user)
48977957Sbenno{
49096938Sbenno	vm_offset_t	eva, va;
49196938Sbenno	struct		thread *td;
49296938Sbenno	struct		proc *p;
49396938Sbenno	vm_map_t	map;
49496938Sbenno	vm_prot_t	ftype;
49596938Sbenno	int		rv;
49696938Sbenno	u_int		user_sr;
49777957Sbenno
49896938Sbenno	td = curthread;
49996906Sbenno	p = td->td_proc;
50096938Sbenno	if (frame->exc == EXC_ISI) {
50196938Sbenno		eva = frame->srr0;
50296938Sbenno		ftype = VM_PROT_READ | VM_PROT_EXECUTE;
50396938Sbenno	} else {
50496938Sbenno		eva = frame->dar;
50596938Sbenno		if (frame->dsisr & DSISR_STORE)
50696938Sbenno			ftype = VM_PROT_READ | VM_PROT_WRITE;
50796938Sbenno		else
50896938Sbenno			ftype = VM_PROT_READ;
50996938Sbenno	}
51096906Sbenno
51196938Sbenno	if (user) {
51296938Sbenno		map = &p->p_vmspace->vm_map;
51396938Sbenno	} else {
51496938Sbenno		if ((eva >> ADDR_SR_SHFT) == USER_SR) {
51596938Sbenno			if (p->p_vmspace == NULL)
51696938Sbenno				return (SIGSEGV);
51796938Sbenno
51896938Sbenno			__asm ("mfsr %0, %1"
51996938Sbenno			    : "=r"(user_sr)
52096938Sbenno			    : "K"(USER_SR));
52196938Sbenno			eva &= ADDR_PIDX | ADDR_POFF;
52296938Sbenno			eva |= user_sr << ADDR_SR_SHFT;
52396938Sbenno			map = &p->p_vmspace->vm_map;
52496938Sbenno		} else {
52596938Sbenno			map = kernel_map;
52696938Sbenno		}
52796938Sbenno	}
52896938Sbenno	va = trunc_page(eva);
52977957Sbenno
53096938Sbenno	mtx_lock(&Giant);
53196938Sbenno	if (map != kernel_map) {
53296938Sbenno		/*
53396938Sbenno		 * Keep swapout from messing with us during this
53496938Sbenno		 *	critical time.
53596938Sbenno		 */
53696255Sbenno		PROC_LOCK(p);
53796938Sbenno		++p->p_lock;
53896255Sbenno		PROC_UNLOCK(p);
53996938Sbenno
54096938Sbenno		/* Fault in the user page: */
54196938Sbenno		rv = vm_fault(map, va, ftype,
54296938Sbenno		      (ftype & VM_PROT_WRITE) ? VM_FAULT_DIRTY
54396938Sbenno					      : VM_FAULT_NORMAL);
54496938Sbenno
54596938Sbenno		PROC_LOCK(p);
54696938Sbenno		--p->p_lock;
54796938Sbenno		PROC_UNLOCK(p);
54896938Sbenno	} else {
54996938Sbenno		/*
55096938Sbenno		 * Don't have to worry about process locking or stacks in the
55196938Sbenno		 * kernel.
55296938Sbenno		 */
55396938Sbenno		rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL);
55496255Sbenno	}
55596938Sbenno	mtx_unlock(&Giant);
55696938Sbenno
55796938Sbenno	if (rv == KERN_SUCCESS)
55896938Sbenno		return (0);
55996938Sbenno
56096938Sbenno	if (!user && handle_onfault(frame))
56196938Sbenno		return (0);
56296938Sbenno
56396938Sbenno	return (SIGSEGV);
56477957Sbenno}
56577957Sbenno
56696255Sbennostatic __inline void
56796906Sbennosetusr(u_int content)
56896255Sbenno{
56996255Sbenno	__asm __volatile ("isync; mtsr %0,%1; isync"
57096255Sbenno		      :: "n"(USER_SR), "r"(content));
57196255Sbenno}
57296255Sbenno
57377957Sbenno/*
57477957Sbenno * kcopy(const void *src, void *dst, size_t len);
57577957Sbenno *
57677957Sbenno * Copy len bytes from src to dst, aborting if we encounter a fatal
57777957Sbenno * page fault.
57877957Sbenno *
57977957Sbenno * kcopy() _must_ save and restore the old fault handler since it is
58077957Sbenno * called by uiomove(), which may be in the path of servicing a non-fatal
58177957Sbenno * page fault.
58277957Sbenno */
58377957Sbennoint
58477957Sbennokcopy(const void *src, void *dst, size_t len)
58577957Sbenno{
58696906Sbenno	struct thread	*td;
58796906Sbenno	faultbuf	env, *oldfault;
58896906Sbenno	int		rv;
58977957Sbenno
59096255Sbenno	td = PCPU_GET(curthread);
59196255Sbenno	oldfault = td->td_pcb->pcb_onfault;
59296255Sbenno	if ((rv = setfault(env)) != 0) {
59396255Sbenno		td->td_pcb->pcb_onfault = oldfault;
59496255Sbenno		return rv;
59577957Sbenno	}
59677957Sbenno
59796255Sbenno	memcpy(dst, src, len);
59877957Sbenno
59996255Sbenno	td->td_pcb->pcb_onfault = oldfault;
60096906Sbenno	return (0);
60177957Sbenno}
60277957Sbenno
60377957Sbennoint
60496906Sbennobadaddr(void *addr, size_t size)
60577957Sbenno{
60696906Sbenno	return (badaddr_read(addr, size, NULL));
60777957Sbenno}
60877957Sbenno
60977957Sbennoint
61096906Sbennobadaddr_read(void *addr, size_t size, int *rptr)
61177957Sbenno{
61296906Sbenno	struct thread	*td;
61396906Sbenno	faultbuf	env;
61496906Sbenno	int		x;
61577957Sbenno
61677957Sbenno	/* Get rid of any stale machine checks that have been waiting.  */
61777957Sbenno	__asm __volatile ("sync; isync");
61877957Sbenno
61996255Sbenno	td = PCPU_GET(curthread);
62096255Sbenno
62177957Sbenno	if (setfault(env)) {
62296255Sbenno		td->td_pcb->pcb_onfault = 0;
62377957Sbenno		__asm __volatile ("sync");
62477957Sbenno		return 1;
62577957Sbenno	}
62677957Sbenno
62777957Sbenno	__asm __volatile ("sync");
62877957Sbenno
62977957Sbenno	switch (size) {
63077957Sbenno	case 1:
63177957Sbenno		x = *(volatile int8_t *)addr;
63277957Sbenno		break;
63377957Sbenno	case 2:
63477957Sbenno		x = *(volatile int16_t *)addr;
63577957Sbenno		break;
63677957Sbenno	case 4:
63777957Sbenno		x = *(volatile int32_t *)addr;
63877957Sbenno		break;
63977957Sbenno	default:
64077957Sbenno		panic("badaddr: invalid size (%d)", size);
64177957Sbenno	}
64277957Sbenno
64377957Sbenno	/* Make sure we took the machine check, if we caused one. */
64477957Sbenno	__asm __volatile ("sync; isync");
64577957Sbenno
64696255Sbenno	td->td_pcb->pcb_onfault = 0;
64777957Sbenno	__asm __volatile ("sync");	/* To be sure. */
64877957Sbenno
64977957Sbenno	/* Use the value to avoid reorder. */
65077957Sbenno	if (rptr)
65177957Sbenno		*rptr = x;
65277957Sbenno
65396906Sbenno	return (0);
65477957Sbenno}
65577957Sbenno
65677957Sbenno/*
65777957Sbenno * For now, this only deals with the particular unaligned access case
65877957Sbenno * that gcc tends to generate.  Eventually it should handle all of the
65977957Sbenno * possibilities that can happen on a 32-bit PowerPC in big-endian mode.
66077957Sbenno */
66177957Sbenno
66277957Sbennostatic int
66396906Sbennofix_unaligned(struct thread *td, struct trapframe *frame)
66477957Sbenno{
66596906Sbenno	struct thread	*fputhread;
66696906Sbenno	int		indicator, reg;
66796906Sbenno	double		*fpr;
66877957Sbenno
66996906Sbenno	indicator = EXC_ALI_OPCODE_INDICATOR(frame->dsisr);
67096906Sbenno
67177957Sbenno	switch (indicator) {
67277957Sbenno	case EXC_ALI_LFD:
67377957Sbenno	case EXC_ALI_STFD:
67496906Sbenno		reg = EXC_ALI_RST(frame->dsisr);
67596906Sbenno		fpr = &td->td_pcb->pcb_fpu.fpr[reg];
67696906Sbenno		fputhread = PCPU_GET(fputhread);
67777957Sbenno
67896906Sbenno		/* Juggle the FPU to ensure that we've initialized
67996906Sbenno		 * the FPRs, and that their current state is in
68096906Sbenno		 * the PCB.
68196906Sbenno		 */
68296906Sbenno		if (fputhread != td) {
68396906Sbenno			if (fputhread)
68496906Sbenno				save_fpu(fputhread);
68596906Sbenno			enable_fpu(td);
68696906Sbenno		}
68796906Sbenno		save_fpu(td);
68877957Sbenno
68996906Sbenno		if (indicator == EXC_ALI_LFD) {
69096906Sbenno			if (copyin((void *)frame->dar, fpr,
69196906Sbenno			    sizeof(double)) != 0)
69296906Sbenno				return -1;
69396906Sbenno			enable_fpu(td);
69496906Sbenno		} else {
69596906Sbenno			if (copyout(fpr, (void *)frame->dar,
69696906Sbenno			    sizeof(double)) != 0)
69796906Sbenno				return -1;
69877957Sbenno		}
69996906Sbenno		return 0;
70077957Sbenno		break;
70177957Sbenno	}
70277957Sbenno
70377957Sbenno	return -1;
70477957Sbenno}
705