xref: /openbsd/sys/arch/hppa/hppa/trap.c (revision c81336dc)
1*c81336dcSart /*	$OpenBSD: trap.c,v 1.29 2001/09/14 14:58:44 art Exp $	*/
2556d2ba7Smickey 
3556d2ba7Smickey /*
48de28e3eSmickey  * Copyright (c) 1998-2000 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 
332ef9a47eSmickey /* #define INTRDEBUG */
342ef9a47eSmickey /* #define TRAPDEBUG */
35556d2ba7Smickey 
36556d2ba7Smickey #include <sys/param.h>
37556d2ba7Smickey #include <sys/systm.h>
38d412f1c2Smickey #include <sys/kernel.h>
39b9b95e0dSmickey #include <sys/syscall.h>
40b9b95e0dSmickey #include <sys/ktrace.h>
41d412f1c2Smickey #include <sys/proc.h>
426acb4cb0Sniklas #include <sys/signalvar.h>
43d412f1c2Smickey #include <sys/user.h>
44d412f1c2Smickey #include <sys/acct.h>
45d412f1c2Smickey #include <sys/signal.h>
46688a8060Smickey #include <sys/device.h>
47556d2ba7Smickey 
48af7386c3Smickey #include <net/netisr.h>
49af7386c3Smickey 
50556d2ba7Smickey #include <vm/vm.h>
518de28e3eSmickey #include <vm/vm_kern.h>
52b9b95e0dSmickey #include <uvm/uvm.h>
53556d2ba7Smickey 
54556d2ba7Smickey #include <machine/iomod.h>
55556d2ba7Smickey #include <machine/cpufunc.h>
56556d2ba7Smickey #include <machine/reg.h>
57556d2ba7Smickey #include <machine/autoconf.h>
58556d2ba7Smickey 
59137d3021Smickey #ifdef DDB
60137d3021Smickey #include <machine/db_machdep.h>
61137d3021Smickey #endif
62137d3021Smickey 
63137d3021Smickey #if defined(INTRDEBUG) || defined(TRAPDEBUG)
64137d3021Smickey #include <ddb/db_output.h>
65137d3021Smickey #endif
66137d3021Smickey 
67556d2ba7Smickey 
68556d2ba7Smickey const char *trap_type[] = {
69e494c7cfSmickey 	"invalid",
70e494c7cfSmickey 	"HPMC",
71556d2ba7Smickey 	"power failure",
72137d3021Smickey 	"recovery counter",
73556d2ba7Smickey 	"external interrupt",
74e494c7cfSmickey 	"LPMC",
75e494c7cfSmickey 	"ITLB miss fault",
76137d3021Smickey 	"instruction protection",
77137d3021Smickey 	"Illegal instruction",
78137d3021Smickey 	"break instruction",
79137d3021Smickey 	"privileged operation",
80137d3021Smickey 	"privileged register",
81137d3021Smickey 	"overflow",
82137d3021Smickey 	"conditional",
83137d3021Smickey 	"assist exception",
84e494c7cfSmickey 	"DTLB miss",
85137d3021Smickey 	"ITLB non-access miss",
86137d3021Smickey 	"DTLB non-access miss",
87137d3021Smickey 	"data protection/rights/alignment",
88137d3021Smickey 	"data break",
89e494c7cfSmickey 	"TLB dirty",
90137d3021Smickey 	"page reference",
91137d3021Smickey 	"assist emulation",
92e494c7cfSmickey 	"higher-priv transfer",
93e494c7cfSmickey 	"lower-priv transfer",
94137d3021Smickey 	"taken branch",
95137d3021Smickey 	"data access rights",
96e494c7cfSmickey 	"data protection",
97137d3021Smickey 	"unaligned data ref",
98556d2ba7Smickey };
99556d2ba7Smickey int trap_types = sizeof(trap_type)/sizeof(trap_type[0]);
100556d2ba7Smickey 
101556d2ba7Smickey u_int32_t sir;
102bed2d21eSmickey int want_resched, astpending;
103556d2ba7Smickey 
104556d2ba7Smickey void pmap_hptdump __P((void));
105a24c0b7aSmickey void cpu_intr __P((struct trapframe *frame));
106b9b95e0dSmickey void syscall __P((struct trapframe *frame, int *args));
107556d2ba7Smickey 
108d412f1c2Smickey static __inline void
109d412f1c2Smickey userret (struct proc *p, register_t pc, u_quad_t oticks)
110d412f1c2Smickey {
111d412f1c2Smickey 	int sig;
112af7386c3Smickey 
113d412f1c2Smickey 	/* take pending signals */
114d412f1c2Smickey 	while ((sig = CURSIG(p)) != 0)
115d412f1c2Smickey 		postsig(sig);
116d412f1c2Smickey 
117d412f1c2Smickey 	p->p_priority = p->p_usrpri;
118d412f1c2Smickey 	if (want_resched) {
119d412f1c2Smickey 		/*
120*c81336dcSart 		 * We're being preempted.
121d412f1c2Smickey 		 */
122*c81336dcSart 		preempt(NULL);
123d412f1c2Smickey 		while ((sig = CURSIG(p)) != 0)
124d412f1c2Smickey 			postsig(sig);
125d412f1c2Smickey 	}
126d412f1c2Smickey 
127d412f1c2Smickey 	/*
128d412f1c2Smickey 	 * If profiling, charge recent system time to the trapped pc.
129d412f1c2Smickey 	 */
130d412f1c2Smickey 	if (p->p_flag & P_PROFIL) {
131d412f1c2Smickey 		extern int psratio;
132d412f1c2Smickey 
133d412f1c2Smickey 		addupc_task(p, pc, (int)(p->p_sticks - oticks) * psratio);
134d412f1c2Smickey 	}
135d412f1c2Smickey 
136d412f1c2Smickey 	curpriority = p->p_priority;
137d412f1c2Smickey }
138d412f1c2Smickey 
139556d2ba7Smickey void
140556d2ba7Smickey trap(type, frame)
141556d2ba7Smickey 	int type;
142556d2ba7Smickey 	struct trapframe *frame;
143556d2ba7Smickey {
144556d2ba7Smickey 	struct proc *p = curproc;
145137d3021Smickey 	struct pcb *pcbp;
146137d3021Smickey 	register vaddr_t va;
147556d2ba7Smickey 	register vm_map_t map;
148f17fa196Smickey 	struct vmspace *vm;
149af7386c3Smickey 	register vm_prot_t vftype;
150556d2ba7Smickey 	register pa_space_t space;
151a24c0b7aSmickey 	u_int opcode;
152556d2ba7Smickey 	int ret;
153af7386c3Smickey 	union sigval sv;
154a24c0b7aSmickey 	int s, si;
155137d3021Smickey 	const char *tts;
1560e979e06Smickey 
157137d3021Smickey 	opcode = frame->tf_iir;
158a24c0b7aSmickey 	if (type == T_ITLBMISS || type == T_ITLBMISSNA) {
159a24c0b7aSmickey 		va = frame->tf_iioq_head;
160a24c0b7aSmickey 		space = frame->tf_iisq_head;
161532740e6Smickey 		vftype = VM_PROT_READ;	/* XXX VM_PROT_EXECUTE ??? */
162a24c0b7aSmickey 	} else {
163b9b95e0dSmickey 		va = frame->tf_ior;
164a24c0b7aSmickey 		space = frame->tf_isr;
165532740e6Smickey 		vftype = inst_store(opcode) ? VM_PROT_WRITE : VM_PROT_READ;
166556d2ba7Smickey 	}
167137d3021Smickey 
168137d3021Smickey 	if (frame->tf_flags & TFF_LAST)
169137d3021Smickey 		p->p_md.md_regs = frame;
170137d3021Smickey 
171af7386c3Smickey #ifdef TRAPDEBUG
172137d3021Smickey 	if ((type & ~T_USER) > trap_types)
173137d3021Smickey 		tts = "reserved";
174137d3021Smickey 	else
175137d3021Smickey 		tts = trap_type[type & ~T_USER];
176137d3021Smickey 
177e494c7cfSmickey 	if (type != T_INTERRUPT && (type & ~T_USER) != T_IBREAK)
178137d3021Smickey 		db_printf("trap: %d, %s for %x:%x at %x:%x, fl=%x, fp=%p\n",
179137d3021Smickey 		    type, tts, space, va, frame->tf_iisq_head,
180137d3021Smickey 		    frame->tf_iioq_head, frame->tf_flags, frame);
181a24c0b7aSmickey 	else if ((type & ~T_USER) == T_IBREAK)
182137d3021Smickey 		db_printf("trap: break instruction %x:%x at %x:%x, fp=%p\n",
183a24c0b7aSmickey 		    break5(opcode), break13(opcode),
184137d3021Smickey 		    frame->tf_iisq_head, frame->tf_iioq_head, frame);
185e494c7cfSmickey 
186e494c7cfSmickey 	{
187e494c7cfSmickey 		extern int etext;
188532740e6Smickey 		if (frame < (struct trapframe *)&etext) {
189532740e6Smickey 			printf("trap: bogus frame ptr %p\n", frame);
190e494c7cfSmickey 			goto dead_end;
191e494c7cfSmickey 		}
192532740e6Smickey 	}
193d412f1c2Smickey #endif
194556d2ba7Smickey 	switch (type) {
195556d2ba7Smickey 	case T_NONEXIST:
196556d2ba7Smickey 	case T_NONEXIST|T_USER:
197137d3021Smickey #ifndef DDB
198af7386c3Smickey 		/* we've got screwed up by the central scrutinizer */
199137d3021Smickey 		panic ("trap: elvis has just left the building!");
200556d2ba7Smickey 		break;
201532740e6Smickey #else
202532740e6Smickey 		goto dead_end;
203137d3021Smickey #endif
204556d2ba7Smickey 	case T_RECOVERY:
205556d2ba7Smickey 	case T_RECOVERY|T_USER:
206137d3021Smickey #ifndef DDB
207af7386c3Smickey 		/* XXX will implement later */
208556d2ba7Smickey 		printf ("trap: handicapped");
209556d2ba7Smickey 		break;
210532740e6Smickey #else
211532740e6Smickey 		goto dead_end;
212d412f1c2Smickey #endif
21366d1ab7aSmickey 
21466d1ab7aSmickey #ifdef DIAGNOSTIC
21566d1ab7aSmickey 	case T_EXCEPTION:
21666d1ab7aSmickey 		panic("FPU/SFU emulation botch");
21766d1ab7aSmickey 
21866d1ab7aSmickey 		/* these just can't happen ever */
21966d1ab7aSmickey 	case T_PRIV_OP:
22066d1ab7aSmickey 	case T_PRIV_REG:
22166d1ab7aSmickey 		/* these just can't make it to the trap() ever */
22266d1ab7aSmickey 	case T_HPMC:      case T_HPMC | T_USER:
22366d1ab7aSmickey 	case T_EMULATION: case T_EMULATION | T_USER:
22466d1ab7aSmickey #endif
225f4daacd8Smickey 	case T_IBREAK:
226a24c0b7aSmickey 	case T_DATALIGN:
227a24c0b7aSmickey 	case T_DBREAK:
2288de28e3eSmickey 	dead_end:
229a24c0b7aSmickey #ifdef DDB
230532740e6Smickey 		if (kdb_trap (type, va, frame)) {
231a24c0b7aSmickey 			if (type == T_IBREAK) {
232f4daacd8Smickey 				/* skip break instruction */
2338de28e3eSmickey 				frame->tf_iioq_head = frame->tf_iioq_tail;
234f4daacd8Smickey 				frame->tf_iioq_tail += 4;
235a24c0b7aSmickey 			}
236556d2ba7Smickey 			return;
237a24c0b7aSmickey 		}
238137d3021Smickey #else
239137d3021Smickey 		if (type == T_DATALIGN)
240137d3021Smickey 			panic ("trap: %s at 0x%x", tts, va);
241137d3021Smickey 		else
242137d3021Smickey 			panic ("trap: no debugger for \"%s\" (%d)", tts, type);
243a24c0b7aSmickey #endif
244556d2ba7Smickey 		break;
245556d2ba7Smickey 
246af7386c3Smickey 	case T_IBREAK | T_USER:
247af7386c3Smickey 	case T_DBREAK | T_USER:
248af7386c3Smickey 		/* pass to user debugger */
249d412f1c2Smickey 		break;
250d412f1c2Smickey 
251af7386c3Smickey 	case T_EXCEPTION | T_USER:	/* co-proc assist trap */
252137d3021Smickey 		sv.sival_int = va;
253af7386c3Smickey 		trapsignal(p, SIGFPE, type &~ T_USER, FPE_FLTINV, sv);
254d412f1c2Smickey 		break;
255d412f1c2Smickey 
256af7386c3Smickey 	case T_OVERFLOW | T_USER:
257137d3021Smickey 		sv.sival_int = va;
258af7386c3Smickey 		trapsignal(p, SIGFPE, type &~ T_USER, FPE_INTOVF, sv);
259d412f1c2Smickey 		break;
260d412f1c2Smickey 
261af7386c3Smickey 	case T_CONDITION | T_USER:
262af7386c3Smickey 		break;
263af7386c3Smickey 
264af7386c3Smickey 	case T_ILLEGAL | T_USER:
265137d3021Smickey 		sv.sival_int = va;
266af7386c3Smickey 		trapsignal(p, SIGILL, type &~ T_USER, ILL_ILLOPC, sv);
267af7386c3Smickey 		break;
268af7386c3Smickey 
269af7386c3Smickey 	case T_PRIV_OP | T_USER:
270137d3021Smickey 		sv.sival_int = va;
271af7386c3Smickey 		trapsignal(p, SIGILL, type &~ T_USER, ILL_PRVOPC, sv);
272af7386c3Smickey 		break;
273af7386c3Smickey 
274af7386c3Smickey 	case T_PRIV_REG | T_USER:
275137d3021Smickey 		sv.sival_int = va;
276af7386c3Smickey 		trapsignal(p, SIGILL, type &~ T_USER, ILL_PRVREG, sv);
277af7386c3Smickey 		break;
278af7386c3Smickey 
279af7386c3Smickey 		/* these should never got here */
280af7386c3Smickey 	case T_HIGHERPL | T_USER:
281af7386c3Smickey 	case T_LOWERPL | T_USER:
282137d3021Smickey 		sv.sival_int = va;
283af7386c3Smickey 		trapsignal(p, SIGSEGV, type &~ T_USER, SEGV_ACCERR, sv);
284af7386c3Smickey 		break;
285af7386c3Smickey 
286af7386c3Smickey 	case T_IPROT | T_USER:
287af7386c3Smickey 	case T_DPROT | T_USER:
288af7386c3Smickey 		sv.sival_int = va;
289af7386c3Smickey 		trapsignal(p, SIGSEGV, vftype, SEGV_ACCERR, sv);
290af7386c3Smickey 		break;
291af7386c3Smickey 
292ec21eae5Smickey 	case T_DATACC:   	case T_USER | T_DATACC:
293ec21eae5Smickey 	case T_ITLBMISS:	case T_USER | T_ITLBMISS:
294ec21eae5Smickey 	case T_DTLBMISS:	case T_USER | T_DTLBMISS:
295ec21eae5Smickey 	case T_ITLBMISSNA:	case T_USER | T_ITLBMISSNA:
296ec21eae5Smickey 	case T_DTLBMISSNA:	case T_USER | T_DTLBMISSNA:
297ec21eae5Smickey 	case T_TLB_DIRTY:	case T_USER | T_TLB_DIRTY:
298bed2d21eSmickey 		va = hppa_trunc_page(va);
299f17fa196Smickey 		vm = p->p_vmspace;
3008de28e3eSmickey 
301532740e6Smickey 		if (!vm) {
302532740e6Smickey #ifdef TRAPDEBUG
303532740e6Smickey 			printf("trap: no vm, p=%p\n", p);
304532740e6Smickey #endif
3058de28e3eSmickey 			goto dead_end;
306532740e6Smickey 		}
3078de28e3eSmickey 
3088de28e3eSmickey 		/*
309e494c7cfSmickey 		 * it could be a kernel map for exec_map faults
3108de28e3eSmickey 		 */
3118de28e3eSmickey 		if (!(type & T_USER) && space == HPPA_SID_KERNEL)
3128de28e3eSmickey 			map = kernel_map;
3138de28e3eSmickey 		else
314f17fa196Smickey 			map = &vm->vm_map;
315556d2ba7Smickey 
316532740e6Smickey 		if (map->pmap->pmap_space != space) {
317532740e6Smickey #ifdef TRAPDEBUG
318532740e6Smickey 			printf("trap: space missmatch %d != %d\n",
319532740e6Smickey 			    space, map->pmap->pmap_space);
320532740e6Smickey #endif
321532740e6Smickey 			/* actually dump the user, crap the kernel */
322532740e6Smickey 			goto dead_end;
323532740e6Smickey 		}
324532740e6Smickey 
325137d3021Smickey 		ret = uvm_fault(map, va, 0, vftype);
326f17fa196Smickey 
327532740e6Smickey #ifdef TRAPDEBUG
328532740e6Smickey 		printf("uvm_fault(%p, %x, %d, %d)=%d\n",
329532740e6Smickey 		    map, va, 0, vftype, ret);
330532740e6Smickey #endif
331532740e6Smickey 
332f17fa196Smickey 		/*
333f17fa196Smickey 		 * If this was a stack access we keep track of the maximum
334f17fa196Smickey 		 * accessed stack size.  Also, if uvm_fault gets a protection
335f17fa196Smickey 		 * failure it is due to accessing the stack region outside
336f17fa196Smickey 		 * the current limit and we need to reflect that as an access
337f17fa196Smickey 		 * error.
338f17fa196Smickey 		 */
339f17fa196Smickey 		if (va >= (vaddr_t)vm->vm_maxsaddr + vm->vm_ssize) {
340f17fa196Smickey 			if (ret == KERN_SUCCESS) {
341c7ba784cSart 				vsize_t nss = btoc(va - USRSTACK + NBPG);
342f17fa196Smickey 				if (nss > vm->vm_ssize)
343f17fa196Smickey 					vm->vm_ssize = nss;
344f17fa196Smickey 			} else if (ret == KERN_PROTECTION_FAILURE)
345f17fa196Smickey 				ret = KERN_INVALID_ADDRESS;
346f17fa196Smickey 		}
347f17fa196Smickey 
348af7386c3Smickey 		if (ret != KERN_SUCCESS) {
349af7386c3Smickey 			if (type & T_USER) {
350137d3021Smickey printf("trapsignal: uvm_fault\n");
351af7386c3Smickey 				sv.sival_int = frame->tf_ior;
352af7386c3Smickey 				trapsignal(p, SIGSEGV, vftype, SEGV_MAPERR, sv);
353137d3021Smickey 			} else {
3548de28e3eSmickey 				if (p && p->p_addr->u_pcb.pcb_onfault) {
3558de28e3eSmickey #ifdef PMAPDEBUG
3568de28e3eSmickey 					printf("trap: copyin/out %d\n",ret);
357137d3021Smickey #endif
3588de28e3eSmickey 					pcbp = &p->p_addr->u_pcb;
3598de28e3eSmickey 					frame->tf_iioq_tail = 4 +
3608de28e3eSmickey 					    (frame->tf_iioq_head =
3618de28e3eSmickey 						pcbp->pcb_onfault);
362137d3021Smickey 					pcbp->pcb_onfault = 0;
363137d3021Smickey 					break;
364af7386c3Smickey 				}
365137d3021Smickey #if 1
366532740e6Smickey if (kdb_trap (type, va, frame))
367137d3021Smickey 	return;
368137d3021Smickey #else
369137d3021Smickey 				panic("trap: uvm_fault(%p, %x, %d, %d): %d",
3702191603aSmickey 				    map, va, 0, vftype, ret);
371137d3021Smickey #endif
372137d3021Smickey 			}
373137d3021Smickey 		}
374556d2ba7Smickey 		break;
375d412f1c2Smickey 
376af7386c3Smickey 	case T_DATALIGN | T_USER:
377137d3021Smickey 		sv.sival_int = va;
378af7386c3Smickey 		trapsignal(p, SIGBUS, vftype, BUS_ADRALN, sv);
379af7386c3Smickey 		break;
380af7386c3Smickey 
381a24c0b7aSmickey 	case T_INTERRUPT:
382a24c0b7aSmickey 	case T_INTERRUPT|T_USER:
383f48ce072Smickey 		frame->tf_flags |= TFF_INTR;
384a24c0b7aSmickey 		cpu_intr(frame);
385137d3021Smickey #if 0
386532740e6Smickey if (kdb_trap (type, va, frame))
387137d3021Smickey return;
388137d3021Smickey #endif
389a24c0b7aSmickey 		/* FALLTHROUGH */
390af7386c3Smickey 	case T_LOWERPL:
391a24c0b7aSmickey 		__asm __volatile ("ldcws 0(%1), %0"
392a24c0b7aSmickey 				  : "=r" (si) : "r" (&sir));
393af7386c3Smickey 		s = spl0();
394a24c0b7aSmickey 		if (si & SIR_CLOCK) {
395af7386c3Smickey 			splclock();
396af7386c3Smickey 			softclock();
397af7386c3Smickey 			spl0();
398af7386c3Smickey 		}
399af7386c3Smickey 
400a24c0b7aSmickey 		if (si & SIR_NET) {
401af7386c3Smickey 			register int ni;
402af7386c3Smickey 			/* use atomic "load & clear" */
403af7386c3Smickey 			__asm __volatile ("ldcws 0(%1), %0"
404af7386c3Smickey 					  : "=r" (ni) : "r" (&netisr));
405af7386c3Smickey 			splnet();
406d136e661Smickey #define	DONETISR(m,c) if (ni & (1 << (m))) c()
407d136e661Smickey #include <net/netisr_dispatch.h>
408af7386c3Smickey 		}
409af7386c3Smickey 		splx(s);
410af7386c3Smickey 		break;
411af7386c3Smickey 
4122ef9a47eSmickey 	case T_DPROT:
4132ef9a47eSmickey 	case T_IPROT:
414af7386c3Smickey 	case T_OVERFLOW:
415af7386c3Smickey 	case T_CONDITION:
416af7386c3Smickey 	case T_ILLEGAL:
417af7386c3Smickey 	case T_HIGHERPL:
418af7386c3Smickey 	case T_TAKENBR:
419af7386c3Smickey 	case T_POWERFAIL:
420af7386c3Smickey 	case T_LPMC:
421af7386c3Smickey 	case T_PAGEREF:
422d412f1c2Smickey 	case T_DATAPID:  	case T_DATAPID  | T_USER:
423d412f1c2Smickey 		if (0 /* T-chip */) {
424d412f1c2Smickey 			break;
425556d2ba7Smickey 		}
426d412f1c2Smickey 		/* FALLTHROUGH to unimplemented */
427d412f1c2Smickey 	default:
428137d3021Smickey #if 1
429532740e6Smickey if (kdb_trap (type, va, frame))
430137d3021Smickey 	return;
431137d3021Smickey #endif
432137d3021Smickey 		panic ("trap: unimplemented \'%s\' (%d)", tts, type);
433d412f1c2Smickey 	}
434af7386c3Smickey 
435af7386c3Smickey 	if (type & T_USER)
436af7386c3Smickey 		userret(p, p->p_md.md_regs->tf_iioq_head, 0);
437d412f1c2Smickey }
438d412f1c2Smickey 
439d412f1c2Smickey void
440d412f1c2Smickey child_return(p)
441d412f1c2Smickey 	struct proc *p;
442d412f1c2Smickey {
443d412f1c2Smickey 	userret(p, p->p_md.md_regs->tf_iioq_head, 0);
444d412f1c2Smickey #ifdef KTRACE
445d412f1c2Smickey 	if (KTRPOINT(p, KTR_SYSRET))
446a27b30d8Sart 		ktrsysret(p, SYS_fork, 0, 0);
447d412f1c2Smickey #endif
448556d2ba7Smickey }
449556d2ba7Smickey 
450b9b95e0dSmickey /*
451b9b95e0dSmickey  * call actual syscall routine
452b9b95e0dSmickey  * from the low-level syscall handler:
453b9b95e0dSmickey  * - all HPPA_FRAME_NARGS syscall's arguments supposed to be copied onto
454b9b95e0dSmickey  *   our stack, this wins compared to copyin just needed amount anyway
455b9b95e0dSmickey  * - register args are copied onto stack too
456b9b95e0dSmickey  */
457b9b95e0dSmickey void
458b9b95e0dSmickey syscall(frame, args)
459b9b95e0dSmickey 	struct trapframe *frame;
460b9b95e0dSmickey 	int *args;
461b9b95e0dSmickey {
462b9b95e0dSmickey 	register struct proc *p;
463b9b95e0dSmickey 	register const struct sysent *callp;
464b9b95e0dSmickey 	int nsys, code, argsize, error;
465b9b95e0dSmickey 	int rval[2];
466b9b95e0dSmickey 
467b9b95e0dSmickey 	uvmexp.syscalls++;
468b9b95e0dSmickey 
469b9b95e0dSmickey 	if (!USERMODE(frame->tf_iioq_head))
470b9b95e0dSmickey 		panic("syscall");
471b9b95e0dSmickey 
472b9b95e0dSmickey 	p = curproc;
473137d3021Smickey 	p->p_md.md_regs = frame;
474b9b95e0dSmickey 	nsys = p->p_emul->e_nsysent;
475b9b95e0dSmickey 	callp = p->p_emul->e_sysent;
476137d3021Smickey 	code = frame->tf_t1;
477b9b95e0dSmickey 	switch (code) {
478b9b95e0dSmickey 	case SYS_syscall:
479532740e6Smickey 		code = *args;
480b9b95e0dSmickey 		args += 1;
481b9b95e0dSmickey 		break;
482b9b95e0dSmickey 	case SYS___syscall:
483b9b95e0dSmickey 		if (callp != sysent)
484b9b95e0dSmickey 			break;
485532740e6Smickey 		code = *args;
486b9b95e0dSmickey 		args += 2;
487b9b95e0dSmickey 	}
488b9b95e0dSmickey 
489b9b95e0dSmickey 	if (code < 0 || code >= nsys)
490b9b95e0dSmickey 		callp += p->p_emul->e_nosys;	/* bad syscall # */
491b9b95e0dSmickey 	else
492b9b95e0dSmickey 		callp += code;
493b9b95e0dSmickey 	argsize = callp->sy_argsize;
494b9b95e0dSmickey 
495b9b95e0dSmickey #ifdef SYSCALL_DEBUG
496b9b95e0dSmickey 	scdebug_call(p, code, args);
497b9b95e0dSmickey #endif
498b9b95e0dSmickey #ifdef KTRACE
499b9b95e0dSmickey 	if (KTRPOINT(p, KTR_SYSCALL))
500a27b30d8Sart 		ktrsyscall(p, code, argsize, args);
501b9b95e0dSmickey #endif
502b9b95e0dSmickey 
503b9b95e0dSmickey 	rval[0] = 0;
504b9b95e0dSmickey 	rval[1] = 0;
505b9b95e0dSmickey 	switch (error = (*callp->sy_call)(p, args, rval)) {
506b9b95e0dSmickey 	case 0:
507532740e6Smickey 		p = curproc;			/* changes on exec() */
508532740e6Smickey 		frame = p->p_md.md_regs;
509b9b95e0dSmickey 		frame->tf_ret0 = rval[0];
510b9b95e0dSmickey 		frame->tf_ret1 = rval[1];
511137d3021Smickey 		frame->tf_t1 = 0;
512b9b95e0dSmickey 		break;
513b9b95e0dSmickey 	case ERESTART:
514b9b95e0dSmickey 		frame->tf_iioq_head -= 4; /* right? XXX */
515532740e6Smickey 		frame->tf_iioq_tail -= 4; /* right? XXX */
516b9b95e0dSmickey 		break;
517b9b95e0dSmickey 	case EJUSTRETURN:
518532740e6Smickey 		p = curproc;
519b9b95e0dSmickey 		break;
520b9b95e0dSmickey 	default:
521b9b95e0dSmickey 		if (p->p_emul->e_errno)
522b9b95e0dSmickey 			error = p->p_emul->e_errno[error];
523137d3021Smickey 		frame->tf_t1 = error;
524b9b95e0dSmickey 		break;
525b9b95e0dSmickey 	}
526b9b95e0dSmickey #ifdef SYSCALL_DEBUG
527b9b95e0dSmickey 	scdebug_ret(p, code, error, rval);
528b9b95e0dSmickey #endif
529532740e6Smickey 	userret(p, frame->tf_iioq_head, 0);
530b9b95e0dSmickey #ifdef KTRACE
531b9b95e0dSmickey 	if (KTRPOINT(p, KTR_SYSRET))
532a27b30d8Sart 		ktrsysret(p, code, error, rval[0]);
533b9b95e0dSmickey #endif
534b9b95e0dSmickey }
535b9b95e0dSmickey 
536556d2ba7Smickey /* all the interrupts, minus cpu clock, which is the last */
537556d2ba7Smickey struct cpu_intr_vector {
5383a81311eSmickey 	struct evcnt evcnt;
539556d2ba7Smickey 	int pri;
540556d2ba7Smickey 	int (*handler) __P((void *));
541556d2ba7Smickey 	void *arg;
542a24c0b7aSmickey } cpu_intr_vectors[CPU_NINTS];
543556d2ba7Smickey 
544b9b95e0dSmickey void *
5453a81311eSmickey cpu_intr_establish(pri, irq, handler, arg, dv)
546b9b95e0dSmickey 	int pri, irq;
547556d2ba7Smickey 	int (*handler) __P((void *));
548556d2ba7Smickey 	void *arg;
5493a81311eSmickey 	struct device *dv;
550556d2ba7Smickey {
5513a81311eSmickey 	register struct cpu_intr_vector *iv;
552556d2ba7Smickey 
553a24c0b7aSmickey 	if (0 <= irq && irq < CPU_NINTS && cpu_intr_vectors[irq].handler)
554b9b95e0dSmickey 		return NULL;
555556d2ba7Smickey 
5563a81311eSmickey 	iv = &cpu_intr_vectors[irq];
5573a81311eSmickey 	iv->pri = pri;
5583a81311eSmickey 	iv->handler = handler;
5593a81311eSmickey 	iv->arg = arg;
560688a8060Smickey 	evcnt_attach(dv, dv->dv_xname, &iv->evcnt);
561556d2ba7Smickey 
562688a8060Smickey 	return iv;
563556d2ba7Smickey }
564556d2ba7Smickey 
565556d2ba7Smickey void
566a24c0b7aSmickey cpu_intr(frame)
567556d2ba7Smickey 	struct trapframe *frame;
568556d2ba7Smickey {
569b9b95e0dSmickey 	u_int32_t eirr;
5703a81311eSmickey 	register struct cpu_intr_vector *iv;
571556d2ba7Smickey 	register int bit;
572556d2ba7Smickey 
573556d2ba7Smickey 	do {
574b9b95e0dSmickey 		mfctl(CR_EIRR, eirr);
575a24c0b7aSmickey 		eirr &= frame->tf_eiem;
576b9b95e0dSmickey 		bit = ffs(eirr) - 1;
577556d2ba7Smickey 		if (bit >= 0) {
578556d2ba7Smickey 			mtctl(1 << bit, CR_EIRR);
579b9b95e0dSmickey 			eirr &= ~(1 << bit);
580b9b95e0dSmickey 			/* ((struct iomod *)cpu_gethpa(0))->io_eir = 0; */
581556d2ba7Smickey #ifdef INTRDEBUG
582a24c0b7aSmickey 			if (bit != 31)
583137d3021Smickey 				db_printf ("cpu_intr: 0x%08x\n", (1 << bit));
584556d2ba7Smickey #endif
5853a81311eSmickey 			iv = &cpu_intr_vectors[bit];
5863a81311eSmickey 			if (iv->handler) {
587688a8060Smickey 				register int s, r;
5883a81311eSmickey 
5893a81311eSmickey 				iv->evcnt.ev_count++;
590688a8060Smickey 				s = splx(iv->pri);
5917cd4d71fSmickey 				/* no arg means pass the frame */
592688a8060Smickey 				r = (iv->handler)(iv->arg? iv->arg:frame);
593688a8060Smickey 				splx(s);
594532740e6Smickey #ifdef INTRDEBUG
595688a8060Smickey 				if (!r)
596137d3021Smickey 					db_printf ("%s: can't handle interrupt\n",
597688a8060Smickey 						   iv->evcnt.ev_name);
598b9b95e0dSmickey #endif
599532740e6Smickey 			}
600532740e6Smickey #ifdef INTRDEBUG
601532740e6Smickey 			else
602137d3021Smickey 				db_printf ("cpu_intr: stray interrupt %d\n", bit);
603532740e6Smickey #endif
604b9b95e0dSmickey 		}
605b9b95e0dSmickey 	} while (eirr);
606556d2ba7Smickey }
607