xref: /openbsd/sys/arch/hppa/hppa/trap.c (revision b9b95e0d)
1*b9b95e0dSmickey /*	$OpenBSD: trap.c,v 1.3 1999/04/20 20:58:01 mickey Exp $	*/
2556d2ba7Smickey 
3556d2ba7Smickey /*
4556d2ba7Smickey  * Copyright (c) 1998 Michael Shalayeff
5556d2ba7Smickey  * All rights reserved.
6556d2ba7Smickey  *
7556d2ba7Smickey  * Redistribution and use in source and binary forms, with or without
8556d2ba7Smickey  * modification, are permitted provided that the following conditions
9556d2ba7Smickey  * are met:
10556d2ba7Smickey  * 1. Redistributions of source code must retain the above copyright
11556d2ba7Smickey  *    notice, this list of conditions and the following disclaimer.
12556d2ba7Smickey  * 2. Redistributions in binary form must reproduce the above copyright
13556d2ba7Smickey  *    notice, this list of conditions and the following disclaimer in the
14556d2ba7Smickey  *    documentation and/or other materials provided with the distribution.
15556d2ba7Smickey  * 3. All advertising materials mentioning features or use of this software
16556d2ba7Smickey  *    must display the following acknowledgement:
17556d2ba7Smickey  *	This product includes software developed by Michael Shalayeff.
18556d2ba7Smickey  * 4. The name of the author may not be used to endorse or promote products
19556d2ba7Smickey  *    derived from this software without specific prior written permission.
20556d2ba7Smickey  *
21556d2ba7Smickey  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22556d2ba7Smickey  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23556d2ba7Smickey  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24556d2ba7Smickey  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25556d2ba7Smickey  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26556d2ba7Smickey  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27556d2ba7Smickey  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28556d2ba7Smickey  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29556d2ba7Smickey  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30556d2ba7Smickey  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31556d2ba7Smickey  */
32556d2ba7Smickey 
33556d2ba7Smickey #define INTRDEBUG
34556d2ba7Smickey 
35556d2ba7Smickey #include <sys/param.h>
36556d2ba7Smickey #include <sys/systm.h>
37*b9b95e0dSmickey #include <sys/syscall.h>
38*b9b95e0dSmickey #include <sys/ktrace.h>
39556d2ba7Smickey 
40556d2ba7Smickey #include <vm/vm.h>
41*b9b95e0dSmickey #include <uvm/uvm.h>
42556d2ba7Smickey 
43556d2ba7Smickey #include <machine/iomod.h>
44556d2ba7Smickey #include <machine/cpufunc.h>
45556d2ba7Smickey #include <machine/reg.h>
46556d2ba7Smickey #include <machine/db_machdep.h>
47556d2ba7Smickey #include <machine/autoconf.h>
48556d2ba7Smickey 
49556d2ba7Smickey #define	FAULT_TYPE(op)	(VM_PROT_READ|(inst_load(op) ? 0 : VM_PROT_WRITE))
50556d2ba7Smickey 
51556d2ba7Smickey const char *trap_type[] = {
52556d2ba7Smickey 	"invalid interrupt vector",
53556d2ba7Smickey 	"high priority machine check",
54556d2ba7Smickey 	"power failure",
55556d2ba7Smickey 	"recovery counter trap",
56556d2ba7Smickey 	"external interrupt",
57556d2ba7Smickey 	"low-priority machine check",
58556d2ba7Smickey 	"instruction TLB miss fault",
59556d2ba7Smickey 	"instruction protection trap",
60556d2ba7Smickey 	"Illegal instruction trap",
61556d2ba7Smickey 	"break instruction trap",
62556d2ba7Smickey 	"privileged operation trap",
63556d2ba7Smickey 	"privileged register trap",
64556d2ba7Smickey 	"overflow trap",
65556d2ba7Smickey 	"conditional trap",
66556d2ba7Smickey 	"assist exception trap",
67556d2ba7Smickey 	"data TLB miss fault",
68556d2ba7Smickey 	"ITLB non-access miss fault",
69556d2ba7Smickey 	"DTLB non-access miss fault",
70556d2ba7Smickey 	"data protection trap/unalligned data reference trap",
71556d2ba7Smickey 	"data break trap",
72556d2ba7Smickey 	"TLB dirty bit trap",
73556d2ba7Smickey 	"page reference trap",
74556d2ba7Smickey 	"assist emulation trap",
75556d2ba7Smickey 	"higher-privelege transfer trap",
76556d2ba7Smickey 	"lower-privilege transfer trap",
77556d2ba7Smickey 	"taken branch trap",
78556d2ba7Smickey 	"data access rights trap",
79556d2ba7Smickey 	"data protection ID trap",
80556d2ba7Smickey 	"unaligned data ref trap",
81556d2ba7Smickey 	"reserved",
82556d2ba7Smickey 	"reserved 2"
83556d2ba7Smickey };
84556d2ba7Smickey int trap_types = sizeof(trap_type)/sizeof(trap_type[0]);
85556d2ba7Smickey 
86556d2ba7Smickey u_int32_t sir;
87*b9b95e0dSmickey int want_resched;
88556d2ba7Smickey 
89556d2ba7Smickey void pmap_hptdump __P((void));
90*b9b95e0dSmickey void cpu_intr __P((u_int32_t t, struct trapframe *frame));
91*b9b95e0dSmickey void syscall __P((struct trapframe *frame, int *args));
92556d2ba7Smickey 
93556d2ba7Smickey void
94556d2ba7Smickey trap(type, frame)
95556d2ba7Smickey 	int type;
96556d2ba7Smickey 	struct trapframe *frame;
97556d2ba7Smickey {
98556d2ba7Smickey 	struct proc *p = curproc;
99556d2ba7Smickey 	register vm_offset_t va;
100556d2ba7Smickey 	register vm_map_t map;
101556d2ba7Smickey 	register pa_space_t space;
102556d2ba7Smickey 	u_int opcode, t;
103556d2ba7Smickey 	int ret;
104556d2ba7Smickey 
105*b9b95e0dSmickey 	va = frame->tf_ior;
106*b9b95e0dSmickey 	space = (pa_space_t) frame->tf_isr;
107556d2ba7Smickey 
108*b9b95e0dSmickey 	if (USERMODE(frame->tf_iioq_head)) {
109556d2ba7Smickey 		type |= T_USER;
110556d2ba7Smickey 		p->p_md.md_regs = frame;
111556d2ba7Smickey 	}
112556d2ba7Smickey 
113556d2ba7Smickey 	if ((type & ~T_USER) != T_INTERRUPT)
114556d2ba7Smickey 		printf("trap: %d, %s for %x:%x at %x:%x\n",
115556d2ba7Smickey 		       type, trap_type[type & ~T_USER], space, va,
116*b9b95e0dSmickey 		       frame->tf_iisq_head, frame->tf_iioq_head);
117556d2ba7Smickey 
118556d2ba7Smickey 	switch (type) {
119556d2ba7Smickey 	case T_NONEXIST:
120556d2ba7Smickey 	case T_NONEXIST|T_USER:
121556d2ba7Smickey 		/* we are screwd up by the central scrutinizer */
122556d2ba7Smickey 		panic ("trap: zombie on the bridge!!!");
123556d2ba7Smickey 		break;
124556d2ba7Smickey 
125556d2ba7Smickey 	case T_RECOVERY:
126556d2ba7Smickey 	case T_RECOVERY|T_USER:
127556d2ba7Smickey 		printf ("trap: handicapped");
128556d2ba7Smickey 		break;
129556d2ba7Smickey 
130556d2ba7Smickey 	case T_INTERRUPT:
131556d2ba7Smickey 	case T_INTERRUPT|T_USER:
132556d2ba7Smickey 		mfctl(CR_EIRR, t);
133*b9b95e0dSmickey 		t &= frame->tf_eiem;
134*b9b95e0dSmickey 		/* ACK it now */
135556d2ba7Smickey 		/* hardcode intvl timer intr, to save for proc switching */
136556d2ba7Smickey 		if (t & INT_ITMR) {
137556d2ba7Smickey 			mtctl(INT_ITMR, CR_EIRR);
138556d2ba7Smickey 			/* we've got an interval timer interrupt */
139556d2ba7Smickey 			cpu_initclocks();
140556d2ba7Smickey 			hardclock(frame);
141*b9b95e0dSmickey 			t ^= INT_ITMR;
142556d2ba7Smickey 		}
143*b9b95e0dSmickey 		if (t)
144*b9b95e0dSmickey 			cpu_intr(t, frame);
145556d2ba7Smickey 		return;
146556d2ba7Smickey 
147556d2ba7Smickey 	case T_HPMC:
148556d2ba7Smickey 	case T_POWERFAIL:
149556d2ba7Smickey 	case T_LPMC:
150556d2ba7Smickey 		break;
151556d2ba7Smickey 
152556d2ba7Smickey 	case T_IBREAK:
153556d2ba7Smickey 	case T_DBREAK:
154556d2ba7Smickey 		if (kdb_trap (type, 0, frame))
155556d2ba7Smickey 			return;
156556d2ba7Smickey 		break;
157556d2ba7Smickey 
158556d2ba7Smickey 	case T_DTLBMISS:
159556d2ba7Smickey 		va = trunc_page(va);
160*b9b95e0dSmickey 		opcode = frame->tf_iir;
161556d2ba7Smickey 
162556d2ba7Smickey #ifdef DDB
163556d2ba7Smickey 		Debugger();
164556d2ba7Smickey #endif
165*b9b95e0dSmickey 		ret = uvm_fault(map, va, FAULT_TYPE(opcode), FALSE);
166556d2ba7Smickey 		if (ret == KERN_SUCCESS)
167556d2ba7Smickey 			break;
16830ada397Smillert 		panic("trap: vm_fault(%p, %x, %d, %d): %d",
169556d2ba7Smickey 		      map, va, FAULT_TYPE(opcode), 0, ret);
170556d2ba7Smickey 		break;
171556d2ba7Smickey 	default:
172556d2ba7Smickey 		/* pmap_hptdump(); */
173556d2ba7Smickey #ifdef DDB
174556d2ba7Smickey 		Debugger();
175556d2ba7Smickey #endif
176556d2ba7Smickey 	}
177556d2ba7Smickey }
178556d2ba7Smickey 
179*b9b95e0dSmickey /*
180*b9b95e0dSmickey  * call actual syscall routine
181*b9b95e0dSmickey  * from the low-level syscall handler:
182*b9b95e0dSmickey  * - all HPPA_FRAME_NARGS syscall's arguments supposed to be copied onto
183*b9b95e0dSmickey  *   our stack, this wins compared to copyin just needed amount anyway
184*b9b95e0dSmickey  * - register args are copied onto stack too
185*b9b95e0dSmickey  */
186*b9b95e0dSmickey void
187*b9b95e0dSmickey syscall(frame, args)
188*b9b95e0dSmickey 	struct trapframe *frame;
189*b9b95e0dSmickey 	int *args;
190*b9b95e0dSmickey {
191*b9b95e0dSmickey 	register struct proc *p;
192*b9b95e0dSmickey 	register const struct sysent *callp;
193*b9b95e0dSmickey 	int nsys, code, argsize, error;
194*b9b95e0dSmickey 	int rval[2];
195*b9b95e0dSmickey 
196*b9b95e0dSmickey 	uvmexp.syscalls++;
197*b9b95e0dSmickey 
198*b9b95e0dSmickey 	if (!USERMODE(frame->tf_iioq_head))
199*b9b95e0dSmickey 		panic("syscall");
200*b9b95e0dSmickey 
201*b9b95e0dSmickey 	p = curproc;
202*b9b95e0dSmickey 	nsys = p->p_emul->e_nsysent;
203*b9b95e0dSmickey 	callp = p->p_emul->e_sysent;
204*b9b95e0dSmickey 	code = frame->tf_arg0;
205*b9b95e0dSmickey 	switch (code) {
206*b9b95e0dSmickey 	case SYS_syscall:
207*b9b95e0dSmickey 		code = frame->tf_arg1;
208*b9b95e0dSmickey 		args += 1;
209*b9b95e0dSmickey 		break;
210*b9b95e0dSmickey 	case SYS___syscall:
211*b9b95e0dSmickey 		if (callp != sysent)
212*b9b95e0dSmickey 			break;
213*b9b95e0dSmickey 		code = frame->tf_arg1; /* XXX or arg2? */
214*b9b95e0dSmickey 		args += 2;
215*b9b95e0dSmickey 	}
216*b9b95e0dSmickey 
217*b9b95e0dSmickey 	if (code < 0 || code >= nsys)
218*b9b95e0dSmickey 		callp += p->p_emul->e_nosys;	/* bad syscall # */
219*b9b95e0dSmickey 	else
220*b9b95e0dSmickey 		callp += code;
221*b9b95e0dSmickey 	argsize = callp->sy_argsize;
222*b9b95e0dSmickey 
223*b9b95e0dSmickey #ifdef SYSCALL_DEBUG
224*b9b95e0dSmickey 	scdebug_call(p, code, args);
225*b9b95e0dSmickey #endif
226*b9b95e0dSmickey #ifdef KTRACE
227*b9b95e0dSmickey 	if (KTRPOINT(p, KTR_SYSCALL))
228*b9b95e0dSmickey 		ktrsyscall(p->p_tracep, code, argsize, args);
229*b9b95e0dSmickey #endif
230*b9b95e0dSmickey 
231*b9b95e0dSmickey 	rval[0] = 0;
232*b9b95e0dSmickey 	rval[1] = 0;
233*b9b95e0dSmickey 	switch (error = (*callp->sy_call)(p, args, rval)) {
234*b9b95e0dSmickey 	case 0:
235*b9b95e0dSmickey 		/* curproc may change iside the fork() */
236*b9b95e0dSmickey 		p = curproc;
237*b9b95e0dSmickey 		frame->tf_ret0 = rval[0];
238*b9b95e0dSmickey 		frame->tf_ret1 = rval[1];
239*b9b95e0dSmickey 		break;
240*b9b95e0dSmickey 	case ERESTART:
241*b9b95e0dSmickey 		frame->tf_iioq_head -= 4; /* right? XXX */
242*b9b95e0dSmickey 		break;
243*b9b95e0dSmickey 	case EJUSTRETURN:
244*b9b95e0dSmickey 		break;
245*b9b95e0dSmickey 	default:
246*b9b95e0dSmickey 		if (p->p_emul->e_errno)
247*b9b95e0dSmickey 			error = p->p_emul->e_errno[error];
248*b9b95e0dSmickey 		frame->tf_ret0 = error;
249*b9b95e0dSmickey 		break;
250*b9b95e0dSmickey 	}
251*b9b95e0dSmickey 
252*b9b95e0dSmickey #ifdef SYSCALL_DEBUG
253*b9b95e0dSmickey 	scdebug_ret(p, code, error, rval);
254*b9b95e0dSmickey #endif
255*b9b95e0dSmickey #ifdef KTRACE
256*b9b95e0dSmickey 	if (KTRPOINT(p, KTR_SYSRET))
257*b9b95e0dSmickey 		ktrsysret(p->p_tracep, code, error, rval[0]);
258*b9b95e0dSmickey #endif
259*b9b95e0dSmickey }
260*b9b95e0dSmickey 
261556d2ba7Smickey /* all the interrupts, minus cpu clock, which is the last */
262556d2ba7Smickey struct cpu_intr_vector {
263556d2ba7Smickey 	const char *name;
264556d2ba7Smickey 	int pri;
265556d2ba7Smickey 	int (*handler) __P((void *));
266556d2ba7Smickey 	void *arg;
267556d2ba7Smickey } cpu_intr_vectors[CPU_NINTS - 1];
268556d2ba7Smickey 
269*b9b95e0dSmickey void *
270*b9b95e0dSmickey cpu_intr_establish(pri, irq, handler, arg, name)
271*b9b95e0dSmickey 	int pri, irq;
272556d2ba7Smickey 	int (*handler) __P((void *));
273556d2ba7Smickey 	void *arg;
274556d2ba7Smickey 	const char *name;
275556d2ba7Smickey {
276556d2ba7Smickey 	register struct cpu_intr_vector *p;
277556d2ba7Smickey 
278*b9b95e0dSmickey 	/* don't allow to override any established vectors,
279*b9b95e0dSmickey 	   AND interval timer hard-bound one */
280*b9b95e0dSmickey 	if (irq >= (CPU_NINTS - 1) || cpu_intr_vectors[irq].handler)
281*b9b95e0dSmickey 		return NULL;
282556d2ba7Smickey 
283*b9b95e0dSmickey 	p = &cpu_intr_vectors[irq];
284556d2ba7Smickey 	p->name = name;
285556d2ba7Smickey 	p->pri = pri;
286556d2ba7Smickey 	p->handler = handler;
287556d2ba7Smickey 	p->arg = arg;
288556d2ba7Smickey 
289*b9b95e0dSmickey 	return p;
290556d2ba7Smickey }
291556d2ba7Smickey 
292556d2ba7Smickey void
293*b9b95e0dSmickey cpu_intr(t, frame)
294*b9b95e0dSmickey 	u_int32_t t;
295556d2ba7Smickey 	struct trapframe *frame;
296556d2ba7Smickey {
297*b9b95e0dSmickey 	u_int32_t eirr;
298556d2ba7Smickey 	register struct cpu_intr_vector *p;
299556d2ba7Smickey 	register int bit;
300556d2ba7Smickey 
301556d2ba7Smickey 	do {
302*b9b95e0dSmickey 		mfctl(CR_EIRR, eirr);
303*b9b95e0dSmickey 		eirr = (t | eirr) & frame->tf_eiem;
304*b9b95e0dSmickey 		bit = ffs(eirr) - 1;
305556d2ba7Smickey 		if (bit >= 0) {
306556d2ba7Smickey 			mtctl(1 << bit, CR_EIRR);
307*b9b95e0dSmickey 			eirr &= ~(1 << bit);
308*b9b95e0dSmickey 			/* ((struct iomod *)cpu_gethpa(0))->io_eir = 0; */
309556d2ba7Smickey #ifdef INTRDEBUG
310*b9b95e0dSmickey 			printf ("cpu_intr: 0x%08x\n", (1 << bit));
311556d2ba7Smickey #endif
312556d2ba7Smickey 			p = &cpu_intr_vectors[bit];
313556d2ba7Smickey 			if (p->handler) {
314556d2ba7Smickey 				register int s = splx(p->pri);
315556d2ba7Smickey 				if (!(p->handler)(p->arg))
316*b9b95e0dSmickey #ifdef INTRDEBUG1
317*b9b95e0dSmickey 					panic ("%s: can't handle interrupt",
318*b9b95e0dSmickey 					       p->name);
319*b9b95e0dSmickey #else
320556d2ba7Smickey 					printf ("%s: can't handle interrupt\n",
321556d2ba7Smickey 						p->name);
322*b9b95e0dSmickey #endif
323556d2ba7Smickey 				splx(s);
324*b9b95e0dSmickey 			} else {
325*b9b95e0dSmickey #ifdef INTRDEBUG
326*b9b95e0dSmickey 				panic  ("cpu_intr: stray interrupt %d", bit);
327*b9b95e0dSmickey #else
328556d2ba7Smickey 				printf ("cpu_intr: stray interrupt %d\n", bit);
329*b9b95e0dSmickey #endif
330556d2ba7Smickey 			}
331*b9b95e0dSmickey 		}
332*b9b95e0dSmickey 	} while (eirr);
333556d2ba7Smickey }
334556d2ba7Smickey 
335