trap.c revision 96452
1/*
2 * Copyright (C) 1995, 1996 Wolfgang Solfrank.
3 * Copyright (C) 1995, 1996 TooLs GmbH.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 *    must display the following acknowledgement:
16 *	This product includes software developed by TooLs GmbH.
17 * 4. The name of TooLs GmbH may not be used to endorse or promote products
18 *    derived from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 *
31 * $NetBSD: trap.c,v 1.58 2002/03/04 04:07:35 dbj Exp $
32 */
33
34#ifndef lint
35static const char rcsid[] =
36  "$FreeBSD: head/sys/powerpc/aim/trap.c 96452 2002-05-12 13:43:21Z benno $";
37#endif /* not lint */
38
39#include "opt_ddb.h"
40#include "opt_ktrace.h"
41
42#include <sys/param.h>
43#include <sys/lock.h>
44#include <sys/mutex.h>
45#include <sys/proc.h>
46#include <sys/reboot.h>
47#include <sys/syscall.h>
48#include <sys/systm.h>
49#include <sys/sysent.h>
50#include <sys/user.h>
51#ifdef KTRACE
52#include <sys/uio.h>
53#include <sys/ktrace.h>
54#endif
55
56#include <vm/vm.h>
57#include <vm/pmap.h>
58#include <vm/vm_extern.h>
59#include <vm/vm_param.h>
60#include <vm/vm_kern.h>
61#include <vm/vm_map.h>
62#include <vm/vm_page.h>
63
64#include <machine/cpu.h>
65#include <machine/db_machdep.h>
66#include <machine/fpu.h>
67#include <machine/frame.h>
68#include <machine/pcb.h>
69#include <machine/pmap.h>
70#include <machine/psl.h>
71#include <machine/trap.h>
72#include <machine/spr.h>
73#include <machine/sr.h>
74
75/* These definitions should probably be somewhere else			XXX */
76#define	FIRSTARG	3		/* first argument is in reg 3 */
77#define	NARGREG		8		/* 8 args are in registers */
78#define	MOREARGS(sp)	((caddr_t)((int)(sp) + 8)) /* more args go here */
79
80#ifndef MULTIPROCESSOR
81volatile int astpending;
82volatile int want_resched;
83extern int intr_depth;
84#endif
85
86void *syscall = NULL;	/* XXX dummy symbol for emul_netbsd */
87
88static int fix_unaligned(struct proc *p, struct trapframe *frame);
89static __inline void setusr(int);
90
91void trap(struct trapframe *);	/* Called from locore / trap_subr */
92int setfault(faultbuf);	/* defined in locore.S */
93/* Why are these not defined in a header? */
94int badaddr(void *, size_t);
95int badaddr_read(void *, size_t, int *);
96
97void
98trap(frame)
99	struct trapframe *frame;
100{
101	struct thread *td = PCPU_GET(curthread);
102	struct proc *p = td->td_proc;
103	int type = frame->exc;
104	int ftype, rv;
105
106#if 0
107	curcpu()->ci_ev_traps.ev_count++;
108#endif
109
110	if (frame->srr1 & PSL_PR)
111		type |= EXC_USER;
112
113#ifdef DIAGNOSTIC
114	if (curpcb->pcb_pmreal != curpm)
115		panic("trap: curpm (%p) != curpcb->pcb_pmreal (%p)",
116		    curpm, curpcb->pcb_pmreal);
117#endif
118
119#if 0
120	uvmexp.traps++;
121#endif
122
123	switch (type) {
124	case EXC_RUNMODETRC|EXC_USER:
125		/* FALLTHROUGH */
126	case EXC_TRC|EXC_USER:
127		PROC_LOCK(p);
128		frame->srr1 &= ~PSL_SE;
129		trapsignal(p, SIGTRAP, EXC_TRC);
130		PROC_UNLOCK(p);
131		break;
132	case EXC_DSI: {
133		faultbuf *fb;
134		/*
135		 * Only query UVM if no interrupts are active (this applies
136		 * "on-fault" as well.
137		 */
138#if 0
139		curcpu()->ci_ev_kdsi.ev_count++;
140#endif
141		if (intr_depth < 0) {
142			struct vm_map *map;
143			vm_offset_t va;
144
145#if 0
146			KERNEL_LOCK(LK_CANRECURSE|LK_EXCLUSIVE);
147#endif
148			map = kernel_map;
149			va = frame->dar;
150			if ((va >> ADDR_SR_SHFT) == USER_SR) {
151				register_t user_sr;
152
153				__asm ("mfsr %0, %1"
154				     : "=r"(user_sr) : "K"(USER_SR));
155				va &= ADDR_PIDX | ADDR_POFF;
156				va |= user_sr << ADDR_SR_SHFT;
157				/* KERNEL_PROC_LOCK(p); XXX */
158				map = &p->p_vmspace->vm_map;
159			}
160			if (frame->dsisr & DSISR_STORE)
161				ftype = VM_PROT_WRITE;
162			else
163				ftype = VM_PROT_READ;
164			rv = vm_fault(map, trunc_page(va), ftype,
165			    VM_FAULT_NORMAL);
166#if 0
167			KERNEL_UNLOCK();
168#endif
169			if (rv == 0)
170				return;
171			if (rv == EACCES)
172				rv = EFAULT;
173		} else {
174			rv = EFAULT;
175		}
176		if ((fb = td->td_pcb->pcb_onfault) != NULL) {
177			frame->srr0 = (*fb)[0];
178			frame->fixreg[1] = (*fb)[1];
179			frame->fixreg[2] = (*fb)[2];
180			frame->fixreg[3] = rv;
181			frame->cr = (*fb)[3];
182			memcpy(&frame->fixreg[13], &(*fb)[4],
183				      19 * sizeof(register_t));
184			return;
185		}
186		printf("trap: kernel %s DSI @ %#x by %#x (DSISR %#x, err=%d)\n",
187		    (frame->dsisr & DSISR_STORE) ? "write" : "read",
188		    frame->dar, frame->srr0, frame->dsisr, rv);
189		goto brain_damage2;
190	}
191	case EXC_DSI|EXC_USER:
192		PROC_LOCK(p);
193		++p->p_lock;
194		PROC_UNLOCK(p);
195#if 0
196		curcpu()->ci_ev_udsi.ev_count++;
197#endif
198		if (frame->dsisr & DSISR_STORE)
199			ftype = VM_PROT_WRITE;
200		else
201			ftype = VM_PROT_READ;
202		rv = vm_fault(&p->p_vmspace->vm_map, trunc_page(frame->dar),
203		    ftype, VM_FAULT_NORMAL);
204#if 0
205		curcpu()->ci_ev_udsi_fatal.ev_count++;
206#endif
207		printf("trap: pid %d (%s): user %s DSI @ %#x "
208		    "by %#x (DSISR %#x, err=%d)\n",
209		    p->p_pid, p->p_comm,
210		    (frame->dsisr & DSISR_STORE) ? "write" : "read",
211		    frame->dar, frame->srr0, frame->dsisr, rv);
212		if (rv == ENOMEM) {
213			printf("UVM: pid %d (%s), uid %d killed: "
214			       "out of swap\n",
215			       p->p_pid, p->p_comm,
216			       td->td_ucred ?  td->td_ucred->cr_uid : -1);
217			trapsignal(p, SIGKILL, EXC_DSI);
218		} else {
219			trapsignal(p, SIGSEGV, EXC_DSI);
220		}
221		PROC_LOCK(p);
222		--p->p_lock;
223		PROC_UNLOCK(p);
224		break;
225	case EXC_ISI:
226		printf("trap: kernel ISI by %#x (SRR1 %#x)\n",
227		    frame->srr0, frame->srr1);
228		goto brain_damage2;
229	case EXC_ISI|EXC_USER:
230		PROC_LOCK(p);
231		++p->p_lock;
232		PROC_UNLOCK(p);
233#if 0
234		curcpu()->ci_ev_isi.ev_count++;
235#endif
236		ftype = VM_PROT_READ | VM_PROT_EXECUTE;
237		rv = vm_fault(&p->p_vmspace->vm_map, trunc_page(frame->srr0),
238		    ftype, VM_FAULT_NORMAL);
239		if (rv == 0) {
240			PROC_LOCK(p);
241			--p->p_lock;
242			PROC_UNLOCK(p);
243			break;
244		}
245#if 0
246		curcpu()->ci_ev_isi_fatal.ev_count++;
247#endif
248		printf("trap: pid %d (%s): user ISI trap @ %#x "
249		    "(SSR1=%#x)\n",
250		    p->p_pid, p->p_comm, frame->srr0, frame->srr1);
251		trapsignal(p, SIGSEGV, EXC_ISI);
252		PROC_LOCK(p);
253		--p->p_lock;
254		PROC_UNLOCK(p);
255		break;
256	case EXC_SC|EXC_USER:
257#if 0
258		curcpu()->ci_ev_scalls.ev_count++;
259#endif
260		{
261			const struct sysent *callp;
262			size_t argsize;
263			register_t code, error;
264			register_t *params, rval[2];
265			int n;
266			register_t args[10];
267
268#if 0
269			uvmexp.syscalls++;
270#endif
271
272			code = frame->fixreg[0];
273			callp = &p->p_sysent->sv_table[0];
274			params = frame->fixreg + FIRSTARG;
275			n = NARGREG;
276
277			switch (code) {
278			case SYS_syscall:
279				/*
280				 * code is first argument,
281				 * followed by actual args.
282				 */
283				code = *params++;
284				n -= 1;
285				break;
286			case SYS___syscall:
287				params++;
288				code = *params++;
289				n -= 2;
290				break;
291			default:
292				break;
293			}
294
295			if (p->p_sysent->sv_mask)
296				code &= p->p_sysent->sv_mask;
297			callp += code;
298			argsize = callp->sy_narg & SYF_ARGMASK;
299
300			if (argsize > n * sizeof(register_t)) {
301				memcpy(args, params, n * sizeof(register_t));
302				error = copyin(MOREARGS(frame->fixreg[1]),
303					       args + n,
304					       argsize - n * sizeof(register_t));
305				if (error)
306					goto syscall_bad;
307				params = args;
308			}
309
310			/*
311			 * Try to run the syscall without Giant if the syscall
312			 * is MP safe.
313			 */
314			if ((callp->sy_narg & SYF_MPSAFE) == 0)
315				mtx_lock(&Giant);
316
317#ifdef	KTRACE
318			if (KTRPOINT(p, KTR_SYSCALL))
319				ktrsyscall(p, code, argsize, params);
320#endif
321
322			rval[0] = 0;
323			rval[1] = 0;
324
325			error = (*callp->sy_call)(td, params);
326			switch (error) {
327			case 0:
328				frame->fixreg[FIRSTARG] = rval[0];
329				frame->fixreg[FIRSTARG + 1] = rval[1];
330				frame->cr &= ~0x10000000;
331				break;
332			case ERESTART:
333				/*
334				 * Set user's pc back to redo the system call.
335				 */
336				frame->srr0 -= 4;
337				break;
338			case EJUSTRETURN:
339				/* nothing to do */
340				break;
341			default:
342syscall_bad:
343#if 0
344				if (p->p_emul->e_errno)
345					error = p->p_emul->e_errno[error];
346#endif
347				frame->fixreg[FIRSTARG] = error;
348				frame->cr |= 0x10000000;
349				break;
350			}
351
352			/*
353			 * Release Giant if we had to get it.  Don't use
354			 * mtx_owned(), we want to catch broken syscalls.
355			 */
356			if ((callp->sy_narg & SYF_MPSAFE) == 0)
357				mtx_unlock(&Giant);
358#ifdef	KTRACE
359			if (KTRPOINT(p, KTR_SYSRET))
360				ktrsysret(p, code, error, rval[0]);
361#endif
362		}
363		break;
364
365	case EXC_FPU|EXC_USER:
366#if 0
367		curcpu()->ci_ev_fpu.ev_count++;
368#endif
369#if 0
370		if (fpuproc) {
371			curcpu()->ci_ev_fpusw.ev_count++;
372			save_fpu(fpuproc);
373		}
374#endif
375#if defined(MULTIPROCESSOR)
376		if (p->p_addr->u_pcb.pcb_fpcpu)
377			save_fpu_proc(p);
378#endif
379#if 0
380		fpuproc = p;
381		p->p_addr->u_pcb.pcb_fpcpu = curcpu();
382		enable_fpu(p);
383#endif
384		break;
385
386#ifdef ALTIVEC
387	case EXC_VEC|EXC_USER:
388#if 0
389		curcpu()->ci_ev_vec.ev_count++;
390#endif
391		if (vecproc) {
392#if 0
393			curcpu()->ci_ev_vecsw.ev_count++;
394#endif
395			save_vec(vecproc);
396		}
397		vecproc = p;
398		enable_vec(p);
399		break;
400#endif
401
402	case EXC_AST|EXC_USER:
403		astpending = 0;		/* we are about to do it */
404		PROC_LOCK(p);
405#if 0
406		uvmexp.softs++;
407		if (p->p_flag & P_OWEUPC) {
408			p->p_flag &= ~P_OWEUPC;
409			ADDUPROF(p);
410		}
411#endif
412		/* Check whether we are being preempted. */
413		if (want_resched)
414			mi_switch();
415		PROC_UNLOCK(p);
416		break;
417
418	case EXC_ALI|EXC_USER:
419		PROC_LOCK(p);
420#if 0
421		curcpu()->ci_ev_ali.ev_count++;
422#endif
423		if (fix_unaligned(p, frame) != 0) {
424#if 0
425			curcpu()->ci_ev_ali_fatal.ev_count++;
426#endif
427			printf("trap: pid %d (%s): user ALI trap @ %#x "
428			    "(SSR1=%#x)\n",
429			    p->p_pid, p->p_comm, frame->srr0,
430			    frame->srr1);
431			trapsignal(p, SIGBUS, EXC_ALI);
432		} else
433			frame->srr0 += 4;
434		PROC_UNLOCK(p);
435		break;
436
437	case EXC_PGM|EXC_USER:
438/* XXX temporarily */
439		PROC_LOCK(p);
440#if 0
441		curcpu()->ci_ev_pgm.ev_count++;
442#endif
443		printf("trap: pid %d (%s): user PGM trap @ %#x "
444		    "(SSR1=%#x)\n",
445		    p->p_pid, p->p_comm, frame->srr0, frame->srr1);
446		if (frame->srr1 & 0x00020000)	/* Bit 14 is set if trap */
447			trapsignal(p, SIGTRAP, EXC_PGM);
448		else
449			trapsignal(p, SIGILL, EXC_PGM);
450		PROC_UNLOCK(p);
451		break;
452
453	case EXC_MCHK: {
454		faultbuf *fb;
455
456		if ((fb = td->td_pcb->pcb_onfault) != NULL) {
457			frame->srr0 = (*fb)[0];
458			frame->fixreg[1] = (*fb)[1];
459			frame->fixreg[2] = (*fb)[2];
460			frame->fixreg[3] = EFAULT;
461			frame->cr = (*fb)[3];
462			memcpy(&frame->fixreg[13], &(*fb)[4],
463			      19 * sizeof(register_t));
464			return;
465		}
466		goto brain_damage;
467	}
468
469	default:
470brain_damage:
471		printf("trap type %x at %x\n", type, frame->srr0);
472brain_damage2:
473#ifdef DDBX
474		if (kdb_trap(type, frame))
475			return;
476#endif
477#ifdef TRAP_PANICWAIT
478		printf("Press a key to panic.\n");
479		cnpollc(1);
480		cngetc();
481		cnpollc(0);
482#endif
483		panic("trap");
484	}
485
486	/* Take pending signals. */
487	{
488		int sig;
489
490		while ((sig = CURSIG(p)) != 0)
491			postsig(sig);
492	}
493
494	/*
495	 * If someone stole the fp or vector unit while we were away,
496	 * disable it
497	 */
498#if 0
499	if (p != fpuproc || p->p_addr->u_pcb.pcb_fpcpu != curcpu())
500		frame->srr1 &= ~PSL_FP;
501#endif
502#ifdef ALTIVEC
503	if (p != vecproc)
504		frame->srr1 &= ~PSL_VEC;
505#endif
506
507#if 0
508	curcpu()->ci_schedstate.spc_curpriority = p->p_priority = p->p_usrpri;
509	p->p_priority = p->p_usrpri;
510#endif
511}
512
513void child_return(void *);
514
515void
516child_return(void *arg)
517{
518	struct thread *td = arg;
519	struct proc *p = td->td_proc;
520	struct trapframe *tf = trapframe(td);
521
522	PROC_UNLOCK(p);
523
524	tf->fixreg[FIRSTARG] = 0;
525	tf->fixreg[FIRSTARG + 1] = 1;
526	tf->cr &= ~0x10000000;
527#if 0
528	tf->srr1 &= ~(PSL_FP|PSL_VEC);	/* Disable FP & AltiVec, as we can't
529					   be them. */
530	td->td_pcb->pcb_fpcpu = NULL;
531#endif
532#ifdef	KTRACE
533	if (KTRPOINT(p, KTR_SYSRET)) {
534		PROC_LOCK(p);
535		ktrsysret(p, SYS_fork, 0, 0);
536		PROC_UNLOCK(p);
537	}
538#endif
539	/* Profiling?							XXX */
540#if 0
541	curcpu()->ci_schedstate.spc_curpriority = p->p_priority;
542#endif
543}
544
545static __inline void
546setusr(content)
547	int content;
548{
549	__asm __volatile ("isync; mtsr %0,%1; isync"
550		      :: "n"(USER_SR), "r"(content));
551}
552
553int kcopy(const void *, void *, size_t);
554
555/*
556 * kcopy(const void *src, void *dst, size_t len);
557 *
558 * Copy len bytes from src to dst, aborting if we encounter a fatal
559 * page fault.
560 *
561 * kcopy() _must_ save and restore the old fault handler since it is
562 * called by uiomove(), which may be in the path of servicing a non-fatal
563 * page fault.
564 */
565int
566kcopy(const void *src, void *dst, size_t len)
567{
568	struct thread *td;
569	faultbuf env, *oldfault;
570	int rv;
571
572	td = PCPU_GET(curthread);
573	oldfault = td->td_pcb->pcb_onfault;
574	if ((rv = setfault(env)) != 0) {
575		td->td_pcb->pcb_onfault = oldfault;
576		return rv;
577	}
578
579	memcpy(dst, src, len);
580
581	td->td_pcb->pcb_onfault = oldfault;
582	return 0;
583}
584
585int
586badaddr(addr, size)
587	void *addr;
588	size_t size;
589{
590	return badaddr_read(addr, size, NULL);
591}
592
593int
594badaddr_read(addr, size, rptr)
595	void *addr;
596	size_t size;
597	int *rptr;
598{
599	struct thread *td;
600	faultbuf env;
601	int x;
602
603	/* Get rid of any stale machine checks that have been waiting.  */
604	__asm __volatile ("sync; isync");
605
606	td = PCPU_GET(curthread);
607
608	if (setfault(env)) {
609		td->td_pcb->pcb_onfault = 0;
610		__asm __volatile ("sync");
611		return 1;
612	}
613
614	__asm __volatile ("sync");
615
616	switch (size) {
617	case 1:
618		x = *(volatile int8_t *)addr;
619		break;
620	case 2:
621		x = *(volatile int16_t *)addr;
622		break;
623	case 4:
624		x = *(volatile int32_t *)addr;
625		break;
626	default:
627		panic("badaddr: invalid size (%d)", size);
628	}
629
630	/* Make sure we took the machine check, if we caused one. */
631	__asm __volatile ("sync; isync");
632
633	td->td_pcb->pcb_onfault = 0;
634	__asm __volatile ("sync");	/* To be sure. */
635
636	/* Use the value to avoid reorder. */
637	if (rptr)
638		*rptr = x;
639
640	return 0;
641}
642
643/*
644 * For now, this only deals with the particular unaligned access case
645 * that gcc tends to generate.  Eventually it should handle all of the
646 * possibilities that can happen on a 32-bit PowerPC in big-endian mode.
647 */
648
649static int
650fix_unaligned(p, frame)
651	struct proc *p;
652	struct trapframe *frame;
653{
654	int indicator = EXC_ALI_OPCODE_INDICATOR(frame->dsisr);
655
656	switch (indicator) {
657	case EXC_ALI_LFD:
658	case EXC_ALI_STFD:
659#if 0
660		{
661			int reg = EXC_ALI_RST(frame->dsisr);
662			double *fpr = &p->p_addr->u_pcb.pcb_fpu.fpr[reg];
663
664			/* Juggle the FPU to ensure that we've initialized
665			 * the FPRs, and that their current state is in
666			 * the PCB.
667			 */
668			if (fpuproc != p) {
669				if (fpuproc)
670					save_fpu(fpuproc);
671				enable_fpu(p);
672			}
673			save_fpu(p);
674
675			if (indicator == EXC_ALI_LFD) {
676				if (copyin((void *)frame->dar, fpr,
677				    sizeof(double)) != 0)
678					return -1;
679				enable_fpu(p);
680			} else {
681				if (copyout(fpr, (void *)frame->dar,
682				    sizeof(double)) != 0)
683					return -1;
684			}
685			return 0;
686		}
687#endif
688		break;
689	}
690
691	return -1;
692}
693