xref: /openbsd/sys/arch/sh/sh/trap.c (revision 4bdc3057)
1 /*	$OpenBSD: trap.c,v 1.42 2020/09/22 15:50:20 deraadt Exp $	*/
2 /*	$NetBSD: exception.c,v 1.32 2006/09/04 23:57:52 uwe Exp $	*/
3 /*	$NetBSD: syscall.c,v 1.6 2006/03/07 07:21:50 thorpej Exp $	*/
4 
5 /*-
6  * Copyright (c) 2002 The NetBSD Foundation, Inc. All rights reserved.
7  * Copyright (c) 1990 The Regents of the University of California.
8  * All rights reserved.
9  *
10  * This code is derived from software contributed to Berkeley by
11  * the University of Utah, and William Jolitz.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  * 3. Neither the name of the University nor the names of its contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  *
37  *	@(#)trap.c	7.4 (Berkeley) 5/13/91
38  */
39 
40 /*-
41  * Copyright (c) 1995 Charles M. Hannum.  All rights reserved.
42  *
43  * This code is derived from software contributed to Berkeley by
44  * the University of Utah, and William Jolitz.
45  *
46  * Redistribution and use in source and binary forms, with or without
47  * modification, are permitted provided that the following conditions
48  * are met:
49  * 1. Redistributions of source code must retain the above copyright
50  *    notice, this list of conditions and the following disclaimer.
51  * 2. Redistributions in binary form must reproduce the above copyright
52  *    notice, this list of conditions and the following disclaimer in the
53  *    documentation and/or other materials provided with the distribution.
54  * 3. All advertising materials mentioning features or use of this software
55  *    must display the following acknowledgement:
56  *	This product includes software developed by the University of
57  *	California, Berkeley and its contributors.
58  * 4. Neither the name of the University nor the names of its contributors
59  *    may be used to endorse or promote products derived from this software
60  *    without specific prior written permission.
61  *
62  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
63  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
64  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
65  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
66  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
67  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
68  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
69  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
70  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
71  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
72  * SUCH DAMAGE.
73  *
74  *	@(#)trap.c	7.4 (Berkeley) 5/13/91
75  */
76 
77 /*
78  * SH3 Trap and System call handling
79  *
80  * T.Horiuchi 1998.06.8
81  */
82 
83 #include <sys/param.h>
84 #include <sys/systm.h>
85 #include <sys/proc.h>
86 #include <sys/pool.h>
87 #include <sys/kernel.h>
88 #include <sys/signal.h>
89 #include <sys/resourcevar.h>
90 #include <sys/signalvar.h>
91 #include <uvm/uvm_extern.h>
92 #include <sys/syscall.h>
93 #include <sys/syscall_mi.h>
94 
95 #include <sh/cache.h>
96 #include <sh/cpu.h>
97 #include <sh/mmu.h>
98 #include <sh/pcb.h>
99 #include <sh/trap.h>
100 #ifdef SH4
101 #include <sh/fpu.h>
102 #endif
103 
104 #ifdef DDB
105 #include <machine/db_machdep.h>
106 #endif
107 
108 const char * const exp_type[] = {
109 	NULL,					/* 000 (reset vector) */
110 	NULL,					/* 020 (reset vector) */
111 	"TLB miss/invalid (load)",		/* 040 EXPEVT_TLB_MISS_LD */
112 	"TLB miss/invalid (store)",		/* 060 EXPEVT_TLB_MISS_ST */
113 	"initial page write",			/* 080 EXPEVT_TLB_MOD */
114 	"TLB protection violation (load)",	/* 0a0 EXPEVT_TLB_PROT_LD */
115 	"TLB protection violation (store)",	/* 0c0 EXPEVT_TLB_PROT_ST */
116 	"address error (load)",			/* 0e0 EXPEVT_ADDR_ERR_LD */
117 	"address error (store)",		/* 100 EXPEVT_ADDR_ERR_ST */
118 	"FPU",					/* 120 EXPEVT_FPU */
119 	NULL,					/* 140 (reset vector) */
120 	"unconditional trap (TRAPA)",		/* 160 EXPEVT_TRAPA */
121 	"reserved instruction code exception",	/* 180 EXPEVT_RES_INST */
122 	"illegal slot instruction exception",	/* 1a0 EXPEVT_SLOT_INST */
123 	NULL,					/* 1c0 (external interrupt) */
124 	"user break point trap",		/* 1e0 EXPEVT_BREAK */
125 	NULL, NULL, NULL, NULL,			/* 200-260 */
126 	NULL, NULL, NULL, NULL,			/* 280-2e0 */
127 	NULL, NULL, NULL, NULL,			/* 300-360 */
128 	NULL, NULL, NULL, NULL,			/* 380-3e0 */
129 	NULL, NULL, NULL, NULL,			/* 400-460 */
130 	NULL, NULL, NULL, NULL,			/* 480-4e0 */
131 	NULL, NULL, NULL, NULL,			/* 500-560 */
132 	NULL, NULL, NULL, NULL,			/* 580-5e0 */
133 	NULL, NULL, NULL, NULL,			/* 600-660 */
134 	NULL, NULL, NULL, NULL,			/* 680-6e0 */
135 	NULL, NULL, NULL, NULL,			/* 700-760 */
136 	NULL, NULL, NULL, NULL,			/* 780-7e0 */
137 	"FPU disabled",				/* 800 EXPEVT_FPU_DISABLE */
138 	"slot FPU disabled"			/* 820 EXPEVT_FPU_SLOT_DISABLE */
139 };
140 const int exp_types = sizeof exp_type / sizeof exp_type[0];
141 
142 void general_exception(struct proc *, struct trapframe *, uint32_t);
143 void tlb_exception(struct proc *, struct trapframe *, uint32_t);
144 void ast(struct proc *, struct trapframe *);
145 void syscall(struct proc *, struct trapframe *);
146 void cachectl(struct proc *, struct trapframe *);
147 
148 /*
149  * void general_exception(struct proc *p, struct trapframe *tf):
150  *	p  ... curproc when exception occured.
151  *	tf ... full user context.
152  *	va ... fault va for user mode EXPEVT_ADDR_ERR_{LD,ST}
153  */
154 void
155 general_exception(struct proc *p, struct trapframe *tf, uint32_t va)
156 {
157 	int expevt = tf->tf_expevt;
158 	int tra = _reg_read_4(SH_(TRA));
159 	int usermode = !KERNELMODE(tf->tf_ssr);
160 	union sigval sv;
161 
162 	uvmexp.traps++;
163 
164 	/*
165 	 * This function is entered at splhigh. Restore the interrupt
166 	 * level to what it was when the trap occured.
167 	 */
168 	splx(tf->tf_ssr & PSL_IMASK);
169 
170 	if (usermode) {
171 		if (p == NULL)
172 			goto do_panic;
173 		KDASSERT(p->p_md.md_regs == tf); /* check exception depth */
174 		expevt |= EXP_USER;
175 		refreshcreds(p);
176 		if (tra != _SH_TRA_SYSCALL << 2) {
177 			if (!uvm_map_inentry(p, &p->p_spinentry, PROC_STACK(p),
178 			    "[%s]%d/%d sp=%lx inside %lx-%lx: not MAP_STACK\n",
179 			    uvm_map_inentry_sp, p->p_vmspace->vm_map.sserial))
180 				goto out;
181 		}
182 	}
183 
184 	switch (expevt) {
185 	case EXPEVT_BREAK:
186 #ifdef DDB
187 		if (db_ktrap(EXPEVT_BREAK, 0, tf))
188 			return;
189 		else
190 #endif
191 			goto do_panic;
192 		break;
193 	case EXPEVT_TRAPA:
194 #ifdef DDB
195 		/* Check for ddb request */
196 		if (tra == (_SH_TRA_BREAK << 2) &&
197 		    db_ktrap(expevt, tra, tf))
198 			return;
199 		else
200 #endif
201 			goto do_panic;
202 		break;
203 	case EXPEVT_TRAPA | EXP_USER:
204 		/* Check for debugger break */
205 		switch (tra) {
206 		case _SH_TRA_BREAK << 2:
207 			tf->tf_spc -= 2; /* back to the breakpoint address */
208 			sv.sival_ptr = (void *)tf->tf_spc;
209 			trapsignal(p, SIGTRAP, expevt & ~EXP_USER, TRAP_BRKPT,
210 			    sv);
211 			goto out;
212 		case _SH_TRA_SYSCALL << 2:
213 			syscall(p, tf);
214 			return;
215 		case _SH_TRA_CACHECTL << 2:
216 			cachectl(p, tf);
217 			return;
218 		default:
219 			sv.sival_ptr = (void *)tf->tf_spc;
220 			trapsignal(p, SIGILL, expevt & ~EXP_USER, ILL_ILLTRP,
221 			    sv);
222 			goto out;
223 		}
224 		break;
225 
226 	case EXPEVT_ADDR_ERR_LD: /* FALLTHROUGH */
227 	case EXPEVT_ADDR_ERR_ST:
228 		KDASSERT(p && p->p_md.md_pcb->pcb_onfault != NULL);
229 		if (p == NULL || p->p_md.md_pcb->pcb_onfault == 0)
230 			goto do_panic;
231 		tf->tf_spc = (int)p->p_md.md_pcb->pcb_onfault;
232 		break;
233 
234 	case EXPEVT_ADDR_ERR_LD | EXP_USER: /* FALLTHROUGH */
235 	case EXPEVT_ADDR_ERR_ST | EXP_USER:
236 		sv.sival_ptr = (void *)va;
237 		if (((int)va) < 0)
238 			trapsignal(p, SIGSEGV, expevt & ~EXP_USER, SEGV_ACCERR,
239 			    sv);
240 		else
241 			trapsignal(p, SIGBUS, expevt & ~EXP_USER, BUS_ADRALN,
242 			    sv);
243 		goto out;
244 
245 	case EXPEVT_RES_INST | EXP_USER: /* FALLTHROUGH */
246 	case EXPEVT_SLOT_INST | EXP_USER:
247 		sv.sival_ptr = (void *)tf->tf_spc;
248 		trapsignal(p, SIGILL, expevt & ~EXP_USER, ILL_ILLOPC, sv);
249 		goto out;
250 
251 	case EXPEVT_BREAK | EXP_USER:
252 		sv.sival_ptr = (void *)tf->tf_spc;
253 		trapsignal(p, SIGTRAP, expevt & ~EXP_USER, TRAP_TRACE, sv);
254 		goto out;
255 
256 #ifdef SH4
257 	case EXPEVT_FPU_DISABLE | EXP_USER: /* FALLTHROUGH */
258 	case EXPEVT_FPU_SLOT_DISABLE | EXP_USER:
259 		sv.sival_ptr = (void *)tf->tf_spc;
260 		trapsignal(p, SIGILL, expevt & ~EXP_USER, ILL_COPROC, sv);
261 		goto out;
262 
263 	case EXPEVT_FPU | EXP_USER:
264 	    {
265 		int fpscr, sigi;
266 
267 		/* XXX worth putting in the trapframe? */
268 		__asm__ volatile ("sts fpscr, %0" : "=r" (fpscr));
269 		fpscr = (fpscr & FPSCR_CAUSE_MASK) >> FPSCR_CAUSE_SHIFT;
270 		if (fpscr & FPEXC_E)
271 			sigi = FPE_FLTINV;	/* XXX any better value? */
272 		else if (fpscr & FPEXC_V)
273 			sigi = FPE_FLTINV;
274 		else if (fpscr & FPEXC_Z)
275 			sigi = FPE_FLTDIV;
276 		else if (fpscr & FPEXC_O)
277 			sigi = FPE_FLTOVF;
278 		else if (fpscr & FPEXC_U)
279 			sigi = FPE_FLTUND;
280 		else if (fpscr & FPEXC_I)
281 			sigi = FPE_FLTRES;
282 		else
283 			sigi = 0;	/* shouldn't happen */
284 		sv.sival_ptr = (void *)tf->tf_spc;
285 		trapsignal(p, SIGFPE, expevt & ~EXP_USER, sigi, sv);
286 	    }
287 		goto out;
288 #endif
289 
290 	default:
291 		goto do_panic;
292 	}
293 
294 	if (!usermode)
295 		return;
296 out:
297 	userret(p);
298 	return;
299 
300 do_panic:
301 	if ((expevt >> 5) < exp_types && exp_type[expevt >> 5] != NULL)
302 		printf("fatal %s", exp_type[expevt >> 5]);
303 	else
304 		printf("EXPEVT 0x%03x", expevt);
305 	printf(" in %s mode\n", expevt & EXP_USER ? "user" : "kernel");
306 	printf("va 0x%x spc 0x%x ssr 0x%x pr 0x%x \n",
307 	    va, tf->tf_spc, tf->tf_ssr, tf->tf_pr);
308 
309 	panic("general_exception");
310 	/* NOTREACHED */
311 }
312 
313 
314 /*
315  * void tlb_exception(struct proc *p, struct trapframe *tf, uint32_t va):
316  *	p  ... curproc when exception occured.
317  *	tf ... full user context.
318  *	va ... fault address.
319  */
320 void
321 tlb_exception(struct proc *p, struct trapframe *tf, uint32_t va)
322 {
323 	struct vm_map *map;
324 	pmap_t pmap;
325 	union sigval sv;
326 	int usermode;
327 	int err, track, ftype;
328 	const char *panic_msg;
329 
330 #define TLB_ASSERT(assert, msg)				\
331 		do {					\
332 			if (!(assert)) {		\
333 				panic_msg =  msg;	\
334 				goto tlb_panic;		\
335 			}				\
336 		} while(/*CONSTCOND*/0)
337 
338 	/*
339 	 * This function is entered at splhigh. Restore the interrupt
340 	 * level to what it was when the trap occured.
341 	 */
342 	splx(tf->tf_ssr & PSL_IMASK);
343 
344 	usermode = !KERNELMODE(tf->tf_ssr);
345 	if (usermode) {
346 		KDASSERT(p->p_md.md_regs == tf);
347 		refreshcreds(p);
348 	} else {
349 		KDASSERT(p == NULL ||		/* idle */
350 		    p == &proc0 ||		/* kthread */
351 		    p->p_md.md_regs != tf);	/* other */
352 	}
353 
354 	switch (tf->tf_expevt) {
355 	case EXPEVT_TLB_MISS_LD:
356 		track = PVH_REFERENCED;
357 		ftype = PROT_READ;
358 		break;
359 	case EXPEVT_TLB_MISS_ST:
360 		track = PVH_REFERENCED;
361 		ftype = PROT_WRITE;
362 		break;
363 	case EXPEVT_TLB_MOD:
364 		track = PVH_REFERENCED | PVH_MODIFIED;
365 		ftype = PROT_WRITE;
366 		break;
367 	case EXPEVT_TLB_PROT_LD:
368 		TLB_ASSERT((int)va > 0,
369 		    "kernel virtual protection fault (load)");
370 		if (usermode) {
371 			sv.sival_ptr = (void *)va;
372 			trapsignal(p, SIGSEGV, tf->tf_expevt, SEGV_ACCERR, sv);
373 			goto user_fault;
374 		} else {
375 			TLB_ASSERT(p->p_md.md_pcb->pcb_onfault != NULL,
376 			    "no copyin/out fault handler (load protection)");
377 			tf->tf_spc = (int)p->p_md.md_pcb->pcb_onfault;
378 		}
379 		return;
380 
381 	case EXPEVT_TLB_PROT_ST:
382 		track = 0;	/* call uvm_fault first. (COW) */
383 		ftype = PROT_WRITE;
384 		break;
385 
386 	default:
387 		TLB_ASSERT(0, "impossible expevt");
388 	}
389 
390 	/* Select address space */
391 	if (usermode) {
392 		TLB_ASSERT(p != NULL, "no curproc");
393 		map = &p->p_vmspace->vm_map;
394 		pmap = map->pmap;
395 	} else {
396 		if ((int)va < 0) {
397 			map = kernel_map;
398 			pmap = pmap_kernel();
399 		} else {
400 			TLB_ASSERT(p != NULL &&
401 			    p->p_md.md_pcb->pcb_onfault != NULL,
402 			    "invalid user-space access from kernel mode");
403 			if (va == 0) {
404 				tf->tf_spc = (int)p->p_md.md_pcb->pcb_onfault;
405 				return;
406 			}
407 			map = &p->p_vmspace->vm_map;
408 			pmap = map->pmap;
409 		}
410 	}
411 
412 	/* Lookup page table. if entry found, load it. */
413 	if (track && __pmap_pte_load(pmap, va, track)) {
414 		if (usermode)
415 			userret(p);
416 		return;
417 	}
418 
419 	err = uvm_fault(map, va, 0, ftype);
420 
421 	/* User stack extension */
422 	if (map != kernel_map &&
423 	    va >= (vaddr_t)p->p_vmspace->vm_maxsaddr) {
424 		if (err == 0)
425 			uvm_grow(p, va);
426 		else if (err == EACCES)
427 			err = EFAULT;
428 	}
429 
430 	/* Page in. load PTE to TLB. */
431 	if (err == 0) {
432 		int loaded = __pmap_pte_load(pmap, va, track);
433 		TLB_ASSERT(loaded, "page table entry not found");
434 		if (usermode)
435 			userret(p);
436 		return;
437 	}
438 
439 	/* Page not found. */
440 	if (usermode) {
441 		sv.sival_ptr = (void *)va;
442 		if (err == ENOMEM) {
443 			printf("UVM: pid %d (%s), uid %d killed: out of swap\n",
444 			    p->p_p->ps_pid, p->p_p->ps_comm,
445 			    p->p_ucred ? (int)p->p_ucred->cr_uid : -1);
446 			trapsignal(p, SIGKILL, tf->tf_expevt, SEGV_MAPERR, sv);
447 		} else
448 			trapsignal(p, SIGSEGV, tf->tf_expevt, SEGV_MAPERR, sv);
449 		goto user_fault;
450 	} else {
451 		TLB_ASSERT(p->p_md.md_pcb->pcb_onfault,
452 		    "no copyin/out fault handler (page not found)");
453 		tf->tf_spc = (int)p->p_md.md_pcb->pcb_onfault;
454 	}
455 	return;
456 
457 user_fault:
458 	userret(p);
459 	ast(p, tf);
460 	return;
461 
462 tlb_panic:
463 	panic("tlb_exception: %s\n"
464 	      "expevt=%x va=%08x ssr=%08x spc=%08x proc=%p onfault=%p",
465 	      panic_msg, tf->tf_expevt, va, tf->tf_ssr, tf->tf_spc,
466 	      p, p ? p->p_md.md_pcb->pcb_onfault : NULL);
467 #undef	TLB_ASSERT
468 }
469 
470 
471 /*
472  * void ast(struct proc *p, struct trapframe *tf):
473  *	p  ... curproc when exception occured.
474  *	tf ... full user context.
475  *	This is called upon exception return. if return from kernel to user,
476  *	handle asynchronous software traps and context switch if needed.
477  */
478 void
479 ast(struct proc *p, struct trapframe *tf)
480 {
481 	if (KERNELMODE(tf->tf_ssr))
482 		return;
483 	KDASSERT(p != NULL);
484 	KDASSERT(p->p_md.md_regs == tf);
485 
486 	while (p->p_md.md_astpending) {
487 		p->p_md.md_astpending = 0;
488 		refreshcreds(p);
489 		uvmexp.softs++;
490 		mi_ast(p, want_resched);
491 		userret(p);
492 	}
493 }
494 
495 void
496 cachectl(struct proc *p, struct trapframe *tf)
497 {
498 	vaddr_t va;
499 	vsize_t len;
500 
501 	if (!SH_HAS_UNIFIED_CACHE) {
502 		va = (vaddr_t)tf->tf_r4;
503 		len = (vsize_t)tf->tf_r5;
504 
505 		if (va < VM_MIN_ADDRESS || va >= VM_MAXUSER_ADDRESS ||
506 		    va + len <= va || va + len >= VM_MAXUSER_ADDRESS)
507 			len = 0;
508 
509 		if (len != 0)
510 			sh_icache_sync_range_index(va, len);
511 	}
512 
513 	userret(p);
514 }
515 
516 void
517 syscall(struct proc *p, struct trapframe *tf)
518 {
519 	caddr_t params;
520 	const struct sysent *callp;
521 	int error, opc, nsys;
522 	size_t argsize;
523 	register_t code, args[8], rval[2], ocode;
524 
525 	uvmexp.syscalls++;
526 
527 	opc = tf->tf_spc;
528 	ocode = code = tf->tf_r0;
529 
530 	nsys = p->p_p->ps_emul->e_nsysent;
531 	callp = p->p_p->ps_emul->e_sysent;
532 
533 	params = (caddr_t)tf->tf_r15;
534 
535 	switch (code) {
536 	case SYS_syscall:
537 		/*
538 		 * Code is first argument, followed by actual args.
539 		 */
540 	        code = tf->tf_r4;
541 		break;
542 	case SYS___syscall:
543 		/*
544 		 * Like syscall, but code is a quad, so as to maintain
545 		 * quad alignment for the rest of the arguments.
546 		 */
547 		if (callp != sysent)
548 			break;
549 #if _BYTE_ORDER == BIG_ENDIAN
550 		code = tf->tf_r5;
551 #else
552 		code = tf->tf_r4;
553 #endif
554 		break;
555 	default:
556 		break;
557 	}
558 	if (code < 0 || code >= nsys)
559 		callp += p->p_p->ps_emul->e_nosys;		/* illegal */
560 	else
561 		callp += code;
562 	argsize = callp->sy_argsize;
563 #ifdef DIAGNOSTIC
564 	if (argsize > sizeof args) {
565 		callp += p->p_p->ps_emul->e_nosys - code;
566 		argsize = callp->sy_argsize;
567 	}
568 #endif
569 
570 	switch (ocode) {
571 	case SYS_syscall:
572 		if (argsize) {
573 			args[0] = tf->tf_r5;
574 			args[1] = tf->tf_r6;
575 			args[2] = tf->tf_r7;
576 			if (argsize > 3 * sizeof(int)) {
577 				argsize -= 3 * sizeof(int);
578 				if ((error = copyin(params, &args[3],
579 				    argsize)))
580 					goto bad;
581 			}
582 		}
583 		break;
584 	case SYS___syscall:
585 		if (argsize) {
586 			args[0] = tf->tf_r6;
587 			args[1] = tf->tf_r7;
588 			if (argsize > 2 * sizeof(int)) {
589 				argsize -= 2 * sizeof(int);
590 				if ((error = copyin(params, &args[2],
591 				    argsize)))
592 					goto bad;
593 			}
594 		}
595 		break;
596 	default:
597 		if (argsize) {
598 			args[0] = tf->tf_r4;
599 			args[1] = tf->tf_r5;
600 			args[2] = tf->tf_r6;
601 			args[3] = tf->tf_r7;
602 			if (argsize > 4 * sizeof(int)) {
603 				argsize -= 4 * sizeof(int);
604 				if ((error = copyin(params, &args[4],
605 				    argsize)))
606 					goto bad;
607 			}
608 		}
609 		break;
610 	}
611 
612 	rval[0] = 0;
613 	rval[1] = tf->tf_r1;
614 
615 	error = mi_syscall(p, code, callp, args, rval);
616 
617 	switch (error) {
618 	case 0:
619 		tf->tf_r0 = rval[0];
620 		tf->tf_r1 = rval[1];
621 		tf->tf_ssr |= PSL_TBIT;	/* T bit */
622 		break;
623 	case ERESTART:
624 		/* 2 = TRAPA instruction size */
625 		tf->tf_spc = opc - 2;
626 		break;
627 	case EJUSTRETURN:
628 		/* nothing to do */
629 		break;
630 	default:
631 	bad:
632 		tf->tf_r0 = error;
633 		tf->tf_ssr &= ~PSL_TBIT;	/* T bit */
634 		break;
635 	}
636 
637 	mi_syscall_return(p, code, error, rval);
638 }
639 
640 /*
641  * void child_return(void *arg):
642  *
643  *	uvm_fork sets this routine to proc_trampoline's service function.
644  *	when returning from here, jump to userland.
645  */
646 void
647 child_return(void *arg)
648 {
649 	struct proc *p = arg;
650 	struct trapframe *tf = p->p_md.md_regs;
651 
652 	tf->tf_r0 = 0;
653 	tf->tf_ssr |= PSL_TBIT; /* This indicates no error. */
654 
655 	mi_child_return(p);
656 }
657 
658