1*446209b7Smiod /* $OpenBSD: trap.c,v 1.62 2003/02/25 14:04:09 miod Exp $ */ 2556d2ba7Smickey 3556d2ba7Smickey /* 4906a25e0Smickey * Copyright (c) 1998-2003 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 * 3. All advertising materials mentioning features or use of this software 16556d2ba7Smickey * must display the following acknowledgement: 17556d2ba7Smickey * This product includes software developed by Michael Shalayeff. 18556d2ba7Smickey * 4. The name of the author may not be used to endorse or promote products 19556d2ba7Smickey * derived from this software without specific prior written permission. 20556d2ba7Smickey * 21556d2ba7Smickey * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22556d2ba7Smickey * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23556d2ba7Smickey * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24556d2ba7Smickey * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25556d2ba7Smickey * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26906a25e0Smickey * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF MIND, 27906a25e0Smickey * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28556d2ba7Smickey * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29556d2ba7Smickey * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30556d2ba7Smickey * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31556d2ba7Smickey */ 32556d2ba7Smickey 33ce94da48Smickey /* #define TRAPDEBUG */ 34556d2ba7Smickey 35556d2ba7Smickey #include <sys/param.h> 36556d2ba7Smickey #include <sys/systm.h> 37b9b95e0dSmickey #include <sys/syscall.h> 38b9b95e0dSmickey #include <sys/ktrace.h> 39d412f1c2Smickey #include <sys/proc.h> 406acb4cb0Sniklas #include <sys/signalvar.h> 41d412f1c2Smickey #include <sys/user.h> 42556d2ba7Smickey 43af7386c3Smickey #include <net/netisr.h> 44af7386c3Smickey 4596a1071fSmiod #include "systrace.h" 4696a1071fSmiod #include <dev/systrace.h> 4796a1071fSmiod 48b9b95e0dSmickey #include <uvm/uvm.h> 49556d2ba7Smickey 50556d2ba7Smickey #include <machine/autoconf.h> 51556d2ba7Smickey 523867ea13Smiod #include <machine/db_machdep.h> /* XXX always needed for inst_store() */ 53137d3021Smickey #ifdef DDB 549d159c9dSmickey #ifdef TRAPDEBUG 55137d3021Smickey #include <ddb/db_output.h> 56137d3021Smickey #endif 579d159c9dSmickey #endif 58556d2ba7Smickey 59556d2ba7Smickey const char *trap_type[] = { 60e494c7cfSmickey "invalid", 61e494c7cfSmickey "HPMC", 62556d2ba7Smickey "power failure", 63137d3021Smickey "recovery counter", 64556d2ba7Smickey "external interrupt", 65e494c7cfSmickey "LPMC", 66e494c7cfSmickey "ITLB miss fault", 67137d3021Smickey "instruction protection", 68137d3021Smickey "Illegal instruction", 69137d3021Smickey "break instruction", 70137d3021Smickey "privileged operation", 71137d3021Smickey "privileged register", 72137d3021Smickey "overflow", 73137d3021Smickey "conditional", 74137d3021Smickey "assist exception", 75e494c7cfSmickey "DTLB miss", 76137d3021Smickey "ITLB non-access miss", 77137d3021Smickey "DTLB non-access miss", 78137d3021Smickey "data protection/rights/alignment", 79137d3021Smickey "data break", 80e494c7cfSmickey "TLB dirty", 81137d3021Smickey "page reference", 82137d3021Smickey "assist emulation", 83e494c7cfSmickey "higher-priv transfer", 84e494c7cfSmickey "lower-priv transfer", 85137d3021Smickey "taken branch", 86137d3021Smickey "data access rights", 87e494c7cfSmickey "data protection", 88137d3021Smickey "unaligned data ref", 89556d2ba7Smickey }; 90556d2ba7Smickey int trap_types = sizeof(trap_type)/sizeof(trap_type[0]); 91556d2ba7Smickey 92bed2d21eSmickey int want_resched, astpending; 93556d2ba7Smickey 9470016991Smickey void 95d412f1c2Smickey userret(struct proc *p, register_t pc, u_quad_t oticks) 96d412f1c2Smickey { 97d412f1c2Smickey int sig; 98af7386c3Smickey 99d412f1c2Smickey /* take pending signals */ 100d412f1c2Smickey while ((sig = CURSIG(p)) != 0) 101d412f1c2Smickey postsig(sig); 102d412f1c2Smickey 103d412f1c2Smickey p->p_priority = p->p_usrpri; 10470016991Smickey if (astpending) { 10570016991Smickey astpending = 0; 10670016991Smickey if (p->p_flag & P_OWEUPC) { 10770016991Smickey p->p_flag &= ~P_OWEUPC; 10870016991Smickey ADDUPROF(p); 10970016991Smickey } 11070016991Smickey } 111d412f1c2Smickey if (want_resched) { 112d412f1c2Smickey /* 113c81336dcSart * We're being preempted. 114d412f1c2Smickey */ 115c81336dcSart preempt(NULL); 116d412f1c2Smickey while ((sig = CURSIG(p)) != 0) 117d412f1c2Smickey postsig(sig); 118d412f1c2Smickey } 119d412f1c2Smickey 120d412f1c2Smickey /* 121d412f1c2Smickey * If profiling, charge recent system time to the trapped pc. 122d412f1c2Smickey */ 123d412f1c2Smickey if (p->p_flag & P_PROFIL) { 124d412f1c2Smickey extern int psratio; 125d412f1c2Smickey 126d412f1c2Smickey addupc_task(p, pc, (int)(p->p_sticks - oticks) * psratio); 127d412f1c2Smickey } 128d412f1c2Smickey 129d412f1c2Smickey curpriority = p->p_priority; 130d412f1c2Smickey } 131d412f1c2Smickey 132556d2ba7Smickey void 133556d2ba7Smickey trap(type, frame) 134556d2ba7Smickey int type; 135556d2ba7Smickey struct trapframe *frame; 136556d2ba7Smickey { 137556d2ba7Smickey struct proc *p = curproc; 138ab8e80c5Sart vaddr_t va; 139ab8e80c5Sart struct vm_map *map; 140f17fa196Smickey struct vmspace *vm; 141af7386c3Smickey register vm_prot_t vftype; 142556d2ba7Smickey register pa_space_t space; 143af7386c3Smickey union sigval sv; 144c37e03c6Smickey u_int opcode; 14570016991Smickey int ret, trapnum; 146137d3021Smickey const char *tts; 1476198d067Smickey vm_fault_t fault = VM_FAULT_INVALID; 14870016991Smickey #ifdef DIAGNOSTIC 14970016991Smickey int oldcpl = cpl; 15070016991Smickey #endif 1510e979e06Smickey 152c37e03c6Smickey trapnum = type & ~T_USER; 153137d3021Smickey opcode = frame->tf_iir; 154969eb289Smickey if (trapnum == T_ITLBMISS || 155969eb289Smickey trapnum == T_EXCEPTION || trapnum == T_EMULATION) { 156a24c0b7aSmickey va = frame->tf_iioq_head; 157a24c0b7aSmickey space = frame->tf_iisq_head; 158e21aaa8cSmickey vftype = UVM_PROT_EXEC; 159a24c0b7aSmickey } else { 160b9b95e0dSmickey va = frame->tf_ior; 161a24c0b7aSmickey space = frame->tf_isr; 1626198d067Smickey /* what is the vftype for the T_ITLBMISSNA ??? XXX */ 163a4be06b3Smickey if (va == frame->tf_iioq_head) 164e21aaa8cSmickey vftype = UVM_PROT_EXEC; 165a4be06b3Smickey else if (inst_store(opcode)) 166e21aaa8cSmickey vftype = UVM_PROT_WRITE; 167a4be06b3Smickey else 168e21aaa8cSmickey vftype = UVM_PROT_READ; 169556d2ba7Smickey } 170137d3021Smickey 171137d3021Smickey if (frame->tf_flags & TFF_LAST) 172137d3021Smickey p->p_md.md_regs = frame; 173137d3021Smickey 174c37e03c6Smickey if (trapnum > trap_types) 175137d3021Smickey tts = "reserved"; 176137d3021Smickey else 177c37e03c6Smickey tts = trap_type[trapnum]; 178137d3021Smickey 179*446209b7Smiod #ifdef TRAPDEBUG 180c37e03c6Smickey if (trapnum != T_INTERRUPT && trapnum != T_IBREAK) 181969c5366Smickey db_printf("trap: %x, %s for %x:%x at %x:%x, fl=%x, fp=%p\n", 182137d3021Smickey type, tts, space, va, frame->tf_iisq_head, 183137d3021Smickey frame->tf_iioq_head, frame->tf_flags, frame); 184c37e03c6Smickey else if (trapnum == T_IBREAK) 185137d3021Smickey db_printf("trap: break instruction %x:%x at %x:%x, fp=%p\n", 186a24c0b7aSmickey break5(opcode), break13(opcode), 187137d3021Smickey frame->tf_iisq_head, frame->tf_iioq_head, frame); 188e494c7cfSmickey 189e494c7cfSmickey { 190e494c7cfSmickey extern int etext; 191532740e6Smickey if (frame < (struct trapframe *)&etext) { 192532740e6Smickey printf("trap: bogus frame ptr %p\n", frame); 193e494c7cfSmickey goto dead_end; 194e494c7cfSmickey } 195532740e6Smickey } 196d412f1c2Smickey #endif 19770016991Smickey if (trapnum != T_INTERRUPT) 19870016991Smickey mtctl(frame->tf_eiem, CR_EIEM); 19970016991Smickey 200556d2ba7Smickey switch (type) { 201556d2ba7Smickey case T_NONEXIST: 202556d2ba7Smickey case T_NONEXIST | T_USER: 203af7386c3Smickey /* we've got screwed up by the central scrutinizer */ 204b67578d8Smickey printf("trap: elvis has just left the building!\n"); 205532740e6Smickey goto dead_end; 206b67578d8Smickey 207556d2ba7Smickey case T_RECOVERY: 208556d2ba7Smickey case T_RECOVERY | T_USER: 209af7386c3Smickey /* XXX will implement later */ 210556d2ba7Smickey printf("trap: handicapped"); 211532740e6Smickey goto dead_end; 21266d1ab7aSmickey 21366d1ab7aSmickey #ifdef DIAGNOSTIC 21466d1ab7aSmickey case T_EXCEPTION: 21566d1ab7aSmickey panic("FPU/SFU emulation botch"); 21666d1ab7aSmickey 21766d1ab7aSmickey /* these just can't happen ever */ 21866d1ab7aSmickey case T_PRIV_OP: 21966d1ab7aSmickey case T_PRIV_REG: 22066d1ab7aSmickey /* these just can't make it to the trap() ever */ 221c6555f83Sderaadt case T_HPMC: 222c6555f83Sderaadt case T_HPMC | T_USER: 22366d1ab7aSmickey #endif 224f4daacd8Smickey case T_IBREAK: 225a24c0b7aSmickey case T_DATALIGN: 226a24c0b7aSmickey case T_DBREAK: 2278de28e3eSmickey dead_end: 228a24c0b7aSmickey #ifdef DDB 229532740e6Smickey if (kdb_trap (type, va, frame)) { 230a24c0b7aSmickey if (type == T_IBREAK) { 231f4daacd8Smickey /* skip break instruction */ 2328de28e3eSmickey frame->tf_iioq_head = frame->tf_iioq_tail; 233f4daacd8Smickey frame->tf_iioq_tail += 4; 234a24c0b7aSmickey } 235556d2ba7Smickey return; 236a24c0b7aSmickey } 237137d3021Smickey #else 238137d3021Smickey if (type == T_DATALIGN) 239137d3021Smickey panic ("trap: %s at 0x%x", tts, va); 240137d3021Smickey else 241137d3021Smickey panic ("trap: no debugger for \"%s\" (%d)", tts, type); 242a24c0b7aSmickey #endif 243556d2ba7Smickey break; 244556d2ba7Smickey 245af7386c3Smickey case T_IBREAK | T_USER: 246b67578d8Smickey /* XXX */ 247b67578d8Smickey frame->tf_iioq_head = frame->tf_iioq_tail; 248b67578d8Smickey frame->tf_iioq_tail += 4; 249af7386c3Smickey case T_DBREAK | T_USER: 250af7386c3Smickey /* pass to user debugger */ 251d412f1c2Smickey break; 252d412f1c2Smickey 25338575cbdSmickey case T_EXCEPTION | T_USER: { 254969eb289Smickey u_int64_t *fpp = (u_int64_t *)frame->tf_cr30; 255969eb289Smickey u_int32_t *pex; 25638575cbdSmickey int i, flt; 25738575cbdSmickey 258969eb289Smickey pex = (u_int32_t *)&fpp[0]; 25938575cbdSmickey for (i = 0, pex++; i < 7 && !*pex; i++, pex++); 260969eb289Smickey flt = 0; 261969eb289Smickey if (i < 7) { 262969eb289Smickey u_int32_t stat = HPPA_FPU_OP(*pex); 263969eb289Smickey if (stat == HPPA_FPU_UNMPL) 264969eb289Smickey flt = FPE_FLTINV; 265969eb289Smickey else if (stat & HPPA_FPU_V) 26638575cbdSmickey flt = FPE_FLTINV; 26738575cbdSmickey else if (stat & HPPA_FPU_Z) 26838575cbdSmickey flt = FPE_FLTDIV; 269969eb289Smickey else if (stat & HPPA_FPU_I) 270969eb289Smickey flt = FPE_FLTRES; 27138575cbdSmickey else if (stat & HPPA_FPU_O) 27238575cbdSmickey flt = FPE_FLTOVF; 27338575cbdSmickey else if (stat & HPPA_FPU_U) 27438575cbdSmickey flt = FPE_FLTUND; 275969eb289Smickey /* still left: under/over-flow w/ inexact */ 27638575cbdSmickey *pex = 0; 277969eb289Smickey } 278969eb289Smickey /* reset the trap flag, as if there was none */ 279969eb289Smickey fpp[0] &= ~(((u_int64_t)HPPA_FPU_T) << 32); 280969eb289Smickey /* flush out, since load is done from phys, only 4 regs */ 281969eb289Smickey fdcache(HPPA_SID_KERNEL, (vaddr_t)fpp, 8 * 4); 28238575cbdSmickey 28338575cbdSmickey sv.sival_int = va; 28438575cbdSmickey trapsignal(p, SIGFPE, type &~ T_USER, flt, sv); 28538575cbdSmickey } 28638575cbdSmickey break; 28738575cbdSmickey 288969eb289Smickey case T_EMULATION: 289969eb289Smickey panic("trap: emulation trap in the kernel"); 290969eb289Smickey break; 291969eb289Smickey 292969eb289Smickey case T_EMULATION | T_USER: 293137d3021Smickey sv.sival_int = va; 294969eb289Smickey trapsignal(p, SIGILL, type &~ T_USER, ILL_ILLOPC, sv); 295d412f1c2Smickey break; 296d412f1c2Smickey 297af7386c3Smickey case T_OVERFLOW | T_USER: 298137d3021Smickey sv.sival_int = va; 299af7386c3Smickey trapsignal(p, SIGFPE, type &~ T_USER, FPE_INTOVF, sv); 300d412f1c2Smickey break; 301d412f1c2Smickey 302af7386c3Smickey case T_CONDITION | T_USER: 303af7386c3Smickey break; 304af7386c3Smickey 305af7386c3Smickey case T_ILLEGAL | T_USER: 306137d3021Smickey sv.sival_int = va; 307af7386c3Smickey trapsignal(p, SIGILL, type &~ T_USER, ILL_ILLOPC, sv); 308af7386c3Smickey break; 309af7386c3Smickey 310af7386c3Smickey case T_PRIV_OP | T_USER: 311137d3021Smickey sv.sival_int = va; 312af7386c3Smickey trapsignal(p, SIGILL, type &~ T_USER, ILL_PRVOPC, sv); 313af7386c3Smickey break; 314af7386c3Smickey 315af7386c3Smickey case T_PRIV_REG | T_USER: 316137d3021Smickey sv.sival_int = va; 317af7386c3Smickey trapsignal(p, SIGILL, type &~ T_USER, ILL_PRVREG, sv); 318af7386c3Smickey break; 319af7386c3Smickey 320af7386c3Smickey /* these should never got here */ 321af7386c3Smickey case T_HIGHERPL | T_USER: 322af7386c3Smickey case T_LOWERPL | T_USER: 323137d3021Smickey sv.sival_int = va; 324a4be06b3Smickey trapsignal(p, SIGSEGV, vftype, SEGV_ACCERR, sv); 325af7386c3Smickey break; 326af7386c3Smickey 327af7386c3Smickey case T_IPROT | T_USER: 328af7386c3Smickey case T_DPROT | T_USER: 329af7386c3Smickey sv.sival_int = va; 330af7386c3Smickey trapsignal(p, SIGSEGV, vftype, SEGV_ACCERR, sv); 331af7386c3Smickey break; 332af7386c3Smickey 333c6555f83Sderaadt case T_DATACC: 334c6555f83Sderaadt case T_DATACC | T_USER: 3356198d067Smickey fault = VM_FAULT_PROTECT; 336c6555f83Sderaadt case T_ITLBMISS: 337c6555f83Sderaadt case T_ITLBMISS | T_USER: 338c6555f83Sderaadt case T_DTLBMISS: 339c6555f83Sderaadt case T_DTLBMISS | T_USER: 340c6555f83Sderaadt case T_ITLBMISSNA: 341c6555f83Sderaadt case T_ITLBMISSNA | T_USER: 342c6555f83Sderaadt case T_DTLBMISSNA: 343c6555f83Sderaadt case T_DTLBMISSNA | T_USER: 344c6555f83Sderaadt case T_TLB_DIRTY: 345c6555f83Sderaadt case T_TLB_DIRTY | T_USER: 346b67578d8Smickey /* 347b67578d8Smickey * user faults out of user addr space are always a fail, 348b67578d8Smickey * this happens on va >= VM_MAXUSER_ADDRESS, where 349b67578d8Smickey * space id will be zero and therefore cause 350b67578d8Smickey * a misbehave lower in the code. 351b67578d8Smickey */ 352b67578d8Smickey if (type & T_USER && va >= VM_MAXUSER_ADDRESS) { 353b67578d8Smickey sv.sival_int = va; 354906a25e0Smickey trapsignal(p, SIGSEGV, vftype, SEGV_ACCERR, sv); 355b67578d8Smickey break; 356b67578d8Smickey } 3578de28e3eSmickey 358b67578d8Smickey if (!(vm = p->p_vmspace)) { 359532740e6Smickey printf("trap: no vm, p=%p\n", p); 3608de28e3eSmickey goto dead_end; 361532740e6Smickey } 3628de28e3eSmickey 3638de28e3eSmickey /* 364e494c7cfSmickey * it could be a kernel map for exec_map faults 3658de28e3eSmickey */ 3668de28e3eSmickey if (!(type & T_USER) && space == HPPA_SID_KERNEL) 3678de28e3eSmickey map = kernel_map; 3688de28e3eSmickey else 369f17fa196Smickey map = &vm->vm_map; 370556d2ba7Smickey 371a228f8d2Smickey if (map->pmap->pm_space != space) { 372906a25e0Smickey if (map->pmap->pm_space != HPPA_SID_KERNEL) { 373906a25e0Smickey sv.sival_int = va; 374906a25e0Smickey trapsignal(p, SIGSEGV, vftype, SEGV_MAPERR, sv); 375906a25e0Smickey } else { 376532740e6Smickey printf("trap: space missmatch %d != %d\n", 377a228f8d2Smickey space, map->pmap->pm_space); 378532740e6Smickey goto dead_end; 379532740e6Smickey } 380906a25e0Smickey } 381532740e6Smickey 382ce94da48Smickey #ifdef TRAPDEBUG 383ce94da48Smickey if (space == -1) { 384ce94da48Smickey extern int pmapdebug; 385ce94da48Smickey pmapdebug = 0xffffff; 386ce94da48Smickey } 387ce94da48Smickey #endif 388a4be06b3Smickey ret = uvm_fault(map, hppa_trunc_page(va), fault, vftype); 389f17fa196Smickey 390532740e6Smickey #ifdef TRAPDEBUG 391ce94da48Smickey if (space == -1) { 392ce94da48Smickey extern int pmapdebug; 393ce94da48Smickey pmapdebug = 0; 394ce94da48Smickey } 395ce94da48Smickey 396532740e6Smickey printf("uvm_fault(%p, %x, %d, %d)=%d\n", 397532740e6Smickey map, va, 0, vftype, ret); 398532740e6Smickey #endif 399532740e6Smickey 400f17fa196Smickey /* 401f17fa196Smickey * If this was a stack access we keep track of the maximum 402f17fa196Smickey * accessed stack size. Also, if uvm_fault gets a protection 403f17fa196Smickey * failure it is due to accessing the stack region outside 404f17fa196Smickey * the current limit and we need to reflect that as an access 405f17fa196Smickey * error. 406f17fa196Smickey */ 407d74aa24bSmickey if (space != 0 && va < (vaddr_t)vm->vm_minsaddr && 408d74aa24bSmickey va >= (vaddr_t)vm->vm_maxsaddr + ctob(vm->vm_ssize)) { 409738a5b4dSart if (ret == 0) { 410a4be06b3Smickey vsize_t nss = btoc(va - USRSTACK + NBPG - 1); 411f17fa196Smickey if (nss > vm->vm_ssize) 412f17fa196Smickey vm->vm_ssize = nss; 413738a5b4dSart } else if (ret == EACCES) 414738a5b4dSart ret = EFAULT; 415f17fa196Smickey } 416f17fa196Smickey 417738a5b4dSart if (ret != 0) { 418af7386c3Smickey if (type & T_USER) { 419a4be06b3Smickey sv.sival_int = va; 420a4be06b3Smickey trapsignal(p, SIGSEGV, vftype, 421a4be06b3Smickey ret == EACCES? SEGV_ACCERR : SEGV_MAPERR, 422a4be06b3Smickey sv); 423137d3021Smickey } else { 4248de28e3eSmickey if (p && p->p_addr->u_pcb.pcb_onfault) { 4258de28e3eSmickey frame->tf_iioq_tail = 4 + 4268de28e3eSmickey (frame->tf_iioq_head = 42738575cbdSmickey p->p_addr->u_pcb.pcb_onfault); 428b04f760fSmickey #ifdef DDB 429b04f760fSmickey frame->tf_iir = 0; 430b04f760fSmickey #endif 431db97f33bSmickey } else { 432db97f33bSmickey panic("trap: " 433db97f33bSmickey "uvm_fault(%p, %x, %d, %d): %d", 4342191603aSmickey map, va, 0, vftype, ret); 435137d3021Smickey } 436137d3021Smickey } 437db97f33bSmickey } 438556d2ba7Smickey break; 439d412f1c2Smickey 440af7386c3Smickey case T_DATALIGN | T_USER: 441137d3021Smickey sv.sival_int = va; 442af7386c3Smickey trapsignal(p, SIGBUS, vftype, BUS_ADRALN, sv); 443af7386c3Smickey break; 444af7386c3Smickey 445a24c0b7aSmickey case T_INTERRUPT: 446a24c0b7aSmickey case T_INTERRUPT | T_USER: 447a24c0b7aSmickey cpu_intr(frame); 448af7386c3Smickey break; 449af7386c3Smickey 450b7d25a19Smickey case T_CONDITION: 451b7d25a19Smickey panic("trap: divide by zero in the kernel"); 452b7d25a19Smickey break; 453b7d25a19Smickey 45470016991Smickey case T_LOWERPL: 4552ef9a47eSmickey case T_DPROT: 4562ef9a47eSmickey case T_IPROT: 457af7386c3Smickey case T_OVERFLOW: 458af7386c3Smickey case T_ILLEGAL: 459af7386c3Smickey case T_HIGHERPL: 460af7386c3Smickey case T_TAKENBR: 461af7386c3Smickey case T_POWERFAIL: 462af7386c3Smickey case T_LPMC: 463af7386c3Smickey case T_PAGEREF: 464c6555f83Sderaadt case T_DATAPID: 465c6555f83Sderaadt case T_DATAPID | T_USER: 466d412f1c2Smickey if (0 /* T-chip */) { 467d412f1c2Smickey break; 468556d2ba7Smickey } 469d412f1c2Smickey /* FALLTHROUGH to unimplemented */ 470d412f1c2Smickey default: 471a228f8d2Smickey #if 0 472532740e6Smickey if (kdb_trap (type, va, frame)) 473137d3021Smickey return; 474137d3021Smickey #endif 47570016991Smickey panic("trap: unimplemented \'%s\' (%d)", tts, trapnum); 476d412f1c2Smickey } 477af7386c3Smickey 47870016991Smickey #ifdef DIAGNOSTIC 47970016991Smickey if (cpl != oldcpl) 48070016991Smickey printf("WARNING: SPL (%d) NOT LOWERED ON " 48170016991Smickey "TRAP (%d) EXIT\n", cpl, trapnum); 48270016991Smickey #endif 48370016991Smickey 48470016991Smickey if (trapnum != T_INTERRUPT) 48570016991Smickey splx(cpl); /* process softints */ 48670016991Smickey 487af7386c3Smickey if (type & T_USER) 48870016991Smickey userret(p, frame->tf_iioq_head, 0); 489d412f1c2Smickey } 490d412f1c2Smickey 491d412f1c2Smickey void 492db36253aSmickey child_return(arg) 493db36253aSmickey void *arg; 494d412f1c2Smickey { 495db36253aSmickey struct proc *p = (struct proc *)arg; 496d412f1c2Smickey userret(p, p->p_md.md_regs->tf_iioq_head, 0); 497d412f1c2Smickey #ifdef KTRACE 498d412f1c2Smickey if (KTRPOINT(p, KTR_SYSRET)) 499a27b30d8Sart ktrsysret(p, SYS_fork, 0, 0); 500d412f1c2Smickey #endif 501556d2ba7Smickey } 502556d2ba7Smickey 503db97f33bSmickey 504b9b95e0dSmickey /* 505b9b95e0dSmickey * call actual syscall routine 506b9b95e0dSmickey */ 507b9b95e0dSmickey void 50870016991Smickey syscall(struct trapframe *frame) 509b9b95e0dSmickey { 510db97f33bSmickey register struct proc *p = curproc; 511b9b95e0dSmickey register const struct sysent *callp; 512b7d25a19Smickey int retq, nsys, code, argsize, argoff, oerror, error; 513b7d25a19Smickey register_t args[8], rval[2]; 51470016991Smickey #ifdef DIAGNOSTIC 51570016991Smickey int oldcpl = cpl; 51670016991Smickey #endif 517b9b95e0dSmickey 518b9b95e0dSmickey uvmexp.syscalls++; 519b9b95e0dSmickey 520b9b95e0dSmickey if (!USERMODE(frame->tf_iioq_head)) 521b9b95e0dSmickey panic("syscall"); 522b9b95e0dSmickey 523137d3021Smickey p->p_md.md_regs = frame; 524b9b95e0dSmickey nsys = p->p_emul->e_nsysent; 525b9b95e0dSmickey callp = p->p_emul->e_sysent; 526db97f33bSmickey 527b7d25a19Smickey argoff = 4; retq = 0; 528db97f33bSmickey switch (code = frame->tf_t1) { 529b9b95e0dSmickey case SYS_syscall: 530db97f33bSmickey code = frame->tf_arg0; 531db97f33bSmickey args[0] = frame->tf_arg1; 532db97f33bSmickey args[1] = frame->tf_arg2; 533db97f33bSmickey args[2] = frame->tf_arg3; 534db97f33bSmickey argoff = 3; 535b9b95e0dSmickey break; 536b9b95e0dSmickey case SYS___syscall: 537b9b95e0dSmickey if (callp != sysent) 538b9b95e0dSmickey break; 539db97f33bSmickey /* 540db97f33bSmickey * this works, because quads get magically swapped 541db97f33bSmickey * due to the args being layed backwards on the stack 542db97f33bSmickey * and then copied in words 543db97f33bSmickey */ 544db97f33bSmickey code = frame->tf_arg0; 545db97f33bSmickey args[0] = frame->tf_arg2; 546db97f33bSmickey args[1] = frame->tf_arg3; 547db97f33bSmickey argoff = 2; 548b7d25a19Smickey retq = 1; 549db97f33bSmickey break; 550db97f33bSmickey default: 551db97f33bSmickey args[0] = frame->tf_arg0; 552db97f33bSmickey args[1] = frame->tf_arg1; 553db97f33bSmickey args[2] = frame->tf_arg2; 554db97f33bSmickey args[3] = frame->tf_arg3; 555db97f33bSmickey break; 556b9b95e0dSmickey } 557b9b95e0dSmickey 558b9b95e0dSmickey if (code < 0 || code >= nsys) 559b9b95e0dSmickey callp += p->p_emul->e_nosys; /* bad syscall # */ 560b9b95e0dSmickey else 561b9b95e0dSmickey callp += code; 562db97f33bSmickey 563db97f33bSmickey oerror = error = 0; 564db97f33bSmickey if ((argsize = callp->sy_argsize)) { 565db97f33bSmickey int i; 566db97f33bSmickey 567db97f33bSmickey for (i = 0, argsize -= argoff * 4; 568db97f33bSmickey argsize > 0; i++, argsize -= 4) { 569db97f33bSmickey error = copyin((void *)(frame->tf_sp + 570db97f33bSmickey HPPA_FRAME_ARG(i + 4)), args + i + argoff, 4); 571db97f33bSmickey 572db97f33bSmickey if (error) 573db97f33bSmickey break; 574db97f33bSmickey } 575db97f33bSmickey 576db97f33bSmickey /* 577db97f33bSmickey * coming from syscall() or __syscall we must be 578db97f33bSmickey * having one of those w/ a 64 bit arguments, 579db97f33bSmickey * which needs a word swap due to the order 580db97f33bSmickey * of the arguments on the stack. 581db97f33bSmickey * this assumes that none of 'em are called 582db97f33bSmickey * by their normal syscall number, maybe a regress 583db97f33bSmickey * test should be used, to whatch the behaviour. 584db97f33bSmickey */ 585db97f33bSmickey if (!error && argoff < 4) { 586db97f33bSmickey int t; 587db97f33bSmickey 588db97f33bSmickey i = 0; 589db97f33bSmickey switch (code) { 590b7d25a19Smickey case SYS_lseek: retq = 0; 591db97f33bSmickey case SYS_truncate: 592db97f33bSmickey case SYS_ftruncate: i = 2; break; 593db97f33bSmickey case SYS_preadv: 594db97f33bSmickey case SYS_pwritev: 595db97f33bSmickey case SYS_pread: 596db97f33bSmickey case SYS_pwrite: i = 4; break; 597db97f33bSmickey case SYS_mmap: i = 6; break; 598db97f33bSmickey } 599db97f33bSmickey 600db97f33bSmickey if (i) { 601db97f33bSmickey t = args[i]; 602db97f33bSmickey args[i] = args[i + 1]; 603db97f33bSmickey args[i + 1] = t; 604db97f33bSmickey } 605db97f33bSmickey } 606db97f33bSmickey } 607b9b95e0dSmickey 608b9b95e0dSmickey #ifdef SYSCALL_DEBUG 609b9b95e0dSmickey scdebug_call(p, code, args); 610b9b95e0dSmickey #endif 611b9b95e0dSmickey #ifdef KTRACE 612b9b95e0dSmickey if (KTRPOINT(p, KTR_SYSCALL)) 613d970adb6Smickey ktrsyscall(p, code, callp->sy_argsize, args); 614b9b95e0dSmickey #endif 615db97f33bSmickey if (error) 616db97f33bSmickey goto bad; 617b9b95e0dSmickey 618b9b95e0dSmickey rval[0] = 0; 619db97f33bSmickey rval[1] = frame->tf_ret1; 62096a1071fSmiod #if NSYSTRACE > 0 62196a1071fSmiod if (ISSET(p->p_flag, P_SYSTRACE)) 622db97f33bSmickey oerror = error = systrace_redirect(code, p, args, rval); 62396a1071fSmiod else 62496a1071fSmiod #endif 625db97f33bSmickey oerror = error = (*callp->sy_call)(p, args, rval); 62696a1071fSmiod switch (error) { 627b9b95e0dSmickey case 0: 628532740e6Smickey p = curproc; /* changes on exec() */ 629532740e6Smickey frame = p->p_md.md_regs; 630b9b95e0dSmickey frame->tf_ret0 = rval[0]; 631b7d25a19Smickey frame->tf_ret1 = rval[!retq]; 632137d3021Smickey frame->tf_t1 = 0; 633b9b95e0dSmickey break; 634b9b95e0dSmickey case ERESTART: 635c37e03c6Smickey frame->tf_iioq_head -= 12; 636c37e03c6Smickey frame->tf_iioq_tail -= 12; 637b9b95e0dSmickey break; 638b9b95e0dSmickey case EJUSTRETURN: 639532740e6Smickey p = curproc; 640b7d25a19Smickey frame = p->p_md.md_regs; 641b9b95e0dSmickey break; 642b9b95e0dSmickey default: 643db97f33bSmickey bad: 644b9b95e0dSmickey if (p->p_emul->e_errno) 645b9b95e0dSmickey error = p->p_emul->e_errno[error]; 646137d3021Smickey frame->tf_t1 = error; 647b9b95e0dSmickey break; 648b9b95e0dSmickey } 649b9b95e0dSmickey #ifdef SYSCALL_DEBUG 650db97f33bSmickey scdebug_ret(p, code, oerror, rval); 651b9b95e0dSmickey #endif 652532740e6Smickey userret(p, frame->tf_iioq_head, 0); 65370016991Smickey splx(cpl); /* process softints */ 654b9b95e0dSmickey #ifdef KTRACE 655b9b95e0dSmickey if (KTRPOINT(p, KTR_SYSRET)) 656db97f33bSmickey ktrsysret(p, code, oerror, rval[0]); 657b9b95e0dSmickey #endif 65870016991Smickey #ifdef DIAGNOSTIC 65970016991Smickey if (cpl != oldcpl) 66070016991Smickey printf("WARNING: SPL (0x%x) NOT LOWERED ON " 66170016991Smickey "syscall(0x%x, 0x%x, 0x%x, 0x%x...) EXIT, PID %d\n", 66270016991Smickey cpl, code, args[0], args[1], args[2], p->p_pid); 66370016991Smickey #endif 664b9b95e0dSmickey } 665