exception.c revision 1.17
1/* $NetBSD: exception.c,v 1.17 2003/11/24 03:11:16 uwe Exp $ */ 2 3/*- 4 * Copyright (c) 1990 The Regents of the University of California. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * the University of Utah, and William Jolitz. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * @(#)trap.c 7.4 (Berkeley) 5/13/91 35 */ 36 37/*- 38 * Copyright (c) 2002 The NetBSD Foundation, Inc. All rights reserved. 39 * Copyright (c) 1995 Charles M. Hannum. All rights reserved. 40 * 41 * This code is derived from software contributed to Berkeley by 42 * the University of Utah, and William Jolitz. 43 * 44 * Redistribution and use in source and binary forms, with or without 45 * modification, are permitted provided that the following conditions 46 * are met: 47 * 1. Redistributions of source code must retain the above copyright 48 * notice, this list of conditions and the following disclaimer. 49 * 2. Redistributions in binary form must reproduce the above copyright 50 * notice, this list of conditions and the following disclaimer in the 51 * documentation and/or other materials provided with the distribution. 52 * 3. All advertising materials mentioning features or use of this software 53 * must display the following acknowledgement: 54 * This product includes software developed by the University of 55 * California, Berkeley and its contributors. 56 * 4. Neither the name of the University nor the names of its contributors 57 * may be used to endorse or promote products derived from this software 58 * without specific prior written permission. 59 * 60 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 61 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 62 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 63 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 64 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 65 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 66 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 67 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 68 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 69 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 70 * SUCH DAMAGE. 71 * 72 * @(#)trap.c 7.4 (Berkeley) 5/13/91 73 */ 74 75/* 76 * SH3 Trap and System call handling 77 * 78 * T.Horiuchi 1998.06.8 79 */ 80 81#include <sys/cdefs.h> 82__KERNEL_RCSID(0, "$NetBSD: exception.c,v 1.17 2003/11/24 03:11:16 uwe Exp $"); 83 84#include "opt_ddb.h" 85#include "opt_kgdb.h" 86#include "opt_syscall_debug.h" 87#include "opt_ktrace.h" 88#include "opt_systrace.h" 89 90#include <sys/param.h> 91#include <sys/systm.h> 92#include <sys/proc.h> 93#include <sys/pool.h> 94#include <sys/user.h> 95#include <sys/kernel.h> 96#include <sys/signal.h> 97#include <sys/syscall.h> 98#include <sys/sa.h> 99#include <sys/savar.h> 100 101#ifdef KTRACE 102#include <sys/ktrace.h> 103#endif 104#ifdef SYSTRACE 105#include <sys/systrace.h> 106#endif 107#ifdef DDB 108#include <sh3/db_machdep.h> 109#endif 110#ifdef KGDB 111#include <sys/kgdb.h> 112#endif 113 114#include <uvm/uvm_extern.h> 115 116#include <sh3/cpu.h> 117#include <sh3/mmu.h> 118#include <sh3/exception.h> 119#include <sh3/userret.h> 120 121const char *exp_type[] = { 122 "--", /* 0x000 (reset vector) */ 123 "--", /* 0x020 (reset vector) */ 124 "TLB miss/invalid (load)", /* 0x040 EXPEVT_TLB_MISS_LD */ 125 "TLB miss/invalid (store)", /* 0x060 EXPEVT_TLB_MISS_ST */ 126 "initial page write", /* 0x080 EXPEVT_TLB_MOD */ 127 "TLB protection violation (load)", /* 0x0a0 EXPEVT_TLB_PROT_LD */ 128 "TLB protection violation (store)", /* 0x0c0 EXPEVT_TLB_PROT_ST */ 129 "address error (load)", /* 0x0e0 EXPEVT_ADDR_ERR_LD */ 130 "address error (store)", /* 0x100 EXPEVT_ADDR_ERR_ST */ 131 "FPU", /* 0x120 EXPEVT_FPU */ 132 "--", /* 0x140 (reset vector) */ 133 "unconditional trap (TRAPA)", /* 0x160 EXPEVT_TRAPA */ 134 "reserved instruction code exception", /* 0x180 EXPEVT_RES_INST */ 135 "illegal slot instruction exception", /* 0x1a0 EXPEVT_SLOT_INST */ 136 "--", /* 0x1c0 (external interrupt) */ 137 "user break point trap", /* 0x1e0 EXPEVT_BREAK */ 138}; 139const int exp_types = sizeof exp_type / sizeof exp_type[0]; 140 141void general_exception(struct lwp *, struct trapframe *, uint32_t); 142void tlb_exception(struct lwp *, struct trapframe *, uint32_t); 143void syscall(struct lwp *, struct trapframe *); 144void ast(struct lwp *, struct trapframe *); 145 146/* 147 * void general_exception(struct lwp *l, struct trapframe *tf): 148 * l ... curlwp when exception occur. 149 * tf ... full user context. 150 * va ... fault va for user mode EXPEVT_ADDR_ERR_{LD,ST} 151 */ 152void 153general_exception(struct lwp *l, struct trapframe *tf, uint32_t va) 154{ 155 int expevt = tf->tf_expevt; 156 boolean_t usermode = !KERNELMODE(tf->tf_ssr); 157 ksiginfo_t ksi; 158 159 uvmexp.traps++; 160 161 if (l == NULL) 162 goto do_panic; 163 164 if (usermode) { 165 KDASSERT(l->l_md.md_regs == tf); /* check exception depth */ 166 expevt |= EXP_USER; 167 } 168 169 switch (expevt) { 170 case EXPEVT_TRAPA | EXP_USER: 171 /* Check for debugger break */ 172 if (_reg_read_4(SH_(TRA)) == (_SH_TRA_BREAK << 2)) { 173 tf->tf_spc -= 2; /* back to the breakpoint address */ 174 KSI_INIT_TRAP(&ksi); 175 ksi.ksi_signo = SIGTRAP; 176 ksi.ksi_code = TRAP_BRKPT; 177 ksi.ksi_addr = (void *)tf->tf_spc; 178 goto trapsignal; 179 } else { 180 syscall(l, tf); 181 return; 182 } 183 break; 184 185 case EXPEVT_ADDR_ERR_LD: 186 /*FALLTHROUGH*/ 187 case EXPEVT_ADDR_ERR_ST: 188 KDASSERT(l->l_md.md_pcb->pcb_onfault != NULL); 189 tf->tf_spc = (int)l->l_md.md_pcb->pcb_onfault; 190 if (tf->tf_spc == 0) 191 goto do_panic; 192 break; 193 194 case EXPEVT_ADDR_ERR_LD | EXP_USER: 195 /*FALLTHROUGH*/ 196 case EXPEVT_ADDR_ERR_ST | EXP_USER: 197 KSI_INIT_TRAP(&ksi); 198 if (((int)va) < 0) { 199 ksi.ksi_signo = SIGSEGV; 200 ksi.ksi_code = SEGV_ACCERR; 201 } else { 202 ksi.ksi_signo = SIGBUS; 203 ksi.ksi_code = BUS_ADRALN; 204 } 205 ksi.ksi_addr = (void *)va; 206 goto trapsignal; 207 208 case EXPEVT_RES_INST | EXP_USER: 209 /*FALLTHROUGH*/ 210 case EXPEVT_SLOT_INST | EXP_USER: 211 KSI_INIT_TRAP(&ksi); 212 ksi.ksi_signo = SIGILL; 213 ksi.ksi_code = ILL_ILLOPC; /* XXX: could be ILL_PRVOPC */ 214 ksi.ksi_addr = (void *)tf->tf_spc; 215 goto trapsignal; 216 217 case EXPEVT_BREAK | EXP_USER: 218 KSI_INIT_TRAP(&ksi); 219 ksi.ksi_signo = SIGTRAP; 220 ksi.ksi_code = TRAP_BRKPT; /* XXX: ??? */ 221 ksi.ksi_addr = (void *)tf->tf_spc; 222 goto trapsignal; 223 224 default: 225 goto do_panic; 226 } 227 228 if (usermode) 229 userret(l); 230 return; 231 232 trapsignal: 233 ksi.ksi_trap = tf->tf_expevt; 234 KERNEL_PROC_LOCK(l); 235 trapsignal(l, &ksi); 236 KERNEL_PROC_UNLOCK(l); 237 userret(l); 238 return; 239 240 do_panic: 241#ifdef DDB 242 if (kdb_trap(expevt, 0, tf)) 243 return; 244#endif 245#ifdef KGDB 246 if (kgdb_trap(EXPEVT_BREAK, tf)) 247 return; 248#endif 249 if (expevt >> 5 < exp_types) 250 printf("fatal %s", exp_type[expevt >> 5]); 251 else 252 printf("EXPEVT 0x%03x", expevt); 253 printf(" in %s mode\n", expevt & EXP_USER ? "user" : "kernel"); 254 printf(" spc %x ssr %x \n", tf->tf_spc, tf->tf_ssr); 255 256 panic("general_exception"); 257 while (/*CONSTCOND*/1) 258 ; 259 /*NOTREACHED*/ 260} 261 262/* 263 * void syscall(struct lwp *l, struct trapframe *tf): 264 * l ... curlwp when exception occur. 265 * tf ... full user context. 266 * System call request from POSIX system call gate interface to kernel. 267 */ 268void 269syscall(struct lwp *l, struct trapframe *tf) 270{ 271 struct proc *p = l->l_proc; 272 caddr_t params; 273 const struct sysent *callp; 274 int error, opc, nsys; 275 size_t argsize; 276 register_t code, args[8], rval[2], ocode; 277 278 uvmexp.syscalls++; 279 280 opc = tf->tf_spc; 281 ocode = code = tf->tf_r0; 282 283 nsys = p->p_emul->e_nsysent; 284 callp = p->p_emul->e_sysent; 285 286 params = (caddr_t)tf->tf_r15; 287 288 switch (code) { 289 case SYS_syscall: 290 /* 291 * Code is first argument, followed by actual args. 292 */ 293 code = tf->tf_r4; /* fuword(params); */ 294 /* params += sizeof(int); */ 295 break; 296 case SYS___syscall: 297 /* 298 * Like syscall, but code is a quad, so as to maintain 299 * quad alignment for the rest of the arguments. 300 */ 301 if (callp != sysent) 302 break; 303 /* fuword(params + _QUAD_LOWWORD * sizeof(int)); */ 304#if _BYTE_ORDER == BIG_ENDIAN 305 code = tf->tf_r5; 306#else 307 code = tf->tf_r4; 308#endif 309 /* params += sizeof(quad_t); */ 310 break; 311 default: 312 break; 313 } 314 if (code < 0 || code >= nsys) 315 callp += p->p_emul->e_nosys; /* illegal */ 316 else 317 callp += code; 318 argsize = callp->sy_argsize; 319 320 if (ocode == SYS_syscall) { 321 if (argsize) { 322 args[0] = tf->tf_r5; 323 args[1] = tf->tf_r6; 324 args[2] = tf->tf_r7; 325 if (argsize > 3 * sizeof(int)) { 326 argsize -= 3 * sizeof(int); 327 error = copyin(params, (caddr_t)&args[3], 328 argsize); 329 } else 330 error = 0; 331 } else 332 error = 0; 333 } 334 else if (ocode == SYS___syscall) { 335 if (argsize) { 336 args[0] = tf->tf_r6; 337 args[1] = tf->tf_r7; 338 if (argsize > 2 * sizeof(int)) { 339 argsize -= 2 * sizeof(int); 340 error = copyin(params, (caddr_t)&args[2], 341 argsize); 342 } else 343 error = 0; 344 } else 345 error = 0; 346 } else { 347 if (argsize) { 348 args[0] = tf->tf_r4; 349 args[1] = tf->tf_r5; 350 args[2] = tf->tf_r6; 351 args[3] = tf->tf_r7; 352 if (argsize > 4 * sizeof(int)) { 353 argsize -= 4 * sizeof(int); 354 error = copyin(params, (caddr_t)&args[4], 355 argsize); 356 } else 357 error = 0; 358 } else 359 error = 0; 360 } 361 362 if (error) 363 goto bad; 364 365 if ((error = trace_enter(l, code, code, NULL, args)) != 0) 366 goto bad; 367 368 rval[0] = 0; 369 rval[1] = tf->tf_r1; 370 error = (*callp->sy_call)(l, args, rval); 371 switch (error) { 372 case 0: 373 tf->tf_r0 = rval[0]; 374 tf->tf_r1 = rval[1]; 375 tf->tf_ssr |= PSL_TBIT; /* T bit */ 376 377 break; 378 case ERESTART: 379 /* 2 = TRAPA instruction size */ 380 tf->tf_spc = opc - 2; 381 382 break; 383 case EJUSTRETURN: 384 /* nothing to do */ 385 break; 386 default: 387 bad: 388 if (p->p_emul->e_errno) 389 error = p->p_emul->e_errno[error]; 390 tf->tf_r0 = error; 391 tf->tf_ssr &= ~PSL_TBIT; /* T bit */ 392 393 break; 394 } 395 396 397 trace_exit(l, code, args, rval, error); 398 399 userret(l); 400} 401 402/* 403 * void tlb_exception(struct lwp *l, struct trapframe *tf, uint32_t va): 404 * l ... curlwp when exception occur. 405 * tf ... full user context. 406 * va ... fault address. 407 */ 408void 409tlb_exception(struct lwp *l, struct trapframe *tf, uint32_t va) 410{ 411#define TLB_ASSERT(assert, msg) \ 412do { \ 413 if (!(assert)) { \ 414 panic_msg = msg; \ 415 goto tlb_panic; \ 416 } \ 417} while(/*CONSTCOND*/0) 418 struct vm_map *map; 419 pmap_t pmap; 420 ksiginfo_t ksi; 421 boolean_t usermode; 422 int err, track, ftype; 423 char *panic_msg; 424 425 usermode = !KERNELMODE(tf->tf_ssr); 426 if (usermode) { 427 KDASSERT(l->l_md.md_regs == tf); 428 } else { 429 KDASSERT(l == NULL || /* idle */ 430 l == &lwp0 || /* kthread */ 431 l->l_md.md_regs != tf); /* other */ 432 } 433 434 switch (tf->tf_expevt) { 435 case EXPEVT_TLB_MISS_LD: 436 track = PVH_REFERENCED; 437 ftype = VM_PROT_READ; 438 break; 439 case EXPEVT_TLB_MISS_ST: 440 track = PVH_REFERENCED; 441 ftype = VM_PROT_WRITE; 442 break; 443 case EXPEVT_TLB_MOD: 444 track = PVH_REFERENCED | PVH_MODIFIED; 445 ftype = VM_PROT_WRITE; 446 break; 447 case EXPEVT_TLB_PROT_LD: 448 TLB_ASSERT((int)va > 0, 449 "kernel virtual protection fault (load)"); 450 if (usermode) { 451 KSI_INIT_TRAP(&ksi); 452 ksi.ksi_signo = SIGSEGV; 453 ksi.ksi_code = SEGV_ACCERR; 454 ksi.ksi_addr = (void *)va; 455 goto user_fault; 456 } else { 457 TLB_ASSERT(l && l->l_md.md_pcb->pcb_onfault != NULL, 458 "no copyin/out fault handler (load protection)"); 459 tf->tf_spc = (int)l->l_md.md_pcb->pcb_onfault; 460 } 461 return; 462 463 case EXPEVT_TLB_PROT_ST: 464 track = 0; /* call uvm_fault first. (COW) */ 465 ftype = VM_PROT_WRITE; 466 break; 467 468 default: 469 TLB_ASSERT(0, "impossible expevt"); 470 } 471 472 /* Select address space */ 473 if (usermode) { 474 TLB_ASSERT(l != NULL, "no curlwp"); 475 map = &l->l_proc->p_vmspace->vm_map; 476 pmap = map->pmap; 477 } else { 478 if ((int)va < 0) { 479 map = kernel_map; 480 pmap = pmap_kernel(); 481 } else { 482 TLB_ASSERT(l != NULL && 483 l->l_md.md_pcb->pcb_onfault != NULL, 484 "invalid user-space access from kernel mode"); 485 if (va == 0) { 486 tf->tf_spc = (int)l->l_md.md_pcb->pcb_onfault; 487 return; 488 } 489 map = &l->l_proc->p_vmspace->vm_map; 490 pmap = map->pmap; 491 } 492 } 493 494 /* Lookup page table. if entry found, load it. */ 495 if (track && __pmap_pte_load(pmap, va, track)) { 496 if (usermode) 497 userret(l); 498 return; 499 } 500 501 /* Page not found. call fault handler */ 502 if (!usermode && pmap != pmap_kernel() && 503 l->l_md.md_pcb->pcb_faultbail) { 504 TLB_ASSERT(l->l_md.md_pcb->pcb_onfault != NULL, 505 "no copyin/out fault handler (interrupt context)"); 506 tf->tf_spc = (int)l->l_md.md_pcb->pcb_onfault; 507 return; 508 } 509 510 if ((map != kernel_map) && (l->l_flag & L_SA)) { 511 KDASSERT(l->l_proc != NULL && l->l_proc->p_sa != NULL); 512 l->l_proc->p_sa->sa_vp_faultaddr = (vaddr_t)va; 513 l->l_flag |= L_SA_PAGEFAULT; 514 } 515 516 err = uvm_fault(map, va, 0, ftype); 517 518 /* User stack extension */ 519 if (map != kernel_map && 520 (va >= (vaddr_t)l->l_proc->p_vmspace->vm_maxsaddr) && 521 (va < USRSTACK)) { 522 if (err == 0) { 523 struct vmspace *vm = l->l_proc->p_vmspace; 524 uint32_t nss; 525 nss = btoc(USRSTACK - va); 526 if (nss > vm->vm_ssize) 527 vm->vm_ssize = nss; 528 } else if (err == EACCES) { 529 err = EFAULT; 530 } 531 } 532 533 if (map != kernel_map) 534 l->l_flag &= ~L_SA_PAGEFAULT; 535 /* Page in. load PTE to TLB. */ 536 if (err == 0) { 537 boolean_t loaded = __pmap_pte_load(pmap, va, track); 538 TLB_ASSERT(loaded, "page table entry not found"); 539 if (usermode) 540 userret(l); 541 return; 542 } 543 544 /* Page not found. */ 545 if (usermode) { 546 KSI_INIT_TRAP(&ksi); 547 if (err == ENOMEM) 548 ksi.ksi_signo = SIGKILL; 549 else { 550 ksi.ksi_signo = SIGSEGV; 551 ksi.ksi_code = SEGV_MAPERR; 552 } 553 goto user_fault; 554 } else { 555 TLB_ASSERT(l->l_md.md_pcb->pcb_onfault, 556 "no copyin/out fault handler (page not found)"); 557 tf->tf_spc = (int)l->l_md.md_pcb->pcb_onfault; 558 } 559 return; 560 561 user_fault: 562 ksi.ksi_trap = tf->tf_expevt 563 KERNEL_PROC_LOCK(l); 564 trapsignal(l, &ksi); 565 KERNEL_PROC_UNLOCK(l); 566 userret(l); 567 ast(l, tf); 568 return; 569 570 tlb_panic: 571 panic("tlb_handler: %s va=0x%08x, ssr=0x%08x, spc=0x%08x" 572 " lwp=%p onfault=%p", panic_msg, va, tf->tf_ssr, tf->tf_spc, 573 l, l ? l->l_md.md_pcb->pcb_onfault : 0); 574#undef TLB_ASSERT 575} 576 577/* 578 * void ast(struct lwp *l, struct trapframe *tf): 579 * l ... curlwp when exception occur. 580 * tf ... full user context. 581 * This is called when exception return. if return from kernel to user, 582 * handle asynchronous software traps and context switch if needed. 583 */ 584void 585ast(struct lwp *l, struct trapframe *tf) 586{ 587 struct proc *p; 588 589 if (KERNELMODE(tf->tf_ssr)) 590 return; 591 KDASSERT(l != NULL); 592 KDASSERT(l->l_md.md_regs == tf); 593 594 p = l->l_proc; 595 596 while (p->p_md.md_astpending) { 597 uvmexp.softs++; 598 p->p_md.md_astpending = 0; 599 600 if (p->p_flag & P_OWEUPC) { 601 p->p_flag &= ~P_OWEUPC; 602 ADDUPROF(p); 603 } 604 605 if (want_resched) { 606 /* We are being preempted. */ 607 preempt(0); 608 } 609 610 userret(l); 611 } 612} 613 614/* 615 * void child_return(void *arg): 616 * 617 * uvm_fork sets this routine to proc_trampoline's service function. 618 * when return from here, jump to user-land. 619 */ 620void 621child_return(void *arg) 622{ 623 struct lwp *l = arg; 624#ifdef KTRACE 625 struct proc *p = l->l_proc; 626#endif 627 struct trapframe *tf = l->l_md.md_regs; 628 629 tf->tf_r0 = 0; 630 tf->tf_ssr |= PSL_TBIT; /* This indicates no error. */ 631 632 userret(l); 633#ifdef KTRACE 634 if (KTRPOINT(p, KTR_SYSRET)) 635 ktrsysret(p, SYS_fork, 0, 0); 636#endif 637} 638 639/* 640 * void startlwp(void *arg): 641 * 642 * Start a new LWP. 643 */ 644void 645startlwp(void *arg) 646{ 647 ucontext_t *uc = arg; 648 struct lwp *l = curlwp; 649 int error; 650 651 error = cpu_setmcontext(l, &uc->uc_mcontext, uc->uc_flags); 652#ifdef DIAGNOSTIC 653 if (error) 654 printf("startlwp: error %d from cpu_setmcontext()", error); 655#endif 656 pool_put(&lwp_uc_pool, uc); 657 658 userret(l); 659} 660 661/* 662 * void upcallret(struct lwp *l): 663 * 664 * Perform userret() for an LWP. 665 * XXX This is a terrible name. 666 */ 667void 668upcallret(struct lwp *l) 669{ 670 671 userret(l); 672} 673