1 /* $NetBSD: trap.c,v 1.114 2024/01/20 00:15:33 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.114 2024/01/20 00:15:33 thorpej Exp $");
43
44 #include "opt_ddb.h"
45 #include "opt_kgdb.h"
46 #include "opt_execfmt.h"
47 #include "opt_compat_sunos.h"
48 #include "opt_fpu_emulate.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
63 #include <machine/pcb.h>
64 #include <machine/psl.h>
65 #include <machine/trap.h>
66 #include <machine/cpu.h>
67 #include <machine/reg.h>
68 #include <machine/db_machdep.h>
69 #include <m68k/cacheops.h>
70
71 #include <uvm/uvm_extern.h>
72
73 #include <dev/cons.h>
74
75 #ifdef FPU_EMULATE
76 #include <m68k/fpe/fpu_emulate.h>
77 #endif
78
79 #ifdef COMPAT_SUNOS
80 #include <compat/sunos/sunos_exec.h>
81 #include <compat/sunos/sunos_syscall.h>
82 #endif
83
84 void trap(struct frame *, int, u_int, u_int);
85
86 #if defined(M68040) || defined(M68060)
87 #ifdef DEBUG
88 void dumpssw(u_short);
89 void dumpwb(int, u_short, u_int, u_int);
90 #endif
91 #endif
92
93 static inline void userret(struct lwp *, struct frame *, u_quad_t, u_int, int);
94
95 const char *trap_type[] = {
96 "Bus error",
97 "Address error",
98 "Illegal instruction",
99 "Zero divide",
100 "CHK instruction",
101 "TRAPV instruction",
102 "Privilege violation",
103 "Trace trap",
104 "MMU fault",
105 "SSIR trap",
106 "Format error",
107 "68881 exception",
108 "Coprocessor violation",
109 "Async system trap"
110 };
111 int trap_types = sizeof trap_type / sizeof trap_type[0];
112
113 /*
114 * Size of various exception stack frames (minus the standard 8 bytes)
115 */
116 short exframesize[] = {
117 FMT0SIZE, /* type 0 - normal (68020/030/040/060) */
118 FMT1SIZE, /* type 1 - throwaway (68020/030/040) */
119 FMT2SIZE, /* type 2 - normal 6-word (68020/030/040/060) */
120 FMT3SIZE, /* type 3 - FP post-instruction (68040/060) */
121 FMT4SIZE, /* type 4 - access error/fp disabled (68060) */
122 -1, -1, /* type 5-6 - undefined */
123 FMT7SIZE, /* type 7 - access error (68040) */
124 58, /* type 8 - bus fault (68010) */
125 FMT9SIZE, /* type 9 - coprocessor mid-instruction (68020/030) */
126 FMTASIZE, /* type A - short bus fault (68020/030) */
127 FMTBSIZE, /* type B - long bus fault (68020/030) */
128 -1, -1, -1, -1 /* type C-F - undefined */
129 };
130
131 #ifdef M68060
132 #define KDFAULT_060(c) (cputype == CPU_68060 && ((c) & FSLW_TM_SV))
133 #define WRFAULT_060(c) (cputype == CPU_68060 && ((c) & FSLW_RW_W))
134 #else
135 #define KDFAULT_060(c) 0
136 #define WRFAULT_060(c) 0
137 #endif
138
139 #ifdef M68040
140 #define KDFAULT_040(c) (cputype == CPU_68040 && \
141 ((c) & SSW4_TMMASK) == SSW4_TMKD)
142 #define WRFAULT_040(c) (cputype == CPU_68040 && \
143 ((c) & (SSW4_LK|SSW4_RW)) != SSW4_RW)
144 #else
145 #define KDFAULT_040(c) 0
146 #define WRFAULT_040(c) 0
147 #endif
148
149 #if defined(M68030) || defined(M68020)
150 #define KDFAULT_OTH(c) (cputype <= CPU_68030 && \
151 ((c) & (SSW_DF|SSW_FCMASK)) == (SSW_DF|FC_SUPERD))
152 #define WRFAULT_OTH(c) (cputype <= CPU_68030 && \
153 (((c) & SSW_DF) != 0 && \
154 ((((c) & SSW_RW) == 0) || (((c) & SSW_RM) != 0))))
155 #else
156 #define KDFAULT_OTH(c) 0
157 #define WRFAULT_OTH(c) 0
158 #endif
159
160 #define KDFAULT(c) (KDFAULT_060(c) || KDFAULT_040(c) || KDFAULT_OTH(c))
161 #define WRFAULT(c) (WRFAULT_060(c) || WRFAULT_040(c) || WRFAULT_OTH(c))
162
163 #ifdef DEBUG
164 int mmudebug = 0;
165 int mmupid = -1;
166 #define MDB_FOLLOW 1
167 #define MDB_WBFOLLOW 2
168 #define MDB_WBFAILED 4
169 #define MDB_ISPID(p) ((p) == mmupid)
170 #endif
171
172 /*
173 * trap and syscall both need the following work done before returning
174 * to user mode.
175 */
176 static inline void
userret(struct lwp * l,struct frame * fp,u_quad_t oticks,u_int faultaddr,int fromtrap)177 userret(struct lwp *l, struct frame *fp, u_quad_t oticks, u_int faultaddr,
178 int fromtrap)
179 {
180 struct proc *p = l->l_proc;
181 #ifdef M68040
182 int sig;
183 int beenhere = 0;
184
185 again:
186 #endif
187 /* Invoke MI userret code */
188 mi_userret(l);
189
190 /*
191 * If profiling, charge system time to the trapped pc.
192 */
193 if (p->p_stflag & PST_PROFIL) {
194 extern int psratio;
195
196 addupc_task(l, fp->f_pc,
197 (int)(p->p_sticks - oticks) * psratio);
198 }
199 #ifdef M68040
200 /*
201 * Deal with user mode writebacks (from trap, or from sigreturn).
202 * If any writeback fails, go back and attempt signal delivery.
203 * unless we have already been here and attempted the writeback
204 * (e.g. bad address with user ignoring SIGSEGV). In that case
205 * we just return to the user without successfully completing
206 * the writebacks. Maybe we should just drop the sucker?
207 */
208 if (cputype == CPU_68040 && fp->f_format == FMT7) {
209 if (beenhere) {
210 #ifdef DEBUG
211 if (mmudebug & MDB_WBFAILED)
212 printf(fromtrap ?
213 "pid %d(%s): writeback aborted, pc=%x, fa=%x\n" :
214 "pid %d(%s): writeback aborted in sigreturn, pc=%x\n",
215 p->p_pid, p->p_comm, fp->f_pc, faultaddr);
216 #endif
217 } else if ((sig = m68040_writeback(fp, fromtrap))) {
218 ksiginfo_t ksi;
219 beenhere = 1;
220 oticks = p->p_sticks;
221 (void)memset(&ksi, 0, sizeof(ksi));
222 ksi.ksi_signo = sig;
223 ksi.ksi_addr = (void *)faultaddr;
224 ksi.ksi_code = BUS_OBJERR;
225 trapsignal(l, &ksi);
226 goto again;
227 }
228 }
229 #endif
230 }
231
232 /*
233 * Used by the common m68k syscall() and child_return() functions.
234 * XXX: Temporary until all m68k ports share common trap()/userret() code.
235 */
236 void machine_userret(struct lwp *, struct frame *, u_quad_t);
237
238 void
machine_userret(struct lwp * l,struct frame * f,u_quad_t t)239 machine_userret(struct lwp *l, struct frame *f, u_quad_t t)
240 {
241
242 userret(l, f, t, 0, 0);
243 }
244
245 /*
246 * Trap is called from locore to handle most types of processor traps,
247 * including events such as simulated software interrupts/AST's.
248 * System calls are broken out for efficiency.
249 */
250 /*ARGSUSED*/
251 void
trap(struct frame * fp,int type,unsigned code,unsigned v)252 trap(struct frame *fp, int type, unsigned code, unsigned v)
253 {
254 struct lwp *l;
255 struct proc *p;
256 struct pcb *pcb;
257 void *onfault;
258 ksiginfo_t ksi;
259 int s;
260 int rv;
261 u_quad_t sticks = 0 /* XXX initializer works around compiler bug */;
262
263 curcpu()->ci_data.cpu_ntrap++;
264 l = curlwp;
265 p = l->l_proc;
266 pcb = lwp_getpcb(l);
267 KASSERT(pcb != NULL);
268
269 KSI_INIT_TRAP(&ksi);
270 ksi.ksi_trap = type & ~T_USER;
271
272 if (USERMODE(fp->f_sr)) {
273 type |= T_USER;
274 sticks = p->p_sticks;
275 l->l_md.md_regs = fp->f_regs;
276 }
277 switch (type) {
278
279 default:
280 dopanic:
281 printf("trap type %d, code = 0x%x, v = 0x%x\n", type, code, v);
282 printf("%s program counter = 0x%x\n",
283 (type & T_USER) ? "user" : "kernel", fp->f_pc);
284 /*
285 * Let the kernel debugger see the trap frame that
286 * caused us to panic. This is a convenience so
287 * one can see registers at the point of failure.
288 */
289 s = splhigh();
290 #ifdef KGDB
291 /* If connected, step or cont returns 1 */
292 if (kgdb_trap(type, fp))
293 goto kgdb_cont;
294 #endif
295 #ifdef DDB
296 (void)kdb_trap(type, (db_regs_t *)fp);
297 #endif
298 #ifdef KGDB
299 kgdb_cont:
300 #endif
301 splx(s);
302 if (panicstr) {
303 printf("trap during panic!\n");
304 #ifdef DEBUG
305 /* XXX should be a machine-dependent hook */
306 printf("(press a key)\n");
307 cnpollc(1);
308 (void)cngetc();
309 cnpollc(0);
310 #endif
311 }
312 regdump((struct trapframe *)fp, 128);
313 type &= ~T_USER;
314 if ((u_int)type < trap_types)
315 panic(trap_type[type]);
316 panic("trap");
317
318 case T_BUSERR: /* kernel bus error */
319 onfault = pcb->pcb_onfault;
320 if (onfault == NULL)
321 goto dopanic;
322 rv = EFAULT;
323 /* FALLTHROUGH */
324
325 copyfault:
326 /*
327 * If we have arranged to catch this fault in any of the
328 * copy to/from user space routines, set PC to return to
329 * indicated location and set flag informing buserror code
330 * that it may need to clean up stack frame.
331 */
332 fp->f_stackadj = exframesize[fp->f_format];
333 fp->f_format = fp->f_vector = 0;
334 fp->f_pc = (int)onfault;
335 fp->f_regs[D0] = rv;
336 return;
337
338 case T_BUSERR|T_USER: /* bus error */
339 case T_ADDRERR|T_USER: /* address error */
340 ksi.ksi_addr = (void *)v;
341 ksi.ksi_signo = SIGBUS;
342 ksi.ksi_code = (type == (T_BUSERR|T_USER)) ?
343 BUS_OBJERR : BUS_ADRERR;
344 break;
345
346 case T_COPERR: /* kernel coprocessor violation */
347 case T_FMTERR|T_USER: /* do all RTE errors come in as T_USER? */
348 case T_FMTERR: /* ...just in case... */
349 /*
350 * The user has most likely trashed the RTE or FP state info
351 * in the stack frame of a signal handler.
352 */
353 printf("pid %d: kernel %s exception\n", p->p_pid,
354 type==T_COPERR ? "coprocessor" : "format");
355 type |= T_USER;
356
357 mutex_enter(p->p_lock);
358 SIGACTION(p, SIGILL).sa_handler = SIG_DFL;
359 sigdelset(&p->p_sigctx.ps_sigignore, SIGILL);
360 sigdelset(&p->p_sigctx.ps_sigcatch, SIGILL);
361 sigdelset(&l->l_sigmask, SIGILL);
362 mutex_exit(p->p_lock);
363
364 ksi.ksi_signo = SIGILL;
365 ksi.ksi_addr = (void *)(int)fp->f_format;
366 /* XXX was ILL_RESAD_FAULT */
367 ksi.ksi_code = (type == T_COPERR) ?
368 ILL_COPROC : ILL_ILLOPC;
369 break;
370
371 case T_COPERR|T_USER: /* user coprocessor violation */
372 /* What is a proper response here? */
373 ksi.ksi_signo = SIGFPE;
374 ksi.ksi_code = FPE_FLTINV;
375 break;
376
377 case T_FPERR|T_USER: /* 68881 exceptions */
378 /*
379 * We pass along the 68881 status which locore stashed
380 * in code for us.
381 */
382 ksi.ksi_signo = SIGFPE;
383 ksi.ksi_code = fpsr2siginfocode(code);
384 break;
385
386 /*
387 * FPU faults in supervisor mode.
388 */
389 case T_ILLINST: /* fnop generates this, apparently. */
390 case T_FPEMULI:
391 case T_FPEMULD: {
392 extern label_t *nofault;
393
394 if (nofault) /* If we're probing. */
395 longjmp(nofault);
396 if (type == T_ILLINST)
397 printf("Kernel Illegal Instruction trap.\n");
398 else
399 printf("Kernel FPU trap.\n");
400 goto dopanic;
401 }
402
403 /*
404 * Unimplemented FPU instructions/datatypes.
405 */
406 case T_FPEMULI|T_USER: /* unimplemented FP instruction */
407 case T_FPEMULD|T_USER: /* unimplemented FP data type */
408 #ifdef FPU_EMULATE
409 if (fpu_emulate(fp, &pcb->pcb_fpregs, &ksi) == 0)
410 ; /* XXX - Deal with tracing? (fp->f_sr & PSL_T) */
411 break;
412 #elif defined(M68040) || defined(M68060)
413 /* XXX need to FSAVE */
414 printf("pid %d(%s): unimplemented FP %s at %x (EA %x)\n",
415 p->p_pid, p->p_comm,
416 fp->f_format == 2 ? "instruction" : "data type",
417 fp->f_pc, fp->f_fmt2.f_iaddr);
418 /* XXX need to FRESTORE */
419 ksi.ksi_signo = SIGFPE;
420 ksi.ksi_code = FPE_FLTINV;
421 break;
422 #endif
423
424 case T_ILLINST|T_USER: /* illegal instruction fault */
425 case T_PRIVINST|T_USER: /* privileged instruction fault */
426 ksi.ksi_addr = (void *)(int)fp->f_format;
427 /* XXX was ILL_PRIVIN_FAULT */
428 ksi.ksi_signo = SIGILL;
429 ksi.ksi_code = (type == (T_PRIVINST|T_USER)) ?
430 ILL_PRVOPC : ILL_ILLOPC;
431 break;
432
433 case T_ZERODIV|T_USER: /* Divide by zero */
434 ksi.ksi_addr = (void *)(int)fp->f_format;
435 /* XXX was FPE_INTDIV_TRAP */
436 ksi.ksi_signo = SIGFPE;
437 ksi.ksi_code = FPE_FLTDIV;
438 break;
439
440 case T_CHKINST|T_USER: /* CHK instruction trap */
441 ksi.ksi_addr = (void *)(int)fp->f_format;
442 /* XXX was FPE_SUBRNG_TRAP */
443 ksi.ksi_signo = SIGFPE;
444 break;
445
446 case T_TRAPVINST|T_USER: /* TRAPV instruction trap */
447 ksi.ksi_addr = (void *)(int)fp->f_format;
448 /* XXX was FPE_INTOVF_TRAP */
449 ksi.ksi_signo = SIGFPE;
450 break;
451
452 /*
453 * XXX: Trace traps are a nightmare.
454 *
455 * HP-UX uses trap #1 for breakpoints,
456 * NetBSD/m68k uses trap #2,
457 * SUN 3.x uses trap #15,
458 * DDB and KGDB uses trap #15 (for kernel breakpoints;
459 * handled elsewhere).
460 *
461 * NetBSD and HP-UX traps both get mapped by locore.s into T_TRACE.
462 * SUN 3.x traps get passed through as T_TRAP15 and are not really
463 * supported yet.
464 *
465 * XXX: We should never get kernel-mode T_TRAP15
466 * XXX: because locore.s now gives them special treatment.
467 */
468 case T_TRAP15: /* kernel breakpoint */
469 #ifdef DEBUG
470 printf("unexpected kernel trace trap, type = %d\n", type);
471 printf("program counter = 0x%x\n", fp->f_pc);
472 #endif
473 fp->f_sr &= ~PSL_T;
474 return;
475
476 case T_TRACE|T_USER: /* user trace trap */
477 #ifdef COMPAT_SUNOS
478 /*
479 * SunOS uses Trap #2 for a "CPU cache flush".
480 * Just flush the on-chip caches and return.
481 */
482 if (p->p_emul == &emul_sunos) {
483 ICIA();
484 DCIU();
485 return;
486 }
487 #endif
488 /* FALLTHROUGH */
489 case T_TRACE: /* tracing a trap instruction */
490 case T_TRAP15|T_USER: /* SUN user trace trap */
491 fp->f_sr &= ~PSL_T;
492 ksi.ksi_signo = SIGTRAP;
493 break;
494
495 case T_ASTFLT: /* system async trap, cannot happen */
496 goto dopanic;
497
498 case T_ASTFLT|T_USER: /* user async trap */
499 astpending = 0;
500 /*
501 * We check for software interrupts first. This is because
502 * they are at a higher level than ASTs, and on a VAX would
503 * interrupt the AST. We assume that if we are processing
504 * an AST that we must be at IPL0 so we don't bother to
505 * check. Note that we ensure that we are at least at SIR
506 * IPL while processing the SIR.
507 */
508 spl1();
509 /* fall into... */
510
511 case T_SSIR: /* software interrupt */
512 case T_SSIR|T_USER:
513 /*
514 * If this was not an AST trap, we are all done.
515 */
516 if (type != (T_ASTFLT|T_USER)) {
517 curcpu()->ci_data.cpu_ntrap--;
518 return;
519 }
520 spl0();
521 if (l->l_pflag & LP_OWEUPC) {
522 l->l_pflag &= ~LP_OWEUPC;
523 ADDUPROF(l);
524 }
525 goto out;
526
527 case T_MMUFLT: /* kernel mode page fault */
528 case T_MMUFLT|T_USER: /* page fault */
529 {
530 vaddr_t va;
531 struct vmspace *vm = p->p_vmspace;
532 struct vm_map *map;
533 vm_prot_t ftype;
534 extern struct vm_map *kernel_map;
535
536 onfault = pcb->pcb_onfault;
537
538 #ifdef DEBUG
539 if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid))
540 printf("trap: T_MMUFLT pid=%d, code=%x, v=%x, pc=%x, sr=%x\n",
541 p->p_pid, code, v, fp->f_pc, fp->f_sr);
542 #endif
543 /*
544 * It is only a kernel address space fault iff:
545 * 1. (type & T_USER) == 0 and
546 * 2. pcb_onfault not set or
547 * 3. pcb_onfault set but supervisor space data fault
548 * The last can occur during an exec() copyin where the
549 * argument space is lazy-allocated.
550 */
551 if ((type & T_USER) == 0 && (onfault == NULL || KDFAULT(code)))
552 map = kernel_map;
553 else {
554 map = vm ? &vm->vm_map : kernel_map;
555 }
556
557 if (WRFAULT(code))
558 ftype = VM_PROT_WRITE;
559 else
560 ftype = VM_PROT_READ;
561
562 va = trunc_page((vaddr_t)v);
563
564 if (map == kernel_map && va == 0) {
565 printf("trap: bad kernel %s access at 0x%x\n",
566 (ftype & VM_PROT_WRITE) ? "read/write" :
567 "read", v);
568 goto dopanic;
569 }
570
571 pcb->pcb_onfault = NULL;
572 rv = uvm_fault(map, va, ftype);
573 pcb->pcb_onfault = onfault;
574 #ifdef DEBUG
575 if (rv && MDB_ISPID(p->p_pid))
576 printf("uvm_fault(%p, 0x%lx, 0x%x) -> 0x%x\n",
577 map, va, ftype, rv);
578 #endif
579 /*
580 * If this was a stack access we keep track of the maximum
581 * accessed stack size. Also, if vm_fault gets a protection
582 * failure it is due to accessing the stack region outside
583 * the current limit and we need to reflect that as an access
584 * error.
585 */
586 if (rv == 0) {
587 if (map != kernel_map && (void *)va >= vm->vm_maxsaddr)
588 uvm_grow(p, va);
589
590 if (type == T_MMUFLT) {
591 #ifdef M68040
592 if (cputype == CPU_68040)
593 (void) m68040_writeback(fp, 1);
594 #endif
595 return;
596 }
597 goto out;
598 }
599 if (rv == EACCES) {
600 ksi.ksi_code = SEGV_ACCERR;
601 rv = EFAULT;
602 } else
603 ksi.ksi_code = SEGV_MAPERR;
604 if (type == T_MMUFLT) {
605 if (onfault)
606 goto copyfault;
607 printf("uvm_fault(%p, 0x%lx, 0x%x) -> 0x%x\n",
608 map, va, ftype, rv);
609 printf(" type %x, code [mmu,,ssw]: %x\n",
610 type, code);
611 goto dopanic;
612 }
613 ksi.ksi_addr = (void *)v;
614 switch (rv) {
615 case ENOMEM:
616 printf("UVM: pid %d (%s), uid %d killed: out of swap\n",
617 p->p_pid, p->p_comm,
618 l->l_cred ?
619 kauth_cred_geteuid(l->l_cred) : -1);
620 ksi.ksi_signo = SIGKILL;
621 break;
622 case EINVAL:
623 ksi.ksi_signo = SIGBUS;
624 ksi.ksi_code = BUS_ADRERR;
625 break;
626 case EACCES:
627 ksi.ksi_signo = SIGSEGV;
628 ksi.ksi_code = SEGV_ACCERR;
629 break;
630 default:
631 ksi.ksi_signo = SIGSEGV;
632 ksi.ksi_code = SEGV_MAPERR;
633 break;
634 }
635 break;
636 }
637 }
638 if (ksi.ksi_signo)
639 trapsignal(l, &ksi);
640 if ((type & T_USER) == 0)
641 return;
642 out:
643 userret(l, fp, sticks, v, 1);
644 }
645