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