1*b9b95e0dSmickey /* $OpenBSD: trap.c,v 1.3 1999/04/20 20:58:01 mickey Exp $ */ 2556d2ba7Smickey 3556d2ba7Smickey /* 4556d2ba7Smickey * Copyright (c) 1998 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 33556d2ba7Smickey #define INTRDEBUG 34556d2ba7Smickey 35556d2ba7Smickey #include <sys/param.h> 36556d2ba7Smickey #include <sys/systm.h> 37*b9b95e0dSmickey #include <sys/syscall.h> 38*b9b95e0dSmickey #include <sys/ktrace.h> 39556d2ba7Smickey 40556d2ba7Smickey #include <vm/vm.h> 41*b9b95e0dSmickey #include <uvm/uvm.h> 42556d2ba7Smickey 43556d2ba7Smickey #include <machine/iomod.h> 44556d2ba7Smickey #include <machine/cpufunc.h> 45556d2ba7Smickey #include <machine/reg.h> 46556d2ba7Smickey #include <machine/db_machdep.h> 47556d2ba7Smickey #include <machine/autoconf.h> 48556d2ba7Smickey 49556d2ba7Smickey #define FAULT_TYPE(op) (VM_PROT_READ|(inst_load(op) ? 0 : VM_PROT_WRITE)) 50556d2ba7Smickey 51556d2ba7Smickey const char *trap_type[] = { 52556d2ba7Smickey "invalid interrupt vector", 53556d2ba7Smickey "high priority machine check", 54556d2ba7Smickey "power failure", 55556d2ba7Smickey "recovery counter trap", 56556d2ba7Smickey "external interrupt", 57556d2ba7Smickey "low-priority machine check", 58556d2ba7Smickey "instruction TLB miss fault", 59556d2ba7Smickey "instruction protection trap", 60556d2ba7Smickey "Illegal instruction trap", 61556d2ba7Smickey "break instruction trap", 62556d2ba7Smickey "privileged operation trap", 63556d2ba7Smickey "privileged register trap", 64556d2ba7Smickey "overflow trap", 65556d2ba7Smickey "conditional trap", 66556d2ba7Smickey "assist exception trap", 67556d2ba7Smickey "data TLB miss fault", 68556d2ba7Smickey "ITLB non-access miss fault", 69556d2ba7Smickey "DTLB non-access miss fault", 70556d2ba7Smickey "data protection trap/unalligned data reference trap", 71556d2ba7Smickey "data break trap", 72556d2ba7Smickey "TLB dirty bit trap", 73556d2ba7Smickey "page reference trap", 74556d2ba7Smickey "assist emulation trap", 75556d2ba7Smickey "higher-privelege transfer trap", 76556d2ba7Smickey "lower-privilege transfer trap", 77556d2ba7Smickey "taken branch trap", 78556d2ba7Smickey "data access rights trap", 79556d2ba7Smickey "data protection ID trap", 80556d2ba7Smickey "unaligned data ref trap", 81556d2ba7Smickey "reserved", 82556d2ba7Smickey "reserved 2" 83556d2ba7Smickey }; 84556d2ba7Smickey int trap_types = sizeof(trap_type)/sizeof(trap_type[0]); 85556d2ba7Smickey 86556d2ba7Smickey u_int32_t sir; 87*b9b95e0dSmickey int want_resched; 88556d2ba7Smickey 89556d2ba7Smickey void pmap_hptdump __P((void)); 90*b9b95e0dSmickey void cpu_intr __P((u_int32_t t, struct trapframe *frame)); 91*b9b95e0dSmickey void syscall __P((struct trapframe *frame, int *args)); 92556d2ba7Smickey 93556d2ba7Smickey void 94556d2ba7Smickey trap(type, frame) 95556d2ba7Smickey int type; 96556d2ba7Smickey struct trapframe *frame; 97556d2ba7Smickey { 98556d2ba7Smickey struct proc *p = curproc; 99556d2ba7Smickey register vm_offset_t va; 100556d2ba7Smickey register vm_map_t map; 101556d2ba7Smickey register pa_space_t space; 102556d2ba7Smickey u_int opcode, t; 103556d2ba7Smickey int ret; 104556d2ba7Smickey 105*b9b95e0dSmickey va = frame->tf_ior; 106*b9b95e0dSmickey space = (pa_space_t) frame->tf_isr; 107556d2ba7Smickey 108*b9b95e0dSmickey if (USERMODE(frame->tf_iioq_head)) { 109556d2ba7Smickey type |= T_USER; 110556d2ba7Smickey p->p_md.md_regs = frame; 111556d2ba7Smickey } 112556d2ba7Smickey 113556d2ba7Smickey if ((type & ~T_USER) != T_INTERRUPT) 114556d2ba7Smickey printf("trap: %d, %s for %x:%x at %x:%x\n", 115556d2ba7Smickey type, trap_type[type & ~T_USER], space, va, 116*b9b95e0dSmickey frame->tf_iisq_head, frame->tf_iioq_head); 117556d2ba7Smickey 118556d2ba7Smickey switch (type) { 119556d2ba7Smickey case T_NONEXIST: 120556d2ba7Smickey case T_NONEXIST|T_USER: 121556d2ba7Smickey /* we are screwd up by the central scrutinizer */ 122556d2ba7Smickey panic ("trap: zombie on the bridge!!!"); 123556d2ba7Smickey break; 124556d2ba7Smickey 125556d2ba7Smickey case T_RECOVERY: 126556d2ba7Smickey case T_RECOVERY|T_USER: 127556d2ba7Smickey printf ("trap: handicapped"); 128556d2ba7Smickey break; 129556d2ba7Smickey 130556d2ba7Smickey case T_INTERRUPT: 131556d2ba7Smickey case T_INTERRUPT|T_USER: 132556d2ba7Smickey mfctl(CR_EIRR, t); 133*b9b95e0dSmickey t &= frame->tf_eiem; 134*b9b95e0dSmickey /* ACK it now */ 135556d2ba7Smickey /* hardcode intvl timer intr, to save for proc switching */ 136556d2ba7Smickey if (t & INT_ITMR) { 137556d2ba7Smickey mtctl(INT_ITMR, CR_EIRR); 138556d2ba7Smickey /* we've got an interval timer interrupt */ 139556d2ba7Smickey cpu_initclocks(); 140556d2ba7Smickey hardclock(frame); 141*b9b95e0dSmickey t ^= INT_ITMR; 142556d2ba7Smickey } 143*b9b95e0dSmickey if (t) 144*b9b95e0dSmickey cpu_intr(t, frame); 145556d2ba7Smickey return; 146556d2ba7Smickey 147556d2ba7Smickey case T_HPMC: 148556d2ba7Smickey case T_POWERFAIL: 149556d2ba7Smickey case T_LPMC: 150556d2ba7Smickey break; 151556d2ba7Smickey 152556d2ba7Smickey case T_IBREAK: 153556d2ba7Smickey case T_DBREAK: 154556d2ba7Smickey if (kdb_trap (type, 0, frame)) 155556d2ba7Smickey return; 156556d2ba7Smickey break; 157556d2ba7Smickey 158556d2ba7Smickey case T_DTLBMISS: 159556d2ba7Smickey va = trunc_page(va); 160*b9b95e0dSmickey opcode = frame->tf_iir; 161556d2ba7Smickey 162556d2ba7Smickey #ifdef DDB 163556d2ba7Smickey Debugger(); 164556d2ba7Smickey #endif 165*b9b95e0dSmickey ret = uvm_fault(map, va, FAULT_TYPE(opcode), FALSE); 166556d2ba7Smickey if (ret == KERN_SUCCESS) 167556d2ba7Smickey break; 16830ada397Smillert panic("trap: vm_fault(%p, %x, %d, %d): %d", 169556d2ba7Smickey map, va, FAULT_TYPE(opcode), 0, ret); 170556d2ba7Smickey break; 171556d2ba7Smickey default: 172556d2ba7Smickey /* pmap_hptdump(); */ 173556d2ba7Smickey #ifdef DDB 174556d2ba7Smickey Debugger(); 175556d2ba7Smickey #endif 176556d2ba7Smickey } 177556d2ba7Smickey } 178556d2ba7Smickey 179*b9b95e0dSmickey /* 180*b9b95e0dSmickey * call actual syscall routine 181*b9b95e0dSmickey * from the low-level syscall handler: 182*b9b95e0dSmickey * - all HPPA_FRAME_NARGS syscall's arguments supposed to be copied onto 183*b9b95e0dSmickey * our stack, this wins compared to copyin just needed amount anyway 184*b9b95e0dSmickey * - register args are copied onto stack too 185*b9b95e0dSmickey */ 186*b9b95e0dSmickey void 187*b9b95e0dSmickey syscall(frame, args) 188*b9b95e0dSmickey struct trapframe *frame; 189*b9b95e0dSmickey int *args; 190*b9b95e0dSmickey { 191*b9b95e0dSmickey register struct proc *p; 192*b9b95e0dSmickey register const struct sysent *callp; 193*b9b95e0dSmickey int nsys, code, argsize, error; 194*b9b95e0dSmickey int rval[2]; 195*b9b95e0dSmickey 196*b9b95e0dSmickey uvmexp.syscalls++; 197*b9b95e0dSmickey 198*b9b95e0dSmickey if (!USERMODE(frame->tf_iioq_head)) 199*b9b95e0dSmickey panic("syscall"); 200*b9b95e0dSmickey 201*b9b95e0dSmickey p = curproc; 202*b9b95e0dSmickey nsys = p->p_emul->e_nsysent; 203*b9b95e0dSmickey callp = p->p_emul->e_sysent; 204*b9b95e0dSmickey code = frame->tf_arg0; 205*b9b95e0dSmickey switch (code) { 206*b9b95e0dSmickey case SYS_syscall: 207*b9b95e0dSmickey code = frame->tf_arg1; 208*b9b95e0dSmickey args += 1; 209*b9b95e0dSmickey break; 210*b9b95e0dSmickey case SYS___syscall: 211*b9b95e0dSmickey if (callp != sysent) 212*b9b95e0dSmickey break; 213*b9b95e0dSmickey code = frame->tf_arg1; /* XXX or arg2? */ 214*b9b95e0dSmickey args += 2; 215*b9b95e0dSmickey } 216*b9b95e0dSmickey 217*b9b95e0dSmickey if (code < 0 || code >= nsys) 218*b9b95e0dSmickey callp += p->p_emul->e_nosys; /* bad syscall # */ 219*b9b95e0dSmickey else 220*b9b95e0dSmickey callp += code; 221*b9b95e0dSmickey argsize = callp->sy_argsize; 222*b9b95e0dSmickey 223*b9b95e0dSmickey #ifdef SYSCALL_DEBUG 224*b9b95e0dSmickey scdebug_call(p, code, args); 225*b9b95e0dSmickey #endif 226*b9b95e0dSmickey #ifdef KTRACE 227*b9b95e0dSmickey if (KTRPOINT(p, KTR_SYSCALL)) 228*b9b95e0dSmickey ktrsyscall(p->p_tracep, code, argsize, args); 229*b9b95e0dSmickey #endif 230*b9b95e0dSmickey 231*b9b95e0dSmickey rval[0] = 0; 232*b9b95e0dSmickey rval[1] = 0; 233*b9b95e0dSmickey switch (error = (*callp->sy_call)(p, args, rval)) { 234*b9b95e0dSmickey case 0: 235*b9b95e0dSmickey /* curproc may change iside the fork() */ 236*b9b95e0dSmickey p = curproc; 237*b9b95e0dSmickey frame->tf_ret0 = rval[0]; 238*b9b95e0dSmickey frame->tf_ret1 = rval[1]; 239*b9b95e0dSmickey break; 240*b9b95e0dSmickey case ERESTART: 241*b9b95e0dSmickey frame->tf_iioq_head -= 4; /* right? XXX */ 242*b9b95e0dSmickey break; 243*b9b95e0dSmickey case EJUSTRETURN: 244*b9b95e0dSmickey break; 245*b9b95e0dSmickey default: 246*b9b95e0dSmickey if (p->p_emul->e_errno) 247*b9b95e0dSmickey error = p->p_emul->e_errno[error]; 248*b9b95e0dSmickey frame->tf_ret0 = error; 249*b9b95e0dSmickey break; 250*b9b95e0dSmickey } 251*b9b95e0dSmickey 252*b9b95e0dSmickey #ifdef SYSCALL_DEBUG 253*b9b95e0dSmickey scdebug_ret(p, code, error, rval); 254*b9b95e0dSmickey #endif 255*b9b95e0dSmickey #ifdef KTRACE 256*b9b95e0dSmickey if (KTRPOINT(p, KTR_SYSRET)) 257*b9b95e0dSmickey ktrsysret(p->p_tracep, code, error, rval[0]); 258*b9b95e0dSmickey #endif 259*b9b95e0dSmickey } 260*b9b95e0dSmickey 261556d2ba7Smickey /* all the interrupts, minus cpu clock, which is the last */ 262556d2ba7Smickey struct cpu_intr_vector { 263556d2ba7Smickey const char *name; 264556d2ba7Smickey int pri; 265556d2ba7Smickey int (*handler) __P((void *)); 266556d2ba7Smickey void *arg; 267556d2ba7Smickey } cpu_intr_vectors[CPU_NINTS - 1]; 268556d2ba7Smickey 269*b9b95e0dSmickey void * 270*b9b95e0dSmickey cpu_intr_establish(pri, irq, handler, arg, name) 271*b9b95e0dSmickey int pri, irq; 272556d2ba7Smickey int (*handler) __P((void *)); 273556d2ba7Smickey void *arg; 274556d2ba7Smickey const char *name; 275556d2ba7Smickey { 276556d2ba7Smickey register struct cpu_intr_vector *p; 277556d2ba7Smickey 278*b9b95e0dSmickey /* don't allow to override any established vectors, 279*b9b95e0dSmickey AND interval timer hard-bound one */ 280*b9b95e0dSmickey if (irq >= (CPU_NINTS - 1) || cpu_intr_vectors[irq].handler) 281*b9b95e0dSmickey return NULL; 282556d2ba7Smickey 283*b9b95e0dSmickey p = &cpu_intr_vectors[irq]; 284556d2ba7Smickey p->name = name; 285556d2ba7Smickey p->pri = pri; 286556d2ba7Smickey p->handler = handler; 287556d2ba7Smickey p->arg = arg; 288556d2ba7Smickey 289*b9b95e0dSmickey return p; 290556d2ba7Smickey } 291556d2ba7Smickey 292556d2ba7Smickey void 293*b9b95e0dSmickey cpu_intr(t, frame) 294*b9b95e0dSmickey u_int32_t t; 295556d2ba7Smickey struct trapframe *frame; 296556d2ba7Smickey { 297*b9b95e0dSmickey u_int32_t eirr; 298556d2ba7Smickey register struct cpu_intr_vector *p; 299556d2ba7Smickey register int bit; 300556d2ba7Smickey 301556d2ba7Smickey do { 302*b9b95e0dSmickey mfctl(CR_EIRR, eirr); 303*b9b95e0dSmickey eirr = (t | eirr) & frame->tf_eiem; 304*b9b95e0dSmickey bit = ffs(eirr) - 1; 305556d2ba7Smickey if (bit >= 0) { 306556d2ba7Smickey mtctl(1 << bit, CR_EIRR); 307*b9b95e0dSmickey eirr &= ~(1 << bit); 308*b9b95e0dSmickey /* ((struct iomod *)cpu_gethpa(0))->io_eir = 0; */ 309556d2ba7Smickey #ifdef INTRDEBUG 310*b9b95e0dSmickey printf ("cpu_intr: 0x%08x\n", (1 << bit)); 311556d2ba7Smickey #endif 312556d2ba7Smickey p = &cpu_intr_vectors[bit]; 313556d2ba7Smickey if (p->handler) { 314556d2ba7Smickey register int s = splx(p->pri); 315556d2ba7Smickey if (!(p->handler)(p->arg)) 316*b9b95e0dSmickey #ifdef INTRDEBUG1 317*b9b95e0dSmickey panic ("%s: can't handle interrupt", 318*b9b95e0dSmickey p->name); 319*b9b95e0dSmickey #else 320556d2ba7Smickey printf ("%s: can't handle interrupt\n", 321556d2ba7Smickey p->name); 322*b9b95e0dSmickey #endif 323556d2ba7Smickey splx(s); 324*b9b95e0dSmickey } else { 325*b9b95e0dSmickey #ifdef INTRDEBUG 326*b9b95e0dSmickey panic ("cpu_intr: stray interrupt %d", bit); 327*b9b95e0dSmickey #else 328556d2ba7Smickey printf ("cpu_intr: stray interrupt %d\n", bit); 329*b9b95e0dSmickey #endif 330556d2ba7Smickey } 331*b9b95e0dSmickey } 332*b9b95e0dSmickey } while (eirr); 333556d2ba7Smickey } 334556d2ba7Smickey 335