xref: /netbsd/sys/arch/mips/mips/trap.c (revision c4a72b64)
1 /*	$NetBSD: trap.c,v 1.175 2002/11/09 20:06:07 thorpej Exp $	*/
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 
47 __KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.175 2002/11/09 20:06:07 thorpej Exp $");
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/ras.h>
59 #include <sys/signalvar.h>
60 #include <sys/syscall.h>
61 #include <sys/user.h>
62 #include <sys/buf.h>
63 #ifdef KTRACE
64 #include <sys/ktrace.h>
65 #endif
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",
113 	"mipsNN cp2 exception",
114 	"reserved 19",
115 	"reserved 20",
116 	"reserved 21",
117 	"mips64 MDMX",
118 	"r4k watch",
119 	"mipsNN machine check",
120 	"reserved 25",
121 	"reserved 26",
122 	"reserved 27",
123 	"reserved 28",
124 	"reserved 29",
125 	"mipsNN cache error",
126 	"r4000 virtual coherency data",
127 };
128 
129 void trap(unsigned, unsigned, unsigned, unsigned, struct trapframe *);
130 void ast(unsigned);
131 
132 extern vaddr_t MachEmulateBranch(struct frame *, vaddr_t, unsigned, int);
133 extern void MachEmulateInst(u_int32_t, u_int32_t, u_int32_t, struct frame *);
134 extern void MachFPTrap(u_int32_t, u_int32_t, u_int32_t, struct frame *);
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 proc *p = arg;
147 	struct frame *frame = (struct frame *)p->p_md.md_regs;
148 
149 	frame->f_regs[V0] = 0;
150 	frame->f_regs[V1] = 1;
151 	frame->f_regs[A3] = 0;
152 	userret(p);
153 #ifdef KTRACE
154 	if (KTRPOINT(p, KTR_SYSRET))
155 		ktrsysret(p, SYS_fork, 0, 0);
156 #endif
157 }
158 
159 #ifdef MIPS3_PLUS
160 #define TRAPTYPE(x) (((x) & MIPS3_CR_EXC_CODE) >> MIPS_CR_EXC_CODE_SHIFT)
161 #else
162 #define TRAPTYPE(x) (((x) & MIPS1_CR_EXC_CODE) >> MIPS_CR_EXC_CODE_SHIFT)
163 #endif
164 #define KERNLAND(x) ((int)(x) < 0)
165 
166 /*
167  * Trap is called from locore to handle most types of processor traps.
168  * System calls are broken out for efficiency.  MIPS can handle software
169  * interrupts as a part of real interrupt processing.
170  */
171 void
172 trap(status, cause, vaddr, opc, frame)
173 	unsigned status;
174 	unsigned cause;
175 	unsigned vaddr;
176 	unsigned opc;
177 	struct trapframe *frame;
178 {
179 	int type, sig;
180 	int ucode = 0;
181 	struct proc *p = curproc;
182 	vm_prot_t ftype;
183 	extern void fswintrberr(void);
184 
185 	uvmexp.traps++;
186 	type = TRAPTYPE(cause);
187 	if (USERMODE(status))
188 		type |= T_USER;
189 
190 	if (status & ((CPUISMIPS3) ? MIPS_SR_INT_IE : MIPS1_SR_INT_ENA_PREV)) {
191 		if (type != T_BREAK) {
192 #ifdef IPL_ICU_MASK
193 			spllowersofthigh();
194 #else
195 			_splset((status & MIPS_HARD_INT_MASK) | MIPS_SR_INT_IE);
196 #endif
197 		}
198 	}
199 
200 	switch (type) {
201 	default:
202 	dopanic:
203 		(void)splhigh();
204 		printf("trap: %s in %s mode\n",
205 			trap_type[TRAPTYPE(cause)],
206 			USERMODE(status) ? "user" : "kernel");
207 		printf("status=0x%x, cause=0x%x, epc=0x%x, vaddr=0x%x\n",
208 			status, cause, opc, vaddr);
209 		if (curproc != NULL)
210 			printf("pid=%d cmd=%s usp=0x%x ",
211 			    p->p_pid, p->p_comm,
212 			    (int)((struct frame *)p->p_md.md_regs)->f_regs[SP]);
213 		else
214 			printf("curproc == NULL ");
215 		printf("ksp=0x%x\n", (int)&status);
216 #if defined(DDB)
217 		kdb_trap(type, (mips_reg_t *) frame);
218 		/* XXX force halt XXX */
219 #elif defined(KGDB)
220 		{
221 			struct frame *f = (struct frame *)&ddb_regs;
222 			extern mips_reg_t kgdb_cause, kgdb_vaddr;
223 			kgdb_cause = cause;
224 			kgdb_vaddr = vaddr;
225 
226 			/*
227 			 * init global ddb_regs, used in db_interface.c routines
228 			 * shared between ddb and gdb. Send ddb_regs to gdb so
229 			 * that db_machdep.h macros will work with it, and
230 			 * allow gdb to alter the PC.
231 			 */
232 			db_set_ddb_regs(type, (mips_reg_t *) frame);
233 			PC_BREAK_ADVANCE(f);
234 			if (kgdb_trap(type, &ddb_regs)) {
235 				((mips_reg_t *)frame)[21] = f->f_regs[PC];
236 				return;
237 			}
238 		}
239 #else
240 		panic("trap");
241 #endif
242 		/*NOTREACHED*/
243 	case T_TLB_MOD:
244 		if (KERNLAND(vaddr)) {
245 			pt_entry_t *pte;
246 			unsigned entry;
247 			paddr_t pa;
248 
249 			pte = kvtopte(vaddr);
250 			entry = pte->pt_entry;
251 			if (!mips_pg_v(entry) || (entry & mips_pg_m_bit())) {
252 				panic("ktlbmod: invalid pte");
253 			}
254 			if (entry & mips_pg_ro_bit()) {
255 				/* write to read only page in the kernel */
256 				ftype = VM_PROT_WRITE;
257 				goto kernelfault;
258 			}
259 			entry |= mips_pg_m_bit();
260 			pte->pt_entry = entry;
261 			vaddr &= ~PGOFSET;
262 			MachTLBUpdate(vaddr, entry);
263 			pa = mips_tlbpfn_to_paddr(entry);
264 			if (!IS_VM_PHYSADDR(pa)) {
265 				printf("ktlbmod: va %x pa %llx\n",
266 				    vaddr, (long long)pa);
267 				panic("ktlbmod: unmanaged page");
268 			}
269 			pmap_set_modified(pa);
270 			return; /* KERN */
271 		}
272 		/*FALLTHROUGH*/
273 	case T_TLB_MOD+T_USER:
274 	    {
275 		pt_entry_t *pte;
276 		unsigned entry;
277 		paddr_t pa;
278 		pmap_t pmap;
279 
280 		pmap  = p->p_vmspace->vm_map.pmap;
281 		if (!(pte = pmap_segmap(pmap, vaddr)))
282 			panic("utlbmod: invalid segmap");
283 		pte += (vaddr >> PGSHIFT) & (NPTEPG - 1);
284 		entry = pte->pt_entry;
285 		if (!mips_pg_v(entry) || (entry & mips_pg_m_bit()))
286 			panic("utlbmod: invalid pte");
287 
288 		if (entry & mips_pg_ro_bit()) {
289 			/* write to read only page */
290 			ftype = VM_PROT_WRITE;
291 			goto pagefault;
292 		}
293 		entry |= mips_pg_m_bit();
294 		pte->pt_entry = entry;
295 		vaddr = (vaddr & ~PGOFSET) |
296 			(pmap->pm_asid << MIPS_TLB_PID_SHIFT);
297 		MachTLBUpdate(vaddr, entry);
298 		pa = mips_tlbpfn_to_paddr(entry);
299 		if (!IS_VM_PHYSADDR(pa)) {
300 			printf("utlbmod: va %x pa %llx\n",
301 			    vaddr, (long long)pa);
302 			panic("utlbmod: unmanaged page");
303 		}
304 		pmap_set_modified(pa);
305 		if (type & T_USER)
306 			userret(p);
307 		return; /* GEN */
308 	    }
309 	case T_TLB_LD_MISS:
310 	case T_TLB_ST_MISS:
311 		ftype = (type == T_TLB_LD_MISS) ? VM_PROT_READ : VM_PROT_WRITE;
312 		if (KERNLAND(vaddr))
313 			goto kernelfault;
314 		/*
315 		 * It is an error for the kernel to access user space except
316 		 * through the copyin/copyout routines.
317 		 */
318 		if (p == NULL || p->p_addr->u_pcb.pcb_onfault == NULL)
319 			goto dopanic;
320 		/* check for fuswintr() or suswintr() getting a page fault */
321 		if (p->p_addr->u_pcb.pcb_onfault == (caddr_t)fswintrberr) {
322 			frame->tf_regs[TF_EPC] = (int)fswintrberr;
323 			return; /* KERN */
324 		}
325 		goto pagefault;
326 	case T_TLB_LD_MISS+T_USER:
327 		ftype = VM_PROT_READ;
328 		goto pagefault;
329 	case T_TLB_ST_MISS+T_USER:
330 		ftype = VM_PROT_WRITE;
331 	pagefault: ;
332 	    {
333 		vaddr_t va;
334 		struct vmspace *vm;
335 		struct vm_map *map;
336 		int rv;
337 
338 		vm = p->p_vmspace;
339 		map = &vm->vm_map;
340 		va = trunc_page(vaddr);
341 
342 		if (p->p_emul->e_fault)
343 			rv = (*p->p_emul->e_fault)(p, va, 0, ftype);
344 		else
345 			rv = uvm_fault(map, va, 0, ftype);
346 #ifdef VMFAULT_TRACE
347 		printf(
348 	    "uvm_fault(%p (pmap %p), %lx (0x%x), 0, %d) -> %d at pc %p\n",
349 		    map, vm->vm_map.pmap, va, vaddr, ftype, rv, (void*)opc);
350 #endif
351 		/*
352 		 * If this was a stack access we keep track of the maximum
353 		 * accessed stack size.  Also, if vm_fault gets a protection
354 		 * failure it is due to accessing the stack region outside
355 		 * the current limit and we need to reflect that as an access
356 		 * error.
357 		 */
358 		if ((caddr_t)va >= vm->vm_maxsaddr) {
359 			if (rv == 0) {
360 				segsz_t nss;
361 
362 				nss = btoc(USRSTACK - va);
363 				if (nss > vm->vm_ssize)
364 					vm->vm_ssize = nss;
365 			}
366 			else if (rv == EACCES)
367 				rv = EFAULT;
368 		}
369 		if (rv == 0) {
370 			if (type & T_USER) {
371 				userret(p);
372 			}
373 			return; /* GEN */
374 		}
375 		if ((type & T_USER) == 0)
376 			goto copyfault;
377 		if (rv == ENOMEM) {
378 			printf("UVM: pid %d (%s), uid %d killed: out of swap\n",
379 			       p->p_pid, p->p_comm,
380 			       p->p_cred && p->p_ucred ?
381 			       p->p_ucred->cr_uid : (uid_t) -1);
382 			sig = SIGKILL;
383 		} else {
384 			sig = (rv == EACCES) ? SIGBUS : SIGSEGV;
385 		}
386 		ucode = vaddr;
387 		break; /* SIGNAL */
388 	    }
389 	kernelfault: ;
390 	    {
391 		vaddr_t va;
392 		int rv;
393 
394 		va = trunc_page(vaddr);
395 		rv = uvm_fault(kernel_map, va, 0, ftype);
396 		if (rv == 0)
397 			return; /* KERN */
398 		/*FALLTHROUGH*/
399 	    }
400 	case T_ADDR_ERR_LD:	/* misaligned access */
401 	case T_ADDR_ERR_ST:	/* misaligned access */
402 	case T_BUS_ERR_LD_ST:	/* BERR asserted to cpu */
403 	copyfault:
404 		if (p == NULL || p->p_addr->u_pcb.pcb_onfault == NULL)
405 			goto dopanic;
406 		frame->tf_regs[TF_EPC] = (int)p->p_addr->u_pcb.pcb_onfault;
407 		return; /* KERN */
408 
409 	case T_ADDR_ERR_LD+T_USER:	/* misaligned or kseg access */
410 	case T_ADDR_ERR_ST+T_USER:	/* misaligned or kseg access */
411 	case T_BUS_ERR_IFETCH+T_USER:	/* BERR asserted to cpu */
412 	case T_BUS_ERR_LD_ST+T_USER:	/* BERR asserted to cpu */
413 		sig = SIGSEGV;
414 		ucode = vaddr;
415 		break; /* SIGNAL */
416 
417 	case T_BREAK:
418 #if defined(DDB)
419 		kdb_trap(type, (mips_reg_t *) frame);
420 		return;	/* KERN */
421 #elif defined(KGDB)
422 		{
423 			struct frame *f = (struct frame *)&ddb_regs;
424 			extern mips_reg_t kgdb_cause, kgdb_vaddr;
425 			kgdb_cause = cause;
426 			kgdb_vaddr = vaddr;
427 
428 			/*
429 			 * init global ddb_regs, used in db_interface.c routines
430 			 * shared between ddb and gdb. Send ddb_regs to gdb so
431 			 * that db_machdep.h macros will work with it, and
432 			 * allow gdb to alter the PC.
433 			 */
434 			db_set_ddb_regs(type, (mips_reg_t *) frame);
435 			PC_BREAK_ADVANCE(f);
436 			if (!kgdb_trap(type, &ddb_regs))
437 				printf("kgdb: ignored %s\n",
438 				       trap_type[TRAPTYPE(cause)]);
439 			else
440 				((mips_reg_t *)frame)[21] = f->f_regs[PC];
441 
442 			return;
443 		}
444 #else
445 		goto dopanic;
446 #endif
447 	case T_BREAK+T_USER:
448 	    {
449 		unsigned va, instr;
450 		int rv;
451 
452 		/* compute address of break instruction */
453 		va = (DELAYBRANCH(cause)) ? opc + sizeof(int) : opc;
454 
455 		/* read break instruction */
456 		instr = fuiword((void *)va);
457 
458 		if (p->p_md.md_ss_addr != va || instr != MIPS_BREAK_SSTEP) {
459 			sig = SIGTRAP;
460 			break;
461 		}
462 		/*
463 		 * Restore original instruction and clear BP
464 		 */
465 		rv = suiword((void *)va, p->p_md.md_ss_instr);
466 		if (rv < 0) {
467 			vaddr_t sa, ea;
468 			sa = trunc_page(va);
469 			ea = round_page(va + sizeof(int) - 1);
470 			rv = uvm_map_protect(&p->p_vmspace->vm_map,
471 				sa, ea, VM_PROT_DEFAULT, FALSE);
472 			if (rv == 0) {
473 				rv = suiword((void *)va, MIPS_BREAK_SSTEP);
474 				(void)uvm_map_protect(&p->p_vmspace->vm_map,
475 				sa, ea, VM_PROT_READ|VM_PROT_EXECUTE, FALSE);
476 			}
477 		}
478 		mips_icache_sync_all();		/* XXXJRT -- necessary? */
479 		mips_dcache_wbinv_all();	/* XXXJRT -- necessary? */
480 
481 		if (rv < 0)
482 			printf("Warning: can't restore instruction at 0x%lx: 0x%x\n",
483 				p->p_md.md_ss_addr, p->p_md.md_ss_instr);
484 		p->p_md.md_ss_addr = 0;
485 		sig = SIGTRAP;
486 		break; /* SIGNAL */
487 	    }
488 	case T_RES_INST+T_USER:
489 	case T_COP_UNUSABLE+T_USER:
490 #if !defined(SOFTFLOAT) && !defined(NOFPU)
491 		if ((cause & MIPS_CR_COP_ERR) == 0x10000000) {
492 			struct frame *f;
493 
494 			f = (struct frame *)p->p_md.md_regs;
495 			savefpregs(fpcurproc);  	/* yield FPA */
496 			loadfpregs(p);          	/* load FPA */
497 			fpcurproc = p;
498 			p->p_md.md_flags |= MDP_FPUSED;
499 			f->f_regs[SR] |= MIPS_SR_COP_1_BIT;
500 		} else
501 #endif
502 		{
503 			MachEmulateInst(status, cause, opc, p->p_md.md_regs);
504 		}
505 		userret(p);
506 		return; /* GEN */
507 	case T_FPE+T_USER:
508 #if defined(SOFTFLOAT)
509 		MachEmulateInst(status, cause, opc, p->p_md.md_regs);
510 #elif !defined(NOFPU)
511 		MachFPTrap(status, cause, opc, p->p_md.md_regs);
512 #endif
513 		userret(p);
514 		return; /* GEN */
515 	case T_OVFLOW+T_USER:
516 	case T_TRAP+T_USER:
517 		sig = SIGFPE;
518 		break; /* SIGNAL */
519 	}
520 	((struct frame *)p->p_md.md_regs)->f_regs[CAUSE] = cause;
521 	((struct frame *)p->p_md.md_regs)->f_regs[BADVADDR] = vaddr;
522 	trapsignal(p, sig, ucode);
523 	if ((type & T_USER) == 0)
524 		panic("trapsignal");
525 	userret(p);
526 	return;
527 }
528 
529 /*
530  * Software (low priority) network interrupt. i.e. softnet().
531  */
532 void
533 netintr()
534 {
535 #define DONETISR(bit, fn)			\
536 	do {					\
537 		if (n & (1 << bit))		\
538 			fn();			\
539 	} while (0)
540 
541 	int n;
542 	n = netisr; netisr = 0;
543 
544 #ifdef SOFTNET_INTR		/* XXX TEMPORARY XXX */
545 	intrcnt[SOFTNET_INTR]++;
546 #endif
547 
548 #include <net/netisr_dispatch.h>
549 
550 #undef DONETISR
551 }
552 
553 /*
554  * Handle asynchronous software traps.
555  * This is called from MachUserIntr() either to deliver signals or
556  * to make involuntary context switch (preemption).
557  */
558 void
559 ast(pc)
560 	unsigned pc;		/* program counter where to continue */
561 {
562 	struct proc *p = curproc;
563 	int sig;
564 
565 	while (p->p_md.md_astpending) {
566 		uvmexp.softs++;
567 		p->p_md.md_astpending = 0;
568 
569 		if (p->p_flag & P_OWEUPC) {
570 			p->p_flag &= ~P_OWEUPC;
571 			ADDUPROF(p);
572 		}
573 
574 		/* Take pending signals. */
575 		while ((sig = CURSIG(p)) != 0)
576 			postsig(sig);
577 
578 		if (want_resched) {
579 			/*
580 			 * We are being preempted.
581 			 */
582 			preempt(NULL);
583 		}
584 
585 		userret(p);
586 	}
587 }
588 
589 
590 /* XXX need to rewrite acient comment XXX
591  * This routine is called by procxmt() to single step one instruction.
592  * We do this by storing a break instruction after the current instruction,
593  * resuming execution, and then restoring the old instruction.
594  */
595 int
596 mips_singlestep(p)
597 	struct proc *p;
598 {
599 	struct frame *f = (struct frame *)p->p_md.md_regs;
600 	vaddr_t pc, va;
601 	int rv;
602 
603 	if (p->p_md.md_ss_addr) {
604 		printf("SS %s (%d): breakpoint already set at %lx\n",
605 			p->p_comm, p->p_pid, p->p_md.md_ss_addr);
606 		return EFAULT;
607 	}
608 	pc = (vaddr_t)f->f_regs[PC];
609 	if (fuiword((void *)pc) != 0) /* not a NOP instruction */
610 		va = MachEmulateBranch(f, pc,
611 		    PCB_FSR(&p->p_addr->u_pcb), 1);
612 	else
613 		va = pc + sizeof(int);
614 
615 	/*
616 	 * We can't single-step into a RAS.  Check if we're in
617 	 * a RAS, and set the breakpoint just past it.
618 	 */
619 	if (p->p_nras != 0) {
620 		while (ras_lookup(p, (caddr_t)va) != (caddr_t)-1)
621 			va += sizeof(int);
622 	}
623 
624 	p->p_md.md_ss_addr = va;
625 	p->p_md.md_ss_instr = fuiword((void *)va);
626 	rv = suiword((void *)va, MIPS_BREAK_SSTEP);
627 	if (rv < 0) {
628 		vaddr_t sa, ea;
629 		sa = trunc_page(va);
630 		ea = round_page(va + sizeof(int) - 1);
631 		rv = uvm_map_protect(&p->p_vmspace->vm_map,
632 		    sa, ea, VM_PROT_DEFAULT, FALSE);
633 		if (rv == 0) {
634 			rv = suiword((void *)va, MIPS_BREAK_SSTEP);
635 			(void)uvm_map_protect(&p->p_vmspace->vm_map,
636 			    sa, ea, VM_PROT_READ|VM_PROT_EXECUTE, FALSE);
637 		}
638 	}
639 #if 0
640 	printf("SS %s (%d): breakpoint set at %x: %x (pc %x) br %x\n",
641 		p->p_comm, p->p_pid, p->p_md.md_ss_addr,
642 		p->p_md.md_ss_instr, pc, fuword((void *)va)); /* XXX */
643 #endif
644 	return 0;
645 }
646 
647 
648 #ifndef DDB_TRACE
649 
650 #if defined(DEBUG) || defined(DDB) || defined(KGDB) || defined(geo)
651 mips_reg_t kdbrpeek(vaddr_t);
652 
653 int
654 kdbpeek(addr)
655 	vaddr_t addr;
656 {
657 	int rc;
658 	if (addr & 3) {
659 		printf("kdbpeek: unaligned address %lx\n", addr);
660 		/* We might have been called from DDB, so do not go there. */
661 		stacktrace();
662 		rc = -1 ;
663 	} else if (addr == NULL) {
664 		printf("kdbpeek: NULL\n");
665 		rc = 0xdeadfeed;
666 	} else {
667 		rc = *(int *)addr;
668 	}
669 	return rc;
670 }
671 
672 mips_reg_t
673 kdbrpeek(addr)
674 	vaddr_t addr;
675 {
676 	mips_reg_t rc;
677 	if (addr & (sizeof(mips_reg_t) - 1)) {
678 		printf("kdbrpeek: unaligned address %lx\n", addr);
679 		/* We might have been called from DDB, so do not go there. */
680 		stacktrace();
681 		rc = -1 ;
682 	} else if (addr == NULL) {
683 		printf("kdbrpeek: NULL\n");
684 		rc = 0xdeadfeed;
685 	} else {
686 		rc = *(mips_reg_t *)addr;
687 	}
688 	return rc;
689 }
690 
691 extern char start[], edata[], verylocore[];
692 extern char mips1_KernGenException[];
693 extern char mips1_UserGenException[];
694 extern char mips1_KernIntr[];
695 extern char mips1_UserIntr[];
696 extern char mips1_SystemCall[];
697 extern char mips3_KernGenException[];
698 extern char mips3_UserGenException[];
699 extern char mips3_KernIntr[];
700 extern char mips3_UserIntr[];
701 extern char mips3_SystemCall[];
702 extern int main(void *);
703 extern void mips_idle(void);
704 extern void cpu_switch(struct proc *, struct proc *);
705 
706 /*
707  *  stack trace code, also useful to DDB one day
708  */
709 
710 /* forward */
711 char *fn_name(unsigned addr);
712 void stacktrace_subr(int, int, int, int, u_int, u_int, u_int, u_int,
713 	    void (*)(const char*, ...));
714 
715 #define	MIPS_JR_RA	0x03e00008	/* instruction code for jr ra */
716 #define	MIPS_JR_K0	0x03400008	/* instruction code for jr k0 */
717 #define	MIPS_ERET	0x42000018	/* instruction code for eret */
718 
719 /*
720  * Do a stack backtrace.
721  * (*printfn)()  prints the output to either the system log,
722  * the console, or both.
723  */
724 void
725 stacktrace_subr(a0, a1, a2, a3, pc, sp, fp, ra, printfn)
726 	int a0, a1, a2, a3;
727 	u_int  pc, sp, fp, ra;
728 	void (*printfn)(const char*, ...);
729 {
730 	unsigned va, subr;
731 	unsigned instr, mask;
732 	InstFmt i;
733 	int more, stksize;
734 	unsigned int frames =  0;
735 	int foundframesize = 0;
736 
737 /* Jump here when done with a frame, to start a new one */
738 loop:
739 	stksize = 0;
740 	subr = 0;
741 	if (frames++ > 100) {
742 		(*printfn)("\nstackframe count exceeded\n");
743 		/* return breaks stackframe-size heuristics with gcc -O2 */
744 		goto finish;	/*XXX*/
745 	}
746 
747 	/* check for bad SP: could foul up next frame */
748 	if (sp & 3 || sp < 0x80000000) {
749 		(*printfn)("SP 0x%x: not in kernel\n", sp);
750 		ra = 0;
751 		subr = 0;
752 		goto done;
753 	}
754 
755 	/* Check for bad PC */
756 	if (pc & 3 || pc < 0x80000000 || pc >= (unsigned)edata) {
757 		(*printfn)("PC 0x%x: not in kernel space\n", pc);
758 		ra = 0;
759 		goto done;
760 	}
761 
762 	/*
763 	 * Find the beginning of the current subroutine by scanning backwards
764 	 * from the current PC for the end of the previous subroutine.
765 	 */
766 	va = pc;
767 	do {
768 		va -= sizeof(int);
769 		if (va <= (unsigned)verylocore)
770 			goto finish;
771 		instr = kdbpeek(va);
772 		if (instr == MIPS_ERET)
773 			goto mips3_eret;
774 	} while (instr != MIPS_JR_RA && instr != MIPS_JR_K0);
775 	/* skip back over branch & delay slot */
776 	va += sizeof(int);
777 mips3_eret:
778 	va += sizeof(int);
779 	/* skip over nulls which might separate .o files */
780 	while ((instr = kdbpeek(va)) == 0)
781 		va += sizeof(int);
782 	subr = va;
783 
784 	/* scan forwards to find stack size and any saved registers */
785 	stksize = 0;
786 	more = 3;
787 	mask = 0;
788 	foundframesize = 0;
789 	for (va = subr; more; va += sizeof(int),
790 			      more = (more == 3) ? 3 : more - 1) {
791 		/* stop if hit our current position */
792 		if (va >= pc)
793 			break;
794 		instr = kdbpeek(va);
795 		i.word = instr;
796 		switch (i.JType.op) {
797 		case OP_SPECIAL:
798 			switch (i.RType.func) {
799 			case OP_JR:
800 			case OP_JALR:
801 				more = 2; /* stop after next instruction */
802 				break;
803 
804 			case OP_SYSCALL:
805 			case OP_BREAK:
806 				more = 1; /* stop now */
807 			};
808 			break;
809 
810 		case OP_BCOND:
811 		case OP_J:
812 		case OP_JAL:
813 		case OP_BEQ:
814 		case OP_BNE:
815 		case OP_BLEZ:
816 		case OP_BGTZ:
817 			more = 2; /* stop after next instruction */
818 			break;
819 
820 		case OP_COP0:
821 		case OP_COP1:
822 		case OP_COP2:
823 		case OP_COP3:
824 			switch (i.RType.rs) {
825 			case OP_BCx:
826 			case OP_BCy:
827 				more = 2; /* stop after next instruction */
828 			};
829 			break;
830 
831 		case OP_SW:
832 			/* look for saved registers on the stack */
833 			if (i.IType.rs != 29)
834 				break;
835 			/* only restore the first one */
836 			if (mask & (1 << i.IType.rt))
837 				break;
838 			mask |= (1 << i.IType.rt);
839 			switch (i.IType.rt) {
840 			case 4: /* a0 */
841 				a0 = kdbpeek(sp + (short)i.IType.imm);
842 				break;
843 
844 			case 5: /* a1 */
845 				a1 = kdbpeek(sp + (short)i.IType.imm);
846 				break;
847 
848 			case 6: /* a2 */
849 				a2 = kdbpeek(sp + (short)i.IType.imm);
850 				break;
851 
852 			case 7: /* a3 */
853 				a3 = kdbpeek(sp + (short)i.IType.imm);
854 				break;
855 
856 			case 30: /* fp */
857 				fp = kdbpeek(sp + (short)i.IType.imm);
858 				break;
859 
860 			case 31: /* ra */
861 				ra = kdbpeek(sp + (short)i.IType.imm);
862 			}
863 			break;
864 
865 		case OP_ADDI:
866 		case OP_ADDIU:
867 			/* look for stack pointer adjustment */
868 			if (i.IType.rs != 29 || i.IType.rt != 29)
869 				break;
870 			/* don't count pops for mcount */
871 			if (!foundframesize) {
872 				stksize = - ((short)i.IType.imm);
873 				foundframesize = 1;
874 			}
875 		}
876 	}
877 done:
878 	(*printfn)("%s+%x (%x,%x,%x,%x) ra %x sz %d\n",
879 		fn_name(subr), pc - subr, a0, a1, a2, a3, ra, stksize);
880 
881 	if (ra) {
882 		if (pc == ra && stksize == 0)
883 			(*printfn)("stacktrace: loop!\n");
884 		else {
885 			pc = ra;
886 			sp += stksize;
887 			ra = 0;
888 			goto loop;
889 		}
890 	} else {
891 finish:
892 		if (curproc)
893 			(*printfn)("User-level: pid %d\n", curproc->p_pid);
894 		else
895 			(*printfn)("User-level: curproc NULL\n");
896 	}
897 }
898 
899 /*
900  * Functions ``special'' enough to print by name
901  */
902 #ifdef __STDC__
903 #define Name(_fn)  { (void*)_fn, # _fn }
904 #else
905 #define Name(_fn) { _fn, "_fn"}
906 #endif
907 static struct { void *addr; char *name;} names[] = {
908 	Name(stacktrace),
909 	Name(stacktrace_subr),
910 	Name(main),
911 	Name(trap),
912 
913 #ifdef MIPS1	/*  r2000 family  (mips-I cpu) */
914 	Name(mips1_KernGenException),
915 	Name(mips1_UserGenException),
916 	Name(mips1_SystemCall),
917 	Name(mips1_KernIntr),
918 	Name(mips1_UserIntr),
919 #endif	/* MIPS1 */
920 
921 /* XXX simonb: need mips32 and mips64 checks here too */
922 #if defined(MIPS3) && !defined(MIPS3_5900) /* r4000 family (mips-III cpu) */
923 	Name(mips3_KernGenException),
924 	Name(mips3_UserGenException),
925 	Name(mips3_SystemCall),
926 	Name(mips3_KernIntr),
927 	Name(mips3_UserIntr),
928 #endif	/* MIPS3 && !MIPS3_5900 */
929 
930 	Name(mips_idle),
931 	Name(cpu_switch),
932 	{0, 0}
933 };
934 
935 /*
936  * Map a function address to a string name, if known; or a hex string.
937  */
938 char *
939 fn_name(unsigned addr)
940 {
941 	static char buf[17];
942 	int i = 0;
943 #ifdef DDB
944 	db_expr_t diff;
945 	db_sym_t sym;
946 	char *symname;
947 #endif
948 
949 #ifdef DDB
950 	diff = 0;
951 	symname = NULL;
952 	sym = db_search_symbol(addr, DB_STGY_ANY, &diff);
953 	db_symbol_values(sym, &symname, 0);
954 	if (symname && diff == 0)
955 		return (symname);
956 #endif
957 	for (i = 0; names[i].name; i++)
958 		if (names[i].addr == (void*)addr)
959 			return (names[i].name);
960 	sprintf(buf, "%x", addr);
961 	return (buf);
962 }
963 
964 #endif /* DEBUG */
965 
966 #endif /* DDB_TRACE */
967