xref: /openbsd/sys/arch/hppa/hppa/trap.c (revision 36dba039)
1*36dba039Sjsg /*	$OpenBSD: trap.c,v 1.166 2024/04/14 03:26:25 jsg 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>
375ab06ed0Sderaadt #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 
inst_store(u_int ins)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
ast(struct proc * p)138c2b93341Sderaadt ast(struct proc *p)
139d412f1c2Smickey {
140da6814fdSjsing 	if (p->p_md.md_astpending) {
141da6814fdSjsing 		p->p_md.md_astpending = 0;
142622fac8aSguenther 		uvmexp.softs++;
143db13da92Sguenther 		mi_ast(p, curcpu()->ci_want_resched);
144c19cb33fSmickey 	}
145c19cb33fSmickey 
146d412f1c2Smickey }
147d412f1c2Smickey 
148556d2ba7Smickey void
trap(int type,struct trapframe * frame)149c33335b0Sjsing trap(int type, struct trapframe *frame)
150556d2ba7Smickey {
151556d2ba7Smickey 	struct proc *p = curproc;
152ab8e80c5Sart 	vaddr_t va;
153ab8e80c5Sart 	struct vm_map *map;
154f17fa196Smickey 	struct vmspace *vm;
1556e66b933Sderaadt 	register vm_prot_t access_type;
156556d2ba7Smickey 	register pa_space_t space;
157af7386c3Smickey 	union sigval sv;
158c37e03c6Smickey 	u_int opcode;
15970016991Smickey 	int ret, trapnum;
160137d3021Smickey 	const char *tts;
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;
1726e66b933Sderaadt 		access_type = PROT_EXEC;
173a24c0b7aSmickey 	} else {
174b9b95e0dSmickey 		va = frame->tf_ior;
175a24c0b7aSmickey 		space = frame->tf_isr;
176a4be06b3Smickey 		if (va == frame->tf_iioq_head)
1776e66b933Sderaadt 			access_type = PROT_EXEC;
178a4be06b3Smickey 		else if (inst_store(opcode))
1796e66b933Sderaadt 			access_type = PROT_WRITE;
180a4be06b3Smickey 		else
1816e66b933Sderaadt 			access_type = 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 
2155e7211b0Sderaadt 	if (type & T_USER)
216a9ddc286Sguenther 		refreshcreds(p);
217003f5e42Sderaadt 
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
247a1a7d5d9Smpi 		if (db_ktrap(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)
257f705839eSderaadt 			panic ("trap: %s at 0x%lx", 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;
266d48416acStobiasu 
2677bfbef72Skettenis #ifdef PTRACE
268afcd8e7bSclaudio 		KERNEL_LOCK();
2697bfbef72Skettenis 		ss_clear_breakpoints(p);
2707bfbef72Skettenis 		if (opcode == SSBREAKPOINT)
2717bfbef72Skettenis 			code = TRAP_TRACE;
272afcd8e7bSclaudio 		KERNEL_UNLOCK();
2737bfbef72Skettenis #endif
274af7386c3Smickey 		/* pass to user debugger */
275f46ffae9Smiod 		sv.sival_int = va;
2767bfbef72Skettenis 		trapsignal(p, SIGTRAP, type & ~T_USER, code, sv);
2777bfbef72Skettenis 		}
278d412f1c2Smickey 		break;
279d412f1c2Smickey 
2807bfbef72Skettenis #ifdef PTRACE
2817bfbef72Skettenis 	case T_TAKENBR | T_USER:
282f4e9e19cSguenther 		KERNEL_LOCK();
283d48416acStobiasu 		ss_clear_breakpoints(p);
284afcd8e7bSclaudio 		KERNEL_UNLOCK();
285d48416acStobiasu 		/* pass to user debugger */
286f46ffae9Smiod 		sv.sival_int = va;
2877bfbef72Skettenis 		trapsignal(p, SIGTRAP, type & ~T_USER, TRAP_TRACE, sv);
2887bfbef72Skettenis 		break;
2897bfbef72Skettenis #endif
2907bfbef72Skettenis 
29138575cbdSmickey 	case T_EXCEPTION | T_USER: {
2922f8e4113Sjsing 		struct hppa_fpstate *hfp;
2932f8e4113Sjsing 		u_int64_t *fpp;
294969eb289Smickey 		u_int32_t *pex;
29538575cbdSmickey 		int i, flt;
29638575cbdSmickey 
2972f8e4113Sjsing 		hfp = (struct hppa_fpstate *)frame->tf_cr30;
2982f8e4113Sjsing 		fpp = (u_int64_t *)&hfp->hfp_regs;
2992f8e4113Sjsing 
300969eb289Smickey 		pex = (u_int32_t *)&fpp[0];
301*36dba039Sjsg 		for (i = 0, pex++; i < 7 && !*pex; i++, pex++)
302*36dba039Sjsg 			;
303969eb289Smickey 		flt = 0;
304969eb289Smickey 		if (i < 7) {
305969eb289Smickey 			u_int32_t stat = HPPA_FPU_OP(*pex);
30628496d60Smickey 			if (stat & HPPA_FPU_UNMPL)
307969eb289Smickey 				flt = FPE_FLTINV;
30828496d60Smickey 			else if (stat & (HPPA_FPU_V << 1))
30938575cbdSmickey 				flt = FPE_FLTINV;
31028496d60Smickey 			else if (stat & (HPPA_FPU_Z << 1))
31138575cbdSmickey 				flt = FPE_FLTDIV;
31228496d60Smickey 			else if (stat & (HPPA_FPU_I << 1))
313969eb289Smickey 				flt = FPE_FLTRES;
31428496d60Smickey 			else if (stat & (HPPA_FPU_O << 1))
31538575cbdSmickey 				flt = FPE_FLTOVF;
31628496d60Smickey 			else if (stat & (HPPA_FPU_U << 1))
31738575cbdSmickey 				flt = FPE_FLTUND;
318969eb289Smickey 			/* still left: under/over-flow w/ inexact */
319ded58a29Smickey 
320ded58a29Smickey 			/* cleanup exceptions (XXX deliver all ?) */
321ded58a29Smickey 			while (i++ < 7)
322ded58a29Smickey 				*pex++ = 0;
323969eb289Smickey 		}
324969eb289Smickey 		/* reset the trap flag, as if there was none */
325969eb289Smickey 		fpp[0] &= ~(((u_int64_t)HPPA_FPU_T) << 32);
32638575cbdSmickey 
32738575cbdSmickey 		sv.sival_int = va;
32838575cbdSmickey 		trapsignal(p, SIGFPE, type & ~T_USER, flt, sv);
32938575cbdSmickey 		}
33038575cbdSmickey 		break;
33138575cbdSmickey 
332969eb289Smickey 	case T_EMULATION:
333969eb289Smickey 		panic("trap: emulation trap in the kernel");
334969eb289Smickey 		break;
335969eb289Smickey 
336969eb289Smickey 	case T_EMULATION | T_USER:
337137d3021Smickey 		sv.sival_int = va;
33828496d60Smickey 		trapsignal(p, SIGILL, type & ~T_USER, ILL_COPROC, sv);
339d412f1c2Smickey 		break;
340d412f1c2Smickey 
341af7386c3Smickey 	case T_OVERFLOW | T_USER:
342137d3021Smickey 		sv.sival_int = va;
343af7386c3Smickey 		trapsignal(p, SIGFPE, type & ~T_USER, FPE_INTOVF, sv);
344d412f1c2Smickey 		break;
345d412f1c2Smickey 
346af7386c3Smickey 	case T_CONDITION | T_USER:
3478b9bddf0Smickey 		sv.sival_int = va;
3488b9bddf0Smickey 		trapsignal(p, SIGFPE, type & ~T_USER, FPE_INTDIV, sv);
349af7386c3Smickey 		break;
350af7386c3Smickey 
351af7386c3Smickey 	case T_PRIV_OP | T_USER:
352137d3021Smickey 		sv.sival_int = va;
353af7386c3Smickey 		trapsignal(p, SIGILL, type & ~T_USER, ILL_PRVOPC, sv);
354af7386c3Smickey 		break;
355af7386c3Smickey 
356af7386c3Smickey 	case T_PRIV_REG | T_USER:
357b0be98e8Smiod 		/*
358b0be98e8Smiod 		 * On PCXS processors, attempting to read control registers
359b0be98e8Smiod 		 * cr26 and cr27 from userland causes a ``privileged register''
360b0be98e8Smiod 		 * trap.  Later processors do not restrict read accesses to
361b0be98e8Smiod 		 * these registers.
362b0be98e8Smiod 		 */
363b0be98e8Smiod 		if (cpu_type == hpcxs &&
364b0be98e8Smiod 		    (opcode & (0xfc1fffe0 | (0x1e << 21))) ==
365b0be98e8Smiod 		     (0x000008a0 | (0x1a << 21))) { /* mfctl %cr{26,27}, %r# */
366b0be98e8Smiod 			register_t cr;
367b0be98e8Smiod 
368b0be98e8Smiod 			if (((opcode >> 21) & 0x1f) == 27)
3695ec14294Skettenis 				cr = frame->tf_cr27;	/* cr27 */
370b0be98e8Smiod 			else
3715ec14294Skettenis 				cr = 0;			/* cr26 */
372b0be98e8Smiod 			frame_regmap(frame, opcode & 0x1f) = cr;
373b0be98e8Smiod 			frame->tf_ipsw |= PSL_N;
374b0be98e8Smiod 		} else {
375137d3021Smickey 			sv.sival_int = va;
376af7386c3Smickey 			trapsignal(p, SIGILL, type & ~T_USER, ILL_PRVREG, sv);
377b0be98e8Smiod 		}
378af7386c3Smickey 		break;
379af7386c3Smickey 
380af7386c3Smickey 		/* these should never got here */
381af7386c3Smickey 	case T_HIGHERPL | T_USER:
382af7386c3Smickey 	case T_LOWERPL | T_USER:
38363b0c7d2Smiod 	case T_DATAPID | T_USER:
384137d3021Smickey 		sv.sival_int = va;
3856e66b933Sderaadt 		trapsignal(p, SIGSEGV, access_type, SEGV_ACCERR, sv);
386af7386c3Smickey 		break;
387af7386c3Smickey 
38878a8f2b7Smiod 	/*
38978a8f2b7Smiod 	 * On PCXS processors, traps T_DATACC, T_DATAPID and T_DATALIGN
39078a8f2b7Smiod 	 * are shared.  We need to sort out the unaligned access situation
39178a8f2b7Smiod 	 * first, before handling this trap as T_DATACC.
39278a8f2b7Smiod 	 */
393af7386c3Smickey 	case T_DPROT | T_USER:
39478a8f2b7Smiod 		if (cpu_type == hpcxs) {
39578a8f2b7Smiod 			if (pcxs_unaligned(opcode, va))
39678a8f2b7Smiod 				goto datalign_user;
39778a8f2b7Smiod 			else
39878a8f2b7Smiod 				goto datacc;
39978a8f2b7Smiod 		}
40078a8f2b7Smiod 
401af7386c3Smickey 		sv.sival_int = va;
4026e66b933Sderaadt 		trapsignal(p, SIGSEGV, access_type, SEGV_ACCERR, sv);
403af7386c3Smickey 		break;
404af7386c3Smickey 
4059208e3abSmickey 	case T_ITLBMISSNA:
4069208e3abSmickey 	case T_ITLBMISSNA | T_USER:
4079208e3abSmickey 	case T_DTLBMISSNA:
4089208e3abSmickey 	case T_DTLBMISSNA | T_USER:
4099208e3abSmickey 		if (space == HPPA_SID_KERNEL)
4109208e3abSmickey 			map = kernel_map;
4119208e3abSmickey 		else {
4129208e3abSmickey 			vm = p->p_vmspace;
4139208e3abSmickey 			map = &vm->vm_map;
4149208e3abSmickey 		}
4159208e3abSmickey 
41698898169Smickey 		if ((opcode & 0xfc003fc0) == 0x04001340) {
41798898169Smickey 			/* lpa failure case */
41898898169Smickey 			frame_regmap(frame, opcode & 0x1f) = 0;
41998898169Smickey 			frame->tf_ipsw |= PSL_N;
42098898169Smickey 		} else if ((opcode & 0xfc001f80) == 0x04001180) {
4219208e3abSmickey 			int pl;
4229208e3abSmickey 
42398898169Smickey 			/* dig probe[rw]i? insns */
4249208e3abSmickey 			if (opcode & 0x2000)
4259208e3abSmickey 				pl = (opcode >> 16) & 3;
4269208e3abSmickey 			else
4279208e3abSmickey 				pl = frame_regmap(frame,
4289208e3abSmickey 				    (opcode >> 16) & 0x1f) & 3;
4299208e3abSmickey 
430cfad034cSjsing 			KERNEL_LOCK();
431cfad034cSjsing 
4329208e3abSmickey 			if ((type & T_USER && space == HPPA_SID_KERNEL) ||
4339208e3abSmickey 			    (frame->tf_iioq_head & 3) != pl ||
4349208e3abSmickey 			    (type & T_USER && va >= VM_MAXUSER_ADDRESS) ||
4356e66b933Sderaadt 			    uvm_fault(map, trunc_page(va), 0,
4361e8cdc2eSderaadt 			     opcode & 0x40? PROT_WRITE : PROT_READ)) {
4379208e3abSmickey 				frame_regmap(frame, opcode & 0x1f) = 0;
4389208e3abSmickey 				frame->tf_ipsw |= PSL_N;
4399208e3abSmickey 			}
440cfad034cSjsing 
441cfad034cSjsing 			KERNEL_UNLOCK();
4429208e3abSmickey 		} else if (type & T_USER) {
4439208e3abSmickey 			sv.sival_int = va;
4449208e3abSmickey 			trapsignal(p, SIGILL, type & ~T_USER, ILL_ILLTRP, sv);
4459208e3abSmickey 		} else
446c8b758f8Smiod 			panic("trap: %s @ 0x%lx:0x%lx for 0x%x:0x%lx irr 0x%08x",
4479208e3abSmickey 			    tts, frame->tf_iisq_head, frame->tf_iioq_head,
4489208e3abSmickey 			    space, va, opcode);
4499208e3abSmickey 		break;
4509208e3abSmickey 
451998e9803Skettenis 	case T_IPROT | T_USER:
4529208e3abSmickey 	case T_TLB_DIRTY:
4539208e3abSmickey 	case T_TLB_DIRTY | T_USER:
454c6555f83Sderaadt 	case T_DATACC:
455c6555f83Sderaadt 	case T_DATACC | T_USER:
45678a8f2b7Smiod datacc:
457c6555f83Sderaadt 	case T_ITLBMISS:
458c6555f83Sderaadt 	case T_ITLBMISS | T_USER:
459c6555f83Sderaadt 	case T_DTLBMISS:
460c6555f83Sderaadt 	case T_DTLBMISS | T_USER:
4615e7211b0Sderaadt 		if (type & T_USER) {
4625e7211b0Sderaadt 			if (!uvm_map_inentry(p, &p->p_spinentry, PROC_STACK(p),
4635e7211b0Sderaadt 			    "[%s]%d/%d sp=%lx inside %lx-%lx: not MAP_STACK\n",
4645e7211b0Sderaadt 			    uvm_map_inentry_sp, p->p_vmspace->vm_map.sserial))
4655e7211b0Sderaadt 				goto out;
4665e7211b0Sderaadt 		}
4675e7211b0Sderaadt 
4688de28e3eSmickey 		/*
469e494c7cfSmickey 		 * it could be a kernel map for exec_map faults
4708de28e3eSmickey 		 */
47143a91648Smickey 		if (space == HPPA_SID_KERNEL)
4728de28e3eSmickey 			map = kernel_map;
47343a91648Smickey 		else {
47443a91648Smickey 			vm = p->p_vmspace;
475f17fa196Smickey 			map = &vm->vm_map;
47643a91648Smickey 		}
477556d2ba7Smickey 
4789208e3abSmickey 		/*
4799208e3abSmickey 		 * user faults out of user addr space are always a fail,
4809208e3abSmickey 		 * this happens on va >= VM_MAXUSER_ADDRESS, where
4819208e3abSmickey 		 * space id will be zero and therefore cause
4829208e3abSmickey 		 * a misbehave lower in the code.
4839208e3abSmickey 		 *
4849208e3abSmickey 		 * also check that faulted space id matches the curproc.
4859208e3abSmickey 		 */
4869208e3abSmickey 		if ((type & T_USER && va >= VM_MAXUSER_ADDRESS) ||
4879208e3abSmickey 		   (type & T_USER && map->pmap->pm_space != space)) {
488906a25e0Smickey 			sv.sival_int = va;
4896e66b933Sderaadt 			trapsignal(p, SIGSEGV, access_type, SEGV_MAPERR, sv);
49043a91648Smickey 			break;
491906a25e0Smickey 		}
492532740e6Smickey 
493cfad034cSjsing 		KERNEL_LOCK();
4946e66b933Sderaadt 		ret = uvm_fault(map, trunc_page(va), 0, access_type);
4952d10d447Sderaadt 		KERNEL_UNLOCK();
496f17fa196Smickey 
497f17fa196Smickey 		/*
498f17fa196Smickey 		 * If this was a stack access we keep track of the maximum
499f17fa196Smickey 		 * accessed stack size.  Also, if uvm_fault gets a protection
500f17fa196Smickey 		 * failure it is due to accessing the stack region outside
501f17fa196Smickey 		 * the current limit and we need to reflect that as an access
502f17fa196Smickey 		 * error.
503f17fa196Smickey 		 */
50464fad640Sderaadt 		if (ret == 0 && space != HPPA_SID_KERNEL)
50562899679Smiod 			uvm_grow(p, va);
506f17fa196Smickey 
507738a5b4dSart 		if (ret != 0) {
508af7386c3Smickey 			if (type & T_USER) {
5095507416cSkettenis 				int signal, sicode;
5105507416cSkettenis 
5115507416cSkettenis 				signal = SIGSEGV;
5125507416cSkettenis 				sicode = SEGV_MAPERR;
5135507416cSkettenis 				if (ret == EACCES)
5145507416cSkettenis 					sicode = SEGV_ACCERR;
5155507416cSkettenis 				if (ret == EIO) {
5165507416cSkettenis 					signal = SIGBUS;
5175507416cSkettenis 					sicode = BUS_OBJERR;
5185507416cSkettenis 				}
519a4be06b3Smickey 				sv.sival_int = va;
5206e66b933Sderaadt 				trapsignal(p, signal, access_type, sicode, sv);
521137d3021Smickey 			} else {
5228de28e3eSmickey 				if (p && p->p_addr->u_pcb.pcb_onfault) {
5238de28e3eSmickey 					frame->tf_iioq_tail = 4 +
5248de28e3eSmickey 					    (frame->tf_iioq_head =
52538575cbdSmickey 						p->p_addr->u_pcb.pcb_onfault);
526b04f760fSmickey #ifdef DDB
527b04f760fSmickey 					frame->tf_iir = 0;
528b04f760fSmickey #endif
529db97f33bSmickey 				} else {
530db97f33bSmickey 					panic("trap: "
5316e66b933Sderaadt 					    "uvm_fault(%p, %lx, 0, %d): %d",
5326e66b933Sderaadt 					    map, va, access_type, ret);
533137d3021Smickey 				}
534137d3021Smickey 			}
535db97f33bSmickey 		}
536556d2ba7Smickey 		break;
537d412f1c2Smickey 
53863b0c7d2Smiod 	case T_DATAPID:
53963b0c7d2Smiod 		/* This should never happen, unless within spcopy() */
54063b0c7d2Smiod 		if (p && p->p_addr->u_pcb.pcb_onfault) {
54163b0c7d2Smiod 			frame->tf_iioq_tail = 4 +
54263b0c7d2Smiod 			    (frame->tf_iioq_head =
54363b0c7d2Smiod 				p->p_addr->u_pcb.pcb_onfault);
54463b0c7d2Smiod #ifdef DDB
54563b0c7d2Smiod 			frame->tf_iir = 0;
54663b0c7d2Smiod #endif
54763b0c7d2Smiod 		} else
54863b0c7d2Smiod 			goto dead_end;
54963b0c7d2Smiod 		break;
55063b0c7d2Smiod 
551af7386c3Smickey 	case T_DATALIGN | T_USER:
55278a8f2b7Smiod datalign_user:
553137d3021Smickey 		sv.sival_int = va;
5546e66b933Sderaadt 		trapsignal(p, SIGBUS, access_type, BUS_ADRALN, sv);
555af7386c3Smickey 		break;
556af7386c3Smickey 
557a24c0b7aSmickey 	case T_INTERRUPT:
558a24c0b7aSmickey 	case T_INTERRUPT | T_USER:
559a24c0b7aSmickey 		cpu_intr(frame);
560af7386c3Smickey 		break;
561af7386c3Smickey 
562b7d25a19Smickey 	case T_CONDITION:
563b7d25a19Smickey 		panic("trap: divide by zero in the kernel");
564b7d25a19Smickey 		break;
565b7d25a19Smickey 
5663147f0deSmickey 	case T_ILLEGAL:
5673147f0deSmickey 	case T_ILLEGAL | T_USER:
5683147f0deSmickey 		/* see if it's a SPOP1,,0 */
56996415af6Smickey 		if ((opcode & 0xfffffe00) == 0x10000200) {
57096415af6Smickey 			frame_regmap(frame, opcode & 0x1f) = 0;
5713147f0deSmickey 			frame->tf_ipsw |= PSL_N;
5723147f0deSmickey 			break;
5733147f0deSmickey 		}
5743147f0deSmickey 		if (type & T_USER) {
5753147f0deSmickey 			sv.sival_int = va;
5763147f0deSmickey 			trapsignal(p, SIGILL, type & ~T_USER, ILL_ILLOPC, sv);
5773147f0deSmickey 			break;
5783147f0deSmickey 		}
5793147f0deSmickey 		/* FALLTHROUGH */
5803147f0deSmickey 
58178a8f2b7Smiod 	/*
58278a8f2b7Smiod 	 * On PCXS processors, traps T_DATACC, T_DATAPID and T_DATALIGN
58378a8f2b7Smiod 	 * are shared.  We need to sort out the unaligned access situation
58478a8f2b7Smiod 	 * first, before handling this trap as T_DATACC.
58578a8f2b7Smiod 	 */
5862ef9a47eSmickey 	case T_DPROT:
58778a8f2b7Smiod 		if (cpu_type == hpcxs) {
58878a8f2b7Smiod 			if (pcxs_unaligned(opcode, va))
58978a8f2b7Smiod 				goto dead_end;
59078a8f2b7Smiod 			else
59178a8f2b7Smiod 				goto datacc;
59278a8f2b7Smiod 		}
59378a8f2b7Smiod 		/* FALLTHROUGH to unimplemented */
59478a8f2b7Smiod 
59578a8f2b7Smiod 	case T_LOWERPL:
5962ef9a47eSmickey 	case T_IPROT:
597af7386c3Smickey 	case T_OVERFLOW:
598af7386c3Smickey 	case T_HIGHERPL:
599af7386c3Smickey 	case T_TAKENBR:
600af7386c3Smickey 	case T_POWERFAIL:
601af7386c3Smickey 	case T_LPMC:
602af7386c3Smickey 	case T_PAGEREF:
603d412f1c2Smickey 		/* FALLTHROUGH to unimplemented */
604d412f1c2Smickey 	default:
605ea3191ebSjsing #ifdef TRAPDEBUG
606a1a7d5d9Smpi 		if (db_ktrap(type, va, frame))
607137d3021Smickey 			return;
608137d3021Smickey #endif
60970016991Smickey 		panic("trap: unimplemented \'%s\' (%d)", tts, trapnum);
610d412f1c2Smickey 	}
611af7386c3Smickey 
61270016991Smickey #ifdef DIAGNOSTIC
613473ddf34Sjsing 	if (curcpu()->ci_cpl != oldcpl)
61470016991Smickey 		printf("WARNING: SPL (%d) NOT LOWERED ON "
615473ddf34Sjsing 		    "TRAP (%d) EXIT\n", curcpu()->ci_cpl, trapnum);
61670016991Smickey #endif
61770016991Smickey 
61870016991Smickey 	if (trapnum != T_INTERRUPT)
619473ddf34Sjsing 		splx(curcpu()->ci_cpl);	/* process softints */
62070016991Smickey 
621ba42a120Smickey 	/*
622ba42a120Smickey 	 * in case we were interrupted from the syscall gate page
62324d53bfeSkrw 	 * treat this as we were not really running user code no more
624ba42a120Smickey 	 * for weird things start to happen on return to the userland
625ba42a120Smickey 	 * and also see a note in locore.S:TLABEL(all)
626ba42a120Smickey 	 */
6277b428176Smickey 	if ((type & T_USER) && !(frame->tf_iisq_head == HPPA_SID_KERNEL &&
628c2b93341Sderaadt 	    (frame->tf_iioq_head & ~PAGE_MASK) == SYSCALLGATE)) {
629c2b93341Sderaadt 		ast(p);
630a0da50afSderaadt out:
631c19cb33fSmickey 		userret(p);
632d412f1c2Smickey 	}
633c2b93341Sderaadt }
634d412f1c2Smickey 
635d412f1c2Smickey void
child_return(void * arg)636cfad034cSjsing child_return(void *arg)
637d412f1c2Smickey {
638db36253aSmickey 	struct proc *p = (struct proc *)arg;
63989afe3e5Smickey 	struct trapframe *tf = p->p_md.md_regs;
64089afe3e5Smickey 
64189afe3e5Smickey 	/*
64289afe3e5Smickey 	 * Set up return value registers as libc:fork() expects
64389afe3e5Smickey 	 */
64489afe3e5Smickey 	tf->tf_ret0 = 0;
64589afe3e5Smickey 	tf->tf_t1 = 0;		/* errno */
64689afe3e5Smickey 
647971e1bb6Sart 	KERNEL_UNLOCK();
648cfad034cSjsing 
649c2b93341Sderaadt 	ast(p);
650fc572715Sguenther 
651fc572715Sguenther 	mi_child_return(p);
652556d2ba7Smickey }
653556d2ba7Smickey 
6547bfbef72Skettenis #ifdef PTRACE
6557bfbef72Skettenis 
6567bfbef72Skettenis #include <sys/ptrace.h>
6577bfbef72Skettenis 
658dd6e4488Sderaadt int	ss_get_value(struct proc *p, vaddr_t addr, u_int *value);
659dd6e4488Sderaadt int	ss_put_value(struct proc *p, vaddr_t addr, u_int value);
660dd6e4488Sderaadt 
6617bfbef72Skettenis int
ss_get_value(struct proc * p,vaddr_t addr,u_int * value)6627bfbef72Skettenis ss_get_value(struct proc *p, vaddr_t addr, u_int *value)
6637bfbef72Skettenis {
6647bfbef72Skettenis 	struct uio uio;
6657bfbef72Skettenis 	struct iovec iov;
6667bfbef72Skettenis 
6677bfbef72Skettenis 	iov.iov_base = (caddr_t)value;
6687bfbef72Skettenis 	iov.iov_len = sizeof(u_int);
6697bfbef72Skettenis 	uio.uio_iov = &iov;
6707bfbef72Skettenis 	uio.uio_iovcnt = 1;
6717bfbef72Skettenis 	uio.uio_offset = (off_t)addr;
6727bfbef72Skettenis 	uio.uio_resid = sizeof(u_int);
6737bfbef72Skettenis 	uio.uio_segflg = UIO_SYSSPACE;
6747bfbef72Skettenis 	uio.uio_rw = UIO_READ;
6757bfbef72Skettenis 	uio.uio_procp = curproc;
67696ce7312Sguenther 	return (process_domem(curproc, p->p_p, &uio, PT_READ_I));
6777bfbef72Skettenis }
6787bfbef72Skettenis 
6797bfbef72Skettenis int
ss_put_value(struct proc * p,vaddr_t addr,u_int value)6807bfbef72Skettenis ss_put_value(struct proc *p, vaddr_t addr, u_int value)
6817bfbef72Skettenis {
6827bfbef72Skettenis 	struct uio uio;
6837bfbef72Skettenis 	struct iovec iov;
6847bfbef72Skettenis 
6857bfbef72Skettenis 	iov.iov_base = (caddr_t)&value;
6867bfbef72Skettenis 	iov.iov_len = sizeof(u_int);
6877bfbef72Skettenis 	uio.uio_iov = &iov;
6887bfbef72Skettenis 	uio.uio_iovcnt = 1;
6897bfbef72Skettenis 	uio.uio_offset = (off_t)addr;
6907bfbef72Skettenis 	uio.uio_resid = sizeof(u_int);
6917bfbef72Skettenis 	uio.uio_segflg = UIO_SYSSPACE;
6927bfbef72Skettenis 	uio.uio_rw = UIO_WRITE;
6937bfbef72Skettenis 	uio.uio_procp = curproc;
69496ce7312Sguenther 	return (process_domem(curproc, p->p_p, &uio, PT_WRITE_I));
6957bfbef72Skettenis }
6967bfbef72Skettenis 
6977bfbef72Skettenis void
ss_clear_breakpoints(struct proc * p)6987bfbef72Skettenis ss_clear_breakpoints(struct proc *p)
6997bfbef72Skettenis {
70036fd90dcSjsg 	/* Restore original instructions. */
7017bfbef72Skettenis 	if (p->p_md.md_bpva != 0) {
7027bfbef72Skettenis 		ss_put_value(p, p->p_md.md_bpva, p->p_md.md_bpsave[0]);
7037bfbef72Skettenis 		ss_put_value(p, p->p_md.md_bpva + 4, p->p_md.md_bpsave[1]);
7047bfbef72Skettenis 		p->p_md.md_bpva = 0;
7057bfbef72Skettenis 	}
7067bfbef72Skettenis }
7077bfbef72Skettenis 
7087bfbef72Skettenis int
process_sstep(struct proc * p,int sstep)7097bfbef72Skettenis process_sstep(struct proc *p, int sstep)
7107bfbef72Skettenis {
7117bfbef72Skettenis 	int error;
7127bfbef72Skettenis 
7137bfbef72Skettenis 	ss_clear_breakpoints(p);
7147bfbef72Skettenis 
71585bd3014Skettenis 	if (sstep == 0) {
7167bfbef72Skettenis 		p->p_md.md_regs->tf_ipsw &= ~PSL_T;
7177bfbef72Skettenis 		return (0);
7187bfbef72Skettenis 	}
7197bfbef72Skettenis 
72085bd3014Skettenis 	/*
72185bd3014Skettenis 	 * Don't touch the syscall gateway page.  Instead, insert a
72285bd3014Skettenis 	 * breakpoint where we're supposed to return.
72385bd3014Skettenis 	 */
72485bd3014Skettenis 	if ((p->p_md.md_regs->tf_iioq_tail & ~PAGE_MASK) == SYSCALLGATE)
72585bd3014Skettenis 		p->p_md.md_bpva = p->p_md.md_regs->tf_r31 & ~HPPA_PC_PRIV_MASK;
72685bd3014Skettenis 	else
7277bfbef72Skettenis 		p->p_md.md_bpva = p->p_md.md_regs->tf_iioq_tail & ~HPPA_PC_PRIV_MASK;
7287bfbef72Skettenis 
7297bfbef72Skettenis 	/*
7307bfbef72Skettenis 	 * Insert two breakpoint instructions; the first one might be
7317bfbef72Skettenis 	 * nullified.  Of course we need to save two instruction
7327bfbef72Skettenis 	 * first.
7337bfbef72Skettenis 	 */
7347bfbef72Skettenis 
7357bfbef72Skettenis 	error = ss_get_value(p, p->p_md.md_bpva, &p->p_md.md_bpsave[0]);
7367bfbef72Skettenis 	if (error)
7377bfbef72Skettenis 		return (error);
7387bfbef72Skettenis 	error = ss_get_value(p, p->p_md.md_bpva + 4, &p->p_md.md_bpsave[1]);
7397bfbef72Skettenis 	if (error)
7407bfbef72Skettenis 		return (error);
7417bfbef72Skettenis 
7427bfbef72Skettenis 	error = ss_put_value(p, p->p_md.md_bpva, SSBREAKPOINT);
7437bfbef72Skettenis 	if (error)
7447bfbef72Skettenis 		return (error);
7457bfbef72Skettenis 	error = ss_put_value(p, p->p_md.md_bpva + 4, SSBREAKPOINT);
7467bfbef72Skettenis 	if (error)
7477bfbef72Skettenis 		return (error);
7487bfbef72Skettenis 
74985bd3014Skettenis 	if ((p->p_md.md_regs->tf_iioq_tail & ~PAGE_MASK) != SYSCALLGATE)
7507bfbef72Skettenis 		p->p_md.md_regs->tf_ipsw |= PSL_T;
75185bd3014Skettenis 	else
75285bd3014Skettenis 		p->p_md.md_regs->tf_ipsw &= ~PSL_T;
75385bd3014Skettenis 
7547bfbef72Skettenis 	return (0);
7557bfbef72Skettenis }
7567bfbef72Skettenis 
7577bfbef72Skettenis #endif	/* PTRACE */
758db97f33bSmickey 
759dd6e4488Sderaadt void	syscall(struct trapframe *frame);
760dd6e4488Sderaadt 
761b9b95e0dSmickey /*
762b9b95e0dSmickey  * call actual syscall routine
763b9b95e0dSmickey  */
764b9b95e0dSmickey void
syscall(struct trapframe * frame)76570016991Smickey syscall(struct trapframe *frame)
766b9b95e0dSmickey {
767f231ff59Sguenther 	struct proc *p = curproc;
768cafeb892Sderaadt 	const struct sysent *callp = sysent;
769cba2cefcSmiod 	int code, argsize, argoff, error;
770b7d25a19Smickey 	register_t args[8], rval[2];
77170016991Smickey #ifdef DIAGNOSTIC
772473ddf34Sjsing 	int oldcpl = curcpu()->ci_cpl;
77370016991Smickey #endif
774b9b95e0dSmickey 
775b9b95e0dSmickey 	uvmexp.syscalls++;
776b9b95e0dSmickey 
777b9b95e0dSmickey 	if (!USERMODE(frame->tf_iioq_head))
778b9b95e0dSmickey 		panic("syscall");
779b9b95e0dSmickey 
780137d3021Smickey 	p->p_md.md_regs = frame;
781db97f33bSmickey 
782cba2cefcSmiod 	argoff = 4;
783dc44c75fSmiod 	code = frame->tf_t1;
784db97f33bSmickey 	args[0] = frame->tf_arg0;
785db97f33bSmickey 	args[1] = frame->tf_arg1;
786db97f33bSmickey 	args[2] = frame->tf_arg2;
787db97f33bSmickey 	args[3] = frame->tf_arg3;
788b9b95e0dSmickey 
789cafeb892Sderaadt 	// XXX out of range stays on syscall0, which we assume is enosys
790cb0f97f9Smiod 	if (code > 0 && code < SYS_MAXSYSCALL)
791b9b95e0dSmickey 		callp += code;
792db97f33bSmickey 
793db97f33bSmickey 	if ((argsize = callp->sy_argsize)) {
794da57a199Smiod 		register_t *s, *e, t;
795db97f33bSmickey 		int i;
796db97f33bSmickey 
797da57a199Smiod 		argsize -= argoff * 4;
798da57a199Smiod 		if (argsize > 0) {
799da57a199Smiod 			i = argsize / 4;
800fc572715Sguenther 			if ((error = copyin((void *)(frame->tf_sp +
801da57a199Smiod 			    HPPA_FRAME_ARG(4 + i - 1)), args + argoff,
802da57a199Smiod 			    argsize)))
803fc572715Sguenther 				goto bad;
804da57a199Smiod 			/* reverse the args[] entries */
805da57a199Smiod 			s = args + argoff;
806da57a199Smiod 			e = s + i - 1;
807da57a199Smiod 			while (s < e) {
808da57a199Smiod 				t = *s;
809da57a199Smiod 				*s = *e;
810da57a199Smiod 				*e = t;
811da57a199Smiod 				s++, e--;
812da57a199Smiod 			}
813db97f33bSmickey 		}
814db97f33bSmickey 
815db97f33bSmickey 		/*
816da57a199Smiod 		 * System calls with 64-bit arguments need a word swap
817da57a199Smiod 		 * due to the order of the arguments on the stack.
818db97f33bSmickey 		 */
819db97f33bSmickey 		i = 0;
820db97f33bSmickey 		switch (code) {
821cba2cefcSmiod 		case SYS_lseek:
822db97f33bSmickey 		case SYS_truncate:
823db97f33bSmickey 		case SYS_ftruncate:	i = 2;	break;
824db97f33bSmickey 		case SYS_preadv:
825db97f33bSmickey 		case SYS_pwritev:
826db97f33bSmickey 		case SYS_pread:
827db97f33bSmickey 		case SYS_pwrite:	i = 4;	break;
828a9d0813cSmiod 		case SYS_mquery:
829db97f33bSmickey 		case SYS_mmap:		i = 6;	break;
830db97f33bSmickey 		}
831db97f33bSmickey 
832db97f33bSmickey 		if (i) {
833db97f33bSmickey 			t = args[i];
834db97f33bSmickey 			args[i] = args[i + 1];
835db97f33bSmickey 			args[i + 1] = t;
836db97f33bSmickey 		}
837db97f33bSmickey 	}
838b9b95e0dSmickey 
839b9b95e0dSmickey 	rval[0] = 0;
840db97f33bSmickey 	rval[1] = frame->tf_ret1;
841cfad034cSjsing 
842cafeb892Sderaadt 	error = mi_syscall(p, code, callp, args, rval);
843fc572715Sguenther 
84496a1071fSmiod 	switch (error) {
845b9b95e0dSmickey 	case 0:
846b9b95e0dSmickey 		frame->tf_ret0 = rval[0];
847cba2cefcSmiod 		frame->tf_ret1 = rval[1];
848137d3021Smickey 		frame->tf_t1 = 0;
849b9b95e0dSmickey 		break;
850b9b95e0dSmickey 	case ERESTART:
851c37e03c6Smickey 		frame->tf_iioq_head -= 12;
852c37e03c6Smickey 		frame->tf_iioq_tail -= 12;
853b9b95e0dSmickey 	case EJUSTRETURN:
854b9b95e0dSmickey 		break;
855b9b95e0dSmickey 	default:
856db97f33bSmickey 	bad:
857137d3021Smickey 		frame->tf_t1 = error;
85847df6ae3Smickey 		frame->tf_ret0 = error;
85947df6ae3Smickey 		frame->tf_ret1 = 0;
860b9b95e0dSmickey 		break;
861b9b95e0dSmickey 	}
862fc572715Sguenther 
863cafeb892Sderaadt 	ast(p);		// XXX why?
864fc572715Sguenther 
8659417b0e6Sguenther 	mi_syscall_return(p, code, error, rval);
866fc572715Sguenther 
86770016991Smickey #ifdef DIAGNOSTIC
868473ddf34Sjsing 	if (curcpu()->ci_cpl != oldcpl) {
86970016991Smickey 		printf("WARNING: SPL (0x%x) NOT LOWERED ON "
870c8b758f8Smiod 		    "syscall(0x%x, 0x%lx, 0x%lx, 0x%lx...) EXIT, PID %d\n",
871473ddf34Sjsing 		    curcpu()->ci_cpl, code, args[0], args[1], args[2],
872552f6074Sguenther 		    p->p_p->ps_pid);
873473ddf34Sjsing 		curcpu()->ci_cpl = oldcpl;
87450552582Smickey 	}
87570016991Smickey #endif
876473ddf34Sjsing 	splx(curcpu()->ci_cpl);	/* process softints */
877b9b95e0dSmickey }
87878a8f2b7Smiod 
87978a8f2b7Smiod /*
88078a8f2b7Smiod  * Decide if opcode `opcode' accessing virtual address `va' caused an
88178a8f2b7Smiod  * unaligned trap. Returns zero if the access is correctly aligned.
88278a8f2b7Smiod  * Used on PCXS processors to sort out exception causes.
88378a8f2b7Smiod  */
88478a8f2b7Smiod int
pcxs_unaligned(u_int opcode,vaddr_t va)88578a8f2b7Smiod pcxs_unaligned(u_int opcode, vaddr_t va)
88678a8f2b7Smiod {
88778a8f2b7Smiod 	u_int mbz_bits;
88878a8f2b7Smiod 
88978a8f2b7Smiod 	/*
89078a8f2b7Smiod 	 * Exit early if the va is obviously aligned enough.
89178a8f2b7Smiod 	 */
89278a8f2b7Smiod 	if ((va & 0x0f) == 0)
89378a8f2b7Smiod 		return 0;
89478a8f2b7Smiod 
89578a8f2b7Smiod 	mbz_bits = 0;
89678a8f2b7Smiod 
89778a8f2b7Smiod 	/*
89878a8f2b7Smiod 	 * Only load and store instructions can cause unaligned access.
89978a8f2b7Smiod 	 * There are three opcode patterns to look for:
90078a8f2b7Smiod 	 * - canonical load/store
90178a8f2b7Smiod 	 * - load/store short or indexed
90278a8f2b7Smiod 	 * - coprocessor load/store
90378a8f2b7Smiod 	 */
90478a8f2b7Smiod 
90578a8f2b7Smiod 	if ((opcode & 0xd0000000) == 0x40000000) {
90678a8f2b7Smiod 		switch ((opcode >> 26) & 0x03) {
90778a8f2b7Smiod 		case 0x00:	/* ldb, stb */
90878a8f2b7Smiod 			mbz_bits = 0x00;
90978a8f2b7Smiod 			break;
91078a8f2b7Smiod 		case 0x01:	/* ldh, sth */
91178a8f2b7Smiod 			mbz_bits = 0x01;
91278a8f2b7Smiod 			break;
91378a8f2b7Smiod 		case 0x02:	/* ldw, stw */
91478a8f2b7Smiod 		case 0x03:	/* ldwm, stwm */
91578a8f2b7Smiod 			mbz_bits = 0x03;
91678a8f2b7Smiod 			break;
91778a8f2b7Smiod 		}
91878a8f2b7Smiod 	} else
91978a8f2b7Smiod 
92078a8f2b7Smiod 	if ((opcode & 0xfc000000) == 0x0c000000) {
92178a8f2b7Smiod 		switch ((opcode >> 6) & 0x0f) {
92278a8f2b7Smiod 		case 0x01:	/* ldhx, ldhs */
92378a8f2b7Smiod 			mbz_bits = 0x01;
92478a8f2b7Smiod 			break;
92578a8f2b7Smiod 		case 0x02:	/* ldwx, ldws */
92678a8f2b7Smiod 			mbz_bits = 0x03;
92778a8f2b7Smiod 			break;
92878a8f2b7Smiod 		case 0x07:	/* ldcwx, ldcws */
92978a8f2b7Smiod 			mbz_bits = 0x0f;
93078a8f2b7Smiod 			break;
93178a8f2b7Smiod 		case 0x09:
93278a8f2b7Smiod 			if ((opcode & (1 << 12)) != 0)	/* sths */
93378a8f2b7Smiod 				mbz_bits = 0x01;
93478a8f2b7Smiod 			break;
93578a8f2b7Smiod 		case 0x0a:
93678a8f2b7Smiod 			if ((opcode & (1 << 12)) != 0)	/* stws */
93778a8f2b7Smiod 				mbz_bits = 0x03;
93878a8f2b7Smiod 			break;
93978a8f2b7Smiod 		}
94078a8f2b7Smiod 	} else
94178a8f2b7Smiod 
94278a8f2b7Smiod 	if ((opcode & 0xf4000000) == 0x24000000) {
94378a8f2b7Smiod 		if ((opcode & (1 << 27)) != 0) {
94478a8f2b7Smiod 			/* cldwx, cstwx, cldws, cstws */
94578a8f2b7Smiod 			mbz_bits = 0x03;
94678a8f2b7Smiod 		} else {
94778a8f2b7Smiod 			/* clddx, cstdx, cldds, cstds */
94878a8f2b7Smiod 			mbz_bits = 0x07;
94978a8f2b7Smiod 		}
95078a8f2b7Smiod 	}
95178a8f2b7Smiod 
95278a8f2b7Smiod 	return (va & mbz_bits);
95378a8f2b7Smiod }
954