trap.c revision 1.20
1/*	$OpenBSD: trap.c,v 1.20 2000/06/08 22:25:19 niklas Exp $	*/
2
3/*
4 * Copyright (c) 1998-2000 Michael Shalayeff
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *	This product includes software developed by Michael Shalayeff.
18 * 4. The name of the author may not be used to endorse or promote products
19 *    derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33#undef INTRDEBUG
34#undef TRAPDEBUG
35
36#include <sys/param.h>
37#include <sys/systm.h>
38#include <sys/kernel.h>
39#include <sys/syscall.h>
40#include <sys/ktrace.h>
41#include <sys/proc.h>
42#include <sys/signalvar.h>
43#include <sys/user.h>
44#include <sys/acct.h>
45#include <sys/signal.h>
46#include <sys/device.h>
47
48#include <net/netisr.h>
49
50#include <vm/vm.h>
51#include <vm/vm_kern.h>
52#include <uvm/uvm.h>
53
54#include <machine/iomod.h>
55#include <machine/cpufunc.h>
56#include <machine/reg.h>
57#include <machine/autoconf.h>
58
59#ifdef DDB
60#include <machine/db_machdep.h>
61#endif
62
63#if defined(INTRDEBUG) || defined(TRAPDEBUG)
64#include <ddb/db_output.h>
65#endif
66
67
68const char *trap_type[] = {
69	"invalid",
70	"HPMC",
71	"power failure",
72	"recovery counter",
73	"external interrupt",
74	"LPMC",
75	"ITLB miss fault",
76	"instruction protection",
77	"Illegal instruction",
78	"break instruction",
79	"privileged operation",
80	"privileged register",
81	"overflow",
82	"conditional",
83	"assist exception",
84	"DTLB miss",
85	"ITLB non-access miss",
86	"DTLB non-access miss",
87	"data protection/rights/alignment",
88	"data break",
89	"TLB dirty",
90	"page reference",
91	"assist emulation",
92	"higher-priv transfer",
93	"lower-priv transfer",
94	"taken branch",
95	"data access rights",
96	"data protection",
97	"unaligned data ref",
98};
99int trap_types = sizeof(trap_type)/sizeof(trap_type[0]);
100
101u_int32_t sir;
102int want_resched;
103
104void pmap_hptdump __P((void));
105void cpu_intr __P((struct trapframe *frame));
106void syscall __P((struct trapframe *frame, int *args));
107
108static __inline void
109userret (struct proc *p, register_t pc, u_quad_t oticks)
110{
111	int sig;
112
113	/* take pending signals */
114	while ((sig = CURSIG(p)) != 0)
115		postsig(sig);
116
117	p->p_priority = p->p_usrpri;
118	if (want_resched) {
119		register int s;
120		/*
121		 * Since we are curproc, a clock interrupt could
122		 * change our priority without changing run queues
123		 * (the running process is not kept on a run queue).
124		 * If this happened after we setrunqueue ourselves but
125		 * before we switch()'ed, we might not be on the queue
126		 * indicated by our priority.
127		 */
128		s = splstatclock();
129		setrunqueue(p);
130		p->p_stats->p_ru.ru_nivcsw++;
131		mi_switch();
132		splx(s);
133		while ((sig = CURSIG(p)) != 0)
134			postsig(sig);
135	}
136
137	/*
138	 * If profiling, charge recent system time to the trapped pc.
139	 */
140	if (p->p_flag & P_PROFIL) {
141		extern int psratio;
142
143		addupc_task(p, pc, (int)(p->p_sticks - oticks) * psratio);
144	}
145
146	curpriority = p->p_priority;
147}
148
149void
150trap(type, frame)
151	int type;
152	struct trapframe *frame;
153{
154	struct proc *p = curproc;
155	struct pcb *pcbp;
156	register vaddr_t va;
157	register vm_map_t map;
158	struct vmspace *vm;
159	register vm_prot_t vftype;
160	register pa_space_t space;
161	u_int opcode;
162	int ret;
163	union sigval sv;
164	int s, si;
165	const char *tts;
166extern db_regs_t ddb_regs;
167ddb_regs = *frame;
168	opcode = frame->tf_iir;
169	if (type == T_ITLBMISS || type == T_ITLBMISSNA) {
170		va = frame->tf_iioq_head;
171		space = frame->tf_iisq_head;
172		vftype = VM_PROT_READ;	/* XXX VM_PROT_EXECUTE ??? */
173	} else {
174		va = frame->tf_ior;
175		space = frame->tf_isr;
176		vftype = inst_store(opcode) ? VM_PROT_WRITE : VM_PROT_READ;
177	}
178
179	if (frame->tf_flags & TFF_LAST)
180		p->p_md.md_regs = frame;
181
182#ifdef TRAPDEBUG
183	if ((type & ~T_USER) > trap_types)
184		tts = "reserved";
185	else
186		tts = trap_type[type & ~T_USER];
187
188	if (type != T_INTERRUPT && (type & ~T_USER) != T_IBREAK)
189		db_printf("trap: %d, %s for %x:%x at %x:%x, fl=%x, fp=%p\n",
190		    type, tts, space, va, frame->tf_iisq_head,
191		    frame->tf_iioq_head, frame->tf_flags, frame);
192	else if ((type & ~T_USER) == T_IBREAK)
193		db_printf("trap: break instruction %x:%x at %x:%x, fp=%p\n",
194		    break5(opcode), break13(opcode),
195		    frame->tf_iisq_head, frame->tf_iioq_head, frame);
196
197	{
198		extern int etext;
199		if (frame < (struct trapframe *)&etext) {
200			printf("trap: bogus frame ptr %p\n", frame);
201			goto dead_end;
202		}
203	}
204#endif
205	switch (type) {
206	case T_NONEXIST:
207	case T_NONEXIST|T_USER:
208#ifndef DDB
209		/* we've got screwed up by the central scrutinizer */
210		panic ("trap: elvis has just left the building!");
211		break;
212#else
213		goto dead_end;
214#endif
215	case T_RECOVERY:
216	case T_RECOVERY|T_USER:
217#ifndef DDB
218		/* XXX will implement later */
219		printf ("trap: handicapped");
220		break;
221#else
222		goto dead_end;
223#endif
224
225#ifdef DIAGNOSTIC
226	case T_EXCEPTION:
227		panic("FPU/SFU emulation botch");
228
229		/* these just can't happen ever */
230	case T_PRIV_OP:
231	case T_PRIV_REG:
232		/* these just can't make it to the trap() ever */
233	case T_HPMC:      case T_HPMC | T_USER:
234	case T_EMULATION: case T_EMULATION | T_USER:
235	case T_TLB_DIRTY: case T_TLB_DIRTY | T_USER:
236#endif
237	case T_IBREAK:
238	case T_DATALIGN:
239	case T_DBREAK:
240	dead_end:
241#ifdef DDB
242		if (kdb_trap (type, va, frame)) {
243			if (type == T_IBREAK) {
244				/* skip break instruction */
245				frame->tf_iioq_head = frame->tf_iioq_tail;
246				frame->tf_iioq_tail += 4;
247			}
248			return;
249		}
250#else
251		if (type == T_DATALIGN)
252			panic ("trap: %s at 0x%x", tts, va);
253		else
254			panic ("trap: no debugger for \"%s\" (%d)", tts, type);
255#endif
256		break;
257
258	case T_IBREAK | T_USER:
259	case T_DBREAK | T_USER:
260		/* pass to user debugger */
261		break;
262
263	case T_EXCEPTION | T_USER:	/* co-proc assist trap */
264		sv.sival_int = va;
265		trapsignal(p, SIGFPE, type &~ T_USER, FPE_FLTINV, sv);
266		break;
267
268	case T_OVERFLOW | T_USER:
269		sv.sival_int = va;
270		trapsignal(p, SIGFPE, type &~ T_USER, FPE_INTOVF, sv);
271		break;
272
273	case T_CONDITION | T_USER:
274		break;
275
276	case T_ILLEGAL | T_USER:
277		sv.sival_int = va;
278		trapsignal(p, SIGILL, type &~ T_USER, ILL_ILLOPC, sv);
279		break;
280
281	case T_PRIV_OP | T_USER:
282		sv.sival_int = va;
283		trapsignal(p, SIGILL, type &~ T_USER, ILL_PRVOPC, sv);
284		break;
285
286	case T_PRIV_REG | T_USER:
287		sv.sival_int = va;
288		trapsignal(p, SIGILL, type &~ T_USER, ILL_PRVREG, sv);
289		break;
290
291		/* these should never got here */
292	case T_HIGHERPL | T_USER:
293	case T_LOWERPL | T_USER:
294		sv.sival_int = va;
295		trapsignal(p, SIGSEGV, type &~ T_USER, SEGV_ACCERR, sv);
296		break;
297
298	case T_IPROT | T_USER:
299	case T_DPROT | T_USER:
300		sv.sival_int = va;
301		trapsignal(p, SIGSEGV, vftype, SEGV_ACCERR, sv);
302		break;
303
304	case T_DPROT:
305	case T_IPROT:
306	case T_DATACC:   	case T_DATACC   | T_USER:
307	case T_ITLBMISS:	case T_ITLBMISS | T_USER:
308	case T_DTLBMISS:	case T_DTLBMISS | T_USER:
309	case T_ITLBMISSNA:	case T_ITLBMISSNA | T_USER:
310	case T_DTLBMISSNA:	case T_DTLBMISSNA | T_USER:
311		va = trunc_page(va);
312		vm = p->p_vmspace;
313
314		if (!vm) {
315#ifdef TRAPDEBUG
316			printf("trap: no vm, p=%p\n", p);
317#endif
318			goto dead_end;
319		}
320
321		/*
322		 * it could be a kernel map for exec_map faults
323		 */
324		if (!(type & T_USER) && space == HPPA_SID_KERNEL)
325			map = kernel_map;
326		else
327			map = &vm->vm_map;
328
329		if (map->pmap->pmap_space != space) {
330#ifdef TRAPDEBUG
331			printf("trap: space missmatch %d != %d\n",
332			    space, map->pmap->pmap_space);
333#endif
334			/* actually dump the user, crap the kernel */
335			goto dead_end;
336		}
337
338		ret = uvm_fault(map, va, 0, vftype);
339
340#ifdef TRAPDEBUG
341		printf("uvm_fault(%p, %x, %d, %d)=%d\n",
342		    map, va, 0, vftype, ret);
343#endif
344
345		/*
346		 * If this was a stack access we keep track of the maximum
347		 * accessed stack size.  Also, if uvm_fault gets a protection
348		 * failure it is due to accessing the stack region outside
349		 * the current limit and we need to reflect that as an access
350		 * error.
351		 */
352		if (va >= (vaddr_t)vm->vm_maxsaddr + vm->vm_ssize) {
353			if (ret == KERN_SUCCESS) {
354				vsize_t nss = clrnd(btoc(va - USRSTACK + NBPG));
355				if (nss > vm->vm_ssize)
356					vm->vm_ssize = nss;
357			} else if (ret == KERN_PROTECTION_FAILURE)
358				ret = KERN_INVALID_ADDRESS;
359		}
360
361		if (ret != KERN_SUCCESS) {
362			if (type & T_USER) {
363printf("trapsignal: uvm_fault\n");
364				sv.sival_int = frame->tf_ior;
365				trapsignal(p, SIGSEGV, vftype, SEGV_MAPERR, sv);
366			} else {
367				if (p && p->p_addr->u_pcb.pcb_onfault) {
368#ifdef PMAPDEBUG
369					printf("trap: copyin/out %d\n",ret);
370#endif
371					pcbp = &p->p_addr->u_pcb;
372					frame->tf_iioq_tail = 4 +
373					    (frame->tf_iioq_head =
374						pcbp->pcb_onfault);
375					pcbp->pcb_onfault = 0;
376					break;
377				}
378#if 1
379if (kdb_trap (type, va, frame))
380	return;
381#else
382				panic("trap: uvm_fault(%p, %x, %d, %d): %d",
383				    map, va, 0, vftype, ret);
384#endif
385			}
386		}
387		break;
388
389	case T_DATALIGN | T_USER:
390		sv.sival_int = va;
391		trapsignal(p, SIGBUS, vftype, BUS_ADRALN, sv);
392		break;
393
394	case T_INTERRUPT:
395	case T_INTERRUPT|T_USER:
396		frame->tf_flags |= TFF_INTR;
397		cpu_intr(frame);
398#if 0
399if (kdb_trap (type, va, frame))
400return;
401#endif
402		/* FALLTHROUGH */
403	case T_LOWERPL:
404		__asm __volatile ("ldcws 0(%1), %0"
405				  : "=r" (si) : "r" (&sir));
406		s = spl0();
407		if (si & SIR_CLOCK) {
408			splclock();
409			softclock();
410			spl0();
411		}
412
413		if (si & SIR_NET) {
414			register int ni;
415			/* use atomic "load & clear" */
416			__asm __volatile ("ldcws 0(%1), %0"
417					  : "=r" (ni) : "r" (&netisr));
418			splnet();
419#define	DONET(m,c) if (ni & (1 << (m))) c()
420#include "ether.h"
421#if NETHER > 0
422			DONET(NETISR_ARP, arpintr);
423#endif
424#ifdef INET
425			DONET(NETISR_IP, ipintr);
426#endif
427#ifdef INET6
428			DONET(NETISR_IPV6, ip6intr);
429#endif
430#ifdef NETATALK
431			DONET(NETISR_ATALK, atintr);
432#endif
433#ifdef IMP
434			DONET(NETISR_IMP, impintr);
435#endif
436#ifdef IPX
437			DONET(NETISR_IPX, ipxintr);
438#endif
439#ifdef NS
440			DONET(NETISR_NS, nsintr);
441#endif
442#ifdef ISO
443			DONET(NETISR_ISO, clnlintr);
444#endif
445#ifdef CCITT
446			DONET(NETISR_CCITT, ccittintr);
447#endif
448#ifdef NATM
449			DONET(NETISR_NATM, natmintr);
450#endif
451#include "ppp.h"
452#if NPPP > 0
453			DONET(NETISR_PPP, pppintr);
454#endif
455#include "bridge.h"
456#if NBRIDGE > 0
457			DONET(NETISR_BRIDGE, bridgeintr)
458#endif
459		}
460		splx(s);
461		break;
462
463	case T_OVERFLOW:
464	case T_CONDITION:
465	case T_ILLEGAL:
466	case T_HIGHERPL:
467	case T_TAKENBR:
468	case T_POWERFAIL:
469	case T_LPMC:
470	case T_PAGEREF:
471	case T_DATAPID:  	case T_DATAPID  | T_USER:
472		if (0 /* T-chip */) {
473			break;
474		}
475		/* FALLTHROUGH to unimplemented */
476	default:
477#if 1
478if (kdb_trap (type, va, frame))
479	return;
480#endif
481		panic ("trap: unimplemented \'%s\' (%d)", tts, type);
482	}
483
484	if (type & T_USER)
485		userret(p, p->p_md.md_regs->tf_iioq_head, 0);
486}
487
488void
489child_return(p)
490	struct proc *p;
491{
492	userret(p, p->p_md.md_regs->tf_iioq_head, 0);
493#ifdef KTRACE
494	if (KTRPOINT(p, KTR_SYSRET))
495		ktrsysret(p->p_tracep, SYS_fork, 0, 0);
496#endif
497}
498
499/*
500 * call actual syscall routine
501 * from the low-level syscall handler:
502 * - all HPPA_FRAME_NARGS syscall's arguments supposed to be copied onto
503 *   our stack, this wins compared to copyin just needed amount anyway
504 * - register args are copied onto stack too
505 */
506void
507syscall(frame, args)
508	struct trapframe *frame;
509	int *args;
510{
511	register struct proc *p;
512	register const struct sysent *callp;
513	int nsys, code, argsize, error;
514	int rval[2];
515
516	uvmexp.syscalls++;
517
518	if (!USERMODE(frame->tf_iioq_head))
519		panic("syscall");
520
521	p = curproc;
522	p->p_md.md_regs = frame;
523	nsys = p->p_emul->e_nsysent;
524	callp = p->p_emul->e_sysent;
525	code = frame->tf_t1;
526	switch (code) {
527	case SYS_syscall:
528		code = *args;
529		args += 1;
530		break;
531	case SYS___syscall:
532		if (callp != sysent)
533			break;
534		code = *args;
535		args += 2;
536	}
537
538	if (code < 0 || code >= nsys)
539		callp += p->p_emul->e_nosys;	/* bad syscall # */
540	else
541		callp += code;
542	argsize = callp->sy_argsize;
543
544#ifdef SYSCALL_DEBUG
545	scdebug_call(p, code, args);
546#endif
547#ifdef KTRACE
548	if (KTRPOINT(p, KTR_SYSCALL))
549		ktrsyscall(p->p_tracep, code, argsize, args);
550#endif
551
552	rval[0] = 0;
553	rval[1] = 0;
554	switch (error = (*callp->sy_call)(p, args, rval)) {
555	case 0:
556		p = curproc;			/* changes on exec() */
557		frame = p->p_md.md_regs;
558		frame->tf_ret0 = rval[0];
559		frame->tf_ret1 = rval[1];
560		frame->tf_t1 = 0;
561		break;
562	case ERESTART:
563		frame->tf_iioq_head -= 4; /* right? XXX */
564		frame->tf_iioq_tail -= 4; /* right? XXX */
565		break;
566	case EJUSTRETURN:
567		p = curproc;
568		break;
569	default:
570		if (p->p_emul->e_errno)
571			error = p->p_emul->e_errno[error];
572		frame->tf_t1 = error;
573		break;
574	}
575#ifdef SYSCALL_DEBUG
576	scdebug_ret(p, code, error, rval);
577#endif
578	userret(p, frame->tf_iioq_head, 0);
579#ifdef KTRACE
580	if (KTRPOINT(p, KTR_SYSRET))
581		ktrsysret(p->p_tracep, code, error, rval[0]);
582#endif
583}
584
585/* all the interrupts, minus cpu clock, which is the last */
586struct cpu_intr_vector {
587	struct evcnt evcnt;
588	int pri;
589	int (*handler) __P((void *));
590	void *arg;
591} cpu_intr_vectors[CPU_NINTS];
592
593void *
594cpu_intr_establish(pri, irq, handler, arg, dv)
595	int pri, irq;
596	int (*handler) __P((void *));
597	void *arg;
598	struct device *dv;
599{
600	register struct cpu_intr_vector *iv;
601
602	if (0 <= irq && irq < CPU_NINTS && cpu_intr_vectors[irq].handler)
603		return NULL;
604
605	iv = &cpu_intr_vectors[irq];
606	iv->pri = pri;
607	iv->handler = handler;
608	iv->arg = arg;
609	evcnt_attach(dv, dv->dv_xname, &iv->evcnt);
610
611	return iv;
612}
613
614void
615cpu_intr(frame)
616	struct trapframe *frame;
617{
618	u_int32_t eirr;
619	register struct cpu_intr_vector *iv;
620	register int bit;
621
622	do {
623		mfctl(CR_EIRR, eirr);
624		eirr &= frame->tf_eiem;
625		bit = ffs(eirr) - 1;
626		if (bit >= 0) {
627			mtctl(1 << bit, CR_EIRR);
628			eirr &= ~(1 << bit);
629			/* ((struct iomod *)cpu_gethpa(0))->io_eir = 0; */
630#ifdef INTRDEBUG
631			if (bit != 31)
632				db_printf ("cpu_intr: 0x%08x\n", (1 << bit));
633#endif
634			iv = &cpu_intr_vectors[bit];
635			if (iv->handler) {
636				register int s, r;
637
638				iv->evcnt.ev_count++;
639				s = splx(iv->pri);
640				/* no arg means pass the frame */
641				r = (iv->handler)(iv->arg? iv->arg:frame);
642				splx(s);
643#ifdef INTRDEBUG
644				if (!r)
645					db_printf ("%s: can't handle interrupt\n",
646						   iv->evcnt.ev_name);
647#endif
648			}
649#ifdef INTRDEBUG
650			else
651				db_printf ("cpu_intr: stray interrupt %d\n", bit);
652#endif
653		}
654	} while (eirr);
655}
656