trap.c revision 1.17
1/*	$OpenBSD: trap.c,v 1.17 2000/01/17 00:30:17 mickey 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#define 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/user.h>
43#include <sys/acct.h>
44#include <sys/signal.h>
45#include <sys/device.h>
46
47#include <net/netisr.h>
48
49#include <vm/vm.h>
50#include <vm/vm_kern.h>
51#include <uvm/uvm.h>
52
53#include <machine/iomod.h>
54#include <machine/cpufunc.h>
55#include <machine/reg.h>
56#include <machine/autoconf.h>
57
58#ifdef DDB
59#include <machine/db_machdep.h>
60#endif
61
62#if defined(INTRDEBUG) || defined(TRAPDEBUG)
63#include <ddb/db_output.h>
64#endif
65
66#define	FAULT_TYPE(op)	(VM_PROT_READ|(inst_store(op) ? VM_PROT_WRITE : 0))
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;
166
167	opcode = frame->tf_iir;
168	if (type == T_ITLBMISS || type == T_ITLBMISSNA) {
169		va = frame->tf_iioq_head;
170		space = frame->tf_iisq_head;
171		vftype = VM_PROT_EXECUTE;
172	} else {
173		va = frame->tf_ior;
174		space = frame->tf_isr;
175		vftype = FAULT_TYPE(opcode);
176	}
177
178	if (frame->tf_flags & TFF_LAST)
179		p->p_md.md_regs = frame;
180
181#ifdef TRAPDEBUG
182	if ((type & ~T_USER) > trap_types)
183		tts = "reserved";
184	else
185		tts = trap_type[type & ~T_USER];
186
187	if (type != T_INTERRUPT && (type & ~T_USER) != T_IBREAK)
188		db_printf("trap: %d, %s for %x:%x at %x:%x, fl=%x, fp=%p\n",
189		    type, tts, space, va, frame->tf_iisq_head,
190		    frame->tf_iioq_head, frame->tf_flags, frame);
191	else if ((type & ~T_USER) == T_IBREAK)
192		db_printf("trap: break instruction %x:%x at %x:%x, fp=%p\n",
193		    break5(opcode), break13(opcode),
194		    frame->tf_iisq_head, frame->tf_iioq_head, frame);
195
196	{
197		extern int etext;
198		if (frame < (struct trapframe *)&etext)
199			goto dead_end;
200	}
201#endif
202	switch (type) {
203	case T_NONEXIST:
204	case T_NONEXIST|T_USER:
205#ifndef DDB
206		/* we've got screwed up by the central scrutinizer */
207		panic ("trap: elvis has just left the building!");
208		break;
209#endif
210	case T_RECOVERY:
211	case T_RECOVERY|T_USER:
212#ifndef DDB
213		/* XXX will implement later */
214		printf ("trap: handicapped");
215		break;
216#endif
217
218#ifdef DIAGNOSTIC
219	case T_EXCEPTION:
220		panic("FPU/SFU emulation botch");
221
222		/* these just can't happen ever */
223	case T_PRIV_OP:
224	case T_PRIV_REG:
225		/* these just can't make it to the trap() ever */
226	case T_HPMC:      case T_HPMC | T_USER:
227	case T_EMULATION: case T_EMULATION | T_USER:
228	case T_TLB_DIRTY: case T_TLB_DIRTY | T_USER:
229#endif
230	case T_IBREAK:
231	case T_DATALIGN:
232	case T_DBREAK:
233	dead_end:
234#ifdef DDB
235		if (kdb_trap (type, 0, frame)) {
236			if (type == T_IBREAK) {
237				/* skip break instruction */
238				frame->tf_iioq_head = frame->tf_iioq_tail;
239				frame->tf_iioq_tail += 4;
240			}
241			return;
242		}
243#else
244		if (type == T_DATALIGN)
245			panic ("trap: %s at 0x%x", tts, va);
246		else
247			panic ("trap: no debugger for \"%s\" (%d)", tts, type);
248#endif
249		break;
250
251	case T_IBREAK | T_USER:
252	case T_DBREAK | T_USER:
253		/* pass to user debugger */
254		break;
255
256	case T_EXCEPTION | T_USER:	/* co-proc assist trap */
257		sv.sival_int = va;
258		trapsignal(p, SIGFPE, type &~ T_USER, FPE_FLTINV, sv);
259		break;
260
261	case T_OVERFLOW | T_USER:
262		sv.sival_int = va;
263		trapsignal(p, SIGFPE, type &~ T_USER, FPE_INTOVF, sv);
264		break;
265
266	case T_CONDITION | T_USER:
267		break;
268
269	case T_ILLEGAL | T_USER:
270		sv.sival_int = va;
271		trapsignal(p, SIGILL, type &~ T_USER, ILL_ILLOPC, sv);
272		break;
273
274	case T_PRIV_OP | T_USER:
275		sv.sival_int = va;
276		trapsignal(p, SIGILL, type &~ T_USER, ILL_PRVOPC, sv);
277		break;
278
279	case T_PRIV_REG | T_USER:
280		sv.sival_int = va;
281		trapsignal(p, SIGILL, type &~ T_USER, ILL_PRVREG, sv);
282		break;
283
284		/* these should never got here */
285	case T_HIGHERPL | T_USER:
286	case T_LOWERPL | T_USER:
287		sv.sival_int = va;
288		trapsignal(p, SIGSEGV, type &~ T_USER, SEGV_ACCERR, sv);
289		break;
290
291	case T_IPROT | T_USER:
292	case T_DPROT | T_USER:
293		sv.sival_int = va;
294		trapsignal(p, SIGSEGV, vftype, SEGV_ACCERR, sv);
295		break;
296
297	case T_DPROT:
298	case T_IPROT:
299	case T_DATACC:   	case T_DATACC   | T_USER:
300	case T_ITLBMISS:	case T_ITLBMISS | T_USER:
301	case T_DTLBMISS:	case T_DTLBMISS | T_USER:
302	case T_ITLBMISSNA:	case T_ITLBMISSNA | T_USER:
303	case T_DTLBMISSNA:	case T_DTLBMISSNA | T_USER:
304		va = trunc_page(va);
305		vm = p->p_vmspace;
306
307		if (!vm)
308			goto dead_end;
309
310		/*
311		 * it could be a kernel map for exec_map faults
312		 */
313		if (!(type & T_USER) && space == HPPA_SID_KERNEL)
314			map = kernel_map;
315		else
316			map = &vm->vm_map;
317
318		ret = uvm_fault(map, va, 0, vftype);
319
320		/*
321		 * If this was a stack access we keep track of the maximum
322		 * accessed stack size.  Also, if uvm_fault gets a protection
323		 * failure it is due to accessing the stack region outside
324		 * the current limit and we need to reflect that as an access
325		 * error.
326		 */
327		if (va >= (vaddr_t)vm->vm_maxsaddr + vm->vm_ssize) {
328			if (ret == KERN_SUCCESS) {
329				vsize_t nss = clrnd(btoc(va - USRSTACK + NBPG));
330				if (nss > vm->vm_ssize)
331					vm->vm_ssize = nss;
332			} else if (ret == KERN_PROTECTION_FAILURE)
333				ret = KERN_INVALID_ADDRESS;
334		}
335
336		if (ret != KERN_SUCCESS) {
337			if (type & T_USER) {
338printf("trapsignal: uvm_fault\n");
339				sv.sival_int = frame->tf_ior;
340				trapsignal(p, SIGSEGV, vftype, SEGV_MAPERR, sv);
341			} else {
342				if (p && p->p_addr->u_pcb.pcb_onfault) {
343#ifdef PMAPDEBUG
344					printf("trap: copyin/out %d\n",ret);
345#endif
346					pcbp = &p->p_addr->u_pcb;
347					frame->tf_iioq_tail = 4 +
348					    (frame->tf_iioq_head =
349						pcbp->pcb_onfault);
350					pcbp->pcb_onfault = 0;
351					break;
352				}
353#if 1
354if (kdb_trap (type, 0, frame))
355	return;
356#else
357				panic("trap: uvm_fault(%p, %x, %d, %d): %d",
358				    map, va, 0, vftype, ret);
359#endif
360			}
361		}
362if (type == (T_DATACC|T_USER) && kdb_trap (type, 0, frame))
363	return;
364		break;
365
366	case T_DATALIGN | T_USER:
367		sv.sival_int = va;
368		trapsignal(p, SIGBUS, vftype, BUS_ADRALN, sv);
369		break;
370
371	case T_INTERRUPT:
372	case T_INTERRUPT|T_USER:
373		cpu_intr(frame);
374#if 0
375if (kdb_trap (type, 0, frame))
376return;
377#endif
378		/* FALLTHROUGH */
379	case T_LOWERPL:
380		__asm __volatile ("ldcws 0(%1), %0"
381				  : "=r" (si) : "r" (&sir));
382		s = spl0();
383		if (si & SIR_CLOCK) {
384			splclock();
385			softclock();
386			spl0();
387		}
388
389		if (si & SIR_NET) {
390			register int ni;
391			/* use atomic "load & clear" */
392			__asm __volatile ("ldcws 0(%1), %0"
393					  : "=r" (ni) : "r" (&netisr));
394			splnet();
395#define	DONET(m,c) if (ni & (1 << (m))) c()
396#include "ether.h"
397#if NETHER > 0
398			DONET(NETISR_ARP, arpintr);
399#endif
400#ifdef INET
401			DONET(NETISR_IP, ipintr);
402#endif
403#ifdef INET6
404			DONET(NETISR_IPV6, ip6intr);
405#endif
406#ifdef NETATALK
407			DONET(NETISR_ATALK, atintr);
408#endif
409#ifdef IMP
410			DONET(NETISR_IMP, impintr);
411#endif
412#ifdef IPX
413			DONET(NETISR_IPX, ipxintr);
414#endif
415#ifdef NS
416			DONET(NETISR_NS, nsintr);
417#endif
418#ifdef ISO
419			DONET(NETISR_ISO, clnlintr);
420#endif
421#ifdef CCITT
422			DONET(NETISR_CCITT, ccittintr);
423#endif
424#ifdef NATM
425			DONET(NETISR_NATM, natmintr);
426#endif
427#include "ppp.h"
428#if NPPP > 0
429			DONET(NETISR_PPP, pppintr);
430#endif
431#include "bridge.h"
432#if NBRIDGE > 0
433			DONET(NETISR_BRIDGE, bridgeintr)
434#endif
435		}
436		splx(s);
437		break;
438
439	case T_OVERFLOW:
440	case T_CONDITION:
441	case T_ILLEGAL:
442	case T_HIGHERPL:
443	case T_TAKENBR:
444	case T_POWERFAIL:
445	case T_LPMC:
446	case T_PAGEREF:
447	case T_DATAPID:  	case T_DATAPID  | T_USER:
448		if (0 /* T-chip */) {
449			break;
450		}
451		/* FALLTHROUGH to unimplemented */
452	default:
453#if 1
454if (kdb_trap (type, 0, frame))
455	return;
456#endif
457		panic ("trap: unimplemented \'%s\' (%d)", tts, type);
458	}
459
460	if (type & T_USER)
461		userret(p, p->p_md.md_regs->tf_iioq_head, 0);
462}
463
464void
465child_return(p)
466	struct proc *p;
467{
468	userret(p, p->p_md.md_regs->tf_iioq_head, 0);
469#ifdef KTRACE
470	if (KTRPOINT(p, KTR_SYSRET))
471		ktrsysret(p->p_tracep, SYS_fork, 0, 0);
472#endif
473}
474
475/*
476 * call actual syscall routine
477 * from the low-level syscall handler:
478 * - all HPPA_FRAME_NARGS syscall's arguments supposed to be copied onto
479 *   our stack, this wins compared to copyin just needed amount anyway
480 * - register args are copied onto stack too
481 */
482void
483syscall(frame, args)
484	struct trapframe *frame;
485	int *args;
486{
487	register struct proc *p;
488	register const struct sysent *callp;
489	int nsys, code, argsize, error;
490	int rval[2];
491
492	uvmexp.syscalls++;
493
494	if (!USERMODE(frame->tf_iioq_head))
495		panic("syscall");
496
497	p = curproc;
498	p->p_md.md_regs = frame;
499	nsys = p->p_emul->e_nsysent;
500	callp = p->p_emul->e_sysent;
501	code = frame->tf_t1;
502	switch (code) {
503	case SYS_syscall:
504		code = frame->tf_arg0;
505		args += 1;
506		break;
507	case SYS___syscall:
508		if (callp != sysent)
509			break;
510		code = frame->tf_arg0; /* XXX or arg1? */
511		args += 2;
512	}
513
514	if (code < 0 || code >= nsys)
515		callp += p->p_emul->e_nosys;	/* bad syscall # */
516	else
517		callp += code;
518	argsize = callp->sy_argsize;
519
520#ifdef SYSCALL_DEBUG
521	scdebug_call(p, code, args);
522#endif
523#ifdef KTRACE
524	if (KTRPOINT(p, KTR_SYSCALL))
525		ktrsyscall(p->p_tracep, code, argsize, args);
526#endif
527
528	rval[0] = 0;
529	rval[1] = 0;
530	switch (error = (*callp->sy_call)(p, args, rval)) {
531	case 0:
532		/* curproc may change inside the fork() */
533		frame->tf_ret0 = rval[0];
534		frame->tf_ret1 = rval[1];
535		frame->tf_t1 = 0;
536		break;
537	case ERESTART:
538		frame->tf_iioq_head -= 4; /* right? XXX */
539		break;
540	case EJUSTRETURN:
541		break;
542	default:
543		if (p->p_emul->e_errno)
544			error = p->p_emul->e_errno[error];
545		frame->tf_t1 = error;
546		break;
547	}
548	p = curproc;
549#ifdef SYSCALL_DEBUG
550	scdebug_ret(p, code, error, rval);
551#endif
552	userret(p, p->p_md.md_regs->tf_iioq_head, 0);
553#ifdef KTRACE
554	if (KTRPOINT(p, KTR_SYSRET))
555		ktrsysret(p->p_tracep, code, error, rval[0]);
556#endif
557}
558
559/* all the interrupts, minus cpu clock, which is the last */
560struct cpu_intr_vector {
561	struct evcnt evcnt;
562	int pri;
563	int (*handler) __P((void *));
564	void *arg;
565} cpu_intr_vectors[CPU_NINTS];
566
567void *
568cpu_intr_establish(pri, irq, handler, arg, dv)
569	int pri, irq;
570	int (*handler) __P((void *));
571	void *arg;
572	struct device *dv;
573{
574	register struct cpu_intr_vector *iv;
575
576	if (0 <= irq && irq < CPU_NINTS && cpu_intr_vectors[irq].handler)
577		return NULL;
578
579	iv = &cpu_intr_vectors[irq];
580	iv->pri = pri;
581	iv->handler = handler;
582	iv->arg = arg;
583	evcnt_attach(dv, dv->dv_xname, &iv->evcnt);
584
585	return iv;
586}
587
588void
589cpu_intr(frame)
590	struct trapframe *frame;
591{
592	u_int32_t eirr;
593	register struct cpu_intr_vector *iv;
594	register int bit;
595
596	do {
597		mfctl(CR_EIRR, eirr);
598		eirr &= frame->tf_eiem;
599		bit = ffs(eirr) - 1;
600		if (bit >= 0) {
601			mtctl(1 << bit, CR_EIRR);
602			eirr &= ~(1 << bit);
603			/* ((struct iomod *)cpu_gethpa(0))->io_eir = 0; */
604#ifdef INTRDEBUG
605			if (bit != 31)
606				db_printf ("cpu_intr: 0x%08x\n", (1 << bit));
607#endif
608			iv = &cpu_intr_vectors[bit];
609			if (iv->handler) {
610				register int s, r;
611
612				iv->evcnt.ev_count++;
613				s = splx(iv->pri);
614				/* no arg means pass the frame */
615				r = (iv->handler)(iv->arg? iv->arg:frame);
616				splx(s);
617#ifdef DEBUG
618				if (!r)
619					db_printf ("%s: can't handle interrupt\n",
620						   iv->evcnt.ev_name);
621#endif
622			} else
623				db_printf ("cpu_intr: stray interrupt %d\n", bit);
624		}
625	} while (eirr);
626}
627