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