1*906a25e0Smickey /* $OpenBSD: trap.c,v 1.58 2003/01/09 20:48:56 mickey Exp $ */ 2556d2ba7Smickey 3556d2ba7Smickey /* 4*906a25e0Smickey * 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 26*906a25e0Smickey * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF MIND, 27*906a25e0Smickey * 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 52137d3021Smickey #ifdef DDB 53137d3021Smickey #include <machine/db_machdep.h> 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; 1584c15bc47Smickey vftype = VM_PROT_EXECUTE; 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) 164a4be06b3Smickey vftype = VM_PROT_EXECUTE; 165a4be06b3Smickey else if (inst_store(opcode)) 166a4be06b3Smickey vftype = VM_PROT_WRITE; 167a4be06b3Smickey else 168a4be06b3Smickey vftype = VM_PROT_READ; 169556d2ba7Smickey } 170137d3021Smickey 171137d3021Smickey if (frame->tf_flags & TFF_LAST) 172137d3021Smickey p->p_md.md_regs = frame; 173137d3021Smickey 174af7386c3Smickey #ifdef TRAPDEBUG 175c37e03c6Smickey if (trapnum > trap_types) 176137d3021Smickey tts = "reserved"; 177137d3021Smickey else 178c37e03c6Smickey tts = trap_type[trapnum]; 179137d3021Smickey 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 */ 22166d1ab7aSmickey case T_HPMC: case T_HPMC | T_USER: 22266d1ab7aSmickey #endif 223f4daacd8Smickey case T_IBREAK: 224a24c0b7aSmickey case T_DATALIGN: 225a24c0b7aSmickey case T_DBREAK: 2268de28e3eSmickey dead_end: 227a24c0b7aSmickey #ifdef DDB 228532740e6Smickey if (kdb_trap (type, va, frame)) { 229a24c0b7aSmickey if (type == T_IBREAK) { 230f4daacd8Smickey /* skip break instruction */ 2318de28e3eSmickey frame->tf_iioq_head = frame->tf_iioq_tail; 232f4daacd8Smickey frame->tf_iioq_tail += 4; 233a24c0b7aSmickey } 234556d2ba7Smickey return; 235a24c0b7aSmickey } 236137d3021Smickey #else 237137d3021Smickey if (type == T_DATALIGN) 238137d3021Smickey panic ("trap: %s at 0x%x", tts, va); 239137d3021Smickey else 240137d3021Smickey panic ("trap: no debugger for \"%s\" (%d)", tts, type); 241a24c0b7aSmickey #endif 242556d2ba7Smickey break; 243556d2ba7Smickey 244af7386c3Smickey case T_IBREAK | T_USER: 245b67578d8Smickey /* XXX */ 246b67578d8Smickey frame->tf_iioq_head = frame->tf_iioq_tail; 247b67578d8Smickey frame->tf_iioq_tail += 4; 248af7386c3Smickey case T_DBREAK | T_USER: 249af7386c3Smickey /* pass to user debugger */ 250d412f1c2Smickey break; 251d412f1c2Smickey 25238575cbdSmickey case T_EXCEPTION | T_USER: { 253969eb289Smickey u_int64_t *fpp = (u_int64_t *)frame->tf_cr30; 254969eb289Smickey u_int32_t *pex; 25538575cbdSmickey int i, flt; 25638575cbdSmickey 257969eb289Smickey pex = (u_int32_t *)&fpp[0]; 25838575cbdSmickey for (i = 0, pex++; i < 7 && !*pex; i++, pex++); 259969eb289Smickey flt = 0; 260969eb289Smickey if (i < 7) { 261969eb289Smickey u_int32_t stat = HPPA_FPU_OP(*pex); 262969eb289Smickey if (stat == HPPA_FPU_UNMPL) 263969eb289Smickey flt = FPE_FLTINV; 264969eb289Smickey else if (stat & HPPA_FPU_V) 26538575cbdSmickey flt = FPE_FLTINV; 26638575cbdSmickey else if (stat & HPPA_FPU_Z) 26738575cbdSmickey flt = FPE_FLTDIV; 268969eb289Smickey else if (stat & HPPA_FPU_I) 269969eb289Smickey flt = FPE_FLTRES; 27038575cbdSmickey else if (stat & HPPA_FPU_O) 27138575cbdSmickey flt = FPE_FLTOVF; 27238575cbdSmickey else if (stat & HPPA_FPU_U) 27338575cbdSmickey flt = FPE_FLTUND; 274969eb289Smickey /* still left: under/over-flow w/ inexact */ 27538575cbdSmickey *pex = 0; 276969eb289Smickey } 277969eb289Smickey /* reset the trap flag, as if there was none */ 278969eb289Smickey fpp[0] &= ~(((u_int64_t)HPPA_FPU_T) << 32); 279969eb289Smickey /* flush out, since load is done from phys, only 4 regs */ 280969eb289Smickey fdcache(HPPA_SID_KERNEL, (vaddr_t)fpp, 8 * 4); 28138575cbdSmickey 28238575cbdSmickey sv.sival_int = va; 28338575cbdSmickey trapsignal(p, SIGFPE, type &~ T_USER, flt, sv); 28438575cbdSmickey } 28538575cbdSmickey break; 28638575cbdSmickey 287969eb289Smickey case T_EMULATION: 288969eb289Smickey panic("trap: emulation trap in the kernel"); 289969eb289Smickey break; 290969eb289Smickey 291969eb289Smickey case T_EMULATION | T_USER: 292137d3021Smickey sv.sival_int = va; 293969eb289Smickey trapsignal(p, SIGILL, type &~ T_USER, ILL_ILLOPC, sv); 294d412f1c2Smickey break; 295d412f1c2Smickey 296af7386c3Smickey case T_OVERFLOW | T_USER: 297137d3021Smickey sv.sival_int = va; 298af7386c3Smickey trapsignal(p, SIGFPE, type &~ T_USER, FPE_INTOVF, sv); 299d412f1c2Smickey break; 300d412f1c2Smickey 301af7386c3Smickey case T_CONDITION | T_USER: 302af7386c3Smickey break; 303af7386c3Smickey 304af7386c3Smickey case T_ILLEGAL | T_USER: 305137d3021Smickey sv.sival_int = va; 306af7386c3Smickey trapsignal(p, SIGILL, type &~ T_USER, ILL_ILLOPC, sv); 307af7386c3Smickey break; 308af7386c3Smickey 309af7386c3Smickey case T_PRIV_OP | T_USER: 310137d3021Smickey sv.sival_int = va; 311af7386c3Smickey trapsignal(p, SIGILL, type &~ T_USER, ILL_PRVOPC, sv); 312af7386c3Smickey break; 313af7386c3Smickey 314af7386c3Smickey case T_PRIV_REG | T_USER: 315137d3021Smickey sv.sival_int = va; 316af7386c3Smickey trapsignal(p, SIGILL, type &~ T_USER, ILL_PRVREG, sv); 317af7386c3Smickey break; 318af7386c3Smickey 319af7386c3Smickey /* these should never got here */ 320af7386c3Smickey case T_HIGHERPL | T_USER: 321af7386c3Smickey case T_LOWERPL | T_USER: 322137d3021Smickey sv.sival_int = va; 323a4be06b3Smickey trapsignal(p, SIGSEGV, vftype, SEGV_ACCERR, sv); 324af7386c3Smickey break; 325af7386c3Smickey 326af7386c3Smickey case T_IPROT | T_USER: 327af7386c3Smickey case T_DPROT | T_USER: 328af7386c3Smickey sv.sival_int = va; 329af7386c3Smickey trapsignal(p, SIGSEGV, vftype, SEGV_ACCERR, sv); 330af7386c3Smickey break; 331af7386c3Smickey 332ec21eae5Smickey case T_DATACC: case T_USER | T_DATACC: 3336198d067Smickey fault = VM_FAULT_PROTECT; 334ec21eae5Smickey case T_ITLBMISS: case T_USER | T_ITLBMISS: 335ec21eae5Smickey case T_DTLBMISS: case T_USER | T_DTLBMISS: 336ec21eae5Smickey case T_ITLBMISSNA: case T_USER | T_ITLBMISSNA: 337ec21eae5Smickey case T_DTLBMISSNA: case T_USER | T_DTLBMISSNA: 338ec21eae5Smickey case T_TLB_DIRTY: case T_USER | T_TLB_DIRTY: 339b67578d8Smickey /* 340b67578d8Smickey * user faults out of user addr space are always a fail, 341b67578d8Smickey * this happens on va >= VM_MAXUSER_ADDRESS, where 342b67578d8Smickey * space id will be zero and therefore cause 343b67578d8Smickey * a misbehave lower in the code. 344b67578d8Smickey */ 345b67578d8Smickey if (type & T_USER && va >= VM_MAXUSER_ADDRESS) { 346b67578d8Smickey sv.sival_int = va; 347*906a25e0Smickey trapsignal(p, SIGSEGV, vftype, SEGV_ACCERR, sv); 348b67578d8Smickey break; 349b67578d8Smickey } 3508de28e3eSmickey 351b67578d8Smickey if (!(vm = p->p_vmspace)) { 352532740e6Smickey printf("trap: no vm, p=%p\n", p); 3538de28e3eSmickey goto dead_end; 354532740e6Smickey } 3558de28e3eSmickey 3568de28e3eSmickey /* 357e494c7cfSmickey * it could be a kernel map for exec_map faults 3588de28e3eSmickey */ 3598de28e3eSmickey if (!(type & T_USER) && space == HPPA_SID_KERNEL) 3608de28e3eSmickey map = kernel_map; 3618de28e3eSmickey else 362f17fa196Smickey map = &vm->vm_map; 363556d2ba7Smickey 364a228f8d2Smickey if (map->pmap->pm_space != space) { 365*906a25e0Smickey if (map->pmap->pm_space != HPPA_SID_KERNEL) { 366*906a25e0Smickey sv.sival_int = va; 367*906a25e0Smickey trapsignal(p, SIGSEGV, vftype, SEGV_MAPERR, sv); 368*906a25e0Smickey } else { 369532740e6Smickey printf("trap: space missmatch %d != %d\n", 370a228f8d2Smickey space, map->pmap->pm_space); 371532740e6Smickey goto dead_end; 372532740e6Smickey } 373*906a25e0Smickey } 374532740e6Smickey 375ce94da48Smickey #ifdef TRAPDEBUG 376ce94da48Smickey if (space == -1) { 377ce94da48Smickey extern int pmapdebug; 378ce94da48Smickey pmapdebug = 0xffffff; 379ce94da48Smickey } 380ce94da48Smickey #endif 381a4be06b3Smickey ret = uvm_fault(map, hppa_trunc_page(va), fault, vftype); 382f17fa196Smickey 383532740e6Smickey #ifdef TRAPDEBUG 384ce94da48Smickey if (space == -1) { 385ce94da48Smickey extern int pmapdebug; 386ce94da48Smickey pmapdebug = 0; 387ce94da48Smickey } 388ce94da48Smickey 389532740e6Smickey printf("uvm_fault(%p, %x, %d, %d)=%d\n", 390532740e6Smickey map, va, 0, vftype, ret); 391532740e6Smickey #endif 392532740e6Smickey 393f17fa196Smickey /* 394f17fa196Smickey * If this was a stack access we keep track of the maximum 395f17fa196Smickey * accessed stack size. Also, if uvm_fault gets a protection 396f17fa196Smickey * failure it is due to accessing the stack region outside 397f17fa196Smickey * the current limit and we need to reflect that as an access 398f17fa196Smickey * error. 399f17fa196Smickey */ 400d74aa24bSmickey if (space != 0 && va < (vaddr_t)vm->vm_minsaddr && 401d74aa24bSmickey va >= (vaddr_t)vm->vm_maxsaddr + ctob(vm->vm_ssize)) { 402738a5b4dSart if (ret == 0) { 403a4be06b3Smickey vsize_t nss = btoc(va - USRSTACK + NBPG - 1); 404f17fa196Smickey if (nss > vm->vm_ssize) 405f17fa196Smickey vm->vm_ssize = nss; 406738a5b4dSart } else if (ret == EACCES) 407738a5b4dSart ret = EFAULT; 408f17fa196Smickey } 409f17fa196Smickey 410738a5b4dSart if (ret != 0) { 411af7386c3Smickey if (type & T_USER) { 412a4be06b3Smickey sv.sival_int = va; 413a4be06b3Smickey trapsignal(p, SIGSEGV, vftype, 414a4be06b3Smickey ret == EACCES? SEGV_ACCERR : SEGV_MAPERR, 415a4be06b3Smickey sv); 416137d3021Smickey } else { 4178de28e3eSmickey if (p && p->p_addr->u_pcb.pcb_onfault) { 4188de28e3eSmickey frame->tf_iioq_tail = 4 + 4198de28e3eSmickey (frame->tf_iioq_head = 42038575cbdSmickey p->p_addr->u_pcb.pcb_onfault); 421b04f760fSmickey #ifdef DDB 422b04f760fSmickey frame->tf_iir = 0; 423b04f760fSmickey #endif 424db97f33bSmickey } else { 425db97f33bSmickey panic("trap: " 426db97f33bSmickey "uvm_fault(%p, %x, %d, %d): %d", 4272191603aSmickey map, va, 0, vftype, ret); 428137d3021Smickey } 429137d3021Smickey } 430db97f33bSmickey } 431556d2ba7Smickey break; 432d412f1c2Smickey 433af7386c3Smickey case T_DATALIGN | T_USER: 434137d3021Smickey sv.sival_int = va; 435af7386c3Smickey trapsignal(p, SIGBUS, vftype, BUS_ADRALN, sv); 436af7386c3Smickey break; 437af7386c3Smickey 438a24c0b7aSmickey case T_INTERRUPT: 439a24c0b7aSmickey case T_INTERRUPT|T_USER: 440a24c0b7aSmickey cpu_intr(frame); 441af7386c3Smickey break; 442af7386c3Smickey 443b7d25a19Smickey case T_CONDITION: 444b7d25a19Smickey panic("trap: divide by zero in the kernel"); 445b7d25a19Smickey break; 446b7d25a19Smickey 44770016991Smickey case T_LOWERPL: 4482ef9a47eSmickey case T_DPROT: 4492ef9a47eSmickey case T_IPROT: 450af7386c3Smickey case T_OVERFLOW: 451af7386c3Smickey case T_ILLEGAL: 452af7386c3Smickey case T_HIGHERPL: 453af7386c3Smickey case T_TAKENBR: 454af7386c3Smickey case T_POWERFAIL: 455af7386c3Smickey case T_LPMC: 456af7386c3Smickey case T_PAGEREF: 457d412f1c2Smickey case T_DATAPID: case T_DATAPID | T_USER: 458d412f1c2Smickey if (0 /* T-chip */) { 459d412f1c2Smickey break; 460556d2ba7Smickey } 461d412f1c2Smickey /* FALLTHROUGH to unimplemented */ 462d412f1c2Smickey default: 463a228f8d2Smickey #if 0 464532740e6Smickey if (kdb_trap (type, va, frame)) 465137d3021Smickey return; 466137d3021Smickey #endif 46770016991Smickey panic("trap: unimplemented \'%s\' (%d)", tts, trapnum); 468d412f1c2Smickey } 469af7386c3Smickey 47070016991Smickey #ifdef DIAGNOSTIC 47170016991Smickey if (cpl != oldcpl) 47270016991Smickey printf("WARNING: SPL (%d) NOT LOWERED ON " 47370016991Smickey "TRAP (%d) EXIT\n", cpl, trapnum); 47470016991Smickey #endif 47570016991Smickey 47670016991Smickey if (trapnum != T_INTERRUPT) 47770016991Smickey splx(cpl); /* process softints */ 47870016991Smickey 479af7386c3Smickey if (type & T_USER) 48070016991Smickey userret(p, frame->tf_iioq_head, 0); 481d412f1c2Smickey } 482d412f1c2Smickey 483d412f1c2Smickey void 484db36253aSmickey child_return(arg) 485db36253aSmickey void *arg; 486d412f1c2Smickey { 487db36253aSmickey struct proc *p = (struct proc *)arg; 488d412f1c2Smickey userret(p, p->p_md.md_regs->tf_iioq_head, 0); 489d412f1c2Smickey #ifdef KTRACE 490d412f1c2Smickey if (KTRPOINT(p, KTR_SYSRET)) 491a27b30d8Sart ktrsysret(p, SYS_fork, 0, 0); 492d412f1c2Smickey #endif 493556d2ba7Smickey } 494556d2ba7Smickey 495db97f33bSmickey 496b9b95e0dSmickey /* 497b9b95e0dSmickey * call actual syscall routine 498b9b95e0dSmickey */ 499b9b95e0dSmickey void 50070016991Smickey syscall(struct trapframe *frame) 501b9b95e0dSmickey { 502db97f33bSmickey register struct proc *p = curproc; 503b9b95e0dSmickey register const struct sysent *callp; 504b7d25a19Smickey int retq, nsys, code, argsize, argoff, oerror, error; 505b7d25a19Smickey register_t args[8], rval[2]; 50670016991Smickey #ifdef DIAGNOSTIC 50770016991Smickey int oldcpl = cpl; 50870016991Smickey #endif 509b9b95e0dSmickey 510b9b95e0dSmickey uvmexp.syscalls++; 511b9b95e0dSmickey 512b9b95e0dSmickey if (!USERMODE(frame->tf_iioq_head)) 513b9b95e0dSmickey panic("syscall"); 514b9b95e0dSmickey 515137d3021Smickey p->p_md.md_regs = frame; 516b9b95e0dSmickey nsys = p->p_emul->e_nsysent; 517b9b95e0dSmickey callp = p->p_emul->e_sysent; 518db97f33bSmickey 519b7d25a19Smickey argoff = 4; retq = 0; 520db97f33bSmickey switch (code = frame->tf_t1) { 521b9b95e0dSmickey case SYS_syscall: 522db97f33bSmickey code = frame->tf_arg0; 523db97f33bSmickey args[0] = frame->tf_arg1; 524db97f33bSmickey args[1] = frame->tf_arg2; 525db97f33bSmickey args[2] = frame->tf_arg3; 526db97f33bSmickey argoff = 3; 527b9b95e0dSmickey break; 528b9b95e0dSmickey case SYS___syscall: 529b9b95e0dSmickey if (callp != sysent) 530b9b95e0dSmickey break; 531db97f33bSmickey /* 532db97f33bSmickey * this works, because quads get magically swapped 533db97f33bSmickey * due to the args being layed backwards on the stack 534db97f33bSmickey * and then copied in words 535db97f33bSmickey */ 536db97f33bSmickey code = frame->tf_arg0; 537db97f33bSmickey args[0] = frame->tf_arg2; 538db97f33bSmickey args[1] = frame->tf_arg3; 539db97f33bSmickey argoff = 2; 540b7d25a19Smickey retq = 1; 541db97f33bSmickey break; 542db97f33bSmickey default: 543db97f33bSmickey args[0] = frame->tf_arg0; 544db97f33bSmickey args[1] = frame->tf_arg1; 545db97f33bSmickey args[2] = frame->tf_arg2; 546db97f33bSmickey args[3] = frame->tf_arg3; 547db97f33bSmickey break; 548b9b95e0dSmickey } 549b9b95e0dSmickey 550b9b95e0dSmickey if (code < 0 || code >= nsys) 551b9b95e0dSmickey callp += p->p_emul->e_nosys; /* bad syscall # */ 552b9b95e0dSmickey else 553b9b95e0dSmickey callp += code; 554db97f33bSmickey 555db97f33bSmickey oerror = error = 0; 556db97f33bSmickey if ((argsize = callp->sy_argsize)) { 557db97f33bSmickey int i; 558db97f33bSmickey 559db97f33bSmickey for (i = 0, argsize -= argoff * 4; 560db97f33bSmickey argsize > 0; i++, argsize -= 4) { 561db97f33bSmickey error = copyin((void *)(frame->tf_sp + 562db97f33bSmickey HPPA_FRAME_ARG(i + 4)), args + i + argoff, 4); 563db97f33bSmickey 564db97f33bSmickey if (error) 565db97f33bSmickey break; 566db97f33bSmickey } 567db97f33bSmickey 568db97f33bSmickey /* 569db97f33bSmickey * coming from syscall() or __syscall we must be 570db97f33bSmickey * having one of those w/ a 64 bit arguments, 571db97f33bSmickey * which needs a word swap due to the order 572db97f33bSmickey * of the arguments on the stack. 573db97f33bSmickey * this assumes that none of 'em are called 574db97f33bSmickey * by their normal syscall number, maybe a regress 575db97f33bSmickey * test should be used, to whatch the behaviour. 576db97f33bSmickey */ 577db97f33bSmickey if (!error && argoff < 4) { 578db97f33bSmickey int t; 579db97f33bSmickey 580db97f33bSmickey i = 0; 581db97f33bSmickey switch (code) { 582b7d25a19Smickey case SYS_lseek: retq = 0; 583db97f33bSmickey case SYS_truncate: 584db97f33bSmickey case SYS_ftruncate: i = 2; break; 585db97f33bSmickey case SYS_preadv: 586db97f33bSmickey case SYS_pwritev: 587db97f33bSmickey case SYS_pread: 588db97f33bSmickey case SYS_pwrite: i = 4; break; 589db97f33bSmickey case SYS_mmap: i = 6; break; 590db97f33bSmickey } 591db97f33bSmickey 592db97f33bSmickey if (i) { 593db97f33bSmickey t = args[i]; 594db97f33bSmickey args[i] = args[i + 1]; 595db97f33bSmickey args[i + 1] = t; 596db97f33bSmickey } 597db97f33bSmickey } 598db97f33bSmickey } 599b9b95e0dSmickey 600b9b95e0dSmickey #ifdef SYSCALL_DEBUG 601b9b95e0dSmickey scdebug_call(p, code, args); 602b9b95e0dSmickey #endif 603b9b95e0dSmickey #ifdef KTRACE 604b9b95e0dSmickey if (KTRPOINT(p, KTR_SYSCALL)) 605d970adb6Smickey ktrsyscall(p, code, callp->sy_argsize, args); 606b9b95e0dSmickey #endif 607db97f33bSmickey if (error) 608db97f33bSmickey goto bad; 609b9b95e0dSmickey 610b9b95e0dSmickey rval[0] = 0; 611db97f33bSmickey rval[1] = frame->tf_ret1; 61296a1071fSmiod #if NSYSTRACE > 0 61396a1071fSmiod if (ISSET(p->p_flag, P_SYSTRACE)) 614db97f33bSmickey oerror = error = systrace_redirect(code, p, args, rval); 61596a1071fSmiod else 61696a1071fSmiod #endif 617db97f33bSmickey oerror = error = (*callp->sy_call)(p, args, rval); 61896a1071fSmiod switch (error) { 619b9b95e0dSmickey case 0: 620532740e6Smickey p = curproc; /* changes on exec() */ 621532740e6Smickey frame = p->p_md.md_regs; 622b9b95e0dSmickey frame->tf_ret0 = rval[0]; 623b7d25a19Smickey frame->tf_ret1 = rval[!retq]; 624137d3021Smickey frame->tf_t1 = 0; 625b9b95e0dSmickey break; 626b9b95e0dSmickey case ERESTART: 627c37e03c6Smickey frame->tf_iioq_head -= 12; 628c37e03c6Smickey frame->tf_iioq_tail -= 12; 629b9b95e0dSmickey break; 630b9b95e0dSmickey case EJUSTRETURN: 631532740e6Smickey p = curproc; 632b7d25a19Smickey frame = p->p_md.md_regs; 633b9b95e0dSmickey break; 634b9b95e0dSmickey default: 635db97f33bSmickey bad: 636b9b95e0dSmickey if (p->p_emul->e_errno) 637b9b95e0dSmickey error = p->p_emul->e_errno[error]; 638137d3021Smickey frame->tf_t1 = error; 639b9b95e0dSmickey break; 640b9b95e0dSmickey } 641b9b95e0dSmickey #ifdef SYSCALL_DEBUG 642db97f33bSmickey scdebug_ret(p, code, oerror, rval); 643b9b95e0dSmickey #endif 644532740e6Smickey userret(p, frame->tf_iioq_head, 0); 64570016991Smickey splx(cpl); /* process softints */ 646b9b95e0dSmickey #ifdef KTRACE 647b9b95e0dSmickey if (KTRPOINT(p, KTR_SYSRET)) 648db97f33bSmickey ktrsysret(p, code, oerror, rval[0]); 649b9b95e0dSmickey #endif 65070016991Smickey #ifdef DIAGNOSTIC 65170016991Smickey if (cpl != oldcpl) 65270016991Smickey printf("WARNING: SPL (0x%x) NOT LOWERED ON " 65370016991Smickey "syscall(0x%x, 0x%x, 0x%x, 0x%x...) EXIT, PID %d\n", 65470016991Smickey cpl, code, args[0], args[1], args[2], p->p_pid); 65570016991Smickey #endif 656b9b95e0dSmickey } 657