1*c81336dcSart /* $OpenBSD: trap.c,v 1.29 2001/09/14 14:58:44 art Exp $ */ 2556d2ba7Smickey 3556d2ba7Smickey /* 48de28e3eSmickey * Copyright (c) 1998-2000 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 26556d2ba7Smickey * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27556d2ba7Smickey * 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 332ef9a47eSmickey /* #define INTRDEBUG */ 342ef9a47eSmickey /* #define TRAPDEBUG */ 35556d2ba7Smickey 36556d2ba7Smickey #include <sys/param.h> 37556d2ba7Smickey #include <sys/systm.h> 38d412f1c2Smickey #include <sys/kernel.h> 39b9b95e0dSmickey #include <sys/syscall.h> 40b9b95e0dSmickey #include <sys/ktrace.h> 41d412f1c2Smickey #include <sys/proc.h> 426acb4cb0Sniklas #include <sys/signalvar.h> 43d412f1c2Smickey #include <sys/user.h> 44d412f1c2Smickey #include <sys/acct.h> 45d412f1c2Smickey #include <sys/signal.h> 46688a8060Smickey #include <sys/device.h> 47556d2ba7Smickey 48af7386c3Smickey #include <net/netisr.h> 49af7386c3Smickey 50556d2ba7Smickey #include <vm/vm.h> 518de28e3eSmickey #include <vm/vm_kern.h> 52b9b95e0dSmickey #include <uvm/uvm.h> 53556d2ba7Smickey 54556d2ba7Smickey #include <machine/iomod.h> 55556d2ba7Smickey #include <machine/cpufunc.h> 56556d2ba7Smickey #include <machine/reg.h> 57556d2ba7Smickey #include <machine/autoconf.h> 58556d2ba7Smickey 59137d3021Smickey #ifdef DDB 60137d3021Smickey #include <machine/db_machdep.h> 61137d3021Smickey #endif 62137d3021Smickey 63137d3021Smickey #if defined(INTRDEBUG) || defined(TRAPDEBUG) 64137d3021Smickey #include <ddb/db_output.h> 65137d3021Smickey #endif 66137d3021Smickey 67556d2ba7Smickey 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 101556d2ba7Smickey u_int32_t sir; 102bed2d21eSmickey int want_resched, astpending; 103556d2ba7Smickey 104556d2ba7Smickey void pmap_hptdump __P((void)); 105a24c0b7aSmickey void cpu_intr __P((struct trapframe *frame)); 106b9b95e0dSmickey void syscall __P((struct trapframe *frame, int *args)); 107556d2ba7Smickey 108d412f1c2Smickey static __inline void 109d412f1c2Smickey userret (struct proc *p, register_t pc, u_quad_t oticks) 110d412f1c2Smickey { 111d412f1c2Smickey int sig; 112af7386c3Smickey 113d412f1c2Smickey /* take pending signals */ 114d412f1c2Smickey while ((sig = CURSIG(p)) != 0) 115d412f1c2Smickey postsig(sig); 116d412f1c2Smickey 117d412f1c2Smickey p->p_priority = p->p_usrpri; 118d412f1c2Smickey if (want_resched) { 119d412f1c2Smickey /* 120*c81336dcSart * We're being preempted. 121d412f1c2Smickey */ 122*c81336dcSart preempt(NULL); 123d412f1c2Smickey while ((sig = CURSIG(p)) != 0) 124d412f1c2Smickey postsig(sig); 125d412f1c2Smickey } 126d412f1c2Smickey 127d412f1c2Smickey /* 128d412f1c2Smickey * If profiling, charge recent system time to the trapped pc. 129d412f1c2Smickey */ 130d412f1c2Smickey if (p->p_flag & P_PROFIL) { 131d412f1c2Smickey extern int psratio; 132d412f1c2Smickey 133d412f1c2Smickey addupc_task(p, pc, (int)(p->p_sticks - oticks) * psratio); 134d412f1c2Smickey } 135d412f1c2Smickey 136d412f1c2Smickey curpriority = p->p_priority; 137d412f1c2Smickey } 138d412f1c2Smickey 139556d2ba7Smickey void 140556d2ba7Smickey trap(type, frame) 141556d2ba7Smickey int type; 142556d2ba7Smickey struct trapframe *frame; 143556d2ba7Smickey { 144556d2ba7Smickey struct proc *p = curproc; 145137d3021Smickey struct pcb *pcbp; 146137d3021Smickey register vaddr_t va; 147556d2ba7Smickey register vm_map_t map; 148f17fa196Smickey struct vmspace *vm; 149af7386c3Smickey register vm_prot_t vftype; 150556d2ba7Smickey register pa_space_t space; 151a24c0b7aSmickey u_int opcode; 152556d2ba7Smickey int ret; 153af7386c3Smickey union sigval sv; 154a24c0b7aSmickey int s, si; 155137d3021Smickey const char *tts; 1560e979e06Smickey 157137d3021Smickey opcode = frame->tf_iir; 158a24c0b7aSmickey if (type == T_ITLBMISS || type == T_ITLBMISSNA) { 159a24c0b7aSmickey va = frame->tf_iioq_head; 160a24c0b7aSmickey space = frame->tf_iisq_head; 161532740e6Smickey vftype = VM_PROT_READ; /* XXX VM_PROT_EXECUTE ??? */ 162a24c0b7aSmickey } else { 163b9b95e0dSmickey va = frame->tf_ior; 164a24c0b7aSmickey space = frame->tf_isr; 165532740e6Smickey vftype = inst_store(opcode) ? VM_PROT_WRITE : VM_PROT_READ; 166556d2ba7Smickey } 167137d3021Smickey 168137d3021Smickey if (frame->tf_flags & TFF_LAST) 169137d3021Smickey p->p_md.md_regs = frame; 170137d3021Smickey 171af7386c3Smickey #ifdef TRAPDEBUG 172137d3021Smickey if ((type & ~T_USER) > trap_types) 173137d3021Smickey tts = "reserved"; 174137d3021Smickey else 175137d3021Smickey tts = trap_type[type & ~T_USER]; 176137d3021Smickey 177e494c7cfSmickey if (type != T_INTERRUPT && (type & ~T_USER) != T_IBREAK) 178137d3021Smickey db_printf("trap: %d, %s for %x:%x at %x:%x, fl=%x, fp=%p\n", 179137d3021Smickey type, tts, space, va, frame->tf_iisq_head, 180137d3021Smickey frame->tf_iioq_head, frame->tf_flags, frame); 181a24c0b7aSmickey else if ((type & ~T_USER) == T_IBREAK) 182137d3021Smickey db_printf("trap: break instruction %x:%x at %x:%x, fp=%p\n", 183a24c0b7aSmickey break5(opcode), break13(opcode), 184137d3021Smickey frame->tf_iisq_head, frame->tf_iioq_head, frame); 185e494c7cfSmickey 186e494c7cfSmickey { 187e494c7cfSmickey extern int etext; 188532740e6Smickey if (frame < (struct trapframe *)&etext) { 189532740e6Smickey printf("trap: bogus frame ptr %p\n", frame); 190e494c7cfSmickey goto dead_end; 191e494c7cfSmickey } 192532740e6Smickey } 193d412f1c2Smickey #endif 194556d2ba7Smickey switch (type) { 195556d2ba7Smickey case T_NONEXIST: 196556d2ba7Smickey case T_NONEXIST|T_USER: 197137d3021Smickey #ifndef DDB 198af7386c3Smickey /* we've got screwed up by the central scrutinizer */ 199137d3021Smickey panic ("trap: elvis has just left the building!"); 200556d2ba7Smickey break; 201532740e6Smickey #else 202532740e6Smickey goto dead_end; 203137d3021Smickey #endif 204556d2ba7Smickey case T_RECOVERY: 205556d2ba7Smickey case T_RECOVERY|T_USER: 206137d3021Smickey #ifndef DDB 207af7386c3Smickey /* XXX will implement later */ 208556d2ba7Smickey printf ("trap: handicapped"); 209556d2ba7Smickey break; 210532740e6Smickey #else 211532740e6Smickey goto dead_end; 212d412f1c2Smickey #endif 21366d1ab7aSmickey 21466d1ab7aSmickey #ifdef DIAGNOSTIC 21566d1ab7aSmickey case T_EXCEPTION: 21666d1ab7aSmickey panic("FPU/SFU emulation botch"); 21766d1ab7aSmickey 21866d1ab7aSmickey /* these just can't happen ever */ 21966d1ab7aSmickey case T_PRIV_OP: 22066d1ab7aSmickey case T_PRIV_REG: 22166d1ab7aSmickey /* these just can't make it to the trap() ever */ 22266d1ab7aSmickey case T_HPMC: case T_HPMC | T_USER: 22366d1ab7aSmickey case T_EMULATION: case T_EMULATION | T_USER: 22466d1ab7aSmickey #endif 225f4daacd8Smickey case T_IBREAK: 226a24c0b7aSmickey case T_DATALIGN: 227a24c0b7aSmickey case T_DBREAK: 2288de28e3eSmickey dead_end: 229a24c0b7aSmickey #ifdef DDB 230532740e6Smickey if (kdb_trap (type, va, frame)) { 231a24c0b7aSmickey if (type == T_IBREAK) { 232f4daacd8Smickey /* skip break instruction */ 2338de28e3eSmickey frame->tf_iioq_head = frame->tf_iioq_tail; 234f4daacd8Smickey frame->tf_iioq_tail += 4; 235a24c0b7aSmickey } 236556d2ba7Smickey return; 237a24c0b7aSmickey } 238137d3021Smickey #else 239137d3021Smickey if (type == T_DATALIGN) 240137d3021Smickey panic ("trap: %s at 0x%x", tts, va); 241137d3021Smickey else 242137d3021Smickey panic ("trap: no debugger for \"%s\" (%d)", tts, type); 243a24c0b7aSmickey #endif 244556d2ba7Smickey break; 245556d2ba7Smickey 246af7386c3Smickey case T_IBREAK | T_USER: 247af7386c3Smickey case T_DBREAK | T_USER: 248af7386c3Smickey /* pass to user debugger */ 249d412f1c2Smickey break; 250d412f1c2Smickey 251af7386c3Smickey case T_EXCEPTION | T_USER: /* co-proc assist trap */ 252137d3021Smickey sv.sival_int = va; 253af7386c3Smickey trapsignal(p, SIGFPE, type &~ T_USER, FPE_FLTINV, sv); 254d412f1c2Smickey break; 255d412f1c2Smickey 256af7386c3Smickey case T_OVERFLOW | T_USER: 257137d3021Smickey sv.sival_int = va; 258af7386c3Smickey trapsignal(p, SIGFPE, type &~ T_USER, FPE_INTOVF, sv); 259d412f1c2Smickey break; 260d412f1c2Smickey 261af7386c3Smickey case T_CONDITION | T_USER: 262af7386c3Smickey break; 263af7386c3Smickey 264af7386c3Smickey case T_ILLEGAL | T_USER: 265137d3021Smickey sv.sival_int = va; 266af7386c3Smickey trapsignal(p, SIGILL, type &~ T_USER, ILL_ILLOPC, sv); 267af7386c3Smickey break; 268af7386c3Smickey 269af7386c3Smickey case T_PRIV_OP | T_USER: 270137d3021Smickey sv.sival_int = va; 271af7386c3Smickey trapsignal(p, SIGILL, type &~ T_USER, ILL_PRVOPC, sv); 272af7386c3Smickey break; 273af7386c3Smickey 274af7386c3Smickey case T_PRIV_REG | T_USER: 275137d3021Smickey sv.sival_int = va; 276af7386c3Smickey trapsignal(p, SIGILL, type &~ T_USER, ILL_PRVREG, sv); 277af7386c3Smickey break; 278af7386c3Smickey 279af7386c3Smickey /* these should never got here */ 280af7386c3Smickey case T_HIGHERPL | T_USER: 281af7386c3Smickey case T_LOWERPL | T_USER: 282137d3021Smickey sv.sival_int = va; 283af7386c3Smickey trapsignal(p, SIGSEGV, type &~ T_USER, SEGV_ACCERR, sv); 284af7386c3Smickey break; 285af7386c3Smickey 286af7386c3Smickey case T_IPROT | T_USER: 287af7386c3Smickey case T_DPROT | T_USER: 288af7386c3Smickey sv.sival_int = va; 289af7386c3Smickey trapsignal(p, SIGSEGV, vftype, SEGV_ACCERR, sv); 290af7386c3Smickey break; 291af7386c3Smickey 292ec21eae5Smickey case T_DATACC: case T_USER | T_DATACC: 293ec21eae5Smickey case T_ITLBMISS: case T_USER | T_ITLBMISS: 294ec21eae5Smickey case T_DTLBMISS: case T_USER | T_DTLBMISS: 295ec21eae5Smickey case T_ITLBMISSNA: case T_USER | T_ITLBMISSNA: 296ec21eae5Smickey case T_DTLBMISSNA: case T_USER | T_DTLBMISSNA: 297ec21eae5Smickey case T_TLB_DIRTY: case T_USER | T_TLB_DIRTY: 298bed2d21eSmickey va = hppa_trunc_page(va); 299f17fa196Smickey vm = p->p_vmspace; 3008de28e3eSmickey 301532740e6Smickey if (!vm) { 302532740e6Smickey #ifdef TRAPDEBUG 303532740e6Smickey printf("trap: no vm, p=%p\n", p); 304532740e6Smickey #endif 3058de28e3eSmickey goto dead_end; 306532740e6Smickey } 3078de28e3eSmickey 3088de28e3eSmickey /* 309e494c7cfSmickey * it could be a kernel map for exec_map faults 3108de28e3eSmickey */ 3118de28e3eSmickey if (!(type & T_USER) && space == HPPA_SID_KERNEL) 3128de28e3eSmickey map = kernel_map; 3138de28e3eSmickey else 314f17fa196Smickey map = &vm->vm_map; 315556d2ba7Smickey 316532740e6Smickey if (map->pmap->pmap_space != space) { 317532740e6Smickey #ifdef TRAPDEBUG 318532740e6Smickey printf("trap: space missmatch %d != %d\n", 319532740e6Smickey space, map->pmap->pmap_space); 320532740e6Smickey #endif 321532740e6Smickey /* actually dump the user, crap the kernel */ 322532740e6Smickey goto dead_end; 323532740e6Smickey } 324532740e6Smickey 325137d3021Smickey ret = uvm_fault(map, va, 0, vftype); 326f17fa196Smickey 327532740e6Smickey #ifdef TRAPDEBUG 328532740e6Smickey printf("uvm_fault(%p, %x, %d, %d)=%d\n", 329532740e6Smickey map, va, 0, vftype, ret); 330532740e6Smickey #endif 331532740e6Smickey 332f17fa196Smickey /* 333f17fa196Smickey * If this was a stack access we keep track of the maximum 334f17fa196Smickey * accessed stack size. Also, if uvm_fault gets a protection 335f17fa196Smickey * failure it is due to accessing the stack region outside 336f17fa196Smickey * the current limit and we need to reflect that as an access 337f17fa196Smickey * error. 338f17fa196Smickey */ 339f17fa196Smickey if (va >= (vaddr_t)vm->vm_maxsaddr + vm->vm_ssize) { 340f17fa196Smickey if (ret == KERN_SUCCESS) { 341c7ba784cSart vsize_t nss = btoc(va - USRSTACK + NBPG); 342f17fa196Smickey if (nss > vm->vm_ssize) 343f17fa196Smickey vm->vm_ssize = nss; 344f17fa196Smickey } else if (ret == KERN_PROTECTION_FAILURE) 345f17fa196Smickey ret = KERN_INVALID_ADDRESS; 346f17fa196Smickey } 347f17fa196Smickey 348af7386c3Smickey if (ret != KERN_SUCCESS) { 349af7386c3Smickey if (type & T_USER) { 350137d3021Smickey printf("trapsignal: uvm_fault\n"); 351af7386c3Smickey sv.sival_int = frame->tf_ior; 352af7386c3Smickey trapsignal(p, SIGSEGV, vftype, SEGV_MAPERR, sv); 353137d3021Smickey } else { 3548de28e3eSmickey if (p && p->p_addr->u_pcb.pcb_onfault) { 3558de28e3eSmickey #ifdef PMAPDEBUG 3568de28e3eSmickey printf("trap: copyin/out %d\n",ret); 357137d3021Smickey #endif 3588de28e3eSmickey pcbp = &p->p_addr->u_pcb; 3598de28e3eSmickey frame->tf_iioq_tail = 4 + 3608de28e3eSmickey (frame->tf_iioq_head = 3618de28e3eSmickey pcbp->pcb_onfault); 362137d3021Smickey pcbp->pcb_onfault = 0; 363137d3021Smickey break; 364af7386c3Smickey } 365137d3021Smickey #if 1 366532740e6Smickey if (kdb_trap (type, va, frame)) 367137d3021Smickey return; 368137d3021Smickey #else 369137d3021Smickey panic("trap: uvm_fault(%p, %x, %d, %d): %d", 3702191603aSmickey map, va, 0, vftype, ret); 371137d3021Smickey #endif 372137d3021Smickey } 373137d3021Smickey } 374556d2ba7Smickey break; 375d412f1c2Smickey 376af7386c3Smickey case T_DATALIGN | T_USER: 377137d3021Smickey sv.sival_int = va; 378af7386c3Smickey trapsignal(p, SIGBUS, vftype, BUS_ADRALN, sv); 379af7386c3Smickey break; 380af7386c3Smickey 381a24c0b7aSmickey case T_INTERRUPT: 382a24c0b7aSmickey case T_INTERRUPT|T_USER: 383f48ce072Smickey frame->tf_flags |= TFF_INTR; 384a24c0b7aSmickey cpu_intr(frame); 385137d3021Smickey #if 0 386532740e6Smickey if (kdb_trap (type, va, frame)) 387137d3021Smickey return; 388137d3021Smickey #endif 389a24c0b7aSmickey /* FALLTHROUGH */ 390af7386c3Smickey case T_LOWERPL: 391a24c0b7aSmickey __asm __volatile ("ldcws 0(%1), %0" 392a24c0b7aSmickey : "=r" (si) : "r" (&sir)); 393af7386c3Smickey s = spl0(); 394a24c0b7aSmickey if (si & SIR_CLOCK) { 395af7386c3Smickey splclock(); 396af7386c3Smickey softclock(); 397af7386c3Smickey spl0(); 398af7386c3Smickey } 399af7386c3Smickey 400a24c0b7aSmickey if (si & SIR_NET) { 401af7386c3Smickey register int ni; 402af7386c3Smickey /* use atomic "load & clear" */ 403af7386c3Smickey __asm __volatile ("ldcws 0(%1), %0" 404af7386c3Smickey : "=r" (ni) : "r" (&netisr)); 405af7386c3Smickey splnet(); 406d136e661Smickey #define DONETISR(m,c) if (ni & (1 << (m))) c() 407d136e661Smickey #include <net/netisr_dispatch.h> 408af7386c3Smickey } 409af7386c3Smickey splx(s); 410af7386c3Smickey break; 411af7386c3Smickey 4122ef9a47eSmickey case T_DPROT: 4132ef9a47eSmickey case T_IPROT: 414af7386c3Smickey case T_OVERFLOW: 415af7386c3Smickey case T_CONDITION: 416af7386c3Smickey case T_ILLEGAL: 417af7386c3Smickey case T_HIGHERPL: 418af7386c3Smickey case T_TAKENBR: 419af7386c3Smickey case T_POWERFAIL: 420af7386c3Smickey case T_LPMC: 421af7386c3Smickey case T_PAGEREF: 422d412f1c2Smickey case T_DATAPID: case T_DATAPID | T_USER: 423d412f1c2Smickey if (0 /* T-chip */) { 424d412f1c2Smickey break; 425556d2ba7Smickey } 426d412f1c2Smickey /* FALLTHROUGH to unimplemented */ 427d412f1c2Smickey default: 428137d3021Smickey #if 1 429532740e6Smickey if (kdb_trap (type, va, frame)) 430137d3021Smickey return; 431137d3021Smickey #endif 432137d3021Smickey panic ("trap: unimplemented \'%s\' (%d)", tts, type); 433d412f1c2Smickey } 434af7386c3Smickey 435af7386c3Smickey if (type & T_USER) 436af7386c3Smickey userret(p, p->p_md.md_regs->tf_iioq_head, 0); 437d412f1c2Smickey } 438d412f1c2Smickey 439d412f1c2Smickey void 440d412f1c2Smickey child_return(p) 441d412f1c2Smickey struct proc *p; 442d412f1c2Smickey { 443d412f1c2Smickey userret(p, p->p_md.md_regs->tf_iioq_head, 0); 444d412f1c2Smickey #ifdef KTRACE 445d412f1c2Smickey if (KTRPOINT(p, KTR_SYSRET)) 446a27b30d8Sart ktrsysret(p, SYS_fork, 0, 0); 447d412f1c2Smickey #endif 448556d2ba7Smickey } 449556d2ba7Smickey 450b9b95e0dSmickey /* 451b9b95e0dSmickey * call actual syscall routine 452b9b95e0dSmickey * from the low-level syscall handler: 453b9b95e0dSmickey * - all HPPA_FRAME_NARGS syscall's arguments supposed to be copied onto 454b9b95e0dSmickey * our stack, this wins compared to copyin just needed amount anyway 455b9b95e0dSmickey * - register args are copied onto stack too 456b9b95e0dSmickey */ 457b9b95e0dSmickey void 458b9b95e0dSmickey syscall(frame, args) 459b9b95e0dSmickey struct trapframe *frame; 460b9b95e0dSmickey int *args; 461b9b95e0dSmickey { 462b9b95e0dSmickey register struct proc *p; 463b9b95e0dSmickey register const struct sysent *callp; 464b9b95e0dSmickey int nsys, code, argsize, error; 465b9b95e0dSmickey int rval[2]; 466b9b95e0dSmickey 467b9b95e0dSmickey uvmexp.syscalls++; 468b9b95e0dSmickey 469b9b95e0dSmickey if (!USERMODE(frame->tf_iioq_head)) 470b9b95e0dSmickey panic("syscall"); 471b9b95e0dSmickey 472b9b95e0dSmickey p = curproc; 473137d3021Smickey p->p_md.md_regs = frame; 474b9b95e0dSmickey nsys = p->p_emul->e_nsysent; 475b9b95e0dSmickey callp = p->p_emul->e_sysent; 476137d3021Smickey code = frame->tf_t1; 477b9b95e0dSmickey switch (code) { 478b9b95e0dSmickey case SYS_syscall: 479532740e6Smickey code = *args; 480b9b95e0dSmickey args += 1; 481b9b95e0dSmickey break; 482b9b95e0dSmickey case SYS___syscall: 483b9b95e0dSmickey if (callp != sysent) 484b9b95e0dSmickey break; 485532740e6Smickey code = *args; 486b9b95e0dSmickey args += 2; 487b9b95e0dSmickey } 488b9b95e0dSmickey 489b9b95e0dSmickey if (code < 0 || code >= nsys) 490b9b95e0dSmickey callp += p->p_emul->e_nosys; /* bad syscall # */ 491b9b95e0dSmickey else 492b9b95e0dSmickey callp += code; 493b9b95e0dSmickey argsize = callp->sy_argsize; 494b9b95e0dSmickey 495b9b95e0dSmickey #ifdef SYSCALL_DEBUG 496b9b95e0dSmickey scdebug_call(p, code, args); 497b9b95e0dSmickey #endif 498b9b95e0dSmickey #ifdef KTRACE 499b9b95e0dSmickey if (KTRPOINT(p, KTR_SYSCALL)) 500a27b30d8Sart ktrsyscall(p, code, argsize, args); 501b9b95e0dSmickey #endif 502b9b95e0dSmickey 503b9b95e0dSmickey rval[0] = 0; 504b9b95e0dSmickey rval[1] = 0; 505b9b95e0dSmickey switch (error = (*callp->sy_call)(p, args, rval)) { 506b9b95e0dSmickey case 0: 507532740e6Smickey p = curproc; /* changes on exec() */ 508532740e6Smickey frame = p->p_md.md_regs; 509b9b95e0dSmickey frame->tf_ret0 = rval[0]; 510b9b95e0dSmickey frame->tf_ret1 = rval[1]; 511137d3021Smickey frame->tf_t1 = 0; 512b9b95e0dSmickey break; 513b9b95e0dSmickey case ERESTART: 514b9b95e0dSmickey frame->tf_iioq_head -= 4; /* right? XXX */ 515532740e6Smickey frame->tf_iioq_tail -= 4; /* right? XXX */ 516b9b95e0dSmickey break; 517b9b95e0dSmickey case EJUSTRETURN: 518532740e6Smickey p = curproc; 519b9b95e0dSmickey break; 520b9b95e0dSmickey default: 521b9b95e0dSmickey if (p->p_emul->e_errno) 522b9b95e0dSmickey error = p->p_emul->e_errno[error]; 523137d3021Smickey frame->tf_t1 = error; 524b9b95e0dSmickey break; 525b9b95e0dSmickey } 526b9b95e0dSmickey #ifdef SYSCALL_DEBUG 527b9b95e0dSmickey scdebug_ret(p, code, error, rval); 528b9b95e0dSmickey #endif 529532740e6Smickey userret(p, frame->tf_iioq_head, 0); 530b9b95e0dSmickey #ifdef KTRACE 531b9b95e0dSmickey if (KTRPOINT(p, KTR_SYSRET)) 532a27b30d8Sart ktrsysret(p, code, error, rval[0]); 533b9b95e0dSmickey #endif 534b9b95e0dSmickey } 535b9b95e0dSmickey 536556d2ba7Smickey /* all the interrupts, minus cpu clock, which is the last */ 537556d2ba7Smickey struct cpu_intr_vector { 5383a81311eSmickey struct evcnt evcnt; 539556d2ba7Smickey int pri; 540556d2ba7Smickey int (*handler) __P((void *)); 541556d2ba7Smickey void *arg; 542a24c0b7aSmickey } cpu_intr_vectors[CPU_NINTS]; 543556d2ba7Smickey 544b9b95e0dSmickey void * 5453a81311eSmickey cpu_intr_establish(pri, irq, handler, arg, dv) 546b9b95e0dSmickey int pri, irq; 547556d2ba7Smickey int (*handler) __P((void *)); 548556d2ba7Smickey void *arg; 5493a81311eSmickey struct device *dv; 550556d2ba7Smickey { 5513a81311eSmickey register struct cpu_intr_vector *iv; 552556d2ba7Smickey 553a24c0b7aSmickey if (0 <= irq && irq < CPU_NINTS && cpu_intr_vectors[irq].handler) 554b9b95e0dSmickey return NULL; 555556d2ba7Smickey 5563a81311eSmickey iv = &cpu_intr_vectors[irq]; 5573a81311eSmickey iv->pri = pri; 5583a81311eSmickey iv->handler = handler; 5593a81311eSmickey iv->arg = arg; 560688a8060Smickey evcnt_attach(dv, dv->dv_xname, &iv->evcnt); 561556d2ba7Smickey 562688a8060Smickey return iv; 563556d2ba7Smickey } 564556d2ba7Smickey 565556d2ba7Smickey void 566a24c0b7aSmickey cpu_intr(frame) 567556d2ba7Smickey struct trapframe *frame; 568556d2ba7Smickey { 569b9b95e0dSmickey u_int32_t eirr; 5703a81311eSmickey register struct cpu_intr_vector *iv; 571556d2ba7Smickey register int bit; 572556d2ba7Smickey 573556d2ba7Smickey do { 574b9b95e0dSmickey mfctl(CR_EIRR, eirr); 575a24c0b7aSmickey eirr &= frame->tf_eiem; 576b9b95e0dSmickey bit = ffs(eirr) - 1; 577556d2ba7Smickey if (bit >= 0) { 578556d2ba7Smickey mtctl(1 << bit, CR_EIRR); 579b9b95e0dSmickey eirr &= ~(1 << bit); 580b9b95e0dSmickey /* ((struct iomod *)cpu_gethpa(0))->io_eir = 0; */ 581556d2ba7Smickey #ifdef INTRDEBUG 582a24c0b7aSmickey if (bit != 31) 583137d3021Smickey db_printf ("cpu_intr: 0x%08x\n", (1 << bit)); 584556d2ba7Smickey #endif 5853a81311eSmickey iv = &cpu_intr_vectors[bit]; 5863a81311eSmickey if (iv->handler) { 587688a8060Smickey register int s, r; 5883a81311eSmickey 5893a81311eSmickey iv->evcnt.ev_count++; 590688a8060Smickey s = splx(iv->pri); 5917cd4d71fSmickey /* no arg means pass the frame */ 592688a8060Smickey r = (iv->handler)(iv->arg? iv->arg:frame); 593688a8060Smickey splx(s); 594532740e6Smickey #ifdef INTRDEBUG 595688a8060Smickey if (!r) 596137d3021Smickey db_printf ("%s: can't handle interrupt\n", 597688a8060Smickey iv->evcnt.ev_name); 598b9b95e0dSmickey #endif 599532740e6Smickey } 600532740e6Smickey #ifdef INTRDEBUG 601532740e6Smickey else 602137d3021Smickey db_printf ("cpu_intr: stray interrupt %d\n", bit); 603532740e6Smickey #endif 604b9b95e0dSmickey } 605b9b95e0dSmickey } while (eirr); 606556d2ba7Smickey } 607