1*9b476898Smickey /* $OpenBSD: trap.c,v 1.84 2005/01/17 20:47:40 mickey 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> 34b9b95e0dSmickey #include <sys/ktrace.h> 35d412f1c2Smickey #include <sys/proc.h> 366acb4cb0Sniklas #include <sys/signalvar.h> 37d412f1c2Smickey #include <sys/user.h> 38556d2ba7Smickey 39af7386c3Smickey #include <net/netisr.h> 40af7386c3Smickey 4196a1071fSmiod #include "systrace.h" 4296a1071fSmiod #include <dev/systrace.h> 4396a1071fSmiod 44b9b95e0dSmickey #include <uvm/uvm.h> 45556d2ba7Smickey 46556d2ba7Smickey #include <machine/autoconf.h> 47556d2ba7Smickey 483867ea13Smiod #include <machine/db_machdep.h> /* XXX always needed for inst_store() */ 49137d3021Smickey #ifdef DDB 509d159c9dSmickey #ifdef TRAPDEBUG 51137d3021Smickey #include <ddb/db_output.h> 52137d3021Smickey #endif 539d159c9dSmickey #endif 54556d2ba7Smickey 55556d2ba7Smickey const char *trap_type[] = { 56e494c7cfSmickey "invalid", 57e494c7cfSmickey "HPMC", 58556d2ba7Smickey "power failure", 59137d3021Smickey "recovery counter", 60556d2ba7Smickey "external interrupt", 61e494c7cfSmickey "LPMC", 62e494c7cfSmickey "ITLB miss fault", 63137d3021Smickey "instruction protection", 64137d3021Smickey "Illegal instruction", 65137d3021Smickey "break instruction", 66137d3021Smickey "privileged operation", 67137d3021Smickey "privileged register", 68137d3021Smickey "overflow", 69137d3021Smickey "conditional", 70137d3021Smickey "assist exception", 71e494c7cfSmickey "DTLB miss", 72137d3021Smickey "ITLB non-access miss", 73137d3021Smickey "DTLB non-access miss", 74137d3021Smickey "data protection/rights/alignment", 75137d3021Smickey "data break", 76e494c7cfSmickey "TLB dirty", 77137d3021Smickey "page reference", 78137d3021Smickey "assist emulation", 79e494c7cfSmickey "higher-priv transfer", 80e494c7cfSmickey "lower-priv transfer", 81137d3021Smickey "taken branch", 82137d3021Smickey "data access rights", 83e494c7cfSmickey "data protection", 84137d3021Smickey "unaligned data ref", 85556d2ba7Smickey }; 86556d2ba7Smickey int trap_types = sizeof(trap_type)/sizeof(trap_type[0]); 87556d2ba7Smickey 88bed2d21eSmickey int want_resched, astpending; 89556d2ba7Smickey 901aec61b7Smickey #define frame_regmap(tf,r) (((u_int *)(tf))[hppa_regmap[(r)]]) 911aec61b7Smickey u_char hppa_regmap[32] = { 921aec61b7Smickey offsetof(struct trapframe, tf_pad[0]) / 4, /* r0 XXX */ 931aec61b7Smickey offsetof(struct trapframe, tf_r1) / 4, 941aec61b7Smickey offsetof(struct trapframe, tf_rp) / 4, 951aec61b7Smickey offsetof(struct trapframe, tf_r3) / 4, 961aec61b7Smickey offsetof(struct trapframe, tf_r4) / 4, 971aec61b7Smickey offsetof(struct trapframe, tf_r5) / 4, 981aec61b7Smickey offsetof(struct trapframe, tf_r6) / 4, 991aec61b7Smickey offsetof(struct trapframe, tf_r7) / 4, 1001aec61b7Smickey offsetof(struct trapframe, tf_r8) / 4, 1011aec61b7Smickey offsetof(struct trapframe, tf_r9) / 4, 1021aec61b7Smickey offsetof(struct trapframe, tf_r10) / 4, 1031aec61b7Smickey offsetof(struct trapframe, tf_r11) / 4, 1041aec61b7Smickey offsetof(struct trapframe, tf_r12) / 4, 1051aec61b7Smickey offsetof(struct trapframe, tf_r13) / 4, 1061aec61b7Smickey offsetof(struct trapframe, tf_r14) / 4, 1071aec61b7Smickey offsetof(struct trapframe, tf_r15) / 4, 1081aec61b7Smickey offsetof(struct trapframe, tf_r16) / 4, 1091aec61b7Smickey offsetof(struct trapframe, tf_r17) / 4, 1101aec61b7Smickey offsetof(struct trapframe, tf_r18) / 4, 1111aec61b7Smickey offsetof(struct trapframe, tf_t4) / 4, 1121aec61b7Smickey offsetof(struct trapframe, tf_t3) / 4, 1131aec61b7Smickey offsetof(struct trapframe, tf_t2) / 4, 1141aec61b7Smickey offsetof(struct trapframe, tf_t1) / 4, 1151aec61b7Smickey offsetof(struct trapframe, tf_arg3) / 4, 1161aec61b7Smickey offsetof(struct trapframe, tf_arg2) / 4, 1171aec61b7Smickey offsetof(struct trapframe, tf_arg1) / 4, 1181aec61b7Smickey offsetof(struct trapframe, tf_arg0) / 4, 1191aec61b7Smickey offsetof(struct trapframe, tf_dp) / 4, 1201aec61b7Smickey offsetof(struct trapframe, tf_ret0) / 4, 1211aec61b7Smickey offsetof(struct trapframe, tf_ret1) / 4, 1221aec61b7Smickey offsetof(struct trapframe, tf_sp) / 4, 1231aec61b7Smickey offsetof(struct trapframe, tf_r31) / 4, 1241aec61b7Smickey }; 1251aec61b7Smickey 12670016991Smickey void 127d412f1c2Smickey userret(struct proc *p, register_t pc, u_quad_t oticks) 128d412f1c2Smickey { 129d412f1c2Smickey int sig; 130af7386c3Smickey 131d412f1c2Smickey /* take pending signals */ 132d412f1c2Smickey while ((sig = CURSIG(p)) != 0) 133d412f1c2Smickey postsig(sig); 134d412f1c2Smickey 135d412f1c2Smickey p->p_priority = p->p_usrpri; 13670016991Smickey if (astpending) { 13770016991Smickey astpending = 0; 13870016991Smickey if (p->p_flag & P_OWEUPC) { 13970016991Smickey p->p_flag &= ~P_OWEUPC; 14070016991Smickey ADDUPROF(p); 14170016991Smickey } 14270016991Smickey } 143d412f1c2Smickey if (want_resched) { 144d412f1c2Smickey /* 145c81336dcSart * We're being preempted. 146d412f1c2Smickey */ 147c81336dcSart preempt(NULL); 148d412f1c2Smickey while ((sig = CURSIG(p)) != 0) 149d412f1c2Smickey postsig(sig); 150d412f1c2Smickey } 151d412f1c2Smickey 152d412f1c2Smickey /* 153d412f1c2Smickey * If profiling, charge recent system time to the trapped pc. 154d412f1c2Smickey */ 155d412f1c2Smickey if (p->p_flag & P_PROFIL) { 156d412f1c2Smickey extern int psratio; 157d412f1c2Smickey 158d412f1c2Smickey addupc_task(p, pc, (int)(p->p_sticks - oticks) * psratio); 159d412f1c2Smickey } 160d412f1c2Smickey 161d412f1c2Smickey curpriority = p->p_priority; 162d412f1c2Smickey } 163d412f1c2Smickey 164556d2ba7Smickey void 165556d2ba7Smickey trap(type, frame) 166556d2ba7Smickey int type; 167556d2ba7Smickey struct trapframe *frame; 168556d2ba7Smickey { 169556d2ba7Smickey struct proc *p = curproc; 170ab8e80c5Sart vaddr_t va; 171ab8e80c5Sart struct vm_map *map; 172f17fa196Smickey struct vmspace *vm; 173af7386c3Smickey register vm_prot_t vftype; 174556d2ba7Smickey register pa_space_t space; 175af7386c3Smickey union sigval sv; 176c37e03c6Smickey u_int opcode; 17770016991Smickey int ret, trapnum; 178137d3021Smickey const char *tts; 1796198d067Smickey vm_fault_t fault = VM_FAULT_INVALID; 18070016991Smickey #ifdef DIAGNOSTIC 18170016991Smickey int oldcpl = cpl; 18270016991Smickey #endif 1830e979e06Smickey 184c37e03c6Smickey trapnum = type & ~T_USER; 185137d3021Smickey opcode = frame->tf_iir; 186*9b476898Smickey if (trapnum <= T_EXCEPTION || trapnum == T_HIGHERPL || 187*9b476898Smickey trapnum == T_LOWERPL || trapnum == T_TAKENBR || 188*9b476898Smickey trapnum == T_IDEBUG || trapnum == T_PERFMON) { 189a24c0b7aSmickey va = frame->tf_iioq_head; 190a24c0b7aSmickey space = frame->tf_iisq_head; 191e21aaa8cSmickey vftype = UVM_PROT_EXEC; 192a24c0b7aSmickey } else { 193b9b95e0dSmickey va = frame->tf_ior; 194a24c0b7aSmickey space = frame->tf_isr; 195a4be06b3Smickey if (va == frame->tf_iioq_head) 196e21aaa8cSmickey vftype = UVM_PROT_EXEC; 197a4be06b3Smickey else if (inst_store(opcode)) 198e21aaa8cSmickey vftype = UVM_PROT_WRITE; 199a4be06b3Smickey else 200e21aaa8cSmickey vftype = UVM_PROT_READ; 201556d2ba7Smickey } 202137d3021Smickey 203137d3021Smickey if (frame->tf_flags & TFF_LAST) 204137d3021Smickey p->p_md.md_regs = frame; 205137d3021Smickey 206c37e03c6Smickey if (trapnum > trap_types) 207137d3021Smickey tts = "reserved"; 208137d3021Smickey else 209c37e03c6Smickey tts = trap_type[trapnum]; 210137d3021Smickey 211446209b7Smiod #ifdef TRAPDEBUG 212c37e03c6Smickey if (trapnum != T_INTERRUPT && trapnum != T_IBREAK) 213969c5366Smickey db_printf("trap: %x, %s for %x:%x at %x:%x, fl=%x, fp=%p\n", 214137d3021Smickey type, tts, space, va, frame->tf_iisq_head, 215137d3021Smickey frame->tf_iioq_head, frame->tf_flags, frame); 216c37e03c6Smickey else if (trapnum == T_IBREAK) 217137d3021Smickey db_printf("trap: break instruction %x:%x at %x:%x, fp=%p\n", 218a24c0b7aSmickey break5(opcode), break13(opcode), 219137d3021Smickey frame->tf_iisq_head, frame->tf_iioq_head, frame); 220e494c7cfSmickey 221e494c7cfSmickey { 222e494c7cfSmickey extern int etext; 223532740e6Smickey if (frame < (struct trapframe *)&etext) { 224532740e6Smickey printf("trap: bogus frame ptr %p\n", frame); 225e494c7cfSmickey goto dead_end; 226e494c7cfSmickey } 227532740e6Smickey } 228d412f1c2Smickey #endif 2297d3bf75dSmickey if (trapnum != T_INTERRUPT) { 2307d3bf75dSmickey uvmexp.traps++; 23170016991Smickey mtctl(frame->tf_eiem, CR_EIEM); 232916310a5Smickey } 23370016991Smickey 234556d2ba7Smickey switch (type) { 235556d2ba7Smickey case T_NONEXIST: 236556d2ba7Smickey case T_NONEXIST | T_USER: 237af7386c3Smickey /* we've got screwed up by the central scrutinizer */ 238b67578d8Smickey printf("trap: elvis has just left the building!\n"); 239532740e6Smickey goto dead_end; 240b67578d8Smickey 241556d2ba7Smickey case T_RECOVERY: 242556d2ba7Smickey case T_RECOVERY | T_USER: 243af7386c3Smickey /* XXX will implement later */ 244556d2ba7Smickey printf("trap: handicapped"); 245532740e6Smickey goto dead_end; 24666d1ab7aSmickey 24766d1ab7aSmickey #ifdef DIAGNOSTIC 24866d1ab7aSmickey case T_EXCEPTION: 24966d1ab7aSmickey panic("FPU/SFU emulation botch"); 25066d1ab7aSmickey 25166d1ab7aSmickey /* these just can't happen ever */ 25266d1ab7aSmickey case T_PRIV_OP: 25366d1ab7aSmickey case T_PRIV_REG: 25466d1ab7aSmickey /* these just can't make it to the trap() ever */ 255c6555f83Sderaadt case T_HPMC: 256c6555f83Sderaadt case T_HPMC | T_USER: 25766d1ab7aSmickey #endif 258f4daacd8Smickey case T_IBREAK: 259a24c0b7aSmickey case T_DATALIGN: 260a24c0b7aSmickey case T_DBREAK: 2618de28e3eSmickey dead_end: 262a24c0b7aSmickey #ifdef DDB 263532740e6Smickey if (kdb_trap (type, va, frame)) { 264a24c0b7aSmickey if (type == T_IBREAK) { 265f4daacd8Smickey /* skip break instruction */ 2668de28e3eSmickey frame->tf_iioq_head = frame->tf_iioq_tail; 267f4daacd8Smickey frame->tf_iioq_tail += 4; 268a24c0b7aSmickey } 269556d2ba7Smickey return; 270a24c0b7aSmickey } 271137d3021Smickey #else 272137d3021Smickey if (type == T_DATALIGN) 273137d3021Smickey panic ("trap: %s at 0x%x", tts, va); 274137d3021Smickey else 275137d3021Smickey panic ("trap: no debugger for \"%s\" (%d)", tts, type); 276a24c0b7aSmickey #endif 277556d2ba7Smickey break; 278556d2ba7Smickey 279af7386c3Smickey case T_IBREAK | T_USER: 280af7386c3Smickey case T_DBREAK | T_USER: 281af7386c3Smickey /* pass to user debugger */ 282c66794d8Skettenis trapsignal(p, SIGTRAP, type &~ T_USER, TRAP_BRKPT, sv); 283d412f1c2Smickey break; 284d412f1c2Smickey 28538575cbdSmickey case T_EXCEPTION | T_USER: { 286969eb289Smickey u_int64_t *fpp = (u_int64_t *)frame->tf_cr30; 287969eb289Smickey u_int32_t *pex; 28838575cbdSmickey int i, flt; 28938575cbdSmickey 290969eb289Smickey pex = (u_int32_t *)&fpp[0]; 29138575cbdSmickey for (i = 0, pex++; i < 7 && !*pex; i++, pex++); 292969eb289Smickey flt = 0; 293969eb289Smickey if (i < 7) { 294969eb289Smickey u_int32_t stat = HPPA_FPU_OP(*pex); 29528496d60Smickey if (stat & HPPA_FPU_UNMPL) 296969eb289Smickey flt = FPE_FLTINV; 29728496d60Smickey else if (stat & (HPPA_FPU_V << 1)) 29838575cbdSmickey flt = FPE_FLTINV; 29928496d60Smickey else if (stat & (HPPA_FPU_Z << 1)) 30038575cbdSmickey flt = FPE_FLTDIV; 30128496d60Smickey else if (stat & (HPPA_FPU_I << 1)) 302969eb289Smickey flt = FPE_FLTRES; 30328496d60Smickey else if (stat & (HPPA_FPU_O << 1)) 30438575cbdSmickey flt = FPE_FLTOVF; 30528496d60Smickey else if (stat & (HPPA_FPU_U << 1)) 30638575cbdSmickey flt = FPE_FLTUND; 307969eb289Smickey /* still left: under/over-flow w/ inexact */ 308ded58a29Smickey 309ded58a29Smickey /* cleanup exceptions (XXX deliver all ?) */ 310ded58a29Smickey while (i++ < 7) 311ded58a29Smickey *pex++ = 0; 312969eb289Smickey } 313969eb289Smickey /* reset the trap flag, as if there was none */ 314969eb289Smickey fpp[0] &= ~(((u_int64_t)HPPA_FPU_T) << 32); 315969eb289Smickey /* flush out, since load is done from phys, only 4 regs */ 316969eb289Smickey fdcache(HPPA_SID_KERNEL, (vaddr_t)fpp, 8 * 4); 31738575cbdSmickey 31838575cbdSmickey sv.sival_int = va; 31938575cbdSmickey trapsignal(p, SIGFPE, type &~ T_USER, flt, sv); 32038575cbdSmickey } 32138575cbdSmickey break; 32238575cbdSmickey 323969eb289Smickey case T_EMULATION: 324969eb289Smickey panic("trap: emulation trap in the kernel"); 325969eb289Smickey break; 326969eb289Smickey 327969eb289Smickey case T_EMULATION | T_USER: 328137d3021Smickey sv.sival_int = va; 32928496d60Smickey trapsignal(p, SIGILL, type &~ T_USER, ILL_COPROC, sv); 330d412f1c2Smickey break; 331d412f1c2Smickey 332af7386c3Smickey case T_OVERFLOW | T_USER: 333137d3021Smickey sv.sival_int = va; 334af7386c3Smickey trapsignal(p, SIGFPE, type &~ T_USER, FPE_INTOVF, sv); 335d412f1c2Smickey break; 336d412f1c2Smickey 337af7386c3Smickey case T_CONDITION | T_USER: 3388b9bddf0Smickey sv.sival_int = va; 3398b9bddf0Smickey trapsignal(p, SIGFPE, type &~ T_USER, FPE_INTDIV, sv); 340af7386c3Smickey break; 341af7386c3Smickey 342af7386c3Smickey case T_PRIV_OP | T_USER: 343137d3021Smickey sv.sival_int = va; 344af7386c3Smickey trapsignal(p, SIGILL, type &~ T_USER, ILL_PRVOPC, sv); 345af7386c3Smickey break; 346af7386c3Smickey 347af7386c3Smickey case T_PRIV_REG | T_USER: 348137d3021Smickey sv.sival_int = va; 349af7386c3Smickey trapsignal(p, SIGILL, type &~ T_USER, ILL_PRVREG, sv); 350af7386c3Smickey break; 351af7386c3Smickey 352af7386c3Smickey /* these should never got here */ 353af7386c3Smickey case T_HIGHERPL | T_USER: 354af7386c3Smickey case T_LOWERPL | T_USER: 355137d3021Smickey sv.sival_int = va; 356a4be06b3Smickey trapsignal(p, SIGSEGV, vftype, SEGV_ACCERR, sv); 357af7386c3Smickey break; 358af7386c3Smickey 359af7386c3Smickey case T_IPROT | T_USER: 360af7386c3Smickey case T_DPROT | T_USER: 361af7386c3Smickey sv.sival_int = va; 362af7386c3Smickey trapsignal(p, SIGSEGV, vftype, SEGV_ACCERR, sv); 363af7386c3Smickey break; 364af7386c3Smickey 3659208e3abSmickey case T_ITLBMISSNA: 3669208e3abSmickey case T_ITLBMISSNA | T_USER: 3679208e3abSmickey case T_DTLBMISSNA: 3689208e3abSmickey case T_DTLBMISSNA | T_USER: 3699208e3abSmickey if (space == HPPA_SID_KERNEL) 3709208e3abSmickey map = kernel_map; 3719208e3abSmickey else { 3729208e3abSmickey vm = p->p_vmspace; 3739208e3abSmickey map = &vm->vm_map; 3749208e3abSmickey } 3759208e3abSmickey 3769208e3abSmickey /* dig probe[rw]i? insns */ 3779208e3abSmickey if ((opcode & 0xfc001f80) == 0x04001180) { 3789208e3abSmickey int pl; 3799208e3abSmickey 3809208e3abSmickey if (opcode & 0x2000) 3819208e3abSmickey pl = (opcode >> 16) & 3; 3829208e3abSmickey else 3839208e3abSmickey pl = frame_regmap(frame, 3849208e3abSmickey (opcode >> 16) & 0x1f) & 3; 3859208e3abSmickey 3869208e3abSmickey if ((type & T_USER && space == HPPA_SID_KERNEL) || 3879208e3abSmickey (frame->tf_iioq_head & 3) != pl || 3889208e3abSmickey (type & T_USER && va >= VM_MAXUSER_ADDRESS) || 3899208e3abSmickey uvm_fault(map, hppa_trunc_page(va), fault, 3909208e3abSmickey opcode & 0x40? UVM_PROT_WRITE : UVM_PROT_READ)) { 3919208e3abSmickey frame_regmap(frame, opcode & 0x1f) = 0; 3929208e3abSmickey frame->tf_ipsw |= PSL_N; 3939208e3abSmickey } 3949208e3abSmickey } else if (type & T_USER) { 3959208e3abSmickey sv.sival_int = va; 3969208e3abSmickey trapsignal(p, SIGILL, type & ~T_USER, ILL_ILLTRP, sv); 3979208e3abSmickey } else 3989208e3abSmickey panic("trap: %s @ 0x%x:0x%x for 0x%x:0x%x irr 0x%08x\n", 3999208e3abSmickey tts, frame->tf_iisq_head, frame->tf_iioq_head, 4009208e3abSmickey space, va, opcode); 4019208e3abSmickey break; 4029208e3abSmickey 4039208e3abSmickey case T_TLB_DIRTY: 4049208e3abSmickey case T_TLB_DIRTY | T_USER: 405c6555f83Sderaadt case T_DATACC: 406c6555f83Sderaadt case T_DATACC | T_USER: 4076198d067Smickey fault = VM_FAULT_PROTECT; 408c6555f83Sderaadt case T_ITLBMISS: 409c6555f83Sderaadt case T_ITLBMISS | T_USER: 410c6555f83Sderaadt case T_DTLBMISS: 411c6555f83Sderaadt case T_DTLBMISS | T_USER: 4128de28e3eSmickey /* 413e494c7cfSmickey * it could be a kernel map for exec_map faults 4148de28e3eSmickey */ 41543a91648Smickey if (space == HPPA_SID_KERNEL) 4168de28e3eSmickey map = kernel_map; 41743a91648Smickey else { 41843a91648Smickey vm = p->p_vmspace; 419f17fa196Smickey map = &vm->vm_map; 42043a91648Smickey } 421556d2ba7Smickey 4229208e3abSmickey /* 4239208e3abSmickey * user faults out of user addr space are always a fail, 4249208e3abSmickey * this happens on va >= VM_MAXUSER_ADDRESS, where 4259208e3abSmickey * space id will be zero and therefore cause 4269208e3abSmickey * a misbehave lower in the code. 4279208e3abSmickey * 4289208e3abSmickey * also check that faulted space id matches the curproc. 4299208e3abSmickey */ 4309208e3abSmickey if ((type & T_USER && va >= VM_MAXUSER_ADDRESS) || 4319208e3abSmickey (type & T_USER && map->pmap->pm_space != space)) { 432906a25e0Smickey sv.sival_int = va; 433906a25e0Smickey trapsignal(p, SIGSEGV, vftype, SEGV_MAPERR, sv); 43443a91648Smickey break; 435906a25e0Smickey } 436532740e6Smickey 437a4be06b3Smickey ret = uvm_fault(map, hppa_trunc_page(va), fault, vftype); 438f17fa196Smickey 439f17fa196Smickey /* 440f17fa196Smickey * If this was a stack access we keep track of the maximum 441f17fa196Smickey * accessed stack size. Also, if uvm_fault gets a protection 442f17fa196Smickey * failure it is due to accessing the stack region outside 443f17fa196Smickey * the current limit and we need to reflect that as an access 444f17fa196Smickey * error. 445f17fa196Smickey */ 44656f69dffSmiod if (space != HPPA_SID_KERNEL && 44762899679Smiod va < (vaddr_t)vm->vm_minsaddr) { 44862899679Smiod if (ret == 0) 44962899679Smiod uvm_grow(p, va); 45062899679Smiod else if (ret == EACCES) 451738a5b4dSart ret = EFAULT; 452f17fa196Smickey } 453f17fa196Smickey 454738a5b4dSart if (ret != 0) { 455af7386c3Smickey if (type & T_USER) { 456a4be06b3Smickey sv.sival_int = va; 457a4be06b3Smickey trapsignal(p, SIGSEGV, vftype, 458a4be06b3Smickey ret == EACCES? SEGV_ACCERR : SEGV_MAPERR, 459a4be06b3Smickey sv); 460137d3021Smickey } else { 4618de28e3eSmickey if (p && p->p_addr->u_pcb.pcb_onfault) { 4628de28e3eSmickey frame->tf_iioq_tail = 4 + 4638de28e3eSmickey (frame->tf_iioq_head = 46438575cbdSmickey p->p_addr->u_pcb.pcb_onfault); 465b04f760fSmickey #ifdef DDB 466b04f760fSmickey frame->tf_iir = 0; 467b04f760fSmickey #endif 468db97f33bSmickey } else { 469db97f33bSmickey panic("trap: " 47056f69dffSmiod "uvm_fault(%p, %lx, %d, %d): %d", 47196415af6Smickey map, va, fault, vftype, ret); 472137d3021Smickey } 473137d3021Smickey } 474db97f33bSmickey } 475556d2ba7Smickey break; 476d412f1c2Smickey 477af7386c3Smickey case T_DATALIGN | T_USER: 478137d3021Smickey sv.sival_int = va; 479af7386c3Smickey trapsignal(p, SIGBUS, vftype, BUS_ADRALN, sv); 480af7386c3Smickey break; 481af7386c3Smickey 482a24c0b7aSmickey case T_INTERRUPT: 483a24c0b7aSmickey case T_INTERRUPT | T_USER: 484a24c0b7aSmickey cpu_intr(frame); 485af7386c3Smickey break; 486af7386c3Smickey 487b7d25a19Smickey case T_CONDITION: 488b7d25a19Smickey panic("trap: divide by zero in the kernel"); 489b7d25a19Smickey break; 490b7d25a19Smickey 4913147f0deSmickey case T_ILLEGAL: 4923147f0deSmickey case T_ILLEGAL | T_USER: 4933147f0deSmickey /* see if it's a SPOP1,,0 */ 49496415af6Smickey if ((opcode & 0xfffffe00) == 0x10000200) { 49596415af6Smickey frame_regmap(frame, opcode & 0x1f) = 0; 4963147f0deSmickey frame->tf_ipsw |= PSL_N; 4973147f0deSmickey break; 4983147f0deSmickey } 4993147f0deSmickey if (type & T_USER) { 5003147f0deSmickey sv.sival_int = va; 5013147f0deSmickey trapsignal(p, SIGILL, type &~ T_USER, ILL_ILLOPC, sv); 5023147f0deSmickey break; 5033147f0deSmickey } 5043147f0deSmickey /* FALLTHROUGH */ 5053147f0deSmickey 50670016991Smickey case T_LOWERPL: 5072ef9a47eSmickey case T_DPROT: 5082ef9a47eSmickey case T_IPROT: 509af7386c3Smickey case T_OVERFLOW: 510af7386c3Smickey case T_HIGHERPL: 511af7386c3Smickey case T_TAKENBR: 512af7386c3Smickey case T_POWERFAIL: 513af7386c3Smickey case T_LPMC: 514af7386c3Smickey case T_PAGEREF: 515c6555f83Sderaadt case T_DATAPID: 516c6555f83Sderaadt case T_DATAPID | T_USER: 517d412f1c2Smickey if (0 /* T-chip */) { 518d412f1c2Smickey break; 519556d2ba7Smickey } 520d412f1c2Smickey /* FALLTHROUGH to unimplemented */ 521d412f1c2Smickey default: 522a228f8d2Smickey #if 0 523532740e6Smickey if (kdb_trap (type, va, frame)) 524137d3021Smickey return; 525137d3021Smickey #endif 52670016991Smickey panic("trap: unimplemented \'%s\' (%d)", tts, trapnum); 527d412f1c2Smickey } 528af7386c3Smickey 52970016991Smickey #ifdef DIAGNOSTIC 53070016991Smickey if (cpl != oldcpl) 53170016991Smickey printf("WARNING: SPL (%d) NOT LOWERED ON " 53270016991Smickey "TRAP (%d) EXIT\n", cpl, trapnum); 53370016991Smickey #endif 53470016991Smickey 53570016991Smickey if (trapnum != T_INTERRUPT) 53670016991Smickey splx(cpl); /* process softints */ 53770016991Smickey 538ba42a120Smickey /* 539ba42a120Smickey * in case we were interrupted from the syscall gate page 540ba42a120Smickey * treat this as we were not realy running user code no more 541ba42a120Smickey * for weird things start to happen on return to the userland 542ba42a120Smickey * and also see a note in locore.S:TLABEL(all) 543ba42a120Smickey */ 544ba42a120Smickey if ((type & T_USER) && 545ba42a120Smickey (frame->tf_iioq_head & ~PAGE_MASK) != SYSCALLGATE) 54670016991Smickey userret(p, frame->tf_iioq_head, 0); 547d412f1c2Smickey } 548d412f1c2Smickey 549d412f1c2Smickey void 550db36253aSmickey child_return(arg) 551db36253aSmickey void *arg; 552d412f1c2Smickey { 553db36253aSmickey struct proc *p = (struct proc *)arg; 55489afe3e5Smickey struct trapframe *tf = p->p_md.md_regs; 55589afe3e5Smickey 55689afe3e5Smickey /* 55789afe3e5Smickey * Set up return value registers as libc:fork() expects 55889afe3e5Smickey */ 55989afe3e5Smickey tf->tf_ret0 = 0; 56089afe3e5Smickey tf->tf_ret1 = 1; /* ischild */ 56189afe3e5Smickey tf->tf_t1 = 0; /* errno */ 56289afe3e5Smickey 56389afe3e5Smickey userret(p, tf->tf_iioq_head, 0); 564d412f1c2Smickey #ifdef KTRACE 565d412f1c2Smickey if (KTRPOINT(p, KTR_SYSRET)) 566a27b30d8Sart ktrsysret(p, SYS_fork, 0, 0); 567d412f1c2Smickey #endif 568556d2ba7Smickey } 569556d2ba7Smickey 570db97f33bSmickey 571b9b95e0dSmickey /* 572b9b95e0dSmickey * call actual syscall routine 573b9b95e0dSmickey */ 574b9b95e0dSmickey void 57570016991Smickey syscall(struct trapframe *frame) 576b9b95e0dSmickey { 577db97f33bSmickey register struct proc *p = curproc; 578b9b95e0dSmickey register const struct sysent *callp; 579b7d25a19Smickey int retq, nsys, code, argsize, argoff, oerror, error; 580b7d25a19Smickey register_t args[8], rval[2]; 58170016991Smickey #ifdef DIAGNOSTIC 58270016991Smickey int oldcpl = cpl; 58370016991Smickey #endif 584b9b95e0dSmickey 585b9b95e0dSmickey uvmexp.syscalls++; 586b9b95e0dSmickey 587b9b95e0dSmickey if (!USERMODE(frame->tf_iioq_head)) 588b9b95e0dSmickey panic("syscall"); 589b9b95e0dSmickey 590137d3021Smickey p->p_md.md_regs = frame; 591b9b95e0dSmickey nsys = p->p_emul->e_nsysent; 592b9b95e0dSmickey callp = p->p_emul->e_sysent; 593db97f33bSmickey 594b7d25a19Smickey argoff = 4; retq = 0; 595db97f33bSmickey switch (code = frame->tf_t1) { 596b9b95e0dSmickey case SYS_syscall: 597db97f33bSmickey code = frame->tf_arg0; 598db97f33bSmickey args[0] = frame->tf_arg1; 599db97f33bSmickey args[1] = frame->tf_arg2; 600db97f33bSmickey args[2] = frame->tf_arg3; 601db97f33bSmickey argoff = 3; 602b9b95e0dSmickey break; 603b9b95e0dSmickey case SYS___syscall: 604b9b95e0dSmickey if (callp != sysent) 605b9b95e0dSmickey break; 606db97f33bSmickey /* 607db97f33bSmickey * this works, because quads get magically swapped 6087503858eSjfb * due to the args being laid backwards on the stack 609db97f33bSmickey * and then copied in words 610db97f33bSmickey */ 611db97f33bSmickey code = frame->tf_arg0; 612db97f33bSmickey args[0] = frame->tf_arg2; 613db97f33bSmickey args[1] = frame->tf_arg3; 614db97f33bSmickey argoff = 2; 615b7d25a19Smickey retq = 1; 616db97f33bSmickey break; 617db97f33bSmickey default: 618db97f33bSmickey args[0] = frame->tf_arg0; 619db97f33bSmickey args[1] = frame->tf_arg1; 620db97f33bSmickey args[2] = frame->tf_arg2; 621db97f33bSmickey args[3] = frame->tf_arg3; 622db97f33bSmickey break; 623b9b95e0dSmickey } 624b9b95e0dSmickey 625b9b95e0dSmickey if (code < 0 || code >= nsys) 626b9b95e0dSmickey callp += p->p_emul->e_nosys; /* bad syscall # */ 627b9b95e0dSmickey else 628b9b95e0dSmickey callp += code; 629db97f33bSmickey 630db97f33bSmickey oerror = error = 0; 631db97f33bSmickey if ((argsize = callp->sy_argsize)) { 632db97f33bSmickey int i; 633db97f33bSmickey 634db97f33bSmickey for (i = 0, argsize -= argoff * 4; 635db97f33bSmickey argsize > 0; i++, argsize -= 4) { 636db97f33bSmickey error = copyin((void *)(frame->tf_sp + 637db97f33bSmickey HPPA_FRAME_ARG(i + 4)), args + i + argoff, 4); 638db97f33bSmickey 639db97f33bSmickey if (error) 640db97f33bSmickey break; 641db97f33bSmickey } 642db97f33bSmickey 643db97f33bSmickey /* 644db97f33bSmickey * coming from syscall() or __syscall we must be 645db97f33bSmickey * having one of those w/ a 64 bit arguments, 646db97f33bSmickey * which needs a word swap due to the order 647db97f33bSmickey * of the arguments on the stack. 648db97f33bSmickey * this assumes that none of 'em are called 649db97f33bSmickey * by their normal syscall number, maybe a regress 650b49f4f07Smiod * test should be used, to watch the behaviour. 651db97f33bSmickey */ 652db97f33bSmickey if (!error && argoff < 4) { 653db97f33bSmickey int t; 654db97f33bSmickey 655db97f33bSmickey i = 0; 656db97f33bSmickey switch (code) { 657b7d25a19Smickey case SYS_lseek: retq = 0; 658db97f33bSmickey case SYS_truncate: 659db97f33bSmickey case SYS_ftruncate: i = 2; break; 660db97f33bSmickey case SYS_preadv: 661db97f33bSmickey case SYS_pwritev: 662db97f33bSmickey case SYS_pread: 663db97f33bSmickey case SYS_pwrite: i = 4; break; 664db97f33bSmickey case SYS_mmap: i = 6; break; 665db97f33bSmickey } 666db97f33bSmickey 667db97f33bSmickey if (i) { 668db97f33bSmickey t = args[i]; 669db97f33bSmickey args[i] = args[i + 1]; 670db97f33bSmickey args[i + 1] = t; 671db97f33bSmickey } 672db97f33bSmickey } 673db97f33bSmickey } 674b9b95e0dSmickey 675b9b95e0dSmickey #ifdef SYSCALL_DEBUG 676b9b95e0dSmickey scdebug_call(p, code, args); 677b9b95e0dSmickey #endif 678b9b95e0dSmickey #ifdef KTRACE 679b9b95e0dSmickey if (KTRPOINT(p, KTR_SYSCALL)) 680d970adb6Smickey ktrsyscall(p, code, callp->sy_argsize, args); 681b9b95e0dSmickey #endif 682db97f33bSmickey if (error) 683db97f33bSmickey goto bad; 684b9b95e0dSmickey 685b9b95e0dSmickey rval[0] = 0; 686db97f33bSmickey rval[1] = frame->tf_ret1; 68796a1071fSmiod #if NSYSTRACE > 0 68896a1071fSmiod if (ISSET(p->p_flag, P_SYSTRACE)) 689db97f33bSmickey oerror = error = systrace_redirect(code, p, args, rval); 69096a1071fSmiod else 69196a1071fSmiod #endif 692db97f33bSmickey oerror = error = (*callp->sy_call)(p, args, rval); 6937882195eSmickey p = curproc; 6947882195eSmickey frame = p->p_md.md_regs; 69596a1071fSmiod switch (error) { 696b9b95e0dSmickey case 0: 697b9b95e0dSmickey frame->tf_ret0 = rval[0]; 698b7d25a19Smickey frame->tf_ret1 = rval[!retq]; 699137d3021Smickey frame->tf_t1 = 0; 700b9b95e0dSmickey break; 701b9b95e0dSmickey case ERESTART: 702c37e03c6Smickey frame->tf_iioq_head -= 12; 703c37e03c6Smickey frame->tf_iioq_tail -= 12; 704b9b95e0dSmickey case EJUSTRETURN: 705b9b95e0dSmickey break; 706b9b95e0dSmickey default: 707db97f33bSmickey bad: 708b9b95e0dSmickey if (p->p_emul->e_errno) 709b9b95e0dSmickey error = p->p_emul->e_errno[error]; 710137d3021Smickey frame->tf_t1 = error; 71147df6ae3Smickey frame->tf_ret0 = error; 71247df6ae3Smickey frame->tf_ret1 = 0; 713b9b95e0dSmickey break; 714b9b95e0dSmickey } 715b9b95e0dSmickey #ifdef SYSCALL_DEBUG 716db97f33bSmickey scdebug_ret(p, code, oerror, rval); 717b9b95e0dSmickey #endif 718532740e6Smickey userret(p, frame->tf_iioq_head, 0); 719b9b95e0dSmickey #ifdef KTRACE 720b9b95e0dSmickey if (KTRPOINT(p, KTR_SYSRET)) 721db97f33bSmickey ktrsysret(p, code, oerror, rval[0]); 722b9b95e0dSmickey #endif 72370016991Smickey #ifdef DIAGNOSTIC 72450552582Smickey if (cpl != oldcpl) { 72570016991Smickey printf("WARNING: SPL (0x%x) NOT LOWERED ON " 72670016991Smickey "syscall(0x%x, 0x%x, 0x%x, 0x%x...) EXIT, PID %d\n", 72770016991Smickey cpl, code, args[0], args[1], args[2], p->p_pid); 72850552582Smickey cpl = oldcpl; 72950552582Smickey } 73070016991Smickey #endif 73150552582Smickey splx(cpl); /* process softints */ 732b9b95e0dSmickey } 733