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