xref: /openbsd/sys/arch/hppa/hppa/trap.c (revision 8f76f5ad)
1*8f76f5adSguenther /*	$OpenBSD: trap.c,v 1.128 2014/03/26 05:23:42 guenther 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>
34fc572715Sguenther #include <sys/syscall_mi.h>
35d412f1c2Smickey #include <sys/proc.h>
366acb4cb0Sniklas #include <sys/signalvar.h>
37d412f1c2Smickey #include <sys/user.h>
38556d2ba7Smickey 
39b9b95e0dSmickey #include <uvm/uvm.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;
142c19cb33fSmickey 		uvmexp.softs++;
14370016991Smickey 		if (p->p_flag & P_OWEUPC) {
144f4e9e19cSguenther 			KERNEL_LOCK();
14570016991Smickey 			ADDUPROF(p);
146f4e9e19cSguenther 			KERNEL_UNLOCK();
14770016991Smickey 		}
148473ddf34Sjsing 		if (curcpu()->ci_want_resched)
149c81336dcSart 			preempt(NULL);
150c19cb33fSmickey 	}
151c19cb33fSmickey 
152d412f1c2Smickey }
153d412f1c2Smickey 
154556d2ba7Smickey void
155c33335b0Sjsing trap(int type, struct trapframe *frame)
156556d2ba7Smickey {
157556d2ba7Smickey 	struct proc *p = curproc;
158ab8e80c5Sart 	vaddr_t va;
159ab8e80c5Sart 	struct vm_map *map;
160f17fa196Smickey 	struct vmspace *vm;
161af7386c3Smickey 	register vm_prot_t vftype;
162556d2ba7Smickey 	register pa_space_t space;
163af7386c3Smickey 	union sigval sv;
164c37e03c6Smickey 	u_int opcode;
16570016991Smickey 	int ret, trapnum;
166137d3021Smickey 	const char *tts;
1676198d067Smickey 	vm_fault_t fault = VM_FAULT_INVALID;
16870016991Smickey #ifdef DIAGNOSTIC
169473ddf34Sjsing 	int oldcpl = curcpu()->ci_cpl;
17070016991Smickey #endif
1710e979e06Smickey 
172c37e03c6Smickey 	trapnum = type & ~T_USER;
173137d3021Smickey 	opcode = frame->tf_iir;
1749b476898Smickey 	if (trapnum <= T_EXCEPTION || trapnum == T_HIGHERPL ||
1759b476898Smickey 	    trapnum == T_LOWERPL || trapnum == T_TAKENBR ||
1769b476898Smickey 	    trapnum == T_IDEBUG || trapnum == T_PERFMON) {
177a24c0b7aSmickey 		va = frame->tf_iioq_head;
178a24c0b7aSmickey 		space = frame->tf_iisq_head;
179e21aaa8cSmickey 		vftype = UVM_PROT_EXEC;
180a24c0b7aSmickey 	} else {
181b9b95e0dSmickey 		va = frame->tf_ior;
182a24c0b7aSmickey 		space = frame->tf_isr;
183a4be06b3Smickey 		if (va == frame->tf_iioq_head)
184e21aaa8cSmickey 			vftype = UVM_PROT_EXEC;
185a4be06b3Smickey 		else if (inst_store(opcode))
186e21aaa8cSmickey 			vftype = UVM_PROT_WRITE;
187a4be06b3Smickey 		else
188e21aaa8cSmickey 			vftype = UVM_PROT_READ;
189556d2ba7Smickey 	}
190137d3021Smickey 
191137d3021Smickey 	if (frame->tf_flags & TFF_LAST)
192137d3021Smickey 		p->p_md.md_regs = frame;
193137d3021Smickey 
194c37e03c6Smickey 	if (trapnum > trap_types)
195137d3021Smickey 		tts = "reserved";
196137d3021Smickey 	else
197c37e03c6Smickey 		tts = trap_type[trapnum];
198137d3021Smickey 
199446209b7Smiod #ifdef TRAPDEBUG
200c37e03c6Smickey 	if (trapnum != T_INTERRUPT && trapnum != T_IBREAK)
201969c5366Smickey 		db_printf("trap: %x, %s for %x:%x at %x:%x, fl=%x, fp=%p\n",
202137d3021Smickey 		    type, tts, space, va, frame->tf_iisq_head,
203137d3021Smickey 		    frame->tf_iioq_head, frame->tf_flags, frame);
204c37e03c6Smickey 	else if (trapnum  == T_IBREAK)
205137d3021Smickey 		db_printf("trap: break instruction %x:%x at %x:%x, fp=%p\n",
206a24c0b7aSmickey 		    break5(opcode), break13(opcode),
207137d3021Smickey 		    frame->tf_iisq_head, frame->tf_iioq_head, frame);
208e494c7cfSmickey 
209e494c7cfSmickey 	{
210e494c7cfSmickey 		extern int etext;
211532740e6Smickey 		if (frame < (struct trapframe *)&etext) {
212532740e6Smickey 			printf("trap: bogus frame ptr %p\n", frame);
213e494c7cfSmickey 			goto dead_end;
214e494c7cfSmickey 		}
215532740e6Smickey 	}
216d412f1c2Smickey #endif
2177d3bf75dSmickey 	if (trapnum != T_INTERRUPT) {
2187d3bf75dSmickey 		uvmexp.traps++;
21970016991Smickey 		mtctl(frame->tf_eiem, CR_EIEM);
220916310a5Smickey 	}
22170016991Smickey 
222556d2ba7Smickey 	switch (type) {
223556d2ba7Smickey 	case T_NONEXIST:
224556d2ba7Smickey 	case T_NONEXIST | T_USER:
225af7386c3Smickey 		/* we've got screwed up by the central scrutinizer */
226b67578d8Smickey 		printf("trap: elvis has just left the building!\n");
227532740e6Smickey 		goto dead_end;
228b67578d8Smickey 
229556d2ba7Smickey 	case T_RECOVERY:
230556d2ba7Smickey 	case T_RECOVERY | T_USER:
231af7386c3Smickey 		/* XXX will implement later */
232556d2ba7Smickey 		printf("trap: handicapped");
233532740e6Smickey 		goto dead_end;
23466d1ab7aSmickey 
23566d1ab7aSmickey #ifdef DIAGNOSTIC
23666d1ab7aSmickey 	case T_EXCEPTION:
23766d1ab7aSmickey 		panic("FPU/SFU emulation botch");
23866d1ab7aSmickey 
23966d1ab7aSmickey 		/* these just can't happen ever */
24066d1ab7aSmickey 	case T_PRIV_OP:
24166d1ab7aSmickey 	case T_PRIV_REG:
24266d1ab7aSmickey 		/* these just can't make it to the trap() ever */
243c6555f83Sderaadt 	case T_HPMC:
244c6555f83Sderaadt 	case T_HPMC | T_USER:
24566d1ab7aSmickey #endif
246f4daacd8Smickey 	case T_IBREAK:
247a24c0b7aSmickey 	case T_DATALIGN:
248a24c0b7aSmickey 	case T_DBREAK:
2498de28e3eSmickey 	dead_end:
250a24c0b7aSmickey #ifdef DDB
251532740e6Smickey 		if (kdb_trap(type, va, frame)) {
252a24c0b7aSmickey 			if (type == T_IBREAK) {
253f4daacd8Smickey 				/* skip break instruction */
2548de28e3eSmickey 				frame->tf_iioq_head = frame->tf_iioq_tail;
255f4daacd8Smickey 				frame->tf_iioq_tail += 4;
256a24c0b7aSmickey 			}
257556d2ba7Smickey 			return;
258a24c0b7aSmickey 		}
259137d3021Smickey #else
26078a8f2b7Smiod 		if (type == T_DATALIGN || type == T_DPROT)
261137d3021Smickey 			panic ("trap: %s at 0x%x", tts, va);
262137d3021Smickey 		else
263137d3021Smickey 			panic ("trap: no debugger for \"%s\" (%d)", tts, type);
264a24c0b7aSmickey #endif
265556d2ba7Smickey 		break;
266556d2ba7Smickey 
267af7386c3Smickey 	case T_IBREAK | T_USER:
2687bfbef72Skettenis 	case T_DBREAK | T_USER: {
2697bfbef72Skettenis 		int code = TRAP_BRKPT;
2707bfbef72Skettenis #ifdef PTRACE
2717bfbef72Skettenis 		ss_clear_breakpoints(p);
2727bfbef72Skettenis 		if (opcode == SSBREAKPOINT)
2737bfbef72Skettenis 			code = TRAP_TRACE;
2747bfbef72Skettenis #endif
275af7386c3Smickey 		/* pass to user debugger */
276f4e9e19cSguenther 		KERNEL_LOCK();
2777bfbef72Skettenis 		trapsignal(p, SIGTRAP, type & ~T_USER, code, sv);
278f4e9e19cSguenther 		KERNEL_UNLOCK();
2797bfbef72Skettenis 		}
280d412f1c2Smickey 		break;
281d412f1c2Smickey 
2827bfbef72Skettenis #ifdef PTRACE
2837bfbef72Skettenis 	case T_TAKENBR | T_USER:
2847bfbef72Skettenis 		ss_clear_breakpoints(p);
2857bfbef72Skettenis 
2867bfbef72Skettenis 		/* pass to user debugger */
287f4e9e19cSguenther 		KERNEL_LOCK();
2887bfbef72Skettenis 		trapsignal(p, SIGTRAP, type & ~T_USER, TRAP_TRACE, sv);
289f4e9e19cSguenther 		KERNEL_UNLOCK();
2907bfbef72Skettenis 		break;
2917bfbef72Skettenis #endif
2927bfbef72Skettenis 
29338575cbdSmickey 	case T_EXCEPTION | T_USER: {
2942f8e4113Sjsing 		struct hppa_fpstate *hfp;
2952f8e4113Sjsing 		u_int64_t *fpp;
296969eb289Smickey 		u_int32_t *pex;
29738575cbdSmickey 		int i, flt;
29838575cbdSmickey 
2992f8e4113Sjsing 		hfp = (struct hppa_fpstate *)frame->tf_cr30;
3002f8e4113Sjsing 		fpp = (u_int64_t *)&hfp->hfp_regs;
3012f8e4113Sjsing 
302969eb289Smickey 		pex = (u_int32_t *)&fpp[0];
30338575cbdSmickey 		for (i = 0, pex++; i < 7 && !*pex; i++, pex++);
304969eb289Smickey 		flt = 0;
305969eb289Smickey 		if (i < 7) {
306969eb289Smickey 			u_int32_t stat = HPPA_FPU_OP(*pex);
30728496d60Smickey 			if (stat & HPPA_FPU_UNMPL)
308969eb289Smickey 				flt = FPE_FLTINV;
30928496d60Smickey 			else if (stat & (HPPA_FPU_V << 1))
31038575cbdSmickey 				flt = FPE_FLTINV;
31128496d60Smickey 			else if (stat & (HPPA_FPU_Z << 1))
31238575cbdSmickey 				flt = FPE_FLTDIV;
31328496d60Smickey 			else if (stat & (HPPA_FPU_I << 1))
314969eb289Smickey 				flt = FPE_FLTRES;
31528496d60Smickey 			else if (stat & (HPPA_FPU_O << 1))
31638575cbdSmickey 				flt = FPE_FLTOVF;
31728496d60Smickey 			else if (stat & (HPPA_FPU_U << 1))
31838575cbdSmickey 				flt = FPE_FLTUND;
319969eb289Smickey 			/* still left: under/over-flow w/ inexact */
320ded58a29Smickey 
321ded58a29Smickey 			/* cleanup exceptions (XXX deliver all ?) */
322ded58a29Smickey 			while (i++ < 7)
323ded58a29Smickey 				*pex++ = 0;
324969eb289Smickey 		}
325969eb289Smickey 		/* reset the trap flag, as if there was none */
326969eb289Smickey 		fpp[0] &= ~(((u_int64_t)HPPA_FPU_T) << 32);
32738575cbdSmickey 
32838575cbdSmickey 		sv.sival_int = va;
329f4e9e19cSguenther 		KERNEL_LOCK();
33038575cbdSmickey 		trapsignal(p, SIGFPE, type & ~T_USER, flt, sv);
331f4e9e19cSguenther 		KERNEL_UNLOCK();
33238575cbdSmickey 		}
33338575cbdSmickey 		break;
33438575cbdSmickey 
335969eb289Smickey 	case T_EMULATION:
336969eb289Smickey 		panic("trap: emulation trap in the kernel");
337969eb289Smickey 		break;
338969eb289Smickey 
339969eb289Smickey 	case T_EMULATION | T_USER:
340137d3021Smickey 		sv.sival_int = va;
341f4e9e19cSguenther 		KERNEL_LOCK();
34228496d60Smickey 		trapsignal(p, SIGILL, type & ~T_USER, ILL_COPROC, sv);
343f4e9e19cSguenther 		KERNEL_UNLOCK();
344d412f1c2Smickey 		break;
345d412f1c2Smickey 
346af7386c3Smickey 	case T_OVERFLOW | T_USER:
347137d3021Smickey 		sv.sival_int = va;
348f4e9e19cSguenther 		KERNEL_LOCK();
349af7386c3Smickey 		trapsignal(p, SIGFPE, type & ~T_USER, FPE_INTOVF, sv);
350f4e9e19cSguenther 		KERNEL_UNLOCK();
351d412f1c2Smickey 		break;
352d412f1c2Smickey 
353af7386c3Smickey 	case T_CONDITION | T_USER:
3548b9bddf0Smickey 		sv.sival_int = va;
355f4e9e19cSguenther 		KERNEL_LOCK();
3568b9bddf0Smickey 		trapsignal(p, SIGFPE, type & ~T_USER, FPE_INTDIV, sv);
357f4e9e19cSguenther 		KERNEL_UNLOCK();
358af7386c3Smickey 		break;
359af7386c3Smickey 
360af7386c3Smickey 	case T_PRIV_OP | T_USER:
361137d3021Smickey 		sv.sival_int = va;
362f4e9e19cSguenther 		KERNEL_LOCK();
363af7386c3Smickey 		trapsignal(p, SIGILL, type & ~T_USER, ILL_PRVOPC, sv);
364f4e9e19cSguenther 		KERNEL_UNLOCK();
365af7386c3Smickey 		break;
366af7386c3Smickey 
367af7386c3Smickey 	case T_PRIV_REG | T_USER:
368b0be98e8Smiod 		/*
369b0be98e8Smiod 		 * On PCXS processors, attempting to read control registers
370b0be98e8Smiod 		 * cr26 and cr27 from userland causes a ``privileged register''
371b0be98e8Smiod 		 * trap.  Later processors do not restrict read accesses to
372b0be98e8Smiod 		 * these registers.
373b0be98e8Smiod 		 */
374b0be98e8Smiod 		if (cpu_type == hpcxs &&
375b0be98e8Smiod 		    (opcode & (0xfc1fffe0 | (0x1e << 21))) ==
376b0be98e8Smiod 		     (0x000008a0 | (0x1a << 21))) { /* mfctl %cr{26,27}, %r# */
377b0be98e8Smiod 			register_t cr;
378b0be98e8Smiod 
379b0be98e8Smiod 			if (((opcode >> 21) & 0x1f) == 27)
380b0be98e8Smiod 				mfctl(CR_TR3, cr);	/* cr27 */
381b0be98e8Smiod 			else
382b0be98e8Smiod 				mfctl(CR_TR2, cr);	/* cr26 */
383b0be98e8Smiod 			frame_regmap(frame, opcode & 0x1f) = cr;
384b0be98e8Smiod 			frame->tf_ipsw |= PSL_N;
385b0be98e8Smiod 		} else {
386137d3021Smickey 			sv.sival_int = va;
387f4e9e19cSguenther 			KERNEL_LOCK();
388af7386c3Smickey 			trapsignal(p, SIGILL, type & ~T_USER, ILL_PRVREG, sv);
389f4e9e19cSguenther 			KERNEL_UNLOCK();
390b0be98e8Smiod 		}
391af7386c3Smickey 		break;
392af7386c3Smickey 
393af7386c3Smickey 		/* these should never got here */
394af7386c3Smickey 	case T_HIGHERPL | T_USER:
395af7386c3Smickey 	case T_LOWERPL | T_USER:
39663b0c7d2Smiod 	case T_DATAPID | T_USER:
397137d3021Smickey 		sv.sival_int = va;
398f4e9e19cSguenther 		KERNEL_LOCK();
399a4be06b3Smickey 		trapsignal(p, SIGSEGV, vftype, SEGV_ACCERR, sv);
400f4e9e19cSguenther 		KERNEL_UNLOCK();
401af7386c3Smickey 		break;
402af7386c3Smickey 
40378a8f2b7Smiod 	/*
40478a8f2b7Smiod 	 * On PCXS processors, traps T_DATACC, T_DATAPID and T_DATALIGN
40578a8f2b7Smiod 	 * are shared.  We need to sort out the unaligned access situation
40678a8f2b7Smiod 	 * first, before handling this trap as T_DATACC.
40778a8f2b7Smiod 	 */
408af7386c3Smickey 	case T_DPROT | T_USER:
40978a8f2b7Smiod 		if (cpu_type == hpcxs) {
41078a8f2b7Smiod 			if (pcxs_unaligned(opcode, va))
41178a8f2b7Smiod 				goto datalign_user;
41278a8f2b7Smiod 			else
41378a8f2b7Smiod 				goto datacc;
41478a8f2b7Smiod 		}
41578a8f2b7Smiod 
416af7386c3Smickey 		sv.sival_int = va;
417f4e9e19cSguenther 		KERNEL_LOCK();
418af7386c3Smickey 		trapsignal(p, SIGSEGV, vftype, SEGV_ACCERR, sv);
419f4e9e19cSguenther 		KERNEL_UNLOCK();
420af7386c3Smickey 		break;
421af7386c3Smickey 
4229208e3abSmickey 	case T_ITLBMISSNA:
4239208e3abSmickey 	case T_ITLBMISSNA | T_USER:
4249208e3abSmickey 	case T_DTLBMISSNA:
4259208e3abSmickey 	case T_DTLBMISSNA | T_USER:
4269208e3abSmickey 		if (space == HPPA_SID_KERNEL)
4279208e3abSmickey 			map = kernel_map;
4289208e3abSmickey 		else {
4299208e3abSmickey 			vm = p->p_vmspace;
4309208e3abSmickey 			map = &vm->vm_map;
4319208e3abSmickey 		}
4329208e3abSmickey 
43398898169Smickey 		if ((opcode & 0xfc003fc0) == 0x04001340) {
43498898169Smickey 			/* lpa failure case */
43598898169Smickey 			frame_regmap(frame, opcode & 0x1f) = 0;
43698898169Smickey 			frame->tf_ipsw |= PSL_N;
43798898169Smickey 		} else if ((opcode & 0xfc001f80) == 0x04001180) {
4389208e3abSmickey 			int pl;
4399208e3abSmickey 
44098898169Smickey 			/* dig probe[rw]i? insns */
4419208e3abSmickey 			if (opcode & 0x2000)
4429208e3abSmickey 				pl = (opcode >> 16) & 3;
4439208e3abSmickey 			else
4449208e3abSmickey 				pl = frame_regmap(frame,
4459208e3abSmickey 				    (opcode >> 16) & 0x1f) & 3;
4469208e3abSmickey 
447cfad034cSjsing 			KERNEL_LOCK();
448cfad034cSjsing 
4499208e3abSmickey 			if ((type & T_USER && space == HPPA_SID_KERNEL) ||
4509208e3abSmickey 			    (frame->tf_iioq_head & 3) != pl ||
4519208e3abSmickey 			    (type & T_USER && va >= VM_MAXUSER_ADDRESS) ||
4525fbb3992Smartin 			    uvm_fault(map, trunc_page(va), fault,
4539208e3abSmickey 			     opcode & 0x40? UVM_PROT_WRITE : UVM_PROT_READ)) {
4549208e3abSmickey 				frame_regmap(frame, opcode & 0x1f) = 0;
4559208e3abSmickey 				frame->tf_ipsw |= PSL_N;
4569208e3abSmickey 			}
457cfad034cSjsing 
458cfad034cSjsing 			KERNEL_UNLOCK();
4599208e3abSmickey 		} else if (type & T_USER) {
4609208e3abSmickey 			sv.sival_int = va;
461f4e9e19cSguenther 			KERNEL_LOCK();
4629208e3abSmickey 			trapsignal(p, SIGILL, type & ~T_USER, ILL_ILLTRP, sv);
463f4e9e19cSguenther 			KERNEL_UNLOCK();
4649208e3abSmickey 		} else
46562a36cb0Sfgsch 			panic("trap: %s @ 0x%x:0x%x for 0x%x:0x%x irr 0x%08x",
4669208e3abSmickey 			    tts, frame->tf_iisq_head, frame->tf_iioq_head,
4679208e3abSmickey 			    space, va, opcode);
4689208e3abSmickey 		break;
4699208e3abSmickey 
470998e9803Skettenis 	case T_IPROT | T_USER:
4719208e3abSmickey 	case T_TLB_DIRTY:
4729208e3abSmickey 	case T_TLB_DIRTY | T_USER:
473c6555f83Sderaadt 	case T_DATACC:
474c6555f83Sderaadt 	case T_DATACC | T_USER:
47578a8f2b7Smiod datacc:
4766198d067Smickey 		fault = VM_FAULT_PROTECT;
477c6555f83Sderaadt 	case T_ITLBMISS:
478c6555f83Sderaadt 	case T_ITLBMISS | T_USER:
479c6555f83Sderaadt 	case T_DTLBMISS:
480c6555f83Sderaadt 	case T_DTLBMISS | T_USER:
4818de28e3eSmickey 		/*
482e494c7cfSmickey 		 * it could be a kernel map for exec_map faults
4838de28e3eSmickey 		 */
48443a91648Smickey 		if (space == HPPA_SID_KERNEL)
4858de28e3eSmickey 			map = kernel_map;
48643a91648Smickey 		else {
48743a91648Smickey 			vm = p->p_vmspace;
488f17fa196Smickey 			map = &vm->vm_map;
48943a91648Smickey 		}
490556d2ba7Smickey 
4919208e3abSmickey 		/*
4929208e3abSmickey 		 * user faults out of user addr space are always a fail,
4939208e3abSmickey 		 * this happens on va >= VM_MAXUSER_ADDRESS, where
4949208e3abSmickey 		 * space id will be zero and therefore cause
4959208e3abSmickey 		 * a misbehave lower in the code.
4969208e3abSmickey 		 *
4979208e3abSmickey 		 * also check that faulted space id matches the curproc.
4989208e3abSmickey 		 */
4999208e3abSmickey 		if ((type & T_USER && va >= VM_MAXUSER_ADDRESS) ||
5009208e3abSmickey 		   (type & T_USER && map->pmap->pm_space != space)) {
501906a25e0Smickey 			sv.sival_int = va;
502f4e9e19cSguenther 			KERNEL_LOCK();
503906a25e0Smickey 			trapsignal(p, SIGSEGV, vftype, SEGV_MAPERR, sv);
504f4e9e19cSguenther 			KERNEL_UNLOCK();
50543a91648Smickey 			break;
506906a25e0Smickey 		}
507532740e6Smickey 
508cfad034cSjsing 		KERNEL_LOCK();
509cfad034cSjsing 
5105fbb3992Smartin 		ret = uvm_fault(map, trunc_page(va), fault, vftype);
511f17fa196Smickey 
512f17fa196Smickey 		/*
513f17fa196Smickey 		 * If this was a stack access we keep track of the maximum
514f17fa196Smickey 		 * accessed stack size.  Also, if uvm_fault gets a protection
515f17fa196Smickey 		 * failure it is due to accessing the stack region outside
516f17fa196Smickey 		 * the current limit and we need to reflect that as an access
517f17fa196Smickey 		 * error.
518f17fa196Smickey 		 */
51956f69dffSmiod 		if (space != HPPA_SID_KERNEL &&
52062899679Smiod 		    va < (vaddr_t)vm->vm_minsaddr) {
52162899679Smiod 			if (ret == 0)
52262899679Smiod 				uvm_grow(p, va);
52362899679Smiod 			else if (ret == EACCES)
524738a5b4dSart 				ret = EFAULT;
525f17fa196Smickey 		}
526f17fa196Smickey 
527cfad034cSjsing 		KERNEL_UNLOCK();
528cfad034cSjsing 
529738a5b4dSart 		if (ret != 0) {
530af7386c3Smickey 			if (type & T_USER) {
531a4be06b3Smickey 				sv.sival_int = va;
532f4e9e19cSguenther 				KERNEL_LOCK();
533a4be06b3Smickey 				trapsignal(p, SIGSEGV, vftype,
534a4be06b3Smickey 				    ret == EACCES? SEGV_ACCERR : SEGV_MAPERR,
535a4be06b3Smickey 				    sv);
536f4e9e19cSguenther 				KERNEL_UNLOCK();
537137d3021Smickey 			} else {
5388de28e3eSmickey 				if (p && p->p_addr->u_pcb.pcb_onfault) {
5398de28e3eSmickey 					frame->tf_iioq_tail = 4 +
5408de28e3eSmickey 					    (frame->tf_iioq_head =
54138575cbdSmickey 						p->p_addr->u_pcb.pcb_onfault);
542b04f760fSmickey #ifdef DDB
543b04f760fSmickey 					frame->tf_iir = 0;
544b04f760fSmickey #endif
545db97f33bSmickey 				} else {
546db97f33bSmickey 					panic("trap: "
54756f69dffSmiod 					    "uvm_fault(%p, %lx, %d, %d): %d",
54896415af6Smickey 					    map, va, fault, vftype, ret);
549137d3021Smickey 				}
550137d3021Smickey 			}
551db97f33bSmickey 		}
552556d2ba7Smickey 		break;
553d412f1c2Smickey 
55463b0c7d2Smiod 	case T_DATAPID:
55563b0c7d2Smiod 		/* This should never happen, unless within spcopy() */
55663b0c7d2Smiod 		if (p && p->p_addr->u_pcb.pcb_onfault) {
55763b0c7d2Smiod 			frame->tf_iioq_tail = 4 +
55863b0c7d2Smiod 			    (frame->tf_iioq_head =
55963b0c7d2Smiod 				p->p_addr->u_pcb.pcb_onfault);
56063b0c7d2Smiod #ifdef DDB
56163b0c7d2Smiod 			frame->tf_iir = 0;
56263b0c7d2Smiod #endif
56363b0c7d2Smiod 		} else
56463b0c7d2Smiod 			goto dead_end;
56563b0c7d2Smiod 		break;
56663b0c7d2Smiod 
567af7386c3Smickey 	case T_DATALIGN | T_USER:
56878a8f2b7Smiod datalign_user:
569137d3021Smickey 		sv.sival_int = va;
570f4e9e19cSguenther 		KERNEL_LOCK();
571af7386c3Smickey 		trapsignal(p, SIGBUS, vftype, BUS_ADRALN, sv);
572f4e9e19cSguenther 		KERNEL_UNLOCK();
573af7386c3Smickey 		break;
574af7386c3Smickey 
575a24c0b7aSmickey 	case T_INTERRUPT:
576a24c0b7aSmickey 	case T_INTERRUPT | T_USER:
577a24c0b7aSmickey 		cpu_intr(frame);
578af7386c3Smickey 		break;
579af7386c3Smickey 
580b7d25a19Smickey 	case T_CONDITION:
581b7d25a19Smickey 		panic("trap: divide by zero in the kernel");
582b7d25a19Smickey 		break;
583b7d25a19Smickey 
5843147f0deSmickey 	case T_ILLEGAL:
5853147f0deSmickey 	case T_ILLEGAL | T_USER:
5863147f0deSmickey 		/* see if it's a SPOP1,,0 */
58796415af6Smickey 		if ((opcode & 0xfffffe00) == 0x10000200) {
58896415af6Smickey 			frame_regmap(frame, opcode & 0x1f) = 0;
5893147f0deSmickey 			frame->tf_ipsw |= PSL_N;
5903147f0deSmickey 			break;
5913147f0deSmickey 		}
5923147f0deSmickey 		if (type & T_USER) {
5933147f0deSmickey 			sv.sival_int = va;
594f4e9e19cSguenther 			KERNEL_LOCK();
5953147f0deSmickey 			trapsignal(p, SIGILL, type & ~T_USER, ILL_ILLOPC, sv);
596f4e9e19cSguenther 			KERNEL_UNLOCK();
5973147f0deSmickey 			break;
5983147f0deSmickey 		}
5993147f0deSmickey 		/* FALLTHROUGH */
6003147f0deSmickey 
60178a8f2b7Smiod 	/*
60278a8f2b7Smiod 	 * On PCXS processors, traps T_DATACC, T_DATAPID and T_DATALIGN
60378a8f2b7Smiod 	 * are shared.  We need to sort out the unaligned access situation
60478a8f2b7Smiod 	 * first, before handling this trap as T_DATACC.
60578a8f2b7Smiod 	 */
6062ef9a47eSmickey 	case T_DPROT:
60778a8f2b7Smiod 		if (cpu_type == hpcxs) {
60878a8f2b7Smiod 			if (pcxs_unaligned(opcode, va))
60978a8f2b7Smiod 				goto dead_end;
61078a8f2b7Smiod 			else
61178a8f2b7Smiod 				goto datacc;
61278a8f2b7Smiod 		}
61378a8f2b7Smiod 		/* FALLTHROUGH to unimplemented */
61478a8f2b7Smiod 
61578a8f2b7Smiod 	case T_LOWERPL:
6162ef9a47eSmickey 	case T_IPROT:
617af7386c3Smickey 	case T_OVERFLOW:
618af7386c3Smickey 	case T_HIGHERPL:
619af7386c3Smickey 	case T_TAKENBR:
620af7386c3Smickey 	case T_POWERFAIL:
621af7386c3Smickey 	case T_LPMC:
622af7386c3Smickey 	case T_PAGEREF:
623d412f1c2Smickey 		/* FALLTHROUGH to unimplemented */
624d412f1c2Smickey 	default:
625ea3191ebSjsing #ifdef TRAPDEBUG
626532740e6Smickey 		if (kdb_trap(type, va, frame))
627137d3021Smickey 			return;
628137d3021Smickey #endif
62970016991Smickey 		panic("trap: unimplemented \'%s\' (%d)", tts, trapnum);
630d412f1c2Smickey 	}
631af7386c3Smickey 
63270016991Smickey #ifdef DIAGNOSTIC
633473ddf34Sjsing 	if (curcpu()->ci_cpl != oldcpl)
63470016991Smickey 		printf("WARNING: SPL (%d) NOT LOWERED ON "
635473ddf34Sjsing 		    "TRAP (%d) EXIT\n", curcpu()->ci_cpl, trapnum);
63670016991Smickey #endif
63770016991Smickey 
63870016991Smickey 	if (trapnum != T_INTERRUPT)
639473ddf34Sjsing 		splx(curcpu()->ci_cpl);	/* process softints */
64070016991Smickey 
641ba42a120Smickey 	/*
642ba42a120Smickey 	 * in case we were interrupted from the syscall gate page
64324d53bfeSkrw 	 * treat this as we were not really running user code no more
644ba42a120Smickey 	 * for weird things start to happen on return to the userland
645ba42a120Smickey 	 * and also see a note in locore.S:TLABEL(all)
646ba42a120Smickey 	 */
6477b428176Smickey 	if ((type & T_USER) && !(frame->tf_iisq_head == HPPA_SID_KERNEL &&
648c2b93341Sderaadt 	    (frame->tf_iioq_head & ~PAGE_MASK) == SYSCALLGATE)) {
649c2b93341Sderaadt 		ast(p);
650c19cb33fSmickey 		userret(p);
651d412f1c2Smickey 	}
652c2b93341Sderaadt }
653d412f1c2Smickey 
654d412f1c2Smickey void
655cfad034cSjsing child_return(void *arg)
656d412f1c2Smickey {
657db36253aSmickey 	struct proc *p = (struct proc *)arg;
65889afe3e5Smickey 	struct trapframe *tf = p->p_md.md_regs;
65989afe3e5Smickey 
66089afe3e5Smickey 	/*
66189afe3e5Smickey 	 * Set up return value registers as libc:fork() expects
66289afe3e5Smickey 	 */
66389afe3e5Smickey 	tf->tf_ret0 = 0;
66489afe3e5Smickey 	tf->tf_ret1 = 1;	/* ischild */
66589afe3e5Smickey 	tf->tf_t1 = 0;		/* errno */
66689afe3e5Smickey 
667971e1bb6Sart 	KERNEL_UNLOCK();
668cfad034cSjsing 
669c2b93341Sderaadt 	ast(p);
670fc572715Sguenther 
671fc572715Sguenther 	mi_child_return(p);
672556d2ba7Smickey }
673556d2ba7Smickey 
6747bfbef72Skettenis #ifdef PTRACE
6757bfbef72Skettenis 
6767bfbef72Skettenis #include <sys/ptrace.h>
6777bfbef72Skettenis 
678dd6e4488Sderaadt int	ss_get_value(struct proc *p, vaddr_t addr, u_int *value);
679dd6e4488Sderaadt int	ss_put_value(struct proc *p, vaddr_t addr, u_int value);
680dd6e4488Sderaadt 
6817bfbef72Skettenis int
6827bfbef72Skettenis ss_get_value(struct proc *p, vaddr_t addr, u_int *value)
6837bfbef72Skettenis {
6847bfbef72Skettenis 	struct uio uio;
6857bfbef72Skettenis 	struct iovec iov;
6867bfbef72Skettenis 
6877bfbef72Skettenis 	iov.iov_base = (caddr_t)value;
6887bfbef72Skettenis 	iov.iov_len = sizeof(u_int);
6897bfbef72Skettenis 	uio.uio_iov = &iov;
6907bfbef72Skettenis 	uio.uio_iovcnt = 1;
6917bfbef72Skettenis 	uio.uio_offset = (off_t)addr;
6927bfbef72Skettenis 	uio.uio_resid = sizeof(u_int);
6937bfbef72Skettenis 	uio.uio_segflg = UIO_SYSSPACE;
6947bfbef72Skettenis 	uio.uio_rw = UIO_READ;
6957bfbef72Skettenis 	uio.uio_procp = curproc;
6960888e41eSmiod 	return (process_domem(curproc, p, &uio, PT_READ_I));
6977bfbef72Skettenis }
6987bfbef72Skettenis 
6997bfbef72Skettenis int
7007bfbef72Skettenis ss_put_value(struct proc *p, vaddr_t addr, u_int value)
7017bfbef72Skettenis {
7027bfbef72Skettenis 	struct uio uio;
7037bfbef72Skettenis 	struct iovec iov;
7047bfbef72Skettenis 
7057bfbef72Skettenis 	iov.iov_base = (caddr_t)&value;
7067bfbef72Skettenis 	iov.iov_len = sizeof(u_int);
7077bfbef72Skettenis 	uio.uio_iov = &iov;
7087bfbef72Skettenis 	uio.uio_iovcnt = 1;
7097bfbef72Skettenis 	uio.uio_offset = (off_t)addr;
7107bfbef72Skettenis 	uio.uio_resid = sizeof(u_int);
7117bfbef72Skettenis 	uio.uio_segflg = UIO_SYSSPACE;
7127bfbef72Skettenis 	uio.uio_rw = UIO_WRITE;
7137bfbef72Skettenis 	uio.uio_procp = curproc;
7140888e41eSmiod 	return (process_domem(curproc, p, &uio, PT_WRITE_I));
7157bfbef72Skettenis }
7167bfbef72Skettenis 
7177bfbef72Skettenis void
7187bfbef72Skettenis ss_clear_breakpoints(struct proc *p)
7197bfbef72Skettenis {
7207bfbef72Skettenis 	/* Restore origional instructions. */
7217bfbef72Skettenis 	if (p->p_md.md_bpva != 0) {
7227bfbef72Skettenis 		ss_put_value(p, p->p_md.md_bpva, p->p_md.md_bpsave[0]);
7237bfbef72Skettenis 		ss_put_value(p, p->p_md.md_bpva + 4, p->p_md.md_bpsave[1]);
7247bfbef72Skettenis 		p->p_md.md_bpva = 0;
7257bfbef72Skettenis 	}
7267bfbef72Skettenis }
7277bfbef72Skettenis 
7287bfbef72Skettenis int
7297bfbef72Skettenis process_sstep(struct proc *p, int sstep)
7307bfbef72Skettenis {
7317bfbef72Skettenis 	int error;
7327bfbef72Skettenis 
7337bfbef72Skettenis 	ss_clear_breakpoints(p);
7347bfbef72Skettenis 
73585bd3014Skettenis 	if (sstep == 0) {
7367bfbef72Skettenis 		p->p_md.md_regs->tf_ipsw &= ~PSL_T;
7377bfbef72Skettenis 		return (0);
7387bfbef72Skettenis 	}
7397bfbef72Skettenis 
74085bd3014Skettenis 	/*
74185bd3014Skettenis 	 * Don't touch the syscall gateway page.  Instead, insert a
74285bd3014Skettenis 	 * breakpoint where we're supposed to return.
74385bd3014Skettenis 	 */
74485bd3014Skettenis 	if ((p->p_md.md_regs->tf_iioq_tail & ~PAGE_MASK) == SYSCALLGATE)
74585bd3014Skettenis 		p->p_md.md_bpva = p->p_md.md_regs->tf_r31 & ~HPPA_PC_PRIV_MASK;
74685bd3014Skettenis 	else
7477bfbef72Skettenis 		p->p_md.md_bpva = p->p_md.md_regs->tf_iioq_tail & ~HPPA_PC_PRIV_MASK;
7487bfbef72Skettenis 
7497bfbef72Skettenis 	/*
7507bfbef72Skettenis 	 * Insert two breakpoint instructions; the first one might be
7517bfbef72Skettenis 	 * nullified.  Of course we need to save two instruction
7527bfbef72Skettenis 	 * first.
7537bfbef72Skettenis 	 */
7547bfbef72Skettenis 
7557bfbef72Skettenis 	error = ss_get_value(p, p->p_md.md_bpva, &p->p_md.md_bpsave[0]);
7567bfbef72Skettenis 	if (error)
7577bfbef72Skettenis 		return (error);
7587bfbef72Skettenis 	error = ss_get_value(p, p->p_md.md_bpva + 4, &p->p_md.md_bpsave[1]);
7597bfbef72Skettenis 	if (error)
7607bfbef72Skettenis 		return (error);
7617bfbef72Skettenis 
7627bfbef72Skettenis 	error = ss_put_value(p, p->p_md.md_bpva, SSBREAKPOINT);
7637bfbef72Skettenis 	if (error)
7647bfbef72Skettenis 		return (error);
7657bfbef72Skettenis 	error = ss_put_value(p, p->p_md.md_bpva + 4, SSBREAKPOINT);
7667bfbef72Skettenis 	if (error)
7677bfbef72Skettenis 		return (error);
7687bfbef72Skettenis 
76985bd3014Skettenis 	if ((p->p_md.md_regs->tf_iioq_tail & ~PAGE_MASK) != SYSCALLGATE)
7707bfbef72Skettenis 		p->p_md.md_regs->tf_ipsw |= PSL_T;
77185bd3014Skettenis 	else
77285bd3014Skettenis 		p->p_md.md_regs->tf_ipsw &= ~PSL_T;
77385bd3014Skettenis 
7747bfbef72Skettenis 	return (0);
7757bfbef72Skettenis }
7767bfbef72Skettenis 
7777bfbef72Skettenis #endif	/* PTRACE */
778db97f33bSmickey 
779dd6e4488Sderaadt void	syscall(struct trapframe *frame);
780dd6e4488Sderaadt 
781b9b95e0dSmickey /*
782b9b95e0dSmickey  * call actual syscall routine
783b9b95e0dSmickey  */
784b9b95e0dSmickey void
78570016991Smickey syscall(struct trapframe *frame)
786b9b95e0dSmickey {
787db97f33bSmickey 	register struct proc *p = curproc;
788b9b95e0dSmickey 	register const struct sysent *callp;
7899417b0e6Sguenther 	int retq, nsys, code, argsize, argoff, error;
790b7d25a19Smickey 	register_t args[8], rval[2];
79170016991Smickey #ifdef DIAGNOSTIC
792473ddf34Sjsing 	int oldcpl = curcpu()->ci_cpl;
79370016991Smickey #endif
794b9b95e0dSmickey 
795b9b95e0dSmickey 	uvmexp.syscalls++;
796b9b95e0dSmickey 
797b9b95e0dSmickey 	if (!USERMODE(frame->tf_iioq_head))
798b9b95e0dSmickey 		panic("syscall");
799b9b95e0dSmickey 
800137d3021Smickey 	p->p_md.md_regs = frame;
801*8f76f5adSguenther 	nsys = p->p_p->ps_emul->e_nsysent;
802*8f76f5adSguenther 	callp = p->p_p->ps_emul->e_sysent;
803db97f33bSmickey 
804b7d25a19Smickey 	argoff = 4; retq = 0;
805db97f33bSmickey 	switch (code = frame->tf_t1) {
806b9b95e0dSmickey 	case SYS_syscall:
807db97f33bSmickey 		code = frame->tf_arg0;
808db97f33bSmickey 		args[0] = frame->tf_arg1;
809db97f33bSmickey 		args[1] = frame->tf_arg2;
810db97f33bSmickey 		args[2] = frame->tf_arg3;
811db97f33bSmickey 		argoff = 3;
812b9b95e0dSmickey 		break;
813b9b95e0dSmickey 	case SYS___syscall:
814b9b95e0dSmickey 		if (callp != sysent)
815b9b95e0dSmickey 			break;
816db97f33bSmickey 		/*
817db97f33bSmickey 		 * this works, because quads get magically swapped
8187503858eSjfb 		 * due to the args being laid backwards on the stack
819db97f33bSmickey 		 * and then copied in words
820db97f33bSmickey 		 */
821db97f33bSmickey 		code = frame->tf_arg0;
822db97f33bSmickey 		args[0] = frame->tf_arg2;
823db97f33bSmickey 		args[1] = frame->tf_arg3;
824db97f33bSmickey 		argoff = 2;
825b7d25a19Smickey 		retq = 1;
826db97f33bSmickey 		break;
827db97f33bSmickey 	default:
828db97f33bSmickey 		args[0] = frame->tf_arg0;
829db97f33bSmickey 		args[1] = frame->tf_arg1;
830db97f33bSmickey 		args[2] = frame->tf_arg2;
831db97f33bSmickey 		args[3] = frame->tf_arg3;
832db97f33bSmickey 		break;
833b9b95e0dSmickey 	}
834b9b95e0dSmickey 
835b9b95e0dSmickey 	if (code < 0 || code >= nsys)
836*8f76f5adSguenther 		callp += p->p_p->ps_emul->e_nosys;	/* bad syscall # */
837b9b95e0dSmickey 	else
838b9b95e0dSmickey 		callp += code;
839db97f33bSmickey 
840db97f33bSmickey 	if ((argsize = callp->sy_argsize)) {
841db97f33bSmickey 		int i;
842db97f33bSmickey 
843db97f33bSmickey 		for (i = 0, argsize -= argoff * 4;
844db97f33bSmickey 		    argsize > 0; i++, argsize -= 4) {
845fc572715Sguenther 			if ((error = copyin((void *)(frame->tf_sp +
846fc572715Sguenther 			    HPPA_FRAME_ARG(i + 4)), args + i + argoff, 4)))
847fc572715Sguenther 				goto bad;
848db97f33bSmickey 		}
849db97f33bSmickey 
850db97f33bSmickey 		/*
851db97f33bSmickey 		 * coming from syscall() or __syscall we must be
852db97f33bSmickey 		 * having one of those w/ a 64 bit arguments,
853db97f33bSmickey 		 * which needs a word swap due to the order
854db97f33bSmickey 		 * of the arguments on the stack.
855db97f33bSmickey 		 * this assumes that none of 'em are called
856db97f33bSmickey 		 * by their normal syscall number, maybe a regress
857b49f4f07Smiod 		 * test should be used, to watch the behaviour.
858db97f33bSmickey 		 */
859fc572715Sguenther 		if (argoff < 4) {
860db97f33bSmickey 			int t;
861db97f33bSmickey 
862db97f33bSmickey 			i = 0;
863db97f33bSmickey 			switch (code) {
864b7d25a19Smickey 			case SYS_lseek:		retq = 0;
865db97f33bSmickey 			case SYS_truncate:
866db97f33bSmickey 			case SYS_ftruncate:	i = 2;	break;
867db97f33bSmickey 			case SYS_preadv:
868db97f33bSmickey 			case SYS_pwritev:
869db97f33bSmickey 			case SYS_pread:
870db97f33bSmickey 			case SYS_pwrite:	i = 4;	break;
871a9d0813cSmiod 			case SYS_mquery:
872db97f33bSmickey 			case SYS_mmap:		i = 6;	break;
873db97f33bSmickey 			}
874db97f33bSmickey 
875db97f33bSmickey 			if (i) {
876db97f33bSmickey 				t = args[i];
877db97f33bSmickey 				args[i] = args[i + 1];
878db97f33bSmickey 				args[i + 1] = t;
879db97f33bSmickey 			}
880db97f33bSmickey 		}
881db97f33bSmickey 	}
882b9b95e0dSmickey 
883b9b95e0dSmickey 	rval[0] = 0;
884db97f33bSmickey 	rval[1] = frame->tf_ret1;
885cfad034cSjsing 
8869417b0e6Sguenther 	error = mi_syscall(p, code, callp, args, rval);
887fc572715Sguenther 
88896a1071fSmiod 	switch (error) {
889b9b95e0dSmickey 	case 0:
890b9b95e0dSmickey 		frame->tf_ret0 = rval[0];
891b7d25a19Smickey 		frame->tf_ret1 = rval[!retq];
892137d3021Smickey 		frame->tf_t1 = 0;
893b9b95e0dSmickey 		break;
894b9b95e0dSmickey 	case ERESTART:
895c37e03c6Smickey 		frame->tf_iioq_head -= 12;
896c37e03c6Smickey 		frame->tf_iioq_tail -= 12;
897b9b95e0dSmickey 	case EJUSTRETURN:
898b9b95e0dSmickey 		break;
899b9b95e0dSmickey 	default:
900db97f33bSmickey 	bad:
901137d3021Smickey 		frame->tf_t1 = error;
90247df6ae3Smickey 		frame->tf_ret0 = error;
90347df6ae3Smickey 		frame->tf_ret1 = 0;
904b9b95e0dSmickey 		break;
905b9b95e0dSmickey 	}
906fc572715Sguenther 
907c2b93341Sderaadt 	ast(p);
908fc572715Sguenther 
9099417b0e6Sguenther 	mi_syscall_return(p, code, error, rval);
910fc572715Sguenther 
91170016991Smickey #ifdef DIAGNOSTIC
912473ddf34Sjsing 	if (curcpu()->ci_cpl != oldcpl) {
91370016991Smickey 		printf("WARNING: SPL (0x%x) NOT LOWERED ON "
91470016991Smickey 		    "syscall(0x%x, 0x%x, 0x%x, 0x%x...) EXIT, PID %d\n",
915473ddf34Sjsing 		    curcpu()->ci_cpl, code, args[0], args[1], args[2],
916473ddf34Sjsing 		    p->p_pid);
917473ddf34Sjsing 		curcpu()->ci_cpl = oldcpl;
91850552582Smickey 	}
91970016991Smickey #endif
920473ddf34Sjsing 	splx(curcpu()->ci_cpl);	/* process softints */
921b9b95e0dSmickey }
92278a8f2b7Smiod 
92378a8f2b7Smiod /*
92478a8f2b7Smiod  * Decide if opcode `opcode' accessing virtual address `va' caused an
92578a8f2b7Smiod  * unaligned trap. Returns zero if the access is correctly aligned.
92678a8f2b7Smiod  * Used on PCXS processors to sort out exception causes.
92778a8f2b7Smiod  */
92878a8f2b7Smiod int
92978a8f2b7Smiod pcxs_unaligned(u_int opcode, vaddr_t va)
93078a8f2b7Smiod {
93178a8f2b7Smiod 	u_int mbz_bits;
93278a8f2b7Smiod 
93378a8f2b7Smiod 	/*
93478a8f2b7Smiod 	 * Exit early if the va is obviously aligned enough.
93578a8f2b7Smiod 	 */
93678a8f2b7Smiod 	if ((va & 0x0f) == 0)
93778a8f2b7Smiod 		return 0;
93878a8f2b7Smiod 
93978a8f2b7Smiod 	mbz_bits = 0;
94078a8f2b7Smiod 
94178a8f2b7Smiod 	/*
94278a8f2b7Smiod 	 * Only load and store instructions can cause unaligned access.
94378a8f2b7Smiod 	 * There are three opcode patterns to look for:
94478a8f2b7Smiod 	 * - canonical load/store
94578a8f2b7Smiod 	 * - load/store short or indexed
94678a8f2b7Smiod 	 * - coprocessor load/store
94778a8f2b7Smiod 	 */
94878a8f2b7Smiod 
94978a8f2b7Smiod 	if ((opcode & 0xd0000000) == 0x40000000) {
95078a8f2b7Smiod 		switch ((opcode >> 26) & 0x03) {
95178a8f2b7Smiod 		case 0x00:	/* ldb, stb */
95278a8f2b7Smiod 			mbz_bits = 0x00;
95378a8f2b7Smiod 			break;
95478a8f2b7Smiod 		case 0x01:	/* ldh, sth */
95578a8f2b7Smiod 			mbz_bits = 0x01;
95678a8f2b7Smiod 			break;
95778a8f2b7Smiod 		case 0x02:	/* ldw, stw */
95878a8f2b7Smiod 		case 0x03:	/* ldwm, stwm */
95978a8f2b7Smiod 			mbz_bits = 0x03;
96078a8f2b7Smiod 			break;
96178a8f2b7Smiod 		}
96278a8f2b7Smiod 	} else
96378a8f2b7Smiod 
96478a8f2b7Smiod 	if ((opcode & 0xfc000000) == 0x0c000000) {
96578a8f2b7Smiod 		switch ((opcode >> 6) & 0x0f) {
96678a8f2b7Smiod 		case 0x01:	/* ldhx, ldhs */
96778a8f2b7Smiod 			mbz_bits = 0x01;
96878a8f2b7Smiod 			break;
96978a8f2b7Smiod 		case 0x02:	/* ldwx, ldws */
97078a8f2b7Smiod 			mbz_bits = 0x03;
97178a8f2b7Smiod 			break;
97278a8f2b7Smiod 		case 0x07:	/* ldcwx, ldcws */
97378a8f2b7Smiod 			mbz_bits = 0x0f;
97478a8f2b7Smiod 			break;
97578a8f2b7Smiod 		case 0x09:
97678a8f2b7Smiod 			if ((opcode & (1 << 12)) != 0)	/* sths */
97778a8f2b7Smiod 				mbz_bits = 0x01;
97878a8f2b7Smiod 			break;
97978a8f2b7Smiod 		case 0x0a:
98078a8f2b7Smiod 			if ((opcode & (1 << 12)) != 0)	/* stws */
98178a8f2b7Smiod 				mbz_bits = 0x03;
98278a8f2b7Smiod 			break;
98378a8f2b7Smiod 		}
98478a8f2b7Smiod 	} else
98578a8f2b7Smiod 
98678a8f2b7Smiod 	if ((opcode & 0xf4000000) == 0x24000000) {
98778a8f2b7Smiod 		if ((opcode & (1 << 27)) != 0) {
98878a8f2b7Smiod 			/* cldwx, cstwx, cldws, cstws */
98978a8f2b7Smiod 			mbz_bits = 0x03;
99078a8f2b7Smiod 		} else {
99178a8f2b7Smiod 			/* clddx, cstdx, cldds, cstds */
99278a8f2b7Smiod 			mbz_bits = 0x07;
99378a8f2b7Smiod 		}
99478a8f2b7Smiod 	}
99578a8f2b7Smiod 
99678a8f2b7Smiod 	return (va & mbz_bits);
99778a8f2b7Smiod }
998