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