xref: /openbsd/sys/arch/hppa/hppa/trap.c (revision 446209b7)
1*446209b7Smiod /*	$OpenBSD: trap.c,v 1.62 2003/02/25 14:04:09 miod Exp $	*/
2556d2ba7Smickey 
3556d2ba7Smickey /*
4906a25e0Smickey  * 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
26906a25e0Smickey  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF MIND,
27906a25e0Smickey  * 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 
523867ea13Smiod #include <machine/db_machdep.h>	/* XXX always needed for inst_store() */
53137d3021Smickey #ifdef DDB
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;
158e21aaa8cSmickey 		vftype = UVM_PROT_EXEC;
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)
164e21aaa8cSmickey 			vftype = UVM_PROT_EXEC;
165a4be06b3Smickey 		else if (inst_store(opcode))
166e21aaa8cSmickey 			vftype = UVM_PROT_WRITE;
167a4be06b3Smickey 		else
168e21aaa8cSmickey 			vftype = UVM_PROT_READ;
169556d2ba7Smickey 	}
170137d3021Smickey 
171137d3021Smickey 	if (frame->tf_flags & TFF_LAST)
172137d3021Smickey 		p->p_md.md_regs = frame;
173137d3021Smickey 
174c37e03c6Smickey 	if (trapnum > trap_types)
175137d3021Smickey 		tts = "reserved";
176137d3021Smickey 	else
177c37e03c6Smickey 		tts = trap_type[trapnum];
178137d3021Smickey 
179*446209b7Smiod #ifdef TRAPDEBUG
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 */
221c6555f83Sderaadt 	case T_HPMC:
222c6555f83Sderaadt 	case T_HPMC | T_USER:
22366d1ab7aSmickey #endif
224f4daacd8Smickey 	case T_IBREAK:
225a24c0b7aSmickey 	case T_DATALIGN:
226a24c0b7aSmickey 	case T_DBREAK:
2278de28e3eSmickey 	dead_end:
228a24c0b7aSmickey #ifdef DDB
229532740e6Smickey 		if (kdb_trap (type, va, frame)) {
230a24c0b7aSmickey 			if (type == T_IBREAK) {
231f4daacd8Smickey 				/* skip break instruction */
2328de28e3eSmickey 				frame->tf_iioq_head = frame->tf_iioq_tail;
233f4daacd8Smickey 				frame->tf_iioq_tail += 4;
234a24c0b7aSmickey 			}
235556d2ba7Smickey 			return;
236a24c0b7aSmickey 		}
237137d3021Smickey #else
238137d3021Smickey 		if (type == T_DATALIGN)
239137d3021Smickey 			panic ("trap: %s at 0x%x", tts, va);
240137d3021Smickey 		else
241137d3021Smickey 			panic ("trap: no debugger for \"%s\" (%d)", tts, type);
242a24c0b7aSmickey #endif
243556d2ba7Smickey 		break;
244556d2ba7Smickey 
245af7386c3Smickey 	case T_IBREAK | T_USER:
246b67578d8Smickey 		/* XXX */
247b67578d8Smickey 		frame->tf_iioq_head = frame->tf_iioq_tail;
248b67578d8Smickey 		frame->tf_iioq_tail += 4;
249af7386c3Smickey 	case T_DBREAK | T_USER:
250af7386c3Smickey 		/* pass to user debugger */
251d412f1c2Smickey 		break;
252d412f1c2Smickey 
25338575cbdSmickey 	case T_EXCEPTION | T_USER: {
254969eb289Smickey 		u_int64_t *fpp = (u_int64_t *)frame->tf_cr30;
255969eb289Smickey 		u_int32_t *pex;
25638575cbdSmickey 		int i, flt;
25738575cbdSmickey 
258969eb289Smickey 		pex = (u_int32_t *)&fpp[0];
25938575cbdSmickey 		for (i = 0, pex++; i < 7 && !*pex; i++, pex++);
260969eb289Smickey 		flt = 0;
261969eb289Smickey 		if (i < 7) {
262969eb289Smickey 			u_int32_t stat = HPPA_FPU_OP(*pex);
263969eb289Smickey 			if (stat == HPPA_FPU_UNMPL)
264969eb289Smickey 				flt = FPE_FLTINV;
265969eb289Smickey 			else if (stat & HPPA_FPU_V)
26638575cbdSmickey 				flt = FPE_FLTINV;
26738575cbdSmickey 			else if (stat & HPPA_FPU_Z)
26838575cbdSmickey 				flt = FPE_FLTDIV;
269969eb289Smickey 			else if (stat & HPPA_FPU_I)
270969eb289Smickey 				flt = FPE_FLTRES;
27138575cbdSmickey 			else if (stat & HPPA_FPU_O)
27238575cbdSmickey 				flt = FPE_FLTOVF;
27338575cbdSmickey 			else if (stat & HPPA_FPU_U)
27438575cbdSmickey 				flt = FPE_FLTUND;
275969eb289Smickey 			/* still left: under/over-flow w/ inexact */
27638575cbdSmickey 			*pex = 0;
277969eb289Smickey 		}
278969eb289Smickey 		/* reset the trap flag, as if there was none */
279969eb289Smickey 		fpp[0] &= ~(((u_int64_t)HPPA_FPU_T) << 32);
280969eb289Smickey 		/* flush out, since load is done from phys, only 4 regs */
281969eb289Smickey 		fdcache(HPPA_SID_KERNEL, (vaddr_t)fpp, 8 * 4);
28238575cbdSmickey 
28338575cbdSmickey 		sv.sival_int = va;
28438575cbdSmickey 		trapsignal(p, SIGFPE, type &~ T_USER, flt, sv);
28538575cbdSmickey 		}
28638575cbdSmickey 		break;
28738575cbdSmickey 
288969eb289Smickey 	case T_EMULATION:
289969eb289Smickey 		panic("trap: emulation trap in the kernel");
290969eb289Smickey 		break;
291969eb289Smickey 
292969eb289Smickey 	case T_EMULATION | T_USER:
293137d3021Smickey 		sv.sival_int = va;
294969eb289Smickey 		trapsignal(p, SIGILL, type &~ T_USER, ILL_ILLOPC, sv);
295d412f1c2Smickey 		break;
296d412f1c2Smickey 
297af7386c3Smickey 	case T_OVERFLOW | T_USER:
298137d3021Smickey 		sv.sival_int = va;
299af7386c3Smickey 		trapsignal(p, SIGFPE, type &~ T_USER, FPE_INTOVF, sv);
300d412f1c2Smickey 		break;
301d412f1c2Smickey 
302af7386c3Smickey 	case T_CONDITION | T_USER:
303af7386c3Smickey 		break;
304af7386c3Smickey 
305af7386c3Smickey 	case T_ILLEGAL | T_USER:
306137d3021Smickey 		sv.sival_int = va;
307af7386c3Smickey 		trapsignal(p, SIGILL, type &~ T_USER, ILL_ILLOPC, sv);
308af7386c3Smickey 		break;
309af7386c3Smickey 
310af7386c3Smickey 	case T_PRIV_OP | T_USER:
311137d3021Smickey 		sv.sival_int = va;
312af7386c3Smickey 		trapsignal(p, SIGILL, type &~ T_USER, ILL_PRVOPC, sv);
313af7386c3Smickey 		break;
314af7386c3Smickey 
315af7386c3Smickey 	case T_PRIV_REG | T_USER:
316137d3021Smickey 		sv.sival_int = va;
317af7386c3Smickey 		trapsignal(p, SIGILL, type &~ T_USER, ILL_PRVREG, sv);
318af7386c3Smickey 		break;
319af7386c3Smickey 
320af7386c3Smickey 		/* these should never got here */
321af7386c3Smickey 	case T_HIGHERPL | T_USER:
322af7386c3Smickey 	case T_LOWERPL | T_USER:
323137d3021Smickey 		sv.sival_int = va;
324a4be06b3Smickey 		trapsignal(p, SIGSEGV, vftype, SEGV_ACCERR, sv);
325af7386c3Smickey 		break;
326af7386c3Smickey 
327af7386c3Smickey 	case T_IPROT | T_USER:
328af7386c3Smickey 	case T_DPROT | T_USER:
329af7386c3Smickey 		sv.sival_int = va;
330af7386c3Smickey 		trapsignal(p, SIGSEGV, vftype, SEGV_ACCERR, sv);
331af7386c3Smickey 		break;
332af7386c3Smickey 
333c6555f83Sderaadt 	case T_DATACC:
334c6555f83Sderaadt 	case T_DATACC | T_USER:
3356198d067Smickey 		fault = VM_FAULT_PROTECT;
336c6555f83Sderaadt 	case T_ITLBMISS:
337c6555f83Sderaadt 	case T_ITLBMISS | T_USER:
338c6555f83Sderaadt 	case T_DTLBMISS:
339c6555f83Sderaadt 	case T_DTLBMISS | T_USER:
340c6555f83Sderaadt 	case T_ITLBMISSNA:
341c6555f83Sderaadt 	case T_ITLBMISSNA | T_USER:
342c6555f83Sderaadt 	case T_DTLBMISSNA:
343c6555f83Sderaadt 	case T_DTLBMISSNA | T_USER:
344c6555f83Sderaadt 	case T_TLB_DIRTY:
345c6555f83Sderaadt 	case T_TLB_DIRTY | T_USER:
346b67578d8Smickey 		/*
347b67578d8Smickey 		 * user faults out of user addr space are always a fail,
348b67578d8Smickey 		 * this happens on va >= VM_MAXUSER_ADDRESS, where
349b67578d8Smickey 		 * space id will be zero and therefore cause
350b67578d8Smickey 		 * a misbehave lower in the code.
351b67578d8Smickey 		 */
352b67578d8Smickey 		if (type & T_USER && va >= VM_MAXUSER_ADDRESS) {
353b67578d8Smickey 			sv.sival_int = va;
354906a25e0Smickey 			trapsignal(p, SIGSEGV, vftype, SEGV_ACCERR, sv);
355b67578d8Smickey 			break;
356b67578d8Smickey 		}
3578de28e3eSmickey 
358b67578d8Smickey 		if (!(vm = p->p_vmspace)) {
359532740e6Smickey 			printf("trap: no vm, p=%p\n", p);
3608de28e3eSmickey 			goto dead_end;
361532740e6Smickey 		}
3628de28e3eSmickey 
3638de28e3eSmickey 		/*
364e494c7cfSmickey 		 * it could be a kernel map for exec_map faults
3658de28e3eSmickey 		 */
3668de28e3eSmickey 		if (!(type & T_USER) && space == HPPA_SID_KERNEL)
3678de28e3eSmickey 			map = kernel_map;
3688de28e3eSmickey 		else
369f17fa196Smickey 			map = &vm->vm_map;
370556d2ba7Smickey 
371a228f8d2Smickey 		if (map->pmap->pm_space != space) {
372906a25e0Smickey 			if (map->pmap->pm_space != HPPA_SID_KERNEL) {
373906a25e0Smickey 				sv.sival_int = va;
374906a25e0Smickey 				trapsignal(p, SIGSEGV, vftype, SEGV_MAPERR, sv);
375906a25e0Smickey 			} else {
376532740e6Smickey 				printf("trap: space missmatch %d != %d\n",
377a228f8d2Smickey 				    space, map->pmap->pm_space);
378532740e6Smickey 				goto dead_end;
379532740e6Smickey 			}
380906a25e0Smickey 		}
381532740e6Smickey 
382ce94da48Smickey #ifdef TRAPDEBUG
383ce94da48Smickey 		if (space == -1) {
384ce94da48Smickey 			extern int pmapdebug;
385ce94da48Smickey 			pmapdebug = 0xffffff;
386ce94da48Smickey 		}
387ce94da48Smickey #endif
388a4be06b3Smickey 		ret = uvm_fault(map, hppa_trunc_page(va), fault, vftype);
389f17fa196Smickey 
390532740e6Smickey #ifdef TRAPDEBUG
391ce94da48Smickey 		if (space == -1) {
392ce94da48Smickey 			extern int pmapdebug;
393ce94da48Smickey 			pmapdebug = 0;
394ce94da48Smickey 		}
395ce94da48Smickey 
396532740e6Smickey 		printf("uvm_fault(%p, %x, %d, %d)=%d\n",
397532740e6Smickey 		    map, va, 0, vftype, ret);
398532740e6Smickey #endif
399532740e6Smickey 
400f17fa196Smickey 		/*
401f17fa196Smickey 		 * If this was a stack access we keep track of the maximum
402f17fa196Smickey 		 * accessed stack size.  Also, if uvm_fault gets a protection
403f17fa196Smickey 		 * failure it is due to accessing the stack region outside
404f17fa196Smickey 		 * the current limit and we need to reflect that as an access
405f17fa196Smickey 		 * error.
406f17fa196Smickey 		 */
407d74aa24bSmickey 		if (space != 0 && va < (vaddr_t)vm->vm_minsaddr &&
408d74aa24bSmickey 		    va >= (vaddr_t)vm->vm_maxsaddr + ctob(vm->vm_ssize)) {
409738a5b4dSart 			if (ret == 0) {
410a4be06b3Smickey 				vsize_t nss = btoc(va - USRSTACK + NBPG - 1);
411f17fa196Smickey 				if (nss > vm->vm_ssize)
412f17fa196Smickey 					vm->vm_ssize = nss;
413738a5b4dSart 			} else if (ret == EACCES)
414738a5b4dSart 				ret = EFAULT;
415f17fa196Smickey 		}
416f17fa196Smickey 
417738a5b4dSart 		if (ret != 0) {
418af7386c3Smickey 			if (type & T_USER) {
419a4be06b3Smickey 				sv.sival_int = va;
420a4be06b3Smickey 				trapsignal(p, SIGSEGV, vftype,
421a4be06b3Smickey 				    ret == EACCES? SEGV_ACCERR : SEGV_MAPERR,
422a4be06b3Smickey 				    sv);
423137d3021Smickey 			} else {
4248de28e3eSmickey 				if (p && p->p_addr->u_pcb.pcb_onfault) {
4258de28e3eSmickey 					frame->tf_iioq_tail = 4 +
4268de28e3eSmickey 					    (frame->tf_iioq_head =
42738575cbdSmickey 						p->p_addr->u_pcb.pcb_onfault);
428b04f760fSmickey #ifdef DDB
429b04f760fSmickey 					frame->tf_iir = 0;
430b04f760fSmickey #endif
431db97f33bSmickey 				} else {
432db97f33bSmickey 					panic("trap: "
433db97f33bSmickey 					    "uvm_fault(%p, %x, %d, %d): %d",
4342191603aSmickey 					    map, va, 0, vftype, ret);
435137d3021Smickey 				}
436137d3021Smickey 			}
437db97f33bSmickey 		}
438556d2ba7Smickey 		break;
439d412f1c2Smickey 
440af7386c3Smickey 	case T_DATALIGN | T_USER:
441137d3021Smickey 		sv.sival_int = va;
442af7386c3Smickey 		trapsignal(p, SIGBUS, vftype, BUS_ADRALN, sv);
443af7386c3Smickey 		break;
444af7386c3Smickey 
445a24c0b7aSmickey 	case T_INTERRUPT:
446a24c0b7aSmickey 	case T_INTERRUPT | T_USER:
447a24c0b7aSmickey 		cpu_intr(frame);
448af7386c3Smickey 		break;
449af7386c3Smickey 
450b7d25a19Smickey 	case T_CONDITION:
451b7d25a19Smickey 		panic("trap: divide by zero in the kernel");
452b7d25a19Smickey 		break;
453b7d25a19Smickey 
45470016991Smickey 	case T_LOWERPL:
4552ef9a47eSmickey 	case T_DPROT:
4562ef9a47eSmickey 	case T_IPROT:
457af7386c3Smickey 	case T_OVERFLOW:
458af7386c3Smickey 	case T_ILLEGAL:
459af7386c3Smickey 	case T_HIGHERPL:
460af7386c3Smickey 	case T_TAKENBR:
461af7386c3Smickey 	case T_POWERFAIL:
462af7386c3Smickey 	case T_LPMC:
463af7386c3Smickey 	case T_PAGEREF:
464c6555f83Sderaadt 	case T_DATAPID:
465c6555f83Sderaadt 	case T_DATAPID | T_USER:
466d412f1c2Smickey 		if (0 /* T-chip */) {
467d412f1c2Smickey 			break;
468556d2ba7Smickey 		}
469d412f1c2Smickey 		/* FALLTHROUGH to unimplemented */
470d412f1c2Smickey 	default:
471a228f8d2Smickey #if 0
472532740e6Smickey if (kdb_trap (type, va, frame))
473137d3021Smickey 	return;
474137d3021Smickey #endif
47570016991Smickey 		panic("trap: unimplemented \'%s\' (%d)", tts, trapnum);
476d412f1c2Smickey 	}
477af7386c3Smickey 
47870016991Smickey #ifdef DIAGNOSTIC
47970016991Smickey 	if (cpl != oldcpl)
48070016991Smickey 		printf("WARNING: SPL (%d) NOT LOWERED ON "
48170016991Smickey 		    "TRAP (%d) EXIT\n", cpl, trapnum);
48270016991Smickey #endif
48370016991Smickey 
48470016991Smickey 	if (trapnum != T_INTERRUPT)
48570016991Smickey 		splx(cpl);	/* process softints */
48670016991Smickey 
487af7386c3Smickey 	if (type & T_USER)
48870016991Smickey 		userret(p, frame->tf_iioq_head, 0);
489d412f1c2Smickey }
490d412f1c2Smickey 
491d412f1c2Smickey void
492db36253aSmickey child_return(arg)
493db36253aSmickey 	void *arg;
494d412f1c2Smickey {
495db36253aSmickey 	struct proc *p = (struct proc *)arg;
496d412f1c2Smickey 	userret(p, p->p_md.md_regs->tf_iioq_head, 0);
497d412f1c2Smickey #ifdef KTRACE
498d412f1c2Smickey 	if (KTRPOINT(p, KTR_SYSRET))
499a27b30d8Sart 		ktrsysret(p, SYS_fork, 0, 0);
500d412f1c2Smickey #endif
501556d2ba7Smickey }
502556d2ba7Smickey 
503db97f33bSmickey 
504b9b95e0dSmickey /*
505b9b95e0dSmickey  * call actual syscall routine
506b9b95e0dSmickey  */
507b9b95e0dSmickey void
50870016991Smickey syscall(struct trapframe *frame)
509b9b95e0dSmickey {
510db97f33bSmickey 	register struct proc *p = curproc;
511b9b95e0dSmickey 	register const struct sysent *callp;
512b7d25a19Smickey 	int retq, nsys, code, argsize, argoff, oerror, error;
513b7d25a19Smickey 	register_t args[8], rval[2];
51470016991Smickey #ifdef DIAGNOSTIC
51570016991Smickey 	int oldcpl = cpl;
51670016991Smickey #endif
517b9b95e0dSmickey 
518b9b95e0dSmickey 	uvmexp.syscalls++;
519b9b95e0dSmickey 
520b9b95e0dSmickey 	if (!USERMODE(frame->tf_iioq_head))
521b9b95e0dSmickey 		panic("syscall");
522b9b95e0dSmickey 
523137d3021Smickey 	p->p_md.md_regs = frame;
524b9b95e0dSmickey 	nsys = p->p_emul->e_nsysent;
525b9b95e0dSmickey 	callp = p->p_emul->e_sysent;
526db97f33bSmickey 
527b7d25a19Smickey 	argoff = 4; retq = 0;
528db97f33bSmickey 	switch (code = frame->tf_t1) {
529b9b95e0dSmickey 	case SYS_syscall:
530db97f33bSmickey 		code = frame->tf_arg0;
531db97f33bSmickey 		args[0] = frame->tf_arg1;
532db97f33bSmickey 		args[1] = frame->tf_arg2;
533db97f33bSmickey 		args[2] = frame->tf_arg3;
534db97f33bSmickey 		argoff = 3;
535b9b95e0dSmickey 		break;
536b9b95e0dSmickey 	case SYS___syscall:
537b9b95e0dSmickey 		if (callp != sysent)
538b9b95e0dSmickey 			break;
539db97f33bSmickey 		/*
540db97f33bSmickey 		 * this works, because quads get magically swapped
541db97f33bSmickey 		 * due to the args being layed backwards on the stack
542db97f33bSmickey 		 * and then copied in words
543db97f33bSmickey 		 */
544db97f33bSmickey 		code = frame->tf_arg0;
545db97f33bSmickey 		args[0] = frame->tf_arg2;
546db97f33bSmickey 		args[1] = frame->tf_arg3;
547db97f33bSmickey 		argoff = 2;
548b7d25a19Smickey 		retq = 1;
549db97f33bSmickey 		break;
550db97f33bSmickey 	default:
551db97f33bSmickey 		args[0] = frame->tf_arg0;
552db97f33bSmickey 		args[1] = frame->tf_arg1;
553db97f33bSmickey 		args[2] = frame->tf_arg2;
554db97f33bSmickey 		args[3] = frame->tf_arg3;
555db97f33bSmickey 		break;
556b9b95e0dSmickey 	}
557b9b95e0dSmickey 
558b9b95e0dSmickey 	if (code < 0 || code >= nsys)
559b9b95e0dSmickey 		callp += p->p_emul->e_nosys;	/* bad syscall # */
560b9b95e0dSmickey 	else
561b9b95e0dSmickey 		callp += code;
562db97f33bSmickey 
563db97f33bSmickey 	oerror = error = 0;
564db97f33bSmickey 	if ((argsize = callp->sy_argsize)) {
565db97f33bSmickey 		int i;
566db97f33bSmickey 
567db97f33bSmickey 		for (i = 0, argsize -= argoff * 4;
568db97f33bSmickey 		    argsize > 0; i++, argsize -= 4) {
569db97f33bSmickey 			error = copyin((void *)(frame->tf_sp +
570db97f33bSmickey 			    HPPA_FRAME_ARG(i + 4)), args + i + argoff, 4);
571db97f33bSmickey 
572db97f33bSmickey 			if (error)
573db97f33bSmickey 				break;
574db97f33bSmickey 		}
575db97f33bSmickey 
576db97f33bSmickey 		/*
577db97f33bSmickey 		 * coming from syscall() or __syscall we must be
578db97f33bSmickey 		 * having one of those w/ a 64 bit arguments,
579db97f33bSmickey 		 * which needs a word swap due to the order
580db97f33bSmickey 		 * of the arguments on the stack.
581db97f33bSmickey 		 * this assumes that none of 'em are called
582db97f33bSmickey 		 * by their normal syscall number, maybe a regress
583db97f33bSmickey 		 * test should be used, to whatch the behaviour.
584db97f33bSmickey 		 */
585db97f33bSmickey 		if (!error && argoff < 4) {
586db97f33bSmickey 			int t;
587db97f33bSmickey 
588db97f33bSmickey 			i = 0;
589db97f33bSmickey 			switch (code) {
590b7d25a19Smickey 			case SYS_lseek:		retq = 0;
591db97f33bSmickey 			case SYS_truncate:
592db97f33bSmickey 			case SYS_ftruncate:	i = 2;	break;
593db97f33bSmickey 			case SYS_preadv:
594db97f33bSmickey 			case SYS_pwritev:
595db97f33bSmickey 			case SYS_pread:
596db97f33bSmickey 			case SYS_pwrite:	i = 4;	break;
597db97f33bSmickey 			case SYS_mmap:		i = 6;	break;
598db97f33bSmickey 			}
599db97f33bSmickey 
600db97f33bSmickey 			if (i) {
601db97f33bSmickey 				t = args[i];
602db97f33bSmickey 				args[i] = args[i + 1];
603db97f33bSmickey 				args[i + 1] = t;
604db97f33bSmickey 			}
605db97f33bSmickey 		}
606db97f33bSmickey 	}
607b9b95e0dSmickey 
608b9b95e0dSmickey #ifdef SYSCALL_DEBUG
609b9b95e0dSmickey 	scdebug_call(p, code, args);
610b9b95e0dSmickey #endif
611b9b95e0dSmickey #ifdef KTRACE
612b9b95e0dSmickey 	if (KTRPOINT(p, KTR_SYSCALL))
613d970adb6Smickey 		ktrsyscall(p, code, callp->sy_argsize, args);
614b9b95e0dSmickey #endif
615db97f33bSmickey 	if (error)
616db97f33bSmickey 		goto bad;
617b9b95e0dSmickey 
618b9b95e0dSmickey 	rval[0] = 0;
619db97f33bSmickey 	rval[1] = frame->tf_ret1;
62096a1071fSmiod #if NSYSTRACE > 0
62196a1071fSmiod 	if (ISSET(p->p_flag, P_SYSTRACE))
622db97f33bSmickey 		oerror = error = systrace_redirect(code, p, args, rval);
62396a1071fSmiod 	else
62496a1071fSmiod #endif
625db97f33bSmickey 		oerror = error = (*callp->sy_call)(p, args, rval);
62696a1071fSmiod 	switch (error) {
627b9b95e0dSmickey 	case 0:
628532740e6Smickey 		p = curproc;			/* changes on exec() */
629532740e6Smickey 		frame = p->p_md.md_regs;
630b9b95e0dSmickey 		frame->tf_ret0 = rval[0];
631b7d25a19Smickey 		frame->tf_ret1 = rval[!retq];
632137d3021Smickey 		frame->tf_t1 = 0;
633b9b95e0dSmickey 		break;
634b9b95e0dSmickey 	case ERESTART:
635c37e03c6Smickey 		frame->tf_iioq_head -= 12;
636c37e03c6Smickey 		frame->tf_iioq_tail -= 12;
637b9b95e0dSmickey 		break;
638b9b95e0dSmickey 	case EJUSTRETURN:
639532740e6Smickey 		p = curproc;
640b7d25a19Smickey 		frame = p->p_md.md_regs;
641b9b95e0dSmickey 		break;
642b9b95e0dSmickey 	default:
643db97f33bSmickey 	bad:
644b9b95e0dSmickey 		if (p->p_emul->e_errno)
645b9b95e0dSmickey 			error = p->p_emul->e_errno[error];
646137d3021Smickey 		frame->tf_t1 = error;
647b9b95e0dSmickey 		break;
648b9b95e0dSmickey 	}
649b9b95e0dSmickey #ifdef SYSCALL_DEBUG
650db97f33bSmickey 	scdebug_ret(p, code, oerror, rval);
651b9b95e0dSmickey #endif
652532740e6Smickey 	userret(p, frame->tf_iioq_head, 0);
65370016991Smickey 	splx(cpl);	/* process softints */
654b9b95e0dSmickey #ifdef KTRACE
655b9b95e0dSmickey 	if (KTRPOINT(p, KTR_SYSRET))
656db97f33bSmickey 		ktrsysret(p, code, oerror, rval[0]);
657b9b95e0dSmickey #endif
65870016991Smickey #ifdef DIAGNOSTIC
65970016991Smickey 	if (cpl != oldcpl)
66070016991Smickey 		printf("WARNING: SPL (0x%x) NOT LOWERED ON "
66170016991Smickey 		    "syscall(0x%x, 0x%x, 0x%x, 0x%x...) EXIT, PID %d\n",
66270016991Smickey 		    cpl, code, args[0], args[1], args[2], p->p_pid);
66370016991Smickey #endif
664b9b95e0dSmickey }
665