trap.c revision 96499
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 96499 2002-05-13 07:44:48Z 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
97extern char	*syscallnames[];
98
99void
100trap(frame)
101	struct trapframe *frame;
102{
103	struct thread *td = PCPU_GET(curthread);
104	struct thread *fputhread;
105	struct proc *p = td->td_proc;
106	int type = frame->exc;
107	int ftype, rv;
108
109#if 0
110	curcpu()->ci_ev_traps.ev_count++;
111#endif
112
113	if (frame->srr1 & PSL_PR)
114		type |= EXC_USER;
115
116#ifdef DIAGNOSTIC
117	if (curpcb->pcb_pmreal != curpm)
118		panic("trap: curpm (%p) != curpcb->pcb_pmreal (%p)",
119		    curpm, curpcb->pcb_pmreal);
120#endif
121
122#if 0
123	uvmexp.traps++;
124#endif
125
126	switch (type) {
127	case EXC_RUNMODETRC|EXC_USER:
128		/* FALLTHROUGH */
129	case EXC_TRC|EXC_USER:
130		PROC_LOCK(p);
131		frame->srr1 &= ~PSL_SE;
132		trapsignal(p, SIGTRAP, EXC_TRC);
133		PROC_UNLOCK(p);
134		break;
135	case EXC_DSI: {
136		faultbuf *fb;
137		/*
138		 * Only query UVM if no interrupts are active (this applies
139		 * "on-fault" as well.
140		 */
141#if 0
142		curcpu()->ci_ev_kdsi.ev_count++;
143#endif
144		if (intr_depth < 0) {
145			struct vm_map *map;
146			vm_offset_t va;
147
148#if 0
149			KERNEL_LOCK(LK_CANRECURSE|LK_EXCLUSIVE);
150#endif
151			map = kernel_map;
152			va = frame->dar;
153			if ((va >> ADDR_SR_SHFT) == USER_SR) {
154				register_t user_sr;
155
156				__asm ("mfsr %0, %1"
157				     : "=r"(user_sr) : "K"(USER_SR));
158				va &= ADDR_PIDX | ADDR_POFF;
159				va |= user_sr << ADDR_SR_SHFT;
160				/* KERNEL_PROC_LOCK(p); XXX */
161				map = &p->p_vmspace->vm_map;
162			}
163			if (frame->dsisr & DSISR_STORE)
164				ftype = VM_PROT_WRITE;
165			else
166				ftype = VM_PROT_READ;
167			rv = vm_fault(map, trunc_page(va), ftype,
168			    VM_FAULT_NORMAL);
169#if 0
170			KERNEL_UNLOCK();
171#endif
172			if (rv == 0)
173				return;
174			if (rv == EACCES)
175				rv = EFAULT;
176		} else {
177			rv = EFAULT;
178		}
179		if ((fb = td->td_pcb->pcb_onfault) != NULL) {
180			frame->srr0 = (*fb)[0];
181			frame->fixreg[1] = (*fb)[1];
182			frame->fixreg[2] = (*fb)[2];
183			frame->fixreg[3] = rv;
184			frame->cr = (*fb)[3];
185			memcpy(&frame->fixreg[13], &(*fb)[4],
186				      19 * sizeof(register_t));
187			return;
188		}
189		printf("trap: kernel %s DSI @ %#x by %#x (DSISR %#x, err=%d)\n",
190		    (frame->dsisr & DSISR_STORE) ? "write" : "read",
191		    frame->dar, frame->srr0, frame->dsisr, rv);
192		goto brain_damage2;
193	}
194	case EXC_DSI|EXC_USER:
195		PROC_LOCK(p);
196		++p->p_lock;
197		PROC_UNLOCK(p);
198#if 0
199		curcpu()->ci_ev_udsi.ev_count++;
200#endif
201		if (frame->dsisr & DSISR_STORE)
202			ftype = VM_PROT_WRITE;
203		else
204			ftype = VM_PROT_READ;
205		rv = vm_fault(&p->p_vmspace->vm_map, trunc_page(frame->dar),
206		    ftype, VM_FAULT_NORMAL);
207#if 0
208		curcpu()->ci_ev_udsi_fatal.ev_count++;
209#endif
210		printf("trap: pid %d (%s): user %s DSI @ %#x "
211		    "by %#x (DSISR %#x, err=%d)\n",
212		    p->p_pid, p->p_comm,
213		    (frame->dsisr & DSISR_STORE) ? "write" : "read",
214		    frame->dar, frame->srr0, frame->dsisr, rv);
215		if (rv == ENOMEM) {
216			printf("UVM: pid %d (%s), uid %d killed: "
217			       "out of swap\n",
218			       p->p_pid, p->p_comm,
219			       td->td_ucred ?  td->td_ucred->cr_uid : -1);
220			trapsignal(p, SIGKILL, EXC_DSI);
221		} else {
222			trapsignal(p, SIGSEGV, EXC_DSI);
223		}
224		PROC_LOCK(p);
225		--p->p_lock;
226		PROC_UNLOCK(p);
227		break;
228	case EXC_ISI:
229		printf("trap: kernel ISI by %#x (SRR1 %#x)\n",
230		    frame->srr0, frame->srr1);
231		goto brain_damage2;
232	case EXC_ISI|EXC_USER:
233		PROC_LOCK(p);
234		++p->p_lock;
235		PROC_UNLOCK(p);
236#if 0
237		curcpu()->ci_ev_isi.ev_count++;
238#endif
239		ftype = VM_PROT_READ | VM_PROT_EXECUTE;
240		rv = vm_fault(&p->p_vmspace->vm_map, trunc_page(frame->srr0),
241		    ftype, VM_FAULT_NORMAL);
242		if (rv == 0) {
243			PROC_LOCK(p);
244			--p->p_lock;
245			PROC_UNLOCK(p);
246			break;
247		}
248#if 0
249		curcpu()->ci_ev_isi_fatal.ev_count++;
250#endif
251		printf("trap: pid %d (%s): user ISI trap @ %#x "
252		    "(SSR1=%#x)\n",
253		    p->p_pid, p->p_comm, frame->srr0, frame->srr1);
254		trapsignal(p, SIGSEGV, EXC_ISI);
255		PROC_LOCK(p);
256		--p->p_lock;
257		PROC_UNLOCK(p);
258		break;
259	case EXC_SC|EXC_USER:
260#if 0
261		curcpu()->ci_ev_scalls.ev_count++;
262#endif
263		{
264			const struct sysent *callp;
265			size_t argsize;
266			register_t code, error;
267			register_t *params, rval[2];
268			int n;
269			register_t args[10];
270
271#if 0
272			uvmexp.syscalls++;
273#endif
274
275			code = frame->fixreg[0];
276			callp = &p->p_sysent->sv_table[0];
277			params = frame->fixreg + FIRSTARG;
278			n = NARGREG;
279
280			switch (code) {
281			case SYS_syscall:
282				/*
283				 * code is first argument,
284				 * followed by actual args.
285				 */
286				code = *params++;
287				n -= 1;
288				break;
289			case SYS___syscall:
290				params++;
291				code = *params++;
292				n -= 2;
293				break;
294			default:
295				break;
296			}
297
298			if (p->p_sysent->sv_mask)
299				code &= p->p_sysent->sv_mask;
300			callp += code;
301			argsize = callp->sy_narg & SYF_ARGMASK;
302
303			if (argsize > n * sizeof(register_t)) {
304				memcpy(args, params, n * sizeof(register_t));
305				error = copyin(MOREARGS(frame->fixreg[1]),
306					       args + n,
307					       argsize - n * sizeof(register_t));
308				if (error)
309					goto syscall_bad;
310				params = args;
311			}
312
313			/*
314			 * Try to run the syscall without Giant if the syscall
315			 * is MP safe.
316			 */
317			if ((callp->sy_narg & SYF_MPSAFE) == 0)
318				mtx_lock(&Giant);
319
320#ifdef	KTRACE
321			if (KTRPOINT(p, KTR_SYSCALL))
322				ktrsyscall(p, code, argsize, params);
323#endif
324
325			rval[0] = 0;
326			rval[1] = 0;
327
328			error = (*callp->sy_call)(td, params);
329			switch (error) {
330			case 0:
331				frame->fixreg[FIRSTARG] = rval[0];
332				frame->fixreg[FIRSTARG + 1] = rval[1];
333				frame->cr &= ~0x10000000;
334				break;
335			case ERESTART:
336				/*
337				 * Set user's pc back to redo the system call.
338				 */
339				frame->srr0 -= 4;
340				break;
341			case EJUSTRETURN:
342				/* nothing to do */
343				break;
344			default:
345syscall_bad:
346#if 0
347				if (p->p_emul->e_errno)
348					error = p->p_emul->e_errno[error];
349#endif
350				frame->fixreg[FIRSTARG] = error;
351				frame->cr |= 0x10000000;
352				break;
353			}
354
355			/*
356			 * Release Giant if we had to get it.  Don't use
357			 * mtx_owned(), we want to catch broken syscalls.
358			 */
359			if ((callp->sy_narg & SYF_MPSAFE) == 0)
360				mtx_unlock(&Giant);
361#ifdef	KTRACE
362			if (KTRPOINT(p, KTR_SYSRET))
363				ktrsysret(p, code, error, rval[0]);
364#endif
365		}
366		break;
367
368	case EXC_FPU|EXC_USER:
369		if ((fputhread = PCPU_GET(fputhread)) != NULL) {
370			KASSERT(fputhread != td,
371			    ("floating-point already enabled"));
372			save_fpu(fputhread);
373		}
374		PCPU_SET(fputhread, td);
375		td->td_pcb->pcb_fpcpu = PCPU_GET(cpuid);
376		enable_fpu(td);
377		frame->srr1 |= PSL_FP;
378		break;
379
380#ifdef ALTIVEC
381	case EXC_VEC|EXC_USER:
382#if 0
383		curcpu()->ci_ev_vec.ev_count++;
384#endif
385		if (vecproc) {
386#if 0
387			curcpu()->ci_ev_vecsw.ev_count++;
388#endif
389			save_vec(vecproc);
390		}
391		vecproc = p;
392		enable_vec(p);
393		break;
394#endif
395
396	case EXC_AST|EXC_USER:
397		astpending = 0;		/* we are about to do it */
398		PROC_LOCK(p);
399#if 0
400		uvmexp.softs++;
401		if (p->p_flag & P_OWEUPC) {
402			p->p_flag &= ~P_OWEUPC;
403			ADDUPROF(p);
404		}
405#endif
406		/* Check whether we are being preempted. */
407		if (want_resched)
408			mi_switch();
409		PROC_UNLOCK(p);
410		break;
411
412	case EXC_ALI|EXC_USER:
413		PROC_LOCK(p);
414#if 0
415		curcpu()->ci_ev_ali.ev_count++;
416#endif
417		if (fix_unaligned(p, frame) != 0) {
418#if 0
419			curcpu()->ci_ev_ali_fatal.ev_count++;
420#endif
421			printf("trap: pid %d (%s): user ALI trap @ %#x "
422			    "(SSR1=%#x)\n",
423			    p->p_pid, p->p_comm, frame->srr0,
424			    frame->srr1);
425			trapsignal(p, SIGBUS, EXC_ALI);
426		} else
427			frame->srr0 += 4;
428		PROC_UNLOCK(p);
429		break;
430
431	case EXC_PGM|EXC_USER:
432/* XXX temporarily */
433		PROC_LOCK(p);
434#if 0
435		curcpu()->ci_ev_pgm.ev_count++;
436#endif
437		printf("trap: pid %d (%s): user PGM trap @ %#x "
438		    "(SSR1=%#x)\n",
439		    p->p_pid, p->p_comm, frame->srr0, frame->srr1);
440		if (frame->srr1 & 0x00020000)	/* Bit 14 is set if trap */
441			trapsignal(p, SIGTRAP, EXC_PGM);
442		else
443			trapsignal(p, SIGILL, EXC_PGM);
444		PROC_UNLOCK(p);
445		break;
446
447	case EXC_MCHK: {
448		faultbuf *fb;
449
450		if ((fb = td->td_pcb->pcb_onfault) != NULL) {
451			frame->srr0 = (*fb)[0];
452			frame->fixreg[1] = (*fb)[1];
453			frame->fixreg[2] = (*fb)[2];
454			frame->fixreg[3] = EFAULT;
455			frame->cr = (*fb)[3];
456			memcpy(&frame->fixreg[13], &(*fb)[4],
457			      19 * sizeof(register_t));
458			return;
459		}
460		goto brain_damage;
461	}
462
463	default:
464brain_damage:
465		printf("trap type %x at %x\n", type, frame->srr0);
466brain_damage2:
467#ifdef DDBX
468		if (kdb_trap(type, frame))
469			return;
470#endif
471#ifdef TRAP_PANICWAIT
472		printf("Press a key to panic.\n");
473		cnpollc(1);
474		cngetc();
475		cnpollc(0);
476#endif
477		panic("trap");
478	}
479
480#if 0
481	/* Take pending signals. */
482	{
483		int sig;
484
485		while ((sig = CURSIG(p)) != 0)
486			postsig(sig);
487	}
488#endif
489
490	/*
491	 * If someone stole the fp or vector unit while we were away,
492	 * disable it
493	 */
494	if (td != PCPU_GET(fputhread) ||
495	    td->td_pcb->pcb_fpcpu != PCPU_GET(cpuid))
496		frame->srr1 &= ~PSL_FP;
497#ifdef ALTIVEC
498	if (p != vecproc)
499		frame->srr1 &= ~PSL_VEC;
500#endif
501
502#if 0
503	curcpu()->ci_schedstate.spc_curpriority = p->p_priority = p->p_usrpri;
504	p->p_priority = p->p_usrpri;
505#endif
506}
507
508void child_return(void *);
509
510void
511child_return(void *arg)
512{
513	struct thread *td = arg;
514	struct proc *p = td->td_proc;
515	struct trapframe *tf = trapframe(td);
516
517	PROC_UNLOCK(p);
518
519	tf->fixreg[FIRSTARG] = 0;
520	tf->fixreg[FIRSTARG + 1] = 1;
521	tf->cr &= ~0x10000000;
522#if 0
523	tf->srr1 &= ~(PSL_FP|PSL_VEC);	/* Disable FP & AltiVec, as we can't
524					   be them. */
525	td->td_pcb->pcb_fpcpu = NULL;
526#endif
527#ifdef	KTRACE
528	if (KTRPOINT(p, KTR_SYSRET)) {
529		PROC_LOCK(p);
530		ktrsysret(p, SYS_fork, 0, 0);
531		PROC_UNLOCK(p);
532	}
533#endif
534	/* Profiling?							XXX */
535#if 0
536	curcpu()->ci_schedstate.spc_curpriority = p->p_priority;
537#endif
538}
539
540static __inline void
541setusr(content)
542	int content;
543{
544	__asm __volatile ("isync; mtsr %0,%1; isync"
545		      :: "n"(USER_SR), "r"(content));
546}
547
548int kcopy(const void *, void *, size_t);
549
550/*
551 * kcopy(const void *src, void *dst, size_t len);
552 *
553 * Copy len bytes from src to dst, aborting if we encounter a fatal
554 * page fault.
555 *
556 * kcopy() _must_ save and restore the old fault handler since it is
557 * called by uiomove(), which may be in the path of servicing a non-fatal
558 * page fault.
559 */
560int
561kcopy(const void *src, void *dst, size_t len)
562{
563	struct thread *td;
564	faultbuf env, *oldfault;
565	int rv;
566
567	td = PCPU_GET(curthread);
568	oldfault = td->td_pcb->pcb_onfault;
569	if ((rv = setfault(env)) != 0) {
570		td->td_pcb->pcb_onfault = oldfault;
571		return rv;
572	}
573
574	memcpy(dst, src, len);
575
576	td->td_pcb->pcb_onfault = oldfault;
577	return 0;
578}
579
580int
581badaddr(addr, size)
582	void *addr;
583	size_t size;
584{
585	return badaddr_read(addr, size, NULL);
586}
587
588int
589badaddr_read(addr, size, rptr)
590	void *addr;
591	size_t size;
592	int *rptr;
593{
594	struct thread *td;
595	faultbuf env;
596	int x;
597
598	/* Get rid of any stale machine checks that have been waiting.  */
599	__asm __volatile ("sync; isync");
600
601	td = PCPU_GET(curthread);
602
603	if (setfault(env)) {
604		td->td_pcb->pcb_onfault = 0;
605		__asm __volatile ("sync");
606		return 1;
607	}
608
609	__asm __volatile ("sync");
610
611	switch (size) {
612	case 1:
613		x = *(volatile int8_t *)addr;
614		break;
615	case 2:
616		x = *(volatile int16_t *)addr;
617		break;
618	case 4:
619		x = *(volatile int32_t *)addr;
620		break;
621	default:
622		panic("badaddr: invalid size (%d)", size);
623	}
624
625	/* Make sure we took the machine check, if we caused one. */
626	__asm __volatile ("sync; isync");
627
628	td->td_pcb->pcb_onfault = 0;
629	__asm __volatile ("sync");	/* To be sure. */
630
631	/* Use the value to avoid reorder. */
632	if (rptr)
633		*rptr = x;
634
635	return 0;
636}
637
638/*
639 * For now, this only deals with the particular unaligned access case
640 * that gcc tends to generate.  Eventually it should handle all of the
641 * possibilities that can happen on a 32-bit PowerPC in big-endian mode.
642 */
643
644static int
645fix_unaligned(p, frame)
646	struct proc *p;
647	struct trapframe *frame;
648{
649	int indicator = EXC_ALI_OPCODE_INDICATOR(frame->dsisr);
650
651	switch (indicator) {
652	case EXC_ALI_LFD:
653	case EXC_ALI_STFD:
654#if 0
655		{
656			int reg = EXC_ALI_RST(frame->dsisr);
657			double *fpr = &p->p_addr->u_pcb.pcb_fpu.fpr[reg];
658
659			/* Juggle the FPU to ensure that we've initialized
660			 * the FPRs, and that their current state is in
661			 * the PCB.
662			 */
663			if (fpuproc != p) {
664				if (fpuproc)
665					save_fpu(fpuproc);
666				enable_fpu(p);
667			}
668			save_fpu(p);
669
670			if (indicator == EXC_ALI_LFD) {
671				if (copyin((void *)frame->dar, fpr,
672				    sizeof(double)) != 0)
673					return -1;
674				enable_fpu(p);
675			} else {
676				if (copyout(fpr, (void *)frame->dar,
677				    sizeof(double)) != 0)
678					return -1;
679			}
680			return 0;
681		}
682#endif
683		break;
684	}
685
686	return -1;
687}
688