Annotation of sys/arch/m88k/m88k/trap.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: trap.c,v 1.40 2007/05/11 10:06:55 pedro Exp $ */
! 2: /*
! 3: * Copyright (c) 2004, Miodrag Vallat.
! 4: * Copyright (c) 1998 Steve Murphree, Jr.
! 5: * Copyright (c) 1996 Nivas Madhur
! 6: * All rights reserved.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: * 1. Redistributions of source code must retain the above copyright
! 12: * notice, this list of conditions and the following disclaimer.
! 13: * 2. Redistributions in binary form must reproduce the above copyright
! 14: * notice, this list of conditions and the following disclaimer in the
! 15: * documentation and/or other materials provided with the distribution.
! 16: * 3. All advertising materials mentioning features or use of this software
! 17: * must display the following acknowledgement:
! 18: * This product includes software developed by Nivas Madhur.
! 19: * 4. The name of the author may not be used to endorse or promote products
! 20: * derived from this software without specific prior written permission
! 21: *
! 22: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 23: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 24: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 25: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 26: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 27: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 28: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 29: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 30: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 31: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 32: *
! 33: */
! 34: /*
! 35: * Mach Operating System
! 36: * Copyright (c) 1991 Carnegie Mellon University
! 37: * Copyright (c) 1991 OMRON Corporation
! 38: * All Rights Reserved.
! 39: *
! 40: * Permission to use, copy, modify and distribute this software and its
! 41: * documentation is hereby granted, provided that both the copyright
! 42: * notice and this permission notice appear in all copies of the
! 43: * software, derivative works or modified versions, and any portions
! 44: * thereof, and that both notices appear in supporting documentation.
! 45: *
! 46: */
! 47:
! 48: #include <sys/types.h>
! 49: #include <sys/param.h>
! 50: #include <sys/proc.h>
! 51: #include <sys/signalvar.h>
! 52: #include <sys/user.h>
! 53: #include <sys/syscall.h>
! 54: #include <sys/systm.h>
! 55: #include <sys/ktrace.h>
! 56:
! 57: #include "systrace.h"
! 58: #include <dev/systrace.h>
! 59:
! 60: #include <uvm/uvm_extern.h>
! 61:
! 62: #include <machine/asm_macro.h> /* enable/disable interrupts */
! 63: #include <machine/cmmu.h>
! 64: #include <machine/cpu.h>
! 65: #ifdef M88100
! 66: #include <machine/m88100.h> /* DMT_xxx */
! 67: #include <machine/m8820x.h> /* CMMU_PFSR_xxx */
! 68: #endif
! 69: #ifdef M88110
! 70: #include <machine/m88110.h>
! 71: #endif
! 72: #include <machine/pcb.h> /* FIP_E, etc. */
! 73: #include <machine/psl.h> /* FIP_E, etc. */
! 74: #include <machine/trap.h>
! 75:
! 76: #include <machine/db_machdep.h>
! 77:
! 78: #define SSBREAKPOINT (0xF000D1F8U) /* Single Step Breakpoint */
! 79:
! 80: #define USERMODE(PSR) (((PSR) & PSR_MODE) == 0)
! 81: #define SYSTEMMODE(PSR) (((PSR) & PSR_MODE) != 0)
! 82:
! 83: __dead void panictrap(int, struct trapframe *);
! 84: __dead void error_fatal(struct trapframe *);
! 85: int double_reg_fixup(struct trapframe *);
! 86: int ss_put_value(struct proc *, vaddr_t, u_int);
! 87:
! 88: extern void regdump(struct trapframe *f);
! 89:
! 90: const char *trap_type[] = {
! 91: "Reset",
! 92: "Interrupt Exception",
! 93: "Instruction Access",
! 94: "Data Access Exception",
! 95: "Misaligned Access",
! 96: "Unimplemented Opcode",
! 97: "Privilege Violation"
! 98: "Bounds Check Violation",
! 99: "Illegal Integer Divide",
! 100: "Integer Overflow",
! 101: "Error Exception",
! 102: "Non-Maskable Exception",
! 103: };
! 104:
! 105: const int trap_types = sizeof trap_type / sizeof trap_type[0];
! 106:
! 107: #ifdef M88100
! 108: const char *pbus_exception_type[] = {
! 109: "Success (No Fault)",
! 110: "unknown 1",
! 111: "unknown 2",
! 112: "Bus Error",
! 113: "Segment Fault",
! 114: "Page Fault",
! 115: "Supervisor Violation",
! 116: "Write Violation",
! 117: };
! 118: #endif
! 119:
! 120: static inline void
! 121: userret(struct proc *p)
! 122: {
! 123: int sig;
! 124:
! 125: /* take pending signals */
! 126: while ((sig = CURSIG(p)) != 0)
! 127: postsig(sig);
! 128:
! 129: curcpu()->ci_schedstate.spc_curpriority = p->p_priority = p->p_usrpri;
! 130: }
! 131:
! 132: __dead void
! 133: panictrap(int type, struct trapframe *frame)
! 134: {
! 135: static int panicing = 0;
! 136:
! 137: if (panicing++ == 0) {
! 138: #ifdef M88100
! 139: if (CPU_IS88100) {
! 140: if (type == 2) {
! 141: /* instruction exception */
! 142: printf("\nInstr access fault (%s) v = %x, "
! 143: "frame %p\n",
! 144: pbus_exception_type[
! 145: CMMU_PFSR_FAULT(frame->tf_ipfsr)],
! 146: frame->tf_sxip & XIP_ADDR, frame);
! 147: } else if (type == 3) {
! 148: /* data access exception */
! 149: printf("\nData access fault (%s) v = %x, "
! 150: "frame %p\n",
! 151: pbus_exception_type[
! 152: CMMU_PFSR_FAULT(frame->tf_dpfsr)],
! 153: frame->tf_sxip & XIP_ADDR, frame);
! 154: } else
! 155: printf("\nTrap type %d, v = %x, frame %p\n",
! 156: type, frame->tf_sxip & XIP_ADDR, frame);
! 157: }
! 158: #endif
! 159: #ifdef M88110
! 160: if (CPU_IS88110) {
! 161: printf("\nTrap type %d, v = %x, frame %p\n",
! 162: type, frame->tf_exip, frame);
! 163: }
! 164: #endif
! 165: #ifdef DDB
! 166: regdump(frame);
! 167: #endif
! 168: }
! 169: if ((u_int)type < trap_types)
! 170: panic(trap_type[type]);
! 171: else
! 172: panic("trap %d", type);
! 173: /*NOTREACHED*/
! 174: }
! 175:
! 176: #ifdef M88100
! 177: void
! 178: m88100_trap(unsigned type, struct trapframe *frame)
! 179: {
! 180: struct proc *p;
! 181: struct vm_map *map;
! 182: vaddr_t va, pcb_onfault;
! 183: vm_prot_t ftype;
! 184: int fault_type, pbus_type;
! 185: u_long fault_code;
! 186: unsigned fault_addr;
! 187: struct vmspace *vm;
! 188: union sigval sv;
! 189: int result;
! 190: #ifdef DDB
! 191: int s;
! 192: u_int psr;
! 193: #endif
! 194: int sig = 0;
! 195:
! 196: extern struct vm_map *kernel_map;
! 197:
! 198: uvmexp.traps++;
! 199: if ((p = curproc) == NULL)
! 200: p = &proc0;
! 201:
! 202: if (USERMODE(frame->tf_epsr)) {
! 203: type += T_USER;
! 204: p->p_md.md_tf = frame; /* for ptrace/signals */
! 205: }
! 206: fault_type = 0;
! 207: fault_code = 0;
! 208: fault_addr = frame->tf_sxip & XIP_ADDR;
! 209:
! 210: switch (type) {
! 211: default:
! 212: panictrap(frame->tf_vector, frame);
! 213: break;
! 214: /*NOTREACHED*/
! 215:
! 216: #if defined(DDB)
! 217: case T_KDB_BREAK:
! 218: s = splhigh();
! 219: set_psr((psr = get_psr()) & ~PSR_IND);
! 220: ddb_break_trap(T_KDB_BREAK, (db_regs_t*)frame);
! 221: set_psr(psr);
! 222: splx(s);
! 223: return;
! 224: case T_KDB_ENTRY:
! 225: s = splhigh();
! 226: set_psr((psr = get_psr()) & ~PSR_IND);
! 227: ddb_entry_trap(T_KDB_ENTRY, (db_regs_t*)frame);
! 228: set_psr(psr);
! 229: splx(s);
! 230: return;
! 231: #endif /* DDB */
! 232: case T_ILLFLT:
! 233: printf("Unimplemented opcode!\n");
! 234: panictrap(frame->tf_vector, frame);
! 235: break;
! 236: case T_INT:
! 237: case T_INT+T_USER:
! 238: curcpu()->ci_intrdepth++;
! 239: md_interrupt_func(T_INT, frame);
! 240: curcpu()->ci_intrdepth--;
! 241: return;
! 242:
! 243: case T_MISALGNFLT:
! 244: printf("kernel misaligned access exception @ 0x%08x\n",
! 245: frame->tf_sxip);
! 246: panictrap(frame->tf_vector, frame);
! 247: break;
! 248:
! 249: case T_INSTFLT:
! 250: /* kernel mode instruction access fault.
! 251: * Should never, never happen for a non-paged kernel.
! 252: */
! 253: #ifdef TRAPDEBUG
! 254: pbus_type = CMMU_PFSR_FAULT(frame->tf_ipfsr);
! 255: printf("Kernel Instruction fault #%d (%s) v = 0x%x, frame 0x%x cpu %p\n",
! 256: pbus_type, pbus_exception_type[pbus_type],
! 257: fault_addr, frame, frame->tf_cpu);
! 258: #endif
! 259: panictrap(frame->tf_vector, frame);
! 260: break;
! 261:
! 262: case T_DATAFLT:
! 263: /* kernel mode data fault */
! 264:
! 265: /* data fault on the user address? */
! 266: if ((frame->tf_dmt0 & DMT_DAS) == 0) {
! 267: type = T_DATAFLT + T_USER;
! 268: goto user_fault;
! 269: }
! 270:
! 271: fault_addr = frame->tf_dma0;
! 272: if (frame->tf_dmt0 & (DMT_WRITE|DMT_LOCKBAR)) {
! 273: ftype = VM_PROT_READ|VM_PROT_WRITE;
! 274: fault_code = VM_PROT_WRITE;
! 275: } else {
! 276: ftype = VM_PROT_READ;
! 277: fault_code = VM_PROT_READ;
! 278: }
! 279:
! 280: va = trunc_page((vaddr_t)fault_addr);
! 281: if (va == 0) {
! 282: panic("trap: bad kernel access at %x", fault_addr);
! 283: }
! 284:
! 285: KERNEL_LOCK();
! 286: vm = p->p_vmspace;
! 287: map = kernel_map;
! 288:
! 289: pbus_type = CMMU_PFSR_FAULT(frame->tf_dpfsr);
! 290: #ifdef TRAPDEBUG
! 291: printf("Kernel Data access fault #%d (%s) v = 0x%x, frame 0x%x cpu %p\n",
! 292: pbus_type, pbus_exception_type[pbus_type],
! 293: fault_addr, frame, frame->tf_cpu);
! 294: #endif
! 295:
! 296: switch (pbus_type) {
! 297: case CMMU_PFSR_SUCCESS:
! 298: /*
! 299: * The fault was resolved. Call data_access_emulation
! 300: * to drain the data unit pipe line and reset dmt0
! 301: * so that trap won't get called again.
! 302: */
! 303: data_access_emulation((unsigned *)frame);
! 304: frame->tf_dpfsr = 0;
! 305: frame->tf_dmt0 = 0;
! 306: KERNEL_UNLOCK();
! 307: return;
! 308: case CMMU_PFSR_SFAULT:
! 309: case CMMU_PFSR_PFAULT:
! 310: if ((pcb_onfault = p->p_addr->u_pcb.pcb_onfault) != 0)
! 311: p->p_addr->u_pcb.pcb_onfault = 0;
! 312: result = uvm_fault(map, va, VM_FAULT_INVALID, ftype);
! 313: p->p_addr->u_pcb.pcb_onfault = pcb_onfault;
! 314: if (result == 0) {
! 315: /*
! 316: * We could resolve the fault. Call
! 317: * data_access_emulation to drain the data
! 318: * unit pipe line and reset dmt0 so that trap
! 319: * won't get called again.
! 320: */
! 321: data_access_emulation((unsigned *)frame);
! 322: frame->tf_dpfsr = 0;
! 323: frame->tf_dmt0 = 0;
! 324: KERNEL_UNLOCK();
! 325: return;
! 326: }
! 327: break;
! 328: }
! 329: #ifdef TRAPDEBUG
! 330: printf("PBUS Fault %d (%s) va = 0x%x\n", pbus_type,
! 331: pbus_exception_type[pbus_type], va);
! 332: #endif
! 333: KERNEL_UNLOCK();
! 334: panictrap(frame->tf_vector, frame);
! 335: /* NOTREACHED */
! 336: case T_INSTFLT+T_USER:
! 337: /* User mode instruction access fault */
! 338: /* FALLTHROUGH */
! 339: case T_DATAFLT+T_USER:
! 340: user_fault:
! 341: if (type == T_INSTFLT + T_USER) {
! 342: pbus_type = CMMU_PFSR_FAULT(frame->tf_ipfsr);
! 343: #ifdef TRAPDEBUG
! 344: printf("User Instruction fault #%d (%s) v = 0x%x, frame 0x%x cpu %p\n",
! 345: pbus_type, pbus_exception_type[pbus_type],
! 346: fault_addr, frame, frame->tf_cpu);
! 347: #endif
! 348: } else {
! 349: fault_addr = frame->tf_dma0;
! 350: pbus_type = CMMU_PFSR_FAULT(frame->tf_dpfsr);
! 351: #ifdef TRAPDEBUG
! 352: printf("User Data access fault #%d (%s) v = 0x%x, frame 0x%x cpu %p\n",
! 353: pbus_type, pbus_exception_type[pbus_type],
! 354: fault_addr, frame, frame->tf_cpu);
! 355: #endif
! 356: }
! 357:
! 358: if (frame->tf_dmt0 & (DMT_WRITE | DMT_LOCKBAR)) {
! 359: ftype = VM_PROT_READ | VM_PROT_WRITE;
! 360: fault_code = VM_PROT_WRITE;
! 361: } else {
! 362: ftype = VM_PROT_READ;
! 363: fault_code = VM_PROT_READ;
! 364: }
! 365:
! 366: va = trunc_page((vaddr_t)fault_addr);
! 367:
! 368: KERNEL_PROC_LOCK(p);
! 369: vm = p->p_vmspace;
! 370: map = &vm->vm_map;
! 371: if ((pcb_onfault = p->p_addr->u_pcb.pcb_onfault) != 0)
! 372: p->p_addr->u_pcb.pcb_onfault = 0;
! 373:
! 374: /* Call uvm_fault() to resolve non-bus error faults */
! 375: switch (pbus_type) {
! 376: case CMMU_PFSR_SUCCESS:
! 377: result = 0;
! 378: break;
! 379: case CMMU_PFSR_BERROR:
! 380: result = EACCES;
! 381: break;
! 382: default:
! 383: result = uvm_fault(map, va, VM_FAULT_INVALID, ftype);
! 384: break;
! 385: }
! 386:
! 387: p->p_addr->u_pcb.pcb_onfault = pcb_onfault;
! 388:
! 389: if ((caddr_t)va >= vm->vm_maxsaddr) {
! 390: if (result == 0)
! 391: uvm_grow(p, va);
! 392: else if (result == EACCES)
! 393: result = EFAULT;
! 394: }
! 395: KERNEL_PROC_UNLOCK(p);
! 396:
! 397: /*
! 398: * This could be a fault caused in copyin*()
! 399: * while accessing user space.
! 400: */
! 401: if (result != 0 && pcb_onfault != 0) {
! 402: frame->tf_snip = pcb_onfault | NIP_V;
! 403: frame->tf_sfip = (pcb_onfault + 4) | FIP_V;
! 404: frame->tf_sxip = 0;
! 405: /*
! 406: * Continue as if the fault had been resolved, but
! 407: * do not try to complete the faulting access.
! 408: */
! 409: frame->tf_dmt0 |= DMT_SKIP;
! 410: result = 0;
! 411: }
! 412:
! 413: if (result == 0) {
! 414: if (type == T_DATAFLT+T_USER) {
! 415: /*
! 416: * We could resolve the fault. Call
! 417: * data_access_emulation to drain the data unit
! 418: * pipe line and reset dmt0 so that trap won't
! 419: * get called again.
! 420: */
! 421: data_access_emulation((unsigned *)frame);
! 422: frame->tf_dpfsr = 0;
! 423: frame->tf_dmt0 = 0;
! 424: } else {
! 425: /*
! 426: * back up SXIP, SNIP,
! 427: * clearing the Error bit
! 428: */
! 429: frame->tf_sfip = frame->tf_snip & ~FIP_E;
! 430: frame->tf_snip = frame->tf_sxip & ~NIP_E;
! 431: frame->tf_ipfsr = 0;
! 432: }
! 433: } else {
! 434: sig = result == EACCES ? SIGBUS : SIGSEGV;
! 435: fault_type = result == EACCES ?
! 436: BUS_ADRERR : SEGV_MAPERR;
! 437: }
! 438: break;
! 439: case T_MISALGNFLT+T_USER:
! 440: /* Fix any misaligned ld.d or st.d instructions */
! 441: sig = double_reg_fixup(frame);
! 442: fault_type = BUS_ADRALN;
! 443: break;
! 444: case T_PRIVINFLT+T_USER:
! 445: case T_ILLFLT+T_USER:
! 446: #ifndef DDB
! 447: case T_KDB_BREAK:
! 448: case T_KDB_ENTRY:
! 449: #endif
! 450: case T_KDB_BREAK+T_USER:
! 451: case T_KDB_ENTRY+T_USER:
! 452: case T_KDB_TRACE:
! 453: case T_KDB_TRACE+T_USER:
! 454: sig = SIGILL;
! 455: break;
! 456: case T_BNDFLT+T_USER:
! 457: sig = SIGFPE;
! 458: break;
! 459: case T_ZERODIV+T_USER:
! 460: sig = SIGFPE;
! 461: fault_type = FPE_INTDIV;
! 462: break;
! 463: case T_OVFFLT+T_USER:
! 464: sig = SIGFPE;
! 465: fault_type = FPE_INTOVF;
! 466: break;
! 467: case T_FPEPFLT+T_USER:
! 468: sig = SIGFPE;
! 469: break;
! 470: case T_SIGSYS+T_USER:
! 471: sig = SIGSYS;
! 472: break;
! 473: case T_STEPBPT+T_USER:
! 474: #ifdef PTRACE
! 475: /*
! 476: * This trap is used by the kernel to support single-step
! 477: * debugging (although any user could generate this trap
! 478: * which should probably be handled differently). When a
! 479: * process is continued by a debugger with the PT_STEP
! 480: * function of ptrace (single step), the kernel inserts
! 481: * one or two breakpoints in the user process so that only
! 482: * one instruction (or two in the case of a delayed branch)
! 483: * is executed. When this breakpoint is hit, we get the
! 484: * T_STEPBPT trap.
! 485: */
! 486: {
! 487: u_int instr;
! 488: vaddr_t pc = PC_REGS(&frame->tf_regs);
! 489:
! 490: /* read break instruction */
! 491: copyin((caddr_t)pc, &instr, sizeof(u_int));
! 492:
! 493: /* check and see if we got here by accident */
! 494: if ((p->p_md.md_bp0va != pc &&
! 495: p->p_md.md_bp1va != pc) ||
! 496: instr != SSBREAKPOINT) {
! 497: sig = SIGTRAP;
! 498: fault_type = TRAP_TRACE;
! 499: break;
! 500: }
! 501:
! 502: /* restore original instruction and clear breakpoint */
! 503: if (p->p_md.md_bp0va == pc) {
! 504: ss_put_value(p, pc, p->p_md.md_bp0save);
! 505: p->p_md.md_bp0va = 0;
! 506: }
! 507: if (p->p_md.md_bp1va == pc) {
! 508: ss_put_value(p, pc, p->p_md.md_bp1save);
! 509: p->p_md.md_bp1va = 0;
! 510: }
! 511:
! 512: #if 1
! 513: frame->tf_sfip = frame->tf_snip;
! 514: frame->tf_snip = pc | NIP_V;
! 515: #endif
! 516: sig = SIGTRAP;
! 517: fault_type = TRAP_BRKPT;
! 518: }
! 519: #else
! 520: sig = SIGTRAP;
! 521: fault_type = TRAP_TRACE;
! 522: #endif
! 523: break;
! 524:
! 525: case T_USERBPT+T_USER:
! 526: /*
! 527: * This trap is meant to be used by debuggers to implement
! 528: * breakpoint debugging. When we get this trap, we just
! 529: * return a signal which gets caught by the debugger.
! 530: */
! 531: frame->tf_sfip = frame->tf_snip;
! 532: frame->tf_snip = frame->tf_sxip;
! 533: sig = SIGTRAP;
! 534: fault_type = TRAP_BRKPT;
! 535: break;
! 536:
! 537: case T_ASTFLT+T_USER:
! 538: uvmexp.softs++;
! 539: p->p_md.md_astpending = 0;
! 540: if (p->p_flag & P_OWEUPC) {
! 541: KERNEL_PROC_LOCK(p);
! 542: ADDUPROF(p);
! 543: KERNEL_PROC_UNLOCK(p);
! 544: }
! 545: if (curcpu()->ci_want_resched)
! 546: preempt(NULL);
! 547: break;
! 548: }
! 549:
! 550: /*
! 551: * If trap from supervisor mode, just return
! 552: */
! 553: if (type < T_USER)
! 554: return;
! 555:
! 556: if (sig) {
! 557: sv.sival_int = fault_addr;
! 558: KERNEL_PROC_LOCK(p);
! 559: trapsignal(p, sig, fault_code, fault_type, sv);
! 560: KERNEL_PROC_UNLOCK(p);
! 561: /*
! 562: * don't want multiple faults - we are going to
! 563: * deliver signal.
! 564: */
! 565: frame->tf_dmt0 = 0;
! 566: frame->tf_ipfsr = frame->tf_dpfsr = 0;
! 567: }
! 568:
! 569: userret(p);
! 570: }
! 571: #endif /* M88100 */
! 572:
! 573: #ifdef M88110
! 574: void
! 575: m88110_trap(unsigned type, struct trapframe *frame)
! 576: {
! 577: struct proc *p;
! 578: struct vm_map *map;
! 579: vaddr_t va, pcb_onfault;
! 580: vm_prot_t ftype;
! 581: int fault_type;
! 582: u_long fault_code;
! 583: unsigned fault_addr;
! 584: struct vmspace *vm;
! 585: union sigval sv;
! 586: int result;
! 587: #ifdef DDB
! 588: int s;
! 589: u_int psr;
! 590: #endif
! 591: int sig = 0;
! 592: pt_entry_t *pte;
! 593:
! 594: extern struct vm_map *kernel_map;
! 595: extern pt_entry_t *pmap_pte(pmap_t, vaddr_t);
! 596:
! 597: uvmexp.traps++;
! 598: if ((p = curproc) == NULL)
! 599: p = &proc0;
! 600:
! 601: if (USERMODE(frame->tf_epsr)) {
! 602: type += T_USER;
! 603: p->p_md.md_tf = frame; /* for ptrace/signals */
! 604: }
! 605: fault_type = 0;
! 606: fault_code = 0;
! 607: fault_addr = frame->tf_exip & XIP_ADDR;
! 608:
! 609: switch (type) {
! 610: default:
! 611: panictrap(frame->tf_vector, frame);
! 612: break;
! 613: /*NOTREACHED*/
! 614:
! 615: case T_110_DRM+T_USER:
! 616: case T_110_DRM:
! 617: #ifdef DEBUG
! 618: printf("DMMU read miss: Hardware Table Searches should be enabled!\n");
! 619: #endif
! 620: panictrap(frame->tf_vector, frame);
! 621: break;
! 622: /*NOTREACHED*/
! 623: case T_110_DWM+T_USER:
! 624: case T_110_DWM:
! 625: #ifdef DEBUG
! 626: printf("DMMU write miss: Hardware Table Searches should be enabled!\n");
! 627: #endif
! 628: panictrap(frame->tf_vector, frame);
! 629: break;
! 630: /*NOTREACHED*/
! 631: case T_110_IAM+T_USER:
! 632: case T_110_IAM:
! 633: #ifdef DEBUG
! 634: printf("IMMU miss: Hardware Table Searches should be enabled!\n");
! 635: #endif
! 636: panictrap(frame->tf_vector, frame);
! 637: break;
! 638: /*NOTREACHED*/
! 639:
! 640: #ifdef DDB
! 641: case T_KDB_TRACE:
! 642: s = splhigh();
! 643: set_psr((psr = get_psr()) & ~PSR_IND);
! 644: ddb_break_trap(T_KDB_TRACE, (db_regs_t*)frame);
! 645: set_psr(psr);
! 646: splx(s);
! 647: return;
! 648: case T_KDB_BREAK:
! 649: s = splhigh();
! 650: set_psr((psr = get_psr()) & ~PSR_IND);
! 651: ddb_break_trap(T_KDB_BREAK, (db_regs_t*)frame);
! 652: set_psr(psr);
! 653: splx(s);
! 654: return;
! 655: case T_KDB_ENTRY:
! 656: s = splhigh();
! 657: set_psr((psr = get_psr()) & ~PSR_IND);
! 658: ddb_entry_trap(T_KDB_ENTRY, (db_regs_t*)frame);
! 659: set_psr(psr);
! 660: /* skip one instruction */
! 661: if (frame->tf_exip & 1)
! 662: frame->tf_exip = frame->tf_enip;
! 663: else
! 664: frame->tf_exip += 4;
! 665: splx(s);
! 666: return;
! 667: #if 0
! 668: case T_ILLFLT:
! 669: s = splhigh();
! 670: set_psr((psr = get_psr()) & ~PSR_IND);
! 671: ddb_error_trap(type == T_ILLFLT ? "unimplemented opcode" :
! 672: "error fault", (db_regs_t*)frame);
! 673: set_psr(psr);
! 674: splx(s);
! 675: return;
! 676: #endif /* 0 */
! 677: #endif /* DDB */
! 678: case T_ILLFLT:
! 679: printf("Unimplemented opcode!\n");
! 680: panictrap(frame->tf_vector, frame);
! 681: break;
! 682: case T_NON_MASK:
! 683: case T_NON_MASK+T_USER:
! 684: curcpu()->ci_intrdepth++;
! 685: md_interrupt_func(T_NON_MASK, frame);
! 686: curcpu()->ci_intrdepth--;
! 687: return;
! 688: case T_INT:
! 689: case T_INT+T_USER:
! 690: curcpu()->ci_intrdepth++;
! 691: md_interrupt_func(T_INT, frame);
! 692: curcpu()->ci_intrdepth--;
! 693: return;
! 694: case T_MISALGNFLT:
! 695: printf("kernel mode misaligned access exception @ 0x%08x\n",
! 696: frame->tf_exip);
! 697: panictrap(frame->tf_vector, frame);
! 698: break;
! 699: /*NOTREACHED*/
! 700:
! 701: case T_INSTFLT:
! 702: /* kernel mode instruction access fault.
! 703: * Should never, never happen for a non-paged kernel.
! 704: */
! 705: #ifdef TRAPDEBUG
! 706: printf("Kernel Instruction fault exip %x isr %x ilar %x\n",
! 707: frame->tf_exip, frame->tf_isr, frame->tf_ilar);
! 708: #endif
! 709: panictrap(frame->tf_vector, frame);
! 710: break;
! 711: /*NOTREACHED*/
! 712:
! 713: case T_DATAFLT:
! 714: /* kernel mode data fault */
! 715:
! 716: /* data fault on the user address? */
! 717: if ((frame->tf_dsr & CMMU_DSR_SU) == 0) {
! 718: type = T_DATAFLT + T_USER;
! 719: goto m88110_user_fault;
! 720: }
! 721:
! 722: #ifdef TRAPDEBUG
! 723: printf("Kernel Data access fault exip %x dsr %x dlar %x\n",
! 724: frame->tf_exip, frame->tf_dsr, frame->tf_dlar);
! 725: #endif
! 726:
! 727: fault_addr = frame->tf_dlar;
! 728: if (frame->tf_dsr & CMMU_DSR_RW) {
! 729: ftype = VM_PROT_READ;
! 730: fault_code = VM_PROT_READ;
! 731: } else {
! 732: ftype = VM_PROT_READ|VM_PROT_WRITE;
! 733: fault_code = VM_PROT_WRITE;
! 734: }
! 735:
! 736: va = trunc_page((vaddr_t)fault_addr);
! 737: if (va == 0) {
! 738: panic("trap: bad kernel access at %x", fault_addr);
! 739: }
! 740:
! 741: KERNEL_LOCK();
! 742: vm = p->p_vmspace;
! 743: map = kernel_map;
! 744:
! 745: if (frame->tf_dsr & (CMMU_DSR_SI | CMMU_DSR_PI)) {
! 746: frame->tf_dsr &= ~CMMU_DSR_WE; /* undefined */
! 747: /*
! 748: * On a segment or a page fault, call uvm_fault() to
! 749: * resolve the fault.
! 750: */
! 751: if ((pcb_onfault = p->p_addr->u_pcb.pcb_onfault) != 0)
! 752: p->p_addr->u_pcb.pcb_onfault = 0;
! 753: result = uvm_fault(map, va, VM_FAULT_INVALID, ftype);
! 754: p->p_addr->u_pcb.pcb_onfault = pcb_onfault;
! 755: if (result == 0) {
! 756: KERNEL_UNLOCK();
! 757: return;
! 758: }
! 759: }
! 760: if (frame->tf_dsr & CMMU_DSR_WE) { /* write fault */
! 761: /*
! 762: * This could be a write protection fault or an
! 763: * exception to set the used and modified bits
! 764: * in the pte. Basically, if we got a write error,
! 765: * then we already have a pte entry that faulted
! 766: * in from a previous seg fault or page fault.
! 767: * Get the pte and check the status of the
! 768: * modified and valid bits to determine if this
! 769: * indeed a real write fault. XXX smurph
! 770: */
! 771: pte = pmap_pte(map->pmap, va);
! 772: #ifdef DEBUG
! 773: if (pte == NULL) {
! 774: KERNEL_UNLOCK();
! 775: panic("NULL pte on write fault??");
! 776: }
! 777: #endif
! 778: if (!(*pte & PG_M) && !(*pte & PG_RO)) {
! 779: /* Set modified bit and try the write again. */
! 780: #ifdef TRAPDEBUG
! 781: printf("Corrected kernel write fault, map %x pte %x\n",
! 782: map->pmap, *pte);
! 783: #endif
! 784: *pte |= PG_M;
! 785: KERNEL_UNLOCK();
! 786: return;
! 787: #if 1 /* shouldn't happen */
! 788: } else {
! 789: /* must be a real wp fault */
! 790: #ifdef TRAPDEBUG
! 791: printf("Uncorrected kernel write fault, map %x pte %x\n",
! 792: map->pmap, *pte);
! 793: #endif
! 794: if ((pcb_onfault = p->p_addr->u_pcb.pcb_onfault) != 0)
! 795: p->p_addr->u_pcb.pcb_onfault = 0;
! 796: result = uvm_fault(map, va, VM_FAULT_INVALID, ftype);
! 797: p->p_addr->u_pcb.pcb_onfault = pcb_onfault;
! 798: if (result == 0) {
! 799: KERNEL_UNLOCK();
! 800: return;
! 801: }
! 802: #endif
! 803: }
! 804: }
! 805: KERNEL_UNLOCK();
! 806: panictrap(frame->tf_vector, frame);
! 807: /* NOTREACHED */
! 808: case T_INSTFLT+T_USER:
! 809: /* User mode instruction access fault */
! 810: /* FALLTHROUGH */
! 811: case T_DATAFLT+T_USER:
! 812: m88110_user_fault:
! 813: if (type == T_INSTFLT+T_USER) {
! 814: ftype = VM_PROT_READ;
! 815: fault_code = VM_PROT_READ;
! 816: #ifdef TRAPDEBUG
! 817: printf("User Instruction fault exip %x isr %x ilar %x\n",
! 818: frame->tf_exip, frame->tf_isr, frame->tf_ilar);
! 819: #endif
! 820: } else {
! 821: fault_addr = frame->tf_dlar;
! 822: if (frame->tf_dsr & CMMU_DSR_RW) {
! 823: ftype = VM_PROT_READ;
! 824: fault_code = VM_PROT_READ;
! 825: } else {
! 826: ftype = VM_PROT_READ|VM_PROT_WRITE;
! 827: fault_code = VM_PROT_WRITE;
! 828: }
! 829: #ifdef TRAPDEBUG
! 830: printf("User Data access fault exip %x dsr %x dlar %x\n",
! 831: frame->tf_exip, frame->tf_dsr, frame->tf_dlar);
! 832: #endif
! 833: }
! 834:
! 835: va = trunc_page((vaddr_t)fault_addr);
! 836:
! 837: KERNEL_PROC_LOCK(p);
! 838: vm = p->p_vmspace;
! 839: map = &vm->vm_map;
! 840: if ((pcb_onfault = p->p_addr->u_pcb.pcb_onfault) != 0)
! 841: p->p_addr->u_pcb.pcb_onfault = 0;
! 842:
! 843: /*
! 844: * Call uvm_fault() to resolve non-bus error faults
! 845: * whenever possible.
! 846: */
! 847: if (type == T_DATAFLT+T_USER) {
! 848: /* data faults */
! 849: if (frame->tf_dsr & CMMU_DSR_BE) {
! 850: /* bus error */
! 851: result = EACCES;
! 852: } else
! 853: if (frame->tf_dsr & (CMMU_DSR_SI | CMMU_DSR_PI)) {
! 854: /* segment or page fault */
! 855: result = uvm_fault(map, va, VM_FAULT_INVALID, ftype);
! 856: p->p_addr->u_pcb.pcb_onfault = pcb_onfault;
! 857: } else
! 858: if (frame->tf_dsr & (CMMU_DSR_CP | CMMU_DSR_WA)) {
! 859: /* copyback or write allocate error */
! 860: result = EACCES;
! 861: } else
! 862: if (frame->tf_dsr & CMMU_DSR_WE) {
! 863: /* write fault */
! 864: /* This could be a write protection fault or an
! 865: * exception to set the used and modified bits
! 866: * in the pte. Basically, if we got a write
! 867: * error, then we already have a pte entry that
! 868: * faulted in from a previous seg fault or page
! 869: * fault.
! 870: * Get the pte and check the status of the
! 871: * modified and valid bits to determine if this
! 872: * indeed a real write fault. XXX smurph
! 873: */
! 874: pte = pmap_pte(vm_map_pmap(map), va);
! 875: #ifdef DEBUG
! 876: if (pte == NULL) {
! 877: KERNEL_PROC_UNLOCK(p);
! 878: panic("NULL pte on write fault??");
! 879: }
! 880: #endif
! 881: if (!(*pte & PG_M) && !(*pte & PG_RO)) {
! 882: /*
! 883: * Set modified bit and try the
! 884: * write again.
! 885: */
! 886: #ifdef TRAPDEBUG
! 887: printf("Corrected userland write fault, map %x pte %x\n",
! 888: map->pmap, *pte);
! 889: #endif
! 890: *pte |= PG_M;
! 891: /*
! 892: * invalidate ATCs to force
! 893: * table search
! 894: */
! 895: set_dcmd(CMMU_DCMD_INV_UATC);
! 896: KERNEL_PROC_UNLOCK(p);
! 897: return;
! 898: } else {
! 899: /* must be a real wp fault */
! 900: #ifdef TRAPDEBUG
! 901: printf("Uncorrected userland write fault, map %x pte %x\n",
! 902: map->pmap, *pte);
! 903: #endif
! 904: result = uvm_fault(map, va, VM_FAULT_INVALID, ftype);
! 905: p->p_addr->u_pcb.pcb_onfault = pcb_onfault;
! 906: }
! 907: } else {
! 908: #ifdef TRAPDEBUG
! 909: printf("Unexpected Data access fault dsr %x\n",
! 910: frame->tf_dsr);
! 911: #endif
! 912: KERNEL_PROC_UNLOCK(p);
! 913: panictrap(frame->tf_vector, frame);
! 914: }
! 915: } else {
! 916: /* instruction faults */
! 917: if (frame->tf_isr &
! 918: (CMMU_ISR_BE | CMMU_ISR_SP | CMMU_ISR_TBE)) {
! 919: /* bus error, supervisor protection */
! 920: result = EACCES;
! 921: } else
! 922: if (frame->tf_isr & (CMMU_ISR_SI | CMMU_ISR_PI)) {
! 923: /* segment or page fault */
! 924: result = uvm_fault(map, va, VM_FAULT_INVALID, ftype);
! 925: p->p_addr->u_pcb.pcb_onfault = pcb_onfault;
! 926: } else {
! 927: #ifdef TRAPDEBUG
! 928: printf("Unexpected Instruction fault isr %x\n",
! 929: frame->tf_isr);
! 930: #endif
! 931: KERNEL_PROC_UNLOCK(p);
! 932: panictrap(frame->tf_vector, frame);
! 933: }
! 934: }
! 935:
! 936: if ((caddr_t)va >= vm->vm_maxsaddr) {
! 937: if (result == 0)
! 938: uvm_grow(p, va);
! 939: else if (result == EACCES)
! 940: result = EFAULT;
! 941: }
! 942: KERNEL_PROC_UNLOCK(p);
! 943:
! 944: /*
! 945: * This could be a fault caused in copyin*()
! 946: * while accessing user space.
! 947: */
! 948: if (result != 0 && pcb_onfault != 0) {
! 949: frame->tf_exip = pcb_onfault;
! 950: /*
! 951: * Continue as if the fault had been resolved.
! 952: */
! 953: result = 0;
! 954: }
! 955:
! 956: if (result != 0) {
! 957: sig = result == EACCES ? SIGBUS : SIGSEGV;
! 958: fault_type = result == EACCES ?
! 959: BUS_ADRERR : SEGV_MAPERR;
! 960: }
! 961: break;
! 962: case T_MISALGNFLT+T_USER:
! 963: /* Fix any misaligned ld.d or st.d instructions */
! 964: sig = double_reg_fixup(frame);
! 965: fault_type = BUS_ADRALN;
! 966: break;
! 967: case T_PRIVINFLT+T_USER:
! 968: case T_ILLFLT+T_USER:
! 969: #ifndef DDB
! 970: case T_KDB_BREAK:
! 971: case T_KDB_ENTRY:
! 972: case T_KDB_TRACE:
! 973: #endif
! 974: case T_KDB_BREAK+T_USER:
! 975: case T_KDB_ENTRY+T_USER:
! 976: case T_KDB_TRACE+T_USER:
! 977: sig = SIGILL;
! 978: break;
! 979: case T_BNDFLT+T_USER:
! 980: sig = SIGFPE;
! 981: break;
! 982: case T_ZERODIV+T_USER:
! 983: sig = SIGFPE;
! 984: fault_type = FPE_INTDIV;
! 985: break;
! 986: case T_OVFFLT+T_USER:
! 987: sig = SIGFPE;
! 988: fault_type = FPE_INTOVF;
! 989: break;
! 990: case T_FPEPFLT+T_USER:
! 991: sig = SIGFPE;
! 992: break;
! 993: case T_SIGSYS+T_USER:
! 994: sig = SIGSYS;
! 995: break;
! 996: case T_STEPBPT+T_USER:
! 997: #ifdef PTRACE
! 998: /*
! 999: * This trap is used by the kernel to support single-step
! 1000: * debugging (although any user could generate this trap
! 1001: * which should probably be handled differently). When a
! 1002: * process is continued by a debugger with the PT_STEP
! 1003: * function of ptrace (single step), the kernel inserts
! 1004: * one or two breakpoints in the user process so that only
! 1005: * one instruction (or two in the case of a delayed branch)
! 1006: * is executed. When this breakpoint is hit, we get the
! 1007: * T_STEPBPT trap.
! 1008: */
! 1009: {
! 1010: u_int instr;
! 1011: vaddr_t pc = PC_REGS(&frame->tf_regs);
! 1012:
! 1013: /* read break instruction */
! 1014: copyin((caddr_t)pc, &instr, sizeof(u_int));
! 1015:
! 1016: /* check and see if we got here by accident */
! 1017: if ((p->p_md.md_bp0va != pc &&
! 1018: p->p_md.md_bp1va != pc) ||
! 1019: instr != SSBREAKPOINT) {
! 1020: sig = SIGTRAP;
! 1021: fault_type = TRAP_TRACE;
! 1022: break;
! 1023: }
! 1024:
! 1025: /* restore original instruction and clear breakpoint */
! 1026: if (p->p_md.md_bp0va == pc) {
! 1027: ss_put_value(p, pc, p->p_md.md_bp0save);
! 1028: p->p_md.md_bp0va = 0;
! 1029: }
! 1030: if (p->p_md.md_bp1va == pc) {
! 1031: ss_put_value(p, pc, p->p_md.md_bp1save);
! 1032: p->p_md.md_bp1va = 0;
! 1033: }
! 1034:
! 1035: sig = SIGTRAP;
! 1036: fault_type = TRAP_BRKPT;
! 1037: }
! 1038: #else
! 1039: sig = SIGTRAP;
! 1040: fault_type = TRAP_TRACE;
! 1041: #endif
! 1042: break;
! 1043: case T_USERBPT+T_USER:
! 1044: /*
! 1045: * This trap is meant to be used by debuggers to implement
! 1046: * breakpoint debugging. When we get this trap, we just
! 1047: * return a signal which gets caught by the debugger.
! 1048: */
! 1049: sig = SIGTRAP;
! 1050: fault_type = TRAP_BRKPT;
! 1051: break;
! 1052:
! 1053: case T_ASTFLT+T_USER:
! 1054: uvmexp.softs++;
! 1055: p->p_md.md_astpending = 0;
! 1056: if (p->p_flag & P_OWEUPC) {
! 1057: KERNEL_PROC_LOCK(p);
! 1058: ADDUPROF(p);
! 1059: KERNEL_PROC_UNLOCK(p);
! 1060: }
! 1061: if (curcpu()->ci_want_resched)
! 1062: preempt(NULL);
! 1063: break;
! 1064: }
! 1065:
! 1066: /*
! 1067: * If trap from supervisor mode, just return
! 1068: */
! 1069: if (type < T_USER)
! 1070: return;
! 1071:
! 1072: if (sig) {
! 1073: sv.sival_int = fault_addr;
! 1074: KERNEL_PROC_LOCK(p);
! 1075: trapsignal(p, sig, fault_code, fault_type, sv);
! 1076: KERNEL_PROC_UNLOCK(p);
! 1077: }
! 1078:
! 1079: userret(p);
! 1080: }
! 1081: #endif /* M88110 */
! 1082:
! 1083: __dead void
! 1084: error_fatal(struct trapframe *frame)
! 1085: {
! 1086: if (frame->tf_vector == 0)
! 1087: printf("\nCPU %d Reset Exception\n", cpu_number());
! 1088: else
! 1089: printf("\nCPU %d Error Exception\n", cpu_number());
! 1090:
! 1091: #ifdef DDB
! 1092: regdump((struct trapframe*)frame);
! 1093: #endif
! 1094: panic("unrecoverable exception %d", frame->tf_vector);
! 1095: }
! 1096:
! 1097: #ifdef M88100
! 1098: void
! 1099: m88100_syscall(register_t code, struct trapframe *tf)
! 1100: {
! 1101: int i, nsys, nap;
! 1102: struct sysent *callp;
! 1103: struct proc *p;
! 1104: int error;
! 1105: register_t args[8], rval[2], *ap;
! 1106:
! 1107: uvmexp.syscalls++;
! 1108:
! 1109: p = curproc;
! 1110:
! 1111: callp = p->p_emul->e_sysent;
! 1112: nsys = p->p_emul->e_nsysent;
! 1113:
! 1114: p->p_md.md_tf = tf;
! 1115:
! 1116: /*
! 1117: * For 88k, all the arguments are passed in the registers (r2-r9),
! 1118: * and further arguments (if any) on stack.
! 1119: * For syscall (and __syscall), r2 (and r3) has the actual code.
! 1120: * __syscall takes a quad syscall number, so that other
! 1121: * arguments are at their natural alignments.
! 1122: */
! 1123: ap = &tf->tf_r[2];
! 1124: nap = 8; /* r2-r9 */
! 1125:
! 1126: switch (code) {
! 1127: case SYS_syscall:
! 1128: code = *ap++;
! 1129: nap--;
! 1130: break;
! 1131: case SYS___syscall:
! 1132: if (callp != sysent)
! 1133: break;
! 1134: code = ap[_QUAD_LOWWORD];
! 1135: ap += 2;
! 1136: nap -= 2;
! 1137: break;
! 1138: }
! 1139:
! 1140: if (code < 0 || code >= nsys)
! 1141: callp += p->p_emul->e_nosys;
! 1142: else
! 1143: callp += code;
! 1144:
! 1145: i = callp->sy_argsize / sizeof(register_t);
! 1146: if (i > sizeof(args) / sizeof(register_t))
! 1147: panic("syscall nargs");
! 1148: if (i > nap) {
! 1149: bcopy((caddr_t)ap, (caddr_t)args, nap * sizeof(register_t));
! 1150: error = copyin((caddr_t)tf->tf_r[31], (caddr_t)(args + nap),
! 1151: (i - nap) * sizeof(register_t));
! 1152: } else {
! 1153: bcopy((caddr_t)ap, (caddr_t)args, i * sizeof(register_t));
! 1154: error = 0;
! 1155: }
! 1156:
! 1157: if (error != 0)
! 1158: goto bad;
! 1159: KERNEL_PROC_LOCK(p);
! 1160: #ifdef SYSCALL_DEBUG
! 1161: scdebug_call(p, code, args);
! 1162: #endif
! 1163: #ifdef KTRACE
! 1164: if (KTRPOINT(p, KTR_SYSCALL))
! 1165: ktrsyscall(p, code, callp->sy_argsize, args);
! 1166: #endif
! 1167: rval[0] = 0;
! 1168: rval[1] = tf->tf_r[3];
! 1169: #if NSYSTRACE > 0
! 1170: if (ISSET(p->p_flag, P_SYSTRACE))
! 1171: error = systrace_redirect(code, p, args, rval);
! 1172: else
! 1173: #endif
! 1174: error = (*callp->sy_call)(p, args, rval);
! 1175: /*
! 1176: * system call will look like:
! 1177: * or r13, r0, <code>
! 1178: * tb0 0, r0, <128> <- sxip
! 1179: * br err <- snip
! 1180: * jmp r1 <- sfip
! 1181: * err: or.u r3, r0, hi16(errno)
! 1182: * st r2, r3, lo16(errno)
! 1183: * subu r2, r0, 1
! 1184: * jmp r1
! 1185: *
! 1186: * So, when we take syscall trap, sxip/snip/sfip will be as
! 1187: * shown above.
! 1188: * Given this,
! 1189: * 1. If the system call returned 0, need to skip nip.
! 1190: * nip = fip, fip += 4
! 1191: * (doesn't matter what fip + 4 will be but we will never
! 1192: * execute this since jmp r1 at nip will change the execution flow.)
! 1193: * 2. If the system call returned an errno > 0, plug the value
! 1194: * in r2, and leave nip and fip unchanged. This will have us
! 1195: * executing "br err" on return to user space.
! 1196: * 3. If the system call code returned ERESTART,
! 1197: * we need to rexecute the trap instruction. Back up the pipe
! 1198: * line.
! 1199: * fip = nip, nip = xip
! 1200: * 4. If the system call returned EJUSTRETURN, don't need to adjust
! 1201: * any pointers.
! 1202: */
! 1203:
! 1204: KERNEL_PROC_UNLOCK(p);
! 1205: switch (error) {
! 1206: case 0:
! 1207: tf->tf_r[2] = rval[0];
! 1208: tf->tf_r[3] = rval[1];
! 1209: tf->tf_epsr &= ~PSR_C;
! 1210: tf->tf_snip = tf->tf_sfip & ~NIP_E;
! 1211: tf->tf_sfip = tf->tf_snip + 4;
! 1212: break;
! 1213: case ERESTART:
! 1214: tf->tf_epsr &= ~PSR_C;
! 1215: tf->tf_sfip = tf->tf_snip & ~FIP_E;
! 1216: tf->tf_snip = tf->tf_sxip & ~NIP_E;
! 1217: break;
! 1218: case EJUSTRETURN:
! 1219: tf->tf_epsr &= ~PSR_C;
! 1220: break;
! 1221: default:
! 1222: bad:
! 1223: if (p->p_emul->e_errno)
! 1224: error = p->p_emul->e_errno[error];
! 1225: tf->tf_r[2] = error;
! 1226: tf->tf_epsr |= PSR_C; /* fail */
! 1227: tf->tf_snip = tf->tf_snip & ~NIP_E;
! 1228: tf->tf_sfip = tf->tf_sfip & ~FIP_E;
! 1229: break;
! 1230: }
! 1231: #ifdef SYSCALL_DEBUG
! 1232: KERNEL_PROC_LOCK(p);
! 1233: scdebug_ret(p, code, error, rval);
! 1234: KERNEL_PROC_UNLOCK(p);
! 1235: #endif
! 1236: userret(p);
! 1237: #ifdef KTRACE
! 1238: if (KTRPOINT(p, KTR_SYSRET)) {
! 1239: KERNEL_PROC_LOCK(p);
! 1240: ktrsysret(p, code, error, rval[0]);
! 1241: KERNEL_PROC_UNLOCK(p);
! 1242: }
! 1243: #endif
! 1244: }
! 1245: #endif /* M88100 */
! 1246:
! 1247: #ifdef M88110
! 1248: /* Instruction pointers operate differently on mc88110 */
! 1249: void
! 1250: m88110_syscall(register_t code, struct trapframe *tf)
! 1251: {
! 1252: int i, nsys, nap;
! 1253: struct sysent *callp;
! 1254: struct proc *p;
! 1255: int error;
! 1256: register_t args[8], rval[2], *ap;
! 1257:
! 1258: uvmexp.syscalls++;
! 1259:
! 1260: p = curproc;
! 1261:
! 1262: callp = p->p_emul->e_sysent;
! 1263: nsys = p->p_emul->e_nsysent;
! 1264:
! 1265: p->p_md.md_tf = tf;
! 1266:
! 1267: /*
! 1268: * For 88k, all the arguments are passed in the registers (r2-r9),
! 1269: * and further arguments (if any) on stack.
! 1270: * For syscall (and __syscall), r2 (and r3) has the actual code.
! 1271: * __syscall takes a quad syscall number, so that other
! 1272: * arguments are at their natural alignments.
! 1273: */
! 1274: ap = &tf->tf_r[2];
! 1275: nap = 8; /* r2-r9 */
! 1276:
! 1277: switch (code) {
! 1278: case SYS_syscall:
! 1279: code = *ap++;
! 1280: nap--;
! 1281: break;
! 1282: case SYS___syscall:
! 1283: if (callp != sysent)
! 1284: break;
! 1285: code = ap[_QUAD_LOWWORD];
! 1286: ap += 2;
! 1287: nap -= 2;
! 1288: break;
! 1289: }
! 1290:
! 1291: if (code < 0 || code >= nsys)
! 1292: callp += p->p_emul->e_nosys;
! 1293: else
! 1294: callp += code;
! 1295:
! 1296: i = callp->sy_argsize / sizeof(register_t);
! 1297: if (i > sizeof(args) > sizeof(register_t))
! 1298: panic("syscall nargs");
! 1299: if (i > nap) {
! 1300: bcopy((caddr_t)ap, (caddr_t)args, nap * sizeof(register_t));
! 1301: error = copyin((caddr_t)tf->tf_r[31], (caddr_t)(args + nap),
! 1302: (i - nap) * sizeof(register_t));
! 1303: } else {
! 1304: bcopy((caddr_t)ap, (caddr_t)args, i * sizeof(register_t));
! 1305: error = 0;
! 1306: }
! 1307:
! 1308: if (error != 0)
! 1309: goto bad;
! 1310: KERNEL_PROC_LOCK(p);
! 1311: #ifdef SYSCALL_DEBUG
! 1312: scdebug_call(p, code, args);
! 1313: #endif
! 1314: #ifdef KTRACE
! 1315: if (KTRPOINT(p, KTR_SYSCALL))
! 1316: ktrsyscall(p, code, callp->sy_argsize, args);
! 1317: #endif
! 1318: rval[0] = 0;
! 1319: rval[1] = tf->tf_r[3];
! 1320: #if NSYSTRACE > 0
! 1321: if (ISSET(p->p_flag, P_SYSTRACE))
! 1322: error = systrace_redirect(code, p, args, rval);
! 1323: else
! 1324: #endif
! 1325: error = (*callp->sy_call)(p, args, rval);
! 1326: /*
! 1327: * system call will look like:
! 1328: * or r13, r0, <code>
! 1329: * tb0 0, r0, <128> <- exip
! 1330: * br err <- enip
! 1331: * jmp r1
! 1332: * err: or.u r3, r0, hi16(errno)
! 1333: * st r2, r3, lo16(errno)
! 1334: * subu r2, r0, 1
! 1335: * jmp r1
! 1336: *
! 1337: * So, when we take syscall trap, exip/enip will be as
! 1338: * shown above.
! 1339: * Given this,
! 1340: * 1. If the system call returned 0, need to jmp r1.
! 1341: * exip += 8
! 1342: * 2. If the system call returned an errno > 0, increment
! 1343: * exip += 4 and plug the value in r2. This will have us
! 1344: * executing "br err" on return to user space.
! 1345: * 3. If the system call code returned ERESTART,
! 1346: * we need to rexecute the trap instruction. leave exip as is.
! 1347: * 4. If the system call returned EJUSTRETURN, just return.
! 1348: * exip += 4
! 1349: */
! 1350:
! 1351: KERNEL_PROC_UNLOCK(p);
! 1352: switch (error) {
! 1353: case 0:
! 1354: tf->tf_r[2] = rval[0];
! 1355: tf->tf_r[3] = rval[1];
! 1356: tf->tf_epsr &= ~PSR_C;
! 1357: /* skip two instructions */
! 1358: if (tf->tf_exip & 1)
! 1359: tf->tf_exip = tf->tf_enip + 4;
! 1360: else
! 1361: tf->tf_exip += 4 + 4;
! 1362: break;
! 1363: case ERESTART:
! 1364: /*
! 1365: * Reexecute the trap.
! 1366: * exip is already at the trap instruction, so
! 1367: * there is nothing to do.
! 1368: */
! 1369: tf->tf_epsr &= ~PSR_C;
! 1370: break;
! 1371: case EJUSTRETURN:
! 1372: tf->tf_epsr &= ~PSR_C;
! 1373: /* skip one instruction */
! 1374: if (tf->tf_exip & 1)
! 1375: tf->tf_exip = tf->tf_enip;
! 1376: else
! 1377: tf->tf_exip += 4;
! 1378: break;
! 1379: default:
! 1380: bad:
! 1381: if (p->p_emul->e_errno)
! 1382: error = p->p_emul->e_errno[error];
! 1383: tf->tf_r[2] = error;
! 1384: tf->tf_epsr |= PSR_C; /* fail */
! 1385: /* skip one instruction */
! 1386: if (tf->tf_exip & 1)
! 1387: tf->tf_exip = tf->tf_enip;
! 1388: else
! 1389: tf->tf_exip += 4;
! 1390: break;
! 1391: }
! 1392:
! 1393: #ifdef SYSCALL_DEBUG
! 1394: KERNEL_PROC_LOCK(p);
! 1395: scdebug_ret(p, code, error, rval);
! 1396: KERNEL_PROC_UNLOCK(p);
! 1397: #endif
! 1398: userret(p);
! 1399: #ifdef KTRACE
! 1400: if (KTRPOINT(p, KTR_SYSRET)) {
! 1401: KERNEL_PROC_LOCK(p);
! 1402: ktrsysret(p, code, error, rval[0]);
! 1403: KERNEL_PROC_UNLOCK(p);
! 1404: }
! 1405: #endif
! 1406: }
! 1407: #endif /* M88110 */
! 1408:
! 1409: /*
! 1410: * Set up return-value registers as fork() libc stub expects,
! 1411: * and do normal return-to-user-mode stuff.
! 1412: */
! 1413: void
! 1414: child_return(arg)
! 1415: void *arg;
! 1416: {
! 1417: struct proc *p = arg;
! 1418: struct trapframe *tf;
! 1419:
! 1420: tf = (struct trapframe *)USER_REGS(p);
! 1421: tf->tf_r[2] = 0;
! 1422: tf->tf_r[3] = 0;
! 1423: tf->tf_epsr &= ~PSR_C;
! 1424: /* skip br instruction as in syscall() */
! 1425: #ifdef M88100
! 1426: if (CPU_IS88100) {
! 1427: tf->tf_snip = tf->tf_sfip & XIP_ADDR;
! 1428: tf->tf_sfip = tf->tf_snip + 4;
! 1429: }
! 1430: #endif
! 1431: #ifdef M88110
! 1432: if (CPU_IS88110) {
! 1433: /* skip two instructions */
! 1434: if (tf->tf_exip & 1)
! 1435: tf->tf_exip = tf->tf_enip + 4;
! 1436: else
! 1437: tf->tf_exip += 4 + 4;
! 1438: }
! 1439: #endif
! 1440:
! 1441: KERNEL_PROC_UNLOCK(p);
! 1442: userret(p);
! 1443:
! 1444: #ifdef KTRACE
! 1445: if (KTRPOINT(p, KTR_SYSRET)) {
! 1446: KERNEL_PROC_LOCK(p);
! 1447: ktrsysret(p,
! 1448: (p->p_flag & P_PPWAIT) ? SYS_vfork : SYS_fork, 0, 0);
! 1449: KERNEL_PROC_UNLOCK(p);
! 1450: }
! 1451: #endif
! 1452: }
! 1453:
! 1454: #ifdef PTRACE
! 1455:
! 1456: /*
! 1457: * User Single Step Debugging Support
! 1458: */
! 1459:
! 1460: #include <sys/ptrace.h>
! 1461:
! 1462: vaddr_t ss_branch_taken(u_int, vaddr_t, struct reg *);
! 1463: int ss_get_value(struct proc *, vaddr_t, u_int *);
! 1464: int ss_inst_branch_or_call(u_int);
! 1465: int ss_put_breakpoint(struct proc *, vaddr_t, vaddr_t *, u_int *);
! 1466:
! 1467: #define SYSCALL_INSTR 0xf000d080 /* tb0 0,r0,128 */
! 1468:
! 1469: int
! 1470: ss_get_value(struct proc *p, vaddr_t addr, u_int *value)
! 1471: {
! 1472: struct uio uio;
! 1473: struct iovec iov;
! 1474:
! 1475: iov.iov_base = (caddr_t)value;
! 1476: iov.iov_len = sizeof(u_int);
! 1477: uio.uio_iov = &iov;
! 1478: uio.uio_iovcnt = 1;
! 1479: uio.uio_offset = (off_t)addr;
! 1480: uio.uio_resid = sizeof(u_int);
! 1481: uio.uio_segflg = UIO_SYSSPACE;
! 1482: uio.uio_rw = UIO_READ;
! 1483: uio.uio_procp = curproc;
! 1484: return (process_domem(curproc, p, &uio, PT_READ_I));
! 1485: }
! 1486:
! 1487: int
! 1488: ss_put_value(struct proc *p, vaddr_t addr, u_int value)
! 1489: {
! 1490: struct uio uio;
! 1491: struct iovec iov;
! 1492:
! 1493: iov.iov_base = (caddr_t)&value;
! 1494: iov.iov_len = sizeof(u_int);
! 1495: uio.uio_iov = &iov;
! 1496: uio.uio_iovcnt = 1;
! 1497: uio.uio_offset = (off_t)addr;
! 1498: uio.uio_resid = sizeof(u_int);
! 1499: uio.uio_segflg = UIO_SYSSPACE;
! 1500: uio.uio_rw = UIO_WRITE;
! 1501: uio.uio_procp = curproc;
! 1502: return (process_domem(curproc, p, &uio, PT_WRITE_I));
! 1503: }
! 1504:
! 1505: /*
! 1506: * ss_branch_taken(instruction, pc, regs)
! 1507: *
! 1508: * instruction will be a control flow instruction location at address pc.
! 1509: * Branch taken is supposed to return the address to which the instruction
! 1510: * would jump if the branch is taken.
! 1511: *
! 1512: * This is different from branch_taken() in ddb, as we also need to process
! 1513: * system calls.
! 1514: */
! 1515: vaddr_t
! 1516: ss_branch_taken(u_int inst, vaddr_t pc, struct reg *regs)
! 1517: {
! 1518: u_int regno;
! 1519:
! 1520: /*
! 1521: * Quick check of the instruction. Note that we know we are only
! 1522: * invoked if ss_inst_branch_or_call() returns TRUE, so we do not
! 1523: * need to repeat the jpm, jsr and syscall stricter checks here.
! 1524: */
! 1525: switch (inst >> (32 - 5)) {
! 1526: case 0x18: /* br */
! 1527: case 0x19: /* bsr */
! 1528: /* signed 26 bit pc relative displacement, shift left 2 bits */
! 1529: inst = (inst & 0x03ffffff) << 2;
! 1530: /* check if sign extension is needed */
! 1531: if (inst & 0x08000000)
! 1532: inst |= 0xf0000000;
! 1533: return (pc + inst);
! 1534:
! 1535: case 0x1a: /* bb0 */
! 1536: case 0x1b: /* bb1 */
! 1537: case 0x1d: /* bcnd */
! 1538: /* signed 16 bit pc relative displacement, shift left 2 bits */
! 1539: inst = (inst & 0x0000ffff) << 2;
! 1540: /* check if sign extension is needed */
! 1541: if (inst & 0x00020000)
! 1542: inst |= 0xfffc0000;
! 1543: return (pc + inst);
! 1544:
! 1545: case 0x1e: /* jmp or jsr */
! 1546: regno = inst & 0x1f; /* get the register value */
! 1547: return (regno == 0 ? 0 : regs->r[regno]);
! 1548:
! 1549: default: /* system call */
! 1550: /*
! 1551: * The regular (pc + 4) breakpoint will match the error
! 1552: * return. Successfull system calls return at (pc + 8),
! 1553: * so we'll set up a branch breakpoint there.
! 1554: */
! 1555: return (pc + 8);
! 1556: }
! 1557: }
! 1558:
! 1559: int
! 1560: ss_inst_branch_or_call(u_int ins)
! 1561: {
! 1562: /* check high five bits */
! 1563: switch (ins >> (32 - 5)) {
! 1564: case 0x18: /* br */
! 1565: case 0x19: /* bsr */
! 1566: case 0x1a: /* bb0 */
! 1567: case 0x1b: /* bb1 */
! 1568: case 0x1d: /* bcnd */
! 1569: return (TRUE);
! 1570: case 0x1e: /* could be jmp or jsr */
! 1571: if ((ins & 0xfffff3e0) == 0xf400c000)
! 1572: return (TRUE);
! 1573: }
! 1574:
! 1575: return (FALSE);
! 1576: }
! 1577:
! 1578: int
! 1579: ss_put_breakpoint(struct proc *p, vaddr_t va, vaddr_t *bpva, u_int *bpsave)
! 1580: {
! 1581: int rc;
! 1582:
! 1583: /* Restore previous breakpoint if we did not trigger it. */
! 1584: if (*bpva != 0) {
! 1585: ss_put_value(p, *bpva, *bpsave);
! 1586: *bpva = 0;
! 1587: }
! 1588:
! 1589: /* Save instruction. */
! 1590: if ((rc = ss_get_value(p, va, bpsave)) != 0)
! 1591: return (rc);
! 1592:
! 1593: /* Store breakpoint instruction at the location now. */
! 1594: *bpva = va;
! 1595: return (ss_put_value(p, va, SSBREAKPOINT));
! 1596: }
! 1597:
! 1598: int
! 1599: process_sstep(struct proc *p, int sstep)
! 1600: {
! 1601: struct reg *sstf = USER_REGS(p);
! 1602: unsigned pc, brpc;
! 1603: unsigned instr;
! 1604: int rc;
! 1605:
! 1606: if (sstep == 0) {
! 1607: /* Restore previous breakpoints if any. */
! 1608: if (p->p_md.md_bp0va != 0) {
! 1609: ss_put_value(p, p->p_md.md_bp0va, p->p_md.md_bp0save);
! 1610: p->p_md.md_bp0va = 0;
! 1611: }
! 1612: if (p->p_md.md_bp1va != 0) {
! 1613: ss_put_value(p, p->p_md.md_bp1va, p->p_md.md_bp1save);
! 1614: p->p_md.md_bp1va = 0;
! 1615: }
! 1616:
! 1617: return (0);
! 1618: }
! 1619:
! 1620: /*
! 1621: * User was stopped at pc, e.g. the instruction at pc was not executed.
! 1622: * Fetch what's at the current location.
! 1623: */
! 1624: pc = PC_REGS(sstf);
! 1625: if ((rc = ss_get_value(p, pc, &instr)) != 0)
! 1626: return (rc);
! 1627:
! 1628: /*
! 1629: * Find if this instruction may cause a branch, and set up a breakpoint
! 1630: * at the branch location.
! 1631: */
! 1632: if (ss_inst_branch_or_call(instr) || instr == SYSCALL_INSTR) {
! 1633: brpc = ss_branch_taken(instr, pc, sstf);
! 1634:
! 1635: /* self-branches are hopeless */
! 1636: if (brpc != pc && brpc != 0) {
! 1637: if ((rc = ss_put_breakpoint(p, brpc,
! 1638: &p->p_md.md_bp1va, &p->p_md.md_bp1save)) != 0)
! 1639: return (rc);
! 1640: }
! 1641: }
! 1642:
! 1643: if ((rc = ss_put_breakpoint(p, pc + 4,
! 1644: &p->p_md.md_bp0va, &p->p_md.md_bp0save)) != 0)
! 1645: return (rc);
! 1646:
! 1647: return (0);
! 1648: }
! 1649:
! 1650: #endif /* PTRACE */
! 1651:
! 1652: #ifdef DIAGNOSTIC
! 1653: void
! 1654: splassert_check(int wantipl, const char *func)
! 1655: {
! 1656: int oldipl;
! 1657:
! 1658: /*
! 1659: * This will raise the spl if too low,
! 1660: * in a feeble attempt to reduce further damage.
! 1661: */
! 1662: oldipl = raiseipl(wantipl);
! 1663:
! 1664: if (oldipl < wantipl) {
! 1665: splassert_fail(wantipl, oldipl, func);
! 1666: }
! 1667: }
! 1668: #endif
! 1669:
! 1670: /*
! 1671: * ld.d and st.d instructions referencing long aligned but not long long
! 1672: * aligned addresses will trigger a misaligned address exception.
! 1673: *
! 1674: * This routine attempts to recover these (valid) statements, by simulating
! 1675: * the split form of the instruction. If it fails, it returns the appropriate
! 1676: * signal number to deliver.
! 1677: *
! 1678: * Note that we do not attempt to do anything for .d.usr instructions - the
! 1679: * kernel never issues such instructions, and they cause a privileged
! 1680: * isntruction exception from userland.
! 1681: */
! 1682: int
! 1683: double_reg_fixup(struct trapframe *frame)
! 1684: {
! 1685: u_int32_t pc, instr, value;
! 1686: int regno, store;
! 1687: vaddr_t addr;
! 1688:
! 1689: /*
! 1690: * Decode the faulting instruction.
! 1691: */
! 1692:
! 1693: pc = PC_REGS(&frame->tf_regs);
! 1694: if (copyin((void *)pc, &instr, sizeof(u_int32_t)) != 0)
! 1695: return SIGSEGV;
! 1696:
! 1697: switch (instr & 0xfc00ff00) {
! 1698: case 0xf4001000: /* ld.d rD, rS1, rS2 */
! 1699: addr = frame->tf_r[(instr >> 16) & 0x1f]
! 1700: + frame->tf_r[(instr & 0x1f)];
! 1701: store = 0;
! 1702: break;
! 1703: case 0xf4002000: /* st.d rD, rS1, rS2 */
! 1704: addr = frame->tf_r[(instr >> 16) & 0x1f]
! 1705: + frame->tf_r[(instr & 0x1f)];
! 1706: store = 1;
! 1707: break;
! 1708: default:
! 1709: switch (instr & 0xfc000000) {
! 1710: case 0x10000000: /* ld.d rD, rS, imm16 */
! 1711: addr = (instr & 0x0000ffff) +
! 1712: frame->tf_r[(instr >> 16) & 0x1f];
! 1713: store = 0;
! 1714: break;
! 1715: case 0x20000000: /* st.d rD, rS, imm16 */
! 1716: addr = (instr & 0x0000ffff) +
! 1717: frame->tf_r[(instr >> 16) & 0x1f];
! 1718: store = 1;
! 1719: break;
! 1720: default:
! 1721: return SIGBUS;
! 1722: }
! 1723: break;
! 1724: }
! 1725:
! 1726: /* We only handle long but not long long aligned access here */
! 1727: if ((addr & 0x07) != 4)
! 1728: return SIGBUS;
! 1729:
! 1730: regno = (instr >> 21) & 0x1f;
! 1731:
! 1732: if (store) {
! 1733: /*
! 1734: * Two word stores.
! 1735: */
! 1736: value = frame->tf_r[regno++];
! 1737: if (copyout(&value, (void *)addr, sizeof(u_int32_t)) != 0)
! 1738: return SIGSEGV;
! 1739: if (regno == 32)
! 1740: value = 0;
! 1741: else
! 1742: value = frame->tf_r[regno];
! 1743: if (copyout(&value, (void *)(addr + 4), sizeof(u_int32_t)) != 0)
! 1744: return SIGSEGV;
! 1745: } else {
! 1746: /*
! 1747: * Two word loads. r0 should be left unaltered, but the
! 1748: * value should still be fetched even if it is discarded.
! 1749: */
! 1750: if (copyin((void *)addr, &value, sizeof(u_int32_t)) != 0)
! 1751: return SIGSEGV;
! 1752: if (regno != 0)
! 1753: frame->tf_r[regno] = value;
! 1754: if (copyin((void *)(addr + 4), &value, sizeof(u_int32_t)) != 0)
! 1755: return SIGSEGV;
! 1756: if (regno != 31)
! 1757: frame->tf_r[regno + 1] = value;
! 1758: }
! 1759:
! 1760: return 0;
! 1761: }
! 1762:
! 1763: void
! 1764: cache_flush(struct trapframe *tf)
! 1765: {
! 1766: struct proc *p;
! 1767: struct pmap *pmap;
! 1768: paddr_t pa;
! 1769: vaddr_t va;
! 1770: vsize_t len, count;
! 1771:
! 1772: if ((p = curproc) == NULL)
! 1773: p = &proc0;
! 1774:
! 1775: p->p_md.md_tf = tf;
! 1776:
! 1777: pmap = vm_map_pmap(&p->p_vmspace->vm_map);
! 1778: va = tf->tf_r[2];
! 1779: len = tf->tf_r[3];
! 1780:
! 1781: if (/* va < VM_MIN_ADDRESS || */ va >= VM_MAXUSER_ADDRESS ||
! 1782: va + len <= va || va + len >= VM_MAXUSER_ADDRESS)
! 1783: len = 0;
! 1784:
! 1785: while (len != 0) {
! 1786: count = min(len, PAGE_SIZE - (va & PAGE_MASK));
! 1787: if (pmap_extract(pmap, va, &pa) != FALSE)
! 1788: dma_cachectl_pa(pa, count, DMA_CACHE_SYNC);
! 1789: va += count;
! 1790: len -= count;
! 1791: }
! 1792:
! 1793: if (CPU_IS88100) {
! 1794: tf->tf_snip = tf->tf_snip & ~NIP_E;
! 1795: tf->tf_sfip = tf->tf_sfip & ~FIP_E;
! 1796: } else {
! 1797: /* skip instruction */
! 1798: if (tf->tf_exip & 1)
! 1799: tf->tf_exip = tf->tf_enip;
! 1800: else
! 1801: tf->tf_exip += 4;
! 1802: }
! 1803:
! 1804: userret(p);
! 1805: }
CVSweb