1*5ab06ed0Sderaadt /* $OpenBSD: trap.c,v 1.133 2014/05/10 21:58:56 deraadt Exp $ */ 2556d2ba7Smickey 3556d2ba7Smickey /* 4fef2e65fSmickey * Copyright (c) 1998-2004 Michael Shalayeff 5556d2ba7Smickey * All rights reserved. 6556d2ba7Smickey * 7556d2ba7Smickey * Redistribution and use in source and binary forms, with or without 8556d2ba7Smickey * modification, are permitted provided that the following conditions 9556d2ba7Smickey * are met: 10556d2ba7Smickey * 1. Redistributions of source code must retain the above copyright 11556d2ba7Smickey * notice, this list of conditions and the following disclaimer. 12556d2ba7Smickey * 2. Redistributions in binary form must reproduce the above copyright 13556d2ba7Smickey * notice, this list of conditions and the following disclaimer in the 14556d2ba7Smickey * documentation and/or other materials provided with the distribution. 15556d2ba7Smickey * 16556d2ba7Smickey * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17556d2ba7Smickey * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18556d2ba7Smickey * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19fef2e65fSmickey * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, 20fef2e65fSmickey * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21fef2e65fSmickey * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22fef2e65fSmickey * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23fef2e65fSmickey * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24fef2e65fSmickey * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 25fef2e65fSmickey * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 26fef2e65fSmickey * THE POSSIBILITY OF SUCH DAMAGE. 27556d2ba7Smickey */ 28556d2ba7Smickey 29ce94da48Smickey /* #define TRAPDEBUG */ 30556d2ba7Smickey 31556d2ba7Smickey #include <sys/param.h> 32556d2ba7Smickey #include <sys/systm.h> 33b9b95e0dSmickey #include <sys/syscall.h> 34d412f1c2Smickey #include <sys/proc.h> 356acb4cb0Sniklas #include <sys/signalvar.h> 36d412f1c2Smickey #include <sys/user.h> 37*5ab06ed0Sderaadt #include <sys/syscall_mi.h> 38556d2ba7Smickey 390d6ad30dSmpi #include <uvm/uvm_extern.h> 40556d2ba7Smickey 41556d2ba7Smickey #include <machine/autoconf.h> 42556d2ba7Smickey 43137d3021Smickey #ifdef DDB 449d159c9dSmickey #ifdef TRAPDEBUG 45137d3021Smickey #include <ddb/db_output.h> 461f3fe449Smiod #else 471f3fe449Smiod #include <machine/db_machdep.h> 48137d3021Smickey #endif 499d159c9dSmickey #endif 50556d2ba7Smickey 511f3fe449Smiod static __inline int inst_store(u_int ins) { 521f3fe449Smiod return (ins & 0xf0000000) == 0x60000000 || /* st */ 531f3fe449Smiod (ins & 0xf4000200) == 0x24000200 || /* fst/cst */ 541f3fe449Smiod (ins & 0xfc000200) == 0x0c000200 || /* stby */ 551f3fe449Smiod (ins & 0xfc0003c0) == 0x0c0001c0; /* ldcw */ 561f3fe449Smiod } 571f3fe449Smiod 5878a8f2b7Smiod int pcxs_unaligned(u_int opcode, vaddr_t va); 597bfbef72Skettenis #ifdef PTRACE 607bfbef72Skettenis void ss_clear_breakpoints(struct proc *p); 617bfbef72Skettenis #endif 627bfbef72Skettenis 63dfd9822dSderaadt void ast(struct proc *); 64dfd9822dSderaadt 657bfbef72Skettenis /* single-step breakpoint */ 667bfbef72Skettenis #define SSBREAKPOINT (HPPA_BREAK_KERNEL | (HPPA_BREAK_SS << 13)) 677bfbef72Skettenis 68556d2ba7Smickey const char *trap_type[] = { 69e494c7cfSmickey "invalid", 70e494c7cfSmickey "HPMC", 71556d2ba7Smickey "power failure", 72137d3021Smickey "recovery counter", 73556d2ba7Smickey "external interrupt", 74e494c7cfSmickey "LPMC", 75e494c7cfSmickey "ITLB miss fault", 76137d3021Smickey "instruction protection", 77137d3021Smickey "Illegal instruction", 78137d3021Smickey "break instruction", 79137d3021Smickey "privileged operation", 80137d3021Smickey "privileged register", 81137d3021Smickey "overflow", 82137d3021Smickey "conditional", 83137d3021Smickey "assist exception", 84e494c7cfSmickey "DTLB miss", 85137d3021Smickey "ITLB non-access miss", 86137d3021Smickey "DTLB non-access miss", 87137d3021Smickey "data protection/rights/alignment", 88137d3021Smickey "data break", 89e494c7cfSmickey "TLB dirty", 90137d3021Smickey "page reference", 91137d3021Smickey "assist emulation", 92e494c7cfSmickey "higher-priv transfer", 93e494c7cfSmickey "lower-priv transfer", 94137d3021Smickey "taken branch", 95137d3021Smickey "data access rights", 96e494c7cfSmickey "data protection", 97137d3021Smickey "unaligned data ref", 98556d2ba7Smickey }; 99556d2ba7Smickey int trap_types = sizeof(trap_type)/sizeof(trap_type[0]); 100556d2ba7Smickey 1011aec61b7Smickey #define frame_regmap(tf,r) (((u_int *)(tf))[hppa_regmap[(r)]]) 1021aec61b7Smickey u_char hppa_regmap[32] = { 1031aec61b7Smickey offsetof(struct trapframe, tf_pad[0]) / 4, /* r0 XXX */ 1041aec61b7Smickey offsetof(struct trapframe, tf_r1) / 4, 1051aec61b7Smickey offsetof(struct trapframe, tf_rp) / 4, 1061aec61b7Smickey offsetof(struct trapframe, tf_r3) / 4, 1071aec61b7Smickey offsetof(struct trapframe, tf_r4) / 4, 1081aec61b7Smickey offsetof(struct trapframe, tf_r5) / 4, 1091aec61b7Smickey offsetof(struct trapframe, tf_r6) / 4, 1101aec61b7Smickey offsetof(struct trapframe, tf_r7) / 4, 1111aec61b7Smickey offsetof(struct trapframe, tf_r8) / 4, 1121aec61b7Smickey offsetof(struct trapframe, tf_r9) / 4, 1131aec61b7Smickey offsetof(struct trapframe, tf_r10) / 4, 1141aec61b7Smickey offsetof(struct trapframe, tf_r11) / 4, 1151aec61b7Smickey offsetof(struct trapframe, tf_r12) / 4, 1161aec61b7Smickey offsetof(struct trapframe, tf_r13) / 4, 1171aec61b7Smickey offsetof(struct trapframe, tf_r14) / 4, 1181aec61b7Smickey offsetof(struct trapframe, tf_r15) / 4, 1191aec61b7Smickey offsetof(struct trapframe, tf_r16) / 4, 1201aec61b7Smickey offsetof(struct trapframe, tf_r17) / 4, 1211aec61b7Smickey offsetof(struct trapframe, tf_r18) / 4, 1221aec61b7Smickey offsetof(struct trapframe, tf_t4) / 4, 1231aec61b7Smickey offsetof(struct trapframe, tf_t3) / 4, 1241aec61b7Smickey offsetof(struct trapframe, tf_t2) / 4, 1251aec61b7Smickey offsetof(struct trapframe, tf_t1) / 4, 1261aec61b7Smickey offsetof(struct trapframe, tf_arg3) / 4, 1271aec61b7Smickey offsetof(struct trapframe, tf_arg2) / 4, 1281aec61b7Smickey offsetof(struct trapframe, tf_arg1) / 4, 1291aec61b7Smickey offsetof(struct trapframe, tf_arg0) / 4, 1301aec61b7Smickey offsetof(struct trapframe, tf_dp) / 4, 1311aec61b7Smickey offsetof(struct trapframe, tf_ret0) / 4, 1321aec61b7Smickey offsetof(struct trapframe, tf_ret1) / 4, 1331aec61b7Smickey offsetof(struct trapframe, tf_sp) / 4, 1341aec61b7Smickey offsetof(struct trapframe, tf_r31) / 4, 1351aec61b7Smickey }; 1361aec61b7Smickey 13770016991Smickey void 138c2b93341Sderaadt ast(struct proc *p) 139d412f1c2Smickey { 140da6814fdSjsing if (p->p_md.md_astpending) { 141da6814fdSjsing p->p_md.md_astpending = 0; 142db13da92Sguenther mi_ast(p, curcpu()->ci_want_resched); 143c19cb33fSmickey } 144c19cb33fSmickey 145d412f1c2Smickey } 146d412f1c2Smickey 147556d2ba7Smickey void 148c33335b0Sjsing trap(int type, struct trapframe *frame) 149556d2ba7Smickey { 150556d2ba7Smickey struct proc *p = curproc; 151ab8e80c5Sart vaddr_t va; 152ab8e80c5Sart struct vm_map *map; 153f17fa196Smickey struct vmspace *vm; 154af7386c3Smickey register vm_prot_t vftype; 155556d2ba7Smickey register pa_space_t space; 156af7386c3Smickey union sigval sv; 157c37e03c6Smickey u_int opcode; 15870016991Smickey int ret, trapnum; 159137d3021Smickey const char *tts; 1606198d067Smickey vm_fault_t fault = VM_FAULT_INVALID; 16170016991Smickey #ifdef DIAGNOSTIC 162473ddf34Sjsing int oldcpl = curcpu()->ci_cpl; 16370016991Smickey #endif 1640e979e06Smickey 165c37e03c6Smickey trapnum = type & ~T_USER; 166137d3021Smickey opcode = frame->tf_iir; 1679b476898Smickey if (trapnum <= T_EXCEPTION || trapnum == T_HIGHERPL || 1689b476898Smickey trapnum == T_LOWERPL || trapnum == T_TAKENBR || 1699b476898Smickey trapnum == T_IDEBUG || trapnum == T_PERFMON) { 170a24c0b7aSmickey va = frame->tf_iioq_head; 171a24c0b7aSmickey space = frame->tf_iisq_head; 172e21aaa8cSmickey vftype = UVM_PROT_EXEC; 173a24c0b7aSmickey } else { 174b9b95e0dSmickey va = frame->tf_ior; 175a24c0b7aSmickey space = frame->tf_isr; 176a4be06b3Smickey if (va == frame->tf_iioq_head) 177e21aaa8cSmickey vftype = UVM_PROT_EXEC; 178a4be06b3Smickey else if (inst_store(opcode)) 179e21aaa8cSmickey vftype = UVM_PROT_WRITE; 180a4be06b3Smickey else 181e21aaa8cSmickey vftype = UVM_PROT_READ; 182556d2ba7Smickey } 183137d3021Smickey 184137d3021Smickey if (frame->tf_flags & TFF_LAST) 185137d3021Smickey p->p_md.md_regs = frame; 186137d3021Smickey 187c37e03c6Smickey if (trapnum > trap_types) 188137d3021Smickey tts = "reserved"; 189137d3021Smickey else 190c37e03c6Smickey tts = trap_type[trapnum]; 191137d3021Smickey 192446209b7Smiod #ifdef TRAPDEBUG 193c37e03c6Smickey if (trapnum != T_INTERRUPT && trapnum != T_IBREAK) 194969c5366Smickey db_printf("trap: %x, %s for %x:%x at %x:%x, fl=%x, fp=%p\n", 195137d3021Smickey type, tts, space, va, frame->tf_iisq_head, 196137d3021Smickey frame->tf_iioq_head, frame->tf_flags, frame); 197c37e03c6Smickey else if (trapnum == T_IBREAK) 198137d3021Smickey db_printf("trap: break instruction %x:%x at %x:%x, fp=%p\n", 199a24c0b7aSmickey break5(opcode), break13(opcode), 200137d3021Smickey frame->tf_iisq_head, frame->tf_iioq_head, frame); 201e494c7cfSmickey 202e494c7cfSmickey { 203e494c7cfSmickey extern int etext; 204532740e6Smickey if (frame < (struct trapframe *)&etext) { 205532740e6Smickey printf("trap: bogus frame ptr %p\n", frame); 206e494c7cfSmickey goto dead_end; 207e494c7cfSmickey } 208532740e6Smickey } 209d412f1c2Smickey #endif 2107d3bf75dSmickey if (trapnum != T_INTERRUPT) { 2117d3bf75dSmickey uvmexp.traps++; 21270016991Smickey mtctl(frame->tf_eiem, CR_EIEM); 213916310a5Smickey } 21470016991Smickey 215a9ddc286Sguenther if (type & T_USER) 216a9ddc286Sguenther refreshcreds(p); 217a9ddc286Sguenther 218556d2ba7Smickey switch (type) { 219556d2ba7Smickey case T_NONEXIST: 220556d2ba7Smickey case T_NONEXIST | T_USER: 221af7386c3Smickey /* we've got screwed up by the central scrutinizer */ 222b67578d8Smickey printf("trap: elvis has just left the building!\n"); 223532740e6Smickey goto dead_end; 224b67578d8Smickey 225556d2ba7Smickey case T_RECOVERY: 226556d2ba7Smickey case T_RECOVERY | T_USER: 227af7386c3Smickey /* XXX will implement later */ 228556d2ba7Smickey printf("trap: handicapped"); 229532740e6Smickey goto dead_end; 23066d1ab7aSmickey 23166d1ab7aSmickey #ifdef DIAGNOSTIC 23266d1ab7aSmickey case T_EXCEPTION: 23366d1ab7aSmickey panic("FPU/SFU emulation botch"); 23466d1ab7aSmickey 23566d1ab7aSmickey /* these just can't happen ever */ 23666d1ab7aSmickey case T_PRIV_OP: 23766d1ab7aSmickey case T_PRIV_REG: 23866d1ab7aSmickey /* these just can't make it to the trap() ever */ 239c6555f83Sderaadt case T_HPMC: 240c6555f83Sderaadt case T_HPMC | T_USER: 24166d1ab7aSmickey #endif 242f4daacd8Smickey case T_IBREAK: 243a24c0b7aSmickey case T_DATALIGN: 244a24c0b7aSmickey case T_DBREAK: 2458de28e3eSmickey dead_end: 246a24c0b7aSmickey #ifdef DDB 247532740e6Smickey if (kdb_trap(type, va, frame)) { 248a24c0b7aSmickey if (type == T_IBREAK) { 249f4daacd8Smickey /* skip break instruction */ 2508de28e3eSmickey frame->tf_iioq_head = frame->tf_iioq_tail; 251f4daacd8Smickey frame->tf_iioq_tail += 4; 252a24c0b7aSmickey } 253556d2ba7Smickey return; 254a24c0b7aSmickey } 255137d3021Smickey #else 25678a8f2b7Smiod if (type == T_DATALIGN || type == T_DPROT) 257137d3021Smickey panic ("trap: %s at 0x%x", tts, va); 258137d3021Smickey else 259137d3021Smickey panic ("trap: no debugger for \"%s\" (%d)", tts, type); 260a24c0b7aSmickey #endif 261556d2ba7Smickey break; 262556d2ba7Smickey 263af7386c3Smickey case T_IBREAK | T_USER: 2647bfbef72Skettenis case T_DBREAK | T_USER: { 2657bfbef72Skettenis int code = TRAP_BRKPT; 2667bfbef72Skettenis #ifdef PTRACE 2677bfbef72Skettenis ss_clear_breakpoints(p); 2687bfbef72Skettenis if (opcode == SSBREAKPOINT) 2697bfbef72Skettenis code = TRAP_TRACE; 2707bfbef72Skettenis #endif 271af7386c3Smickey /* pass to user debugger */ 272f4e9e19cSguenther KERNEL_LOCK(); 2737bfbef72Skettenis trapsignal(p, SIGTRAP, type & ~T_USER, code, sv); 274f4e9e19cSguenther KERNEL_UNLOCK(); 2757bfbef72Skettenis } 276d412f1c2Smickey break; 277d412f1c2Smickey 2787bfbef72Skettenis #ifdef PTRACE 2797bfbef72Skettenis case T_TAKENBR | T_USER: 2807bfbef72Skettenis ss_clear_breakpoints(p); 2817bfbef72Skettenis 2827bfbef72Skettenis /* pass to user debugger */ 283f4e9e19cSguenther KERNEL_LOCK(); 2847bfbef72Skettenis trapsignal(p, SIGTRAP, type & ~T_USER, TRAP_TRACE, sv); 285f4e9e19cSguenther KERNEL_UNLOCK(); 2867bfbef72Skettenis break; 2877bfbef72Skettenis #endif 2887bfbef72Skettenis 28938575cbdSmickey case T_EXCEPTION | T_USER: { 2902f8e4113Sjsing struct hppa_fpstate *hfp; 2912f8e4113Sjsing u_int64_t *fpp; 292969eb289Smickey u_int32_t *pex; 29338575cbdSmickey int i, flt; 29438575cbdSmickey 2952f8e4113Sjsing hfp = (struct hppa_fpstate *)frame->tf_cr30; 2962f8e4113Sjsing fpp = (u_int64_t *)&hfp->hfp_regs; 2972f8e4113Sjsing 298969eb289Smickey pex = (u_int32_t *)&fpp[0]; 29938575cbdSmickey for (i = 0, pex++; i < 7 && !*pex; i++, pex++); 300969eb289Smickey flt = 0; 301969eb289Smickey if (i < 7) { 302969eb289Smickey u_int32_t stat = HPPA_FPU_OP(*pex); 30328496d60Smickey if (stat & HPPA_FPU_UNMPL) 304969eb289Smickey flt = FPE_FLTINV; 30528496d60Smickey else if (stat & (HPPA_FPU_V << 1)) 30638575cbdSmickey flt = FPE_FLTINV; 30728496d60Smickey else if (stat & (HPPA_FPU_Z << 1)) 30838575cbdSmickey flt = FPE_FLTDIV; 30928496d60Smickey else if (stat & (HPPA_FPU_I << 1)) 310969eb289Smickey flt = FPE_FLTRES; 31128496d60Smickey else if (stat & (HPPA_FPU_O << 1)) 31238575cbdSmickey flt = FPE_FLTOVF; 31328496d60Smickey else if (stat & (HPPA_FPU_U << 1)) 31438575cbdSmickey flt = FPE_FLTUND; 315969eb289Smickey /* still left: under/over-flow w/ inexact */ 316ded58a29Smickey 317ded58a29Smickey /* cleanup exceptions (XXX deliver all ?) */ 318ded58a29Smickey while (i++ < 7) 319ded58a29Smickey *pex++ = 0; 320969eb289Smickey } 321969eb289Smickey /* reset the trap flag, as if there was none */ 322969eb289Smickey fpp[0] &= ~(((u_int64_t)HPPA_FPU_T) << 32); 32338575cbdSmickey 32438575cbdSmickey sv.sival_int = va; 325f4e9e19cSguenther KERNEL_LOCK(); 32638575cbdSmickey trapsignal(p, SIGFPE, type & ~T_USER, flt, sv); 327f4e9e19cSguenther KERNEL_UNLOCK(); 32838575cbdSmickey } 32938575cbdSmickey break; 33038575cbdSmickey 331969eb289Smickey case T_EMULATION: 332969eb289Smickey panic("trap: emulation trap in the kernel"); 333969eb289Smickey break; 334969eb289Smickey 335969eb289Smickey case T_EMULATION | T_USER: 336137d3021Smickey sv.sival_int = va; 337f4e9e19cSguenther KERNEL_LOCK(); 33828496d60Smickey trapsignal(p, SIGILL, type & ~T_USER, ILL_COPROC, sv); 339f4e9e19cSguenther KERNEL_UNLOCK(); 340d412f1c2Smickey break; 341d412f1c2Smickey 342af7386c3Smickey case T_OVERFLOW | T_USER: 343137d3021Smickey sv.sival_int = va; 344f4e9e19cSguenther KERNEL_LOCK(); 345af7386c3Smickey trapsignal(p, SIGFPE, type & ~T_USER, FPE_INTOVF, sv); 346f4e9e19cSguenther KERNEL_UNLOCK(); 347d412f1c2Smickey break; 348d412f1c2Smickey 349af7386c3Smickey case T_CONDITION | T_USER: 3508b9bddf0Smickey sv.sival_int = va; 351f4e9e19cSguenther KERNEL_LOCK(); 3528b9bddf0Smickey trapsignal(p, SIGFPE, type & ~T_USER, FPE_INTDIV, sv); 353f4e9e19cSguenther KERNEL_UNLOCK(); 354af7386c3Smickey break; 355af7386c3Smickey 356af7386c3Smickey case T_PRIV_OP | T_USER: 357137d3021Smickey sv.sival_int = va; 358f4e9e19cSguenther KERNEL_LOCK(); 359af7386c3Smickey trapsignal(p, SIGILL, type & ~T_USER, ILL_PRVOPC, sv); 360f4e9e19cSguenther KERNEL_UNLOCK(); 361af7386c3Smickey break; 362af7386c3Smickey 363af7386c3Smickey case T_PRIV_REG | T_USER: 364b0be98e8Smiod /* 365b0be98e8Smiod * On PCXS processors, attempting to read control registers 366b0be98e8Smiod * cr26 and cr27 from userland causes a ``privileged register'' 367b0be98e8Smiod * trap. Later processors do not restrict read accesses to 368b0be98e8Smiod * these registers. 369b0be98e8Smiod */ 370b0be98e8Smiod if (cpu_type == hpcxs && 371b0be98e8Smiod (opcode & (0xfc1fffe0 | (0x1e << 21))) == 372b0be98e8Smiod (0x000008a0 | (0x1a << 21))) { /* mfctl %cr{26,27}, %r# */ 373b0be98e8Smiod register_t cr; 374b0be98e8Smiod 375b0be98e8Smiod if (((opcode >> 21) & 0x1f) == 27) 376b0be98e8Smiod mfctl(CR_TR3, cr); /* cr27 */ 377b0be98e8Smiod else 378b0be98e8Smiod mfctl(CR_TR2, cr); /* cr26 */ 379b0be98e8Smiod frame_regmap(frame, opcode & 0x1f) = cr; 380b0be98e8Smiod frame->tf_ipsw |= PSL_N; 381b0be98e8Smiod } else { 382137d3021Smickey sv.sival_int = va; 383f4e9e19cSguenther KERNEL_LOCK(); 384af7386c3Smickey trapsignal(p, SIGILL, type & ~T_USER, ILL_PRVREG, sv); 385f4e9e19cSguenther KERNEL_UNLOCK(); 386b0be98e8Smiod } 387af7386c3Smickey break; 388af7386c3Smickey 389af7386c3Smickey /* these should never got here */ 390af7386c3Smickey case T_HIGHERPL | T_USER: 391af7386c3Smickey case T_LOWERPL | T_USER: 39263b0c7d2Smiod case T_DATAPID | T_USER: 393137d3021Smickey sv.sival_int = va; 394f4e9e19cSguenther KERNEL_LOCK(); 395a4be06b3Smickey trapsignal(p, SIGSEGV, vftype, SEGV_ACCERR, sv); 396f4e9e19cSguenther KERNEL_UNLOCK(); 397af7386c3Smickey break; 398af7386c3Smickey 39978a8f2b7Smiod /* 40078a8f2b7Smiod * On PCXS processors, traps T_DATACC, T_DATAPID and T_DATALIGN 40178a8f2b7Smiod * are shared. We need to sort out the unaligned access situation 40278a8f2b7Smiod * first, before handling this trap as T_DATACC. 40378a8f2b7Smiod */ 404af7386c3Smickey case T_DPROT | T_USER: 40578a8f2b7Smiod if (cpu_type == hpcxs) { 40678a8f2b7Smiod if (pcxs_unaligned(opcode, va)) 40778a8f2b7Smiod goto datalign_user; 40878a8f2b7Smiod else 40978a8f2b7Smiod goto datacc; 41078a8f2b7Smiod } 41178a8f2b7Smiod 412af7386c3Smickey sv.sival_int = va; 413f4e9e19cSguenther KERNEL_LOCK(); 414af7386c3Smickey trapsignal(p, SIGSEGV, vftype, SEGV_ACCERR, sv); 415f4e9e19cSguenther KERNEL_UNLOCK(); 416af7386c3Smickey break; 417af7386c3Smickey 4189208e3abSmickey case T_ITLBMISSNA: 4199208e3abSmickey case T_ITLBMISSNA | T_USER: 4209208e3abSmickey case T_DTLBMISSNA: 4219208e3abSmickey case T_DTLBMISSNA | T_USER: 4229208e3abSmickey if (space == HPPA_SID_KERNEL) 4239208e3abSmickey map = kernel_map; 4249208e3abSmickey else { 4259208e3abSmickey vm = p->p_vmspace; 4269208e3abSmickey map = &vm->vm_map; 4279208e3abSmickey } 4289208e3abSmickey 42998898169Smickey if ((opcode & 0xfc003fc0) == 0x04001340) { 43098898169Smickey /* lpa failure case */ 43198898169Smickey frame_regmap(frame, opcode & 0x1f) = 0; 43298898169Smickey frame->tf_ipsw |= PSL_N; 43398898169Smickey } else if ((opcode & 0xfc001f80) == 0x04001180) { 4349208e3abSmickey int pl; 4359208e3abSmickey 43698898169Smickey /* dig probe[rw]i? insns */ 4379208e3abSmickey if (opcode & 0x2000) 4389208e3abSmickey pl = (opcode >> 16) & 3; 4399208e3abSmickey else 4409208e3abSmickey pl = frame_regmap(frame, 4419208e3abSmickey (opcode >> 16) & 0x1f) & 3; 4429208e3abSmickey 443cfad034cSjsing KERNEL_LOCK(); 444cfad034cSjsing 4459208e3abSmickey if ((type & T_USER && space == HPPA_SID_KERNEL) || 4469208e3abSmickey (frame->tf_iioq_head & 3) != pl || 4479208e3abSmickey (type & T_USER && va >= VM_MAXUSER_ADDRESS) || 4485fbb3992Smartin uvm_fault(map, trunc_page(va), fault, 4499208e3abSmickey opcode & 0x40? UVM_PROT_WRITE : UVM_PROT_READ)) { 4509208e3abSmickey frame_regmap(frame, opcode & 0x1f) = 0; 4519208e3abSmickey frame->tf_ipsw |= PSL_N; 4529208e3abSmickey } 453cfad034cSjsing 454cfad034cSjsing KERNEL_UNLOCK(); 4559208e3abSmickey } else if (type & T_USER) { 4569208e3abSmickey sv.sival_int = va; 457f4e9e19cSguenther KERNEL_LOCK(); 4589208e3abSmickey trapsignal(p, SIGILL, type & ~T_USER, ILL_ILLTRP, sv); 459f4e9e19cSguenther KERNEL_UNLOCK(); 4609208e3abSmickey } else 461c8b758f8Smiod panic("trap: %s @ 0x%lx:0x%lx for 0x%x:0x%lx irr 0x%08x", 4629208e3abSmickey tts, frame->tf_iisq_head, frame->tf_iioq_head, 4639208e3abSmickey space, va, opcode); 4649208e3abSmickey break; 4659208e3abSmickey 466998e9803Skettenis case T_IPROT | T_USER: 4679208e3abSmickey case T_TLB_DIRTY: 4689208e3abSmickey case T_TLB_DIRTY | T_USER: 469c6555f83Sderaadt case T_DATACC: 470c6555f83Sderaadt case T_DATACC | T_USER: 47178a8f2b7Smiod datacc: 4726198d067Smickey fault = VM_FAULT_PROTECT; 473c6555f83Sderaadt case T_ITLBMISS: 474c6555f83Sderaadt case T_ITLBMISS | T_USER: 475c6555f83Sderaadt case T_DTLBMISS: 476c6555f83Sderaadt case T_DTLBMISS | T_USER: 4778de28e3eSmickey /* 478e494c7cfSmickey * it could be a kernel map for exec_map faults 4798de28e3eSmickey */ 48043a91648Smickey if (space == HPPA_SID_KERNEL) 4818de28e3eSmickey map = kernel_map; 48243a91648Smickey else { 48343a91648Smickey vm = p->p_vmspace; 484f17fa196Smickey map = &vm->vm_map; 48543a91648Smickey } 486556d2ba7Smickey 4879208e3abSmickey /* 4889208e3abSmickey * user faults out of user addr space are always a fail, 4899208e3abSmickey * this happens on va >= VM_MAXUSER_ADDRESS, where 4909208e3abSmickey * space id will be zero and therefore cause 4919208e3abSmickey * a misbehave lower in the code. 4929208e3abSmickey * 4939208e3abSmickey * also check that faulted space id matches the curproc. 4949208e3abSmickey */ 4959208e3abSmickey if ((type & T_USER && va >= VM_MAXUSER_ADDRESS) || 4969208e3abSmickey (type & T_USER && map->pmap->pm_space != space)) { 497906a25e0Smickey sv.sival_int = va; 498f4e9e19cSguenther KERNEL_LOCK(); 499906a25e0Smickey trapsignal(p, SIGSEGV, vftype, SEGV_MAPERR, sv); 500f4e9e19cSguenther KERNEL_UNLOCK(); 50143a91648Smickey break; 502906a25e0Smickey } 503532740e6Smickey 504cfad034cSjsing KERNEL_LOCK(); 505cfad034cSjsing 5065fbb3992Smartin ret = uvm_fault(map, trunc_page(va), fault, vftype); 507f17fa196Smickey 508f17fa196Smickey /* 509f17fa196Smickey * If this was a stack access we keep track of the maximum 510f17fa196Smickey * accessed stack size. Also, if uvm_fault gets a protection 511f17fa196Smickey * failure it is due to accessing the stack region outside 512f17fa196Smickey * the current limit and we need to reflect that as an access 513f17fa196Smickey * error. 514f17fa196Smickey */ 51556f69dffSmiod if (space != HPPA_SID_KERNEL && 51662899679Smiod va < (vaddr_t)vm->vm_minsaddr) { 51762899679Smiod if (ret == 0) 51862899679Smiod uvm_grow(p, va); 51962899679Smiod else if (ret == EACCES) 520738a5b4dSart ret = EFAULT; 521f17fa196Smickey } 522f17fa196Smickey 523cfad034cSjsing KERNEL_UNLOCK(); 524cfad034cSjsing 525738a5b4dSart if (ret != 0) { 526af7386c3Smickey if (type & T_USER) { 527a4be06b3Smickey sv.sival_int = va; 528f4e9e19cSguenther KERNEL_LOCK(); 529a4be06b3Smickey trapsignal(p, SIGSEGV, vftype, 530a4be06b3Smickey ret == EACCES? SEGV_ACCERR : SEGV_MAPERR, 531a4be06b3Smickey sv); 532f4e9e19cSguenther KERNEL_UNLOCK(); 533137d3021Smickey } else { 5348de28e3eSmickey if (p && p->p_addr->u_pcb.pcb_onfault) { 5358de28e3eSmickey frame->tf_iioq_tail = 4 + 5368de28e3eSmickey (frame->tf_iioq_head = 53738575cbdSmickey p->p_addr->u_pcb.pcb_onfault); 538b04f760fSmickey #ifdef DDB 539b04f760fSmickey frame->tf_iir = 0; 540b04f760fSmickey #endif 541db97f33bSmickey } else { 542db97f33bSmickey panic("trap: " 54356f69dffSmiod "uvm_fault(%p, %lx, %d, %d): %d", 54496415af6Smickey map, va, fault, vftype, ret); 545137d3021Smickey } 546137d3021Smickey } 547db97f33bSmickey } 548556d2ba7Smickey break; 549d412f1c2Smickey 55063b0c7d2Smiod case T_DATAPID: 55163b0c7d2Smiod /* This should never happen, unless within spcopy() */ 55263b0c7d2Smiod if (p && p->p_addr->u_pcb.pcb_onfault) { 55363b0c7d2Smiod frame->tf_iioq_tail = 4 + 55463b0c7d2Smiod (frame->tf_iioq_head = 55563b0c7d2Smiod p->p_addr->u_pcb.pcb_onfault); 55663b0c7d2Smiod #ifdef DDB 55763b0c7d2Smiod frame->tf_iir = 0; 55863b0c7d2Smiod #endif 55963b0c7d2Smiod } else 56063b0c7d2Smiod goto dead_end; 56163b0c7d2Smiod break; 56263b0c7d2Smiod 563af7386c3Smickey case T_DATALIGN | T_USER: 56478a8f2b7Smiod datalign_user: 565137d3021Smickey sv.sival_int = va; 566f4e9e19cSguenther KERNEL_LOCK(); 567af7386c3Smickey trapsignal(p, SIGBUS, vftype, BUS_ADRALN, sv); 568f4e9e19cSguenther KERNEL_UNLOCK(); 569af7386c3Smickey break; 570af7386c3Smickey 571a24c0b7aSmickey case T_INTERRUPT: 572a24c0b7aSmickey case T_INTERRUPT | T_USER: 573a24c0b7aSmickey cpu_intr(frame); 574af7386c3Smickey break; 575af7386c3Smickey 576b7d25a19Smickey case T_CONDITION: 577b7d25a19Smickey panic("trap: divide by zero in the kernel"); 578b7d25a19Smickey break; 579b7d25a19Smickey 5803147f0deSmickey case T_ILLEGAL: 5813147f0deSmickey case T_ILLEGAL | T_USER: 5823147f0deSmickey /* see if it's a SPOP1,,0 */ 58396415af6Smickey if ((opcode & 0xfffffe00) == 0x10000200) { 58496415af6Smickey frame_regmap(frame, opcode & 0x1f) = 0; 5853147f0deSmickey frame->tf_ipsw |= PSL_N; 5863147f0deSmickey break; 5873147f0deSmickey } 5883147f0deSmickey if (type & T_USER) { 5893147f0deSmickey sv.sival_int = va; 590f4e9e19cSguenther KERNEL_LOCK(); 5913147f0deSmickey trapsignal(p, SIGILL, type & ~T_USER, ILL_ILLOPC, sv); 592f4e9e19cSguenther KERNEL_UNLOCK(); 5933147f0deSmickey break; 5943147f0deSmickey } 5953147f0deSmickey /* FALLTHROUGH */ 5963147f0deSmickey 59778a8f2b7Smiod /* 59878a8f2b7Smiod * On PCXS processors, traps T_DATACC, T_DATAPID and T_DATALIGN 59978a8f2b7Smiod * are shared. We need to sort out the unaligned access situation 60078a8f2b7Smiod * first, before handling this trap as T_DATACC. 60178a8f2b7Smiod */ 6022ef9a47eSmickey case T_DPROT: 60378a8f2b7Smiod if (cpu_type == hpcxs) { 60478a8f2b7Smiod if (pcxs_unaligned(opcode, va)) 60578a8f2b7Smiod goto dead_end; 60678a8f2b7Smiod else 60778a8f2b7Smiod goto datacc; 60878a8f2b7Smiod } 60978a8f2b7Smiod /* FALLTHROUGH to unimplemented */ 61078a8f2b7Smiod 61178a8f2b7Smiod case T_LOWERPL: 6122ef9a47eSmickey case T_IPROT: 613af7386c3Smickey case T_OVERFLOW: 614af7386c3Smickey case T_HIGHERPL: 615af7386c3Smickey case T_TAKENBR: 616af7386c3Smickey case T_POWERFAIL: 617af7386c3Smickey case T_LPMC: 618af7386c3Smickey case T_PAGEREF: 619d412f1c2Smickey /* FALLTHROUGH to unimplemented */ 620d412f1c2Smickey default: 621ea3191ebSjsing #ifdef TRAPDEBUG 622532740e6Smickey if (kdb_trap(type, va, frame)) 623137d3021Smickey return; 624137d3021Smickey #endif 62570016991Smickey panic("trap: unimplemented \'%s\' (%d)", tts, trapnum); 626d412f1c2Smickey } 627af7386c3Smickey 62870016991Smickey #ifdef DIAGNOSTIC 629473ddf34Sjsing if (curcpu()->ci_cpl != oldcpl) 63070016991Smickey printf("WARNING: SPL (%d) NOT LOWERED ON " 631473ddf34Sjsing "TRAP (%d) EXIT\n", curcpu()->ci_cpl, trapnum); 63270016991Smickey #endif 63370016991Smickey 63470016991Smickey if (trapnum != T_INTERRUPT) 635473ddf34Sjsing splx(curcpu()->ci_cpl); /* process softints */ 63670016991Smickey 637ba42a120Smickey /* 638ba42a120Smickey * in case we were interrupted from the syscall gate page 63924d53bfeSkrw * treat this as we were not really running user code no more 640ba42a120Smickey * for weird things start to happen on return to the userland 641ba42a120Smickey * and also see a note in locore.S:TLABEL(all) 642ba42a120Smickey */ 6437b428176Smickey if ((type & T_USER) && !(frame->tf_iisq_head == HPPA_SID_KERNEL && 644c2b93341Sderaadt (frame->tf_iioq_head & ~PAGE_MASK) == SYSCALLGATE)) { 645c2b93341Sderaadt ast(p); 646c19cb33fSmickey userret(p); 647d412f1c2Smickey } 648c2b93341Sderaadt } 649d412f1c2Smickey 650d412f1c2Smickey void 651cfad034cSjsing child_return(void *arg) 652d412f1c2Smickey { 653db36253aSmickey struct proc *p = (struct proc *)arg; 65489afe3e5Smickey struct trapframe *tf = p->p_md.md_regs; 65589afe3e5Smickey 65689afe3e5Smickey /* 65789afe3e5Smickey * Set up return value registers as libc:fork() expects 65889afe3e5Smickey */ 65989afe3e5Smickey tf->tf_ret0 = 0; 66089afe3e5Smickey tf->tf_ret1 = 1; /* ischild */ 66189afe3e5Smickey tf->tf_t1 = 0; /* errno */ 66289afe3e5Smickey 663971e1bb6Sart KERNEL_UNLOCK(); 664cfad034cSjsing 665c2b93341Sderaadt ast(p); 666fc572715Sguenther 667fc572715Sguenther mi_child_return(p); 668556d2ba7Smickey } 669556d2ba7Smickey 6707bfbef72Skettenis #ifdef PTRACE 6717bfbef72Skettenis 6727bfbef72Skettenis #include <sys/ptrace.h> 6737bfbef72Skettenis 674dd6e4488Sderaadt int ss_get_value(struct proc *p, vaddr_t addr, u_int *value); 675dd6e4488Sderaadt int ss_put_value(struct proc *p, vaddr_t addr, u_int value); 676dd6e4488Sderaadt 6777bfbef72Skettenis int 6787bfbef72Skettenis ss_get_value(struct proc *p, vaddr_t addr, u_int *value) 6797bfbef72Skettenis { 6807bfbef72Skettenis struct uio uio; 6817bfbef72Skettenis struct iovec iov; 6827bfbef72Skettenis 6837bfbef72Skettenis iov.iov_base = (caddr_t)value; 6847bfbef72Skettenis iov.iov_len = sizeof(u_int); 6857bfbef72Skettenis uio.uio_iov = &iov; 6867bfbef72Skettenis uio.uio_iovcnt = 1; 6877bfbef72Skettenis uio.uio_offset = (off_t)addr; 6887bfbef72Skettenis uio.uio_resid = sizeof(u_int); 6897bfbef72Skettenis uio.uio_segflg = UIO_SYSSPACE; 6907bfbef72Skettenis uio.uio_rw = UIO_READ; 6917bfbef72Skettenis uio.uio_procp = curproc; 6920888e41eSmiod return (process_domem(curproc, p, &uio, PT_READ_I)); 6937bfbef72Skettenis } 6947bfbef72Skettenis 6957bfbef72Skettenis int 6967bfbef72Skettenis ss_put_value(struct proc *p, vaddr_t addr, u_int value) 6977bfbef72Skettenis { 6987bfbef72Skettenis struct uio uio; 6997bfbef72Skettenis struct iovec iov; 7007bfbef72Skettenis 7017bfbef72Skettenis iov.iov_base = (caddr_t)&value; 7027bfbef72Skettenis iov.iov_len = sizeof(u_int); 7037bfbef72Skettenis uio.uio_iov = &iov; 7047bfbef72Skettenis uio.uio_iovcnt = 1; 7057bfbef72Skettenis uio.uio_offset = (off_t)addr; 7067bfbef72Skettenis uio.uio_resid = sizeof(u_int); 7077bfbef72Skettenis uio.uio_segflg = UIO_SYSSPACE; 7087bfbef72Skettenis uio.uio_rw = UIO_WRITE; 7097bfbef72Skettenis uio.uio_procp = curproc; 7100888e41eSmiod return (process_domem(curproc, p, &uio, PT_WRITE_I)); 7117bfbef72Skettenis } 7127bfbef72Skettenis 7137bfbef72Skettenis void 7147bfbef72Skettenis ss_clear_breakpoints(struct proc *p) 7157bfbef72Skettenis { 7167bfbef72Skettenis /* Restore origional instructions. */ 7177bfbef72Skettenis if (p->p_md.md_bpva != 0) { 7187bfbef72Skettenis ss_put_value(p, p->p_md.md_bpva, p->p_md.md_bpsave[0]); 7197bfbef72Skettenis ss_put_value(p, p->p_md.md_bpva + 4, p->p_md.md_bpsave[1]); 7207bfbef72Skettenis p->p_md.md_bpva = 0; 7217bfbef72Skettenis } 7227bfbef72Skettenis } 7237bfbef72Skettenis 7247bfbef72Skettenis int 7257bfbef72Skettenis process_sstep(struct proc *p, int sstep) 7267bfbef72Skettenis { 7277bfbef72Skettenis int error; 7287bfbef72Skettenis 7297bfbef72Skettenis ss_clear_breakpoints(p); 7307bfbef72Skettenis 73185bd3014Skettenis if (sstep == 0) { 7327bfbef72Skettenis p->p_md.md_regs->tf_ipsw &= ~PSL_T; 7337bfbef72Skettenis return (0); 7347bfbef72Skettenis } 7357bfbef72Skettenis 73685bd3014Skettenis /* 73785bd3014Skettenis * Don't touch the syscall gateway page. Instead, insert a 73885bd3014Skettenis * breakpoint where we're supposed to return. 73985bd3014Skettenis */ 74085bd3014Skettenis if ((p->p_md.md_regs->tf_iioq_tail & ~PAGE_MASK) == SYSCALLGATE) 74185bd3014Skettenis p->p_md.md_bpva = p->p_md.md_regs->tf_r31 & ~HPPA_PC_PRIV_MASK; 74285bd3014Skettenis else 7437bfbef72Skettenis p->p_md.md_bpva = p->p_md.md_regs->tf_iioq_tail & ~HPPA_PC_PRIV_MASK; 7447bfbef72Skettenis 7457bfbef72Skettenis /* 7467bfbef72Skettenis * Insert two breakpoint instructions; the first one might be 7477bfbef72Skettenis * nullified. Of course we need to save two instruction 7487bfbef72Skettenis * first. 7497bfbef72Skettenis */ 7507bfbef72Skettenis 7517bfbef72Skettenis error = ss_get_value(p, p->p_md.md_bpva, &p->p_md.md_bpsave[0]); 7527bfbef72Skettenis if (error) 7537bfbef72Skettenis return (error); 7547bfbef72Skettenis error = ss_get_value(p, p->p_md.md_bpva + 4, &p->p_md.md_bpsave[1]); 7557bfbef72Skettenis if (error) 7567bfbef72Skettenis return (error); 7577bfbef72Skettenis 7587bfbef72Skettenis error = ss_put_value(p, p->p_md.md_bpva, SSBREAKPOINT); 7597bfbef72Skettenis if (error) 7607bfbef72Skettenis return (error); 7617bfbef72Skettenis error = ss_put_value(p, p->p_md.md_bpva + 4, SSBREAKPOINT); 7627bfbef72Skettenis if (error) 7637bfbef72Skettenis return (error); 7647bfbef72Skettenis 76585bd3014Skettenis if ((p->p_md.md_regs->tf_iioq_tail & ~PAGE_MASK) != SYSCALLGATE) 7667bfbef72Skettenis p->p_md.md_regs->tf_ipsw |= PSL_T; 76785bd3014Skettenis else 76885bd3014Skettenis p->p_md.md_regs->tf_ipsw &= ~PSL_T; 76985bd3014Skettenis 7707bfbef72Skettenis return (0); 7717bfbef72Skettenis } 7727bfbef72Skettenis 7737bfbef72Skettenis #endif /* PTRACE */ 774db97f33bSmickey 775dd6e4488Sderaadt void syscall(struct trapframe *frame); 776dd6e4488Sderaadt 777b9b95e0dSmickey /* 778b9b95e0dSmickey * call actual syscall routine 779b9b95e0dSmickey */ 780b9b95e0dSmickey void 78170016991Smickey syscall(struct trapframe *frame) 782b9b95e0dSmickey { 783db97f33bSmickey register struct proc *p = curproc; 784b9b95e0dSmickey register const struct sysent *callp; 7859417b0e6Sguenther int retq, nsys, code, argsize, argoff, error; 786b7d25a19Smickey register_t args[8], rval[2]; 78770016991Smickey #ifdef DIAGNOSTIC 788473ddf34Sjsing int oldcpl = curcpu()->ci_cpl; 78970016991Smickey #endif 790b9b95e0dSmickey 791b9b95e0dSmickey uvmexp.syscalls++; 792b9b95e0dSmickey 793b9b95e0dSmickey if (!USERMODE(frame->tf_iioq_head)) 794b9b95e0dSmickey panic("syscall"); 795b9b95e0dSmickey 796137d3021Smickey p->p_md.md_regs = frame; 7978f76f5adSguenther nsys = p->p_p->ps_emul->e_nsysent; 7988f76f5adSguenther callp = p->p_p->ps_emul->e_sysent; 799db97f33bSmickey 800b7d25a19Smickey argoff = 4; retq = 0; 801db97f33bSmickey switch (code = frame->tf_t1) { 802b9b95e0dSmickey case SYS_syscall: 803db97f33bSmickey code = frame->tf_arg0; 804db97f33bSmickey args[0] = frame->tf_arg1; 805db97f33bSmickey args[1] = frame->tf_arg2; 806db97f33bSmickey args[2] = frame->tf_arg3; 807db97f33bSmickey argoff = 3; 808b9b95e0dSmickey break; 809b9b95e0dSmickey case SYS___syscall: 810b9b95e0dSmickey if (callp != sysent) 811b9b95e0dSmickey break; 812db97f33bSmickey /* 813db97f33bSmickey * this works, because quads get magically swapped 8147503858eSjfb * due to the args being laid backwards on the stack 815db97f33bSmickey * and then copied in words 816db97f33bSmickey */ 817db97f33bSmickey code = frame->tf_arg0; 818db97f33bSmickey args[0] = frame->tf_arg2; 819db97f33bSmickey args[1] = frame->tf_arg3; 820db97f33bSmickey argoff = 2; 821b7d25a19Smickey retq = 1; 822db97f33bSmickey break; 823db97f33bSmickey default: 824db97f33bSmickey args[0] = frame->tf_arg0; 825db97f33bSmickey args[1] = frame->tf_arg1; 826db97f33bSmickey args[2] = frame->tf_arg2; 827db97f33bSmickey args[3] = frame->tf_arg3; 828db97f33bSmickey break; 829b9b95e0dSmickey } 830b9b95e0dSmickey 831b9b95e0dSmickey if (code < 0 || code >= nsys) 8328f76f5adSguenther callp += p->p_p->ps_emul->e_nosys; /* bad syscall # */ 833b9b95e0dSmickey else 834b9b95e0dSmickey callp += code; 835db97f33bSmickey 836db97f33bSmickey if ((argsize = callp->sy_argsize)) { 837db97f33bSmickey int i; 838db97f33bSmickey 839db97f33bSmickey for (i = 0, argsize -= argoff * 4; 840db97f33bSmickey argsize > 0; i++, argsize -= 4) { 841fc572715Sguenther if ((error = copyin((void *)(frame->tf_sp + 842fc572715Sguenther HPPA_FRAME_ARG(i + 4)), args + i + argoff, 4))) 843fc572715Sguenther goto bad; 844db97f33bSmickey } 845db97f33bSmickey 846db97f33bSmickey /* 847db97f33bSmickey * coming from syscall() or __syscall we must be 848db97f33bSmickey * having one of those w/ a 64 bit arguments, 849db97f33bSmickey * which needs a word swap due to the order 850db97f33bSmickey * of the arguments on the stack. 851db97f33bSmickey * this assumes that none of 'em are called 852db97f33bSmickey * by their normal syscall number, maybe a regress 853b49f4f07Smiod * test should be used, to watch the behaviour. 854db97f33bSmickey */ 855fc572715Sguenther if (argoff < 4) { 856db97f33bSmickey int t; 857db97f33bSmickey 858db97f33bSmickey i = 0; 859db97f33bSmickey switch (code) { 860b7d25a19Smickey case SYS_lseek: retq = 0; 861db97f33bSmickey case SYS_truncate: 862db97f33bSmickey case SYS_ftruncate: i = 2; break; 863db97f33bSmickey case SYS_preadv: 864db97f33bSmickey case SYS_pwritev: 865db97f33bSmickey case SYS_pread: 866db97f33bSmickey case SYS_pwrite: i = 4; break; 867a9d0813cSmiod case SYS_mquery: 868db97f33bSmickey case SYS_mmap: i = 6; break; 869db97f33bSmickey } 870db97f33bSmickey 871db97f33bSmickey if (i) { 872db97f33bSmickey t = args[i]; 873db97f33bSmickey args[i] = args[i + 1]; 874db97f33bSmickey args[i + 1] = t; 875db97f33bSmickey } 876db97f33bSmickey } 877db97f33bSmickey } 878b9b95e0dSmickey 879b9b95e0dSmickey rval[0] = 0; 880db97f33bSmickey rval[1] = frame->tf_ret1; 881cfad034cSjsing 8829417b0e6Sguenther error = mi_syscall(p, code, callp, args, rval); 883fc572715Sguenther 88496a1071fSmiod switch (error) { 885b9b95e0dSmickey case 0: 886b9b95e0dSmickey frame->tf_ret0 = rval[0]; 887b7d25a19Smickey frame->tf_ret1 = rval[!retq]; 888137d3021Smickey frame->tf_t1 = 0; 889b9b95e0dSmickey break; 890b9b95e0dSmickey case ERESTART: 891c37e03c6Smickey frame->tf_iioq_head -= 12; 892c37e03c6Smickey frame->tf_iioq_tail -= 12; 893b9b95e0dSmickey case EJUSTRETURN: 894b9b95e0dSmickey break; 895b9b95e0dSmickey default: 896db97f33bSmickey bad: 897137d3021Smickey frame->tf_t1 = error; 89847df6ae3Smickey frame->tf_ret0 = error; 89947df6ae3Smickey frame->tf_ret1 = 0; 900b9b95e0dSmickey break; 901b9b95e0dSmickey } 902fc572715Sguenther 903c2b93341Sderaadt ast(p); 904fc572715Sguenther 9059417b0e6Sguenther mi_syscall_return(p, code, error, rval); 906fc572715Sguenther 90770016991Smickey #ifdef DIAGNOSTIC 908473ddf34Sjsing if (curcpu()->ci_cpl != oldcpl) { 90970016991Smickey printf("WARNING: SPL (0x%x) NOT LOWERED ON " 910c8b758f8Smiod "syscall(0x%x, 0x%lx, 0x%lx, 0x%lx...) EXIT, PID %d\n", 911473ddf34Sjsing curcpu()->ci_cpl, code, args[0], args[1], args[2], 912473ddf34Sjsing p->p_pid); 913473ddf34Sjsing curcpu()->ci_cpl = oldcpl; 91450552582Smickey } 91570016991Smickey #endif 916473ddf34Sjsing splx(curcpu()->ci_cpl); /* process softints */ 917b9b95e0dSmickey } 91878a8f2b7Smiod 91978a8f2b7Smiod /* 92078a8f2b7Smiod * Decide if opcode `opcode' accessing virtual address `va' caused an 92178a8f2b7Smiod * unaligned trap. Returns zero if the access is correctly aligned. 92278a8f2b7Smiod * Used on PCXS processors to sort out exception causes. 92378a8f2b7Smiod */ 92478a8f2b7Smiod int 92578a8f2b7Smiod pcxs_unaligned(u_int opcode, vaddr_t va) 92678a8f2b7Smiod { 92778a8f2b7Smiod u_int mbz_bits; 92878a8f2b7Smiod 92978a8f2b7Smiod /* 93078a8f2b7Smiod * Exit early if the va is obviously aligned enough. 93178a8f2b7Smiod */ 93278a8f2b7Smiod if ((va & 0x0f) == 0) 93378a8f2b7Smiod return 0; 93478a8f2b7Smiod 93578a8f2b7Smiod mbz_bits = 0; 93678a8f2b7Smiod 93778a8f2b7Smiod /* 93878a8f2b7Smiod * Only load and store instructions can cause unaligned access. 93978a8f2b7Smiod * There are three opcode patterns to look for: 94078a8f2b7Smiod * - canonical load/store 94178a8f2b7Smiod * - load/store short or indexed 94278a8f2b7Smiod * - coprocessor load/store 94378a8f2b7Smiod */ 94478a8f2b7Smiod 94578a8f2b7Smiod if ((opcode & 0xd0000000) == 0x40000000) { 94678a8f2b7Smiod switch ((opcode >> 26) & 0x03) { 94778a8f2b7Smiod case 0x00: /* ldb, stb */ 94878a8f2b7Smiod mbz_bits = 0x00; 94978a8f2b7Smiod break; 95078a8f2b7Smiod case 0x01: /* ldh, sth */ 95178a8f2b7Smiod mbz_bits = 0x01; 95278a8f2b7Smiod break; 95378a8f2b7Smiod case 0x02: /* ldw, stw */ 95478a8f2b7Smiod case 0x03: /* ldwm, stwm */ 95578a8f2b7Smiod mbz_bits = 0x03; 95678a8f2b7Smiod break; 95778a8f2b7Smiod } 95878a8f2b7Smiod } else 95978a8f2b7Smiod 96078a8f2b7Smiod if ((opcode & 0xfc000000) == 0x0c000000) { 96178a8f2b7Smiod switch ((opcode >> 6) & 0x0f) { 96278a8f2b7Smiod case 0x01: /* ldhx, ldhs */ 96378a8f2b7Smiod mbz_bits = 0x01; 96478a8f2b7Smiod break; 96578a8f2b7Smiod case 0x02: /* ldwx, ldws */ 96678a8f2b7Smiod mbz_bits = 0x03; 96778a8f2b7Smiod break; 96878a8f2b7Smiod case 0x07: /* ldcwx, ldcws */ 96978a8f2b7Smiod mbz_bits = 0x0f; 97078a8f2b7Smiod break; 97178a8f2b7Smiod case 0x09: 97278a8f2b7Smiod if ((opcode & (1 << 12)) != 0) /* sths */ 97378a8f2b7Smiod mbz_bits = 0x01; 97478a8f2b7Smiod break; 97578a8f2b7Smiod case 0x0a: 97678a8f2b7Smiod if ((opcode & (1 << 12)) != 0) /* stws */ 97778a8f2b7Smiod mbz_bits = 0x03; 97878a8f2b7Smiod break; 97978a8f2b7Smiod } 98078a8f2b7Smiod } else 98178a8f2b7Smiod 98278a8f2b7Smiod if ((opcode & 0xf4000000) == 0x24000000) { 98378a8f2b7Smiod if ((opcode & (1 << 27)) != 0) { 98478a8f2b7Smiod /* cldwx, cstwx, cldws, cstws */ 98578a8f2b7Smiod mbz_bits = 0x03; 98678a8f2b7Smiod } else { 98778a8f2b7Smiod /* clddx, cstdx, cldds, cstds */ 98878a8f2b7Smiod mbz_bits = 0x07; 98978a8f2b7Smiod } 99078a8f2b7Smiod } 99178a8f2b7Smiod 99278a8f2b7Smiod return (va & mbz_bits); 99378a8f2b7Smiod } 994