xref: /netbsd-src/sys/arch/mac68k/mac68k/trap.c (revision c13a5359d541fd49b4c406f5b12209b1640235a5)
1 /*	$NetBSD: trap.c,v 1.154 2024/01/20 00:15:32 thorpej Exp $	*/
2 
3 /*
4  * Copyright (c) 1988 University of Utah.
5  * Copyright (c) 1982, 1986, 1990, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * the Systems Programming Group of the University of Utah Computer
10  * Science Department.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  * from: Utah $Hdr: trap.c 1.37 92/12/20$
37  *
38  *	@(#)trap.c	8.5 (Berkeley) 1/4/94
39  */
40 
41 #include <sys/cdefs.h>
42 __KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.154 2024/01/20 00:15:32 thorpej Exp $");
43 
44 #include "opt_ddb.h"
45 #include "opt_execfmt.h"
46 #include "opt_fpu_emulate.h"
47 #include "opt_kgdb.h"
48 #include "opt_compat_sunos.h"
49 #include "opt_m68k_arch.h"
50 
51 #include <sys/param.h>
52 #include <sys/systm.h>
53 #include <sys/proc.h>
54 #include <sys/acct.h>
55 #include <sys/kernel.h>
56 #include <sys/signalvar.h>
57 #include <sys/resourcevar.h>
58 #include <sys/syscall.h>
59 #include <sys/syslog.h>
60 #include <sys/userret.h>
61 #include <sys/kauth.h>
62 #ifdef KGDB
63 #include <sys/kgdb.h>
64 #endif
65 #ifdef DEBUG
66 #include <dev/cons.h>
67 #endif
68 
69 #include <m68k/cacheops.h>
70 #include <machine/db_machdep.h>
71 #include <machine/pcb.h>
72 #include <machine/psl.h>
73 #include <machine/trap.h>
74 #include <machine/cpu.h>
75 #include <machine/reg.h>
76 
77 #include <m68k/fpe/fpu_emulate.h>
78 
79 #include <uvm/uvm_extern.h>
80 
81 #include "zsc.h"
82 
83 #ifdef COMPAT_SUNOS
84 #include <compat/sunos/sunos_syscall.h>
85 extern struct emul emul_sunos;
86 #endif
87 
88 const char	*trap_type[] = {
89 	"Bus error",
90 	"Address error",
91 	"Illegal instruction",
92 	"Zero divide",
93 	"CHK instruction",
94 	"TRAPV instruction",
95 	"Privilege violation",
96 	"Trace trap",
97 	"MMU fault",
98 	"SSIR trap",
99 	"Format error",
100 	"68881 exception",
101 	"Coprocessor violation",
102 	"Async system trap"
103 };
104 int	trap_types = sizeof trap_type / sizeof trap_type[0];
105 
106 /*
107  * Size of various exception stack frames (minus the standard 8 bytes)
108  */
109 short	exframesize[] = {
110 	FMT0SIZE,	/* type 0 - normal (68020/030/040) */
111 	FMT1SIZE,	/* type 1 - throwaway (68020/030/040) */
112 	FMT2SIZE,	/* type 2 - normal 6-word (68020/030/040) */
113 	FMT3SIZE,	/* type 3 - FP post-instruction (68040) */
114 	FMT4SIZE,	/* type 4 - LC040 FP exception (68LC040) */
115 	-1, -1,		/* type 5-6 - undefined */
116 	FMT7SIZE,	/* type 7 - access error (68040) */
117 	58,		/* type 8 - bus fault (68010) */
118 	FMT9SIZE,	/* type 9 - coprocessor mid-instruction (68020/030) */
119 	FMTASIZE,	/* type A - short bus fault (68020/030) */
120 	FMTBSIZE,	/* type B - long bus fault (68020/030) */
121 	-1, -1, -1, -1	/* type C-F - undefined */
122 };
123 
124 #ifdef M68040
125 #define KDFAULT(c)	(mmutype == MMU_68040 ?			\
126 			  ((c) & SSW4_TMMASK) == SSW4_TMKD : 	\
127 			  ((c) & (SSW_DF|FC_SUPERD)) == (SSW_DF|FC_SUPERD))
128 #define WRFAULT(c)	(mmutype == MMU_68040 ?		\
129 			  ((c) & (SSW4_LK|SSW4_RW)) != SSW4_RW : 	\
130 			 (((c) & SSW_DF) != 0 && \
131 			 ((((c) & SSW_RW) == 0) || (((c) & SSW_RM) != 0))))
132 #else
133 #define KDFAULT(c)	(((c) & (SSW_DF|SSW_FCMASK)) == (SSW_DF|FC_SUPERD))
134 #define WRFAULT(c)	(((c) & SSW_DF) != 0 && \
135 			    ((((c) & SSW_RW) == 0) || (((c) & SSW_RM) != 0)))
136 #endif
137 
138 #ifdef DEBUG
139 int mmudebug = 0;
140 int mmupid = -1;
141 #define MDB_FOLLOW	1
142 #define MDB_WBFOLLOW	2
143 #define MDB_WBFAILED	4
144 #define MDB_ISPID(pid)	((pid) == mmupid)
145 #endif
146 
147 /* trap() only called from locore */
148 void	trap(struct frame *, int, u_int, u_int);
149 
150 static inline void userret(struct lwp *, struct frame *, u_quad_t, u_int, int);
151 
152 /*
153  * Trap and syscall both need the following work done before returning
154  * to user mode.
155  */
156 static inline void
userret(struct lwp * l,struct frame * fp,u_quad_t oticks,u_int faultaddr,int fromtrap)157 userret(struct lwp *l, struct frame *fp, u_quad_t oticks, u_int faultaddr,
158     int fromtrap)
159 {
160 	struct proc *p = l->l_proc;
161 #if defined(M68040)
162 	int sig;
163 	int beenhere = 0;
164 
165 again:
166 #endif
167 	/* Invoke MI userret code */
168 	mi_userret(l);
169 
170 	/*
171 	 * If profiling, charge recent system time.
172 	 */
173 	if (p->p_stflag & PST_PROFIL) {
174 		extern int psratio;
175 
176 		addupc_task(l, fp->f_pc,
177 		    (int)(p->p_sticks - oticks) * psratio);
178 	}
179 #if defined(M68040)
180 	/*
181 	 * Deal with user mode writebacks (from trap, or from sigreturn).
182 	 * If any writeback fails, go back and attempt signal delivery
183 	 * unless we have already been here and attempted the writeback
184 	 * (e.g. bad address with user ignoring SIGSEGV).  In that case,
185 	 * we just return to the user without successfully completing
186 	 * the writebacks.  Maybe we should just drop the sucker?
187 	 */
188 	if (mmutype == MMU_68040 && fp->f_format == FMT7) {
189 		if (beenhere) {
190 #if DEBUG
191 			if (mmudebug & MDB_WBFAILED)
192 				printf(fromtrap ?
193 		"pid %d(%s): writeback aborted, pc=%x, fa=%x\n" :
194 		"pid %d(%s): writeback aborted in sigreturn, pc=%x\n",
195 				    p->p_pid, p->p_comm, fp->f_pc, faultaddr);
196 #endif
197 		} else if ((sig = m68040_writeback(fp, fromtrap))) {
198 			ksiginfo_t ksi;
199 			beenhere = 1;
200 			oticks = p->p_sticks;
201 			(void)memset(&ksi, 0, sizeof(ksi));
202 			ksi.ksi_signo = sig;
203 			ksi.ksi_addr = (void *)faultaddr;
204 			ksi.ksi_code = BUS_OBJERR;
205 			trapsignal(l, &ksi);
206 			goto again;
207 		}
208 	}
209 #endif
210 }
211 
212 /*
213  * Used by the common m68k syscall() and child_return() functions.
214  * XXX: Temporary until all m68k ports share common trap()/userret() code.
215  */
216 void machine_userret(struct lwp *, struct frame *, u_quad_t);
217 
218 void
machine_userret(struct lwp * l,struct frame * f,u_quad_t t)219 machine_userret(struct lwp *l, struct frame *f, u_quad_t t)
220 {
221 
222 	userret(l, f, t, 0, 0);
223 }
224 
225 /*
226  * Trap is called from locore to handle most types of processor traps,
227  * including events such as simulated software interrupts/AST's.
228  * System calls are broken out for efficiency.
229  */
230 /*ARGSUSED*/
231 void
trap(struct frame * fp,int type,u_int code,u_int v)232 trap(struct frame *fp, int type, u_int code, u_int v)
233 {
234 	struct lwp *l;
235 	struct proc *p;
236 	struct pcb *pcb;
237 	void *onfault;
238 	ksiginfo_t ksi;
239 	int s;
240 	int rv;
241 	u_quad_t sticks;
242 
243 	curcpu()->ci_data.cpu_ntrap++;
244 	l = curlwp;
245 	p = l->l_proc;
246 	pcb = lwp_getpcb(l);
247 
248 	KSI_INIT_TRAP(&ksi);
249 	ksi.ksi_trap = type & ~T_USER;
250 
251 	if (USERMODE(fp->f_sr)) {
252 		type |= T_USER;
253 		sticks = p->p_sticks;
254 		l->l_md.md_regs = fp->f_regs;
255 	} else
256 		sticks = 0;
257 
258 	switch (type) {
259 	default:
260 	dopanic:
261 		printf("trap type %d, code = 0x%x, v = 0x%x\n", type, code, v);
262 		printf("%s program counter = 0x%x\n",
263 		    (type & T_USER) ? "user" : "kernel", fp->f_pc);
264 		/*
265 		 * Let the kernel debugger see the trap frame that
266 		 * caused us to panic.  This is a convenience so
267 		 * one can see registers at the point of failure.
268 		 */
269 		s = splhigh();
270 #ifdef KGDB
271 		/* If connected, step or cont returns 1 */
272 		if (kgdb_trap(type, (db_regs_t *)fp))
273 			goto kgdb_cont;
274 #endif
275 #ifdef DDB
276 		(void)kdb_trap(type, (db_regs_t *)fp);
277 #endif
278 #ifdef KGDB
279 	kgdb_cont:
280 #endif
281 		splx(s);
282 		if (panicstr) {
283 			printf("trap during panic!\n");
284 #ifdef DEBUG
285 			/* XXX should be a machine-dependent hook */
286 			printf("(press a key)\n");
287 			cnpollc(1);
288 			(void)cngetc();
289 			cnpollc(0);
290 #endif
291 		}
292 		regdump((struct trapframe *)fp, 128);
293 		type &= ~T_USER;
294 		if ((u_int)type < trap_types)
295 			panic(trap_type[type]);
296 		panic("trap");
297 
298 	case T_BUSERR:		/* Kernel bus error */
299 		onfault = pcb->pcb_onfault;
300 		if (onfault == NULL)
301 			goto dopanic;
302 		rv = EFAULT;
303 		/*
304 		 * If we have arranged to catch this fault in any of the
305 		 * copy to/from user space routines, set PC to return to
306 		 * indicated location and set flag informing buserror code
307 		 * that it may need to clean up stack frame.
308 		 */
309 copyfault:
310 		fp->f_stackadj = exframesize[fp->f_format];
311 		fp->f_format = fp->f_vector = 0;
312 		fp->f_pc = (int)onfault;
313 		fp->f_regs[D0] = rv;
314 		return;
315 
316 	case T_BUSERR|T_USER:	/* Bus error */
317 	case T_ADDRERR|T_USER:	/* Address error */
318 		ksi.ksi_addr = (void *)v;
319 		ksi.ksi_signo = SIGBUS;
320 		ksi.ksi_code = (type == (T_BUSERR|T_USER)) ?
321 			BUS_OBJERR : BUS_ADRERR;
322 		break;
323 
324 	case T_ILLINST|T_USER:	/* Illegal instruction fault */
325 	case T_PRIVINST|T_USER:	/* Privileged instruction fault */
326 		ksi.ksi_addr = (void *)(int)fp->f_format;
327 				/* XXX was ILL_PRIVIN_FAULT */
328 		ksi.ksi_signo = SIGILL;
329 		ksi.ksi_code = (type == (T_PRIVINST|T_USER)) ?
330 			ILL_PRVOPC : ILL_ILLOPC;
331 		break;
332 	/*
333 	 * divde by zero, CHK/TRAPV inst
334 	 */
335 	case T_ZERODIV|T_USER:		/* Integer divide by zero trap */
336 		ksi.ksi_code = FPE_INTDIV;
337 	case T_CHKINST|T_USER:		/* CHK instruction trap */
338 	case T_TRAPVINST|T_USER:	/* TRAPV instruction trap */
339 		ksi.ksi_addr = (void *)(int)fp->f_format;
340 		ksi.ksi_signo = SIGFPE;
341 		break;
342 
343 	/*
344 	 * User coprocessor violation
345 	 */
346 	case T_COPERR|T_USER:
347 	/* XXX What is a proper response here? */
348 		ksi.ksi_signo = SIGFPE;
349 		ksi.ksi_code = FPE_FLTINV;
350 		break;
351 	/*
352 	 * 6888x exceptions
353 	 */
354 	case T_FPERR|T_USER:
355 		/*
356 		 * We decode the 68881 status register which locore
357 		 * stashed in code for us.
358 		 */
359 		ksi.ksi_signo = SIGFPE;
360 		ksi.ksi_code = fpsr2siginfocode(code);
361 		break;
362 
363 	/*
364 	 * FPU faults in supervisor mode.
365 	 */
366 	case T_ILLINST:	/* fnop generates this, apparently. */
367 	case T_FPEMULI:
368 	case T_FPEMULD: {
369 		extern label_t *nofault;
370 
371 		if (nofault)	/* If we're probing. */
372 			longjmp(nofault);
373 		if (type == T_ILLINST)
374 			printf("Kernel Illegal Instruction trap.\n");
375 		else
376 			printf("Kernel FPU trap.\n");
377 		goto dopanic;
378 	}
379 
380 	/*
381 	 * Unimplemented FPU instructions/datatypes.
382 	 */
383 	case T_FPEMULI|T_USER:
384 	case T_FPEMULD|T_USER:
385 #ifdef FPU_EMULATE
386 		if (fpu_emulate(fp, &pcb->pcb_fpregs, &ksi) == 0)
387 			; /* XXX - Deal with tracing? (fp->f_sr & PSL_T) */
388 #else
389 		uprintf("pid %d killed: no floating point support.\n",
390 			p->p_pid);
391 		ksi.ksi_signo = SIGILL;
392 		ksi.ksi_code = ILL_ILLOPC;
393 #endif
394 		break;
395 
396 	case T_COPERR:		/* Kernel coprocessor violation */
397 	case T_FMTERR:		/* Kernel format error */
398 	case T_FMTERR|T_USER:	/* User format error */
399 		/*
400 		 * The user has most likely trashed the RTE or FP state info
401 		 * in the stack frame of a signal handler.
402 		 */
403 		printf("pid %d: kernel %s exception\n", p->p_pid,
404 		    type==T_COPERR ? "coprocessor" : "format");
405 		type |= T_USER;
406 		mutex_enter(p->p_lock);
407 		SIGACTION(p, SIGILL).sa_handler = SIG_DFL;
408 		sigdelset(&p->p_sigctx.ps_sigignore, SIGILL);
409 		sigdelset(&p->p_sigctx.ps_sigcatch, SIGILL);
410 		sigdelset(&l->l_sigmask, SIGILL);
411 		mutex_exit(p->p_lock);
412 		ksi.ksi_signo = SIGILL;
413 		ksi.ksi_addr = (void *)(int)fp->f_format;
414 				/* XXX was ILL_RESAD_FAULT */
415 		ksi.ksi_code = (type == T_COPERR) ?
416 			ILL_COPROC : ILL_ILLOPC;
417 		break;
418 
419 	/*
420 	 * XXX: Trace traps are a nightmare.
421 	 *
422 	 *	HP-UX uses trap #1 for breakpoints,
423 	 *	NetBSD/m68k uses trap #2,
424 	 *	SUN 3.x uses trap #15,
425 	 *	DDB and KGDB uses trap #15 (for kernel breakpoints;
426 	 *	handled elsewhere).
427 	 *
428 	 * NetBSD and HP-UX traps both get mapped by locore.s into T_TRACE.
429 	 * SUN 3.x traps get passed through as T_TRAP15 and are not really
430 	 * supported yet.
431 	 *
432 	 * XXX: We should never get kernel-mode T_TRAP15 because
433 	 * XXX: locore.s now gives it special treatment.
434 	 */
435 	case T_TRAP15:		/* SUN trace trap */
436 #ifdef DEBUG
437 		printf("unexpected kernel trace trap, type = %d\n", type);
438 		printf("program counter = 0x%x\n", fp->f_pc);
439 #endif
440 		fp->f_sr &= ~PSL_T;
441 		ksi.ksi_signo = SIGTRAP;
442 		break;
443 
444 	case T_TRACE|T_USER:	/* user trace trap */
445 #ifdef COMPAT_SUNOS
446 		/*
447 		 * SunOS uses Trap #2 for a "CPU cache flush".
448 		 * Just flush the on-chip caches and return.
449 		 */
450 		if (p->p_emul == &emul_sunos) {
451 			ICIA();
452 			DCIU();
453 			return;
454 		}
455 #endif
456 		/* FALLTHROUGH */
457 	case T_TRACE:		/* tracing a trap instruction */
458 	case T_TRAP15|T_USER:	/* SUN user trace trap */
459 		fp->f_sr &= ~PSL_T;
460 		ksi.ksi_addr = (void *)fp->f_pc;
461 		ksi.ksi_signo = SIGTRAP;
462 		if (type == (T_TRAP15|T_USER))
463 			ksi.ksi_code = TRAP_BRKPT;
464 		else
465 			ksi.ksi_code = TRAP_TRACE;
466 		break;
467 
468 	case T_ASTFLT:		/* System async trap, cannot happen */
469 		goto dopanic;
470 
471 	case T_ASTFLT|T_USER:	/* User async trap. */
472 		astpending = 0;
473 		/*
474 		 * We check for software interrupts first.  This is because
475 		 * they are at a higher level than ASTs, and on a VAX would
476 		 * interrupt the AST.  We assume that if we are processing
477 		 * an AST that we must be at IPL0 so we don't bother to
478 		 * check.  Note that we ensure that we are at least at SIR
479 		 * IPL while processing the SIR.
480 		 */
481 		spl1();
482 		/* fall into... */
483 
484 	case T_SSIR:		/* Software interrupt */
485 	case T_SSIR|T_USER:
486 		/*
487 		 * If this was not an AST trap, we are all done.
488 		 */
489 		if (type != (T_ASTFLT|T_USER)) {
490 			curcpu()->ci_data.cpu_ntrap--;
491 			return;
492 		}
493 		spl0();
494 		if (l->l_pflag & LP_OWEUPC) {
495 			l->l_pflag &= ~LP_OWEUPC;
496 			ADDUPROF(l);
497 		}
498 		goto out;
499 
500 	case T_MMUFLT:		/* Kernel mode page fault */
501 	case T_MMUFLT|T_USER:	/* page fault */
502 	    {
503 		vaddr_t va;
504 		struct vmspace *vm = p->p_vmspace;
505 		struct vm_map *map;
506 		vm_prot_t ftype;
507 		extern struct vm_map *kernel_map;
508 
509 		onfault = pcb->pcb_onfault;
510 
511 #ifdef DEBUG
512 		if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid))
513 		printf("trap: T_MMUFLT pid=%d, code=%x, v=%x, pc=%x, sr=%x\n",
514 			p->p_pid, code, v, fp->f_pc, fp->f_sr);
515 #endif
516 		/*
517 		 * It is only a kernel address space fault iff:
518 		 *	1. (type & T_USER) == 0 and
519 		 *	2. pcb_onfault not set or
520 		 *	3. pcb_onfault set but supervisor data fault
521 		 * The last can occur during an exec() copyin where the
522 		 * argument space is lazy-allocated.
523 		 */
524 		if (type == T_MMUFLT && (onfault == NULL || KDFAULT(code)))
525 			map = kernel_map;
526 		else {
527 			map = vm ? &vm->vm_map : kernel_map;
528 		}
529 		if (WRFAULT(code))
530 			ftype = VM_PROT_WRITE;
531 		else
532 			ftype = VM_PROT_READ;
533 		va = trunc_page((vaddr_t)v);
534 #ifdef DEBUG
535 		if (map == kernel_map && va == 0) {
536 			printf("trap: bad kernel access at %x\n", v);
537 			goto dopanic;
538 		}
539 #endif
540 		pcb->pcb_onfault = NULL;
541 		rv = uvm_fault(map, va, ftype);
542 		pcb->pcb_onfault = onfault;
543 #ifdef DEBUG
544 		if (rv && MDB_ISPID(p->p_pid))
545 			printf("uvm_fault(%p, 0x%lx, 0x%x) -> 0x%x\n",
546 			    map, va, ftype, rv);
547 #endif
548 		/*
549 		 * If this was a stack access, we keep track of the maximum
550 		 * accessed stack size.  Also, if vm_fault gets a protection
551 		 * failure, it is due to accessing the stack region outside
552 		 * the current limit and we need to reflect that as an access
553 		 * error.
554 		 */
555 		if (rv == 0) {
556 			if (map != kernel_map && (void *)va >= vm->vm_maxsaddr)
557 				uvm_grow(p, va);
558 
559 			if (type == T_MMUFLT) {
560 #if defined(M68040)
561 				if (mmutype == MMU_68040)
562 					(void)m68040_writeback(fp, 1);
563 #endif
564 				return;
565 			}
566 			goto out;
567 		}
568 		if (type == T_MMUFLT) {
569 			if (onfault)
570 				goto copyfault;
571 			printf("uvm_fault(%p, 0x%lx, 0x%x) -> 0x%x\n",
572 			    map, va, ftype, rv);
573 			printf("  type %x, code [mmu,,ssw]: %x\n",
574 				type, code);
575 			goto dopanic;
576 		}
577 		ksi.ksi_addr = (void *)v;
578 		switch (rv) {
579 		case ENOMEM:
580 			printf("UVM: pid %d (%s), uid %d killed: out of swap\n",
581 			       p->p_pid, p->p_comm,
582 			       l->l_cred ?
583 			       kauth_cred_geteuid(l->l_cred) : -1);
584 			ksi.ksi_signo = SIGKILL;
585 			break;
586 		case EINVAL:
587 			ksi.ksi_signo = SIGBUS;
588 			ksi.ksi_code = BUS_ADRERR;
589 			break;
590 		case EACCES:
591 			ksi.ksi_signo = SIGSEGV;
592 			ksi.ksi_code = SEGV_ACCERR;
593 			break;
594 		default:
595 			ksi.ksi_signo = SIGSEGV;
596 			ksi.ksi_code = SEGV_MAPERR;
597 			break;
598 		}
599 		break;
600 	    }
601 	}
602 	if (ksi.ksi_signo)
603 		trapsignal(l, &ksi);
604 	if ((type & T_USER) == 0)
605 		return;
606 out:
607 	userret(l, fp, sticks, v, 1);
608 }
609