xref: /openbsd/sys/arch/hppa/hppa/trap.c (revision 5ab06ed0)
1*5ab06ed0Sderaadt /*	$OpenBSD: trap.c,v 1.133 2014/05/10 21:58:56 deraadt 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>
34d412f1c2Smickey #include <sys/proc.h>
356acb4cb0Sniklas #include <sys/signalvar.h>
36d412f1c2Smickey #include <sys/user.h>
37*5ab06ed0Sderaadt #include <sys/syscall_mi.h>
38556d2ba7Smickey 
390d6ad30dSmpi #include <uvm/uvm_extern.h>
40556d2ba7Smickey 
41556d2ba7Smickey #include <machine/autoconf.h>
42556d2ba7Smickey 
43137d3021Smickey #ifdef DDB
449d159c9dSmickey #ifdef TRAPDEBUG
45137d3021Smickey #include <ddb/db_output.h>
461f3fe449Smiod #else
471f3fe449Smiod #include <machine/db_machdep.h>
48137d3021Smickey #endif
499d159c9dSmickey #endif
50556d2ba7Smickey 
511f3fe449Smiod static __inline int inst_store(u_int ins) {
521f3fe449Smiod 	return (ins & 0xf0000000) == 0x60000000 ||	/* st */
531f3fe449Smiod 	       (ins & 0xf4000200) == 0x24000200 ||	/* fst/cst */
541f3fe449Smiod 	       (ins & 0xfc000200) == 0x0c000200 ||	/* stby */
551f3fe449Smiod 	       (ins & 0xfc0003c0) == 0x0c0001c0;	/* ldcw */
561f3fe449Smiod }
571f3fe449Smiod 
5878a8f2b7Smiod int	pcxs_unaligned(u_int opcode, vaddr_t va);
597bfbef72Skettenis #ifdef PTRACE
607bfbef72Skettenis void	ss_clear_breakpoints(struct proc *p);
617bfbef72Skettenis #endif
627bfbef72Skettenis 
63dfd9822dSderaadt void	ast(struct proc *);
64dfd9822dSderaadt 
657bfbef72Skettenis /* single-step breakpoint */
667bfbef72Skettenis #define SSBREAKPOINT	(HPPA_BREAK_KERNEL | (HPPA_BREAK_SS << 13))
677bfbef72Skettenis 
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 
1011aec61b7Smickey #define	frame_regmap(tf,r)	(((u_int *)(tf))[hppa_regmap[(r)]])
1021aec61b7Smickey u_char hppa_regmap[32] = {
1031aec61b7Smickey 	offsetof(struct trapframe, tf_pad[0]) / 4,	/* r0 XXX */
1041aec61b7Smickey 	offsetof(struct trapframe, tf_r1) / 4,
1051aec61b7Smickey 	offsetof(struct trapframe, tf_rp) / 4,
1061aec61b7Smickey 	offsetof(struct trapframe, tf_r3) / 4,
1071aec61b7Smickey 	offsetof(struct trapframe, tf_r4) / 4,
1081aec61b7Smickey 	offsetof(struct trapframe, tf_r5) / 4,
1091aec61b7Smickey 	offsetof(struct trapframe, tf_r6) / 4,
1101aec61b7Smickey 	offsetof(struct trapframe, tf_r7) / 4,
1111aec61b7Smickey 	offsetof(struct trapframe, tf_r8) / 4,
1121aec61b7Smickey 	offsetof(struct trapframe, tf_r9) / 4,
1131aec61b7Smickey 	offsetof(struct trapframe, tf_r10) / 4,
1141aec61b7Smickey 	offsetof(struct trapframe, tf_r11) / 4,
1151aec61b7Smickey 	offsetof(struct trapframe, tf_r12) / 4,
1161aec61b7Smickey 	offsetof(struct trapframe, tf_r13) / 4,
1171aec61b7Smickey 	offsetof(struct trapframe, tf_r14) / 4,
1181aec61b7Smickey 	offsetof(struct trapframe, tf_r15) / 4,
1191aec61b7Smickey 	offsetof(struct trapframe, tf_r16) / 4,
1201aec61b7Smickey 	offsetof(struct trapframe, tf_r17) / 4,
1211aec61b7Smickey 	offsetof(struct trapframe, tf_r18) / 4,
1221aec61b7Smickey 	offsetof(struct trapframe, tf_t4) / 4,
1231aec61b7Smickey 	offsetof(struct trapframe, tf_t3) / 4,
1241aec61b7Smickey 	offsetof(struct trapframe, tf_t2) / 4,
1251aec61b7Smickey 	offsetof(struct trapframe, tf_t1) / 4,
1261aec61b7Smickey 	offsetof(struct trapframe, tf_arg3) / 4,
1271aec61b7Smickey 	offsetof(struct trapframe, tf_arg2) / 4,
1281aec61b7Smickey 	offsetof(struct trapframe, tf_arg1) / 4,
1291aec61b7Smickey 	offsetof(struct trapframe, tf_arg0) / 4,
1301aec61b7Smickey 	offsetof(struct trapframe, tf_dp) / 4,
1311aec61b7Smickey 	offsetof(struct trapframe, tf_ret0) / 4,
1321aec61b7Smickey 	offsetof(struct trapframe, tf_ret1) / 4,
1331aec61b7Smickey 	offsetof(struct trapframe, tf_sp) / 4,
1341aec61b7Smickey 	offsetof(struct trapframe, tf_r31) / 4,
1351aec61b7Smickey };
1361aec61b7Smickey 
13770016991Smickey void
138c2b93341Sderaadt ast(struct proc *p)
139d412f1c2Smickey {
140da6814fdSjsing 	if (p->p_md.md_astpending) {
141da6814fdSjsing 		p->p_md.md_astpending = 0;
142db13da92Sguenther 		mi_ast(p, curcpu()->ci_want_resched);
143c19cb33fSmickey 	}
144c19cb33fSmickey 
145d412f1c2Smickey }
146d412f1c2Smickey 
147556d2ba7Smickey void
148c33335b0Sjsing trap(int type, struct trapframe *frame)
149556d2ba7Smickey {
150556d2ba7Smickey 	struct proc *p = curproc;
151ab8e80c5Sart 	vaddr_t va;
152ab8e80c5Sart 	struct vm_map *map;
153f17fa196Smickey 	struct vmspace *vm;
154af7386c3Smickey 	register vm_prot_t vftype;
155556d2ba7Smickey 	register pa_space_t space;
156af7386c3Smickey 	union sigval sv;
157c37e03c6Smickey 	u_int opcode;
15870016991Smickey 	int ret, trapnum;
159137d3021Smickey 	const char *tts;
1606198d067Smickey 	vm_fault_t fault = VM_FAULT_INVALID;
16170016991Smickey #ifdef DIAGNOSTIC
162473ddf34Sjsing 	int oldcpl = curcpu()->ci_cpl;
16370016991Smickey #endif
1640e979e06Smickey 
165c37e03c6Smickey 	trapnum = type & ~T_USER;
166137d3021Smickey 	opcode = frame->tf_iir;
1679b476898Smickey 	if (trapnum <= T_EXCEPTION || trapnum == T_HIGHERPL ||
1689b476898Smickey 	    trapnum == T_LOWERPL || trapnum == T_TAKENBR ||
1699b476898Smickey 	    trapnum == T_IDEBUG || trapnum == T_PERFMON) {
170a24c0b7aSmickey 		va = frame->tf_iioq_head;
171a24c0b7aSmickey 		space = frame->tf_iisq_head;
172e21aaa8cSmickey 		vftype = UVM_PROT_EXEC;
173a24c0b7aSmickey 	} else {
174b9b95e0dSmickey 		va = frame->tf_ior;
175a24c0b7aSmickey 		space = frame->tf_isr;
176a4be06b3Smickey 		if (va == frame->tf_iioq_head)
177e21aaa8cSmickey 			vftype = UVM_PROT_EXEC;
178a4be06b3Smickey 		else if (inst_store(opcode))
179e21aaa8cSmickey 			vftype = UVM_PROT_WRITE;
180a4be06b3Smickey 		else
181e21aaa8cSmickey 			vftype = UVM_PROT_READ;
182556d2ba7Smickey 	}
183137d3021Smickey 
184137d3021Smickey 	if (frame->tf_flags & TFF_LAST)
185137d3021Smickey 		p->p_md.md_regs = frame;
186137d3021Smickey 
187c37e03c6Smickey 	if (trapnum > trap_types)
188137d3021Smickey 		tts = "reserved";
189137d3021Smickey 	else
190c37e03c6Smickey 		tts = trap_type[trapnum];
191137d3021Smickey 
192446209b7Smiod #ifdef TRAPDEBUG
193c37e03c6Smickey 	if (trapnum != T_INTERRUPT && trapnum != T_IBREAK)
194969c5366Smickey 		db_printf("trap: %x, %s for %x:%x at %x:%x, fl=%x, fp=%p\n",
195137d3021Smickey 		    type, tts, space, va, frame->tf_iisq_head,
196137d3021Smickey 		    frame->tf_iioq_head, frame->tf_flags, frame);
197c37e03c6Smickey 	else if (trapnum  == T_IBREAK)
198137d3021Smickey 		db_printf("trap: break instruction %x:%x at %x:%x, fp=%p\n",
199a24c0b7aSmickey 		    break5(opcode), break13(opcode),
200137d3021Smickey 		    frame->tf_iisq_head, frame->tf_iioq_head, frame);
201e494c7cfSmickey 
202e494c7cfSmickey 	{
203e494c7cfSmickey 		extern int etext;
204532740e6Smickey 		if (frame < (struct trapframe *)&etext) {
205532740e6Smickey 			printf("trap: bogus frame ptr %p\n", frame);
206e494c7cfSmickey 			goto dead_end;
207e494c7cfSmickey 		}
208532740e6Smickey 	}
209d412f1c2Smickey #endif
2107d3bf75dSmickey 	if (trapnum != T_INTERRUPT) {
2117d3bf75dSmickey 		uvmexp.traps++;
21270016991Smickey 		mtctl(frame->tf_eiem, CR_EIEM);
213916310a5Smickey 	}
21470016991Smickey 
215a9ddc286Sguenther 	if (type & T_USER)
216a9ddc286Sguenther 		refreshcreds(p);
217a9ddc286Sguenther 
218556d2ba7Smickey 	switch (type) {
219556d2ba7Smickey 	case T_NONEXIST:
220556d2ba7Smickey 	case T_NONEXIST | T_USER:
221af7386c3Smickey 		/* we've got screwed up by the central scrutinizer */
222b67578d8Smickey 		printf("trap: elvis has just left the building!\n");
223532740e6Smickey 		goto dead_end;
224b67578d8Smickey 
225556d2ba7Smickey 	case T_RECOVERY:
226556d2ba7Smickey 	case T_RECOVERY | T_USER:
227af7386c3Smickey 		/* XXX will implement later */
228556d2ba7Smickey 		printf("trap: handicapped");
229532740e6Smickey 		goto dead_end;
23066d1ab7aSmickey 
23166d1ab7aSmickey #ifdef DIAGNOSTIC
23266d1ab7aSmickey 	case T_EXCEPTION:
23366d1ab7aSmickey 		panic("FPU/SFU emulation botch");
23466d1ab7aSmickey 
23566d1ab7aSmickey 		/* these just can't happen ever */
23666d1ab7aSmickey 	case T_PRIV_OP:
23766d1ab7aSmickey 	case T_PRIV_REG:
23866d1ab7aSmickey 		/* these just can't make it to the trap() ever */
239c6555f83Sderaadt 	case T_HPMC:
240c6555f83Sderaadt 	case T_HPMC | T_USER:
24166d1ab7aSmickey #endif
242f4daacd8Smickey 	case T_IBREAK:
243a24c0b7aSmickey 	case T_DATALIGN:
244a24c0b7aSmickey 	case T_DBREAK:
2458de28e3eSmickey 	dead_end:
246a24c0b7aSmickey #ifdef DDB
247532740e6Smickey 		if (kdb_trap(type, va, frame)) {
248a24c0b7aSmickey 			if (type == T_IBREAK) {
249f4daacd8Smickey 				/* skip break instruction */
2508de28e3eSmickey 				frame->tf_iioq_head = frame->tf_iioq_tail;
251f4daacd8Smickey 				frame->tf_iioq_tail += 4;
252a24c0b7aSmickey 			}
253556d2ba7Smickey 			return;
254a24c0b7aSmickey 		}
255137d3021Smickey #else
25678a8f2b7Smiod 		if (type == T_DATALIGN || type == T_DPROT)
257137d3021Smickey 			panic ("trap: %s at 0x%x", tts, va);
258137d3021Smickey 		else
259137d3021Smickey 			panic ("trap: no debugger for \"%s\" (%d)", tts, type);
260a24c0b7aSmickey #endif
261556d2ba7Smickey 		break;
262556d2ba7Smickey 
263af7386c3Smickey 	case T_IBREAK | T_USER:
2647bfbef72Skettenis 	case T_DBREAK | T_USER: {
2657bfbef72Skettenis 		int code = TRAP_BRKPT;
2667bfbef72Skettenis #ifdef PTRACE
2677bfbef72Skettenis 		ss_clear_breakpoints(p);
2687bfbef72Skettenis 		if (opcode == SSBREAKPOINT)
2697bfbef72Skettenis 			code = TRAP_TRACE;
2707bfbef72Skettenis #endif
271af7386c3Smickey 		/* pass to user debugger */
272f4e9e19cSguenther 		KERNEL_LOCK();
2737bfbef72Skettenis 		trapsignal(p, SIGTRAP, type & ~T_USER, code, sv);
274f4e9e19cSguenther 		KERNEL_UNLOCK();
2757bfbef72Skettenis 		}
276d412f1c2Smickey 		break;
277d412f1c2Smickey 
2787bfbef72Skettenis #ifdef PTRACE
2797bfbef72Skettenis 	case T_TAKENBR | T_USER:
2807bfbef72Skettenis 		ss_clear_breakpoints(p);
2817bfbef72Skettenis 
2827bfbef72Skettenis 		/* pass to user debugger */
283f4e9e19cSguenther 		KERNEL_LOCK();
2847bfbef72Skettenis 		trapsignal(p, SIGTRAP, type & ~T_USER, TRAP_TRACE, sv);
285f4e9e19cSguenther 		KERNEL_UNLOCK();
2867bfbef72Skettenis 		break;
2877bfbef72Skettenis #endif
2887bfbef72Skettenis 
28938575cbdSmickey 	case T_EXCEPTION | T_USER: {
2902f8e4113Sjsing 		struct hppa_fpstate *hfp;
2912f8e4113Sjsing 		u_int64_t *fpp;
292969eb289Smickey 		u_int32_t *pex;
29338575cbdSmickey 		int i, flt;
29438575cbdSmickey 
2952f8e4113Sjsing 		hfp = (struct hppa_fpstate *)frame->tf_cr30;
2962f8e4113Sjsing 		fpp = (u_int64_t *)&hfp->hfp_regs;
2972f8e4113Sjsing 
298969eb289Smickey 		pex = (u_int32_t *)&fpp[0];
29938575cbdSmickey 		for (i = 0, pex++; i < 7 && !*pex; i++, pex++);
300969eb289Smickey 		flt = 0;
301969eb289Smickey 		if (i < 7) {
302969eb289Smickey 			u_int32_t stat = HPPA_FPU_OP(*pex);
30328496d60Smickey 			if (stat & HPPA_FPU_UNMPL)
304969eb289Smickey 				flt = FPE_FLTINV;
30528496d60Smickey 			else if (stat & (HPPA_FPU_V << 1))
30638575cbdSmickey 				flt = FPE_FLTINV;
30728496d60Smickey 			else if (stat & (HPPA_FPU_Z << 1))
30838575cbdSmickey 				flt = FPE_FLTDIV;
30928496d60Smickey 			else if (stat & (HPPA_FPU_I << 1))
310969eb289Smickey 				flt = FPE_FLTRES;
31128496d60Smickey 			else if (stat & (HPPA_FPU_O << 1))
31238575cbdSmickey 				flt = FPE_FLTOVF;
31328496d60Smickey 			else if (stat & (HPPA_FPU_U << 1))
31438575cbdSmickey 				flt = FPE_FLTUND;
315969eb289Smickey 			/* still left: under/over-flow w/ inexact */
316ded58a29Smickey 
317ded58a29Smickey 			/* cleanup exceptions (XXX deliver all ?) */
318ded58a29Smickey 			while (i++ < 7)
319ded58a29Smickey 				*pex++ = 0;
320969eb289Smickey 		}
321969eb289Smickey 		/* reset the trap flag, as if there was none */
322969eb289Smickey 		fpp[0] &= ~(((u_int64_t)HPPA_FPU_T) << 32);
32338575cbdSmickey 
32438575cbdSmickey 		sv.sival_int = va;
325f4e9e19cSguenther 		KERNEL_LOCK();
32638575cbdSmickey 		trapsignal(p, SIGFPE, type & ~T_USER, flt, sv);
327f4e9e19cSguenther 		KERNEL_UNLOCK();
32838575cbdSmickey 		}
32938575cbdSmickey 		break;
33038575cbdSmickey 
331969eb289Smickey 	case T_EMULATION:
332969eb289Smickey 		panic("trap: emulation trap in the kernel");
333969eb289Smickey 		break;
334969eb289Smickey 
335969eb289Smickey 	case T_EMULATION | T_USER:
336137d3021Smickey 		sv.sival_int = va;
337f4e9e19cSguenther 		KERNEL_LOCK();
33828496d60Smickey 		trapsignal(p, SIGILL, type & ~T_USER, ILL_COPROC, sv);
339f4e9e19cSguenther 		KERNEL_UNLOCK();
340d412f1c2Smickey 		break;
341d412f1c2Smickey 
342af7386c3Smickey 	case T_OVERFLOW | T_USER:
343137d3021Smickey 		sv.sival_int = va;
344f4e9e19cSguenther 		KERNEL_LOCK();
345af7386c3Smickey 		trapsignal(p, SIGFPE, type & ~T_USER, FPE_INTOVF, sv);
346f4e9e19cSguenther 		KERNEL_UNLOCK();
347d412f1c2Smickey 		break;
348d412f1c2Smickey 
349af7386c3Smickey 	case T_CONDITION | T_USER:
3508b9bddf0Smickey 		sv.sival_int = va;
351f4e9e19cSguenther 		KERNEL_LOCK();
3528b9bddf0Smickey 		trapsignal(p, SIGFPE, type & ~T_USER, FPE_INTDIV, sv);
353f4e9e19cSguenther 		KERNEL_UNLOCK();
354af7386c3Smickey 		break;
355af7386c3Smickey 
356af7386c3Smickey 	case T_PRIV_OP | T_USER:
357137d3021Smickey 		sv.sival_int = va;
358f4e9e19cSguenther 		KERNEL_LOCK();
359af7386c3Smickey 		trapsignal(p, SIGILL, type & ~T_USER, ILL_PRVOPC, sv);
360f4e9e19cSguenther 		KERNEL_UNLOCK();
361af7386c3Smickey 		break;
362af7386c3Smickey 
363af7386c3Smickey 	case T_PRIV_REG | T_USER:
364b0be98e8Smiod 		/*
365b0be98e8Smiod 		 * On PCXS processors, attempting to read control registers
366b0be98e8Smiod 		 * cr26 and cr27 from userland causes a ``privileged register''
367b0be98e8Smiod 		 * trap.  Later processors do not restrict read accesses to
368b0be98e8Smiod 		 * these registers.
369b0be98e8Smiod 		 */
370b0be98e8Smiod 		if (cpu_type == hpcxs &&
371b0be98e8Smiod 		    (opcode & (0xfc1fffe0 | (0x1e << 21))) ==
372b0be98e8Smiod 		     (0x000008a0 | (0x1a << 21))) { /* mfctl %cr{26,27}, %r# */
373b0be98e8Smiod 			register_t cr;
374b0be98e8Smiod 
375b0be98e8Smiod 			if (((opcode >> 21) & 0x1f) == 27)
376b0be98e8Smiod 				mfctl(CR_TR3, cr);	/* cr27 */
377b0be98e8Smiod 			else
378b0be98e8Smiod 				mfctl(CR_TR2, cr);	/* cr26 */
379b0be98e8Smiod 			frame_regmap(frame, opcode & 0x1f) = cr;
380b0be98e8Smiod 			frame->tf_ipsw |= PSL_N;
381b0be98e8Smiod 		} else {
382137d3021Smickey 			sv.sival_int = va;
383f4e9e19cSguenther 			KERNEL_LOCK();
384af7386c3Smickey 			trapsignal(p, SIGILL, type & ~T_USER, ILL_PRVREG, sv);
385f4e9e19cSguenther 			KERNEL_UNLOCK();
386b0be98e8Smiod 		}
387af7386c3Smickey 		break;
388af7386c3Smickey 
389af7386c3Smickey 		/* these should never got here */
390af7386c3Smickey 	case T_HIGHERPL | T_USER:
391af7386c3Smickey 	case T_LOWERPL | T_USER:
39263b0c7d2Smiod 	case T_DATAPID | T_USER:
393137d3021Smickey 		sv.sival_int = va;
394f4e9e19cSguenther 		KERNEL_LOCK();
395a4be06b3Smickey 		trapsignal(p, SIGSEGV, vftype, SEGV_ACCERR, sv);
396f4e9e19cSguenther 		KERNEL_UNLOCK();
397af7386c3Smickey 		break;
398af7386c3Smickey 
39978a8f2b7Smiod 	/*
40078a8f2b7Smiod 	 * On PCXS processors, traps T_DATACC, T_DATAPID and T_DATALIGN
40178a8f2b7Smiod 	 * are shared.  We need to sort out the unaligned access situation
40278a8f2b7Smiod 	 * first, before handling this trap as T_DATACC.
40378a8f2b7Smiod 	 */
404af7386c3Smickey 	case T_DPROT | T_USER:
40578a8f2b7Smiod 		if (cpu_type == hpcxs) {
40678a8f2b7Smiod 			if (pcxs_unaligned(opcode, va))
40778a8f2b7Smiod 				goto datalign_user;
40878a8f2b7Smiod 			else
40978a8f2b7Smiod 				goto datacc;
41078a8f2b7Smiod 		}
41178a8f2b7Smiod 
412af7386c3Smickey 		sv.sival_int = va;
413f4e9e19cSguenther 		KERNEL_LOCK();
414af7386c3Smickey 		trapsignal(p, SIGSEGV, vftype, SEGV_ACCERR, sv);
415f4e9e19cSguenther 		KERNEL_UNLOCK();
416af7386c3Smickey 		break;
417af7386c3Smickey 
4189208e3abSmickey 	case T_ITLBMISSNA:
4199208e3abSmickey 	case T_ITLBMISSNA | T_USER:
4209208e3abSmickey 	case T_DTLBMISSNA:
4219208e3abSmickey 	case T_DTLBMISSNA | T_USER:
4229208e3abSmickey 		if (space == HPPA_SID_KERNEL)
4239208e3abSmickey 			map = kernel_map;
4249208e3abSmickey 		else {
4259208e3abSmickey 			vm = p->p_vmspace;
4269208e3abSmickey 			map = &vm->vm_map;
4279208e3abSmickey 		}
4289208e3abSmickey 
42998898169Smickey 		if ((opcode & 0xfc003fc0) == 0x04001340) {
43098898169Smickey 			/* lpa failure case */
43198898169Smickey 			frame_regmap(frame, opcode & 0x1f) = 0;
43298898169Smickey 			frame->tf_ipsw |= PSL_N;
43398898169Smickey 		} else if ((opcode & 0xfc001f80) == 0x04001180) {
4349208e3abSmickey 			int pl;
4359208e3abSmickey 
43698898169Smickey 			/* dig probe[rw]i? insns */
4379208e3abSmickey 			if (opcode & 0x2000)
4389208e3abSmickey 				pl = (opcode >> 16) & 3;
4399208e3abSmickey 			else
4409208e3abSmickey 				pl = frame_regmap(frame,
4419208e3abSmickey 				    (opcode >> 16) & 0x1f) & 3;
4429208e3abSmickey 
443cfad034cSjsing 			KERNEL_LOCK();
444cfad034cSjsing 
4459208e3abSmickey 			if ((type & T_USER && space == HPPA_SID_KERNEL) ||
4469208e3abSmickey 			    (frame->tf_iioq_head & 3) != pl ||
4479208e3abSmickey 			    (type & T_USER && va >= VM_MAXUSER_ADDRESS) ||
4485fbb3992Smartin 			    uvm_fault(map, trunc_page(va), fault,
4499208e3abSmickey 			     opcode & 0x40? UVM_PROT_WRITE : UVM_PROT_READ)) {
4509208e3abSmickey 				frame_regmap(frame, opcode & 0x1f) = 0;
4519208e3abSmickey 				frame->tf_ipsw |= PSL_N;
4529208e3abSmickey 			}
453cfad034cSjsing 
454cfad034cSjsing 			KERNEL_UNLOCK();
4559208e3abSmickey 		} else if (type & T_USER) {
4569208e3abSmickey 			sv.sival_int = va;
457f4e9e19cSguenther 			KERNEL_LOCK();
4589208e3abSmickey 			trapsignal(p, SIGILL, type & ~T_USER, ILL_ILLTRP, sv);
459f4e9e19cSguenther 			KERNEL_UNLOCK();
4609208e3abSmickey 		} else
461c8b758f8Smiod 			panic("trap: %s @ 0x%lx:0x%lx for 0x%x:0x%lx irr 0x%08x",
4629208e3abSmickey 			    tts, frame->tf_iisq_head, frame->tf_iioq_head,
4639208e3abSmickey 			    space, va, opcode);
4649208e3abSmickey 		break;
4659208e3abSmickey 
466998e9803Skettenis 	case T_IPROT | T_USER:
4679208e3abSmickey 	case T_TLB_DIRTY:
4689208e3abSmickey 	case T_TLB_DIRTY | T_USER:
469c6555f83Sderaadt 	case T_DATACC:
470c6555f83Sderaadt 	case T_DATACC | T_USER:
47178a8f2b7Smiod datacc:
4726198d067Smickey 		fault = VM_FAULT_PROTECT;
473c6555f83Sderaadt 	case T_ITLBMISS:
474c6555f83Sderaadt 	case T_ITLBMISS | T_USER:
475c6555f83Sderaadt 	case T_DTLBMISS:
476c6555f83Sderaadt 	case T_DTLBMISS | T_USER:
4778de28e3eSmickey 		/*
478e494c7cfSmickey 		 * it could be a kernel map for exec_map faults
4798de28e3eSmickey 		 */
48043a91648Smickey 		if (space == HPPA_SID_KERNEL)
4818de28e3eSmickey 			map = kernel_map;
48243a91648Smickey 		else {
48343a91648Smickey 			vm = p->p_vmspace;
484f17fa196Smickey 			map = &vm->vm_map;
48543a91648Smickey 		}
486556d2ba7Smickey 
4879208e3abSmickey 		/*
4889208e3abSmickey 		 * user faults out of user addr space are always a fail,
4899208e3abSmickey 		 * this happens on va >= VM_MAXUSER_ADDRESS, where
4909208e3abSmickey 		 * space id will be zero and therefore cause
4919208e3abSmickey 		 * a misbehave lower in the code.
4929208e3abSmickey 		 *
4939208e3abSmickey 		 * also check that faulted space id matches the curproc.
4949208e3abSmickey 		 */
4959208e3abSmickey 		if ((type & T_USER && va >= VM_MAXUSER_ADDRESS) ||
4969208e3abSmickey 		   (type & T_USER && map->pmap->pm_space != space)) {
497906a25e0Smickey 			sv.sival_int = va;
498f4e9e19cSguenther 			KERNEL_LOCK();
499906a25e0Smickey 			trapsignal(p, SIGSEGV, vftype, SEGV_MAPERR, sv);
500f4e9e19cSguenther 			KERNEL_UNLOCK();
50143a91648Smickey 			break;
502906a25e0Smickey 		}
503532740e6Smickey 
504cfad034cSjsing 		KERNEL_LOCK();
505cfad034cSjsing 
5065fbb3992Smartin 		ret = uvm_fault(map, trunc_page(va), fault, vftype);
507f17fa196Smickey 
508f17fa196Smickey 		/*
509f17fa196Smickey 		 * If this was a stack access we keep track of the maximum
510f17fa196Smickey 		 * accessed stack size.  Also, if uvm_fault gets a protection
511f17fa196Smickey 		 * failure it is due to accessing the stack region outside
512f17fa196Smickey 		 * the current limit and we need to reflect that as an access
513f17fa196Smickey 		 * error.
514f17fa196Smickey 		 */
51556f69dffSmiod 		if (space != HPPA_SID_KERNEL &&
51662899679Smiod 		    va < (vaddr_t)vm->vm_minsaddr) {
51762899679Smiod 			if (ret == 0)
51862899679Smiod 				uvm_grow(p, va);
51962899679Smiod 			else if (ret == EACCES)
520738a5b4dSart 				ret = EFAULT;
521f17fa196Smickey 		}
522f17fa196Smickey 
523cfad034cSjsing 		KERNEL_UNLOCK();
524cfad034cSjsing 
525738a5b4dSart 		if (ret != 0) {
526af7386c3Smickey 			if (type & T_USER) {
527a4be06b3Smickey 				sv.sival_int = va;
528f4e9e19cSguenther 				KERNEL_LOCK();
529a4be06b3Smickey 				trapsignal(p, SIGSEGV, vftype,
530a4be06b3Smickey 				    ret == EACCES? SEGV_ACCERR : SEGV_MAPERR,
531a4be06b3Smickey 				    sv);
532f4e9e19cSguenther 				KERNEL_UNLOCK();
533137d3021Smickey 			} else {
5348de28e3eSmickey 				if (p && p->p_addr->u_pcb.pcb_onfault) {
5358de28e3eSmickey 					frame->tf_iioq_tail = 4 +
5368de28e3eSmickey 					    (frame->tf_iioq_head =
53738575cbdSmickey 						p->p_addr->u_pcb.pcb_onfault);
538b04f760fSmickey #ifdef DDB
539b04f760fSmickey 					frame->tf_iir = 0;
540b04f760fSmickey #endif
541db97f33bSmickey 				} else {
542db97f33bSmickey 					panic("trap: "
54356f69dffSmiod 					    "uvm_fault(%p, %lx, %d, %d): %d",
54496415af6Smickey 					    map, va, fault, vftype, ret);
545137d3021Smickey 				}
546137d3021Smickey 			}
547db97f33bSmickey 		}
548556d2ba7Smickey 		break;
549d412f1c2Smickey 
55063b0c7d2Smiod 	case T_DATAPID:
55163b0c7d2Smiod 		/* This should never happen, unless within spcopy() */
55263b0c7d2Smiod 		if (p && p->p_addr->u_pcb.pcb_onfault) {
55363b0c7d2Smiod 			frame->tf_iioq_tail = 4 +
55463b0c7d2Smiod 			    (frame->tf_iioq_head =
55563b0c7d2Smiod 				p->p_addr->u_pcb.pcb_onfault);
55663b0c7d2Smiod #ifdef DDB
55763b0c7d2Smiod 			frame->tf_iir = 0;
55863b0c7d2Smiod #endif
55963b0c7d2Smiod 		} else
56063b0c7d2Smiod 			goto dead_end;
56163b0c7d2Smiod 		break;
56263b0c7d2Smiod 
563af7386c3Smickey 	case T_DATALIGN | T_USER:
56478a8f2b7Smiod datalign_user:
565137d3021Smickey 		sv.sival_int = va;
566f4e9e19cSguenther 		KERNEL_LOCK();
567af7386c3Smickey 		trapsignal(p, SIGBUS, vftype, BUS_ADRALN, sv);
568f4e9e19cSguenther 		KERNEL_UNLOCK();
569af7386c3Smickey 		break;
570af7386c3Smickey 
571a24c0b7aSmickey 	case T_INTERRUPT:
572a24c0b7aSmickey 	case T_INTERRUPT | T_USER:
573a24c0b7aSmickey 		cpu_intr(frame);
574af7386c3Smickey 		break;
575af7386c3Smickey 
576b7d25a19Smickey 	case T_CONDITION:
577b7d25a19Smickey 		panic("trap: divide by zero in the kernel");
578b7d25a19Smickey 		break;
579b7d25a19Smickey 
5803147f0deSmickey 	case T_ILLEGAL:
5813147f0deSmickey 	case T_ILLEGAL | T_USER:
5823147f0deSmickey 		/* see if it's a SPOP1,,0 */
58396415af6Smickey 		if ((opcode & 0xfffffe00) == 0x10000200) {
58496415af6Smickey 			frame_regmap(frame, opcode & 0x1f) = 0;
5853147f0deSmickey 			frame->tf_ipsw |= PSL_N;
5863147f0deSmickey 			break;
5873147f0deSmickey 		}
5883147f0deSmickey 		if (type & T_USER) {
5893147f0deSmickey 			sv.sival_int = va;
590f4e9e19cSguenther 			KERNEL_LOCK();
5913147f0deSmickey 			trapsignal(p, SIGILL, type & ~T_USER, ILL_ILLOPC, sv);
592f4e9e19cSguenther 			KERNEL_UNLOCK();
5933147f0deSmickey 			break;
5943147f0deSmickey 		}
5953147f0deSmickey 		/* FALLTHROUGH */
5963147f0deSmickey 
59778a8f2b7Smiod 	/*
59878a8f2b7Smiod 	 * On PCXS processors, traps T_DATACC, T_DATAPID and T_DATALIGN
59978a8f2b7Smiod 	 * are shared.  We need to sort out the unaligned access situation
60078a8f2b7Smiod 	 * first, before handling this trap as T_DATACC.
60178a8f2b7Smiod 	 */
6022ef9a47eSmickey 	case T_DPROT:
60378a8f2b7Smiod 		if (cpu_type == hpcxs) {
60478a8f2b7Smiod 			if (pcxs_unaligned(opcode, va))
60578a8f2b7Smiod 				goto dead_end;
60678a8f2b7Smiod 			else
60778a8f2b7Smiod 				goto datacc;
60878a8f2b7Smiod 		}
60978a8f2b7Smiod 		/* FALLTHROUGH to unimplemented */
61078a8f2b7Smiod 
61178a8f2b7Smiod 	case T_LOWERPL:
6122ef9a47eSmickey 	case T_IPROT:
613af7386c3Smickey 	case T_OVERFLOW:
614af7386c3Smickey 	case T_HIGHERPL:
615af7386c3Smickey 	case T_TAKENBR:
616af7386c3Smickey 	case T_POWERFAIL:
617af7386c3Smickey 	case T_LPMC:
618af7386c3Smickey 	case T_PAGEREF:
619d412f1c2Smickey 		/* FALLTHROUGH to unimplemented */
620d412f1c2Smickey 	default:
621ea3191ebSjsing #ifdef TRAPDEBUG
622532740e6Smickey 		if (kdb_trap(type, va, frame))
623137d3021Smickey 			return;
624137d3021Smickey #endif
62570016991Smickey 		panic("trap: unimplemented \'%s\' (%d)", tts, trapnum);
626d412f1c2Smickey 	}
627af7386c3Smickey 
62870016991Smickey #ifdef DIAGNOSTIC
629473ddf34Sjsing 	if (curcpu()->ci_cpl != oldcpl)
63070016991Smickey 		printf("WARNING: SPL (%d) NOT LOWERED ON "
631473ddf34Sjsing 		    "TRAP (%d) EXIT\n", curcpu()->ci_cpl, trapnum);
63270016991Smickey #endif
63370016991Smickey 
63470016991Smickey 	if (trapnum != T_INTERRUPT)
635473ddf34Sjsing 		splx(curcpu()->ci_cpl);	/* process softints */
63670016991Smickey 
637ba42a120Smickey 	/*
638ba42a120Smickey 	 * in case we were interrupted from the syscall gate page
63924d53bfeSkrw 	 * treat this as we were not really running user code no more
640ba42a120Smickey 	 * for weird things start to happen on return to the userland
641ba42a120Smickey 	 * and also see a note in locore.S:TLABEL(all)
642ba42a120Smickey 	 */
6437b428176Smickey 	if ((type & T_USER) && !(frame->tf_iisq_head == HPPA_SID_KERNEL &&
644c2b93341Sderaadt 	    (frame->tf_iioq_head & ~PAGE_MASK) == SYSCALLGATE)) {
645c2b93341Sderaadt 		ast(p);
646c19cb33fSmickey 		userret(p);
647d412f1c2Smickey 	}
648c2b93341Sderaadt }
649d412f1c2Smickey 
650d412f1c2Smickey void
651cfad034cSjsing child_return(void *arg)
652d412f1c2Smickey {
653db36253aSmickey 	struct proc *p = (struct proc *)arg;
65489afe3e5Smickey 	struct trapframe *tf = p->p_md.md_regs;
65589afe3e5Smickey 
65689afe3e5Smickey 	/*
65789afe3e5Smickey 	 * Set up return value registers as libc:fork() expects
65889afe3e5Smickey 	 */
65989afe3e5Smickey 	tf->tf_ret0 = 0;
66089afe3e5Smickey 	tf->tf_ret1 = 1;	/* ischild */
66189afe3e5Smickey 	tf->tf_t1 = 0;		/* errno */
66289afe3e5Smickey 
663971e1bb6Sart 	KERNEL_UNLOCK();
664cfad034cSjsing 
665c2b93341Sderaadt 	ast(p);
666fc572715Sguenther 
667fc572715Sguenther 	mi_child_return(p);
668556d2ba7Smickey }
669556d2ba7Smickey 
6707bfbef72Skettenis #ifdef PTRACE
6717bfbef72Skettenis 
6727bfbef72Skettenis #include <sys/ptrace.h>
6737bfbef72Skettenis 
674dd6e4488Sderaadt int	ss_get_value(struct proc *p, vaddr_t addr, u_int *value);
675dd6e4488Sderaadt int	ss_put_value(struct proc *p, vaddr_t addr, u_int value);
676dd6e4488Sderaadt 
6777bfbef72Skettenis int
6787bfbef72Skettenis ss_get_value(struct proc *p, vaddr_t addr, u_int *value)
6797bfbef72Skettenis {
6807bfbef72Skettenis 	struct uio uio;
6817bfbef72Skettenis 	struct iovec iov;
6827bfbef72Skettenis 
6837bfbef72Skettenis 	iov.iov_base = (caddr_t)value;
6847bfbef72Skettenis 	iov.iov_len = sizeof(u_int);
6857bfbef72Skettenis 	uio.uio_iov = &iov;
6867bfbef72Skettenis 	uio.uio_iovcnt = 1;
6877bfbef72Skettenis 	uio.uio_offset = (off_t)addr;
6887bfbef72Skettenis 	uio.uio_resid = sizeof(u_int);
6897bfbef72Skettenis 	uio.uio_segflg = UIO_SYSSPACE;
6907bfbef72Skettenis 	uio.uio_rw = UIO_READ;
6917bfbef72Skettenis 	uio.uio_procp = curproc;
6920888e41eSmiod 	return (process_domem(curproc, p, &uio, PT_READ_I));
6937bfbef72Skettenis }
6947bfbef72Skettenis 
6957bfbef72Skettenis int
6967bfbef72Skettenis ss_put_value(struct proc *p, vaddr_t addr, u_int value)
6977bfbef72Skettenis {
6987bfbef72Skettenis 	struct uio uio;
6997bfbef72Skettenis 	struct iovec iov;
7007bfbef72Skettenis 
7017bfbef72Skettenis 	iov.iov_base = (caddr_t)&value;
7027bfbef72Skettenis 	iov.iov_len = sizeof(u_int);
7037bfbef72Skettenis 	uio.uio_iov = &iov;
7047bfbef72Skettenis 	uio.uio_iovcnt = 1;
7057bfbef72Skettenis 	uio.uio_offset = (off_t)addr;
7067bfbef72Skettenis 	uio.uio_resid = sizeof(u_int);
7077bfbef72Skettenis 	uio.uio_segflg = UIO_SYSSPACE;
7087bfbef72Skettenis 	uio.uio_rw = UIO_WRITE;
7097bfbef72Skettenis 	uio.uio_procp = curproc;
7100888e41eSmiod 	return (process_domem(curproc, p, &uio, PT_WRITE_I));
7117bfbef72Skettenis }
7127bfbef72Skettenis 
7137bfbef72Skettenis void
7147bfbef72Skettenis ss_clear_breakpoints(struct proc *p)
7157bfbef72Skettenis {
7167bfbef72Skettenis 	/* Restore origional instructions. */
7177bfbef72Skettenis 	if (p->p_md.md_bpva != 0) {
7187bfbef72Skettenis 		ss_put_value(p, p->p_md.md_bpva, p->p_md.md_bpsave[0]);
7197bfbef72Skettenis 		ss_put_value(p, p->p_md.md_bpva + 4, p->p_md.md_bpsave[1]);
7207bfbef72Skettenis 		p->p_md.md_bpva = 0;
7217bfbef72Skettenis 	}
7227bfbef72Skettenis }
7237bfbef72Skettenis 
7247bfbef72Skettenis int
7257bfbef72Skettenis process_sstep(struct proc *p, int sstep)
7267bfbef72Skettenis {
7277bfbef72Skettenis 	int error;
7287bfbef72Skettenis 
7297bfbef72Skettenis 	ss_clear_breakpoints(p);
7307bfbef72Skettenis 
73185bd3014Skettenis 	if (sstep == 0) {
7327bfbef72Skettenis 		p->p_md.md_regs->tf_ipsw &= ~PSL_T;
7337bfbef72Skettenis 		return (0);
7347bfbef72Skettenis 	}
7357bfbef72Skettenis 
73685bd3014Skettenis 	/*
73785bd3014Skettenis 	 * Don't touch the syscall gateway page.  Instead, insert a
73885bd3014Skettenis 	 * breakpoint where we're supposed to return.
73985bd3014Skettenis 	 */
74085bd3014Skettenis 	if ((p->p_md.md_regs->tf_iioq_tail & ~PAGE_MASK) == SYSCALLGATE)
74185bd3014Skettenis 		p->p_md.md_bpva = p->p_md.md_regs->tf_r31 & ~HPPA_PC_PRIV_MASK;
74285bd3014Skettenis 	else
7437bfbef72Skettenis 		p->p_md.md_bpva = p->p_md.md_regs->tf_iioq_tail & ~HPPA_PC_PRIV_MASK;
7447bfbef72Skettenis 
7457bfbef72Skettenis 	/*
7467bfbef72Skettenis 	 * Insert two breakpoint instructions; the first one might be
7477bfbef72Skettenis 	 * nullified.  Of course we need to save two instruction
7487bfbef72Skettenis 	 * first.
7497bfbef72Skettenis 	 */
7507bfbef72Skettenis 
7517bfbef72Skettenis 	error = ss_get_value(p, p->p_md.md_bpva, &p->p_md.md_bpsave[0]);
7527bfbef72Skettenis 	if (error)
7537bfbef72Skettenis 		return (error);
7547bfbef72Skettenis 	error = ss_get_value(p, p->p_md.md_bpva + 4, &p->p_md.md_bpsave[1]);
7557bfbef72Skettenis 	if (error)
7567bfbef72Skettenis 		return (error);
7577bfbef72Skettenis 
7587bfbef72Skettenis 	error = ss_put_value(p, p->p_md.md_bpva, SSBREAKPOINT);
7597bfbef72Skettenis 	if (error)
7607bfbef72Skettenis 		return (error);
7617bfbef72Skettenis 	error = ss_put_value(p, p->p_md.md_bpva + 4, SSBREAKPOINT);
7627bfbef72Skettenis 	if (error)
7637bfbef72Skettenis 		return (error);
7647bfbef72Skettenis 
76585bd3014Skettenis 	if ((p->p_md.md_regs->tf_iioq_tail & ~PAGE_MASK) != SYSCALLGATE)
7667bfbef72Skettenis 		p->p_md.md_regs->tf_ipsw |= PSL_T;
76785bd3014Skettenis 	else
76885bd3014Skettenis 		p->p_md.md_regs->tf_ipsw &= ~PSL_T;
76985bd3014Skettenis 
7707bfbef72Skettenis 	return (0);
7717bfbef72Skettenis }
7727bfbef72Skettenis 
7737bfbef72Skettenis #endif	/* PTRACE */
774db97f33bSmickey 
775dd6e4488Sderaadt void	syscall(struct trapframe *frame);
776dd6e4488Sderaadt 
777b9b95e0dSmickey /*
778b9b95e0dSmickey  * call actual syscall routine
779b9b95e0dSmickey  */
780b9b95e0dSmickey void
78170016991Smickey syscall(struct trapframe *frame)
782b9b95e0dSmickey {
783db97f33bSmickey 	register struct proc *p = curproc;
784b9b95e0dSmickey 	register const struct sysent *callp;
7859417b0e6Sguenther 	int retq, nsys, code, argsize, argoff, error;
786b7d25a19Smickey 	register_t args[8], rval[2];
78770016991Smickey #ifdef DIAGNOSTIC
788473ddf34Sjsing 	int oldcpl = curcpu()->ci_cpl;
78970016991Smickey #endif
790b9b95e0dSmickey 
791b9b95e0dSmickey 	uvmexp.syscalls++;
792b9b95e0dSmickey 
793b9b95e0dSmickey 	if (!USERMODE(frame->tf_iioq_head))
794b9b95e0dSmickey 		panic("syscall");
795b9b95e0dSmickey 
796137d3021Smickey 	p->p_md.md_regs = frame;
7978f76f5adSguenther 	nsys = p->p_p->ps_emul->e_nsysent;
7988f76f5adSguenther 	callp = p->p_p->ps_emul->e_sysent;
799db97f33bSmickey 
800b7d25a19Smickey 	argoff = 4; retq = 0;
801db97f33bSmickey 	switch (code = frame->tf_t1) {
802b9b95e0dSmickey 	case SYS_syscall:
803db97f33bSmickey 		code = frame->tf_arg0;
804db97f33bSmickey 		args[0] = frame->tf_arg1;
805db97f33bSmickey 		args[1] = frame->tf_arg2;
806db97f33bSmickey 		args[2] = frame->tf_arg3;
807db97f33bSmickey 		argoff = 3;
808b9b95e0dSmickey 		break;
809b9b95e0dSmickey 	case SYS___syscall:
810b9b95e0dSmickey 		if (callp != sysent)
811b9b95e0dSmickey 			break;
812db97f33bSmickey 		/*
813db97f33bSmickey 		 * this works, because quads get magically swapped
8147503858eSjfb 		 * due to the args being laid backwards on the stack
815db97f33bSmickey 		 * and then copied in words
816db97f33bSmickey 		 */
817db97f33bSmickey 		code = frame->tf_arg0;
818db97f33bSmickey 		args[0] = frame->tf_arg2;
819db97f33bSmickey 		args[1] = frame->tf_arg3;
820db97f33bSmickey 		argoff = 2;
821b7d25a19Smickey 		retq = 1;
822db97f33bSmickey 		break;
823db97f33bSmickey 	default:
824db97f33bSmickey 		args[0] = frame->tf_arg0;
825db97f33bSmickey 		args[1] = frame->tf_arg1;
826db97f33bSmickey 		args[2] = frame->tf_arg2;
827db97f33bSmickey 		args[3] = frame->tf_arg3;
828db97f33bSmickey 		break;
829b9b95e0dSmickey 	}
830b9b95e0dSmickey 
831b9b95e0dSmickey 	if (code < 0 || code >= nsys)
8328f76f5adSguenther 		callp += p->p_p->ps_emul->e_nosys;	/* bad syscall # */
833b9b95e0dSmickey 	else
834b9b95e0dSmickey 		callp += code;
835db97f33bSmickey 
836db97f33bSmickey 	if ((argsize = callp->sy_argsize)) {
837db97f33bSmickey 		int i;
838db97f33bSmickey 
839db97f33bSmickey 		for (i = 0, argsize -= argoff * 4;
840db97f33bSmickey 		    argsize > 0; i++, argsize -= 4) {
841fc572715Sguenther 			if ((error = copyin((void *)(frame->tf_sp +
842fc572715Sguenther 			    HPPA_FRAME_ARG(i + 4)), args + i + argoff, 4)))
843fc572715Sguenther 				goto bad;
844db97f33bSmickey 		}
845db97f33bSmickey 
846db97f33bSmickey 		/*
847db97f33bSmickey 		 * coming from syscall() or __syscall we must be
848db97f33bSmickey 		 * having one of those w/ a 64 bit arguments,
849db97f33bSmickey 		 * which needs a word swap due to the order
850db97f33bSmickey 		 * of the arguments on the stack.
851db97f33bSmickey 		 * this assumes that none of 'em are called
852db97f33bSmickey 		 * by their normal syscall number, maybe a regress
853b49f4f07Smiod 		 * test should be used, to watch the behaviour.
854db97f33bSmickey 		 */
855fc572715Sguenther 		if (argoff < 4) {
856db97f33bSmickey 			int t;
857db97f33bSmickey 
858db97f33bSmickey 			i = 0;
859db97f33bSmickey 			switch (code) {
860b7d25a19Smickey 			case SYS_lseek:		retq = 0;
861db97f33bSmickey 			case SYS_truncate:
862db97f33bSmickey 			case SYS_ftruncate:	i = 2;	break;
863db97f33bSmickey 			case SYS_preadv:
864db97f33bSmickey 			case SYS_pwritev:
865db97f33bSmickey 			case SYS_pread:
866db97f33bSmickey 			case SYS_pwrite:	i = 4;	break;
867a9d0813cSmiod 			case SYS_mquery:
868db97f33bSmickey 			case SYS_mmap:		i = 6;	break;
869db97f33bSmickey 			}
870db97f33bSmickey 
871db97f33bSmickey 			if (i) {
872db97f33bSmickey 				t = args[i];
873db97f33bSmickey 				args[i] = args[i + 1];
874db97f33bSmickey 				args[i + 1] = t;
875db97f33bSmickey 			}
876db97f33bSmickey 		}
877db97f33bSmickey 	}
878b9b95e0dSmickey 
879b9b95e0dSmickey 	rval[0] = 0;
880db97f33bSmickey 	rval[1] = frame->tf_ret1;
881cfad034cSjsing 
8829417b0e6Sguenther 	error = mi_syscall(p, code, callp, args, rval);
883fc572715Sguenther 
88496a1071fSmiod 	switch (error) {
885b9b95e0dSmickey 	case 0:
886b9b95e0dSmickey 		frame->tf_ret0 = rval[0];
887b7d25a19Smickey 		frame->tf_ret1 = rval[!retq];
888137d3021Smickey 		frame->tf_t1 = 0;
889b9b95e0dSmickey 		break;
890b9b95e0dSmickey 	case ERESTART:
891c37e03c6Smickey 		frame->tf_iioq_head -= 12;
892c37e03c6Smickey 		frame->tf_iioq_tail -= 12;
893b9b95e0dSmickey 	case EJUSTRETURN:
894b9b95e0dSmickey 		break;
895b9b95e0dSmickey 	default:
896db97f33bSmickey 	bad:
897137d3021Smickey 		frame->tf_t1 = error;
89847df6ae3Smickey 		frame->tf_ret0 = error;
89947df6ae3Smickey 		frame->tf_ret1 = 0;
900b9b95e0dSmickey 		break;
901b9b95e0dSmickey 	}
902fc572715Sguenther 
903c2b93341Sderaadt 	ast(p);
904fc572715Sguenther 
9059417b0e6Sguenther 	mi_syscall_return(p, code, error, rval);
906fc572715Sguenther 
90770016991Smickey #ifdef DIAGNOSTIC
908473ddf34Sjsing 	if (curcpu()->ci_cpl != oldcpl) {
90970016991Smickey 		printf("WARNING: SPL (0x%x) NOT LOWERED ON "
910c8b758f8Smiod 		    "syscall(0x%x, 0x%lx, 0x%lx, 0x%lx...) EXIT, PID %d\n",
911473ddf34Sjsing 		    curcpu()->ci_cpl, code, args[0], args[1], args[2],
912473ddf34Sjsing 		    p->p_pid);
913473ddf34Sjsing 		curcpu()->ci_cpl = oldcpl;
91450552582Smickey 	}
91570016991Smickey #endif
916473ddf34Sjsing 	splx(curcpu()->ci_cpl);	/* process softints */
917b9b95e0dSmickey }
91878a8f2b7Smiod 
91978a8f2b7Smiod /*
92078a8f2b7Smiod  * Decide if opcode `opcode' accessing virtual address `va' caused an
92178a8f2b7Smiod  * unaligned trap. Returns zero if the access is correctly aligned.
92278a8f2b7Smiod  * Used on PCXS processors to sort out exception causes.
92378a8f2b7Smiod  */
92478a8f2b7Smiod int
92578a8f2b7Smiod pcxs_unaligned(u_int opcode, vaddr_t va)
92678a8f2b7Smiod {
92778a8f2b7Smiod 	u_int mbz_bits;
92878a8f2b7Smiod 
92978a8f2b7Smiod 	/*
93078a8f2b7Smiod 	 * Exit early if the va is obviously aligned enough.
93178a8f2b7Smiod 	 */
93278a8f2b7Smiod 	if ((va & 0x0f) == 0)
93378a8f2b7Smiod 		return 0;
93478a8f2b7Smiod 
93578a8f2b7Smiod 	mbz_bits = 0;
93678a8f2b7Smiod 
93778a8f2b7Smiod 	/*
93878a8f2b7Smiod 	 * Only load and store instructions can cause unaligned access.
93978a8f2b7Smiod 	 * There are three opcode patterns to look for:
94078a8f2b7Smiod 	 * - canonical load/store
94178a8f2b7Smiod 	 * - load/store short or indexed
94278a8f2b7Smiod 	 * - coprocessor load/store
94378a8f2b7Smiod 	 */
94478a8f2b7Smiod 
94578a8f2b7Smiod 	if ((opcode & 0xd0000000) == 0x40000000) {
94678a8f2b7Smiod 		switch ((opcode >> 26) & 0x03) {
94778a8f2b7Smiod 		case 0x00:	/* ldb, stb */
94878a8f2b7Smiod 			mbz_bits = 0x00;
94978a8f2b7Smiod 			break;
95078a8f2b7Smiod 		case 0x01:	/* ldh, sth */
95178a8f2b7Smiod 			mbz_bits = 0x01;
95278a8f2b7Smiod 			break;
95378a8f2b7Smiod 		case 0x02:	/* ldw, stw */
95478a8f2b7Smiod 		case 0x03:	/* ldwm, stwm */
95578a8f2b7Smiod 			mbz_bits = 0x03;
95678a8f2b7Smiod 			break;
95778a8f2b7Smiod 		}
95878a8f2b7Smiod 	} else
95978a8f2b7Smiod 
96078a8f2b7Smiod 	if ((opcode & 0xfc000000) == 0x0c000000) {
96178a8f2b7Smiod 		switch ((opcode >> 6) & 0x0f) {
96278a8f2b7Smiod 		case 0x01:	/* ldhx, ldhs */
96378a8f2b7Smiod 			mbz_bits = 0x01;
96478a8f2b7Smiod 			break;
96578a8f2b7Smiod 		case 0x02:	/* ldwx, ldws */
96678a8f2b7Smiod 			mbz_bits = 0x03;
96778a8f2b7Smiod 			break;
96878a8f2b7Smiod 		case 0x07:	/* ldcwx, ldcws */
96978a8f2b7Smiod 			mbz_bits = 0x0f;
97078a8f2b7Smiod 			break;
97178a8f2b7Smiod 		case 0x09:
97278a8f2b7Smiod 			if ((opcode & (1 << 12)) != 0)	/* sths */
97378a8f2b7Smiod 				mbz_bits = 0x01;
97478a8f2b7Smiod 			break;
97578a8f2b7Smiod 		case 0x0a:
97678a8f2b7Smiod 			if ((opcode & (1 << 12)) != 0)	/* stws */
97778a8f2b7Smiod 				mbz_bits = 0x03;
97878a8f2b7Smiod 			break;
97978a8f2b7Smiod 		}
98078a8f2b7Smiod 	} else
98178a8f2b7Smiod 
98278a8f2b7Smiod 	if ((opcode & 0xf4000000) == 0x24000000) {
98378a8f2b7Smiod 		if ((opcode & (1 << 27)) != 0) {
98478a8f2b7Smiod 			/* cldwx, cstwx, cldws, cstws */
98578a8f2b7Smiod 			mbz_bits = 0x03;
98678a8f2b7Smiod 		} else {
98778a8f2b7Smiod 			/* clddx, cstdx, cldds, cstds */
98878a8f2b7Smiod 			mbz_bits = 0x07;
98978a8f2b7Smiod 		}
99078a8f2b7Smiod 	}
99178a8f2b7Smiod 
99278a8f2b7Smiod 	return (va & mbz_bits);
99378a8f2b7Smiod }
994