xref: /openbsd/sys/arch/hppa/hppa/trap.c (revision 9b476898)
1*9b476898Smickey /*	$OpenBSD: trap.c,v 1.84 2005/01/17 20:47:40 mickey Exp $	*/
2556d2ba7Smickey 
3556d2ba7Smickey /*
4fef2e65fSmickey  * Copyright (c) 1998-2004 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  *
16556d2ba7Smickey  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17556d2ba7Smickey  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18556d2ba7Smickey  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19fef2e65fSmickey  * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
20fef2e65fSmickey  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21fef2e65fSmickey  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22fef2e65fSmickey  * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23fef2e65fSmickey  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24fef2e65fSmickey  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
25fef2e65fSmickey  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26fef2e65fSmickey  * THE POSSIBILITY OF SUCH DAMAGE.
27556d2ba7Smickey  */
28556d2ba7Smickey 
29ce94da48Smickey /* #define TRAPDEBUG */
30556d2ba7Smickey 
31556d2ba7Smickey #include <sys/param.h>
32556d2ba7Smickey #include <sys/systm.h>
33b9b95e0dSmickey #include <sys/syscall.h>
34b9b95e0dSmickey #include <sys/ktrace.h>
35d412f1c2Smickey #include <sys/proc.h>
366acb4cb0Sniklas #include <sys/signalvar.h>
37d412f1c2Smickey #include <sys/user.h>
38556d2ba7Smickey 
39af7386c3Smickey #include <net/netisr.h>
40af7386c3Smickey 
4196a1071fSmiod #include "systrace.h"
4296a1071fSmiod #include <dev/systrace.h>
4396a1071fSmiod 
44b9b95e0dSmickey #include <uvm/uvm.h>
45556d2ba7Smickey 
46556d2ba7Smickey #include <machine/autoconf.h>
47556d2ba7Smickey 
483867ea13Smiod #include <machine/db_machdep.h>	/* XXX always needed for inst_store() */
49137d3021Smickey #ifdef DDB
509d159c9dSmickey #ifdef TRAPDEBUG
51137d3021Smickey #include <ddb/db_output.h>
52137d3021Smickey #endif
539d159c9dSmickey #endif
54556d2ba7Smickey 
55556d2ba7Smickey const char *trap_type[] = {
56e494c7cfSmickey 	"invalid",
57e494c7cfSmickey 	"HPMC",
58556d2ba7Smickey 	"power failure",
59137d3021Smickey 	"recovery counter",
60556d2ba7Smickey 	"external interrupt",
61e494c7cfSmickey 	"LPMC",
62e494c7cfSmickey 	"ITLB miss fault",
63137d3021Smickey 	"instruction protection",
64137d3021Smickey 	"Illegal instruction",
65137d3021Smickey 	"break instruction",
66137d3021Smickey 	"privileged operation",
67137d3021Smickey 	"privileged register",
68137d3021Smickey 	"overflow",
69137d3021Smickey 	"conditional",
70137d3021Smickey 	"assist exception",
71e494c7cfSmickey 	"DTLB miss",
72137d3021Smickey 	"ITLB non-access miss",
73137d3021Smickey 	"DTLB non-access miss",
74137d3021Smickey 	"data protection/rights/alignment",
75137d3021Smickey 	"data break",
76e494c7cfSmickey 	"TLB dirty",
77137d3021Smickey 	"page reference",
78137d3021Smickey 	"assist emulation",
79e494c7cfSmickey 	"higher-priv transfer",
80e494c7cfSmickey 	"lower-priv transfer",
81137d3021Smickey 	"taken branch",
82137d3021Smickey 	"data access rights",
83e494c7cfSmickey 	"data protection",
84137d3021Smickey 	"unaligned data ref",
85556d2ba7Smickey };
86556d2ba7Smickey int trap_types = sizeof(trap_type)/sizeof(trap_type[0]);
87556d2ba7Smickey 
88bed2d21eSmickey int want_resched, astpending;
89556d2ba7Smickey 
901aec61b7Smickey #define	frame_regmap(tf,r)	(((u_int *)(tf))[hppa_regmap[(r)]])
911aec61b7Smickey u_char hppa_regmap[32] = {
921aec61b7Smickey 	offsetof(struct trapframe, tf_pad[0]) / 4,	/* r0 XXX */
931aec61b7Smickey 	offsetof(struct trapframe, tf_r1) / 4,
941aec61b7Smickey 	offsetof(struct trapframe, tf_rp) / 4,
951aec61b7Smickey 	offsetof(struct trapframe, tf_r3) / 4,
961aec61b7Smickey 	offsetof(struct trapframe, tf_r4) / 4,
971aec61b7Smickey 	offsetof(struct trapframe, tf_r5) / 4,
981aec61b7Smickey 	offsetof(struct trapframe, tf_r6) / 4,
991aec61b7Smickey 	offsetof(struct trapframe, tf_r7) / 4,
1001aec61b7Smickey 	offsetof(struct trapframe, tf_r8) / 4,
1011aec61b7Smickey 	offsetof(struct trapframe, tf_r9) / 4,
1021aec61b7Smickey 	offsetof(struct trapframe, tf_r10) / 4,
1031aec61b7Smickey 	offsetof(struct trapframe, tf_r11) / 4,
1041aec61b7Smickey 	offsetof(struct trapframe, tf_r12) / 4,
1051aec61b7Smickey 	offsetof(struct trapframe, tf_r13) / 4,
1061aec61b7Smickey 	offsetof(struct trapframe, tf_r14) / 4,
1071aec61b7Smickey 	offsetof(struct trapframe, tf_r15) / 4,
1081aec61b7Smickey 	offsetof(struct trapframe, tf_r16) / 4,
1091aec61b7Smickey 	offsetof(struct trapframe, tf_r17) / 4,
1101aec61b7Smickey 	offsetof(struct trapframe, tf_r18) / 4,
1111aec61b7Smickey 	offsetof(struct trapframe, tf_t4) / 4,
1121aec61b7Smickey 	offsetof(struct trapframe, tf_t3) / 4,
1131aec61b7Smickey 	offsetof(struct trapframe, tf_t2) / 4,
1141aec61b7Smickey 	offsetof(struct trapframe, tf_t1) / 4,
1151aec61b7Smickey 	offsetof(struct trapframe, tf_arg3) / 4,
1161aec61b7Smickey 	offsetof(struct trapframe, tf_arg2) / 4,
1171aec61b7Smickey 	offsetof(struct trapframe, tf_arg1) / 4,
1181aec61b7Smickey 	offsetof(struct trapframe, tf_arg0) / 4,
1191aec61b7Smickey 	offsetof(struct trapframe, tf_dp) / 4,
1201aec61b7Smickey 	offsetof(struct trapframe, tf_ret0) / 4,
1211aec61b7Smickey 	offsetof(struct trapframe, tf_ret1) / 4,
1221aec61b7Smickey 	offsetof(struct trapframe, tf_sp) / 4,
1231aec61b7Smickey 	offsetof(struct trapframe, tf_r31) / 4,
1241aec61b7Smickey };
1251aec61b7Smickey 
12670016991Smickey void
127d412f1c2Smickey userret(struct proc *p, register_t pc, u_quad_t oticks)
128d412f1c2Smickey {
129d412f1c2Smickey 	int sig;
130af7386c3Smickey 
131d412f1c2Smickey 	/* take pending signals */
132d412f1c2Smickey 	while ((sig = CURSIG(p)) != 0)
133d412f1c2Smickey 		postsig(sig);
134d412f1c2Smickey 
135d412f1c2Smickey 	p->p_priority = p->p_usrpri;
13670016991Smickey 	if (astpending) {
13770016991Smickey 		astpending = 0;
13870016991Smickey 		if (p->p_flag & P_OWEUPC) {
13970016991Smickey 			p->p_flag &= ~P_OWEUPC;
14070016991Smickey 			ADDUPROF(p);
14170016991Smickey 		}
14270016991Smickey 	}
143d412f1c2Smickey 	if (want_resched) {
144d412f1c2Smickey 		/*
145c81336dcSart 		 * We're being preempted.
146d412f1c2Smickey 		 */
147c81336dcSart 		preempt(NULL);
148d412f1c2Smickey 		while ((sig = CURSIG(p)) != 0)
149d412f1c2Smickey 			postsig(sig);
150d412f1c2Smickey 	}
151d412f1c2Smickey 
152d412f1c2Smickey 	/*
153d412f1c2Smickey 	 * If profiling, charge recent system time to the trapped pc.
154d412f1c2Smickey 	 */
155d412f1c2Smickey 	if (p->p_flag & P_PROFIL) {
156d412f1c2Smickey 		extern int psratio;
157d412f1c2Smickey 
158d412f1c2Smickey 		addupc_task(p, pc, (int)(p->p_sticks - oticks) * psratio);
159d412f1c2Smickey 	}
160d412f1c2Smickey 
161d412f1c2Smickey 	curpriority = p->p_priority;
162d412f1c2Smickey }
163d412f1c2Smickey 
164556d2ba7Smickey void
165556d2ba7Smickey trap(type, frame)
166556d2ba7Smickey 	int type;
167556d2ba7Smickey 	struct trapframe *frame;
168556d2ba7Smickey {
169556d2ba7Smickey 	struct proc *p = curproc;
170ab8e80c5Sart 	vaddr_t va;
171ab8e80c5Sart 	struct vm_map *map;
172f17fa196Smickey 	struct vmspace *vm;
173af7386c3Smickey 	register vm_prot_t vftype;
174556d2ba7Smickey 	register pa_space_t space;
175af7386c3Smickey 	union sigval sv;
176c37e03c6Smickey 	u_int opcode;
17770016991Smickey 	int ret, trapnum;
178137d3021Smickey 	const char *tts;
1796198d067Smickey 	vm_fault_t fault = VM_FAULT_INVALID;
18070016991Smickey #ifdef DIAGNOSTIC
18170016991Smickey 	int oldcpl = cpl;
18270016991Smickey #endif
1830e979e06Smickey 
184c37e03c6Smickey 	trapnum = type & ~T_USER;
185137d3021Smickey 	opcode = frame->tf_iir;
186*9b476898Smickey 	if (trapnum <= T_EXCEPTION || trapnum == T_HIGHERPL ||
187*9b476898Smickey 	    trapnum == T_LOWERPL || trapnum == T_TAKENBR ||
188*9b476898Smickey 	    trapnum == T_IDEBUG || trapnum == T_PERFMON) {
189a24c0b7aSmickey 		va = frame->tf_iioq_head;
190a24c0b7aSmickey 		space = frame->tf_iisq_head;
191e21aaa8cSmickey 		vftype = UVM_PROT_EXEC;
192a24c0b7aSmickey 	} else {
193b9b95e0dSmickey 		va = frame->tf_ior;
194a24c0b7aSmickey 		space = frame->tf_isr;
195a4be06b3Smickey 		if (va == frame->tf_iioq_head)
196e21aaa8cSmickey 			vftype = UVM_PROT_EXEC;
197a4be06b3Smickey 		else if (inst_store(opcode))
198e21aaa8cSmickey 			vftype = UVM_PROT_WRITE;
199a4be06b3Smickey 		else
200e21aaa8cSmickey 			vftype = UVM_PROT_READ;
201556d2ba7Smickey 	}
202137d3021Smickey 
203137d3021Smickey 	if (frame->tf_flags & TFF_LAST)
204137d3021Smickey 		p->p_md.md_regs = frame;
205137d3021Smickey 
206c37e03c6Smickey 	if (trapnum > trap_types)
207137d3021Smickey 		tts = "reserved";
208137d3021Smickey 	else
209c37e03c6Smickey 		tts = trap_type[trapnum];
210137d3021Smickey 
211446209b7Smiod #ifdef TRAPDEBUG
212c37e03c6Smickey 	if (trapnum != T_INTERRUPT && trapnum != T_IBREAK)
213969c5366Smickey 		db_printf("trap: %x, %s for %x:%x at %x:%x, fl=%x, fp=%p\n",
214137d3021Smickey 		    type, tts, space, va, frame->tf_iisq_head,
215137d3021Smickey 		    frame->tf_iioq_head, frame->tf_flags, frame);
216c37e03c6Smickey 	else if (trapnum  == T_IBREAK)
217137d3021Smickey 		db_printf("trap: break instruction %x:%x at %x:%x, fp=%p\n",
218a24c0b7aSmickey 		    break5(opcode), break13(opcode),
219137d3021Smickey 		    frame->tf_iisq_head, frame->tf_iioq_head, frame);
220e494c7cfSmickey 
221e494c7cfSmickey 	{
222e494c7cfSmickey 		extern int etext;
223532740e6Smickey 		if (frame < (struct trapframe *)&etext) {
224532740e6Smickey 			printf("trap: bogus frame ptr %p\n", frame);
225e494c7cfSmickey 			goto dead_end;
226e494c7cfSmickey 		}
227532740e6Smickey 	}
228d412f1c2Smickey #endif
2297d3bf75dSmickey 	if (trapnum != T_INTERRUPT) {
2307d3bf75dSmickey 		uvmexp.traps++;
23170016991Smickey 		mtctl(frame->tf_eiem, CR_EIEM);
232916310a5Smickey 	}
23370016991Smickey 
234556d2ba7Smickey 	switch (type) {
235556d2ba7Smickey 	case T_NONEXIST:
236556d2ba7Smickey 	case T_NONEXIST | T_USER:
237af7386c3Smickey 		/* we've got screwed up by the central scrutinizer */
238b67578d8Smickey 		printf("trap: elvis has just left the building!\n");
239532740e6Smickey 		goto dead_end;
240b67578d8Smickey 
241556d2ba7Smickey 	case T_RECOVERY:
242556d2ba7Smickey 	case T_RECOVERY | T_USER:
243af7386c3Smickey 		/* XXX will implement later */
244556d2ba7Smickey 		printf("trap: handicapped");
245532740e6Smickey 		goto dead_end;
24666d1ab7aSmickey 
24766d1ab7aSmickey #ifdef DIAGNOSTIC
24866d1ab7aSmickey 	case T_EXCEPTION:
24966d1ab7aSmickey 		panic("FPU/SFU emulation botch");
25066d1ab7aSmickey 
25166d1ab7aSmickey 		/* these just can't happen ever */
25266d1ab7aSmickey 	case T_PRIV_OP:
25366d1ab7aSmickey 	case T_PRIV_REG:
25466d1ab7aSmickey 		/* these just can't make it to the trap() ever */
255c6555f83Sderaadt 	case T_HPMC:
256c6555f83Sderaadt 	case T_HPMC | T_USER:
25766d1ab7aSmickey #endif
258f4daacd8Smickey 	case T_IBREAK:
259a24c0b7aSmickey 	case T_DATALIGN:
260a24c0b7aSmickey 	case T_DBREAK:
2618de28e3eSmickey 	dead_end:
262a24c0b7aSmickey #ifdef DDB
263532740e6Smickey 		if (kdb_trap (type, va, frame)) {
264a24c0b7aSmickey 			if (type == T_IBREAK) {
265f4daacd8Smickey 				/* skip break instruction */
2668de28e3eSmickey 				frame->tf_iioq_head = frame->tf_iioq_tail;
267f4daacd8Smickey 				frame->tf_iioq_tail += 4;
268a24c0b7aSmickey 			}
269556d2ba7Smickey 			return;
270a24c0b7aSmickey 		}
271137d3021Smickey #else
272137d3021Smickey 		if (type == T_DATALIGN)
273137d3021Smickey 			panic ("trap: %s at 0x%x", tts, va);
274137d3021Smickey 		else
275137d3021Smickey 			panic ("trap: no debugger for \"%s\" (%d)", tts, type);
276a24c0b7aSmickey #endif
277556d2ba7Smickey 		break;
278556d2ba7Smickey 
279af7386c3Smickey 	case T_IBREAK | T_USER:
280af7386c3Smickey 	case T_DBREAK | T_USER:
281af7386c3Smickey 		/* pass to user debugger */
282c66794d8Skettenis 		trapsignal(p, SIGTRAP, type &~ T_USER, TRAP_BRKPT, sv);
283d412f1c2Smickey 		break;
284d412f1c2Smickey 
28538575cbdSmickey 	case T_EXCEPTION | T_USER: {
286969eb289Smickey 		u_int64_t *fpp = (u_int64_t *)frame->tf_cr30;
287969eb289Smickey 		u_int32_t *pex;
28838575cbdSmickey 		int i, flt;
28938575cbdSmickey 
290969eb289Smickey 		pex = (u_int32_t *)&fpp[0];
29138575cbdSmickey 		for (i = 0, pex++; i < 7 && !*pex; i++, pex++);
292969eb289Smickey 		flt = 0;
293969eb289Smickey 		if (i < 7) {
294969eb289Smickey 			u_int32_t stat = HPPA_FPU_OP(*pex);
29528496d60Smickey 			if (stat & HPPA_FPU_UNMPL)
296969eb289Smickey 				flt = FPE_FLTINV;
29728496d60Smickey 			else if (stat & (HPPA_FPU_V << 1))
29838575cbdSmickey 				flt = FPE_FLTINV;
29928496d60Smickey 			else if (stat & (HPPA_FPU_Z << 1))
30038575cbdSmickey 				flt = FPE_FLTDIV;
30128496d60Smickey 			else if (stat & (HPPA_FPU_I << 1))
302969eb289Smickey 				flt = FPE_FLTRES;
30328496d60Smickey 			else if (stat & (HPPA_FPU_O << 1))
30438575cbdSmickey 				flt = FPE_FLTOVF;
30528496d60Smickey 			else if (stat & (HPPA_FPU_U << 1))
30638575cbdSmickey 				flt = FPE_FLTUND;
307969eb289Smickey 			/* still left: under/over-flow w/ inexact */
308ded58a29Smickey 
309ded58a29Smickey 			/* cleanup exceptions (XXX deliver all ?) */
310ded58a29Smickey 			while (i++ < 7)
311ded58a29Smickey 				*pex++ = 0;
312969eb289Smickey 		}
313969eb289Smickey 		/* reset the trap flag, as if there was none */
314969eb289Smickey 		fpp[0] &= ~(((u_int64_t)HPPA_FPU_T) << 32);
315969eb289Smickey 		/* flush out, since load is done from phys, only 4 regs */
316969eb289Smickey 		fdcache(HPPA_SID_KERNEL, (vaddr_t)fpp, 8 * 4);
31738575cbdSmickey 
31838575cbdSmickey 		sv.sival_int = va;
31938575cbdSmickey 		trapsignal(p, SIGFPE, type &~ T_USER, flt, sv);
32038575cbdSmickey 		}
32138575cbdSmickey 		break;
32238575cbdSmickey 
323969eb289Smickey 	case T_EMULATION:
324969eb289Smickey 		panic("trap: emulation trap in the kernel");
325969eb289Smickey 		break;
326969eb289Smickey 
327969eb289Smickey 	case T_EMULATION | T_USER:
328137d3021Smickey 		sv.sival_int = va;
32928496d60Smickey 		trapsignal(p, SIGILL, type &~ T_USER, ILL_COPROC, sv);
330d412f1c2Smickey 		break;
331d412f1c2Smickey 
332af7386c3Smickey 	case T_OVERFLOW | T_USER:
333137d3021Smickey 		sv.sival_int = va;
334af7386c3Smickey 		trapsignal(p, SIGFPE, type &~ T_USER, FPE_INTOVF, sv);
335d412f1c2Smickey 		break;
336d412f1c2Smickey 
337af7386c3Smickey 	case T_CONDITION | T_USER:
3388b9bddf0Smickey 		sv.sival_int = va;
3398b9bddf0Smickey 		trapsignal(p, SIGFPE, type &~ T_USER, FPE_INTDIV, sv);
340af7386c3Smickey 		break;
341af7386c3Smickey 
342af7386c3Smickey 	case T_PRIV_OP | T_USER:
343137d3021Smickey 		sv.sival_int = va;
344af7386c3Smickey 		trapsignal(p, SIGILL, type &~ T_USER, ILL_PRVOPC, sv);
345af7386c3Smickey 		break;
346af7386c3Smickey 
347af7386c3Smickey 	case T_PRIV_REG | T_USER:
348137d3021Smickey 		sv.sival_int = va;
349af7386c3Smickey 		trapsignal(p, SIGILL, type &~ T_USER, ILL_PRVREG, sv);
350af7386c3Smickey 		break;
351af7386c3Smickey 
352af7386c3Smickey 		/* these should never got here */
353af7386c3Smickey 	case T_HIGHERPL | T_USER:
354af7386c3Smickey 	case T_LOWERPL | T_USER:
355137d3021Smickey 		sv.sival_int = va;
356a4be06b3Smickey 		trapsignal(p, SIGSEGV, vftype, SEGV_ACCERR, sv);
357af7386c3Smickey 		break;
358af7386c3Smickey 
359af7386c3Smickey 	case T_IPROT | T_USER:
360af7386c3Smickey 	case T_DPROT | T_USER:
361af7386c3Smickey 		sv.sival_int = va;
362af7386c3Smickey 		trapsignal(p, SIGSEGV, vftype, SEGV_ACCERR, sv);
363af7386c3Smickey 		break;
364af7386c3Smickey 
3659208e3abSmickey 	case T_ITLBMISSNA:
3669208e3abSmickey 	case T_ITLBMISSNA | T_USER:
3679208e3abSmickey 	case T_DTLBMISSNA:
3689208e3abSmickey 	case T_DTLBMISSNA | T_USER:
3699208e3abSmickey 		if (space == HPPA_SID_KERNEL)
3709208e3abSmickey 			map = kernel_map;
3719208e3abSmickey 		else {
3729208e3abSmickey 			vm = p->p_vmspace;
3739208e3abSmickey 			map = &vm->vm_map;
3749208e3abSmickey 		}
3759208e3abSmickey 
3769208e3abSmickey 		/* dig probe[rw]i? insns */
3779208e3abSmickey 		if ((opcode & 0xfc001f80) == 0x04001180) {
3789208e3abSmickey 			int pl;
3799208e3abSmickey 
3809208e3abSmickey 			if (opcode & 0x2000)
3819208e3abSmickey 				pl = (opcode >> 16) & 3;
3829208e3abSmickey 			else
3839208e3abSmickey 				pl = frame_regmap(frame,
3849208e3abSmickey 				    (opcode >> 16) & 0x1f) & 3;
3859208e3abSmickey 
3869208e3abSmickey 			if ((type & T_USER && space == HPPA_SID_KERNEL) ||
3879208e3abSmickey 			    (frame->tf_iioq_head & 3) != pl ||
3889208e3abSmickey 			    (type & T_USER && va >= VM_MAXUSER_ADDRESS) ||
3899208e3abSmickey 			    uvm_fault(map, hppa_trunc_page(va), fault,
3909208e3abSmickey 			     opcode & 0x40? UVM_PROT_WRITE : UVM_PROT_READ)) {
3919208e3abSmickey 				frame_regmap(frame, opcode & 0x1f) = 0;
3929208e3abSmickey 				frame->tf_ipsw |= PSL_N;
3939208e3abSmickey 			}
3949208e3abSmickey 		} else if (type & T_USER) {
3959208e3abSmickey 			sv.sival_int = va;
3969208e3abSmickey 			trapsignal(p, SIGILL, type & ~T_USER, ILL_ILLTRP, sv);
3979208e3abSmickey 		} else
3989208e3abSmickey 			panic("trap: %s @ 0x%x:0x%x for 0x%x:0x%x irr 0x%08x\n",
3999208e3abSmickey 			    tts, frame->tf_iisq_head, frame->tf_iioq_head,
4009208e3abSmickey 			    space, va, opcode);
4019208e3abSmickey 		break;
4029208e3abSmickey 
4039208e3abSmickey 	case T_TLB_DIRTY:
4049208e3abSmickey 	case T_TLB_DIRTY | T_USER:
405c6555f83Sderaadt 	case T_DATACC:
406c6555f83Sderaadt 	case T_DATACC | T_USER:
4076198d067Smickey 		fault = VM_FAULT_PROTECT;
408c6555f83Sderaadt 	case T_ITLBMISS:
409c6555f83Sderaadt 	case T_ITLBMISS | T_USER:
410c6555f83Sderaadt 	case T_DTLBMISS:
411c6555f83Sderaadt 	case T_DTLBMISS | T_USER:
4128de28e3eSmickey 		/*
413e494c7cfSmickey 		 * it could be a kernel map for exec_map faults
4148de28e3eSmickey 		 */
41543a91648Smickey 		if (space == HPPA_SID_KERNEL)
4168de28e3eSmickey 			map = kernel_map;
41743a91648Smickey 		else {
41843a91648Smickey 			vm = p->p_vmspace;
419f17fa196Smickey 			map = &vm->vm_map;
42043a91648Smickey 		}
421556d2ba7Smickey 
4229208e3abSmickey 		/*
4239208e3abSmickey 		 * user faults out of user addr space are always a fail,
4249208e3abSmickey 		 * this happens on va >= VM_MAXUSER_ADDRESS, where
4259208e3abSmickey 		 * space id will be zero and therefore cause
4269208e3abSmickey 		 * a misbehave lower in the code.
4279208e3abSmickey 		 *
4289208e3abSmickey 		 * also check that faulted space id matches the curproc.
4299208e3abSmickey 		 */
4309208e3abSmickey 		if ((type & T_USER && va >= VM_MAXUSER_ADDRESS) ||
4319208e3abSmickey 		   (type & T_USER && map->pmap->pm_space != space)) {
432906a25e0Smickey 			sv.sival_int = va;
433906a25e0Smickey 			trapsignal(p, SIGSEGV, vftype, SEGV_MAPERR, sv);
43443a91648Smickey 			break;
435906a25e0Smickey 		}
436532740e6Smickey 
437a4be06b3Smickey 		ret = uvm_fault(map, hppa_trunc_page(va), fault, vftype);
438f17fa196Smickey 
439f17fa196Smickey 		/*
440f17fa196Smickey 		 * If this was a stack access we keep track of the maximum
441f17fa196Smickey 		 * accessed stack size.  Also, if uvm_fault gets a protection
442f17fa196Smickey 		 * failure it is due to accessing the stack region outside
443f17fa196Smickey 		 * the current limit and we need to reflect that as an access
444f17fa196Smickey 		 * error.
445f17fa196Smickey 		 */
44656f69dffSmiod 		if (space != HPPA_SID_KERNEL &&
44762899679Smiod 		    va < (vaddr_t)vm->vm_minsaddr) {
44862899679Smiod 			if (ret == 0)
44962899679Smiod 				uvm_grow(p, va);
45062899679Smiod 			else if (ret == EACCES)
451738a5b4dSart 				ret = EFAULT;
452f17fa196Smickey 		}
453f17fa196Smickey 
454738a5b4dSart 		if (ret != 0) {
455af7386c3Smickey 			if (type & T_USER) {
456a4be06b3Smickey 				sv.sival_int = va;
457a4be06b3Smickey 				trapsignal(p, SIGSEGV, vftype,
458a4be06b3Smickey 				    ret == EACCES? SEGV_ACCERR : SEGV_MAPERR,
459a4be06b3Smickey 				    sv);
460137d3021Smickey 			} else {
4618de28e3eSmickey 				if (p && p->p_addr->u_pcb.pcb_onfault) {
4628de28e3eSmickey 					frame->tf_iioq_tail = 4 +
4638de28e3eSmickey 					    (frame->tf_iioq_head =
46438575cbdSmickey 						p->p_addr->u_pcb.pcb_onfault);
465b04f760fSmickey #ifdef DDB
466b04f760fSmickey 					frame->tf_iir = 0;
467b04f760fSmickey #endif
468db97f33bSmickey 				} else {
469db97f33bSmickey 					panic("trap: "
47056f69dffSmiod 					    "uvm_fault(%p, %lx, %d, %d): %d",
47196415af6Smickey 					    map, va, fault, vftype, ret);
472137d3021Smickey 				}
473137d3021Smickey 			}
474db97f33bSmickey 		}
475556d2ba7Smickey 		break;
476d412f1c2Smickey 
477af7386c3Smickey 	case T_DATALIGN | T_USER:
478137d3021Smickey 		sv.sival_int = va;
479af7386c3Smickey 		trapsignal(p, SIGBUS, vftype, BUS_ADRALN, sv);
480af7386c3Smickey 		break;
481af7386c3Smickey 
482a24c0b7aSmickey 	case T_INTERRUPT:
483a24c0b7aSmickey 	case T_INTERRUPT | T_USER:
484a24c0b7aSmickey 		cpu_intr(frame);
485af7386c3Smickey 		break;
486af7386c3Smickey 
487b7d25a19Smickey 	case T_CONDITION:
488b7d25a19Smickey 		panic("trap: divide by zero in the kernel");
489b7d25a19Smickey 		break;
490b7d25a19Smickey 
4913147f0deSmickey 	case T_ILLEGAL:
4923147f0deSmickey 	case T_ILLEGAL | T_USER:
4933147f0deSmickey 		/* see if it's a SPOP1,,0 */
49496415af6Smickey 		if ((opcode & 0xfffffe00) == 0x10000200) {
49596415af6Smickey 			frame_regmap(frame, opcode & 0x1f) = 0;
4963147f0deSmickey 			frame->tf_ipsw |= PSL_N;
4973147f0deSmickey 			break;
4983147f0deSmickey 		}
4993147f0deSmickey 		if (type & T_USER) {
5003147f0deSmickey 			sv.sival_int = va;
5013147f0deSmickey 			trapsignal(p, SIGILL, type &~ T_USER, ILL_ILLOPC, sv);
5023147f0deSmickey 			break;
5033147f0deSmickey 		}
5043147f0deSmickey 		/* FALLTHROUGH */
5053147f0deSmickey 
50670016991Smickey 	case T_LOWERPL:
5072ef9a47eSmickey 	case T_DPROT:
5082ef9a47eSmickey 	case T_IPROT:
509af7386c3Smickey 	case T_OVERFLOW:
510af7386c3Smickey 	case T_HIGHERPL:
511af7386c3Smickey 	case T_TAKENBR:
512af7386c3Smickey 	case T_POWERFAIL:
513af7386c3Smickey 	case T_LPMC:
514af7386c3Smickey 	case T_PAGEREF:
515c6555f83Sderaadt 	case T_DATAPID:
516c6555f83Sderaadt 	case T_DATAPID | T_USER:
517d412f1c2Smickey 		if (0 /* T-chip */) {
518d412f1c2Smickey 			break;
519556d2ba7Smickey 		}
520d412f1c2Smickey 		/* FALLTHROUGH to unimplemented */
521d412f1c2Smickey 	default:
522a228f8d2Smickey #if 0
523532740e6Smickey if (kdb_trap (type, va, frame))
524137d3021Smickey 	return;
525137d3021Smickey #endif
52670016991Smickey 		panic("trap: unimplemented \'%s\' (%d)", tts, trapnum);
527d412f1c2Smickey 	}
528af7386c3Smickey 
52970016991Smickey #ifdef DIAGNOSTIC
53070016991Smickey 	if (cpl != oldcpl)
53170016991Smickey 		printf("WARNING: SPL (%d) NOT LOWERED ON "
53270016991Smickey 		    "TRAP (%d) EXIT\n", cpl, trapnum);
53370016991Smickey #endif
53470016991Smickey 
53570016991Smickey 	if (trapnum != T_INTERRUPT)
53670016991Smickey 		splx(cpl);	/* process softints */
53770016991Smickey 
538ba42a120Smickey 	/*
539ba42a120Smickey 	 * in case we were interrupted from the syscall gate page
540ba42a120Smickey 	 * treat this as we were not realy running user code no more
541ba42a120Smickey 	 * for weird things start to happen on return to the userland
542ba42a120Smickey 	 * and also see a note in locore.S:TLABEL(all)
543ba42a120Smickey 	 */
544ba42a120Smickey 	if ((type & T_USER) &&
545ba42a120Smickey 	    (frame->tf_iioq_head & ~PAGE_MASK) != SYSCALLGATE)
54670016991Smickey 		userret(p, frame->tf_iioq_head, 0);
547d412f1c2Smickey }
548d412f1c2Smickey 
549d412f1c2Smickey void
550db36253aSmickey child_return(arg)
551db36253aSmickey 	void *arg;
552d412f1c2Smickey {
553db36253aSmickey 	struct proc *p = (struct proc *)arg;
55489afe3e5Smickey 	struct trapframe *tf = p->p_md.md_regs;
55589afe3e5Smickey 
55689afe3e5Smickey 	/*
55789afe3e5Smickey 	 * Set up return value registers as libc:fork() expects
55889afe3e5Smickey 	 */
55989afe3e5Smickey 	tf->tf_ret0 = 0;
56089afe3e5Smickey 	tf->tf_ret1 = 1;	/* ischild */
56189afe3e5Smickey 	tf->tf_t1 = 0;		/* errno */
56289afe3e5Smickey 
56389afe3e5Smickey 	userret(p, tf->tf_iioq_head, 0);
564d412f1c2Smickey #ifdef KTRACE
565d412f1c2Smickey 	if (KTRPOINT(p, KTR_SYSRET))
566a27b30d8Sart 		ktrsysret(p, SYS_fork, 0, 0);
567d412f1c2Smickey #endif
568556d2ba7Smickey }
569556d2ba7Smickey 
570db97f33bSmickey 
571b9b95e0dSmickey /*
572b9b95e0dSmickey  * call actual syscall routine
573b9b95e0dSmickey  */
574b9b95e0dSmickey void
57570016991Smickey syscall(struct trapframe *frame)
576b9b95e0dSmickey {
577db97f33bSmickey 	register struct proc *p = curproc;
578b9b95e0dSmickey 	register const struct sysent *callp;
579b7d25a19Smickey 	int retq, nsys, code, argsize, argoff, oerror, error;
580b7d25a19Smickey 	register_t args[8], rval[2];
58170016991Smickey #ifdef DIAGNOSTIC
58270016991Smickey 	int oldcpl = cpl;
58370016991Smickey #endif
584b9b95e0dSmickey 
585b9b95e0dSmickey 	uvmexp.syscalls++;
586b9b95e0dSmickey 
587b9b95e0dSmickey 	if (!USERMODE(frame->tf_iioq_head))
588b9b95e0dSmickey 		panic("syscall");
589b9b95e0dSmickey 
590137d3021Smickey 	p->p_md.md_regs = frame;
591b9b95e0dSmickey 	nsys = p->p_emul->e_nsysent;
592b9b95e0dSmickey 	callp = p->p_emul->e_sysent;
593db97f33bSmickey 
594b7d25a19Smickey 	argoff = 4; retq = 0;
595db97f33bSmickey 	switch (code = frame->tf_t1) {
596b9b95e0dSmickey 	case SYS_syscall:
597db97f33bSmickey 		code = frame->tf_arg0;
598db97f33bSmickey 		args[0] = frame->tf_arg1;
599db97f33bSmickey 		args[1] = frame->tf_arg2;
600db97f33bSmickey 		args[2] = frame->tf_arg3;
601db97f33bSmickey 		argoff = 3;
602b9b95e0dSmickey 		break;
603b9b95e0dSmickey 	case SYS___syscall:
604b9b95e0dSmickey 		if (callp != sysent)
605b9b95e0dSmickey 			break;
606db97f33bSmickey 		/*
607db97f33bSmickey 		 * this works, because quads get magically swapped
6087503858eSjfb 		 * due to the args being laid backwards on the stack
609db97f33bSmickey 		 * and then copied in words
610db97f33bSmickey 		 */
611db97f33bSmickey 		code = frame->tf_arg0;
612db97f33bSmickey 		args[0] = frame->tf_arg2;
613db97f33bSmickey 		args[1] = frame->tf_arg3;
614db97f33bSmickey 		argoff = 2;
615b7d25a19Smickey 		retq = 1;
616db97f33bSmickey 		break;
617db97f33bSmickey 	default:
618db97f33bSmickey 		args[0] = frame->tf_arg0;
619db97f33bSmickey 		args[1] = frame->tf_arg1;
620db97f33bSmickey 		args[2] = frame->tf_arg2;
621db97f33bSmickey 		args[3] = frame->tf_arg3;
622db97f33bSmickey 		break;
623b9b95e0dSmickey 	}
624b9b95e0dSmickey 
625b9b95e0dSmickey 	if (code < 0 || code >= nsys)
626b9b95e0dSmickey 		callp += p->p_emul->e_nosys;	/* bad syscall # */
627b9b95e0dSmickey 	else
628b9b95e0dSmickey 		callp += code;
629db97f33bSmickey 
630db97f33bSmickey 	oerror = error = 0;
631db97f33bSmickey 	if ((argsize = callp->sy_argsize)) {
632db97f33bSmickey 		int i;
633db97f33bSmickey 
634db97f33bSmickey 		for (i = 0, argsize -= argoff * 4;
635db97f33bSmickey 		    argsize > 0; i++, argsize -= 4) {
636db97f33bSmickey 			error = copyin((void *)(frame->tf_sp +
637db97f33bSmickey 			    HPPA_FRAME_ARG(i + 4)), args + i + argoff, 4);
638db97f33bSmickey 
639db97f33bSmickey 			if (error)
640db97f33bSmickey 				break;
641db97f33bSmickey 		}
642db97f33bSmickey 
643db97f33bSmickey 		/*
644db97f33bSmickey 		 * coming from syscall() or __syscall we must be
645db97f33bSmickey 		 * having one of those w/ a 64 bit arguments,
646db97f33bSmickey 		 * which needs a word swap due to the order
647db97f33bSmickey 		 * of the arguments on the stack.
648db97f33bSmickey 		 * this assumes that none of 'em are called
649db97f33bSmickey 		 * by their normal syscall number, maybe a regress
650b49f4f07Smiod 		 * test should be used, to watch the behaviour.
651db97f33bSmickey 		 */
652db97f33bSmickey 		if (!error && argoff < 4) {
653db97f33bSmickey 			int t;
654db97f33bSmickey 
655db97f33bSmickey 			i = 0;
656db97f33bSmickey 			switch (code) {
657b7d25a19Smickey 			case SYS_lseek:		retq = 0;
658db97f33bSmickey 			case SYS_truncate:
659db97f33bSmickey 			case SYS_ftruncate:	i = 2;	break;
660db97f33bSmickey 			case SYS_preadv:
661db97f33bSmickey 			case SYS_pwritev:
662db97f33bSmickey 			case SYS_pread:
663db97f33bSmickey 			case SYS_pwrite:	i = 4;	break;
664db97f33bSmickey 			case SYS_mmap:		i = 6;	break;
665db97f33bSmickey 			}
666db97f33bSmickey 
667db97f33bSmickey 			if (i) {
668db97f33bSmickey 				t = args[i];
669db97f33bSmickey 				args[i] = args[i + 1];
670db97f33bSmickey 				args[i + 1] = t;
671db97f33bSmickey 			}
672db97f33bSmickey 		}
673db97f33bSmickey 	}
674b9b95e0dSmickey 
675b9b95e0dSmickey #ifdef SYSCALL_DEBUG
676b9b95e0dSmickey 	scdebug_call(p, code, args);
677b9b95e0dSmickey #endif
678b9b95e0dSmickey #ifdef KTRACE
679b9b95e0dSmickey 	if (KTRPOINT(p, KTR_SYSCALL))
680d970adb6Smickey 		ktrsyscall(p, code, callp->sy_argsize, args);
681b9b95e0dSmickey #endif
682db97f33bSmickey 	if (error)
683db97f33bSmickey 		goto bad;
684b9b95e0dSmickey 
685b9b95e0dSmickey 	rval[0] = 0;
686db97f33bSmickey 	rval[1] = frame->tf_ret1;
68796a1071fSmiod #if NSYSTRACE > 0
68896a1071fSmiod 	if (ISSET(p->p_flag, P_SYSTRACE))
689db97f33bSmickey 		oerror = error = systrace_redirect(code, p, args, rval);
69096a1071fSmiod 	else
69196a1071fSmiod #endif
692db97f33bSmickey 		oerror = error = (*callp->sy_call)(p, args, rval);
6937882195eSmickey 	p = curproc;
6947882195eSmickey 	frame = p->p_md.md_regs;
69596a1071fSmiod 	switch (error) {
696b9b95e0dSmickey 	case 0:
697b9b95e0dSmickey 		frame->tf_ret0 = rval[0];
698b7d25a19Smickey 		frame->tf_ret1 = rval[!retq];
699137d3021Smickey 		frame->tf_t1 = 0;
700b9b95e0dSmickey 		break;
701b9b95e0dSmickey 	case ERESTART:
702c37e03c6Smickey 		frame->tf_iioq_head -= 12;
703c37e03c6Smickey 		frame->tf_iioq_tail -= 12;
704b9b95e0dSmickey 	case EJUSTRETURN:
705b9b95e0dSmickey 		break;
706b9b95e0dSmickey 	default:
707db97f33bSmickey 	bad:
708b9b95e0dSmickey 		if (p->p_emul->e_errno)
709b9b95e0dSmickey 			error = p->p_emul->e_errno[error];
710137d3021Smickey 		frame->tf_t1 = error;
71147df6ae3Smickey 		frame->tf_ret0 = error;
71247df6ae3Smickey 		frame->tf_ret1 = 0;
713b9b95e0dSmickey 		break;
714b9b95e0dSmickey 	}
715b9b95e0dSmickey #ifdef SYSCALL_DEBUG
716db97f33bSmickey 	scdebug_ret(p, code, oerror, rval);
717b9b95e0dSmickey #endif
718532740e6Smickey 	userret(p, frame->tf_iioq_head, 0);
719b9b95e0dSmickey #ifdef KTRACE
720b9b95e0dSmickey 	if (KTRPOINT(p, KTR_SYSRET))
721db97f33bSmickey 		ktrsysret(p, code, oerror, rval[0]);
722b9b95e0dSmickey #endif
72370016991Smickey #ifdef DIAGNOSTIC
72450552582Smickey 	if (cpl != oldcpl) {
72570016991Smickey 		printf("WARNING: SPL (0x%x) NOT LOWERED ON "
72670016991Smickey 		    "syscall(0x%x, 0x%x, 0x%x, 0x%x...) EXIT, PID %d\n",
72770016991Smickey 		    cpl, code, args[0], args[1], args[2], p->p_pid);
72850552582Smickey 		cpl = oldcpl;
72950552582Smickey 	}
73070016991Smickey #endif
73150552582Smickey 	splx(cpl);	/* process softints */
732b9b95e0dSmickey }
733