trap.c revision 1.85
1331722Seadler/* $OpenBSD: trap.c,v 1.85 2005/04/07 00:23:51 mickey Exp $ */ 2239281Sgonzo 3239281Sgonzo/* 4239281Sgonzo * Copyright (c) 1998-2004 Michael Shalayeff 5239281Sgonzo * All rights reserved. 6239281Sgonzo * 7239281Sgonzo * Redistribution and use in source and binary forms, with or without 8239281Sgonzo * modification, are permitted provided that the following conditions 9239281Sgonzo * are met: 10239281Sgonzo * 1. Redistributions of source code must retain the above copyright 11239281Sgonzo * notice, this list of conditions and the following disclaimer. 12239281Sgonzo * 2. Redistributions in binary form must reproduce the above copyright 13239281Sgonzo * notice, this list of conditions and the following disclaimer in the 14239281Sgonzo * documentation and/or other materials provided with the distribution. 15239281Sgonzo * 16239281Sgonzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17239281Sgonzo * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18239281Sgonzo * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19239281Sgonzo * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, 20239281Sgonzo * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21239281Sgonzo * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22239281Sgonzo * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23239281Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24239281Sgonzo * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 25239281Sgonzo * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 26239281Sgonzo * THE POSSIBILITY OF SUCH DAMAGE. 27239281Sgonzo */ 28239281Sgonzo 29239281Sgonzo/* #define TRAPDEBUG */ 30239281Sgonzo 31239281Sgonzo#include <sys/param.h> 32239281Sgonzo#include <sys/systm.h> 33239281Sgonzo#include <sys/syscall.h> 34239281Sgonzo#include <sys/ktrace.h> 35239281Sgonzo#include <sys/proc.h> 36239281Sgonzo#include <sys/signalvar.h> 37239281Sgonzo#include <sys/user.h> 38239281Sgonzo 39239281Sgonzo#include <net/netisr.h> 40239281Sgonzo 41239281Sgonzo#include "systrace.h" 42239281Sgonzo#include <dev/systrace.h> 43239281Sgonzo 44239281Sgonzo#include <uvm/uvm.h> 45239281Sgonzo 46239281Sgonzo#include <machine/autoconf.h> 47239281Sgonzo 48239281Sgonzo#include <machine/db_machdep.h> /* XXX always needed for inst_store() */ 49239281Sgonzo#ifdef DDB 50239281Sgonzo#ifdef TRAPDEBUG 51239281Sgonzo#include <ddb/db_output.h> 52239281Sgonzo#endif 53239281Sgonzo#endif 54239281Sgonzo 55239281Sgonzoconst char *trap_type[] = { 56239281Sgonzo "invalid", 57239281Sgonzo "HPMC", 58239281Sgonzo "power failure", 59239281Sgonzo "recovery counter", 60239281Sgonzo "external interrupt", 61239281Sgonzo "LPMC", 62239281Sgonzo "ITLB miss fault", 63239281Sgonzo "instruction protection", 64239281Sgonzo "Illegal instruction", 65283276Sgonzo "break instruction", 66239281Sgonzo "privileged operation", 67239281Sgonzo "privileged register", 68239281Sgonzo "overflow", 69239281Sgonzo "conditional", 70239281Sgonzo "assist exception", 71239281Sgonzo "DTLB miss", 72239281Sgonzo "ITLB non-access miss", 73239281Sgonzo "DTLB non-access miss", 74239281Sgonzo "data protection/rights/alignment", 75239281Sgonzo "data break", 76239281Sgonzo "TLB dirty", 77239281Sgonzo "page reference", 78239281Sgonzo "assist emulation", 79239281Sgonzo "higher-priv transfer", 80239281Sgonzo "lower-priv transfer", 81239281Sgonzo "taken branch", 82239281Sgonzo "data access rights", 83239281Sgonzo "data protection", 84239281Sgonzo "unaligned data ref", 85239281Sgonzo}; 86239281Sgonzoint trap_types = sizeof(trap_type)/sizeof(trap_type[0]); 87239281Sgonzo 88239281Sgonzoint want_resched, astpending; 89239281Sgonzo 90261410Sian#define frame_regmap(tf,r) (((u_int *)(tf))[hppa_regmap[(r)]]) 91261410Sianu_char hppa_regmap[32] = { 92261410Sian offsetof(struct trapframe, tf_pad[0]) / 4, /* r0 XXX */ 93283276Sgonzo offsetof(struct trapframe, tf_r1) / 4, 94239281Sgonzo offsetof(struct trapframe, tf_rp) / 4, 95239281Sgonzo offsetof(struct trapframe, tf_r3) / 4, 96283276Sgonzo offsetof(struct trapframe, tf_r4) / 4, 97283276Sgonzo offsetof(struct trapframe, tf_r5) / 4, 98283276Sgonzo offsetof(struct trapframe, tf_r6) / 4, 99283276Sgonzo offsetof(struct trapframe, tf_r7) / 4, 100239281Sgonzo offsetof(struct trapframe, tf_r8) / 4, 101239281Sgonzo offsetof(struct trapframe, tf_r9) / 4, 102239281Sgonzo offsetof(struct trapframe, tf_r10) / 4, 103239281Sgonzo offsetof(struct trapframe, tf_r11) / 4, 104239281Sgonzo offsetof(struct trapframe, tf_r12) / 4, 105239281Sgonzo offsetof(struct trapframe, tf_r13) / 4, 106239281Sgonzo offsetof(struct trapframe, tf_r14) / 4, 107239281Sgonzo offsetof(struct trapframe, tf_r15) / 4, 108239281Sgonzo offsetof(struct trapframe, tf_r16) / 4, 109239281Sgonzo offsetof(struct trapframe, tf_r17) / 4, 110239281Sgonzo offsetof(struct trapframe, tf_r18) / 4, 111239281Sgonzo offsetof(struct trapframe, tf_t4) / 4, 112299069Spfg offsetof(struct trapframe, tf_t3) / 4, 113239281Sgonzo offsetof(struct trapframe, tf_t2) / 4, 114239281Sgonzo offsetof(struct trapframe, tf_t1) / 4, 115239281Sgonzo offsetof(struct trapframe, tf_arg3) / 4, 116239281Sgonzo offsetof(struct trapframe, tf_arg2) / 4, 117239281Sgonzo offsetof(struct trapframe, tf_arg1) / 4, 118239281Sgonzo offsetof(struct trapframe, tf_arg0) / 4, 119239281Sgonzo offsetof(struct trapframe, tf_dp) / 4, 120239281Sgonzo offsetof(struct trapframe, tf_ret0) / 4, 121239281Sgonzo offsetof(struct trapframe, tf_ret1) / 4, 122239281Sgonzo offsetof(struct trapframe, tf_sp) / 4, 123239281Sgonzo offsetof(struct trapframe, tf_r31) / 4, 124239281Sgonzo}; 125239281Sgonzo 126239281Sgonzovoid 127239281Sgonzouserret(struct proc *p, register_t pc, u_quad_t oticks) 128239281Sgonzo{ 129239281Sgonzo int sig; 130239281Sgonzo 131239281Sgonzo /* take pending signals */ 132310856Sloos while ((sig = CURSIG(p)) != 0) 133310856Sloos postsig(sig); 134310856Sloos 135310856Sloos p->p_priority = p->p_usrpri; 136239281Sgonzo if (astpending) { 137239281Sgonzo astpending = 0; 138239281Sgonzo if (p->p_flag & P_OWEUPC) { 139239281Sgonzo p->p_flag &= ~P_OWEUPC; 140239281Sgonzo ADDUPROF(p); 141239281Sgonzo } 142239281Sgonzo } 143239281Sgonzo if (want_resched) { 144239281Sgonzo /* 145239281Sgonzo * We're being preempted. 146239281Sgonzo */ 147239281Sgonzo preempt(NULL); 148239281Sgonzo while ((sig = CURSIG(p)) != 0) 149239281Sgonzo postsig(sig); 150239281Sgonzo } 151239281Sgonzo 152239281Sgonzo /* 153239281Sgonzo * If profiling, charge recent system time to the trapped pc. 154239281Sgonzo */ 155239281Sgonzo if (p->p_flag & P_PROFIL) { 156239281Sgonzo extern int psratio; 157239281Sgonzo 158239281Sgonzo addupc_task(p, pc, (int)(p->p_sticks - oticks) * psratio); 159239281Sgonzo } 160239281Sgonzo 161239281Sgonzo curpriority = p->p_priority; 162283276Sgonzo} 163239281Sgonzo 164239281Sgonzovoid 165239281Sgonzotrap(type, frame) 166239281Sgonzo int type; 167239281Sgonzo struct trapframe *frame; 168239281Sgonzo{ 169239281Sgonzo struct proc *p = curproc; 170239281Sgonzo vaddr_t va; 171239281Sgonzo struct vm_map *map; 172239281Sgonzo struct vmspace *vm; 173239281Sgonzo register vm_prot_t vftype; 174295660Sskra register pa_space_t space; 175295660Sskra union sigval sv; 176 u_int opcode; 177 int ret, trapnum; 178 const char *tts; 179 vm_fault_t fault = VM_FAULT_INVALID; 180#ifdef DIAGNOSTIC 181 int oldcpl = cpl; 182#endif 183 184 trapnum = type & ~T_USER; 185 opcode = frame->tf_iir; 186 if (trapnum <= T_EXCEPTION || trapnum == T_HIGHERPL || 187 trapnum == T_LOWERPL || trapnum == T_TAKENBR || 188 trapnum == T_IDEBUG || trapnum == T_PERFMON) { 189 va = frame->tf_iioq_head; 190 space = frame->tf_iisq_head; 191 vftype = UVM_PROT_EXEC; 192 } else { 193 va = frame->tf_ior; 194 space = frame->tf_isr; 195 if (va == frame->tf_iioq_head) 196 vftype = UVM_PROT_EXEC; 197 else if (inst_store(opcode)) 198 vftype = UVM_PROT_WRITE; 199 else 200 vftype = UVM_PROT_READ; 201 } 202 203 if (frame->tf_flags & TFF_LAST) 204 p->p_md.md_regs = frame; 205 206 if (trapnum > trap_types) 207 tts = "reserved"; 208 else 209 tts = trap_type[trapnum]; 210 211#ifdef TRAPDEBUG 212 if (trapnum != T_INTERRUPT && trapnum != T_IBREAK) 213 db_printf("trap: %x, %s for %x:%x at %x:%x, fl=%x, fp=%p\n", 214 type, tts, space, va, frame->tf_iisq_head, 215 frame->tf_iioq_head, frame->tf_flags, frame); 216 else if (trapnum == T_IBREAK) 217 db_printf("trap: break instruction %x:%x at %x:%x, fp=%p\n", 218 break5(opcode), break13(opcode), 219 frame->tf_iisq_head, frame->tf_iioq_head, frame); 220 221 { 222 extern int etext; 223 if (frame < (struct trapframe *)&etext) { 224 printf("trap: bogus frame ptr %p\n", frame); 225 goto dead_end; 226 } 227 } 228#endif 229 if (trapnum != T_INTERRUPT) { 230 uvmexp.traps++; 231 mtctl(frame->tf_eiem, CR_EIEM); 232 } 233 234 switch (type) { 235 case T_NONEXIST: 236 case T_NONEXIST | T_USER: 237 /* we've got screwed up by the central scrutinizer */ 238 printf("trap: elvis has just left the building!\n"); 239 goto dead_end; 240 241 case T_RECOVERY: 242 case T_RECOVERY | T_USER: 243 /* XXX will implement later */ 244 printf("trap: handicapped"); 245 goto dead_end; 246 247#ifdef DIAGNOSTIC 248 case T_EXCEPTION: 249 panic("FPU/SFU emulation botch"); 250 251 /* these just can't happen ever */ 252 case T_PRIV_OP: 253 case T_PRIV_REG: 254 /* these just can't make it to the trap() ever */ 255 case T_HPMC: 256 case T_HPMC | T_USER: 257#endif 258 case T_IBREAK: 259 case T_DATALIGN: 260 case T_DBREAK: 261 dead_end: 262#ifdef DDB 263 if (kdb_trap (type, va, frame)) { 264 if (type == T_IBREAK) { 265 /* skip break instruction */ 266 frame->tf_iioq_head = frame->tf_iioq_tail; 267 frame->tf_iioq_tail += 4; 268 } 269 return; 270 } 271#else 272 if (type == T_DATALIGN) 273 panic ("trap: %s at 0x%x", tts, va); 274 else 275 panic ("trap: no debugger for \"%s\" (%d)", tts, type); 276#endif 277 break; 278 279 case T_IBREAK | T_USER: 280 case T_DBREAK | T_USER: 281 /* pass to user debugger */ 282 trapsignal(p, SIGTRAP, type &~ T_USER, TRAP_BRKPT, sv); 283 break; 284 285 case T_EXCEPTION | T_USER: { 286 u_int64_t *fpp = (u_int64_t *)frame->tf_cr30; 287 u_int32_t *pex; 288 int i, flt; 289 290 pex = (u_int32_t *)&fpp[0]; 291 for (i = 0, pex++; i < 7 && !*pex; i++, pex++); 292 flt = 0; 293 if (i < 7) { 294 u_int32_t stat = HPPA_FPU_OP(*pex); 295 if (stat & HPPA_FPU_UNMPL) 296 flt = FPE_FLTINV; 297 else if (stat & (HPPA_FPU_V << 1)) 298 flt = FPE_FLTINV; 299 else if (stat & (HPPA_FPU_Z << 1)) 300 flt = FPE_FLTDIV; 301 else if (stat & (HPPA_FPU_I << 1)) 302 flt = FPE_FLTRES; 303 else if (stat & (HPPA_FPU_O << 1)) 304 flt = FPE_FLTOVF; 305 else if (stat & (HPPA_FPU_U << 1)) 306 flt = FPE_FLTUND; 307 /* still left: under/over-flow w/ inexact */ 308 309 /* cleanup exceptions (XXX deliver all ?) */ 310 while (i++ < 7) 311 *pex++ = 0; 312 } 313 /* reset the trap flag, as if there was none */ 314 fpp[0] &= ~(((u_int64_t)HPPA_FPU_T) << 32); 315 /* flush out, since load is done from phys, only 4 regs */ 316 fdcache(HPPA_SID_KERNEL, (vaddr_t)fpp, 8 * 4); 317 318 sv.sival_int = va; 319 trapsignal(p, SIGFPE, type &~ T_USER, flt, sv); 320 } 321 break; 322 323 case T_EMULATION: 324 panic("trap: emulation trap in the kernel"); 325 break; 326 327 case T_EMULATION | T_USER: 328 sv.sival_int = va; 329 trapsignal(p, SIGILL, type &~ T_USER, ILL_COPROC, sv); 330 break; 331 332 case T_OVERFLOW | T_USER: 333 sv.sival_int = va; 334 trapsignal(p, SIGFPE, type &~ T_USER, FPE_INTOVF, sv); 335 break; 336 337 case T_CONDITION | T_USER: 338 sv.sival_int = va; 339 trapsignal(p, SIGFPE, type &~ T_USER, FPE_INTDIV, sv); 340 break; 341 342 case T_PRIV_OP | T_USER: 343 sv.sival_int = va; 344 trapsignal(p, SIGILL, type &~ T_USER, ILL_PRVOPC, sv); 345 break; 346 347 case T_PRIV_REG | T_USER: 348 sv.sival_int = va; 349 trapsignal(p, SIGILL, type &~ T_USER, ILL_PRVREG, sv); 350 break; 351 352 /* these should never got here */ 353 case T_HIGHERPL | T_USER: 354 case T_LOWERPL | T_USER: 355 sv.sival_int = va; 356 trapsignal(p, SIGSEGV, vftype, SEGV_ACCERR, sv); 357 break; 358 359 case T_IPROT | T_USER: 360 case T_DPROT | T_USER: 361 sv.sival_int = va; 362 trapsignal(p, SIGSEGV, vftype, SEGV_ACCERR, sv); 363 break; 364 365 case T_ITLBMISSNA: 366 case T_ITLBMISSNA | T_USER: 367 case T_DTLBMISSNA: 368 case T_DTLBMISSNA | T_USER: 369 if (space == HPPA_SID_KERNEL) 370 map = kernel_map; 371 else { 372 vm = p->p_vmspace; 373 map = &vm->vm_map; 374 } 375 376 if ((opcode & 0xfc003fc0) == 0x04001340) { 377 /* lpa failure case */ 378 frame_regmap(frame, opcode & 0x1f) = 0; 379 frame->tf_ipsw |= PSL_N; 380 } else if ((opcode & 0xfc001f80) == 0x04001180) { 381 int pl; 382 383 /* dig probe[rw]i? insns */ 384 if (opcode & 0x2000) 385 pl = (opcode >> 16) & 3; 386 else 387 pl = frame_regmap(frame, 388 (opcode >> 16) & 0x1f) & 3; 389 390 if ((type & T_USER && space == HPPA_SID_KERNEL) || 391 (frame->tf_iioq_head & 3) != pl || 392 (type & T_USER && va >= VM_MAXUSER_ADDRESS) || 393 uvm_fault(map, hppa_trunc_page(va), fault, 394 opcode & 0x40? UVM_PROT_WRITE : UVM_PROT_READ)) { 395 frame_regmap(frame, opcode & 0x1f) = 0; 396 frame->tf_ipsw |= PSL_N; 397 } 398 } else if (type & T_USER) { 399 sv.sival_int = va; 400 trapsignal(p, SIGILL, type & ~T_USER, ILL_ILLTRP, sv); 401 } else 402 panic("trap: %s @ 0x%x:0x%x for 0x%x:0x%x irr 0x%08x\n", 403 tts, frame->tf_iisq_head, frame->tf_iioq_head, 404 space, va, opcode); 405 break; 406 407 case T_TLB_DIRTY: 408 case T_TLB_DIRTY | T_USER: 409 case T_DATACC: 410 case T_DATACC | T_USER: 411 fault = VM_FAULT_PROTECT; 412 case T_ITLBMISS: 413 case T_ITLBMISS | T_USER: 414 case T_DTLBMISS: 415 case T_DTLBMISS | T_USER: 416 /* 417 * it could be a kernel map for exec_map faults 418 */ 419 if (space == HPPA_SID_KERNEL) 420 map = kernel_map; 421 else { 422 vm = p->p_vmspace; 423 map = &vm->vm_map; 424 } 425 426 /* 427 * user faults out of user addr space are always a fail, 428 * this happens on va >= VM_MAXUSER_ADDRESS, where 429 * space id will be zero and therefore cause 430 * a misbehave lower in the code. 431 * 432 * also check that faulted space id matches the curproc. 433 */ 434 if ((type & T_USER && va >= VM_MAXUSER_ADDRESS) || 435 (type & T_USER && map->pmap->pm_space != space)) { 436 sv.sival_int = va; 437 trapsignal(p, SIGSEGV, vftype, SEGV_MAPERR, sv); 438 break; 439 } 440 441 ret = uvm_fault(map, hppa_trunc_page(va), fault, vftype); 442 443 /* 444 * If this was a stack access we keep track of the maximum 445 * accessed stack size. Also, if uvm_fault gets a protection 446 * failure it is due to accessing the stack region outside 447 * the current limit and we need to reflect that as an access 448 * error. 449 */ 450 if (space != HPPA_SID_KERNEL && 451 va < (vaddr_t)vm->vm_minsaddr) { 452 if (ret == 0) 453 uvm_grow(p, va); 454 else if (ret == EACCES) 455 ret = EFAULT; 456 } 457 458 if (ret != 0) { 459 if (type & T_USER) { 460 sv.sival_int = va; 461 trapsignal(p, SIGSEGV, vftype, 462 ret == EACCES? SEGV_ACCERR : SEGV_MAPERR, 463 sv); 464 } else { 465 if (p && p->p_addr->u_pcb.pcb_onfault) { 466 frame->tf_iioq_tail = 4 + 467 (frame->tf_iioq_head = 468 p->p_addr->u_pcb.pcb_onfault); 469#ifdef DDB 470 frame->tf_iir = 0; 471#endif 472 } else { 473 panic("trap: " 474 "uvm_fault(%p, %lx, %d, %d): %d", 475 map, va, fault, vftype, ret); 476 } 477 } 478 } 479 break; 480 481 case T_DATALIGN | T_USER: 482 sv.sival_int = va; 483 trapsignal(p, SIGBUS, vftype, BUS_ADRALN, sv); 484 break; 485 486 case T_INTERRUPT: 487 case T_INTERRUPT | T_USER: 488 cpu_intr(frame); 489 break; 490 491 case T_CONDITION: 492 panic("trap: divide by zero in the kernel"); 493 break; 494 495 case T_ILLEGAL: 496 case T_ILLEGAL | T_USER: 497 /* see if it's a SPOP1,,0 */ 498 if ((opcode & 0xfffffe00) == 0x10000200) { 499 frame_regmap(frame, opcode & 0x1f) = 0; 500 frame->tf_ipsw |= PSL_N; 501 break; 502 } 503 if (type & T_USER) { 504 sv.sival_int = va; 505 trapsignal(p, SIGILL, type &~ T_USER, ILL_ILLOPC, sv); 506 break; 507 } 508 /* FALLTHROUGH */ 509 510 case T_LOWERPL: 511 case T_DPROT: 512 case T_IPROT: 513 case T_OVERFLOW: 514 case T_HIGHERPL: 515 case T_TAKENBR: 516 case T_POWERFAIL: 517 case T_LPMC: 518 case T_PAGEREF: 519 case T_DATAPID: 520 case T_DATAPID | T_USER: 521 if (0 /* T-chip */) { 522 break; 523 } 524 /* FALLTHROUGH to unimplemented */ 525 default: 526#if 0 527if (kdb_trap (type, va, frame)) 528 return; 529#endif 530 panic("trap: unimplemented \'%s\' (%d)", tts, trapnum); 531 } 532 533#ifdef DIAGNOSTIC 534 if (cpl != oldcpl) 535 printf("WARNING: SPL (%d) NOT LOWERED ON " 536 "TRAP (%d) EXIT\n", cpl, trapnum); 537#endif 538 539 if (trapnum != T_INTERRUPT) 540 splx(cpl); /* process softints */ 541 542 /* 543 * in case we were interrupted from the syscall gate page 544 * treat this as we were not realy running user code no more 545 * for weird things start to happen on return to the userland 546 * and also see a note in locore.S:TLABEL(all) 547 */ 548 if ((type & T_USER) && 549 (frame->tf_iioq_head & ~PAGE_MASK) != SYSCALLGATE) 550 userret(p, frame->tf_iioq_head, 0); 551} 552 553void 554child_return(arg) 555 void *arg; 556{ 557 struct proc *p = (struct proc *)arg; 558 struct trapframe *tf = p->p_md.md_regs; 559 560 /* 561 * Set up return value registers as libc:fork() expects 562 */ 563 tf->tf_ret0 = 0; 564 tf->tf_ret1 = 1; /* ischild */ 565 tf->tf_t1 = 0; /* errno */ 566 567 userret(p, tf->tf_iioq_head, 0); 568#ifdef KTRACE 569 if (KTRPOINT(p, KTR_SYSRET)) 570 ktrsysret(p, SYS_fork, 0, 0); 571#endif 572} 573 574 575/* 576 * call actual syscall routine 577 */ 578void 579syscall(struct trapframe *frame) 580{ 581 register struct proc *p = curproc; 582 register const struct sysent *callp; 583 int retq, nsys, code, argsize, argoff, oerror, error; 584 register_t args[8], rval[2]; 585#ifdef DIAGNOSTIC 586 int oldcpl = cpl; 587#endif 588 589 uvmexp.syscalls++; 590 591 if (!USERMODE(frame->tf_iioq_head)) 592 panic("syscall"); 593 594 p->p_md.md_regs = frame; 595 nsys = p->p_emul->e_nsysent; 596 callp = p->p_emul->e_sysent; 597 598 argoff = 4; retq = 0; 599 switch (code = frame->tf_t1) { 600 case SYS_syscall: 601 code = frame->tf_arg0; 602 args[0] = frame->tf_arg1; 603 args[1] = frame->tf_arg2; 604 args[2] = frame->tf_arg3; 605 argoff = 3; 606 break; 607 case SYS___syscall: 608 if (callp != sysent) 609 break; 610 /* 611 * this works, because quads get magically swapped 612 * due to the args being laid backwards on the stack 613 * and then copied in words 614 */ 615 code = frame->tf_arg0; 616 args[0] = frame->tf_arg2; 617 args[1] = frame->tf_arg3; 618 argoff = 2; 619 retq = 1; 620 break; 621 default: 622 args[0] = frame->tf_arg0; 623 args[1] = frame->tf_arg1; 624 args[2] = frame->tf_arg2; 625 args[3] = frame->tf_arg3; 626 break; 627 } 628 629 if (code < 0 || code >= nsys) 630 callp += p->p_emul->e_nosys; /* bad syscall # */ 631 else 632 callp += code; 633 634 oerror = error = 0; 635 if ((argsize = callp->sy_argsize)) { 636 int i; 637 638 for (i = 0, argsize -= argoff * 4; 639 argsize > 0; i++, argsize -= 4) { 640 error = copyin((void *)(frame->tf_sp + 641 HPPA_FRAME_ARG(i + 4)), args + i + argoff, 4); 642 643 if (error) 644 break; 645 } 646 647 /* 648 * coming from syscall() or __syscall we must be 649 * having one of those w/ a 64 bit arguments, 650 * which needs a word swap due to the order 651 * of the arguments on the stack. 652 * this assumes that none of 'em are called 653 * by their normal syscall number, maybe a regress 654 * test should be used, to watch the behaviour. 655 */ 656 if (!error && argoff < 4) { 657 int t; 658 659 i = 0; 660 switch (code) { 661 case SYS_lseek: retq = 0; 662 case SYS_truncate: 663 case SYS_ftruncate: i = 2; break; 664 case SYS_preadv: 665 case SYS_pwritev: 666 case SYS_pread: 667 case SYS_pwrite: i = 4; break; 668 case SYS_mmap: i = 6; break; 669 } 670 671 if (i) { 672 t = args[i]; 673 args[i] = args[i + 1]; 674 args[i + 1] = t; 675 } 676 } 677 } 678 679#ifdef SYSCALL_DEBUG 680 scdebug_call(p, code, args); 681#endif 682#ifdef KTRACE 683 if (KTRPOINT(p, KTR_SYSCALL)) 684 ktrsyscall(p, code, callp->sy_argsize, args); 685#endif 686 if (error) 687 goto bad; 688 689 rval[0] = 0; 690 rval[1] = frame->tf_ret1; 691#if NSYSTRACE > 0 692 if (ISSET(p->p_flag, P_SYSTRACE)) 693 oerror = error = systrace_redirect(code, p, args, rval); 694 else 695#endif 696 oerror = error = (*callp->sy_call)(p, args, rval); 697 p = curproc; 698 frame = p->p_md.md_regs; 699 switch (error) { 700 case 0: 701 frame->tf_ret0 = rval[0]; 702 frame->tf_ret1 = rval[!retq]; 703 frame->tf_t1 = 0; 704 break; 705 case ERESTART: 706 frame->tf_iioq_head -= 12; 707 frame->tf_iioq_tail -= 12; 708 case EJUSTRETURN: 709 break; 710 default: 711 bad: 712 if (p->p_emul->e_errno) 713 error = p->p_emul->e_errno[error]; 714 frame->tf_t1 = error; 715 frame->tf_ret0 = error; 716 frame->tf_ret1 = 0; 717 break; 718 } 719#ifdef SYSCALL_DEBUG 720 scdebug_ret(p, code, oerror, rval); 721#endif 722 userret(p, frame->tf_iioq_head, 0); 723#ifdef KTRACE 724 if (KTRPOINT(p, KTR_SYSRET)) 725 ktrsysret(p, code, oerror, rval[0]); 726#endif 727#ifdef DIAGNOSTIC 728 if (cpl != oldcpl) { 729 printf("WARNING: SPL (0x%x) NOT LOWERED ON " 730 "syscall(0x%x, 0x%x, 0x%x, 0x%x...) EXIT, PID %d\n", 731 cpl, code, args[0], args[1], args[2], p->p_pid); 732 cpl = oldcpl; 733 } 734#endif 735 splx(cpl); /* process softints */ 736} 737