Annotation of src/sys/arch/mips/mips/trap.c, Revision 1.165.2.8
1.165.2.8! nathanw 1: /* $NetBSD: trap.c,v 1.165.2.7 2002/04/01 07:41:13 nathanw Exp $ */
1.165.2.2 wdk 2:
3: /*
4: * Copyright (c) 1988 University of Utah.
5: * Copyright (c) 1992, 1993
6: * The Regents of the University of California. All rights reserved.
7: *
8: * This code is derived from software contributed to Berkeley by
9: * the Systems Programming Group of the University of Utah Computer
10: * Science Department and Ralph Campbell.
11: *
12: * Redistribution and use in source and binary forms, with or without
13: * modification, are permitted provided that the following conditions
14: * are met:
15: * 1. Redistributions of source code must retain the above copyright
16: * notice, this list of conditions and the following disclaimer.
17: * 2. Redistributions in binary form must reproduce the above copyright
18: * notice, this list of conditions and the following disclaimer in the
19: * documentation and/or other materials provided with the distribution.
20: * 3. All advertising materials mentioning features or use of this software
21: * must display the following acknowledgement:
22: * This product includes software developed by the University of
23: * California, Berkeley and its contributors.
24: * 4. Neither the name of the University nor the names of its contributors
25: * may be used to endorse or promote products derived from this software
26: * without specific prior written permission.
27: *
28: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38: * SUCH DAMAGE.
39: *
40: * from: Utah Hdr: trap.c 1.32 91/04/06
41: *
42: * @(#)trap.c 8.5 (Berkeley) 1/11/94
43: */
44:
45: #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
46:
1.165.2.8! nathanw 47: __KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.165.2.7 2002/04/01 07:41:13 nathanw Exp $");
1.165.2.2 wdk 48:
49: #include "opt_cputype.h" /* which mips CPU levels do we support? */
50: #include "opt_ktrace.h"
51: #include "opt_ddb.h"
52: #include "opt_kgdb.h"
53:
54: #include <sys/param.h>
55: #include <sys/systm.h>
56: #include <sys/kernel.h>
57: #include <sys/proc.h>
58: #include <sys/signalvar.h>
59: #include <sys/syscall.h>
60: #include <sys/user.h>
61: #include <sys/buf.h>
62: #ifdef KTRACE
63: #include <sys/ktrace.h>
64: #endif
65: #include <sys/savar.h>
66:
67: #include <mips/cache.h>
68: #include <mips/locore.h>
69: #include <mips/mips_opcode.h>
70:
71: #include <uvm/uvm_extern.h>
72:
73: #include <machine/cpu.h>
74: #include <mips/trap.h>
75: #include <mips/reg.h>
76: #include <mips/regnum.h> /* symbolic register indices */
77: #include <mips/pte.h>
78: #include <mips/psl.h>
79: #include <mips/userret.h>
80:
81: #include <net/netisr.h>
82:
83: #ifdef DDB
84: #include <machine/db_machdep.h>
85: #include <ddb/db_sym.h>
86: #endif
87:
88: #ifdef KGDB
89: #include <sys/kgdb.h>
90: #endif
91:
92: int want_resched;
93:
94: const char *trap_type[] = {
95: "external interrupt",
96: "TLB modification",
97: "TLB miss (load or instr. fetch)",
98: "TLB miss (store)",
99: "address error (load or I-fetch)",
100: "address error (store)",
101: "bus error (I-fetch)",
102: "bus error (load or store)",
103: "system call",
104: "breakpoint",
105: "reserved instruction",
106: "coprocessor unusable",
107: "arithmetic overflow",
108: "r4k trap/r3k reserved 13",
109: "r4k virtual coherency instruction/r3k reserved 14",
110: "r4k floating point/ r3k reserved 15",
111: "reserved 16",
112: "reserved 17",
1.165.2.8! nathanw 113: "mipsNN cp2 exception",
1.165.2.2 wdk 114: "reserved 19",
115: "reserved 20",
116: "reserved 21",
1.165.2.8! nathanw 117: "mips64 MDMX",
! 118: "r4k watch",
! 119: "mipsNN machine check",
1.165.2.2 wdk 120: "reserved 25",
121: "reserved 26",
122: "reserved 27",
123: "reserved 28",
124: "reserved 29",
1.165.2.8! nathanw 125: "mipsNN cache error",
1.165.2.2 wdk 126: "r4000 virtual coherency data",
127: };
128:
1.165.2.8! nathanw 129: void trap(unsigned, unsigned, unsigned, unsigned, struct trapframe *);
! 130: void ast(unsigned);
1.165.2.2 wdk 131:
1.165.2.8! nathanw 132: vaddr_t MachEmulateBranch(struct frame *, vaddr_t, unsigned, int);
! 133: extern void MachEmulateFP(unsigned);
! 134: extern void MachFPInterrupt(unsigned, unsigned, unsigned, struct frame *);
1.165.2.2 wdk 135:
136: #define DELAYBRANCH(x) ((int)(x)<0)
137:
138: /*
139: * fork syscall returns directly to user process via proc_trampoline,
140: * which will be called the very first time when child gets running.
141: */
142: void
143: child_return(arg)
144: void *arg;
145: {
146: struct lwp *l = arg;
147: struct proc *p = l->l_proc;
148: struct frame *frame = (struct frame *)l->l_md.md_regs;
149:
150: frame->f_regs[V0] = 0;
151: frame->f_regs[V1] = 1;
152: frame->f_regs[A3] = 0;
153: userret(l);
154: #ifdef KTRACE
155: if (KTRPOINT(p, KTR_SYSRET))
156: ktrsysret(p, SYS_fork, 0, 0);
157: #endif
158: }
159:
1.165.2.8! nathanw 160: #ifdef MIPS3_PLUS
1.165.2.2 wdk 161: #define TRAPTYPE(x) (((x) & MIPS3_CR_EXC_CODE) >> MIPS_CR_EXC_CODE_SHIFT)
162: #else
163: #define TRAPTYPE(x) (((x) & MIPS1_CR_EXC_CODE) >> MIPS_CR_EXC_CODE_SHIFT)
164: #endif
165: #define KERNLAND(x) ((int)(x) < 0)
166:
167: /*
168: * Trap is called from locore to handle most types of processor traps.
169: * System calls are broken out for efficiency. MIPS can handle software
170: * interrupts as a part of real interrupt processing.
171: */
172: void
173: trap(status, cause, vaddr, opc, frame)
174: unsigned status;
175: unsigned cause;
176: unsigned vaddr;
177: unsigned opc;
178: struct trapframe *frame;
179: {
180: int type, sig;
181: int ucode = 0;
182: struct lwp *l = curproc;
1.165.2.3 wdk 183: struct proc *p;
1.165.2.2 wdk 184: vm_prot_t ftype;
1.165.2.8! nathanw 185: extern void fswintrberr(void);
1.165.2.2 wdk 186:
1.165.2.3 wdk 187: p = l ? l->l_proc : NULL;
1.165.2.2 wdk 188: uvmexp.traps++;
189: type = TRAPTYPE(cause);
190: if (USERMODE(status))
191: type |= T_USER;
192:
193: if (status & ((CPUISMIPS3) ? MIPS_SR_INT_IE : MIPS1_SR_INT_ENA_PREV)) {
194: if (type != T_BREAK) {
195: #ifdef IPL_ICU_MASK
196: spllowersofthigh();
197: #else
198: _splset((status & MIPS_HARD_INT_MASK) | MIPS_SR_INT_IE);
199: #endif
200: }
201: }
202:
203: switch (type) {
204: default:
205: dopanic:
206: (void)splhigh();
207: printf("trap: %s in %s mode\n",
208: trap_type[TRAPTYPE(cause)],
209: USERMODE(status) ? "user" : "kernel");
210: printf("status=0x%x, cause=0x%x, epc=0x%x, vaddr=0x%x\n",
211: status, cause, opc, vaddr);
212: if (curproc != NULL)
213: printf("pid=%d cmd=%s usp=0x%x ",
214: p->p_pid, p->p_comm,
215: (int)((struct frame *)l->l_md.md_regs)->f_regs[SP]);
216: else
217: printf("curproc == NULL ");
218: printf("ksp=0x%x\n", (int)&status);
219: #if defined(DDB)
220: kdb_trap(type, (mips_reg_t *) frame);
221: /* XXX force halt XXX */
222: #elif defined(KGDB)
223: {
224: struct frame *f = (struct frame *)&ddb_regs;
225: extern mips_reg_t kgdb_cause, kgdb_vaddr;
226: kgdb_cause = cause;
227: kgdb_vaddr = vaddr;
228:
229: /*
230: * init global ddb_regs, used in db_interface.c routines
231: * shared between ddb and gdb. Send ddb_regs to gdb so
232: * that db_machdep.h macros will work with it, and
233: * allow gdb to alter the PC.
234: */
235: db_set_ddb_regs(type, (mips_reg_t *) frame);
236: PC_BREAK_ADVANCE(f);
237: if (kgdb_trap(type, &ddb_regs)) {
238: ((mips_reg_t *)frame)[21] = f->f_regs[PC];
239: return;
240: }
241: }
242: #else
243: panic("trap");
244: #endif
245: /*NOTREACHED*/
246: case T_TLB_MOD:
247: if (KERNLAND(vaddr)) {
248: pt_entry_t *pte;
249: unsigned entry;
250: paddr_t pa;
251:
252: pte = kvtopte(vaddr);
253: entry = pte->pt_entry;
254: if (!mips_pg_v(entry) || (entry & mips_pg_m_bit())) {
255: panic("ktlbmod: invalid pte");
256: }
257: if (entry & mips_pg_ro_bit()) {
258: /* write to read only page in the kernel */
259: ftype = VM_PROT_WRITE;
260: goto kernelfault;
261: }
262: entry |= mips_pg_m_bit();
263: pte->pt_entry = entry;
264: vaddr &= ~PGOFSET;
265: MachTLBUpdate(vaddr, entry);
266: pa = mips_tlbpfn_to_paddr(entry);
267: if (!IS_VM_PHYSADDR(pa)) {
268: printf("ktlbmod: va %x pa %llx\n",
269: vaddr, (long long)pa);
270: panic("ktlbmod: unmanaged page");
271: }
272: pmap_set_modified(pa);
273: return; /* KERN */
274: }
275: /*FALLTHROUGH*/
276: case T_TLB_MOD+T_USER:
277: {
278: pt_entry_t *pte;
279: unsigned entry;
280: paddr_t pa;
281: pmap_t pmap;
282:
283: pmap = p->p_vmspace->vm_map.pmap;
284: if (!(pte = pmap_segmap(pmap, vaddr)))
285: panic("utlbmod: invalid segmap");
286: pte += (vaddr >> PGSHIFT) & (NPTEPG - 1);
287: entry = pte->pt_entry;
288: if (!mips_pg_v(entry) || (entry & mips_pg_m_bit()))
289: panic("utlbmod: invalid pte");
290:
291: if (entry & mips_pg_ro_bit()) {
292: /* write to read only page */
293: ftype = VM_PROT_WRITE;
294: goto pagefault;
295: }
296: entry |= mips_pg_m_bit();
297: pte->pt_entry = entry;
298: vaddr = (vaddr & ~PGOFSET) |
299: (pmap->pm_asid << MIPS_TLB_PID_SHIFT);
300: MachTLBUpdate(vaddr, entry);
301: pa = mips_tlbpfn_to_paddr(entry);
302: if (!IS_VM_PHYSADDR(pa)) {
303: printf("utlbmod: va %x pa %llx\n",
304: vaddr, (long long)pa);
305: panic("utlbmod: unmanaged page");
306: }
307: pmap_set_modified(pa);
308: if (type & T_USER)
309: userret(l);
310: return; /* GEN */
311: }
312: case T_TLB_LD_MISS:
313: case T_TLB_ST_MISS:
314: ftype = (type == T_TLB_LD_MISS) ? VM_PROT_READ : VM_PROT_WRITE;
315: if (KERNLAND(vaddr))
316: goto kernelfault;
317: /*
318: * It is an error for the kernel to access user space except
319: * through the copyin/copyout routines.
320: */
1.165.2.4 nathanw 321: if (l == NULL || l->l_addr->u_pcb.pcb_onfault == NULL)
1.165.2.2 wdk 322: goto dopanic;
323: /* check for fuswintr() or suswintr() getting a page fault */
324: if (l->l_addr->u_pcb.pcb_onfault == (caddr_t)fswintrberr) {
325: frame->tf_epc = (int)fswintrberr;
326: return; /* KERN */
327: }
328: goto pagefault;
329: case T_TLB_LD_MISS+T_USER:
330: ftype = VM_PROT_READ;
331: goto pagefault;
332: case T_TLB_ST_MISS+T_USER:
333: ftype = VM_PROT_WRITE;
334: pagefault: ;
335: {
336: vaddr_t va;
337: struct vmspace *vm;
338: struct vm_map *map;
339: int rv;
340:
341: vm = p->p_vmspace;
342: map = &vm->vm_map;
343: va = trunc_page(vaddr);
344: rv = uvm_fault(map, va, 0, ftype);
345: #ifdef VMFAULT_TRACE
346: printf(
1.165.2.8! nathanw 347: "uvm_fault(%p (pmap %p), %lx (0x%x), 0, %d) -> %d at pc %p\n",
1.165.2.2 wdk 348: map, vm->vm_map.pmap, va, vaddr, ftype, rv, (void*)opc);
349: #endif
350: /*
351: * If this was a stack access we keep track of the maximum
352: * accessed stack size. Also, if vm_fault gets a protection
353: * failure it is due to accessing the stack region outside
354: * the current limit and we need to reflect that as an access
355: * error.
356: */
357: if ((caddr_t)va >= vm->vm_maxsaddr) {
358: if (rv == 0) {
359: unsigned nss;
360:
361: nss = btoc(USRSTACK-(unsigned)va);
362: if (nss > vm->vm_ssize)
363: vm->vm_ssize = nss;
364: }
365: else if (rv == EACCES)
366: rv = EFAULT;
367: }
368: if (rv == 0) {
369: if (type & T_USER) {
370: userret(l);
371: }
372: return; /* GEN */
373: }
374: if ((type & T_USER) == 0)
375: goto copyfault;
376: if (rv == ENOMEM) {
377: printf("UVM: pid %d (%s), uid %d killed: out of swap\n",
378: p->p_pid, p->p_comm,
379: p->p_cred && p->p_ucred ?
380: p->p_ucred->cr_uid : -1);
381: sig = SIGKILL;
382: } else {
383: sig = (rv == EACCES) ? SIGBUS : SIGSEGV;
384: }
385: ucode = vaddr;
386: break; /* SIGNAL */
387: }
388: kernelfault: ;
389: {
390: vaddr_t va;
391: int rv;
392:
393: va = trunc_page(vaddr);
394: rv = uvm_fault(kernel_map, va, 0, ftype);
395: if (rv == 0)
396: return; /* KERN */
397: /*FALLTHROUGH*/
398: }
399: case T_ADDR_ERR_LD: /* misaligned access */
400: case T_ADDR_ERR_ST: /* misaligned access */
401: case T_BUS_ERR_LD_ST: /* BERR asserted to cpu */
402: copyfault:
1.165.2.4 nathanw 403: if (l == NULL || l->l_addr->u_pcb.pcb_onfault == NULL)
1.165.2.2 wdk 404: goto dopanic;
405: frame->tf_epc = (int)l->l_addr->u_pcb.pcb_onfault;
406: return; /* KERN */
407:
408: case T_ADDR_ERR_LD+T_USER: /* misaligned or kseg access */
409: case T_ADDR_ERR_ST+T_USER: /* misaligned or kseg access */
410: case T_BUS_ERR_IFETCH+T_USER: /* BERR asserted to cpu */
411: case T_BUS_ERR_LD_ST+T_USER: /* BERR asserted to cpu */
412: sig = SIGSEGV;
413: ucode = vaddr;
414: break; /* SIGNAL */
415:
416: case T_BREAK:
417: #if defined(DDB)
418: kdb_trap(type, (mips_reg_t *) frame);
419: return; /* KERN */
420: #elif defined(KGDB)
421: {
422: struct frame *f = (struct frame *)&ddb_regs;
423: extern mips_reg_t kgdb_cause, kgdb_vaddr;
424: kgdb_cause = cause;
425: kgdb_vaddr = vaddr;
426:
427: /*
428: * init global ddb_regs, used in db_interface.c routines
429: * shared between ddb and gdb. Send ddb_regs to gdb so
430: * that db_machdep.h macros will work with it, and
431: * allow gdb to alter the PC.
432: */
433: db_set_ddb_regs(type, (mips_reg_t *) frame);
434: PC_BREAK_ADVANCE(f);
435: if (!kgdb_trap(type, &ddb_regs))
436: printf("kgdb: ignored %s\n",
437: trap_type[TRAPTYPE(cause)]);
438: else
439: ((mips_reg_t *)frame)[21] = f->f_regs[PC];
440:
441: return;
442: }
443: #else
444: goto dopanic;
445: #endif
446: case T_BREAK+T_USER:
447: {
448: unsigned va, instr;
449: int rv;
450:
451: /* compute address of break instruction */
452: va = (DELAYBRANCH(cause)) ? opc + sizeof(int) : opc;
453:
454: /* read break instruction */
455: instr = fuiword((void *)va);
456:
457: if (l->l_md.md_ss_addr != va || instr != MIPS_BREAK_SSTEP) {
458: sig = SIGTRAP;
459: break;
460: }
461: /*
462: * Restore original instruction and clear BP
463: */
464: rv = suiword((void *)va, l->l_md.md_ss_instr);
465: if (rv < 0) {
466: vaddr_t sa, ea;
467: sa = trunc_page(va);
468: ea = round_page(va + sizeof(int) - 1);
469: rv = uvm_map_protect(&p->p_vmspace->vm_map,
470: sa, ea, VM_PROT_DEFAULT, FALSE);
471: if (rv == 0) {
472: rv = suiword((void *)va, MIPS_BREAK_SSTEP);
473: (void)uvm_map_protect(&p->p_vmspace->vm_map,
474: sa, ea, VM_PROT_READ|VM_PROT_EXECUTE, FALSE);
475: }
476: }
477: mips_icache_sync_all(); /* XXXJRT -- necessary? */
478: mips_dcache_wbinv_all(); /* XXXJRT -- necessary? */
479:
480: if (rv < 0)
481: printf("Warning: can't restore instruction at 0x%x: 0x%x\n",
482: l->l_md.md_ss_addr, l->l_md.md_ss_instr);
483: l->l_md.md_ss_addr = 0;
484: sig = SIGTRAP;
485: break; /* SIGNAL */
486: }
487: case T_RES_INST+T_USER:
488: #if defined(MIPS3_5900) && defined(SOFTFLOAT)
489: MachFPInterrupt(status, cause, opc, p->p_md.md_regs);
490: userret(l);
491: return; /* GEN */
492: #else
493: sig = SIGILL;
494: break; /* SIGNAL */
495: #endif
496: break; /* SIGNAL */
497: case T_COP_UNUSABLE+T_USER:
498: #if defined(NOFPU) && !defined(SOFTFLOAT)
499: sig = SIGILL;
500: break; /* SIGNAL */
501: #endif
502: if ((cause & MIPS_CR_COP_ERR) != 0x10000000) {
503: sig = SIGILL; /* only FPU instructions allowed */
504: break; /* SIGNAL */
505: }
506: #ifndef SOFTFLOAT
507: {
508: struct frame *f;
509:
510: f = (struct frame *)l->l_md.md_regs;
511: savefpregs(l); /* yield FPA */
512: loadfpregs(l); /* load FPA */
513: fpcurproc = l;
514: l->l_md.md_flags |= MDP_FPUSED;
515: f->f_regs[SR] |= MIPS_SR_COP_1_BIT;
516: }
517: #else
518: MachFPInterrupt(status, cause, opc, p->p_md.md_regs);
519: #endif
520: userret(l);
521: return; /* GEN */
522: case T_FPE+T_USER:
523: #if !defined(NOFPU) || defined(SOFTFLOAT)
524: MachFPInterrupt(status, cause, opc, l->l_md.md_regs);
525: #endif
526: userret(l);
527: return; /* GEN */
528: case T_OVFLOW+T_USER:
529: case T_TRAP+T_USER:
530: sig = SIGFPE;
531: break; /* SIGNAL */
532: }
533: ((struct frame *)l->l_md.md_regs)->f_regs[CAUSE] = cause;
534: ((struct frame *)l->l_md.md_regs)->f_regs[BADVADDR] = vaddr;
535: trapsignal(l, sig, ucode);
536: if ((type & T_USER) == 0)
537: panic("trapsignal");
538: userret(l);
539: return;
540: }
541:
542: /*
543: * Software (low priority) network interrupt. i.e. softnet().
544: */
545: void
546: netintr()
547: {
548: #define DONETISR(bit, fn) \
549: do { \
550: if (n & (1 << bit)) \
551: fn(); \
552: } while (0)
553:
554: int n;
555: n = netisr; netisr = 0;
556:
557: #ifdef SOFTNET_INTR /* XXX TEMPORARY XXX */
558: intrcnt[SOFTNET_INTR]++;
559: #endif
560:
561: #include <net/netisr_dispatch.h>
562:
563: #undef DONETISR
564: }
565:
566: /*
567: * Handle asynchronous software traps.
568: * This is called from MachUserIntr() either to deliver signals or
569: * to make involuntary context switch (preemption).
570: */
571: void
572: ast(pc)
573: unsigned pc; /* program counter where to continue */
574: {
575: struct lwp *l = curproc;
576: struct proc *p = l->l_proc;
577: int sig;
578:
579: while (p->p_md.md_astpending) {
580: uvmexp.softs++;
581: p->p_md.md_astpending = 0;
582:
583: if (p->p_flag & P_OWEUPC) {
584: p->p_flag &= ~P_OWEUPC;
585: ADDUPROF(p);
586: }
587:
588: /* Take pending signals. */
589: while ((sig = CURSIG(l)) != 0)
590: postsig(sig);
591:
592: if (want_resched) {
593: /*
594: * We are being preempted.
595: */
596: preempt(NULL);
597: }
598:
599: userret(l);
600: }
601: }
602:
603: /*
604: * Analyse 'next' PC address taking account of branch/jump instructions
605: */
606: vaddr_t
607: MachEmulateBranch(f, instpc, fpuCSR, allowNonBranch)
608: struct frame *f;
609: vaddr_t instpc;
610: unsigned fpuCSR;
611: int allowNonBranch;
612: {
613: #define BRANCHTARGET(p) (4 + (p) + ((short)((InstFmt *)(p))->IType.imm << 2))
614: InstFmt inst;
615: vaddr_t nextpc;
616:
617: if (instpc < MIPS_KSEG0_START)
618: inst.word = fuiword((void *)instpc);
619: else
620: inst.word = *(unsigned *)instpc;
621:
622: switch ((int)inst.JType.op) {
623: case OP_SPECIAL:
624: if (inst.RType.func == OP_JR || inst.RType.func == OP_JALR)
625: nextpc = f->f_regs[inst.RType.rs];
626: else if (allowNonBranch)
627: nextpc = instpc + 4;
628: else
629: panic("MachEmulateBranch: Non-branch");
630: break;
631:
632: case OP_BCOND:
633: switch ((int)inst.IType.rt) {
634: case OP_BLTZ:
635: case OP_BLTZAL:
636: case OP_BLTZL: /* squashed */
637: case OP_BLTZALL: /* squashed */
638: if ((int)(f->f_regs[inst.RType.rs]) < 0)
639: nextpc = BRANCHTARGET(instpc);
640: else
641: nextpc = instpc + 8;
642: break;
643:
644: case OP_BGEZ:
645: case OP_BGEZAL:
646: case OP_BGEZL: /* squashed */
647: case OP_BGEZALL: /* squashed */
648: if ((int)(f->f_regs[inst.RType.rs]) >= 0)
649: nextpc = BRANCHTARGET(instpc);
650: else
651: nextpc = instpc + 8;
652: break;
653:
654: default:
655: panic("MachEmulateBranch: Bad branch cond");
656: }
657: break;
658:
659: case OP_J:
660: case OP_JAL:
661: nextpc = (inst.JType.target << 2) |
662: ((unsigned)instpc & 0xF0000000);
663: break;
664:
665: case OP_BEQ:
666: case OP_BEQL: /* squashed */
667: if (f->f_regs[inst.RType.rs] == f->f_regs[inst.RType.rt])
668: nextpc = BRANCHTARGET(instpc);
669: else
670: nextpc = instpc + 8;
671: break;
672:
673: case OP_BNE:
674: case OP_BNEL: /* squashed */
675: if (f->f_regs[inst.RType.rs] != f->f_regs[inst.RType.rt])
676: nextpc = BRANCHTARGET(instpc);
677: else
678: nextpc = instpc + 8;
679: break;
680:
681: case OP_BLEZ:
682: case OP_BLEZL: /* squashed */
683: if ((int)(f->f_regs[inst.RType.rs]) <= 0)
684: nextpc = BRANCHTARGET(instpc);
685: else
686: nextpc = instpc + 8;
687: break;
688:
689: case OP_BGTZ:
690: case OP_BGTZL: /* squashed */
691: if ((int)(f->f_regs[inst.RType.rs]) > 0)
692: nextpc = BRANCHTARGET(instpc);
693: else
694: nextpc = instpc + 8;
695: break;
696:
697: case OP_COP1:
698: if (inst.RType.rs == OP_BCx || inst.RType.rs == OP_BCy) {
699: int condition = (fpuCSR & MIPS_FPU_COND_BIT) != 0;
700: if ((inst.RType.rt & COPz_BC_TF_MASK) != COPz_BC_TRUE)
701: condition = !condition;
702: if (condition)
703: nextpc = BRANCHTARGET(instpc);
704: else
705: nextpc = instpc + 8;
706: }
707: else if (allowNonBranch)
708: nextpc = instpc + 4;
709: else
710: panic("MachEmulateBranch: Bad COP1 branch instruction");
711: break;
712:
713: default:
714: if (!allowNonBranch)
715: panic("MachEmulateBranch: Non-branch instruction");
716: nextpc = instpc + 4;
717: }
718: return nextpc;
719: #undef BRANCHTARGET
720: }
721:
722: /* XXX need to rewrite acient comment XXX
723: * This routine is called by procxmt() to single step one instruction.
724: * We do this by storing a break instruction after the current instruction,
725: * resuming execution, and then restoring the old instruction.
726: */
727: int
728: mips_singlestep(l)
729: struct lwp *l;
730: {
731: struct frame *f = (struct frame *)l->l_md.md_regs;
732: struct proc *p = l->l_proc;
733: vaddr_t pc, va;
734: int rv;
735:
736: if (l->l_md.md_ss_addr) {
737: printf("SS %s (%d): breakpoint already set at %x\n",
738: p->p_comm, p->p_pid, l->l_md.md_ss_addr);
739: return EFAULT;
740: }
741: pc = (vaddr_t)f->f_regs[PC];
742: if (fuiword((void *)pc) != 0) /* not a NOP instruction */
743: va = MachEmulateBranch(f, pc,
1.165.2.7 nathanw 744: PCB_FSR(&l->l_addr->u_pcb), 1);
1.165.2.2 wdk 745: else
746: va = pc + sizeof(int);
747: l->l_md.md_ss_addr = va;
748: l->l_md.md_ss_instr = fuiword((void *)va);
749: rv = suiword((void *)va, MIPS_BREAK_SSTEP);
750: if (rv < 0) {
751: vaddr_t sa, ea;
752: sa = trunc_page(va);
753: ea = round_page(va + sizeof(int) - 1);
754: rv = uvm_map_protect(&p->p_vmspace->vm_map,
755: sa, ea, VM_PROT_DEFAULT, FALSE);
756: if (rv == 0) {
757: rv = suiword((void *)va, MIPS_BREAK_SSTEP);
758: (void)uvm_map_protect(&p->p_vmspace->vm_map,
759: sa, ea, VM_PROT_READ|VM_PROT_EXECUTE, FALSE);
760: }
761: }
762: #if 0
763: printf("SS %s (%d): breakpoint set at %x: %x (pc %x) br %x\n",
764: p->p_comm, p->p_pid, p->p_md.md_ss_addr,
765: p->p_md.md_ss_instr, pc, fuword((void *)va)); /* XXX */
766: #endif
767: return 0;
768: }
769:
770:
771: #ifndef DDB_TRACE
772:
773: #if defined(DEBUG) || defined(DDB) || defined(KGDB) || defined(geo)
1.165.2.8! nathanw 774: mips_reg_t kdbrpeek(vaddr_t);
1.165.2.2 wdk 775:
776: int
777: kdbpeek(addr)
778: vaddr_t addr;
779: {
780: int rc;
781: if (addr & 3) {
782: printf("kdbpeek: unaligned address %lx\n", addr);
783: /* We might have been called from DDB, so do not go there. */
784: stacktrace();
785: rc = -1 ;
786: } else if (addr == NULL) {
787: printf("kdbpeek: NULL\n");
788: rc = 0xdeadfeed;
789: } else {
790: rc = *(int *)addr;
791: }
792: return rc;
793: }
794:
795: mips_reg_t
796: kdbrpeek(addr)
797: vaddr_t addr;
798: {
799: mips_reg_t rc;
800: if (addr & (sizeof(mips_reg_t) - 1)) {
801: printf("kdbrpeek: unaligned address %lx\n", addr);
802: /* We might have been called from DDB, so do not go there. */
803: stacktrace();
804: rc = -1 ;
805: } else if (addr == NULL) {
806: printf("kdbrpeek: NULL\n");
807: rc = 0xdeadfeed;
808: } else {
809: rc = *(mips_reg_t *)addr;
810: }
811: return rc;
812: }
813:
814: extern char start[], edata[], verylocore[];
815: extern char mips1_KernGenException[];
816: extern char mips1_UserGenException[];
817: extern char mips1_KernIntr[];
818: extern char mips1_UserIntr[];
819: extern char mips1_SystemCall[];
820: extern char mips3_KernGenException[];
821: extern char mips3_UserGenException[];
822: extern char mips3_KernIntr[];
823: extern char mips3_UserIntr[];
824: extern char mips3_SystemCall[];
1.165.2.8! nathanw 825: extern int main(void *);
! 826: extern void mips_idle(void);
! 827: extern void cpu_switch(struct lwp *);
1.165.2.2 wdk 828:
829: /*
830: * stack trace code, also useful to DDB one day
831: */
832:
833: /* forward */
834: char *fn_name(unsigned addr);
1.165.2.8! nathanw 835: void stacktrace_subr(int, int, int, int, u_int, u_int, u_int, u_int,
! 836: void (*)(const char*, ...));
1.165.2.2 wdk 837:
838: #define MIPS_JR_RA 0x03e00008 /* instruction code for jr ra */
839: #define MIPS_JR_K0 0x03400008 /* instruction code for jr k0 */
840: #define MIPS_ERET 0x42000018 /* instruction code for eret */
841:
842: /*
843: * Do a stack backtrace.
844: * (*printfn)() prints the output to either the system log,
845: * the console, or both.
846: */
847: void
848: stacktrace_subr(a0, a1, a2, a3, pc, sp, fp, ra, printfn)
849: int a0, a1, a2, a3;
850: u_int pc, sp, fp, ra;
1.165.2.8! nathanw 851: void (*printfn)(const char*, ...);
1.165.2.2 wdk 852: {
853: unsigned va, subr;
854: unsigned instr, mask;
855: InstFmt i;
856: int more, stksize;
857: unsigned int frames = 0;
858: int foundframesize = 0;
859:
860: /* Jump here when done with a frame, to start a new one */
861: loop:
862: stksize = 0;
863: subr = 0;
864: if (frames++ > 100) {
865: (*printfn)("\nstackframe count exceeded\n");
866: /* return breaks stackframe-size heuristics with gcc -O2 */
867: goto finish; /*XXX*/
868: }
869:
870: /* check for bad SP: could foul up next frame */
871: if (sp & 3 || sp < 0x80000000) {
872: (*printfn)("SP 0x%x: not in kernel\n", sp);
873: ra = 0;
874: subr = 0;
875: goto done;
876: }
877:
878: /* Check for bad PC */
879: if (pc & 3 || pc < 0x80000000 || pc >= (unsigned)edata) {
880: (*printfn)("PC 0x%x: not in kernel space\n", pc);
881: ra = 0;
882: goto done;
883: }
884:
885: /*
886: * Find the beginning of the current subroutine by scanning backwards
887: * from the current PC for the end of the previous subroutine.
888: */
889: va = pc;
890: do {
891: va -= sizeof(int);
892: if (va <= (unsigned)verylocore)
893: goto finish;
894: instr = kdbpeek(va);
895: if (instr == MIPS_ERET)
896: goto mips3_eret;
897: } while (instr != MIPS_JR_RA && instr != MIPS_JR_K0);
898: /* skip back over branch & delay slot */
899: va += sizeof(int);
900: mips3_eret:
901: va += sizeof(int);
902: /* skip over nulls which might separate .o files */
903: while ((instr = kdbpeek(va)) == 0)
904: va += sizeof(int);
905: subr = va;
906:
907: /* scan forwards to find stack size and any saved registers */
908: stksize = 0;
909: more = 3;
910: mask = 0;
911: foundframesize = 0;
912: for (va = subr; more; va += sizeof(int),
913: more = (more == 3) ? 3 : more - 1) {
914: /* stop if hit our current position */
915: if (va >= pc)
916: break;
917: instr = kdbpeek(va);
918: i.word = instr;
919: switch (i.JType.op) {
920: case OP_SPECIAL:
921: switch (i.RType.func) {
922: case OP_JR:
923: case OP_JALR:
924: more = 2; /* stop after next instruction */
925: break;
926:
927: case OP_SYSCALL:
928: case OP_BREAK:
929: more = 1; /* stop now */
930: };
931: break;
932:
933: case OP_BCOND:
934: case OP_J:
935: case OP_JAL:
936: case OP_BEQ:
937: case OP_BNE:
938: case OP_BLEZ:
939: case OP_BGTZ:
940: more = 2; /* stop after next instruction */
941: break;
942:
943: case OP_COP0:
944: case OP_COP1:
945: case OP_COP2:
946: case OP_COP3:
947: switch (i.RType.rs) {
948: case OP_BCx:
949: case OP_BCy:
950: more = 2; /* stop after next instruction */
951: };
952: break;
953:
954: case OP_SW:
955: /* look for saved registers on the stack */
956: if (i.IType.rs != 29)
957: break;
958: /* only restore the first one */
959: if (mask & (1 << i.IType.rt))
960: break;
961: mask |= (1 << i.IType.rt);
962: switch (i.IType.rt) {
963: case 4: /* a0 */
964: a0 = kdbpeek(sp + (short)i.IType.imm);
965: break;
966:
967: case 5: /* a1 */
968: a1 = kdbpeek(sp + (short)i.IType.imm);
969: break;
970:
971: case 6: /* a2 */
972: a2 = kdbpeek(sp + (short)i.IType.imm);
973: break;
974:
975: case 7: /* a3 */
976: a3 = kdbpeek(sp + (short)i.IType.imm);
977: break;
978:
979: case 30: /* fp */
980: fp = kdbpeek(sp + (short)i.IType.imm);
981: break;
982:
983: case 31: /* ra */
984: ra = kdbpeek(sp + (short)i.IType.imm);
985: }
986: break;
987:
988: case OP_ADDI:
989: case OP_ADDIU:
990: /* look for stack pointer adjustment */
991: if (i.IType.rs != 29 || i.IType.rt != 29)
992: break;
993: /* don't count pops for mcount */
994: if (!foundframesize) {
995: stksize = - ((short)i.IType.imm);
996: foundframesize = 1;
997: }
998: }
999: }
1000: done:
1001: (*printfn)("%s+%x (%x,%x,%x,%x) ra %x sz %d\n",
1002: fn_name(subr), pc - subr, a0, a1, a2, a3, ra, stksize);
1003:
1004: if (ra) {
1005: if (pc == ra && stksize == 0)
1006: (*printfn)("stacktrace: loop!\n");
1007: else {
1008: pc = ra;
1009: sp += stksize;
1010: ra = 0;
1011: goto loop;
1012: }
1013: } else {
1014: finish:
1.165.2.6 gmcgarry 1015: if (curproc != NULL && curproc->l_proc != NULL)
1.165.2.2 wdk 1016: (*printfn)("User-level: pid %d\n",
1017: curproc->l_proc->p_pid);
1018: else
1019: (*printfn)("User-level: curproc NULL\n");
1020: }
1021: }
1022:
1023: /*
1024: * Functions ``special'' enough to print by name
1025: */
1026: #ifdef __STDC__
1027: #define Name(_fn) { (void*)_fn, # _fn }
1028: #else
1029: #define Name(_fn) { _fn, "_fn"}
1030: #endif
1031: static struct { void *addr; char *name;} names[] = {
1032: Name(stacktrace),
1033: Name(stacktrace_subr),
1034: Name(main),
1035: Name(trap),
1036:
1037: #ifdef MIPS1 /* r2000 family (mips-I cpu) */
1038: Name(mips1_KernGenException),
1039: Name(mips1_UserGenException),
1040: Name(mips1_SystemCall),
1041: Name(mips1_KernIntr),
1042: Name(mips1_UserIntr),
1043: #endif /* MIPS1 */
1044:
1.165.2.8! nathanw 1045: /* XXX simonb: need mips32 and mips64 checks here too */
! 1046: #if defined(MIPS3) && !defined(MIPS3_5900) /* r4000 family (mips-III cpu) */
1.165.2.2 wdk 1047: Name(mips3_KernGenException),
1048: Name(mips3_UserGenException),
1049: Name(mips3_SystemCall),
1050: Name(mips3_KernIntr),
1051: Name(mips3_UserIntr),
1.165.2.8! nathanw 1052: #endif /* MIPS3 && !MIPS3_5900 */
1.165.2.2 wdk 1053:
1054: Name(mips_idle),
1055: Name(cpu_switch),
1056: {0, 0}
1057: };
1058:
1059: /*
1060: * Map a function address to a string name, if known; or a hex string.
1061: */
1062: char *
1063: fn_name(unsigned addr)
1064: {
1065: static char buf[17];
1066: int i = 0;
1067: #ifdef DDB
1068: db_expr_t diff;
1069: db_sym_t sym;
1070: char *symname;
1071: #endif
1072:
1073: #ifdef DDB
1074: diff = 0;
1075: symname = NULL;
1076: sym = db_search_symbol(addr, DB_STGY_ANY, &diff);
1077: db_symbol_values(sym, &symname, 0);
1078: if (symname && diff == 0)
1079: return (symname);
1080: #endif
1081: for (i = 0; names[i].name; i++)
1082: if (names[i].addr == (void*)addr)
1083: return (names[i].name);
1084: sprintf(buf, "%x", addr);
1085: return (buf);
1086: }
1087:
1088: #endif /* DEBUG */
1089:
1090: #endif /* DDB_TRACE */
CVSweb <webmaster@jp.NetBSD.org>