trap.c revision 1.114
1/*	$OpenBSD: trap.c,v 1.114 2011/04/03 14:56:28 guenther Exp $	*/
2
3/*
4 * Copyright (c) 1998-2004 Michael Shalayeff
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
25 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 * THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/* #define TRAPDEBUG */
30
31#include <sys/param.h>
32#include <sys/systm.h>
33#include <sys/syscall.h>
34#include <sys/ktrace.h>
35#include <sys/proc.h>
36#include <sys/signalvar.h>
37#include <sys/user.h>
38
39#include "systrace.h"
40#include <dev/systrace.h>
41
42#include <uvm/uvm.h>
43
44#include <machine/autoconf.h>
45
46#ifdef DDB
47#ifdef TRAPDEBUG
48#include <ddb/db_output.h>
49#else
50#include <machine/db_machdep.h>
51#endif
52#endif
53
54static __inline int inst_store(u_int ins) {
55	return (ins & 0xf0000000) == 0x60000000 ||	/* st */
56	       (ins & 0xf4000200) == 0x24000200 ||	/* fst/cst */
57	       (ins & 0xfc000200) == 0x0c000200 ||	/* stby */
58	       (ins & 0xfc0003c0) == 0x0c0001c0;	/* ldcw */
59}
60
61int	pcxs_unaligned(u_int opcode, vaddr_t va);
62#ifdef PTRACE
63void	ss_clear_breakpoints(struct proc *p);
64#endif
65
66/* single-step breakpoint */
67#define SSBREAKPOINT	(HPPA_BREAK_KERNEL | (HPPA_BREAK_SS << 13))
68
69const char *trap_type[] = {
70	"invalid",
71	"HPMC",
72	"power failure",
73	"recovery counter",
74	"external interrupt",
75	"LPMC",
76	"ITLB miss fault",
77	"instruction protection",
78	"Illegal instruction",
79	"break instruction",
80	"privileged operation",
81	"privileged register",
82	"overflow",
83	"conditional",
84	"assist exception",
85	"DTLB miss",
86	"ITLB non-access miss",
87	"DTLB non-access miss",
88	"data protection/rights/alignment",
89	"data break",
90	"TLB dirty",
91	"page reference",
92	"assist emulation",
93	"higher-priv transfer",
94	"lower-priv transfer",
95	"taken branch",
96	"data access rights",
97	"data protection",
98	"unaligned data ref",
99};
100int trap_types = sizeof(trap_type)/sizeof(trap_type[0]);
101
102#define	frame_regmap(tf,r)	(((u_int *)(tf))[hppa_regmap[(r)]])
103u_char hppa_regmap[32] = {
104	offsetof(struct trapframe, tf_pad[0]) / 4,	/* r0 XXX */
105	offsetof(struct trapframe, tf_r1) / 4,
106	offsetof(struct trapframe, tf_rp) / 4,
107	offsetof(struct trapframe, tf_r3) / 4,
108	offsetof(struct trapframe, tf_r4) / 4,
109	offsetof(struct trapframe, tf_r5) / 4,
110	offsetof(struct trapframe, tf_r6) / 4,
111	offsetof(struct trapframe, tf_r7) / 4,
112	offsetof(struct trapframe, tf_r8) / 4,
113	offsetof(struct trapframe, tf_r9) / 4,
114	offsetof(struct trapframe, tf_r10) / 4,
115	offsetof(struct trapframe, tf_r11) / 4,
116	offsetof(struct trapframe, tf_r12) / 4,
117	offsetof(struct trapframe, tf_r13) / 4,
118	offsetof(struct trapframe, tf_r14) / 4,
119	offsetof(struct trapframe, tf_r15) / 4,
120	offsetof(struct trapframe, tf_r16) / 4,
121	offsetof(struct trapframe, tf_r17) / 4,
122	offsetof(struct trapframe, tf_r18) / 4,
123	offsetof(struct trapframe, tf_t4) / 4,
124	offsetof(struct trapframe, tf_t3) / 4,
125	offsetof(struct trapframe, tf_t2) / 4,
126	offsetof(struct trapframe, tf_t1) / 4,
127	offsetof(struct trapframe, tf_arg3) / 4,
128	offsetof(struct trapframe, tf_arg2) / 4,
129	offsetof(struct trapframe, tf_arg1) / 4,
130	offsetof(struct trapframe, tf_arg0) / 4,
131	offsetof(struct trapframe, tf_dp) / 4,
132	offsetof(struct trapframe, tf_ret0) / 4,
133	offsetof(struct trapframe, tf_ret1) / 4,
134	offsetof(struct trapframe, tf_sp) / 4,
135	offsetof(struct trapframe, tf_r31) / 4,
136};
137
138void	userret(struct proc *p);
139
140void
141userret(struct proc *p)
142{
143	int sig;
144
145	if (p->p_md.md_astpending) {
146		p->p_md.md_astpending = 0;
147		uvmexp.softs++;
148		if (p->p_flag & P_OWEUPC) {
149			KERNEL_PROC_LOCK(p);
150			ADDUPROF(p);
151			KERNEL_PROC_UNLOCK(p);
152		}
153		if (curcpu()->ci_want_resched)
154			preempt(NULL);
155	}
156
157	while ((sig = CURSIG(p)) != 0)
158		postsig(sig);
159
160	p->p_cpu->ci_schedstate.spc_curpriority = p->p_priority = p->p_usrpri;
161}
162
163void
164trap(int type, struct trapframe *frame)
165{
166	struct proc *p = curproc;
167	vaddr_t va;
168	struct vm_map *map;
169	struct vmspace *vm;
170	register vm_prot_t vftype;
171	register pa_space_t space;
172	union sigval sv;
173	u_int opcode;
174	int ret, trapnum;
175	const char *tts;
176	vm_fault_t fault = VM_FAULT_INVALID;
177#ifdef DIAGNOSTIC
178	int oldcpl = curcpu()->ci_cpl;
179#endif
180
181	trapnum = type & ~T_USER;
182	opcode = frame->tf_iir;
183	if (trapnum <= T_EXCEPTION || trapnum == T_HIGHERPL ||
184	    trapnum == T_LOWERPL || trapnum == T_TAKENBR ||
185	    trapnum == T_IDEBUG || trapnum == T_PERFMON) {
186		va = frame->tf_iioq_head;
187		space = frame->tf_iisq_head;
188		vftype = UVM_PROT_EXEC;
189	} else {
190		va = frame->tf_ior;
191		space = frame->tf_isr;
192		if (va == frame->tf_iioq_head)
193			vftype = UVM_PROT_EXEC;
194		else if (inst_store(opcode))
195			vftype = UVM_PROT_WRITE;
196		else
197			vftype = UVM_PROT_READ;
198	}
199
200	if (frame->tf_flags & TFF_LAST)
201		p->p_md.md_regs = frame;
202
203	if (trapnum > trap_types)
204		tts = "reserved";
205	else
206		tts = trap_type[trapnum];
207
208#ifdef TRAPDEBUG
209	if (trapnum != T_INTERRUPT && trapnum != T_IBREAK)
210		db_printf("trap: %x, %s for %x:%x at %x:%x, fl=%x, fp=%p\n",
211		    type, tts, space, va, frame->tf_iisq_head,
212		    frame->tf_iioq_head, frame->tf_flags, frame);
213	else if (trapnum  == T_IBREAK)
214		db_printf("trap: break instruction %x:%x at %x:%x, fp=%p\n",
215		    break5(opcode), break13(opcode),
216		    frame->tf_iisq_head, frame->tf_iioq_head, frame);
217
218	{
219		extern int etext;
220		if (frame < (struct trapframe *)&etext) {
221			printf("trap: bogus frame ptr %p\n", frame);
222			goto dead_end;
223		}
224	}
225#endif
226	if (trapnum != T_INTERRUPT) {
227		uvmexp.traps++;
228		mtctl(frame->tf_eiem, CR_EIEM);
229	}
230
231	switch (type) {
232	case T_NONEXIST:
233	case T_NONEXIST | T_USER:
234		/* we've got screwed up by the central scrutinizer */
235		printf("trap: elvis has just left the building!\n");
236		goto dead_end;
237
238	case T_RECOVERY:
239	case T_RECOVERY | T_USER:
240		/* XXX will implement later */
241		printf("trap: handicapped");
242		goto dead_end;
243
244#ifdef DIAGNOSTIC
245	case T_EXCEPTION:
246		panic("FPU/SFU emulation botch");
247
248		/* these just can't happen ever */
249	case T_PRIV_OP:
250	case T_PRIV_REG:
251		/* these just can't make it to the trap() ever */
252	case T_HPMC:
253	case T_HPMC | T_USER:
254#endif
255	case T_IBREAK:
256	case T_DATALIGN:
257	case T_DBREAK:
258	dead_end:
259#ifdef DDB
260		if (kdb_trap (type, va, frame)) {
261			if (type == T_IBREAK) {
262				/* skip break instruction */
263				frame->tf_iioq_head = frame->tf_iioq_tail;
264				frame->tf_iioq_tail += 4;
265			}
266			return;
267		}
268#else
269		if (type == T_DATALIGN || type == T_DPROT)
270			panic ("trap: %s at 0x%x", tts, va);
271		else
272			panic ("trap: no debugger for \"%s\" (%d)", tts, type);
273#endif
274		break;
275
276	case T_IBREAK | T_USER:
277	case T_DBREAK | T_USER: {
278		int code = TRAP_BRKPT;
279#ifdef PTRACE
280		ss_clear_breakpoints(p);
281		if (opcode == SSBREAKPOINT)
282			code = TRAP_TRACE;
283#endif
284		/* pass to user debugger */
285		KERNEL_PROC_LOCK(p);
286		trapsignal(p, SIGTRAP, type &~ T_USER, code, sv);
287		KERNEL_PROC_UNLOCK(p);
288		}
289		break;
290
291#ifdef PTRACE
292	case T_TAKENBR | T_USER:
293		ss_clear_breakpoints(p);
294
295		/* pass to user debugger */
296		KERNEL_PROC_LOCK(p);
297		trapsignal(p, SIGTRAP, type &~ T_USER, TRAP_TRACE, sv);
298		KERNEL_PROC_UNLOCK(p);
299		break;
300#endif
301
302	case T_EXCEPTION | T_USER: {
303		struct hppa_fpstate *hfp;
304		u_int64_t *fpp;
305		u_int32_t *pex;
306		int i, flt;
307
308		hfp = (struct hppa_fpstate *)frame->tf_cr30;
309		fpp = (u_int64_t *)&hfp->hfp_regs;
310
311		pex = (u_int32_t *)&fpp[0];
312		for (i = 0, pex++; i < 7 && !*pex; i++, pex++);
313		flt = 0;
314		if (i < 7) {
315			u_int32_t stat = HPPA_FPU_OP(*pex);
316			if (stat & HPPA_FPU_UNMPL)
317				flt = FPE_FLTINV;
318			else if (stat & (HPPA_FPU_V << 1))
319				flt = FPE_FLTINV;
320			else if (stat & (HPPA_FPU_Z << 1))
321				flt = FPE_FLTDIV;
322			else if (stat & (HPPA_FPU_I << 1))
323				flt = FPE_FLTRES;
324			else if (stat & (HPPA_FPU_O << 1))
325				flt = FPE_FLTOVF;
326			else if (stat & (HPPA_FPU_U << 1))
327				flt = FPE_FLTUND;
328			/* still left: under/over-flow w/ inexact */
329
330			/* cleanup exceptions (XXX deliver all ?) */
331			while (i++ < 7)
332				*pex++ = 0;
333		}
334		/* reset the trap flag, as if there was none */
335		fpp[0] &= ~(((u_int64_t)HPPA_FPU_T) << 32);
336
337		sv.sival_int = va;
338		KERNEL_PROC_LOCK(p);
339		trapsignal(p, SIGFPE, type &~ T_USER, flt, sv);
340		KERNEL_PROC_UNLOCK(p);
341		}
342		break;
343
344	case T_EMULATION:
345		panic("trap: emulation trap in the kernel");
346		break;
347
348	case T_EMULATION | T_USER:
349		sv.sival_int = va;
350		KERNEL_PROC_LOCK(p);
351		trapsignal(p, SIGILL, type &~ T_USER, ILL_COPROC, sv);
352		KERNEL_PROC_UNLOCK(p);
353		break;
354
355	case T_OVERFLOW | T_USER:
356		sv.sival_int = va;
357		KERNEL_PROC_LOCK(p);
358		trapsignal(p, SIGFPE, type &~ T_USER, FPE_INTOVF, sv);
359		KERNEL_PROC_UNLOCK(p);
360		break;
361
362	case T_CONDITION | T_USER:
363		sv.sival_int = va;
364		KERNEL_PROC_LOCK(p);
365		trapsignal(p, SIGFPE, type &~ T_USER, FPE_INTDIV, sv);
366		KERNEL_PROC_UNLOCK(p);
367		break;
368
369	case T_PRIV_OP | T_USER:
370		sv.sival_int = va;
371		KERNEL_PROC_LOCK(p);
372		trapsignal(p, SIGILL, type &~ T_USER, ILL_PRVOPC, sv);
373		KERNEL_PROC_UNLOCK(p);
374		break;
375
376	case T_PRIV_REG | T_USER:
377		sv.sival_int = va;
378		KERNEL_PROC_LOCK(p);
379		trapsignal(p, SIGILL, type &~ T_USER, ILL_PRVREG, sv);
380		KERNEL_PROC_UNLOCK(p);
381		break;
382
383		/* these should never got here */
384	case T_HIGHERPL | T_USER:
385	case T_LOWERPL | T_USER:
386		sv.sival_int = va;
387		KERNEL_PROC_LOCK(p);
388		trapsignal(p, SIGSEGV, vftype, SEGV_ACCERR, sv);
389		KERNEL_PROC_UNLOCK(p);
390		break;
391
392	/*
393	 * On PCXS processors, traps T_DATACC, T_DATAPID and T_DATALIGN
394	 * are shared.  We need to sort out the unaligned access situation
395	 * first, before handling this trap as T_DATACC.
396	 */
397	case T_DPROT | T_USER:
398		if (cpu_type == hpcxs) {
399			if (pcxs_unaligned(opcode, va))
400				goto datalign_user;
401			else
402				goto datacc;
403		}
404		/* FALLTHROUGH */
405
406	case T_IPROT | T_USER:
407		sv.sival_int = va;
408		KERNEL_PROC_LOCK(p);
409		trapsignal(p, SIGSEGV, vftype, SEGV_ACCERR, sv);
410		KERNEL_PROC_UNLOCK(p);
411		break;
412
413	case T_ITLBMISSNA:
414	case T_ITLBMISSNA | T_USER:
415	case T_DTLBMISSNA:
416	case T_DTLBMISSNA | T_USER:
417		if (space == HPPA_SID_KERNEL)
418			map = kernel_map;
419		else {
420			vm = p->p_vmspace;
421			map = &vm->vm_map;
422		}
423
424		if ((opcode & 0xfc003fc0) == 0x04001340) {
425			/* lpa failure case */
426			frame_regmap(frame, opcode & 0x1f) = 0;
427			frame->tf_ipsw |= PSL_N;
428		} else if ((opcode & 0xfc001f80) == 0x04001180) {
429			int pl;
430
431			/* dig probe[rw]i? insns */
432			if (opcode & 0x2000)
433				pl = (opcode >> 16) & 3;
434			else
435				pl = frame_regmap(frame,
436				    (opcode >> 16) & 0x1f) & 3;
437
438			if (type & T_USER)
439				KERNEL_PROC_LOCK(p);
440			else
441				KERNEL_LOCK();
442
443			if ((type & T_USER && space == HPPA_SID_KERNEL) ||
444			    (frame->tf_iioq_head & 3) != pl ||
445			    (type & T_USER && va >= VM_MAXUSER_ADDRESS) ||
446			    uvm_fault(map, trunc_page(va), fault,
447			     opcode & 0x40? UVM_PROT_WRITE : UVM_PROT_READ)) {
448				frame_regmap(frame, opcode & 0x1f) = 0;
449				frame->tf_ipsw |= PSL_N;
450			}
451
452			if (type & T_USER)
453				KERNEL_PROC_UNLOCK(p);
454			else
455				KERNEL_UNLOCK();
456		} else if (type & T_USER) {
457			sv.sival_int = va;
458			KERNEL_PROC_LOCK(p);
459			trapsignal(p, SIGILL, type & ~T_USER, ILL_ILLTRP, sv);
460			KERNEL_PROC_UNLOCK(p);
461		} else
462			panic("trap: %s @ 0x%x:0x%x for 0x%x:0x%x irr 0x%08x",
463			    tts, frame->tf_iisq_head, frame->tf_iioq_head,
464			    space, va, opcode);
465		break;
466
467	case T_TLB_DIRTY:
468	case T_TLB_DIRTY | T_USER:
469	case T_DATACC:
470	case T_DATACC | T_USER:
471datacc:
472		fault = VM_FAULT_PROTECT;
473	case T_ITLBMISS:
474	case T_ITLBMISS | T_USER:
475	case T_DTLBMISS:
476	case T_DTLBMISS | T_USER:
477		/*
478		 * it could be a kernel map for exec_map faults
479		 */
480		if (space == HPPA_SID_KERNEL)
481			map = kernel_map;
482		else {
483			vm = p->p_vmspace;
484			map = &vm->vm_map;
485		}
486
487		/*
488		 * user faults out of user addr space are always a fail,
489		 * this happens on va >= VM_MAXUSER_ADDRESS, where
490		 * space id will be zero and therefore cause
491		 * a misbehave lower in the code.
492		 *
493		 * also check that faulted space id matches the curproc.
494		 */
495		if ((type & T_USER && va >= VM_MAXUSER_ADDRESS) ||
496		   (type & T_USER && map->pmap->pm_space != space)) {
497			sv.sival_int = va;
498			KERNEL_PROC_LOCK(p);
499			trapsignal(p, SIGSEGV, vftype, SEGV_MAPERR, sv);
500			KERNEL_PROC_UNLOCK(p);
501			break;
502		}
503
504		if (type & T_USER)
505			KERNEL_PROC_LOCK(p);
506		else
507			KERNEL_LOCK();
508
509		ret = uvm_fault(map, trunc_page(va), fault, vftype);
510
511		/*
512		 * If this was a stack access we keep track of the maximum
513		 * accessed stack size.  Also, if uvm_fault gets a protection
514		 * failure it is due to accessing the stack region outside
515		 * the current limit and we need to reflect that as an access
516		 * error.
517		 */
518		if (space != HPPA_SID_KERNEL &&
519		    va < (vaddr_t)vm->vm_minsaddr) {
520			if (ret == 0)
521				uvm_grow(p, va);
522			else if (ret == EACCES)
523				ret = EFAULT;
524		}
525
526		if (type & T_USER)
527			KERNEL_PROC_UNLOCK(p);
528		else
529			KERNEL_UNLOCK();
530
531		if (ret != 0) {
532			if (type & T_USER) {
533				sv.sival_int = va;
534				KERNEL_PROC_LOCK(p);
535				trapsignal(p, SIGSEGV, vftype,
536				    ret == EACCES? SEGV_ACCERR : SEGV_MAPERR,
537				    sv);
538				KERNEL_PROC_UNLOCK(p);
539			} else {
540				if (p && p->p_addr->u_pcb.pcb_onfault) {
541					frame->tf_iioq_tail = 4 +
542					    (frame->tf_iioq_head =
543						p->p_addr->u_pcb.pcb_onfault);
544#ifdef DDB
545					frame->tf_iir = 0;
546#endif
547				} else {
548					panic("trap: "
549					    "uvm_fault(%p, %lx, %d, %d): %d",
550					    map, va, fault, vftype, ret);
551				}
552			}
553		}
554		break;
555
556	case T_DATALIGN | T_USER:
557datalign_user:
558		sv.sival_int = va;
559		KERNEL_PROC_LOCK(p);
560		trapsignal(p, SIGBUS, vftype, BUS_ADRALN, sv);
561		KERNEL_PROC_UNLOCK(p);
562		break;
563
564	case T_INTERRUPT:
565	case T_INTERRUPT | T_USER:
566		cpu_intr(frame);
567		break;
568
569	case T_CONDITION:
570		panic("trap: divide by zero in the kernel");
571		break;
572
573	case T_ILLEGAL:
574	case T_ILLEGAL | T_USER:
575		/* see if it's a SPOP1,,0 */
576		if ((opcode & 0xfffffe00) == 0x10000200) {
577			frame_regmap(frame, opcode & 0x1f) = 0;
578			frame->tf_ipsw |= PSL_N;
579			break;
580		}
581		if (type & T_USER) {
582			sv.sival_int = va;
583			KERNEL_PROC_LOCK(p);
584			trapsignal(p, SIGILL, type &~ T_USER, ILL_ILLOPC, sv);
585			KERNEL_PROC_UNLOCK(p);
586			break;
587		}
588		/* FALLTHROUGH */
589
590	/*
591	 * On PCXS processors, traps T_DATACC, T_DATAPID and T_DATALIGN
592	 * are shared.  We need to sort out the unaligned access situation
593	 * first, before handling this trap as T_DATACC.
594	 */
595	case T_DPROT:
596		if (cpu_type == hpcxs) {
597			if (pcxs_unaligned(opcode, va))
598				goto dead_end;
599			else
600				goto datacc;
601		}
602		/* FALLTHROUGH to unimplemented */
603
604	case T_LOWERPL:
605	case T_IPROT:
606	case T_OVERFLOW:
607	case T_HIGHERPL:
608	case T_TAKENBR:
609	case T_POWERFAIL:
610	case T_LPMC:
611	case T_PAGEREF:
612	case T_DATAPID:
613	case T_DATAPID | T_USER:
614		/* FALLTHROUGH to unimplemented */
615	default:
616#if 0
617if (kdb_trap (type, va, frame))
618	return;
619#endif
620		panic("trap: unimplemented \'%s\' (%d)", tts, trapnum);
621	}
622
623#ifdef DIAGNOSTIC
624	if (curcpu()->ci_cpl != oldcpl)
625		printf("WARNING: SPL (%d) NOT LOWERED ON "
626		    "TRAP (%d) EXIT\n", curcpu()->ci_cpl, trapnum);
627#endif
628
629	if (trapnum != T_INTERRUPT)
630		splx(curcpu()->ci_cpl);	/* process softints */
631
632	/*
633	 * in case we were interrupted from the syscall gate page
634	 * treat this as we were not really running user code no more
635	 * for weird things start to happen on return to the userland
636	 * and also see a note in locore.S:TLABEL(all)
637	 */
638	if ((type & T_USER) && !(frame->tf_iisq_head == HPPA_SID_KERNEL &&
639	    (frame->tf_iioq_head & ~PAGE_MASK) == SYSCALLGATE))
640		userret(p);
641}
642
643void
644child_return(void *arg)
645{
646	struct proc *p = (struct proc *)arg;
647	struct trapframe *tf = p->p_md.md_regs;
648
649	/*
650	 * Set up return value registers as libc:fork() expects
651	 */
652	tf->tf_ret0 = 0;
653	tf->tf_ret1 = 1;	/* ischild */
654	tf->tf_t1 = 0;		/* errno */
655
656	KERNEL_PROC_UNLOCK(p);
657
658	userret(p);
659#ifdef KTRACE
660	if (KTRPOINT(p, KTR_SYSRET)) {
661		KERNEL_PROC_LOCK(p);
662		ktrsysret(p,
663		    (p->p_flag & P_THREAD) ? SYS_rfork :
664		    (p->p_p->ps_flags & PS_PPWAIT) ? SYS_vfork : SYS_fork,
665		    0, 0);
666		KERNEL_PROC_UNLOCK(p);
667	}
668#endif
669}
670
671#ifdef PTRACE
672
673#include <sys/ptrace.h>
674
675int	ss_get_value(struct proc *p, vaddr_t addr, u_int *value);
676int	ss_put_value(struct proc *p, vaddr_t addr, u_int value);
677
678int
679ss_get_value(struct proc *p, vaddr_t addr, u_int *value)
680{
681	struct uio uio;
682	struct iovec iov;
683
684	iov.iov_base = (caddr_t)value;
685	iov.iov_len = sizeof(u_int);
686	uio.uio_iov = &iov;
687	uio.uio_iovcnt = 1;
688	uio.uio_offset = (off_t)addr;
689	uio.uio_resid = sizeof(u_int);
690	uio.uio_segflg = UIO_SYSSPACE;
691	uio.uio_rw = UIO_READ;
692	uio.uio_procp = curproc;
693	return (process_domem(curproc, p, &uio, PT_READ_I));
694}
695
696int
697ss_put_value(struct proc *p, vaddr_t addr, u_int value)
698{
699	struct uio uio;
700	struct iovec iov;
701
702	iov.iov_base = (caddr_t)&value;
703	iov.iov_len = sizeof(u_int);
704	uio.uio_iov = &iov;
705	uio.uio_iovcnt = 1;
706	uio.uio_offset = (off_t)addr;
707	uio.uio_resid = sizeof(u_int);
708	uio.uio_segflg = UIO_SYSSPACE;
709	uio.uio_rw = UIO_WRITE;
710	uio.uio_procp = curproc;
711	return (process_domem(curproc, p, &uio, PT_WRITE_I));
712}
713
714void
715ss_clear_breakpoints(struct proc *p)
716{
717	/* Restore origional instructions. */
718	if (p->p_md.md_bpva != 0) {
719		ss_put_value(p, p->p_md.md_bpva, p->p_md.md_bpsave[0]);
720		ss_put_value(p, p->p_md.md_bpva + 4, p->p_md.md_bpsave[1]);
721		p->p_md.md_bpva = 0;
722	}
723}
724
725int
726process_sstep(struct proc *p, int sstep)
727{
728	int error;
729
730	ss_clear_breakpoints(p);
731
732	if (sstep == 0) {
733		p->p_md.md_regs->tf_ipsw &= ~PSL_T;
734		return (0);
735	}
736
737	/*
738	 * Don't touch the syscall gateway page.  Instead, insert a
739	 * breakpoint where we're supposed to return.
740	 */
741	if ((p->p_md.md_regs->tf_iioq_tail & ~PAGE_MASK) == SYSCALLGATE)
742		p->p_md.md_bpva = p->p_md.md_regs->tf_r31 & ~HPPA_PC_PRIV_MASK;
743	else
744		p->p_md.md_bpva = p->p_md.md_regs->tf_iioq_tail & ~HPPA_PC_PRIV_MASK;
745
746	/*
747	 * Insert two breakpoint instructions; the first one might be
748	 * nullified.  Of course we need to save two instruction
749	 * first.
750	 */
751
752	error = ss_get_value(p, p->p_md.md_bpva, &p->p_md.md_bpsave[0]);
753	if (error)
754		return (error);
755	error = ss_get_value(p, p->p_md.md_bpva + 4, &p->p_md.md_bpsave[1]);
756	if (error)
757		return (error);
758
759	error = ss_put_value(p, p->p_md.md_bpva, SSBREAKPOINT);
760	if (error)
761		return (error);
762	error = ss_put_value(p, p->p_md.md_bpva + 4, SSBREAKPOINT);
763	if (error)
764		return (error);
765
766	if ((p->p_md.md_regs->tf_iioq_tail & ~PAGE_MASK) != SYSCALLGATE)
767		p->p_md.md_regs->tf_ipsw |= PSL_T;
768	else
769		p->p_md.md_regs->tf_ipsw &= ~PSL_T;
770
771	return (0);
772}
773
774#endif	/* PTRACE */
775
776void	syscall(struct trapframe *frame);
777
778/*
779 * call actual syscall routine
780 */
781void
782syscall(struct trapframe *frame)
783{
784	register struct proc *p = curproc;
785	register const struct sysent *callp;
786	int retq, nsys, code, argsize, argoff, oerror, error;
787	register_t args[8], rval[2];
788#ifdef DIAGNOSTIC
789	int oldcpl = curcpu()->ci_cpl;
790#endif
791
792	uvmexp.syscalls++;
793
794	if (!USERMODE(frame->tf_iioq_head))
795		panic("syscall");
796
797	p->p_md.md_regs = frame;
798	nsys = p->p_emul->e_nsysent;
799	callp = p->p_emul->e_sysent;
800
801	argoff = 4; retq = 0;
802	switch (code = frame->tf_t1) {
803	case SYS_syscall:
804		code = frame->tf_arg0;
805		args[0] = frame->tf_arg1;
806		args[1] = frame->tf_arg2;
807		args[2] = frame->tf_arg3;
808		argoff = 3;
809		break;
810	case SYS___syscall:
811		if (callp != sysent)
812			break;
813		/*
814		 * this works, because quads get magically swapped
815		 * due to the args being laid backwards on the stack
816		 * and then copied in words
817		 */
818		code = frame->tf_arg0;
819		args[0] = frame->tf_arg2;
820		args[1] = frame->tf_arg3;
821		argoff = 2;
822		retq = 1;
823		break;
824	default:
825		args[0] = frame->tf_arg0;
826		args[1] = frame->tf_arg1;
827		args[2] = frame->tf_arg2;
828		args[3] = frame->tf_arg3;
829		break;
830	}
831
832	if (code < 0 || code >= nsys)
833		callp += p->p_emul->e_nosys;	/* bad syscall # */
834	else
835		callp += code;
836
837	oerror = error = 0;
838	if ((argsize = callp->sy_argsize)) {
839		int i;
840
841		for (i = 0, argsize -= argoff * 4;
842		    argsize > 0; i++, argsize -= 4) {
843			error = copyin((void *)(frame->tf_sp +
844			    HPPA_FRAME_ARG(i + 4)), args + i + argoff, 4);
845
846			if (error)
847				break;
848		}
849
850		/*
851		 * coming from syscall() or __syscall we must be
852		 * having one of those w/ a 64 bit arguments,
853		 * which needs a word swap due to the order
854		 * of the arguments on the stack.
855		 * this assumes that none of 'em are called
856		 * by their normal syscall number, maybe a regress
857		 * test should be used, to watch the behaviour.
858		 */
859		if (!error && argoff < 4) {
860			int t;
861
862			i = 0;
863			switch (code) {
864			case SYS_lseek:		retq = 0;
865			case SYS_truncate:
866			case SYS_ftruncate:	i = 2;	break;
867			case SYS_preadv:
868			case SYS_pwritev:
869			case SYS_pread:
870			case SYS_pwrite:	i = 4;	break;
871			case SYS_mquery:
872			case SYS_mmap:		i = 6;	break;
873			}
874
875			if (i) {
876				t = args[i];
877				args[i] = args[i + 1];
878				args[i + 1] = t;
879			}
880		}
881	}
882
883#ifdef SYSCALL_DEBUG
884	KERNEL_PROC_LOCK(p);
885	scdebug_call(p, code, args);
886	KERNEL_PROC_UNLOCK(p);
887#endif
888#ifdef KTRACE
889	if (KTRPOINT(p, KTR_SYSCALL)) {
890		KERNEL_PROC_LOCK(p);
891		ktrsyscall(p, code, callp->sy_argsize, args);
892		KERNEL_PROC_UNLOCK(p);
893	}
894#endif
895	if (error)
896		goto bad;
897
898	rval[0] = 0;
899	rval[1] = frame->tf_ret1;
900#if NSYSTRACE > 0
901	if (ISSET(p->p_flag, P_SYSTRACE)) {
902		KERNEL_PROC_LOCK(p);
903		oerror = error = systrace_redirect(code, p, args, rval);
904		KERNEL_PROC_UNLOCK(p);
905	} else
906#endif
907	{
908		int nolock = (callp->sy_flags & SY_NOLOCK);
909		if (!nolock)
910			KERNEL_PROC_LOCK(p);
911		oerror = error = (*callp->sy_call)(p, args, rval);
912		if (!nolock)
913			KERNEL_PROC_UNLOCK(p);
914
915	}
916	switch (error) {
917	case 0:
918		frame->tf_ret0 = rval[0];
919		frame->tf_ret1 = rval[!retq];
920		frame->tf_t1 = 0;
921		break;
922	case ERESTART:
923		frame->tf_iioq_head -= 12;
924		frame->tf_iioq_tail -= 12;
925	case EJUSTRETURN:
926		break;
927	default:
928	bad:
929		if (p->p_emul->e_errno)
930			error = p->p_emul->e_errno[error];
931		frame->tf_t1 = error;
932		frame->tf_ret0 = error;
933		frame->tf_ret1 = 0;
934		break;
935	}
936#ifdef SYSCALL_DEBUG
937	KERNEL_PROC_LOCK(p);
938	scdebug_ret(p, code, oerror, rval);
939	KERNEL_PROC_UNLOCK(p);
940#endif
941	userret(p);
942#ifdef KTRACE
943	if (KTRPOINT(p, KTR_SYSRET)) {
944		KERNEL_PROC_LOCK(p);
945		ktrsysret(p, code, oerror, rval[0]);
946		KERNEL_PROC_UNLOCK(p);
947	}
948#endif
949#ifdef DIAGNOSTIC
950	if (curcpu()->ci_cpl != oldcpl) {
951		printf("WARNING: SPL (0x%x) NOT LOWERED ON "
952		    "syscall(0x%x, 0x%x, 0x%x, 0x%x...) EXIT, PID %d\n",
953		    curcpu()->ci_cpl, code, args[0], args[1], args[2],
954		    p->p_pid);
955		curcpu()->ci_cpl = oldcpl;
956	}
957#endif
958	splx(curcpu()->ci_cpl);	/* process softints */
959}
960
961/*
962 * Decide if opcode `opcode' accessing virtual address `va' caused an
963 * unaligned trap. Returns zero if the access is correctly aligned.
964 * Used on PCXS processors to sort out exception causes.
965 */
966int
967pcxs_unaligned(u_int opcode, vaddr_t va)
968{
969	u_int mbz_bits;
970
971	/*
972	 * Exit early if the va is obviously aligned enough.
973	 */
974	if ((va & 0x0f) == 0)
975		return 0;
976
977	mbz_bits = 0;
978
979	/*
980	 * Only load and store instructions can cause unaligned access.
981	 * There are three opcode patterns to look for:
982	 * - canonical load/store
983	 * - load/store short or indexed
984	 * - coprocessor load/store
985	 */
986
987	if ((opcode & 0xd0000000) == 0x40000000) {
988		switch ((opcode >> 26) & 0x03) {
989		case 0x00:	/* ldb, stb */
990			mbz_bits = 0x00;
991			break;
992		case 0x01:	/* ldh, sth */
993			mbz_bits = 0x01;
994			break;
995		case 0x02:	/* ldw, stw */
996		case 0x03:	/* ldwm, stwm */
997			mbz_bits = 0x03;
998			break;
999		}
1000	} else
1001
1002	if ((opcode & 0xfc000000) == 0x0c000000) {
1003		switch ((opcode >> 6) & 0x0f) {
1004		case 0x01:	/* ldhx, ldhs */
1005			mbz_bits = 0x01;
1006			break;
1007		case 0x02:	/* ldwx, ldws */
1008			mbz_bits = 0x03;
1009			break;
1010		case 0x07:	/* ldcwx, ldcws */
1011			mbz_bits = 0x0f;
1012			break;
1013		case 0x09:
1014			if ((opcode & (1 << 12)) != 0)	/* sths */
1015				mbz_bits = 0x01;
1016			break;
1017		case 0x0a:
1018			if ((opcode & (1 << 12)) != 0)	/* stws */
1019				mbz_bits = 0x03;
1020			break;
1021		}
1022	} else
1023
1024	if ((opcode & 0xf4000000) == 0x24000000) {
1025		if ((opcode & (1 << 27)) != 0) {
1026			/* cldwx, cstwx, cldws, cstws */
1027			mbz_bits = 0x03;
1028		} else {
1029			/* clddx, cstdx, cldds, cstds */
1030			mbz_bits = 0x07;
1031		}
1032	}
1033
1034	return (va & mbz_bits);
1035}
1036