xref: /openbsd/sys/arch/hppa/hppa/trap.c (revision 906a25e0)
1*906a25e0Smickey /*	$OpenBSD: trap.c,v 1.58 2003/01/09 20:48:56 mickey Exp $	*/
2556d2ba7Smickey 
3556d2ba7Smickey /*
4*906a25e0Smickey  * Copyright (c) 1998-2003 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
26*906a25e0Smickey  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF MIND,
27*906a25e0Smickey  * USE, 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 
33ce94da48Smickey /* #define TRAPDEBUG */
34556d2ba7Smickey 
35556d2ba7Smickey #include <sys/param.h>
36556d2ba7Smickey #include <sys/systm.h>
37b9b95e0dSmickey #include <sys/syscall.h>
38b9b95e0dSmickey #include <sys/ktrace.h>
39d412f1c2Smickey #include <sys/proc.h>
406acb4cb0Sniklas #include <sys/signalvar.h>
41d412f1c2Smickey #include <sys/user.h>
42556d2ba7Smickey 
43af7386c3Smickey #include <net/netisr.h>
44af7386c3Smickey 
4596a1071fSmiod #include "systrace.h"
4696a1071fSmiod #include <dev/systrace.h>
4796a1071fSmiod 
48b9b95e0dSmickey #include <uvm/uvm.h>
49556d2ba7Smickey 
50556d2ba7Smickey #include <machine/autoconf.h>
51556d2ba7Smickey 
52137d3021Smickey #ifdef DDB
53137d3021Smickey #include <machine/db_machdep.h>
549d159c9dSmickey #ifdef TRAPDEBUG
55137d3021Smickey #include <ddb/db_output.h>
56137d3021Smickey #endif
579d159c9dSmickey #endif
58556d2ba7Smickey 
59556d2ba7Smickey const char *trap_type[] = {
60e494c7cfSmickey 	"invalid",
61e494c7cfSmickey 	"HPMC",
62556d2ba7Smickey 	"power failure",
63137d3021Smickey 	"recovery counter",
64556d2ba7Smickey 	"external interrupt",
65e494c7cfSmickey 	"LPMC",
66e494c7cfSmickey 	"ITLB miss fault",
67137d3021Smickey 	"instruction protection",
68137d3021Smickey 	"Illegal instruction",
69137d3021Smickey 	"break instruction",
70137d3021Smickey 	"privileged operation",
71137d3021Smickey 	"privileged register",
72137d3021Smickey 	"overflow",
73137d3021Smickey 	"conditional",
74137d3021Smickey 	"assist exception",
75e494c7cfSmickey 	"DTLB miss",
76137d3021Smickey 	"ITLB non-access miss",
77137d3021Smickey 	"DTLB non-access miss",
78137d3021Smickey 	"data protection/rights/alignment",
79137d3021Smickey 	"data break",
80e494c7cfSmickey 	"TLB dirty",
81137d3021Smickey 	"page reference",
82137d3021Smickey 	"assist emulation",
83e494c7cfSmickey 	"higher-priv transfer",
84e494c7cfSmickey 	"lower-priv transfer",
85137d3021Smickey 	"taken branch",
86137d3021Smickey 	"data access rights",
87e494c7cfSmickey 	"data protection",
88137d3021Smickey 	"unaligned data ref",
89556d2ba7Smickey };
90556d2ba7Smickey int trap_types = sizeof(trap_type)/sizeof(trap_type[0]);
91556d2ba7Smickey 
92bed2d21eSmickey int want_resched, astpending;
93556d2ba7Smickey 
9470016991Smickey void
95d412f1c2Smickey userret(struct proc *p, register_t pc, u_quad_t oticks)
96d412f1c2Smickey {
97d412f1c2Smickey 	int sig;
98af7386c3Smickey 
99d412f1c2Smickey 	/* take pending signals */
100d412f1c2Smickey 	while ((sig = CURSIG(p)) != 0)
101d412f1c2Smickey 		postsig(sig);
102d412f1c2Smickey 
103d412f1c2Smickey 	p->p_priority = p->p_usrpri;
10470016991Smickey 	if (astpending) {
10570016991Smickey 		astpending = 0;
10670016991Smickey 		if (p->p_flag & P_OWEUPC) {
10770016991Smickey 			p->p_flag &= ~P_OWEUPC;
10870016991Smickey 			ADDUPROF(p);
10970016991Smickey 		}
11070016991Smickey 	}
111d412f1c2Smickey 	if (want_resched) {
112d412f1c2Smickey 		/*
113c81336dcSart 		 * We're being preempted.
114d412f1c2Smickey 		 */
115c81336dcSart 		preempt(NULL);
116d412f1c2Smickey 		while ((sig = CURSIG(p)) != 0)
117d412f1c2Smickey 			postsig(sig);
118d412f1c2Smickey 	}
119d412f1c2Smickey 
120d412f1c2Smickey 	/*
121d412f1c2Smickey 	 * If profiling, charge recent system time to the trapped pc.
122d412f1c2Smickey 	 */
123d412f1c2Smickey 	if (p->p_flag & P_PROFIL) {
124d412f1c2Smickey 		extern int psratio;
125d412f1c2Smickey 
126d412f1c2Smickey 		addupc_task(p, pc, (int)(p->p_sticks - oticks) * psratio);
127d412f1c2Smickey 	}
128d412f1c2Smickey 
129d412f1c2Smickey 	curpriority = p->p_priority;
130d412f1c2Smickey }
131d412f1c2Smickey 
132556d2ba7Smickey void
133556d2ba7Smickey trap(type, frame)
134556d2ba7Smickey 	int type;
135556d2ba7Smickey 	struct trapframe *frame;
136556d2ba7Smickey {
137556d2ba7Smickey 	struct proc *p = curproc;
138ab8e80c5Sart 	vaddr_t va;
139ab8e80c5Sart 	struct vm_map *map;
140f17fa196Smickey 	struct vmspace *vm;
141af7386c3Smickey 	register vm_prot_t vftype;
142556d2ba7Smickey 	register pa_space_t space;
143af7386c3Smickey 	union sigval sv;
144c37e03c6Smickey 	u_int opcode;
14570016991Smickey 	int ret, trapnum;
146137d3021Smickey 	const char *tts;
1476198d067Smickey 	vm_fault_t fault = VM_FAULT_INVALID;
14870016991Smickey #ifdef DIAGNOSTIC
14970016991Smickey 	int oldcpl = cpl;
15070016991Smickey #endif
1510e979e06Smickey 
152c37e03c6Smickey 	trapnum = type & ~T_USER;
153137d3021Smickey 	opcode = frame->tf_iir;
154969eb289Smickey 	if (trapnum == T_ITLBMISS ||
155969eb289Smickey 	    trapnum == T_EXCEPTION || trapnum == T_EMULATION) {
156a24c0b7aSmickey 		va = frame->tf_iioq_head;
157a24c0b7aSmickey 		space = frame->tf_iisq_head;
1584c15bc47Smickey 		vftype = VM_PROT_EXECUTE;
159a24c0b7aSmickey 	} else {
160b9b95e0dSmickey 		va = frame->tf_ior;
161a24c0b7aSmickey 		space = frame->tf_isr;
1626198d067Smickey 		/* what is the vftype for the T_ITLBMISSNA ??? XXX */
163a4be06b3Smickey 		if (va == frame->tf_iioq_head)
164a4be06b3Smickey 			vftype = VM_PROT_EXECUTE;
165a4be06b3Smickey 		else if (inst_store(opcode))
166a4be06b3Smickey 			vftype = VM_PROT_WRITE;
167a4be06b3Smickey 		else
168a4be06b3Smickey 			vftype = VM_PROT_READ;
169556d2ba7Smickey 	}
170137d3021Smickey 
171137d3021Smickey 	if (frame->tf_flags & TFF_LAST)
172137d3021Smickey 		p->p_md.md_regs = frame;
173137d3021Smickey 
174af7386c3Smickey #ifdef TRAPDEBUG
175c37e03c6Smickey 	if (trapnum > trap_types)
176137d3021Smickey 		tts = "reserved";
177137d3021Smickey 	else
178c37e03c6Smickey 		tts = trap_type[trapnum];
179137d3021Smickey 
180c37e03c6Smickey 	if (trapnum != T_INTERRUPT && trapnum != T_IBREAK)
181969c5366Smickey 		db_printf("trap: %x, %s for %x:%x at %x:%x, fl=%x, fp=%p\n",
182137d3021Smickey 		    type, tts, space, va, frame->tf_iisq_head,
183137d3021Smickey 		    frame->tf_iioq_head, frame->tf_flags, frame);
184c37e03c6Smickey 	else if (trapnum  == T_IBREAK)
185137d3021Smickey 		db_printf("trap: break instruction %x:%x at %x:%x, fp=%p\n",
186a24c0b7aSmickey 		    break5(opcode), break13(opcode),
187137d3021Smickey 		    frame->tf_iisq_head, frame->tf_iioq_head, frame);
188e494c7cfSmickey 
189e494c7cfSmickey 	{
190e494c7cfSmickey 		extern int etext;
191532740e6Smickey 		if (frame < (struct trapframe *)&etext) {
192532740e6Smickey 			printf("trap: bogus frame ptr %p\n", frame);
193e494c7cfSmickey 			goto dead_end;
194e494c7cfSmickey 		}
195532740e6Smickey 	}
196d412f1c2Smickey #endif
19770016991Smickey 	if (trapnum != T_INTERRUPT)
19870016991Smickey 		mtctl(frame->tf_eiem, CR_EIEM);
19970016991Smickey 
200556d2ba7Smickey 	switch (type) {
201556d2ba7Smickey 	case T_NONEXIST:
202556d2ba7Smickey 	case T_NONEXIST|T_USER:
203af7386c3Smickey 		/* we've got screwed up by the central scrutinizer */
204b67578d8Smickey 		printf("trap: elvis has just left the building!\n");
205532740e6Smickey 		goto dead_end;
206b67578d8Smickey 
207556d2ba7Smickey 	case T_RECOVERY:
208556d2ba7Smickey 	case T_RECOVERY|T_USER:
209af7386c3Smickey 		/* XXX will implement later */
210556d2ba7Smickey 		printf("trap: handicapped");
211532740e6Smickey 		goto dead_end;
21266d1ab7aSmickey 
21366d1ab7aSmickey #ifdef DIAGNOSTIC
21466d1ab7aSmickey 	case T_EXCEPTION:
21566d1ab7aSmickey 		panic("FPU/SFU emulation botch");
21666d1ab7aSmickey 
21766d1ab7aSmickey 		/* these just can't happen ever */
21866d1ab7aSmickey 	case T_PRIV_OP:
21966d1ab7aSmickey 	case T_PRIV_REG:
22066d1ab7aSmickey 		/* these just can't make it to the trap() ever */
22166d1ab7aSmickey 	case T_HPMC:      case T_HPMC | T_USER:
22266d1ab7aSmickey #endif
223f4daacd8Smickey 	case T_IBREAK:
224a24c0b7aSmickey 	case T_DATALIGN:
225a24c0b7aSmickey 	case T_DBREAK:
2268de28e3eSmickey 	dead_end:
227a24c0b7aSmickey #ifdef DDB
228532740e6Smickey 		if (kdb_trap (type, va, frame)) {
229a24c0b7aSmickey 			if (type == T_IBREAK) {
230f4daacd8Smickey 				/* skip break instruction */
2318de28e3eSmickey 				frame->tf_iioq_head = frame->tf_iioq_tail;
232f4daacd8Smickey 				frame->tf_iioq_tail += 4;
233a24c0b7aSmickey 			}
234556d2ba7Smickey 			return;
235a24c0b7aSmickey 		}
236137d3021Smickey #else
237137d3021Smickey 		if (type == T_DATALIGN)
238137d3021Smickey 			panic ("trap: %s at 0x%x", tts, va);
239137d3021Smickey 		else
240137d3021Smickey 			panic ("trap: no debugger for \"%s\" (%d)", tts, type);
241a24c0b7aSmickey #endif
242556d2ba7Smickey 		break;
243556d2ba7Smickey 
244af7386c3Smickey 	case T_IBREAK | T_USER:
245b67578d8Smickey 		/* XXX */
246b67578d8Smickey 		frame->tf_iioq_head = frame->tf_iioq_tail;
247b67578d8Smickey 		frame->tf_iioq_tail += 4;
248af7386c3Smickey 	case T_DBREAK | T_USER:
249af7386c3Smickey 		/* pass to user debugger */
250d412f1c2Smickey 		break;
251d412f1c2Smickey 
25238575cbdSmickey 	case T_EXCEPTION | T_USER: {
253969eb289Smickey 		u_int64_t *fpp = (u_int64_t *)frame->tf_cr30;
254969eb289Smickey 		u_int32_t *pex;
25538575cbdSmickey 		int i, flt;
25638575cbdSmickey 
257969eb289Smickey 		pex = (u_int32_t *)&fpp[0];
25838575cbdSmickey 		for (i = 0, pex++; i < 7 && !*pex; i++, pex++);
259969eb289Smickey 		flt = 0;
260969eb289Smickey 		if (i < 7) {
261969eb289Smickey 			u_int32_t stat = HPPA_FPU_OP(*pex);
262969eb289Smickey 			if (stat == HPPA_FPU_UNMPL)
263969eb289Smickey 				flt = FPE_FLTINV;
264969eb289Smickey 			else if (stat & HPPA_FPU_V)
26538575cbdSmickey 				flt = FPE_FLTINV;
26638575cbdSmickey 			else if (stat & HPPA_FPU_Z)
26738575cbdSmickey 				flt = FPE_FLTDIV;
268969eb289Smickey 			else if (stat & HPPA_FPU_I)
269969eb289Smickey 				flt = FPE_FLTRES;
27038575cbdSmickey 			else if (stat & HPPA_FPU_O)
27138575cbdSmickey 				flt = FPE_FLTOVF;
27238575cbdSmickey 			else if (stat & HPPA_FPU_U)
27338575cbdSmickey 				flt = FPE_FLTUND;
274969eb289Smickey 			/* still left: under/over-flow w/ inexact */
27538575cbdSmickey 			*pex = 0;
276969eb289Smickey 		}
277969eb289Smickey 		/* reset the trap flag, as if there was none */
278969eb289Smickey 		fpp[0] &= ~(((u_int64_t)HPPA_FPU_T) << 32);
279969eb289Smickey 		/* flush out, since load is done from phys, only 4 regs */
280969eb289Smickey 		fdcache(HPPA_SID_KERNEL, (vaddr_t)fpp, 8 * 4);
28138575cbdSmickey 
28238575cbdSmickey 		sv.sival_int = va;
28338575cbdSmickey 		trapsignal(p, SIGFPE, type &~ T_USER, flt, sv);
28438575cbdSmickey 		}
28538575cbdSmickey 		break;
28638575cbdSmickey 
287969eb289Smickey 	case T_EMULATION:
288969eb289Smickey 		panic("trap: emulation trap in the kernel");
289969eb289Smickey 		break;
290969eb289Smickey 
291969eb289Smickey 	case T_EMULATION | T_USER:
292137d3021Smickey 		sv.sival_int = va;
293969eb289Smickey 		trapsignal(p, SIGILL, type &~ T_USER, ILL_ILLOPC, sv);
294d412f1c2Smickey 		break;
295d412f1c2Smickey 
296af7386c3Smickey 	case T_OVERFLOW | T_USER:
297137d3021Smickey 		sv.sival_int = va;
298af7386c3Smickey 		trapsignal(p, SIGFPE, type &~ T_USER, FPE_INTOVF, sv);
299d412f1c2Smickey 		break;
300d412f1c2Smickey 
301af7386c3Smickey 	case T_CONDITION | T_USER:
302af7386c3Smickey 		break;
303af7386c3Smickey 
304af7386c3Smickey 	case T_ILLEGAL | T_USER:
305137d3021Smickey 		sv.sival_int = va;
306af7386c3Smickey 		trapsignal(p, SIGILL, type &~ T_USER, ILL_ILLOPC, sv);
307af7386c3Smickey 		break;
308af7386c3Smickey 
309af7386c3Smickey 	case T_PRIV_OP | T_USER:
310137d3021Smickey 		sv.sival_int = va;
311af7386c3Smickey 		trapsignal(p, SIGILL, type &~ T_USER, ILL_PRVOPC, sv);
312af7386c3Smickey 		break;
313af7386c3Smickey 
314af7386c3Smickey 	case T_PRIV_REG | T_USER:
315137d3021Smickey 		sv.sival_int = va;
316af7386c3Smickey 		trapsignal(p, SIGILL, type &~ T_USER, ILL_PRVREG, sv);
317af7386c3Smickey 		break;
318af7386c3Smickey 
319af7386c3Smickey 		/* these should never got here */
320af7386c3Smickey 	case T_HIGHERPL | T_USER:
321af7386c3Smickey 	case T_LOWERPL | T_USER:
322137d3021Smickey 		sv.sival_int = va;
323a4be06b3Smickey 		trapsignal(p, SIGSEGV, vftype, SEGV_ACCERR, sv);
324af7386c3Smickey 		break;
325af7386c3Smickey 
326af7386c3Smickey 	case T_IPROT | T_USER:
327af7386c3Smickey 	case T_DPROT | T_USER:
328af7386c3Smickey 		sv.sival_int = va;
329af7386c3Smickey 		trapsignal(p, SIGSEGV, vftype, SEGV_ACCERR, sv);
330af7386c3Smickey 		break;
331af7386c3Smickey 
332ec21eae5Smickey 	case T_DATACC:   	case T_USER | T_DATACC:
3336198d067Smickey 		fault = VM_FAULT_PROTECT;
334ec21eae5Smickey 	case T_ITLBMISS:	case T_USER | T_ITLBMISS:
335ec21eae5Smickey 	case T_DTLBMISS:	case T_USER | T_DTLBMISS:
336ec21eae5Smickey 	case T_ITLBMISSNA:	case T_USER | T_ITLBMISSNA:
337ec21eae5Smickey 	case T_DTLBMISSNA:	case T_USER | T_DTLBMISSNA:
338ec21eae5Smickey 	case T_TLB_DIRTY:	case T_USER | T_TLB_DIRTY:
339b67578d8Smickey 		/*
340b67578d8Smickey 		 * user faults out of user addr space are always a fail,
341b67578d8Smickey 		 * this happens on va >= VM_MAXUSER_ADDRESS, where
342b67578d8Smickey 		 * space id will be zero and therefore cause
343b67578d8Smickey 		 * a misbehave lower in the code.
344b67578d8Smickey 		 */
345b67578d8Smickey 		if (type & T_USER && va >= VM_MAXUSER_ADDRESS) {
346b67578d8Smickey 			sv.sival_int = va;
347*906a25e0Smickey 			trapsignal(p, SIGSEGV, vftype, SEGV_ACCERR, sv);
348b67578d8Smickey 			break;
349b67578d8Smickey 		}
3508de28e3eSmickey 
351b67578d8Smickey 		if (!(vm = p->p_vmspace)) {
352532740e6Smickey 			printf("trap: no vm, p=%p\n", p);
3538de28e3eSmickey 			goto dead_end;
354532740e6Smickey 		}
3558de28e3eSmickey 
3568de28e3eSmickey 		/*
357e494c7cfSmickey 		 * it could be a kernel map for exec_map faults
3588de28e3eSmickey 		 */
3598de28e3eSmickey 		if (!(type & T_USER) && space == HPPA_SID_KERNEL)
3608de28e3eSmickey 			map = kernel_map;
3618de28e3eSmickey 		else
362f17fa196Smickey 			map = &vm->vm_map;
363556d2ba7Smickey 
364a228f8d2Smickey 		if (map->pmap->pm_space != space) {
365*906a25e0Smickey 			if (map->pmap->pm_space != HPPA_SID_KERNEL) {
366*906a25e0Smickey 				sv.sival_int = va;
367*906a25e0Smickey 				trapsignal(p, SIGSEGV, vftype, SEGV_MAPERR, sv);
368*906a25e0Smickey 			} else {
369532740e6Smickey 				printf("trap: space missmatch %d != %d\n",
370a228f8d2Smickey 				    space, map->pmap->pm_space);
371532740e6Smickey 				goto dead_end;
372532740e6Smickey 			}
373*906a25e0Smickey 		}
374532740e6Smickey 
375ce94da48Smickey #ifdef TRAPDEBUG
376ce94da48Smickey 		if (space == -1) {
377ce94da48Smickey 			extern int pmapdebug;
378ce94da48Smickey 			pmapdebug = 0xffffff;
379ce94da48Smickey 		}
380ce94da48Smickey #endif
381a4be06b3Smickey 		ret = uvm_fault(map, hppa_trunc_page(va), fault, vftype);
382f17fa196Smickey 
383532740e6Smickey #ifdef TRAPDEBUG
384ce94da48Smickey 		if (space == -1) {
385ce94da48Smickey 			extern int pmapdebug;
386ce94da48Smickey 			pmapdebug = 0;
387ce94da48Smickey 		}
388ce94da48Smickey 
389532740e6Smickey 		printf("uvm_fault(%p, %x, %d, %d)=%d\n",
390532740e6Smickey 		    map, va, 0, vftype, ret);
391532740e6Smickey #endif
392532740e6Smickey 
393f17fa196Smickey 		/*
394f17fa196Smickey 		 * If this was a stack access we keep track of the maximum
395f17fa196Smickey 		 * accessed stack size.  Also, if uvm_fault gets a protection
396f17fa196Smickey 		 * failure it is due to accessing the stack region outside
397f17fa196Smickey 		 * the current limit and we need to reflect that as an access
398f17fa196Smickey 		 * error.
399f17fa196Smickey 		 */
400d74aa24bSmickey 		if (space != 0 && va < (vaddr_t)vm->vm_minsaddr &&
401d74aa24bSmickey 		    va >= (vaddr_t)vm->vm_maxsaddr + ctob(vm->vm_ssize)) {
402738a5b4dSart 			if (ret == 0) {
403a4be06b3Smickey 				vsize_t nss = btoc(va - USRSTACK + NBPG - 1);
404f17fa196Smickey 				if (nss > vm->vm_ssize)
405f17fa196Smickey 					vm->vm_ssize = nss;
406738a5b4dSart 			} else if (ret == EACCES)
407738a5b4dSart 				ret = EFAULT;
408f17fa196Smickey 		}
409f17fa196Smickey 
410738a5b4dSart 		if (ret != 0) {
411af7386c3Smickey 			if (type & T_USER) {
412a4be06b3Smickey 				sv.sival_int = va;
413a4be06b3Smickey 				trapsignal(p, SIGSEGV, vftype,
414a4be06b3Smickey 				    ret == EACCES? SEGV_ACCERR : SEGV_MAPERR,
415a4be06b3Smickey 				    sv);
416137d3021Smickey 			} else {
4178de28e3eSmickey 				if (p && p->p_addr->u_pcb.pcb_onfault) {
4188de28e3eSmickey 					frame->tf_iioq_tail = 4 +
4198de28e3eSmickey 					    (frame->tf_iioq_head =
42038575cbdSmickey 						p->p_addr->u_pcb.pcb_onfault);
421b04f760fSmickey #ifdef DDB
422b04f760fSmickey 					frame->tf_iir = 0;
423b04f760fSmickey #endif
424db97f33bSmickey 				} else {
425db97f33bSmickey 					panic("trap: "
426db97f33bSmickey 					    "uvm_fault(%p, %x, %d, %d): %d",
4272191603aSmickey 					    map, va, 0, vftype, ret);
428137d3021Smickey 				}
429137d3021Smickey 			}
430db97f33bSmickey 		}
431556d2ba7Smickey 		break;
432d412f1c2Smickey 
433af7386c3Smickey 	case T_DATALIGN | T_USER:
434137d3021Smickey 		sv.sival_int = va;
435af7386c3Smickey 		trapsignal(p, SIGBUS, vftype, BUS_ADRALN, sv);
436af7386c3Smickey 		break;
437af7386c3Smickey 
438a24c0b7aSmickey 	case T_INTERRUPT:
439a24c0b7aSmickey 	case T_INTERRUPT|T_USER:
440a24c0b7aSmickey 		cpu_intr(frame);
441af7386c3Smickey 		break;
442af7386c3Smickey 
443b7d25a19Smickey 	case T_CONDITION:
444b7d25a19Smickey 		panic("trap: divide by zero in the kernel");
445b7d25a19Smickey 		break;
446b7d25a19Smickey 
44770016991Smickey 	case T_LOWERPL:
4482ef9a47eSmickey 	case T_DPROT:
4492ef9a47eSmickey 	case T_IPROT:
450af7386c3Smickey 	case T_OVERFLOW:
451af7386c3Smickey 	case T_ILLEGAL:
452af7386c3Smickey 	case T_HIGHERPL:
453af7386c3Smickey 	case T_TAKENBR:
454af7386c3Smickey 	case T_POWERFAIL:
455af7386c3Smickey 	case T_LPMC:
456af7386c3Smickey 	case T_PAGEREF:
457d412f1c2Smickey 	case T_DATAPID:  	case T_DATAPID  | T_USER:
458d412f1c2Smickey 		if (0 /* T-chip */) {
459d412f1c2Smickey 			break;
460556d2ba7Smickey 		}
461d412f1c2Smickey 		/* FALLTHROUGH to unimplemented */
462d412f1c2Smickey 	default:
463a228f8d2Smickey #if 0
464532740e6Smickey if (kdb_trap (type, va, frame))
465137d3021Smickey 	return;
466137d3021Smickey #endif
46770016991Smickey 		panic("trap: unimplemented \'%s\' (%d)", tts, trapnum);
468d412f1c2Smickey 	}
469af7386c3Smickey 
47070016991Smickey #ifdef DIAGNOSTIC
47170016991Smickey 	if (cpl != oldcpl)
47270016991Smickey 		printf("WARNING: SPL (%d) NOT LOWERED ON "
47370016991Smickey 		    "TRAP (%d) EXIT\n", cpl, trapnum);
47470016991Smickey #endif
47570016991Smickey 
47670016991Smickey 	if (trapnum != T_INTERRUPT)
47770016991Smickey 		splx(cpl);	/* process softints */
47870016991Smickey 
479af7386c3Smickey 	if (type & T_USER)
48070016991Smickey 		userret(p, frame->tf_iioq_head, 0);
481d412f1c2Smickey }
482d412f1c2Smickey 
483d412f1c2Smickey void
484db36253aSmickey child_return(arg)
485db36253aSmickey 	void *arg;
486d412f1c2Smickey {
487db36253aSmickey 	struct proc *p = (struct proc *)arg;
488d412f1c2Smickey 	userret(p, p->p_md.md_regs->tf_iioq_head, 0);
489d412f1c2Smickey #ifdef KTRACE
490d412f1c2Smickey 	if (KTRPOINT(p, KTR_SYSRET))
491a27b30d8Sart 		ktrsysret(p, SYS_fork, 0, 0);
492d412f1c2Smickey #endif
493556d2ba7Smickey }
494556d2ba7Smickey 
495db97f33bSmickey 
496b9b95e0dSmickey /*
497b9b95e0dSmickey  * call actual syscall routine
498b9b95e0dSmickey  */
499b9b95e0dSmickey void
50070016991Smickey syscall(struct trapframe *frame)
501b9b95e0dSmickey {
502db97f33bSmickey 	register struct proc *p = curproc;
503b9b95e0dSmickey 	register const struct sysent *callp;
504b7d25a19Smickey 	int retq, nsys, code, argsize, argoff, oerror, error;
505b7d25a19Smickey 	register_t args[8], rval[2];
50670016991Smickey #ifdef DIAGNOSTIC
50770016991Smickey 	int oldcpl = cpl;
50870016991Smickey #endif
509b9b95e0dSmickey 
510b9b95e0dSmickey 	uvmexp.syscalls++;
511b9b95e0dSmickey 
512b9b95e0dSmickey 	if (!USERMODE(frame->tf_iioq_head))
513b9b95e0dSmickey 		panic("syscall");
514b9b95e0dSmickey 
515137d3021Smickey 	p->p_md.md_regs = frame;
516b9b95e0dSmickey 	nsys = p->p_emul->e_nsysent;
517b9b95e0dSmickey 	callp = p->p_emul->e_sysent;
518db97f33bSmickey 
519b7d25a19Smickey 	argoff = 4; retq = 0;
520db97f33bSmickey 	switch (code = frame->tf_t1) {
521b9b95e0dSmickey 	case SYS_syscall:
522db97f33bSmickey 		code = frame->tf_arg0;
523db97f33bSmickey 		args[0] = frame->tf_arg1;
524db97f33bSmickey 		args[1] = frame->tf_arg2;
525db97f33bSmickey 		args[2] = frame->tf_arg3;
526db97f33bSmickey 		argoff = 3;
527b9b95e0dSmickey 		break;
528b9b95e0dSmickey 	case SYS___syscall:
529b9b95e0dSmickey 		if (callp != sysent)
530b9b95e0dSmickey 			break;
531db97f33bSmickey 		/*
532db97f33bSmickey 		 * this works, because quads get magically swapped
533db97f33bSmickey 		 * due to the args being layed backwards on the stack
534db97f33bSmickey 		 * and then copied in words
535db97f33bSmickey 		 */
536db97f33bSmickey 		code = frame->tf_arg0;
537db97f33bSmickey 		args[0] = frame->tf_arg2;
538db97f33bSmickey 		args[1] = frame->tf_arg3;
539db97f33bSmickey 		argoff = 2;
540b7d25a19Smickey 		retq = 1;
541db97f33bSmickey 		break;
542db97f33bSmickey 	default:
543db97f33bSmickey 		args[0] = frame->tf_arg0;
544db97f33bSmickey 		args[1] = frame->tf_arg1;
545db97f33bSmickey 		args[2] = frame->tf_arg2;
546db97f33bSmickey 		args[3] = frame->tf_arg3;
547db97f33bSmickey 		break;
548b9b95e0dSmickey 	}
549b9b95e0dSmickey 
550b9b95e0dSmickey 	if (code < 0 || code >= nsys)
551b9b95e0dSmickey 		callp += p->p_emul->e_nosys;	/* bad syscall # */
552b9b95e0dSmickey 	else
553b9b95e0dSmickey 		callp += code;
554db97f33bSmickey 
555db97f33bSmickey 	oerror = error = 0;
556db97f33bSmickey 	if ((argsize = callp->sy_argsize)) {
557db97f33bSmickey 		int i;
558db97f33bSmickey 
559db97f33bSmickey 		for (i = 0, argsize -= argoff * 4;
560db97f33bSmickey 		    argsize > 0; i++, argsize -= 4) {
561db97f33bSmickey 			error = copyin((void *)(frame->tf_sp +
562db97f33bSmickey 			    HPPA_FRAME_ARG(i + 4)), args + i + argoff, 4);
563db97f33bSmickey 
564db97f33bSmickey 			if (error)
565db97f33bSmickey 				break;
566db97f33bSmickey 		}
567db97f33bSmickey 
568db97f33bSmickey 		/*
569db97f33bSmickey 		 * coming from syscall() or __syscall we must be
570db97f33bSmickey 		 * having one of those w/ a 64 bit arguments,
571db97f33bSmickey 		 * which needs a word swap due to the order
572db97f33bSmickey 		 * of the arguments on the stack.
573db97f33bSmickey 		 * this assumes that none of 'em are called
574db97f33bSmickey 		 * by their normal syscall number, maybe a regress
575db97f33bSmickey 		 * test should be used, to whatch the behaviour.
576db97f33bSmickey 		 */
577db97f33bSmickey 		if (!error && argoff < 4) {
578db97f33bSmickey 			int t;
579db97f33bSmickey 
580db97f33bSmickey 			i = 0;
581db97f33bSmickey 			switch (code) {
582b7d25a19Smickey 			case SYS_lseek:		retq = 0;
583db97f33bSmickey 			case SYS_truncate:
584db97f33bSmickey 			case SYS_ftruncate:	i = 2;	break;
585db97f33bSmickey 			case SYS_preadv:
586db97f33bSmickey 			case SYS_pwritev:
587db97f33bSmickey 			case SYS_pread:
588db97f33bSmickey 			case SYS_pwrite:	i = 4;	break;
589db97f33bSmickey 			case SYS_mmap:		i = 6;	break;
590db97f33bSmickey 			}
591db97f33bSmickey 
592db97f33bSmickey 			if (i) {
593db97f33bSmickey 				t = args[i];
594db97f33bSmickey 				args[i] = args[i + 1];
595db97f33bSmickey 				args[i + 1] = t;
596db97f33bSmickey 			}
597db97f33bSmickey 		}
598db97f33bSmickey 	}
599b9b95e0dSmickey 
600b9b95e0dSmickey #ifdef SYSCALL_DEBUG
601b9b95e0dSmickey 	scdebug_call(p, code, args);
602b9b95e0dSmickey #endif
603b9b95e0dSmickey #ifdef KTRACE
604b9b95e0dSmickey 	if (KTRPOINT(p, KTR_SYSCALL))
605d970adb6Smickey 		ktrsyscall(p, code, callp->sy_argsize, args);
606b9b95e0dSmickey #endif
607db97f33bSmickey 	if (error)
608db97f33bSmickey 		goto bad;
609b9b95e0dSmickey 
610b9b95e0dSmickey 	rval[0] = 0;
611db97f33bSmickey 	rval[1] = frame->tf_ret1;
61296a1071fSmiod #if NSYSTRACE > 0
61396a1071fSmiod 	if (ISSET(p->p_flag, P_SYSTRACE))
614db97f33bSmickey 		oerror = error = systrace_redirect(code, p, args, rval);
61596a1071fSmiod 	else
61696a1071fSmiod #endif
617db97f33bSmickey 		oerror = error = (*callp->sy_call)(p, args, rval);
61896a1071fSmiod 	switch (error) {
619b9b95e0dSmickey 	case 0:
620532740e6Smickey 		p = curproc;			/* changes on exec() */
621532740e6Smickey 		frame = p->p_md.md_regs;
622b9b95e0dSmickey 		frame->tf_ret0 = rval[0];
623b7d25a19Smickey 		frame->tf_ret1 = rval[!retq];
624137d3021Smickey 		frame->tf_t1 = 0;
625b9b95e0dSmickey 		break;
626b9b95e0dSmickey 	case ERESTART:
627c37e03c6Smickey 		frame->tf_iioq_head -= 12;
628c37e03c6Smickey 		frame->tf_iioq_tail -= 12;
629b9b95e0dSmickey 		break;
630b9b95e0dSmickey 	case EJUSTRETURN:
631532740e6Smickey 		p = curproc;
632b7d25a19Smickey 		frame = p->p_md.md_regs;
633b9b95e0dSmickey 		break;
634b9b95e0dSmickey 	default:
635db97f33bSmickey 	bad:
636b9b95e0dSmickey 		if (p->p_emul->e_errno)
637b9b95e0dSmickey 			error = p->p_emul->e_errno[error];
638137d3021Smickey 		frame->tf_t1 = error;
639b9b95e0dSmickey 		break;
640b9b95e0dSmickey 	}
641b9b95e0dSmickey #ifdef SYSCALL_DEBUG
642db97f33bSmickey 	scdebug_ret(p, code, oerror, rval);
643b9b95e0dSmickey #endif
644532740e6Smickey 	userret(p, frame->tf_iioq_head, 0);
64570016991Smickey 	splx(cpl);	/* process softints */
646b9b95e0dSmickey #ifdef KTRACE
647b9b95e0dSmickey 	if (KTRPOINT(p, KTR_SYSRET))
648db97f33bSmickey 		ktrsysret(p, code, oerror, rval[0]);
649b9b95e0dSmickey #endif
65070016991Smickey #ifdef DIAGNOSTIC
65170016991Smickey 	if (cpl != oldcpl)
65270016991Smickey 		printf("WARNING: SPL (0x%x) NOT LOWERED ON "
65370016991Smickey 		    "syscall(0x%x, 0x%x, 0x%x, 0x%x...) EXIT, PID %d\n",
65470016991Smickey 		    cpl, code, args[0], args[1], args[2], p->p_pid);
65570016991Smickey #endif
656b9b95e0dSmickey }
657