trap.c revision 1.114
1/* $OpenBSD: trap.c,v 1.114 2011/04/03 14:56:28 guenther Exp $ */ 2 3/* 4 * Copyright (c) 1998-2004 Michael Shalayeff 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 25 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 26 * THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29/* #define TRAPDEBUG */ 30 31#include <sys/param.h> 32#include <sys/systm.h> 33#include <sys/syscall.h> 34#include <sys/ktrace.h> 35#include <sys/proc.h> 36#include <sys/signalvar.h> 37#include <sys/user.h> 38 39#include "systrace.h" 40#include <dev/systrace.h> 41 42#include <uvm/uvm.h> 43 44#include <machine/autoconf.h> 45 46#ifdef DDB 47#ifdef TRAPDEBUG 48#include <ddb/db_output.h> 49#else 50#include <machine/db_machdep.h> 51#endif 52#endif 53 54static __inline int inst_store(u_int ins) { 55 return (ins & 0xf0000000) == 0x60000000 || /* st */ 56 (ins & 0xf4000200) == 0x24000200 || /* fst/cst */ 57 (ins & 0xfc000200) == 0x0c000200 || /* stby */ 58 (ins & 0xfc0003c0) == 0x0c0001c0; /* ldcw */ 59} 60 61int pcxs_unaligned(u_int opcode, vaddr_t va); 62#ifdef PTRACE 63void ss_clear_breakpoints(struct proc *p); 64#endif 65 66/* single-step breakpoint */ 67#define SSBREAKPOINT (HPPA_BREAK_KERNEL | (HPPA_BREAK_SS << 13)) 68 69const char *trap_type[] = { 70 "invalid", 71 "HPMC", 72 "power failure", 73 "recovery counter", 74 "external interrupt", 75 "LPMC", 76 "ITLB miss fault", 77 "instruction protection", 78 "Illegal instruction", 79 "break instruction", 80 "privileged operation", 81 "privileged register", 82 "overflow", 83 "conditional", 84 "assist exception", 85 "DTLB miss", 86 "ITLB non-access miss", 87 "DTLB non-access miss", 88 "data protection/rights/alignment", 89 "data break", 90 "TLB dirty", 91 "page reference", 92 "assist emulation", 93 "higher-priv transfer", 94 "lower-priv transfer", 95 "taken branch", 96 "data access rights", 97 "data protection", 98 "unaligned data ref", 99}; 100int trap_types = sizeof(trap_type)/sizeof(trap_type[0]); 101 102#define frame_regmap(tf,r) (((u_int *)(tf))[hppa_regmap[(r)]]) 103u_char hppa_regmap[32] = { 104 offsetof(struct trapframe, tf_pad[0]) / 4, /* r0 XXX */ 105 offsetof(struct trapframe, tf_r1) / 4, 106 offsetof(struct trapframe, tf_rp) / 4, 107 offsetof(struct trapframe, tf_r3) / 4, 108 offsetof(struct trapframe, tf_r4) / 4, 109 offsetof(struct trapframe, tf_r5) / 4, 110 offsetof(struct trapframe, tf_r6) / 4, 111 offsetof(struct trapframe, tf_r7) / 4, 112 offsetof(struct trapframe, tf_r8) / 4, 113 offsetof(struct trapframe, tf_r9) / 4, 114 offsetof(struct trapframe, tf_r10) / 4, 115 offsetof(struct trapframe, tf_r11) / 4, 116 offsetof(struct trapframe, tf_r12) / 4, 117 offsetof(struct trapframe, tf_r13) / 4, 118 offsetof(struct trapframe, tf_r14) / 4, 119 offsetof(struct trapframe, tf_r15) / 4, 120 offsetof(struct trapframe, tf_r16) / 4, 121 offsetof(struct trapframe, tf_r17) / 4, 122 offsetof(struct trapframe, tf_r18) / 4, 123 offsetof(struct trapframe, tf_t4) / 4, 124 offsetof(struct trapframe, tf_t3) / 4, 125 offsetof(struct trapframe, tf_t2) / 4, 126 offsetof(struct trapframe, tf_t1) / 4, 127 offsetof(struct trapframe, tf_arg3) / 4, 128 offsetof(struct trapframe, tf_arg2) / 4, 129 offsetof(struct trapframe, tf_arg1) / 4, 130 offsetof(struct trapframe, tf_arg0) / 4, 131 offsetof(struct trapframe, tf_dp) / 4, 132 offsetof(struct trapframe, tf_ret0) / 4, 133 offsetof(struct trapframe, tf_ret1) / 4, 134 offsetof(struct trapframe, tf_sp) / 4, 135 offsetof(struct trapframe, tf_r31) / 4, 136}; 137 138void userret(struct proc *p); 139 140void 141userret(struct proc *p) 142{ 143 int sig; 144 145 if (p->p_md.md_astpending) { 146 p->p_md.md_astpending = 0; 147 uvmexp.softs++; 148 if (p->p_flag & P_OWEUPC) { 149 KERNEL_PROC_LOCK(p); 150 ADDUPROF(p); 151 KERNEL_PROC_UNLOCK(p); 152 } 153 if (curcpu()->ci_want_resched) 154 preempt(NULL); 155 } 156 157 while ((sig = CURSIG(p)) != 0) 158 postsig(sig); 159 160 p->p_cpu->ci_schedstate.spc_curpriority = p->p_priority = p->p_usrpri; 161} 162 163void 164trap(int type, struct trapframe *frame) 165{ 166 struct proc *p = curproc; 167 vaddr_t va; 168 struct vm_map *map; 169 struct vmspace *vm; 170 register vm_prot_t vftype; 171 register pa_space_t space; 172 union sigval sv; 173 u_int opcode; 174 int ret, trapnum; 175 const char *tts; 176 vm_fault_t fault = VM_FAULT_INVALID; 177#ifdef DIAGNOSTIC 178 int oldcpl = curcpu()->ci_cpl; 179#endif 180 181 trapnum = type & ~T_USER; 182 opcode = frame->tf_iir; 183 if (trapnum <= T_EXCEPTION || trapnum == T_HIGHERPL || 184 trapnum == T_LOWERPL || trapnum == T_TAKENBR || 185 trapnum == T_IDEBUG || trapnum == T_PERFMON) { 186 va = frame->tf_iioq_head; 187 space = frame->tf_iisq_head; 188 vftype = UVM_PROT_EXEC; 189 } else { 190 va = frame->tf_ior; 191 space = frame->tf_isr; 192 if (va == frame->tf_iioq_head) 193 vftype = UVM_PROT_EXEC; 194 else if (inst_store(opcode)) 195 vftype = UVM_PROT_WRITE; 196 else 197 vftype = UVM_PROT_READ; 198 } 199 200 if (frame->tf_flags & TFF_LAST) 201 p->p_md.md_regs = frame; 202 203 if (trapnum > trap_types) 204 tts = "reserved"; 205 else 206 tts = trap_type[trapnum]; 207 208#ifdef TRAPDEBUG 209 if (trapnum != T_INTERRUPT && trapnum != T_IBREAK) 210 db_printf("trap: %x, %s for %x:%x at %x:%x, fl=%x, fp=%p\n", 211 type, tts, space, va, frame->tf_iisq_head, 212 frame->tf_iioq_head, frame->tf_flags, frame); 213 else if (trapnum == T_IBREAK) 214 db_printf("trap: break instruction %x:%x at %x:%x, fp=%p\n", 215 break5(opcode), break13(opcode), 216 frame->tf_iisq_head, frame->tf_iioq_head, frame); 217 218 { 219 extern int etext; 220 if (frame < (struct trapframe *)&etext) { 221 printf("trap: bogus frame ptr %p\n", frame); 222 goto dead_end; 223 } 224 } 225#endif 226 if (trapnum != T_INTERRUPT) { 227 uvmexp.traps++; 228 mtctl(frame->tf_eiem, CR_EIEM); 229 } 230 231 switch (type) { 232 case T_NONEXIST: 233 case T_NONEXIST | T_USER: 234 /* we've got screwed up by the central scrutinizer */ 235 printf("trap: elvis has just left the building!\n"); 236 goto dead_end; 237 238 case T_RECOVERY: 239 case T_RECOVERY | T_USER: 240 /* XXX will implement later */ 241 printf("trap: handicapped"); 242 goto dead_end; 243 244#ifdef DIAGNOSTIC 245 case T_EXCEPTION: 246 panic("FPU/SFU emulation botch"); 247 248 /* these just can't happen ever */ 249 case T_PRIV_OP: 250 case T_PRIV_REG: 251 /* these just can't make it to the trap() ever */ 252 case T_HPMC: 253 case T_HPMC | T_USER: 254#endif 255 case T_IBREAK: 256 case T_DATALIGN: 257 case T_DBREAK: 258 dead_end: 259#ifdef DDB 260 if (kdb_trap (type, va, frame)) { 261 if (type == T_IBREAK) { 262 /* skip break instruction */ 263 frame->tf_iioq_head = frame->tf_iioq_tail; 264 frame->tf_iioq_tail += 4; 265 } 266 return; 267 } 268#else 269 if (type == T_DATALIGN || type == T_DPROT) 270 panic ("trap: %s at 0x%x", tts, va); 271 else 272 panic ("trap: no debugger for \"%s\" (%d)", tts, type); 273#endif 274 break; 275 276 case T_IBREAK | T_USER: 277 case T_DBREAK | T_USER: { 278 int code = TRAP_BRKPT; 279#ifdef PTRACE 280 ss_clear_breakpoints(p); 281 if (opcode == SSBREAKPOINT) 282 code = TRAP_TRACE; 283#endif 284 /* pass to user debugger */ 285 KERNEL_PROC_LOCK(p); 286 trapsignal(p, SIGTRAP, type &~ T_USER, code, sv); 287 KERNEL_PROC_UNLOCK(p); 288 } 289 break; 290 291#ifdef PTRACE 292 case T_TAKENBR | T_USER: 293 ss_clear_breakpoints(p); 294 295 /* pass to user debugger */ 296 KERNEL_PROC_LOCK(p); 297 trapsignal(p, SIGTRAP, type &~ T_USER, TRAP_TRACE, sv); 298 KERNEL_PROC_UNLOCK(p); 299 break; 300#endif 301 302 case T_EXCEPTION | T_USER: { 303 struct hppa_fpstate *hfp; 304 u_int64_t *fpp; 305 u_int32_t *pex; 306 int i, flt; 307 308 hfp = (struct hppa_fpstate *)frame->tf_cr30; 309 fpp = (u_int64_t *)&hfp->hfp_regs; 310 311 pex = (u_int32_t *)&fpp[0]; 312 for (i = 0, pex++; i < 7 && !*pex; i++, pex++); 313 flt = 0; 314 if (i < 7) { 315 u_int32_t stat = HPPA_FPU_OP(*pex); 316 if (stat & HPPA_FPU_UNMPL) 317 flt = FPE_FLTINV; 318 else if (stat & (HPPA_FPU_V << 1)) 319 flt = FPE_FLTINV; 320 else if (stat & (HPPA_FPU_Z << 1)) 321 flt = FPE_FLTDIV; 322 else if (stat & (HPPA_FPU_I << 1)) 323 flt = FPE_FLTRES; 324 else if (stat & (HPPA_FPU_O << 1)) 325 flt = FPE_FLTOVF; 326 else if (stat & (HPPA_FPU_U << 1)) 327 flt = FPE_FLTUND; 328 /* still left: under/over-flow w/ inexact */ 329 330 /* cleanup exceptions (XXX deliver all ?) */ 331 while (i++ < 7) 332 *pex++ = 0; 333 } 334 /* reset the trap flag, as if there was none */ 335 fpp[0] &= ~(((u_int64_t)HPPA_FPU_T) << 32); 336 337 sv.sival_int = va; 338 KERNEL_PROC_LOCK(p); 339 trapsignal(p, SIGFPE, type &~ T_USER, flt, sv); 340 KERNEL_PROC_UNLOCK(p); 341 } 342 break; 343 344 case T_EMULATION: 345 panic("trap: emulation trap in the kernel"); 346 break; 347 348 case T_EMULATION | T_USER: 349 sv.sival_int = va; 350 KERNEL_PROC_LOCK(p); 351 trapsignal(p, SIGILL, type &~ T_USER, ILL_COPROC, sv); 352 KERNEL_PROC_UNLOCK(p); 353 break; 354 355 case T_OVERFLOW | T_USER: 356 sv.sival_int = va; 357 KERNEL_PROC_LOCK(p); 358 trapsignal(p, SIGFPE, type &~ T_USER, FPE_INTOVF, sv); 359 KERNEL_PROC_UNLOCK(p); 360 break; 361 362 case T_CONDITION | T_USER: 363 sv.sival_int = va; 364 KERNEL_PROC_LOCK(p); 365 trapsignal(p, SIGFPE, type &~ T_USER, FPE_INTDIV, sv); 366 KERNEL_PROC_UNLOCK(p); 367 break; 368 369 case T_PRIV_OP | T_USER: 370 sv.sival_int = va; 371 KERNEL_PROC_LOCK(p); 372 trapsignal(p, SIGILL, type &~ T_USER, ILL_PRVOPC, sv); 373 KERNEL_PROC_UNLOCK(p); 374 break; 375 376 case T_PRIV_REG | T_USER: 377 sv.sival_int = va; 378 KERNEL_PROC_LOCK(p); 379 trapsignal(p, SIGILL, type &~ T_USER, ILL_PRVREG, sv); 380 KERNEL_PROC_UNLOCK(p); 381 break; 382 383 /* these should never got here */ 384 case T_HIGHERPL | T_USER: 385 case T_LOWERPL | T_USER: 386 sv.sival_int = va; 387 KERNEL_PROC_LOCK(p); 388 trapsignal(p, SIGSEGV, vftype, SEGV_ACCERR, sv); 389 KERNEL_PROC_UNLOCK(p); 390 break; 391 392 /* 393 * On PCXS processors, traps T_DATACC, T_DATAPID and T_DATALIGN 394 * are shared. We need to sort out the unaligned access situation 395 * first, before handling this trap as T_DATACC. 396 */ 397 case T_DPROT | T_USER: 398 if (cpu_type == hpcxs) { 399 if (pcxs_unaligned(opcode, va)) 400 goto datalign_user; 401 else 402 goto datacc; 403 } 404 /* FALLTHROUGH */ 405 406 case T_IPROT | T_USER: 407 sv.sival_int = va; 408 KERNEL_PROC_LOCK(p); 409 trapsignal(p, SIGSEGV, vftype, SEGV_ACCERR, sv); 410 KERNEL_PROC_UNLOCK(p); 411 break; 412 413 case T_ITLBMISSNA: 414 case T_ITLBMISSNA | T_USER: 415 case T_DTLBMISSNA: 416 case T_DTLBMISSNA | T_USER: 417 if (space == HPPA_SID_KERNEL) 418 map = kernel_map; 419 else { 420 vm = p->p_vmspace; 421 map = &vm->vm_map; 422 } 423 424 if ((opcode & 0xfc003fc0) == 0x04001340) { 425 /* lpa failure case */ 426 frame_regmap(frame, opcode & 0x1f) = 0; 427 frame->tf_ipsw |= PSL_N; 428 } else if ((opcode & 0xfc001f80) == 0x04001180) { 429 int pl; 430 431 /* dig probe[rw]i? insns */ 432 if (opcode & 0x2000) 433 pl = (opcode >> 16) & 3; 434 else 435 pl = frame_regmap(frame, 436 (opcode >> 16) & 0x1f) & 3; 437 438 if (type & T_USER) 439 KERNEL_PROC_LOCK(p); 440 else 441 KERNEL_LOCK(); 442 443 if ((type & T_USER && space == HPPA_SID_KERNEL) || 444 (frame->tf_iioq_head & 3) != pl || 445 (type & T_USER && va >= VM_MAXUSER_ADDRESS) || 446 uvm_fault(map, trunc_page(va), fault, 447 opcode & 0x40? UVM_PROT_WRITE : UVM_PROT_READ)) { 448 frame_regmap(frame, opcode & 0x1f) = 0; 449 frame->tf_ipsw |= PSL_N; 450 } 451 452 if (type & T_USER) 453 KERNEL_PROC_UNLOCK(p); 454 else 455 KERNEL_UNLOCK(); 456 } else if (type & T_USER) { 457 sv.sival_int = va; 458 KERNEL_PROC_LOCK(p); 459 trapsignal(p, SIGILL, type & ~T_USER, ILL_ILLTRP, sv); 460 KERNEL_PROC_UNLOCK(p); 461 } else 462 panic("trap: %s @ 0x%x:0x%x for 0x%x:0x%x irr 0x%08x", 463 tts, frame->tf_iisq_head, frame->tf_iioq_head, 464 space, va, opcode); 465 break; 466 467 case T_TLB_DIRTY: 468 case T_TLB_DIRTY | T_USER: 469 case T_DATACC: 470 case T_DATACC | T_USER: 471datacc: 472 fault = VM_FAULT_PROTECT; 473 case T_ITLBMISS: 474 case T_ITLBMISS | T_USER: 475 case T_DTLBMISS: 476 case T_DTLBMISS | T_USER: 477 /* 478 * it could be a kernel map for exec_map faults 479 */ 480 if (space == HPPA_SID_KERNEL) 481 map = kernel_map; 482 else { 483 vm = p->p_vmspace; 484 map = &vm->vm_map; 485 } 486 487 /* 488 * user faults out of user addr space are always a fail, 489 * this happens on va >= VM_MAXUSER_ADDRESS, where 490 * space id will be zero and therefore cause 491 * a misbehave lower in the code. 492 * 493 * also check that faulted space id matches the curproc. 494 */ 495 if ((type & T_USER && va >= VM_MAXUSER_ADDRESS) || 496 (type & T_USER && map->pmap->pm_space != space)) { 497 sv.sival_int = va; 498 KERNEL_PROC_LOCK(p); 499 trapsignal(p, SIGSEGV, vftype, SEGV_MAPERR, sv); 500 KERNEL_PROC_UNLOCK(p); 501 break; 502 } 503 504 if (type & T_USER) 505 KERNEL_PROC_LOCK(p); 506 else 507 KERNEL_LOCK(); 508 509 ret = uvm_fault(map, trunc_page(va), fault, vftype); 510 511 /* 512 * If this was a stack access we keep track of the maximum 513 * accessed stack size. Also, if uvm_fault gets a protection 514 * failure it is due to accessing the stack region outside 515 * the current limit and we need to reflect that as an access 516 * error. 517 */ 518 if (space != HPPA_SID_KERNEL && 519 va < (vaddr_t)vm->vm_minsaddr) { 520 if (ret == 0) 521 uvm_grow(p, va); 522 else if (ret == EACCES) 523 ret = EFAULT; 524 } 525 526 if (type & T_USER) 527 KERNEL_PROC_UNLOCK(p); 528 else 529 KERNEL_UNLOCK(); 530 531 if (ret != 0) { 532 if (type & T_USER) { 533 sv.sival_int = va; 534 KERNEL_PROC_LOCK(p); 535 trapsignal(p, SIGSEGV, vftype, 536 ret == EACCES? SEGV_ACCERR : SEGV_MAPERR, 537 sv); 538 KERNEL_PROC_UNLOCK(p); 539 } else { 540 if (p && p->p_addr->u_pcb.pcb_onfault) { 541 frame->tf_iioq_tail = 4 + 542 (frame->tf_iioq_head = 543 p->p_addr->u_pcb.pcb_onfault); 544#ifdef DDB 545 frame->tf_iir = 0; 546#endif 547 } else { 548 panic("trap: " 549 "uvm_fault(%p, %lx, %d, %d): %d", 550 map, va, fault, vftype, ret); 551 } 552 } 553 } 554 break; 555 556 case T_DATALIGN | T_USER: 557datalign_user: 558 sv.sival_int = va; 559 KERNEL_PROC_LOCK(p); 560 trapsignal(p, SIGBUS, vftype, BUS_ADRALN, sv); 561 KERNEL_PROC_UNLOCK(p); 562 break; 563 564 case T_INTERRUPT: 565 case T_INTERRUPT | T_USER: 566 cpu_intr(frame); 567 break; 568 569 case T_CONDITION: 570 panic("trap: divide by zero in the kernel"); 571 break; 572 573 case T_ILLEGAL: 574 case T_ILLEGAL | T_USER: 575 /* see if it's a SPOP1,,0 */ 576 if ((opcode & 0xfffffe00) == 0x10000200) { 577 frame_regmap(frame, opcode & 0x1f) = 0; 578 frame->tf_ipsw |= PSL_N; 579 break; 580 } 581 if (type & T_USER) { 582 sv.sival_int = va; 583 KERNEL_PROC_LOCK(p); 584 trapsignal(p, SIGILL, type &~ T_USER, ILL_ILLOPC, sv); 585 KERNEL_PROC_UNLOCK(p); 586 break; 587 } 588 /* FALLTHROUGH */ 589 590 /* 591 * On PCXS processors, traps T_DATACC, T_DATAPID and T_DATALIGN 592 * are shared. We need to sort out the unaligned access situation 593 * first, before handling this trap as T_DATACC. 594 */ 595 case T_DPROT: 596 if (cpu_type == hpcxs) { 597 if (pcxs_unaligned(opcode, va)) 598 goto dead_end; 599 else 600 goto datacc; 601 } 602 /* FALLTHROUGH to unimplemented */ 603 604 case T_LOWERPL: 605 case T_IPROT: 606 case T_OVERFLOW: 607 case T_HIGHERPL: 608 case T_TAKENBR: 609 case T_POWERFAIL: 610 case T_LPMC: 611 case T_PAGEREF: 612 case T_DATAPID: 613 case T_DATAPID | T_USER: 614 /* FALLTHROUGH to unimplemented */ 615 default: 616#if 0 617if (kdb_trap (type, va, frame)) 618 return; 619#endif 620 panic("trap: unimplemented \'%s\' (%d)", tts, trapnum); 621 } 622 623#ifdef DIAGNOSTIC 624 if (curcpu()->ci_cpl != oldcpl) 625 printf("WARNING: SPL (%d) NOT LOWERED ON " 626 "TRAP (%d) EXIT\n", curcpu()->ci_cpl, trapnum); 627#endif 628 629 if (trapnum != T_INTERRUPT) 630 splx(curcpu()->ci_cpl); /* process softints */ 631 632 /* 633 * in case we were interrupted from the syscall gate page 634 * treat this as we were not really running user code no more 635 * for weird things start to happen on return to the userland 636 * and also see a note in locore.S:TLABEL(all) 637 */ 638 if ((type & T_USER) && !(frame->tf_iisq_head == HPPA_SID_KERNEL && 639 (frame->tf_iioq_head & ~PAGE_MASK) == SYSCALLGATE)) 640 userret(p); 641} 642 643void 644child_return(void *arg) 645{ 646 struct proc *p = (struct proc *)arg; 647 struct trapframe *tf = p->p_md.md_regs; 648 649 /* 650 * Set up return value registers as libc:fork() expects 651 */ 652 tf->tf_ret0 = 0; 653 tf->tf_ret1 = 1; /* ischild */ 654 tf->tf_t1 = 0; /* errno */ 655 656 KERNEL_PROC_UNLOCK(p); 657 658 userret(p); 659#ifdef KTRACE 660 if (KTRPOINT(p, KTR_SYSRET)) { 661 KERNEL_PROC_LOCK(p); 662 ktrsysret(p, 663 (p->p_flag & P_THREAD) ? SYS_rfork : 664 (p->p_p->ps_flags & PS_PPWAIT) ? SYS_vfork : SYS_fork, 665 0, 0); 666 KERNEL_PROC_UNLOCK(p); 667 } 668#endif 669} 670 671#ifdef PTRACE 672 673#include <sys/ptrace.h> 674 675int ss_get_value(struct proc *p, vaddr_t addr, u_int *value); 676int ss_put_value(struct proc *p, vaddr_t addr, u_int value); 677 678int 679ss_get_value(struct proc *p, vaddr_t addr, u_int *value) 680{ 681 struct uio uio; 682 struct iovec iov; 683 684 iov.iov_base = (caddr_t)value; 685 iov.iov_len = sizeof(u_int); 686 uio.uio_iov = &iov; 687 uio.uio_iovcnt = 1; 688 uio.uio_offset = (off_t)addr; 689 uio.uio_resid = sizeof(u_int); 690 uio.uio_segflg = UIO_SYSSPACE; 691 uio.uio_rw = UIO_READ; 692 uio.uio_procp = curproc; 693 return (process_domem(curproc, p, &uio, PT_READ_I)); 694} 695 696int 697ss_put_value(struct proc *p, vaddr_t addr, u_int value) 698{ 699 struct uio uio; 700 struct iovec iov; 701 702 iov.iov_base = (caddr_t)&value; 703 iov.iov_len = sizeof(u_int); 704 uio.uio_iov = &iov; 705 uio.uio_iovcnt = 1; 706 uio.uio_offset = (off_t)addr; 707 uio.uio_resid = sizeof(u_int); 708 uio.uio_segflg = UIO_SYSSPACE; 709 uio.uio_rw = UIO_WRITE; 710 uio.uio_procp = curproc; 711 return (process_domem(curproc, p, &uio, PT_WRITE_I)); 712} 713 714void 715ss_clear_breakpoints(struct proc *p) 716{ 717 /* Restore origional instructions. */ 718 if (p->p_md.md_bpva != 0) { 719 ss_put_value(p, p->p_md.md_bpva, p->p_md.md_bpsave[0]); 720 ss_put_value(p, p->p_md.md_bpva + 4, p->p_md.md_bpsave[1]); 721 p->p_md.md_bpva = 0; 722 } 723} 724 725int 726process_sstep(struct proc *p, int sstep) 727{ 728 int error; 729 730 ss_clear_breakpoints(p); 731 732 if (sstep == 0) { 733 p->p_md.md_regs->tf_ipsw &= ~PSL_T; 734 return (0); 735 } 736 737 /* 738 * Don't touch the syscall gateway page. Instead, insert a 739 * breakpoint where we're supposed to return. 740 */ 741 if ((p->p_md.md_regs->tf_iioq_tail & ~PAGE_MASK) == SYSCALLGATE) 742 p->p_md.md_bpva = p->p_md.md_regs->tf_r31 & ~HPPA_PC_PRIV_MASK; 743 else 744 p->p_md.md_bpva = p->p_md.md_regs->tf_iioq_tail & ~HPPA_PC_PRIV_MASK; 745 746 /* 747 * Insert two breakpoint instructions; the first one might be 748 * nullified. Of course we need to save two instruction 749 * first. 750 */ 751 752 error = ss_get_value(p, p->p_md.md_bpva, &p->p_md.md_bpsave[0]); 753 if (error) 754 return (error); 755 error = ss_get_value(p, p->p_md.md_bpva + 4, &p->p_md.md_bpsave[1]); 756 if (error) 757 return (error); 758 759 error = ss_put_value(p, p->p_md.md_bpva, SSBREAKPOINT); 760 if (error) 761 return (error); 762 error = ss_put_value(p, p->p_md.md_bpva + 4, SSBREAKPOINT); 763 if (error) 764 return (error); 765 766 if ((p->p_md.md_regs->tf_iioq_tail & ~PAGE_MASK) != SYSCALLGATE) 767 p->p_md.md_regs->tf_ipsw |= PSL_T; 768 else 769 p->p_md.md_regs->tf_ipsw &= ~PSL_T; 770 771 return (0); 772} 773 774#endif /* PTRACE */ 775 776void syscall(struct trapframe *frame); 777 778/* 779 * call actual syscall routine 780 */ 781void 782syscall(struct trapframe *frame) 783{ 784 register struct proc *p = curproc; 785 register const struct sysent *callp; 786 int retq, nsys, code, argsize, argoff, oerror, error; 787 register_t args[8], rval[2]; 788#ifdef DIAGNOSTIC 789 int oldcpl = curcpu()->ci_cpl; 790#endif 791 792 uvmexp.syscalls++; 793 794 if (!USERMODE(frame->tf_iioq_head)) 795 panic("syscall"); 796 797 p->p_md.md_regs = frame; 798 nsys = p->p_emul->e_nsysent; 799 callp = p->p_emul->e_sysent; 800 801 argoff = 4; retq = 0; 802 switch (code = frame->tf_t1) { 803 case SYS_syscall: 804 code = frame->tf_arg0; 805 args[0] = frame->tf_arg1; 806 args[1] = frame->tf_arg2; 807 args[2] = frame->tf_arg3; 808 argoff = 3; 809 break; 810 case SYS___syscall: 811 if (callp != sysent) 812 break; 813 /* 814 * this works, because quads get magically swapped 815 * due to the args being laid backwards on the stack 816 * and then copied in words 817 */ 818 code = frame->tf_arg0; 819 args[0] = frame->tf_arg2; 820 args[1] = frame->tf_arg3; 821 argoff = 2; 822 retq = 1; 823 break; 824 default: 825 args[0] = frame->tf_arg0; 826 args[1] = frame->tf_arg1; 827 args[2] = frame->tf_arg2; 828 args[3] = frame->tf_arg3; 829 break; 830 } 831 832 if (code < 0 || code >= nsys) 833 callp += p->p_emul->e_nosys; /* bad syscall # */ 834 else 835 callp += code; 836 837 oerror = error = 0; 838 if ((argsize = callp->sy_argsize)) { 839 int i; 840 841 for (i = 0, argsize -= argoff * 4; 842 argsize > 0; i++, argsize -= 4) { 843 error = copyin((void *)(frame->tf_sp + 844 HPPA_FRAME_ARG(i + 4)), args + i + argoff, 4); 845 846 if (error) 847 break; 848 } 849 850 /* 851 * coming from syscall() or __syscall we must be 852 * having one of those w/ a 64 bit arguments, 853 * which needs a word swap due to the order 854 * of the arguments on the stack. 855 * this assumes that none of 'em are called 856 * by their normal syscall number, maybe a regress 857 * test should be used, to watch the behaviour. 858 */ 859 if (!error && argoff < 4) { 860 int t; 861 862 i = 0; 863 switch (code) { 864 case SYS_lseek: retq = 0; 865 case SYS_truncate: 866 case SYS_ftruncate: i = 2; break; 867 case SYS_preadv: 868 case SYS_pwritev: 869 case SYS_pread: 870 case SYS_pwrite: i = 4; break; 871 case SYS_mquery: 872 case SYS_mmap: i = 6; break; 873 } 874 875 if (i) { 876 t = args[i]; 877 args[i] = args[i + 1]; 878 args[i + 1] = t; 879 } 880 } 881 } 882 883#ifdef SYSCALL_DEBUG 884 KERNEL_PROC_LOCK(p); 885 scdebug_call(p, code, args); 886 KERNEL_PROC_UNLOCK(p); 887#endif 888#ifdef KTRACE 889 if (KTRPOINT(p, KTR_SYSCALL)) { 890 KERNEL_PROC_LOCK(p); 891 ktrsyscall(p, code, callp->sy_argsize, args); 892 KERNEL_PROC_UNLOCK(p); 893 } 894#endif 895 if (error) 896 goto bad; 897 898 rval[0] = 0; 899 rval[1] = frame->tf_ret1; 900#if NSYSTRACE > 0 901 if (ISSET(p->p_flag, P_SYSTRACE)) { 902 KERNEL_PROC_LOCK(p); 903 oerror = error = systrace_redirect(code, p, args, rval); 904 KERNEL_PROC_UNLOCK(p); 905 } else 906#endif 907 { 908 int nolock = (callp->sy_flags & SY_NOLOCK); 909 if (!nolock) 910 KERNEL_PROC_LOCK(p); 911 oerror = error = (*callp->sy_call)(p, args, rval); 912 if (!nolock) 913 KERNEL_PROC_UNLOCK(p); 914 915 } 916 switch (error) { 917 case 0: 918 frame->tf_ret0 = rval[0]; 919 frame->tf_ret1 = rval[!retq]; 920 frame->tf_t1 = 0; 921 break; 922 case ERESTART: 923 frame->tf_iioq_head -= 12; 924 frame->tf_iioq_tail -= 12; 925 case EJUSTRETURN: 926 break; 927 default: 928 bad: 929 if (p->p_emul->e_errno) 930 error = p->p_emul->e_errno[error]; 931 frame->tf_t1 = error; 932 frame->tf_ret0 = error; 933 frame->tf_ret1 = 0; 934 break; 935 } 936#ifdef SYSCALL_DEBUG 937 KERNEL_PROC_LOCK(p); 938 scdebug_ret(p, code, oerror, rval); 939 KERNEL_PROC_UNLOCK(p); 940#endif 941 userret(p); 942#ifdef KTRACE 943 if (KTRPOINT(p, KTR_SYSRET)) { 944 KERNEL_PROC_LOCK(p); 945 ktrsysret(p, code, oerror, rval[0]); 946 KERNEL_PROC_UNLOCK(p); 947 } 948#endif 949#ifdef DIAGNOSTIC 950 if (curcpu()->ci_cpl != oldcpl) { 951 printf("WARNING: SPL (0x%x) NOT LOWERED ON " 952 "syscall(0x%x, 0x%x, 0x%x, 0x%x...) EXIT, PID %d\n", 953 curcpu()->ci_cpl, code, args[0], args[1], args[2], 954 p->p_pid); 955 curcpu()->ci_cpl = oldcpl; 956 } 957#endif 958 splx(curcpu()->ci_cpl); /* process softints */ 959} 960 961/* 962 * Decide if opcode `opcode' accessing virtual address `va' caused an 963 * unaligned trap. Returns zero if the access is correctly aligned. 964 * Used on PCXS processors to sort out exception causes. 965 */ 966int 967pcxs_unaligned(u_int opcode, vaddr_t va) 968{ 969 u_int mbz_bits; 970 971 /* 972 * Exit early if the va is obviously aligned enough. 973 */ 974 if ((va & 0x0f) == 0) 975 return 0; 976 977 mbz_bits = 0; 978 979 /* 980 * Only load and store instructions can cause unaligned access. 981 * There are three opcode patterns to look for: 982 * - canonical load/store 983 * - load/store short or indexed 984 * - coprocessor load/store 985 */ 986 987 if ((opcode & 0xd0000000) == 0x40000000) { 988 switch ((opcode >> 26) & 0x03) { 989 case 0x00: /* ldb, stb */ 990 mbz_bits = 0x00; 991 break; 992 case 0x01: /* ldh, sth */ 993 mbz_bits = 0x01; 994 break; 995 case 0x02: /* ldw, stw */ 996 case 0x03: /* ldwm, stwm */ 997 mbz_bits = 0x03; 998 break; 999 } 1000 } else 1001 1002 if ((opcode & 0xfc000000) == 0x0c000000) { 1003 switch ((opcode >> 6) & 0x0f) { 1004 case 0x01: /* ldhx, ldhs */ 1005 mbz_bits = 0x01; 1006 break; 1007 case 0x02: /* ldwx, ldws */ 1008 mbz_bits = 0x03; 1009 break; 1010 case 0x07: /* ldcwx, ldcws */ 1011 mbz_bits = 0x0f; 1012 break; 1013 case 0x09: 1014 if ((opcode & (1 << 12)) != 0) /* sths */ 1015 mbz_bits = 0x01; 1016 break; 1017 case 0x0a: 1018 if ((opcode & (1 << 12)) != 0) /* stws */ 1019 mbz_bits = 0x03; 1020 break; 1021 } 1022 } else 1023 1024 if ((opcode & 0xf4000000) == 0x24000000) { 1025 if ((opcode & (1 << 27)) != 0) { 1026 /* cldwx, cstwx, cldws, cstws */ 1027 mbz_bits = 0x03; 1028 } else { 1029 /* clddx, cstdx, cldds, cstds */ 1030 mbz_bits = 0x07; 1031 } 1032 } 1033 1034 return (va & mbz_bits); 1035} 1036