trap.c revision 77957
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.26 2000/05/27 00:40:40 sommerfeld Exp $
32 */
33
34#ifndef lint
35static const char rcsid[] =
36  "$FreeBSD: head/sys/powerpc/aim/trap.c 77957 2001-06-10 02:39:37Z 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/proc.h>
44#include <sys/reboot.h>
45#include <sys/syscall.h>
46#include <sys/systm.h>
47#include <sys/uio.h>
48#include <sys/user.h>
49#include <sys/ktrace.h>
50
51#include <vm/vm.h>
52#include <vm/vm_kern.h>
53#include <vm/pmap.h>
54
55#include <machine/cpu.h>
56#include <machine/frame.h>
57#include <machine/pcb.h>
58#include <machine/psl.h>
59#include <machine/trap.h>
60
61/* These definitions should probably be somewhere else				XXX */
62#define	FIRSTARG	3		/* first argument is in reg 3 */
63#define	NARGREG		8		/* 8 args are in registers */
64#define	MOREARGS(sp)	((caddr_t)((int)(sp) + 8)) /* more args go here */
65
66volatile int	astpending;
67volatile int	want_resched;
68
69#if 0 /* XXX: not used yet */
70static int fix_unaligned __P((struct proc *p, struct trapframe *frame));
71#endif
72
73void
74trap(struct trapframe *frame)
75{
76#if 0 /* XXX: This code hasn't been reworked yet. */
77	struct proc *p;
78	int type;
79	u_quad_t sticks;
80
81	p = curproc;
82	type = frame->exc;
83
84	if (frame->srr1 & PSL_PR) {
85		type |= EXC_USER;
86		sticks = p->p_sticks;
87	}
88
89	switch (type) {
90	case EXC_TRC|EXC_USER:
91		frame->srr1 &= ~PSL_SE;
92		trapsignal(p, SIGTRAP, EXC_TRC);
93		break;
94	case EXC_DSI:
95		{
96			vm_map_t map;
97			vaddr_t va;
98			int ftype;
99			faultbuf *fb;
100
101			map = kernel_map;
102			va = frame->dar;
103			if ((va >> ADDR_SR_SHFT) == USER_SR) {
104				sr_t user_sr;
105
106				__asm ("mfsr %0, %1"
107				     : "=r"(user_sr) : "K"(USER_SR));
108				va &= ADDR_PIDX | ADDR_POFF;
109				va |= user_sr << ADDR_SR_SHFT;
110				map = &p->p_vmspace->vm_map;
111			}
112			if (frame->dsisr & DSISR_STORE)
113				ftype = VM_PROT_READ | VM_PROT_WRITE;
114			else
115				ftype = VM_PROT_READ;
116			if (uvm_fault(map, trunc_page(va), 0, ftype)
117			    == KERN_SUCCESS)
118				return;
119			if (fb = p->p_addr->u_pcb.pcb_onfault) {
120				frame->srr0 = (*fb)[0];
121				frame->fixreg[1] = (*fb)[1];
122				frame->fixreg[2] = (*fb)[2];
123				frame->cr = (*fb)[3];
124				bcopy(&(*fb)[4], &frame->fixreg[13],
125				      19 * sizeof(register_t));
126				return;
127			}
128			map = kernel_map;
129		}
130		goto brain_damage;
131	case EXC_DSI|EXC_USER:
132		{
133			int ftype, rv;
134
135			if (frame->dsisr & DSISR_STORE)
136				ftype = VM_PROT_READ | VM_PROT_WRITE;
137			else
138				ftype = VM_PROT_READ;
139			if ((rv = uvm_fault(&p->p_vmspace->vm_map,
140					    trunc_page(frame->dar), 0, ftype))
141			    == KERN_SUCCESS)
142				break;
143			if (rv == KERN_RESOURCE_SHORTAGE) {
144				printf("UVM: pid %d (%s), uid %d killed: "
145				       "out of swap\n",
146				       p->p_pid, p->p_comm,
147				       p->p_cred && p->p_ucred ?
148				       p->p_ucred->cr_uid : -1);
149				trapsignal(p, SIGKILL, EXC_DSI);
150			} else {
151				trapsignal(p, SIGSEGV, EXC_DSI);
152			}
153		}
154		break;
155	case EXC_ISI|EXC_USER:
156		{
157			int ftype;
158
159			ftype = VM_PROT_READ | VM_PROT_EXECUTE;
160			if (uvm_fault(&p->p_vmspace->vm_map,
161				     trunc_page(frame->srr0), 0, ftype)
162			    == KERN_SUCCESS)
163				break;
164		}
165		trapsignal(p, SIGSEGV, EXC_ISI);
166		break;
167	case EXC_SC|EXC_USER:
168		{
169			struct sysent *callp;
170			size_t argsize;
171			register_t code, error;
172			register_t *params, rval[2];
173			int nsys, n;
174			register_t args[10];
175
176			uvmexp.syscalls++;
177
178			nsys = p->p_emul->e_nsysent;
179			callp = p->p_emul->e_sysent;
180
181			code = frame->fixreg[0];
182			params = frame->fixreg + FIRSTARG;
183
184			switch (code) {
185			case SYS_syscall:
186				/*
187				 * code is first argument,
188				 * followed by actual args.
189				 */
190				code = *params++;
191				break;
192			case SYS___syscall:
193				/*
194				 * Like syscall, but code is a quad,
195				 * so as to maintain quad alignment
196				 * for the rest of the args.
197				 */
198				if (callp != sysent)
199					break;
200				params++;
201				code = *params++;
202				break;
203			default:
204				break;
205			}
206			if (code < 0 || code >= nsys)
207				callp += p->p_emul->e_nosys;
208			else
209				callp += code;
210			argsize = callp->sy_argsize;
211			n = NARGREG - (params - (frame->fixreg + FIRSTARG));
212			if (argsize > n * sizeof(register_t)) {
213				bcopy(params, args, n * sizeof(register_t));
214				if (error = copyin(MOREARGS(frame->fixreg[1]),
215						   args + n,
216						   argsize - n * sizeof(register_t))) {
217#ifdef	KTRACE
218					/* Can't get all the arguments! */
219					if (KTRPOINT(p, KTR_SYSCALL))
220						ktrsyscall(p, code, argsize,
221						    args);
222#endif
223					goto syscall_bad;
224				}
225				params = args;
226			}
227#ifdef	KTRACE
228			if (KTRPOINT(p, KTR_SYSCALL))
229				ktrsyscall(p, code, argsize, params);
230#endif
231			rval[0] = 0;
232			rval[1] = frame->fixreg[FIRSTARG + 1];
233
234			switch (error = (*callp->sy_call)(p, params, rval)) {
235			case 0:
236				frame->fixreg[FIRSTARG] = rval[0];
237				frame->fixreg[FIRSTARG + 1] = rval[1];
238				frame->cr &= ~0x10000000;
239				break;
240			case ERESTART:
241				/*
242				 * Set user's pc back to redo the system call.
243				 */
244				frame->srr0 -= 4;
245				break;
246			case EJUSTRETURN:
247				/* nothing to do */
248				break;
249			default:
250syscall_bad:
251				if (p->p_emul->e_errno)
252					error = p->p_emul->e_errno[error];
253				frame->fixreg[FIRSTARG] = error;
254				frame->cr |= 0x10000000;
255				break;
256			}
257#ifdef	KTRACE
258			if (KTRPOINT(p, KTR_SYSRET))
259				ktrsysret(p, code, error, rval[0]);
260#endif
261		}
262		break;
263
264	case EXC_FPU|EXC_USER:
265		if (fpuproc)
266			save_fpu(fpuproc);
267		fpuproc = p;
268		enable_fpu(p);
269		break;
270
271	case EXC_AST|EXC_USER:
272		/* This is just here that we trap */
273		break;
274
275	case EXC_ALI|EXC_USER:
276		if (fix_unaligned(p, frame) != 0)
277			trapsignal(p, SIGBUS, EXC_ALI);
278		else
279			frame->srr0 += 4;
280		break;
281
282	case EXC_PGM|EXC_USER:
283/* XXX temporarily */
284		if (frame->srr1 & 0x0002000)
285			trapsignal(p, SIGTRAP, EXC_PGM);
286		else
287			trapsignal(p, SIGILL, EXC_PGM);
288		break;
289
290	case EXC_MCHK:
291		{
292			faultbuf *fb;
293
294			if (fb = p->p_addr->u_pcb.pcb_onfault) {
295				frame->srr0 = (*fb)[0];
296				frame->fixreg[1] = (*fb)[1];
297				frame->fixreg[2] = (*fb)[2];
298				frame->cr = (*fb)[3];
299				bcopy(&(*fb)[4], &frame->fixreg[13],
300				      19 * sizeof(register_t));
301				return;
302			}
303		}
304		goto brain_damage;
305
306	default:
307brain_damage:
308		printf("trap type %x at %x\n", type, frame->srr0);
309#ifdef DDB
310		Debugger();			 /* XXX temporarily */
311#endif
312#ifdef TRAP_PANICWAIT
313		printf("Press a key to panic.\n");
314		cngetc();
315#endif
316		panic("trap");
317	}
318
319	astpending = 0;		/* we are about to do it */
320
321	uvmexp.softs++;
322
323	if (p->p_flag & P_OWEUPC) {
324		p->p_flag &= ~P_OWEUPC;
325		ADDUPROF(p);
326	}
327
328	/* take pending signals */
329	{
330		int sig;
331
332		while (sig = CURSIG(p))
333			postsig(sig);
334	}
335
336	p->p_priority = p->p_usrpri;
337	if (want_resched) {
338		int sig;
339		/*
340		 * We are being preempted.
341		 */
342		preempt(NULL);
343		while (sig = CURSIG(p))
344			postsig(sig);
345	}
346
347	/*
348	 * If profiling, charge recent system time to the trapped pc.
349	 */
350	if (p->p_flag & P_PROFIL) {
351		extern int psratio;
352
353		addupc_task(p, frame->srr0,
354			    (int)(p->p_sticks - sticks) * psratio);
355	}
356	/*
357	 * If someone stole the fpu while we were away, disable it
358	 */
359	if (p != fpuproc)
360		frame->srr1 &= ~PSL_FP;
361	curcpu()->ci_schedstate.spc_curpriority = p->p_priority;
362#endif
363}
364
365#if 0 /* XXX: child_return not used */
366void
367child_return(void *arg)
368{
369	struct proc *p;
370	struct trapframe *tf;
371
372	p = arg;
373	tf = trapframe(p);
374
375	tf->fixreg[FIRSTARG] = 0;
376	tf->fixreg[FIRSTARG + 1] = 1;
377	tf->cr &= ~0x10000000;
378	tf->srr1 &= ~PSL_FP;	/* Disable FPU, as we can't be fpuproc */
379#ifdef	KTRACE
380	if (KTRPOINT(p, KTR_SYSRET))
381		ktrsysret(p, SYS_fork, 0, 0);
382#endif
383	/* Profiling?							XXX */
384	curcpu()->ci_schedstate.spc_curpriority = p->p_priority;
385}
386#endif
387
388static __inline void
389setusr(int content)
390{
391
392	__asm __volatile ("isync; mtsr %0,%1; isync"
393		          :: "n"(USER_SR), "r"(content));
394}
395
396int
397copyin(udaddr, kaddr, len)
398	const void *udaddr;
399	void *kaddr;
400	size_t len;
401{
402	const char *up;
403	char *kp;
404	char *p;
405	size_t l;
406	faultbuf env;
407
408	up = udaddr;
409	kp = kaddr;
410
411#if 0
412	if (setfault(env)) {
413		curpcb->pcb_onfault = 0;
414		return EFAULT;
415	}
416#endif
417	while (len > 0) {
418		p = (char *)USER_ADDR + ((u_int)up & ~SEGMENT_MASK);
419		l = ((char *)USER_ADDR + SEGMENT_LENGTH) - p;
420		if (l > len)
421			l = len;
422		setusr(curpcb->pcb_pm->pm_sr[(u_int)up >> ADDR_SR_SHFT]);
423		bcopy(p, kp, l);
424		up += l;
425		kp += l;
426		len -= l;
427	}
428	curpcb->pcb_onfault = 0;
429	return 0;
430}
431
432int
433copyout(kaddr, udaddr, len)
434	const void *kaddr;
435	void *udaddr;
436	size_t len;
437{
438	const char *kp;
439	char *up;
440	char *p;
441	size_t l;
442	faultbuf env;
443
444	kp = kaddr;
445	up = udaddr;
446
447#if 0
448	if (setfault(env)) {
449		curpcb->pcb_onfault = 0;
450		return EFAULT;
451	}
452#endif
453	while (len > 0) {
454		p = (char *)USER_ADDR + ((u_int)up & ~SEGMENT_MASK);
455		l = ((char *)USER_ADDR + SEGMENT_LENGTH) - p;
456		if (l > len)
457			l = len;
458		setusr(curpcb->pcb_pm->pm_sr[(u_int)up >> ADDR_SR_SHFT]);
459		bcopy(kp, p, l);
460		up += l;
461		kp += l;
462		len -= l;
463	}
464	curpcb->pcb_onfault = 0;
465	return 0;
466}
467
468#if 0 /* XXX: not used yet */
469/*
470 * kcopy(const void *src, void *dst, size_t len);
471 *
472 * Copy len bytes from src to dst, aborting if we encounter a fatal
473 * page fault.
474 *
475 * kcopy() _must_ save and restore the old fault handler since it is
476 * called by uiomove(), which may be in the path of servicing a non-fatal
477 * page fault.
478 */
479int
480kcopy(const void *src, void *dst, size_t len)
481{
482	faultbuf env, *oldfault;
483
484	oldfault = curpcb->pcb_onfault;
485	if (setfault(env)) {
486		curpcb->pcb_onfault = oldfault;
487		return EFAULT;
488	}
489
490	bcopy(src, dst, len);
491
492	curpcb->pcb_onfault = oldfault;
493	return 0;
494}
495
496int
497badaddr(void *addr, size_t size)
498{
499
500	return badaddr_read(addr, size, NULL);
501}
502
503int
504badaddr_read(void *addr, size_t size, int *rptr)
505{
506	faultbuf env;
507	int x;
508
509	/* Get rid of any stale machine checks that have been waiting.  */
510	__asm __volatile ("sync; isync");
511
512	if (setfault(env)) {
513		curpcb->pcb_onfault = 0;
514		__asm __volatile ("sync");
515		return 1;
516	}
517
518	__asm __volatile ("sync");
519
520	switch (size) {
521	case 1:
522		x = *(volatile int8_t *)addr;
523		break;
524	case 2:
525		x = *(volatile int16_t *)addr;
526		break;
527	case 4:
528		x = *(volatile int32_t *)addr;
529		break;
530	default:
531		panic("badaddr: invalid size (%d)", size);
532	}
533
534	/* Make sure we took the machine check, if we caused one. */
535	__asm __volatile ("sync; isync");
536
537	curpcb->pcb_onfault = 0;
538	__asm __volatile ("sync");	/* To be sure. */
539
540	/* Use the value to avoid reorder. */
541	if (rptr)
542		*rptr = x;
543
544	return 0;
545}
546#endif
547
548/*
549 * For now, this only deals with the particular unaligned access case
550 * that gcc tends to generate.  Eventually it should handle all of the
551 * possibilities that can happen on a 32-bit PowerPC in big-endian mode.
552 */
553
554#if 0 /* XXX: Not used yet */
555static int
556fix_unaligned(p, frame)
557	struct proc *p;
558	struct trapframe *frame;
559{
560	int indicator;
561
562	indicator = EXC_ALI_OPCODE_INDICATOR(frame->dsisr);
563
564	switch (indicator) {
565	case EXC_ALI_LFD:
566	case EXC_ALI_STFD:
567		{
568			int reg = EXC_ALI_RST(frame->dsisr);
569			double *fpr = &p->p_addr->u_pcb.pcb_fpu.fpr[reg];
570
571			/* Juggle the FPU to ensure that we've initialized
572			 * the FPRs, and that their current state is in
573			 * the PCB.
574			 */
575			if (fpuproc != p) {
576				if (fpuproc)
577					save_fpu(fpuproc);
578				enable_fpu(p);
579			}
580			save_fpu(p);
581
582			if (indicator == EXC_ALI_LFD) {
583				if (copyin((void *)frame->dar, fpr,
584				    sizeof(double)) != 0)
585					return -1;
586				enable_fpu(p);
587			} else {
588				if (copyout(fpr, (void *)frame->dar,
589				    sizeof(double)) != 0)
590					return -1;
591			}
592			return 0;
593		}
594		break;
595	}
596
597	return -1;
598}
599#endif
600
601void
602userret(struct proc *p, struct trapframe *frame, u_quad_t oticks)
603{
604
605	/* XXX: Coming soon */
606	return;
607}
608