trap.c revision 1.11
1/*	$NetBSD: trap.c,v 1.11 2003/02/02 20:43:23 matt Exp $	*/
2
3/*
4 * Copyright 2001 Wasabi Systems, Inc.
5 * All rights reserved.
6 *
7 * Written by Eduardo Horvath and Simon Burge for Wasabi Systems, Inc.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 *    must display the following acknowledgement:
19 *      This product includes software developed for the NetBSD Project by
20 *      Wasabi Systems, Inc.
21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22 *    or promote products derived from this software without specific prior
23 *    written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 */
37
38/*
39 * Copyright (C) 1995, 1996 Wolfgang Solfrank.
40 * Copyright (C) 1995, 1996 TooLs GmbH.
41 * All rights reserved.
42 *
43 * Redistribution and use in source and binary forms, with or without
44 * modification, are permitted provided that the following conditions
45 * are met:
46 * 1. Redistributions of source code must retain the above copyright
47 *    notice, this list of conditions and the following disclaimer.
48 * 2. Redistributions in binary form must reproduce the above copyright
49 *    notice, this list of conditions and the following disclaimer in the
50 *    documentation and/or other materials provided with the distribution.
51 * 3. All advertising materials mentioning features or use of this software
52 *    must display the following acknowledgement:
53 *	This product includes software developed by TooLs GmbH.
54 * 4. The name of TooLs GmbH may not be used to endorse or promote products
55 *    derived from this software without specific prior written permission.
56 *
57 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
58 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
59 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
60 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
61 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
62 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
63 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
64 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
65 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
66 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
67 */
68
69#include "opt_altivec.h"
70#include "opt_ddb.h"
71#include "opt_ktrace.h"
72#include "opt_systrace.h"
73#include "opt_syscall_debug.h"
74
75#include <sys/param.h>
76#include <sys/proc.h>
77#include <sys/reboot.h>
78#include <sys/syscall.h>
79#include <sys/systm.h>
80#include <sys/user.h>
81#ifdef KTRACE
82#include <sys/ktrace.h>
83#endif
84#include <sys/pool.h>
85#include <sys/sa.h>
86#include <sys/savar.h>
87#ifdef SYSTRACE
88#include <sys/systrace.h>
89#endif
90
91#include <uvm/uvm_extern.h>
92
93#include <dev/cons.h>
94
95#include <machine/cpu.h>
96#include <machine/db_machdep.h>
97#include <machine/fpu.h>
98#include <machine/frame.h>
99#include <machine/pcb.h>
100#include <machine/psl.h>
101#include <machine/trap.h>
102
103#include <powerpc/spr.h>
104#include <powerpc/ibm4xx/pmap.h>
105#include <powerpc/ibm4xx/tlb.h>
106#include <powerpc/fpu/fpu_extern.h>
107
108/* These definitions should probably be somewhere else			XXX */
109#define	FIRSTARG	3		/* first argument is in reg 3 */
110#define	NARGREG		8		/* 8 args are in registers */
111#define	MOREARGS(sp)	((caddr_t)((int)(sp) + 8)) /* more args go here */
112
113static int fix_unaligned __P((struct lwp *l, struct trapframe *frame));
114
115void trap __P((struct trapframe *));	/* Called from locore / trap_subr */
116/* Why are these not defined in a header? */
117int badaddr __P((void *, size_t));
118int badaddr_read __P((void *, size_t, int *));
119int ctx_setup __P((int, int));
120
121#ifdef DEBUG
122#define TDB_ALL	0x1
123int trapdebug = /* TDB_ALL */ 0;
124#define	DBPRINTF(x, y)	if (trapdebug & (x)) printf y
125#else
126#define DBPRINTF(x, y)
127#endif
128
129void
130trap(struct trapframe *frame)
131{
132	struct lwp *l = curlwp;
133	struct proc *p = l ? l->l_proc : NULL;
134	int type = frame->exc;
135	int ftype, rv;
136
137	KASSERT(l == 0 || (l->l_stat == LSONPROC));
138
139	if (frame->srr1 & PSL_PR)
140		type |= EXC_USER;
141
142	ftype = VM_PROT_READ;
143
144DBPRINTF(TDB_ALL, ("trap(%x) at %x from frame %p &frame %p\n",
145	type, frame->srr0, frame, &frame));
146
147	switch (type) {
148	case EXC_DEBUG|EXC_USER:
149{
150	int srr2, srr3;
151__asm __volatile("mfspr %0,0x3f0" : "=r" (rv), "=r" (srr2), "=r" (srr3) :);
152printf("debug reg is %x srr2 %x srr3 %x\n", rv, srr2, srr3);
153}
154		/*
155		 * DEBUG intr -- probably single-step.
156		 */
157	case EXC_TRC|EXC_USER:
158		KERNEL_PROC_LOCK(l);
159		frame->srr1 &= ~PSL_SE;
160		trapsignal(l, SIGTRAP, EXC_TRC);
161		KERNEL_PROC_UNLOCK(l);
162		break;
163
164	  /* If we could not find and install appropriate TLB entry, fall through */
165
166	case EXC_DSI:
167		/* FALLTHROUGH */
168	case EXC_DTMISS:
169		{
170			struct vm_map *map;
171			vaddr_t va;
172			struct faultbuf *fb = NULL;
173
174			KERNEL_LOCK(LK_CANRECURSE|LK_EXCLUSIVE);
175			va = frame->dar;
176			if (frame->tf_xtra[TF_PID] == KERNEL_PID) {
177				map = kernel_map;
178			} else {
179				map = &p->p_vmspace->vm_map;
180			}
181
182			if (frame->tf_xtra[TF_ESR] & (ESR_DST|ESR_DIZ))
183				ftype = VM_PROT_WRITE;
184
185DBPRINTF(TDB_ALL, ("trap(EXC_DSI) at %x %s fault on %p esr %x\n",
186frame->srr0, (ftype&VM_PROT_WRITE) ? "write" : "read", (void *)va, frame->tf_xtra[TF_ESR]));
187			rv = uvm_fault(map, trunc_page(va), 0, ftype);
188			KERNEL_UNLOCK();
189			if (rv == 0)
190				goto done;
191			if ((fb = l->l_addr->u_pcb.pcb_onfault) != NULL) {
192				frame->tf_xtra[TF_PID] = KERNEL_PID;
193				frame->srr0 = fb->fb_pc;
194				frame->srr1 |= PSL_IR; /* Re-enable IMMU */
195				frame->fixreg[1] = fb->fb_sp;
196				frame->fixreg[2] = fb->fb_r2;
197				frame->fixreg[3] = 1; /* Return TRUE */
198				frame->cr = fb->fb_cr;
199				memcpy(&frame->fixreg[13], fb->fb_fixreg,
200				    sizeof(fb->fb_fixreg));
201				goto done;
202			}
203		}
204		goto brain_damage;
205
206	case EXC_DSI|EXC_USER:
207		/* FALLTHROUGH */
208	case EXC_DTMISS|EXC_USER:
209		KERNEL_PROC_LOCK(l);
210
211		if (frame->tf_xtra[TF_ESR] & (ESR_DST|ESR_DIZ))
212			ftype = VM_PROT_WRITE;
213
214DBPRINTF(TDB_ALL, ("trap(EXC_DSI|EXC_USER) at %x %s fault on %x %x\n",
215frame->srr0, (ftype&VM_PROT_WRITE) ? "write" : "read", frame->dar, frame->tf_xtra[TF_ESR]));
216KASSERT(l == curlwp && (l->l_stat == LSONPROC));
217		rv = uvm_fault(&p->p_vmspace->vm_map,
218			       trunc_page(frame->dar), 0, ftype);
219		if (rv == 0) {
220		  KERNEL_PROC_UNLOCK(l);
221		  break;
222		}
223		if (rv == ENOMEM) {
224			printf("UVM: pid %d (%s) lid %d, uid %d killed: "
225			       "out of swap\n",
226			       p->p_pid, p->p_comm, l->l_lid,
227			       p->p_cred && p->p_ucred ?
228			       p->p_ucred->cr_uid : -1);
229			trapsignal(l, SIGKILL, EXC_DSI);
230		} else {
231			trapsignal(l, SIGSEGV, EXC_DSI);
232		}
233		KERNEL_PROC_UNLOCK(l);
234		break;
235	case EXC_ITMISS|EXC_USER:
236	case EXC_ISI|EXC_USER:
237		KERNEL_PROC_LOCK(l);
238		ftype = VM_PROT_READ | VM_PROT_EXECUTE;
239DBPRINTF(TDB_ALL, ("trap(EXC_ISI|EXC_USER) at %x %s fault on %x tf %p\n",
240frame->srr0, (ftype&VM_PROT_WRITE) ? "write" : "read", frame->srr0, frame));
241		rv = uvm_fault(&p->p_vmspace->vm_map, trunc_page(frame->srr0), 0, ftype);
242		if (rv == 0) {
243		  KERNEL_PROC_UNLOCK(l);
244		  break;
245		}
246		trapsignal(l, SIGSEGV, EXC_ISI);
247		KERNEL_PROC_UNLOCK(l);
248		break;
249
250	case EXC_AST|EXC_USER:
251		curcpu()->ci_astpending = 0;	/* we are about to do it */
252		KERNEL_PROC_LOCK(l);
253		uvmexp.softs++;
254		if (p->p_flag & P_OWEUPC) {
255			p->p_flag &= ~P_OWEUPC;
256			ADDUPROF(p);
257		}
258		/* Check whether we are being preempted. */
259		if (curcpu()->ci_want_resched)
260			preempt(0);
261		KERNEL_PROC_UNLOCK(l);
262		break;
263
264
265	case EXC_ALI|EXC_USER:
266		KERNEL_PROC_LOCK(l);
267		if (fix_unaligned(l, frame) != 0)
268			trapsignal(l, SIGBUS, EXC_ALI);
269		else
270			frame->srr0 += 4;
271		KERNEL_PROC_UNLOCK(l);
272		break;
273
274	case EXC_PGM|EXC_USER:
275		/*
276		 * Illegal insn:
277		 *
278		 * let's try to see if it's FPU and can be emulated.
279		 */
280		uvmexp.traps ++;
281		if (!(l->l_addr->u_pcb.pcb_flags & PCB_FPU)) {
282			memset(&l->l_addr->u_pcb.pcb_fpu, 0,
283				sizeof l->l_addr->u_pcb.pcb_fpu);
284			l->l_addr->u_pcb.pcb_flags |= PCB_FPU;
285		}
286
287		if ((rv = fpu_emulate(frame,
288			(struct fpreg *)&l->l_addr->u_pcb.pcb_fpu))) {
289			KERNEL_PROC_LOCK(l);
290			trapsignal(l, rv, EXC_PGM);
291			KERNEL_PROC_UNLOCK(l);
292		}
293		break;
294
295	case EXC_MCHK:
296		{
297			struct faultbuf *fb;
298
299			if ((fb = l->l_addr->u_pcb.pcb_onfault) != NULL) {
300				frame->tf_xtra[TF_PID] = KERNEL_PID;
301				frame->srr0 = fb->fb_pc;
302				frame->srr1 |= PSL_IR; /* Re-enable IMMU */
303				frame->fixreg[1] = fb->fb_sp;
304				frame->fixreg[2] = fb->fb_r2;
305				frame->fixreg[3] = 1; /* Return TRUE */
306				frame->cr = fb->fb_cr;
307				memcpy(&frame->fixreg[13], fb->fb_fixreg,
308				    sizeof(fb->fb_fixreg));
309				goto done;
310			}
311		}
312		goto brain_damage;
313	default:
314brain_damage:
315		printf("trap type 0x%x at 0x%lx\n", type, frame->srr0);
316#ifdef DDB
317		if (kdb_trap(type, frame))
318			goto done;
319#endif
320#ifdef TRAP_PANICWAIT
321		printf("Press a key to panic.\n");
322		cngetc();
323#endif
324		panic("trap");
325	}
326
327	/* Take pending signals. */
328	{
329		int sig;
330
331		while ((sig = CURSIG(l)) != 0)
332			postsig(sig);
333	}
334
335	/* Invoke per-process kernel-exit handling, if any */
336	if (p->p_userret)
337		(p->p_userret)(l, p->p_userret_arg);
338
339	/* Invoke any pending upcalls */
340	while (l->l_flag & L_SA_UPCALL)
341		sa_upcall_userret(l);
342
343	curcpu()->ci_schedstate.spc_curpriority = l->l_priority = l->l_usrpri;
344  done:
345	return;
346}
347
348int
349ctx_setup(int ctx, int srr1)
350{
351	volatile struct pmap *pm;
352
353	/* Update PID if we're returning to user mode. */
354	if (srr1 & PSL_PR) {
355		pm = curproc->p_vmspace->vm_map.pmap;
356		if (!pm->pm_ctx) {
357			ctx_alloc((struct pmap *)pm);
358		}
359		ctx = pm->pm_ctx;
360		if (srr1 & PSL_SE) {
361			int dbreg, mask = 0x48000000;
362				/*
363				 * Set the Internal Debug and
364				 * Instruction Completion bits of
365				 * the DBCR0 register.
366				 *
367				 * XXX this is also used by jtag debuggers...
368				 */
369			__asm __volatile("mfspr %0,0x3f2;"
370				"or %0,%0,%1;"
371				"mtspr 0x3f2,%0;" :
372				"=&r" (dbreg) : "r" (mask));
373		}
374	}
375	else if (!ctx) {
376		ctx = KERNEL_PID;
377	}
378	return (ctx);
379}
380
381/*
382 * Used by copyin()/copyout()
383 */
384extern vaddr_t vmaprange __P((struct proc *, vaddr_t, vsize_t, int));
385extern void vunmaprange __P((vaddr_t, vsize_t));
386static int bigcopyin __P((const void *,	void *,	size_t ));
387static int bigcopyout __P((const void *, void *, size_t ));
388
389int
390copyin(const void *udaddr, void *kaddr, size_t len)
391{
392	struct pmap *pm = curproc->p_vmspace->vm_map.pmap;
393	int msr, pid, tmp, ctx;
394	struct faultbuf env;
395
396	/* For bigger buffers use the faster copy */
397	if (len > 256) return (bigcopyin(udaddr, kaddr, len));
398
399	if (setfault(&env)) {
400		curpcb->pcb_onfault = 0;
401		return EFAULT;
402	}
403
404	if (!(ctx = pm->pm_ctx)) {
405		/* No context -- assign it one */
406		ctx_alloc(pm);
407		ctx = pm->pm_ctx;
408	}
409
410	asm volatile("addi %6,%6,1; mtctr %6;"	/* Set up counter */
411		"mfmsr %0;"			/* Save MSR */
412		"li %1,0x20; "
413		"andc %1,%0,%1; mtmsr %1;"	/* Disable IMMU */
414		"mfpid %1;"			/* Save old PID */
415		"sync; isync;"
416
417		"1: bdz 2f;"			/* while len */
418		"mtpid %3; sync;"		/* Load user ctx */
419		"lbz %2,0(%4); addi %4,%4,1;"	/* Load byte */
420		"sync; isync;"
421		"mtpid %1;sync;"
422		"stb %2,0(%5); dcbf 0,%5; addi %5,%5,1;"	/* Store kernel byte */
423		"sync; isync;"
424		"b 1b;"				/* repeat */
425
426		"2: mtpid %1; mtmsr %0;"	/* Restore PID and MSR */
427		"sync; isync;"
428		: "=&r" (msr), "=&r" (pid), "=&r" (tmp)
429		: "r" (ctx), "r" (udaddr), "r" (kaddr), "r" (len));
430
431	curpcb->pcb_onfault = 0;
432	return 0;
433}
434
435static int
436bigcopyin(const void *udaddr, void *kaddr, size_t len)
437{
438	const char *up;
439	char *kp = kaddr;
440	struct lwp *l = curlwp;
441	struct proc *p;
442	int error;
443
444	if (!l) {
445		return EFAULT;
446	}
447
448	p = l->l_proc;
449
450	/*
451	 * Stolen from physio():
452	 */
453	PHOLD(l);
454	error = uvm_vslock(p, (caddr_t)udaddr, len, VM_PROT_READ);
455	if (error) {
456		PRELE(l);
457		return EFAULT;
458	}
459	up = (char *)vmaprange(p, (vaddr_t)udaddr, len, VM_PROT_READ);
460
461	memcpy(kp, up, len);
462	vunmaprange((vaddr_t)up, len);
463	uvm_vsunlock(p, (caddr_t)udaddr, len);
464	PRELE(l);
465
466	return 0;
467}
468
469int
470copyout(const void *kaddr, void *udaddr, size_t len)
471{
472	struct pmap *pm = curproc->p_vmspace->vm_map.pmap;
473	int msr, pid, tmp, ctx;
474	struct faultbuf env;
475
476	/* For big copies use more efficient routine */
477	if (len > 256) return (bigcopyout(kaddr, udaddr, len));
478
479	if (setfault(&env)) {
480		curpcb->pcb_onfault = 0;
481		return EFAULT;
482	}
483
484	if (!(ctx = pm->pm_ctx)) {
485		/* No context -- assign it one */
486		ctx_alloc(pm);
487		ctx = pm->pm_ctx;
488	}
489
490	asm volatile("addi %6,%6,1; mtctr %6;"	/* Set up counter */
491		"mfmsr %0;"			/* Save MSR */
492		"li %1,0x20; "
493		"andc %1,%0,%1; mtmsr %1;"	/* Disable IMMU */
494		"mfpid %1;"			/* Save old PID */
495		"sync; isync;"
496
497		"1: bdz 2f;"			/* while len */
498		"mtpid %1;sync;"
499		"lbz %2,0(%5); addi %5,%5,1;"	/* Load kernel byte */
500		"sync; isync;"
501		"mtpid %3; sync;"		/* Load user ctx */
502		"stb %2,0(%4);  dcbf 0,%4; addi %4,%4,1;"	/* Store user byte */
503		"sync; isync;"
504		"b 1b;"				/* repeat */
505
506		"2: mtpid %1; mtmsr %0;"	/* Restore PID and MSR */
507		"sync; isync;"
508		: "=&r" (msr), "=&r" (pid), "=&r" (tmp)
509		: "r" (ctx), "r" (udaddr), "r" (kaddr), "r" (len));
510
511	curpcb->pcb_onfault = 0;
512	return 0;
513}
514
515static int
516bigcopyout(const void *kaddr, void *udaddr, size_t len)
517{
518	char *up;
519	const char *kp = (char *)kaddr;
520	struct lwp *l = curlwp;
521	struct proc *p;
522	int error;
523
524	if (!l) {
525		return EFAULT;
526	}
527
528	p = l->l_proc;
529
530	/*
531	 * Stolen from physio():
532	 */
533	PHOLD(l);
534	error = uvm_vslock(p, udaddr, len, VM_PROT_WRITE);
535	if (error) {
536		PRELE(l);
537		return EFAULT;
538	}
539	up = (char *)vmaprange(p, (vaddr_t)udaddr, len,
540		VM_PROT_READ|VM_PROT_WRITE);
541
542	memcpy(up, kp, len);
543	vunmaprange((vaddr_t)up, len);
544	uvm_vsunlock(p, udaddr, len);
545	PRELE(l);
546
547	return 0;
548}
549
550/*
551 * kcopy(const void *src, void *dst, size_t len);
552 *
553 * Copy len bytes from src to dst, aborting if we encounter a fatal
554 * page fault.
555 *
556 * kcopy() _must_ save and restore the old fault handler since it is
557 * called by uiomove(), which may be in the path of servicing a non-fatal
558 * page fault.
559 */
560int
561kcopy(const void *src, void *dst, size_t len)
562{
563	struct faultbuf env, *oldfault;
564
565	oldfault = curpcb->pcb_onfault;
566	if (setfault(&env)) {
567		curpcb->pcb_onfault = oldfault;
568		return EFAULT;
569	}
570
571	memcpy(dst, src, len);
572
573	curpcb->pcb_onfault = oldfault;
574	return 0;
575}
576
577int
578badaddr(void *addr, size_t size)
579{
580
581	return badaddr_read(addr, size, NULL);
582}
583
584int
585badaddr_read(void *addr, size_t size, int *rptr)
586{
587	struct faultbuf env;
588	int x;
589
590	/* Get rid of any stale machine checks that have been waiting.  */
591	__asm __volatile ("sync; isync");
592
593	if (setfault(&env)) {
594		curpcb->pcb_onfault = 0;
595		__asm __volatile ("sync");
596		return 1;
597	}
598
599	__asm __volatile ("sync");
600
601	switch (size) {
602	case 1:
603		x = *(volatile int8_t *)addr;
604		break;
605	case 2:
606		x = *(volatile int16_t *)addr;
607		break;
608	case 4:
609		x = *(volatile int32_t *)addr;
610		break;
611	default:
612		panic("badaddr: invalid size (%d)", size);
613	}
614
615	/* Make sure we took the machine check, if we caused one. */
616	__asm __volatile ("sync; isync");
617
618	curpcb->pcb_onfault = 0;
619	__asm __volatile ("sync");	/* To be sure. */
620
621	/* Use the value to avoid reorder. */
622	if (rptr)
623		*rptr = x;
624
625	return 0;
626}
627
628/*
629 * For now, this only deals with the particular unaligned access case
630 * that gcc tends to generate.  Eventually it should handle all of the
631 * possibilities that can happen on a 32-bit PowerPC in big-endian mode.
632 */
633
634static int
635fix_unaligned(struct lwp *l, struct trapframe *frame)
636{
637
638	return -1;
639}
640
641/*
642 * Start a new LWP
643 */
644void
645startlwp(arg)
646	void *arg;
647{
648	int err;
649	ucontext_t *uc = arg;
650	struct lwp *l = curlwp;
651
652	err = cpu_setmcontext(l, &uc->uc_mcontext, uc->uc_flags);
653#if DIAGNOSTIC
654	if (err) {
655		printf("Error %d from cpu_setmcontext.", err);
656	}
657#endif
658	pool_put(&lwp_uc_pool, uc);
659
660	upcallret(l);
661}
662
663/*
664 * XXX This is a terrible name.
665 */
666void
667upcallret(l)
668	struct lwp *l;
669{
670	int sig;
671
672	/* Take pending signals. */
673	while ((sig = CURSIG(l)) != 0)
674		postsig(sig);
675
676	/* Invoke per-process kernel-exit handling, if any */
677	if (l->l_proc->p_userret)
678		(l->l_proc->p_userret)(l, l->l_proc->p_userret_arg);
679
680	/* Invoke any pending upcalls */
681	while (l->l_flag & L_SA_UPCALL)
682		sa_upcall_userret(l);
683
684	curcpu()->ci_schedstate.spc_curpriority = l->l_priority = l->l_usrpri;
685}
686