Annotation of sys/arch/mips64/mips64/trap.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: trap.c,v 1.37 2007/07/16 20:21:20 miod Exp $ */
2: /* tracked to 1.23 */
3:
4: /*
5: * Copyright (c) 1988 University of Utah.
6: * Copyright (c) 1992, 1993
7: * The Regents of the University of California. All rights reserved.
8: *
9: * This code is derived from software contributed to Berkeley by
10: * the Systems Programming Group of the University of Utah Computer
11: * Science Department and Ralph Campbell.
12: *
13: * Redistribution and use in source and binary forms, with or without
14: * modification, are permitted provided that the following conditions
15: * are met:
16: * 1. Redistributions of source code must retain the above copyright
17: * notice, this list of conditions and the following disclaimer.
18: * 2. Redistributions in binary form must reproduce the above copyright
19: * notice, this list of conditions and the following disclaimer in the
20: * documentation and/or other materials provided with the distribution.
21: * 3. All advertising materials mentioning features or use of this software
22: * must display the following acknowledgement:
23: * This product includes software developed by the University of
24: * California, Berkeley and its contributors.
25: * 4. Neither the name of the University nor the names of its contributors
26: * may be used to endorse or promote products derived from this software
27: * without specific prior written permission.
28: *
29: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39: * SUCH DAMAGE.
40: *
41: * from: Utah Hdr: trap.c 1.32 91/04/06
42: *
43: * from: @(#)trap.c 8.5 (Berkeley) 1/11/94
44: */
45:
46: /*
47: * THIS CODE SHOULD BE REWRITTEN!
48: */
49:
50: #include <sys/param.h>
51: #include <sys/systm.h>
52: #include <sys/exec.h>
53: #include <sys/proc.h>
54: #include <sys/kernel.h>
55: #include <sys/signalvar.h>
56: #include <sys/syscall.h>
57: #include <sys/user.h>
58: #include <sys/buf.h>
59: #include <sys/device.h>
60: #ifdef KTRACE
61: #include <sys/ktrace.h>
62: #endif
63: #ifdef PTRACE
64: #include <sys/ptrace.h>
65: #endif
66: #include <net/netisr.h>
67:
68: #include <uvm/uvm_extern.h>
69:
70: #include <machine/trap.h>
71: #include <machine/psl.h>
72: #include <machine/cpu.h>
73: #include <machine/pio.h>
74: #include <machine/intr.h>
75: #include <machine/autoconf.h>
76: #include <machine/pte.h>
77: #include <machine/pmap.h>
78: #include <machine/mips_opcode.h>
79: #include <machine/frame.h>
80: #include <machine/regnum.h>
81:
82: #include <mips64/rm7000.h>
83:
84: #include <mips64/archtype.h>
85:
86: #ifdef DDB
87: #include <mips64/db_machdep.h>
88: #include <ddb/db_sym.h>
89: #endif
90:
91: #include <sys/cdefs.h>
92: #include <sys/syslog.h>
93:
94: #include "systrace.h"
95: #include <dev/systrace.h>
96:
97: int want_resched; /* resched() was called */
98: struct proc *machFPCurProcPtr; /* pointer to last proc to use FP */
99:
100: char *trap_type[] = {
101: "external interrupt",
102: "TLB modification",
103: "TLB miss (load or instr. fetch)",
104: "TLB miss (store)",
105: "address error (load or I-fetch)",
106: "address error (store)",
107: "bus error (I-fetch)",
108: "bus error (load or store)",
109: "system call",
110: "breakpoint",
111: "reserved instruction",
112: "coprocessor unusable",
113: "arithmetic overflow",
114: "trap",
115: "virtual coherency instruction",
116: "floating point",
117: "reserved 16",
118: "reserved 17",
119: "reserved 18",
120: "reserved 19",
121: "reserved 20",
122: "reserved 21",
123: "reserved 22",
124: "watch",
125: "reserved 24",
126: "reserved 25",
127: "reserved 26",
128: "reserved 27",
129: "reserved 28",
130: "reserved 29",
131: "reserved 30",
132: "virtual coherency data",
133: };
134:
135: #if defined(DDB) || defined(DEBUG)
136: extern register_t *tlbtrcptr;
137: struct trapdebug trapdebug[TRAPSIZE], *trp = trapdebug;
138:
139: void stacktrace(struct trap_frame *);
140: void logstacktrace(struct trap_frame *);
141: int kdbpeek(void *);
142: /* extern functions printed by name in stack backtraces */
143: extern void idle(void);
144: #endif /* DDB || DEBUG */
145:
146: #if defined(DDB)
147: int kdb_trap(int, db_regs_t *);
148: #endif
149:
150: extern void MipsSwitchFPState(struct proc *, struct trap_frame *);
151: extern void MipsSwitchFPState16(struct proc *, struct trap_frame *);
152: extern void MipsFPTrap(u_int, u_int, u_int, union sigval);
153:
154: void trap(struct trap_frame *);
155: #ifdef PTRACE
156: int cpu_singlestep(struct proc *);
157: #endif
158: u_long MipsEmulateBranch(struct trap_frame *, long, int, u_int);
159:
160: static __inline__ void
161: userret(struct proc *p)
162: {
163: int sig;
164:
165: /* take pending signals */
166: while ((sig = CURSIG(p)) != 0)
167: postsig(sig);
168:
169: p->p_cpu->ci_schedstate.spc_curpriority = p->p_priority = p->p_usrpri;
170: }
171:
172: /*
173: * Handle an exception.
174: * In the case of a kernel trap, we return the pc where to resume if
175: * pcb_onfault is set, otherwise, return old pc.
176: */
177: void
178: trap(trapframe)
179: struct trap_frame *trapframe;
180: {
181: int type, i;
182: unsigned ucode = 0;
183: struct proc *p = curproc;
184: vm_prot_t ftype;
185: extern vaddr_t onfault_table[];
186: int onfault;
187: int typ = 0;
188: union sigval sv;
189:
190: trapdebug_enter(trapframe, -1);
191:
192: type = (trapframe->cause & CR_EXC_CODE) >> CR_EXC_CODE_SHIFT;
193: if (USERMODE(trapframe->sr)) {
194: type |= T_USER;
195: }
196:
197: /*
198: * Enable hardware interrupts if they were on before the trap.
199: * If it was off disable all (splhigh) so we don't accidently
200: * enable it when doing a spllower().
201: */
202: if (trapframe->sr & SR_INT_ENAB) {
203: if (type != T_BREAK) {
204: #ifndef IMASK_EXTERNAL
205: updateimask(trapframe->cpl);
206: #endif
207: enableintr();
208: }
209: } else
210: splhigh();
211:
212:
213: switch (type) {
214: case T_TLB_MOD:
215: /* check for kernel address */
216: if (trapframe->badvaddr < 0) {
217: pt_entry_t *pte;
218: unsigned int entry;
219: paddr_t pa;
220: vm_page_t pg;
221:
222: pte = kvtopte(trapframe->badvaddr);
223: entry = pte->pt_entry;
224: #ifdef DIAGNOSTIC
225: if (!(entry & PG_V) || (entry & PG_M))
226: panic("trap: ktlbmod: invalid pte");
227: #endif
228: if (pmap_is_page_ro(pmap_kernel(),
229: trunc_page(trapframe->badvaddr), entry)) {
230: /* write to read only page in the kernel */
231: ftype = VM_PROT_WRITE;
232: goto kernel_fault;
233: }
234: entry |= PG_M;
235: pte->pt_entry = entry;
236: tlb_update(trapframe->badvaddr & ~PGOFSET, entry);
237: pa = pfn_to_pad(entry);
238: pg = PHYS_TO_VM_PAGE(pa);
239: if (pg == NULL)
240: panic("trap: ktlbmod: unmanaged page");
241: pmap_set_modify(pg);
242: return;
243: }
244: /* FALLTHROUGH */
245:
246: case T_TLB_MOD+T_USER:
247: {
248: pt_entry_t *pte;
249: unsigned int entry;
250: paddr_t pa;
251: vm_page_t pg;
252: pmap_t pmap = p->p_vmspace->vm_map.pmap;
253:
254: if (!(pte = pmap_segmap(pmap, trapframe->badvaddr)))
255: panic("trap: utlbmod: invalid segmap");
256: pte += uvtopte(trapframe->badvaddr);
257: entry = pte->pt_entry;
258: #ifdef DIAGNOSTIC
259: if (!(entry & PG_V) || (entry & PG_M))
260: panic("trap: utlbmod: invalid pte");
261: #endif
262: if (pmap_is_page_ro(pmap,
263: trunc_page(trapframe->badvaddr), entry)) {
264: /* write to read only page */
265: ftype = VM_PROT_WRITE;
266: goto fault_common;
267: }
268: entry |= PG_M;
269: pte->pt_entry = entry;
270: tlb_update((trapframe->badvaddr & ~PGOFSET) |
271: (pmap->pm_tlbpid << VMTLB_PID_SHIFT), entry);
272: pa = pfn_to_pad(entry);
273: pg = PHYS_TO_VM_PAGE(pa);
274: if (pg == NULL)
275: panic("trap: utlbmod: unmanaged page");
276: pmap_set_modify(pg);
277: if (!USERMODE(trapframe->sr))
278: return;
279: goto out;
280: }
281:
282: case T_TLB_LD_MISS:
283: case T_TLB_ST_MISS:
284: ftype = (type == T_TLB_ST_MISS) ? VM_PROT_WRITE : VM_PROT_READ;
285: /* check for kernel address */
286: if (trapframe->badvaddr < 0) {
287: vaddr_t va;
288: int rv;
289:
290: kernel_fault:
291: va = trunc_page((vaddr_t)trapframe->badvaddr);
292: onfault = p->p_addr->u_pcb.pcb_onfault;
293: p->p_addr->u_pcb.pcb_onfault = 0;
294: rv = uvm_fault(kernel_map, trunc_page(va), 0, ftype);
295: p->p_addr->u_pcb.pcb_onfault = onfault;
296: if (rv == 0)
297: return;
298: if (onfault != 0) {
299: p->p_addr->u_pcb.pcb_onfault = 0;
300: trapframe->pc = onfault_table[onfault];
301: return;
302: }
303: goto err;
304: }
305: /*
306: * It is an error for the kernel to access user space except
307: * through the copyin/copyout routines.
308: */
309: #if 0
310: /*
311: * However we allow accesses to the top of user stack for
312: * compat emul data.
313: */
314: #define szsigcode ((long)(p->p_emul->e_esigcode - p->p_emul->e_sigcode))
315: if (trapframe->badvaddr < VM_MAXUSER_ADDRESS &&
316: trapframe->badvaddr >= (long)STACKGAPBASE)
317: goto fault_common;
318: #undef szsigcode
319: #endif
320:
321: if (p->p_addr->u_pcb.pcb_onfault != 0) {
322: /*
323: * We want to resolve the TLB fault before invoking
324: * pcb_onfault if necessary.
325: */
326: goto fault_common;
327: } else {
328: goto err;
329: }
330:
331: case T_TLB_LD_MISS+T_USER:
332: ftype = VM_PROT_READ;
333: goto fault_common;
334:
335: case T_TLB_ST_MISS+T_USER:
336: ftype = VM_PROT_WRITE;
337: fault_common:
338: {
339: vaddr_t va;
340: struct vmspace *vm;
341: vm_map_t map;
342: int rv;
343:
344: vm = p->p_vmspace;
345: map = &vm->vm_map;
346: va = trunc_page((vaddr_t)trapframe->badvaddr);
347:
348: onfault = p->p_addr->u_pcb.pcb_onfault;
349: p->p_addr->u_pcb.pcb_onfault = 0;
350: rv = uvm_fault(map, trunc_page(va), 0, ftype);
351: p->p_addr->u_pcb.pcb_onfault = onfault;
352:
353: /*
354: * If this was a stack access we keep track of the maximum
355: * accessed stack size. Also, if vm_fault gets a protection
356: * failure it is due to accessing the stack region outside
357: * the current limit and we need to reflect that as an access
358: * error.
359: */
360: if ((caddr_t)va >= vm->vm_maxsaddr) {
361: if (rv == 0)
362: uvm_grow(p, va);
363: else if (rv == EACCES)
364: rv = EFAULT;
365: }
366: if (rv == 0) {
367: if (!USERMODE(trapframe->sr))
368: return;
369: goto out;
370: }
371: if (!USERMODE(trapframe->sr)) {
372: if (onfault != 0) {
373: p->p_addr->u_pcb.pcb_onfault = 0;
374: trapframe->pc = onfault_table[onfault];
375: return;
376: }
377: goto err;
378: }
379:
380: #ifdef ADEBUG
381: printf("SIG-SEGV @%p pc %p, ra %p\n", trapframe->badvaddr, trapframe->pc, trapframe->ra);
382: #endif
383: ucode = ftype;
384: i = SIGSEGV;
385: typ = SEGV_MAPERR;
386: break;
387: }
388:
389: case T_ADDR_ERR_LD+T_USER: /* misaligned or kseg access */
390: case T_ADDR_ERR_ST+T_USER: /* misaligned or kseg access */
391: ucode = 0; /* XXX should be VM_PROT_something */
392: i = SIGBUS;
393: typ = BUS_ADRALN;
394: #ifdef ADEBUG
395: printf("SIG-BUSA @%p pc %p, ra %p\n", trapframe->badvaddr, trapframe->pc, trapframe->ra);
396: #endif
397: break;
398: case T_BUS_ERR_IFETCH+T_USER: /* BERR asserted to cpu */
399: case T_BUS_ERR_LD_ST+T_USER: /* BERR asserted to cpu */
400: ucode = 0; /* XXX should be VM_PROT_something */
401: i = SIGBUS;
402: typ = BUS_OBJERR;
403: #ifdef ADEBUG
404: printf("SIG-BUSB @%p pc %p, ra %p\n", trapframe->badvaddr, trapframe->pc, trapframe->ra);
405: #endif
406: break;
407:
408: case T_SYSCALL+T_USER:
409: {
410: struct trap_frame *locr0 = p->p_md.md_regs;
411: struct sysent *callp;
412: unsigned int code;
413: unsigned long tpc;
414: int numsys;
415: struct args {
416: register_t i[8];
417: } args;
418: register_t rval[2];
419:
420: uvmexp.syscalls++;
421:
422: /* compute next PC after syscall instruction */
423: tpc = trapframe->pc; /* Remember if restart */
424: if ((int)trapframe->cause & CR_BR_DELAY) {
425: locr0->pc = MipsEmulateBranch(locr0, trapframe->pc, 0, 0);
426: }
427: else {
428: locr0->pc += 4;
429: }
430: callp = p->p_emul->e_sysent;
431: numsys = p->p_emul->e_nsysent;
432: code = locr0->v0;
433: switch (code) {
434: case SYS_syscall:
435: /*
436: * Code is first argument, followed by actual args.
437: */
438: code = locr0->a0;
439: if (code >= numsys)
440: callp += p->p_emul->e_nosys; /* (illegal) */
441: else
442: callp += code;
443: i = callp->sy_argsize / sizeof(register_t);
444: args.i[0] = locr0->a1;
445: args.i[1] = locr0->a2;
446: args.i[2] = locr0->a3;
447: if (i > 3) {
448: if (p->p_md.md_flags & MDP_O32) {
449: int32_t p[5];
450:
451: i = copyin((int32_t *)locr0->sp + 4,
452: p, 5 * sizeof(int32_t));
453: args.i[3] = p[0];
454: args.i[4] = p[1];
455: args.i[5] = p[2];
456: args.i[6] = p[3];
457: args.i[7] = p[4];
458: } else {
459: args.i[3] = locr0->a4;
460: args.i[4] = locr0->a5;
461: args.i[5] = locr0->a6;
462: args.i[6] = locr0->a7;
463: i = copyin((void *)locr0->sp,
464: &args.i[7], sizeof(register_t));
465: }
466: }
467: break;
468:
469: case SYS___syscall:
470: /*
471: * Like syscall, but code is a quad, so as to maintain
472: * quad alignment for the rest of the arguments.
473: */
474: if (p->p_md.md_flags & MDP_O32) {
475: if (_QUAD_LOWWORD == 0) {
476: code = locr0->a0;
477: } else {
478: code = locr0->a1;
479: }
480: args.i[0] = locr0->a2;
481: args.i[1] = locr0->a3;
482: } else {
483: code = locr0->a0;
484: args.i[0] = locr0->a1;
485: args.i[1] = locr0->a2;
486: args.i[2] = locr0->a3;
487: }
488:
489: if (code >= numsys)
490: callp += p->p_emul->e_nosys; /* (illegal) */
491: else
492: callp += code;
493: i = callp->sy_argsize / sizeof(int);
494: if (i > 2 && p->p_md.md_flags & MDP_O32) {
495: int32_t p[6];
496:
497: i = copyin((int32_t *)locr0->sp + 4,
498: p, 6 * sizeof(int32_t));
499: args.i[2] = p[0];
500: args.i[3] = p[1];
501: args.i[4] = p[2];
502: args.i[5] = p[3];
503: args.i[6] = p[4];
504: args.i[7] = p[5];
505: } else if (i > 3) {
506: args.i[3] = locr0->a4;
507: args.i[4] = locr0->a5;
508: args.i[5] = locr0->a6;
509: args.i[6] = locr0->a7;
510: i = copyin((void *)locr0->sp, &args.i[7],
511: sizeof(register_t));
512: }
513: break;
514:
515: default:
516: if (code >= numsys)
517: callp += p->p_emul->e_nosys; /* (illegal) */
518: else
519: callp += code;
520:
521: i = callp->sy_narg;
522: args.i[0] = locr0->a0;
523: args.i[1] = locr0->a1;
524: args.i[2] = locr0->a2;
525: args.i[3] = locr0->a3;
526: if (i > 4) {
527: if (p->p_md.md_flags & MDP_O32) {
528: int32_t p[4];
529:
530: i = copyin((int32_t *)locr0->sp + 4,
531: p, 4 * sizeof(int32_t));
532: args.i[4] = p[0];
533: args.i[5] = p[1];
534: args.i[6] = p[2];
535: args.i[7] = p[3];
536: } else {
537: args.i[4] = locr0->a4;
538: args.i[5] = locr0->a5;
539: args.i[6] = locr0->a6;
540: args.i[7] = locr0->a7;
541: }
542: }
543: }
544: #ifdef SYSCALL_DEBUG
545: scdebug_call(p, code, args.i);
546: #endif
547: #ifdef KTRACE
548: if (KTRPOINT(p, KTR_SYSCALL))
549: ktrsyscall(p, code, callp->sy_argsize, args.i);
550: #endif
551: rval[0] = 0;
552: rval[1] = locr0->v1;
553: #if defined(DDB) || defined(DEBUG)
554: if (trp == trapdebug)
555: trapdebug[TRAPSIZE - 1].code = code;
556: else
557: trp[-1].code = code;
558: #endif
559: #if NSYSTRACE > 0
560: if (ISSET(p->p_flag, P_SYSTRACE))
561: i = systrace_redirect(code, p, args.i, rval);
562: else
563: #endif
564: i = (*callp->sy_call)(p, &args, rval);
565:
566: switch (i) {
567: case 0:
568: locr0->v0 = rval[0];
569: locr0->v1 = rval[1];
570: locr0->a3 = 0;
571: break;
572:
573: case ERESTART:
574: locr0->pc = tpc;
575: break;
576:
577: case EJUSTRETURN:
578: break; /* nothing to do */
579:
580: default:
581: locr0->v0 = i;
582: locr0->a3 = 1;
583: }
584: if (code == SYS_ptrace)
585: Mips_SyncCache();
586: #ifdef SYSCALL_DEBUG
587: scdebug_ret(p, code, i, rval);
588: #endif
589: #ifdef KTRACE
590: if (KTRPOINT(p, KTR_SYSRET))
591: ktrsysret(p, code, i, rval[0]);
592: #endif
593: goto out;
594: }
595:
596: #ifdef DDB
597: case T_BREAK:
598: kdb_trap(type, trapframe);
599: return;
600: #endif
601:
602: case T_BREAK+T_USER:
603: {
604: caddr_t va;
605: u_int32_t instr;
606: struct trap_frame *locr0 = p->p_md.md_regs;
607:
608: /* compute address of break instruction */
609: va = (caddr_t)trapframe->pc;
610: if ((int)trapframe->cause & CR_BR_DELAY)
611: va += 4;
612:
613: /* read break instruction */
614: copyin(va, &instr, sizeof(int32_t));
615:
616: #if 0
617: printf("trap: %s (%d) breakpoint %x at %x: (adr %x ins %x)\n",
618: p->p_comm, p->p_pid, instr, trapframe->pc,
619: p->p_md.md_ss_addr, p->p_md.md_ss_instr); /* XXX */
620: #endif
621:
622: switch ((instr & BREAK_VAL_MASK) >> BREAK_VAL_SHIFT) {
623: case 6: /* gcc range error */
624: i = SIGFPE;
625: typ = FPE_FLTSUB;
626: /* skip instruction */
627: if ((int)trapframe->cause & CR_BR_DELAY)
628: locr0->pc = MipsEmulateBranch(locr0,
629: trapframe->pc, 0, 0);
630: else
631: locr0->pc += 4;
632: break;
633: case 7: /* gcc divide by zero */
634: i = SIGFPE;
635: typ = FPE_FLTDIV; /* XXX FPE_INTDIV ? */
636: /* skip instruction */
637: if ((int)trapframe->cause & CR_BR_DELAY)
638: locr0->pc = MipsEmulateBranch(locr0,
639: trapframe->pc, 0, 0);
640: else
641: locr0->pc += 4;
642: break;
643: #ifdef PTRACE
644: case BREAK_SSTEP_VAL:
645: if (p->p_md.md_ss_addr == (long)va) {
646: struct uio uio;
647: struct iovec iov;
648: int error;
649:
650: /*
651: * Restore original instruction and clear BP
652: */
653: iov.iov_base = (caddr_t)&p->p_md.md_ss_instr;
654: iov.iov_len = sizeof(int);
655: uio.uio_iov = &iov;
656: uio.uio_iovcnt = 1;
657: uio.uio_offset = (off_t)(long)va;
658: uio.uio_resid = sizeof(int);
659: uio.uio_segflg = UIO_SYSSPACE;
660: uio.uio_rw = UIO_WRITE;
661: uio.uio_procp = curproc;
662: error = process_domem(curproc, p, &uio,
663: PT_WRITE_I);
664: Mips_SyncCache();
665:
666: if (error)
667: printf("Warning: can't restore instruction at %x: %x\n",
668: p->p_md.md_ss_addr,
669: p->p_md.md_ss_instr);
670:
671: p->p_md.md_ss_addr = 0;
672: typ = TRAP_BRKPT;
673: } else {
674: typ = TRAP_TRACE;
675: }
676: i = SIGTRAP;
677: break;
678: #endif
679: default:
680: typ = TRAP_TRACE;
681: i = SIGTRAP;
682: break;
683: }
684:
685: break;
686: }
687:
688: case T_IWATCH+T_USER:
689: case T_DWATCH+T_USER:
690: {
691: caddr_t va;
692: /* compute address of trapped instruction */
693: va = (caddr_t)trapframe->pc;
694: if ((int)trapframe->cause & CR_BR_DELAY)
695: va += 4;
696: printf("watch exception @ %p\n", va);
697: if (rm7k_watchintr(trapframe)) {
698: /* Return to user, don't add any more overhead */
699: return;
700: }
701: i = SIGTRAP;
702: typ = TRAP_BRKPT;
703: break;
704: }
705:
706: case T_TRAP+T_USER:
707: {
708: caddr_t va;
709: u_int32_t instr;
710: struct trap_frame *locr0 = p->p_md.md_regs;
711:
712: /* compute address of trap instruction */
713: va = (caddr_t)trapframe->pc;
714: if ((int)trapframe->cause & CR_BR_DELAY)
715: va += 4;
716: /* read break instruction */
717: copyin(va, &instr, sizeof(int32_t));
718:
719: if ((int)trapframe->cause & CR_BR_DELAY) {
720: locr0->pc = MipsEmulateBranch(locr0, trapframe->pc, 0, 0);
721: } else {
722: locr0->pc += 4;
723: }
724: if (instr == 0x040c0000) { /* Performance cntr trap */
725: int result;
726:
727: result = rm7k_perfcntr(trapframe->a0, trapframe->a1,
728: trapframe->a2, trapframe->a3);
729: locr0->v0 = -result;
730: /* Return to user, don't add any more overhead */
731: return;
732: }
733: else {
734: i = SIGEMT; /* Stuff it with something for now */
735: typ = 0;
736: }
737: break;
738: }
739:
740: case T_RES_INST+T_USER:
741: i = SIGILL;
742: typ = ILL_ILLOPC;
743: break;
744:
745: case T_COP_UNUSABLE+T_USER:
746: if ((trapframe->cause & CR_COP_ERR) != 0x10000000) {
747: i = SIGILL; /* only FPU instructions allowed */
748: typ = ILL_ILLOPC;
749: break;
750: }
751:
752: if (p->p_md.md_regs->sr & SR_FR_32)
753: MipsSwitchFPState(machFPCurProcPtr, p->p_md.md_regs);
754: else
755: MipsSwitchFPState16(machFPCurProcPtr, p->p_md.md_regs);
756:
757: machFPCurProcPtr = p;
758: p->p_md.md_regs->sr |= SR_COP_1_BIT;
759: p->p_md.md_flags |= MDP_FPUSED;
760: goto out;
761:
762: case T_FPE:
763: printf("FPU Trap: PC %x CR %x SR %x\n",
764: trapframe->pc, trapframe->cause, trapframe->sr);
765: goto err;
766:
767: case T_FPE+T_USER:
768: sv.sival_ptr = (void *)trapframe->pc;
769: MipsFPTrap(trapframe->sr, trapframe->cause, trapframe->pc, sv);
770: goto out;
771:
772: case T_OVFLOW+T_USER:
773: i = SIGFPE;
774: typ = FPE_FLTOVF;
775: break;
776:
777: case T_ADDR_ERR_LD: /* misaligned access */
778: case T_ADDR_ERR_ST: /* misaligned access */
779: case T_BUS_ERR_LD_ST: /* BERR asserted to cpu */
780: if ((onfault = p->p_addr->u_pcb.pcb_onfault) != 0) {
781: p->p_addr->u_pcb.pcb_onfault = 0;
782: trapframe->pc = onfault_table[onfault];
783: return;
784: }
785: goto err;
786:
787: default:
788: err:
789: disableintr();
790: #if !defined(DDB) && defined(DEBUG)
791: trapDump("trap");
792: #endif
793: printf("\nTrap cause = %d Frame %p\n", type, trapframe);
794: printf("Trap PC %p RA %p fault %p\n",
795: trapframe->pc, trapframe->ra, trapframe->badvaddr);
796: #ifdef DDB
797: stacktrace(!USERMODE(trapframe->sr) ? trapframe : p->p_md.md_regs);
798: kdb_trap(type, trapframe);
799: #endif
800: panic("trap");
801: }
802: p->p_md.md_regs->pc = trapframe->pc;
803: p->p_md.md_regs->cause = trapframe->cause;
804: p->p_md.md_regs->badvaddr = trapframe->badvaddr;
805: sv.sival_ptr = (void *)trapframe->badvaddr;
806: trapsignal(p, i, ucode, typ, sv);
807: out:
808: /*
809: * Note: we should only get here if returning to user mode.
810: */
811: userret(p);
812: }
813:
814: void
815: child_return(arg)
816: void *arg;
817: {
818: struct proc *p = arg;
819: struct trap_frame *trapframe;
820:
821: trapframe = p->p_md.md_regs;
822: trapframe->v0 = 0;
823: trapframe->v1 = 1;
824: trapframe->a3 = 0;
825:
826: userret(p);
827:
828: #ifdef KTRACE
829: if (KTRPOINT(p, KTR_SYSRET))
830: ktrsysret(p,
831: (p->p_flag & P_PPWAIT) ? SYS_vfork : SYS_fork, 0, 0);
832: #endif
833: }
834:
835: #if defined(DDB) || defined(DEBUG)
836: void
837: trapDump(msg)
838: char *msg;
839: {
840: struct trapdebug *ptrp;
841: int i;
842: int s;
843:
844: s = splhigh();
845: ptrp = trp;
846: printf("trapDump(%s)\n", msg);
847: for (i = 0; i < TRAPSIZE; i++) {
848: if (ptrp == trapdebug) {
849: ptrp = &trapdebug[TRAPSIZE - 1];
850: }
851: else {
852: ptrp--;
853: }
854:
855: if (ptrp->cause == 0)
856: break;
857:
858: printf("%s: PC %p CR 0x%x SR 0x%x\n",
859: trap_type[(ptrp->cause & CR_EXC_CODE) >> CR_EXC_CODE_SHIFT],
860: ptrp->pc, ptrp->cause, ptrp->status);
861:
862: printf(" RA %p SP %p ADR %p\n", ptrp->ra, ptrp->sp, ptrp->vadr);
863: }
864:
865: splx(s);
866: }
867: #endif
868:
869:
870: /*
871: * Return the resulting PC as if the branch was executed.
872: */
873: unsigned long
874: MipsEmulateBranch(framePtr, instPC, fpcCSR, curinst)
875: struct trap_frame *framePtr;
876: long instPC;
877: int fpcCSR;
878: u_int curinst;
879: {
880: InstFmt inst;
881: unsigned long retAddr;
882: int condition;
883: register_t *regsPtr = (register_t *)framePtr;
884:
885: #define GetBranchDest(InstPtr, inst) \
886: ((unsigned long)InstPtr + 4 + ((short)inst.IType.imm << 2))
887:
888:
889: if (curinst) {
890: inst = *(InstFmt *)&curinst;
891: }
892: else {
893: inst = *(InstFmt *)instPC;
894: }
895: #if 0
896: printf("regsPtr=%x PC=%x Inst=%x fpcCsr=%x\n", regsPtr, instPC,
897: inst.word, fpcCSR); /* XXX */
898: #endif
899: regsPtr[ZERO] = 0; /* Make sure zero is 0x0 */
900:
901: switch ((int)inst.JType.op) {
902: case OP_SPECIAL:
903: switch ((int)inst.RType.func) {
904: case OP_JR:
905: case OP_JALR:
906: retAddr = regsPtr[inst.RType.rs];
907: break;
908:
909: default:
910: retAddr = instPC + 4;
911: break;
912: }
913: break;
914:
915: case OP_BCOND:
916: switch ((int)inst.IType.rt) {
917: case OP_BLTZ:
918: case OP_BLTZL:
919: case OP_BLTZAL:
920: case OP_BLTZALL:
921: if ((int)(regsPtr[inst.RType.rs]) < 0)
922: retAddr = GetBranchDest(instPC, inst);
923: else
924: retAddr = instPC + 8;
925: break;
926:
927: case OP_BGEZ:
928: case OP_BGEZL:
929: case OP_BGEZAL:
930: case OP_BGEZALL:
931: if ((int)(regsPtr[inst.RType.rs]) >= 0)
932: retAddr = GetBranchDest(instPC, inst);
933: else
934: retAddr = instPC + 8;
935: break;
936:
937: case OP_TGEI:
938: case OP_TGEIU:
939: case OP_TLTI:
940: case OP_TLTIU:
941: case OP_TEQI:
942: case OP_TNEI:
943: retAddr = instPC + 4; /* Like syscall... */
944: break;
945:
946: default:
947: panic("MipsEmulateBranch: Bad branch cond");
948: }
949: break;
950:
951: case OP_J:
952: case OP_JAL:
953: retAddr = (inst.JType.target << 2) | (instPC & ~0x0fffffff);
954: break;
955:
956: case OP_BEQ:
957: case OP_BEQL:
958: if (regsPtr[inst.RType.rs] == regsPtr[inst.RType.rt])
959: retAddr = GetBranchDest(instPC, inst);
960: else
961: retAddr = instPC + 8;
962: break;
963:
964: case OP_BNE:
965: case OP_BNEL:
966: if (regsPtr[inst.RType.rs] != regsPtr[inst.RType.rt])
967: retAddr = GetBranchDest(instPC, inst);
968: else
969: retAddr = instPC + 8;
970: break;
971:
972: case OP_BLEZ:
973: case OP_BLEZL:
974: if ((int)(regsPtr[inst.RType.rs]) <= 0)
975: retAddr = GetBranchDest(instPC, inst);
976: else
977: retAddr = instPC + 8;
978: break;
979:
980: case OP_BGTZ:
981: case OP_BGTZL:
982: if ((int)(regsPtr[inst.RType.rs]) > 0)
983: retAddr = GetBranchDest(instPC, inst);
984: else
985: retAddr = instPC + 8;
986: break;
987:
988: case OP_COP1:
989: switch (inst.RType.rs) {
990: case OP_BCx:
991: case OP_BCy:
992: if ((inst.RType.rt & COPz_BC_TF_MASK) == COPz_BC_TRUE)
993: condition = fpcCSR & FPC_COND_BIT;
994: else
995: condition = !(fpcCSR & FPC_COND_BIT);
996: if (condition)
997: retAddr = GetBranchDest(instPC, inst);
998: else
999: retAddr = instPC + 8;
1000: break;
1001:
1002: default:
1003: retAddr = instPC + 4;
1004: }
1005: break;
1006:
1007: default:
1008: retAddr = instPC + 4;
1009: }
1010: return (retAddr);
1011: }
1012:
1013: #ifdef PTRACE
1014:
1015: /*
1016: * This routine is called by procxmt() to single step one instruction.
1017: * We do this by storing a break instruction after the current instruction,
1018: * resuming execution, and then restoring the old instruction.
1019: */
1020: int
1021: cpu_singlestep(p)
1022: struct proc *p;
1023: {
1024: vaddr_t va;
1025: struct trap_frame *locr0 = p->p_md.md_regs;
1026: int error;
1027: int bpinstr = BREAK_SSTEP;
1028: int curinstr;
1029: struct uio uio;
1030: struct iovec iov;
1031:
1032: /*
1033: * Fetch what's at the current location.
1034: */
1035: iov.iov_base = (caddr_t)&curinstr;
1036: iov.iov_len = sizeof(int);
1037: uio.uio_iov = &iov;
1038: uio.uio_iovcnt = 1;
1039: uio.uio_offset = (off_t)locr0->pc;
1040: uio.uio_resid = sizeof(int);
1041: uio.uio_segflg = UIO_SYSSPACE;
1042: uio.uio_rw = UIO_READ;
1043: uio.uio_procp = curproc;
1044: process_domem(curproc, p, &uio, PT_READ_I);
1045:
1046: /* compute next address after current location */
1047: if (curinstr != 0) {
1048: va = MipsEmulateBranch(locr0, locr0->pc, locr0->fsr, curinstr);
1049: }
1050: else {
1051: va = locr0->pc + 4;
1052: }
1053: if (p->p_md.md_ss_addr) {
1054: printf("SS %s (%d): breakpoint already set at %x (va %x)\n",
1055: p->p_comm, p->p_pid, p->p_md.md_ss_addr, va); /* XXX */
1056: return (EFAULT);
1057: }
1058:
1059: /*
1060: * Fetch what's at the current location.
1061: */
1062: iov.iov_base = (caddr_t)&p->p_md.md_ss_instr;
1063: iov.iov_len = sizeof(int);
1064: uio.uio_iov = &iov;
1065: uio.uio_iovcnt = 1;
1066: uio.uio_offset = (off_t)va;
1067: uio.uio_resid = sizeof(int);
1068: uio.uio_segflg = UIO_SYSSPACE;
1069: uio.uio_rw = UIO_READ;
1070: uio.uio_procp = curproc;
1071: process_domem(curproc, p, &uio, PT_READ_I);
1072:
1073: /*
1074: * Store breakpoint instruction at the "next" location now.
1075: */
1076: iov.iov_base = (caddr_t)&bpinstr;
1077: iov.iov_len = sizeof(int);
1078: uio.uio_iov = &iov;
1079: uio.uio_iovcnt = 1;
1080: uio.uio_offset = (off_t)va;
1081: uio.uio_resid = sizeof(int);
1082: uio.uio_segflg = UIO_SYSSPACE;
1083: uio.uio_rw = UIO_WRITE;
1084: uio.uio_procp = curproc;
1085: error = process_domem(curproc, p, &uio, PT_WRITE_I);
1086: Mips_SyncCache();
1087: if (error)
1088: return (EFAULT);
1089:
1090: p->p_md.md_ss_addr = va;
1091: #if 0
1092: printf("SS %s (%d): breakpoint set at %x: %x (pc %x) br %x\n",
1093: p->p_comm, p->p_pid, p->p_md.md_ss_addr,
1094: p->p_md.md_ss_instr, locr0[PC], curinstr); /* XXX */
1095: #endif
1096: return (0);
1097: }
1098:
1099: #endif /* PTRACE */
1100:
1101: #if defined(DDB) || defined(DEBUG)
1102: #define MIPS_JR_RA 0x03e00008 /* instruction code for jr ra */
1103:
1104: /* forward */
1105: #if !defined(DDB)
1106: char *fn_name(long addr);
1107: #endif
1108: void stacktrace_subr(struct trap_frame *, int (*)(const char*, ...));
1109:
1110: /*
1111: * Print a stack backtrace.
1112: */
1113: void
1114: stacktrace(regs)
1115: struct trap_frame *regs;
1116: {
1117: stacktrace_subr(regs, printf);
1118: }
1119:
1120: void
1121: logstacktrace(regs)
1122: struct trap_frame *regs;
1123: {
1124: stacktrace_subr(regs, addlog);
1125: }
1126:
1127: void
1128: stacktrace_subr(regs, printfn)
1129: struct trap_frame *regs;
1130: int (*printfn)(const char*, ...);
1131: {
1132: long pc, sp, fp, ra, va, subr;
1133: long a0, a1, a2, a3;
1134: unsigned instr, mask;
1135: InstFmt i;
1136: int more, stksize;
1137: extern char edata[];
1138: unsigned int frames = 0;
1139:
1140: /* get initial values from the exception frame */
1141: sp = regs->sp;
1142: pc = regs->pc;
1143: fp = regs->s8;
1144: ra = regs->ra; /* May be a 'leaf' function */
1145: a0 = regs->a0;
1146: a1 = regs->a1;
1147: a2 = regs->a2;
1148: a3 = regs->a3;
1149:
1150: /* Jump here when done with a frame, to start a new one */
1151: loop:
1152:
1153: /* Jump here after a nonstandard (interrupt handler) frame */
1154: stksize = 0;
1155: subr = 0;
1156: if (frames++ > 6) {
1157: (*printfn)("stackframe count exceeded\n");
1158: return;
1159: }
1160:
1161: /* check for bad SP: could foul up next frame */
1162: if (sp & 3 || (!IS_XKPHYS((vaddr_t)sp) && sp < KSEG0_BASE)) {
1163: (*printfn)("SP %p: not in kernel\n", sp);
1164: ra = 0;
1165: subr = 0;
1166: goto done;
1167: }
1168:
1169: #if 0
1170: /* Backtraces should contine through interrupts from kernel mode */
1171: if (pc >= (vaddr_t)MipsKernIntr && pc < (vaddr_t)MipsUserIntr) {
1172: (*printfn)("MipsKernIntr+%x: (%x, %x ,%x) -------\n",
1173: pc-(vaddr_t)MipsKernIntr, a0, a1, a2);
1174: regs = (struct trap_frame *)(sp + STAND_ARG_SIZE);
1175: a0 = kdbpeek(®s->a0);
1176: a1 = kdbpeek(®s->a1);
1177: a2 = kdbpeek(®s->a2);
1178: a3 = kdbpeek(®s->a3);
1179:
1180: pc = kdbpeek(®s->pc); /* exc_pc - pc at time of exception */
1181: ra = kdbpeek(®s->ra); /* ra at time of exception */
1182: sp = kdbpeek(®s->sp);
1183: goto specialframe;
1184: }
1185: #endif
1186:
1187:
1188: # define Between(x, y, z) \
1189: ( ((x) <= (y)) && ((y) < (z)) )
1190: # define pcBetween(a,b) \
1191: Between((vaddr_t)a, pc, (vaddr_t)b)
1192:
1193: /* check for bad PC */
1194: if (pc & 3 || pc < KSEG0_BASE || pc >= (unsigned)edata) {
1195: (*printfn)("PC %p: not in kernel\n", pc);
1196: ra = 0;
1197: goto done;
1198: }
1199:
1200: /*
1201: * Find the beginning of the current subroutine by scanning backwards
1202: * from the current PC for the end of the previous subroutine.
1203: */
1204: if (!subr) {
1205: va = pc - sizeof(int);
1206: while ((instr = kdbpeek((void *)va)) != MIPS_JR_RA)
1207: va -= sizeof(int);
1208: va += 2 * sizeof(int); /* skip back over branch & delay slot */
1209: /* skip over nulls which might separate .o files */
1210: while ((instr = kdbpeek((void *)va)) == 0)
1211: va += sizeof(int);
1212: subr = va;
1213: }
1214:
1215: /*
1216: * Jump here for locore entry points for which the preceding
1217: * function doesn't end in "j ra"
1218: */
1219: /* scan forwards to find stack size and any saved registers */
1220: stksize = 0;
1221: more = 3;
1222: mask = 0;
1223: for (va = subr; more; va += sizeof(int),
1224: more = (more == 3) ? 3 : more - 1) {
1225: /* stop if hit our current position */
1226: if (va >= pc)
1227: break;
1228: instr = kdbpeek((void *)va);
1229: i.word = instr;
1230: switch (i.JType.op) {
1231: case OP_SPECIAL:
1232: switch (i.RType.func) {
1233: case OP_JR:
1234: case OP_JALR:
1235: more = 2; /* stop after next instruction */
1236: break;
1237:
1238: case OP_SYSCALL:
1239: case OP_BREAK:
1240: more = 1; /* stop now */
1241: };
1242: break;
1243:
1244: case OP_BCOND:
1245: case OP_J:
1246: case OP_JAL:
1247: case OP_BEQ:
1248: case OP_BNE:
1249: case OP_BLEZ:
1250: case OP_BGTZ:
1251: more = 2; /* stop after next instruction */
1252: break;
1253:
1254: case OP_COP0:
1255: case OP_COP1:
1256: case OP_COP2:
1257: case OP_COP3:
1258: switch (i.RType.rs) {
1259: case OP_BCx:
1260: case OP_BCy:
1261: more = 2; /* stop after next instruction */
1262: };
1263: break;
1264:
1265: case OP_SW:
1266: case OP_SD:
1267: /* look for saved registers on the stack */
1268: if (i.IType.rs != 29)
1269: break;
1270: /* only restore the first one */
1271: if (mask & (1 << i.IType.rt))
1272: break;
1273: mask |= (1 << i.IType.rt);
1274: switch (i.IType.rt) {
1275: case 4: /* a0 */
1276: a0 = kdbpeek((void *)(sp + (short)i.IType.imm));
1277: break;
1278:
1279: case 5: /* a1 */
1280: a1 = kdbpeek((void *)(sp + (short)i.IType.imm));
1281: break;
1282:
1283: case 6: /* a2 */
1284: a2 = kdbpeek((void *)(sp + (short)i.IType.imm));
1285: break;
1286:
1287: case 7: /* a3 */
1288: a3 = kdbpeek((void *)(sp + (short)i.IType.imm));
1289: break;
1290:
1291: case 30: /* fp */
1292: fp = kdbpeek((void *)(sp + (short)i.IType.imm));
1293: break;
1294:
1295: case 31: /* ra */
1296: ra = kdbpeek((void *)(sp + (short)i.IType.imm));
1297: }
1298: break;
1299:
1300: case OP_ADDI:
1301: case OP_ADDIU:
1302: case OP_DADDI:
1303: case OP_DADDIU:
1304: /* look for stack pointer adjustment */
1305: if (i.IType.rs != 29 || i.IType.rt != 29)
1306: break;
1307: stksize = - ((short)i.IType.imm);
1308: }
1309: }
1310:
1311: done:
1312: #ifdef DDB
1313: db_printsym(pc, DB_STGY_ANY, printfn);
1314: #else
1315: (*printfn)("%s+%x", fn_name(subr), pc - subr);
1316: #endif
1317: if (frames == 1)
1318: (*printfn)(" ra %p sp %p (%p,%p,%p,%p)\n",
1319: ra, sp, a0, a1, a2, a3);
1320: else
1321: (*printfn)(" ra %p sp %p\n", ra, sp);
1322:
1323: if (ra) {
1324: if (pc == ra && stksize == 0)
1325: (*printfn)("stacktrace: loop!\n");
1326: else {
1327: pc = ra;
1328: sp += stksize;
1329: ra = 0;
1330: goto loop;
1331: }
1332: } else {
1333: if (curproc)
1334: (*printfn)("User-level: pid %d\n", curproc->p_pid);
1335: else
1336: (*printfn)("User-level: curproc NULL\n");
1337: }
1338: }
1339:
1340: #if !defined(DDB)
1341: /*
1342: * Functions ``special'' enough to print by name
1343: */
1344: #ifdef __STDC__
1345: #define Name(_fn) { (void*)_fn, # _fn }
1346: #else
1347: #define Name(_fn) { _fn, "_fn"}
1348: #endif
1349: static struct { void *addr; char *name;} names[] = {
1350: Name(trap),
1351: {0, 0}
1352: };
1353:
1354: /*
1355: * Map a function address to a string name, if known; or a hex string.
1356: */
1357: char *
1358: fn_name(long addr)
1359: {
1360: static char buf[17];
1361: int i = 0;
1362:
1363: for (i = 0; names[i].name; i++)
1364: if (names[i].addr == (void*)addr)
1365: return (names[i].name);
1366: snprintf(buf, sizeof(buf), "%x", addr);
1367: return (buf);
1368: }
1369: #endif /* !DDB */
1370:
1371: #endif /* DDB || DEBUG */
CVSweb