xref: /openbsd/sys/arch/m88k/m88k/db_interface.c (revision 949c1c4e)
1 /*	$OpenBSD: db_interface.c,v 1.32 2024/11/07 16:02:29 miod Exp $	*/
2 /*
3  * Mach Operating System
4  * Copyright (c) 1993-1991 Carnegie Mellon University
5  * Copyright (c) 1991 OMRON Corporation
6  * All Rights Reserved.
7  *
8  * Permission to use, copy, modify and distribute this software and its
9  * documentation is hereby granted, provided that both the copyright
10  * notice and this permission notice appear in all copies of the
11  * software, derivative works or modified versions, and any portions
12  * thereof, and that both notices appear in supporting documentation.
13  *
14  * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
15  * CONDITION.  CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND
16  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
17  *
18  * Carnegie Mellon requests users of this software to return to
19  *
20  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
21  *  School of Computer Science
22  *  Carnegie Mellon University
23  *  Pittsburgh PA 15213-3890
24  *
25  * any improvements or extensions that they make and grant Carnegie the
26  * rights to redistribute these changes.
27  */
28 
29 /*
30  * m88k interface to ddb debugger
31  */
32 
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/proc.h>
36 #include <sys/reboot.h>
37 
38 #include <uvm/uvm_extern.h>
39 
40 #include <machine/asm_macro.h>
41 #include <machine/cmmu.h>
42 #include <machine/trap.h>
43 #include <machine/db_machdep.h>
44 #include <machine/cpu.h>
45 #ifdef M88100
46 #include <machine/m88100.h>
47 #include <machine/m8820x.h>
48 #endif
49 
50 #include <ddb/db_access.h>
51 #include <ddb/db_command.h>
52 #include <ddb/db_extern.h>
53 #include <ddb/db_interface.h>
54 #include <ddb/db_output.h>
55 #include <ddb/db_run.h>
56 #include <ddb/db_sym.h>
57 
58 extern label_t *db_recover;
59 extern int frame_is_sane(db_regs_t *, int);	/* db_trace */
60 extern void cnpollc(int);
61 
62 void	kdbprinttrap(int);
63 
64 int	m88k_dmx_print(u_int, u_int, u_int, u_int);
65 
66 void	m88k_db_trap(int, struct trapframe *);
67 void	m88k_db_print_frame(db_expr_t, int, db_expr_t, char *);
68 void	m88k_db_registers(db_expr_t, int, db_expr_t, char *);
69 void	m88k_db_where(db_expr_t, int, db_expr_t, char *);
70 void	m88k_db_frame_search(db_expr_t, int, db_expr_t, char *);
71 
72 db_regs_t ddb_regs;
73 
74 #ifdef MULTIPROCESSOR
75 #include <sys/mplock.h>
76 struct __mp_lock ddb_mp_lock;
77 cpuid_t	ddb_mp_nextcpu = (cpuid_t)-1;
78 
79 void	m88k_db_cpu_cmd(db_expr_t, int, db_expr_t, char *);
80 #endif
81 
82 /*
83  * If you really feel like understanding the following procedure and
84  * macros, see pages 6-22 to 6-30 (Section 6.7.3) of
85  *
86  * MC88100 RISC Microprocessor User's Manual Second Edition
87  * (Motorola Order: MC88100UM/AD REV 1)
88  *
89  * and ERRATA-5 (6-23, 6-24, 6-24) of
90  *
91  * Errata to MC88100 User's Manual Second Edition MC88100UM/AD Rev 1
92  * (Oct 2, 1990)
93  * (Motorola Order: MC88100UMAD/AD)
94  */
95 
96 #ifdef M88100
97 /* macros for decoding dmt registers */
98 
99 /*
100  * return 1 if the printing of the next stage should be suppressed
101  */
102 int
m88k_dmx_print(u_int t,u_int d,u_int a,u_int no)103 m88k_dmx_print(u_int t, u_int d, u_int a, u_int no)
104 {
105 	static const u_int addr_mod[16] = {
106 		0, 3, 2, 2, 1, 0, 0, 0,
107 		0, 0, 0, 0, 0, 0, 0, 0
108 	};
109 	static const char *mode[16]  = {
110 		"?", ".b", ".b", ".h", ".b", "?", "?", "?",
111 		".b", "?", "?" , "?" , ".h" , "?", "?", ""
112 	};
113 	static const u_int mask[16] = {
114 		0, 0xff, 0xff00, 0xffff,
115 		0xff0000, 0, 0, 0,
116 		0xff000000, 0, 0, 0,
117 		0xffff0000, 0, 0, 0xffffffff
118 	};
119 	static const u_int shift[16] = {
120 		0,  0, 8, 0, 16, 0, 0, 0,
121 		24, 0, 0, 0, 16, 0, 0, 0
122 	};
123 	int reg = DMT_DREGBITS(t);
124 
125 	if (ISSET(t, DMT_LOCKBAR)) {
126 		db_printf("xmem%s%s r%d(0x%x) <-> mem(0x%x),",
127 		    DMT_ENBITS(t) == 0x0f ? "" : ".bu",
128 		    ISSET(t, DMT_DAS) ? "" : ".usr", reg,
129 		    ((t >> 2 & 0xf) == 0xf) ? d : (d & 0xff), a);
130 		return 1;
131 	} else if (DMT_ENBITS(t) == 0xf) {
132 		/* full or double word */
133 		if (ISSET(t, DMT_WRITE)) {
134 			if (ISSET(t, DMT_DOUB1) && no == 2)
135 				db_printf("st.d%s -> mem(0x%x) (** restart sxip **)",
136 				    ISSET(t, DMT_DAS) ? "" : ".usr", a);
137 			else
138 				db_printf("st%s (0x%x) -> mem(0x%x)",
139 				    ISSET(t, DMT_DAS) ? "" : ".usr", d, a);
140 		} else {
141 			/* load */
142 			if (ISSET(t, DMT_DOUB1) && no == 2)
143 				db_printf("ld.d%s r%d <- mem(0x%x), r%d <- mem(0x%x)",
144 				    ISSET(t, DMT_DAS) ? "" : ".usr", reg, a, reg+1, a+4);
145 			else
146 				db_printf("ld%s r%d <- mem(0x%x)",
147 				    ISSET(t, DMT_DAS) ? "" : ".usr", reg, a);
148 		}
149 	} else {
150 		/* fractional word - check if load or store */
151 		a += addr_mod[DMT_ENBITS(t)];
152 		if (ISSET(t, DMT_WRITE))
153 			db_printf("st%s%s (0x%x) -> mem(0x%x)",
154 			    mode[DMT_ENBITS(t)],
155 			    ISSET(t, DMT_DAS) ? "" : ".usr",
156 			    (d & mask[DMT_ENBITS(t)]) >> shift[DMT_ENBITS(t)],
157 			    a);
158 		else
159 			db_printf("ld%s%s%s r%d <- mem(0x%x)",
160 			    mode[DMT_ENBITS(t)],
161 			    ISSET(t, DMT_SIGNED) ? "" : "u",
162 			    ISSET(t, DMT_DAS) ? "" : ".usr", reg, a);
163 	}
164 	return (0);
165 }
166 #endif	/* M88100 */
167 
168 void
m88k_db_print_frame(addr,have_addr,count,modif)169 m88k_db_print_frame(addr, have_addr, count, modif)
170 	db_expr_t addr;
171 	int have_addr;
172 	db_expr_t count;
173 	char *modif;
174 {
175 	struct trapframe *s = (struct trapframe *)addr;
176 	const char *name;
177 	db_expr_t offset;
178 #ifdef M88100
179 	int suppress1 = 0, suppress2 = 0;
180 #endif
181 	int c, force = 0, help = 0;
182 
183 	if (!have_addr) {
184 		db_printf("requires address of frame\n");
185 		help = 1;
186 	}
187 
188 	while (modif && *modif) {
189 		switch (c = *modif++, c) {
190 		case 'f':
191 			force = 1;
192 			break;
193 		case 'h':
194 			help = 1;
195 			break;
196 		default:
197 			db_printf("unknown modifier [%c]\n", c);
198 			help = 1;
199 			break;
200 		}
201 	}
202 
203 	if (help) {
204 		db_printf("usage: mach frame/[f] ADDRESS\n");
205 		db_printf("  /f force printing of insane frames.\n");
206 		return;
207 	}
208 
209 	if (badaddr((vaddr_t)s, 4) ||
210 	    badaddr((vaddr_t)(&((db_regs_t*)s)->fpit), 4)) {
211 		db_printf("frame at %8p is unreadable\n", s);
212 		return;
213 	}
214 
215 	if (frame_is_sane((db_regs_t *)s, 0) == 0) {
216 		if (force == 0)
217 			return;
218 	}
219 
220 #define R(i) s->tf_r[i]
221 #define IPMASK(x) ((x) &  ~(3))
222 	db_printf("R00-05: 0x%08lx  0x%08lx  0x%08lx  0x%08lx  0x%08lx  0x%08lx\n",
223 	    R(0), R(1), R(2), R(3), R(4), R(5));
224 	db_printf("R06-11: 0x%08lx  0x%08lx  0x%08lx  0x%08lx  0x%08lx  0x%08lx\n",
225 	    R(6), R(7), R(8), R(9), R(10), R(11));
226 	db_printf("R12-17: 0x%08lx  0x%08lx  0x%08lx  0x%08lx  0x%08lx  0x%08lx\n",
227 	    R(12), R(13), R(14), R(15), R(16), R(17));
228 	db_printf("R18-23: 0x%08lx  0x%08lx  0x%08lx  0x%08lx  0x%08lx  0x%08lx\n",
229 	    R(18), R(19), R(20), R(21), R(22), R(23));
230 	db_printf("R24-29: 0x%08lx  0x%08lx  0x%08lx  0x%08lx  0x%08lx  0x%08lx\n",
231 	    R(24), R(25), R(26), R(27), R(28), R(29));
232 	db_printf("R30-31: 0x%08lx  0x%08lx\n", R(30), R(31));
233 
234 	db_printf("%cxip: 0x%08lx ",
235 	    CPU_IS88110 ? 'e' : 's', s->tf_sxip & XIP_ADDR);
236 	db_find_xtrn_sym_and_offset((vaddr_t)IPMASK(s->tf_sxip),
237 	    &name, &offset);
238 	if (name != NULL && (u_int)offset <= db_maxoff)
239 		db_printf("%s+0x%08x", name, (u_int)offset);
240 	db_printf("\n");
241 
242 	if (s->tf_snip != s->tf_sxip + 4) {
243 		db_printf("%cnip: 0x%08lx ",
244 		    CPU_IS88110 ? 'e' : 's', s->tf_snip);
245 		db_find_xtrn_sym_and_offset((vaddr_t)IPMASK(s->tf_snip),
246 		    &name, &offset);
247 		if (name != NULL && (u_int)offset <= db_maxoff)
248 			db_printf("%s+0x%08x", name, (u_int)offset);
249 		db_printf("\n");
250 	}
251 
252 #ifdef M88100
253 	if (CPU_IS88100) {
254 		if (s->tf_sfip != s->tf_snip + 4) {
255 			db_printf("sfip: 0x%08lx ", s->tf_sfip);
256 			db_find_xtrn_sym_and_offset((vaddr_t)IPMASK(s->tf_sfip),
257 			    &name, &offset);
258 			if (name != NULL && (u_int)offset <= db_maxoff)
259 				db_printf("%s+0x%08x", name, (u_int)offset);
260 			db_printf("\n");
261 		}
262 	}
263 #endif
264 #ifdef M88110
265 	if (CPU_IS88110) {
266 		db_printf("fpsr: 0x%08lx fpcr: 0x%08lx fpecr: 0x%08lx\n",
267 			  s->tf_fpsr, s->tf_fpcr, s->tf_fpecr);
268 		db_printf("dsap 0x%08lx duap 0x%08lx dsr 0x%08lx dlar 0x%08lx dpar 0x%08lx\n",
269 			  s->tf_dsap, s->tf_duap, s->tf_dsr, s->tf_dlar, s->tf_dpar);
270 		db_printf("isap 0x%08lx iuap 0x%08lx isr 0x%08lx ilar 0x%08lx ipar 0x%08lx\n",
271 			  s->tf_isap, s->tf_iuap, s->tf_isr, s->tf_ilar, s->tf_ipar);
272 	}
273 #endif
274 
275 	db_printf("epsr: 0x%08lx                current process: %p\n",
276 		  s->tf_epsr, curproc);
277 	db_printf("vector: 0x%02lx                    interrupt mask: 0x%08lx\n",
278 		  s->tf_vector, s->tf_mask);
279 
280 	/*
281 	 * If the vector indicates trap, instead of an exception or
282 	 * interrupt, skip the check of dmt and fp regs.
283 	 *
284 	 * Interrupt and exceptions are vectored at 0-10 and 114-127.
285 	 */
286 	if (!(s->tf_vector <= 10 ||
287 	    (114 <= s->tf_vector && s->tf_vector <= 127))) {
288 		db_printf("\n");
289 		return;
290 	}
291 
292 #ifdef M88100
293 	if (CPU_IS88100) {
294 		if (s->tf_vector == /*data*/3 || s->tf_dmt0 & DMT_VALID) {
295 			db_printf("dmt,d,a0: 0x%08lx  0x%08lx  0x%08lx ",
296 			    s->tf_dmt0, s->tf_dmd0, s->tf_dma0);
297 			db_find_xtrn_sym_and_offset((vaddr_t)s->tf_dma0,
298 			    &name, &offset);
299 			if (name != NULL && (u_int)offset <= db_maxoff)
300 				db_printf("%s+0x%08x", name, (u_int)offset);
301 			db_printf("\n          ");
302 
303 			suppress1 = m88k_dmx_print(s->tf_dmt0, s->tf_dmd0,
304 			    s->tf_dma0, 0);
305 			db_printf("\n");
306 
307 			if ((s->tf_dmt1 & DMT_VALID) && (!suppress1)) {
308 				db_printf("dmt,d,a1: 0x%08lx  0x%08lx  0x%08lx ",
309 				    s->tf_dmt1, s->tf_dmd1, s->tf_dma1);
310 				db_find_xtrn_sym_and_offset((vaddr_t)s->tf_dma1,
311 				    &name, &offset);
312 				if (name != NULL && (u_int)offset <= db_maxoff)
313 					db_printf("%s+0x%08x", name,
314 					    (u_int)offset);
315 				db_printf("\n          ");
316 				suppress2 = m88k_dmx_print(s->tf_dmt1,
317 				    s->tf_dmd1, s->tf_dma1, 1);
318 				db_printf("\n");
319 
320 				if ((s->tf_dmt2 & DMT_VALID) && (!suppress2)) {
321 					db_printf("dmt,d,a2: 0x%08lx  0x%08lx  0x%08lx ",
322 						  s->tf_dmt2, s->tf_dmd2, s->tf_dma2);
323 					db_find_xtrn_sym_and_offset((vaddr_t)s->tf_dma2,
324 					    &name, &offset);
325 					if (name != 0 &&
326 					    (u_int)offset <= db_maxoff)
327 						db_printf("%s+0x%08x", name,
328 						    (u_int)offset);
329 					db_printf("\n          ");
330 					m88k_dmx_print(s->tf_dmt2, s->tf_dmd2,
331 					    s->tf_dma2, 2);
332 					db_printf("\n");
333 				}
334 			}
335 
336 			db_printf("fault code %ld\n",
337 			    CMMU_PFSR_FAULT(s->tf_dpfsr));
338 		}
339 	}
340 #endif	/* M88100 */
341 
342 	if (s->tf_fpecr & 255) { /* floating point error occurred */
343 		db_printf("fpecr: 0x%08lx fpsr: 0x%08lx fpcr: 0x%08lx\n",
344 		    s->tf_fpecr, s->tf_fpsr, s->tf_fpcr);
345 #ifdef M88100
346 		if (CPU_IS88100) {
347 			db_printf("fcr1-4: 0x%08lx  0x%08lx  0x%08lx  0x%08lx\n",
348 			    s->tf_fphs1, s->tf_fpls1, s->tf_fphs2, s->tf_fpls2);
349 			db_printf("fcr5-8: 0x%08lx  0x%08lx  0x%08lx  0x%08lx\n",
350 			    s->tf_fppt, s->tf_fprh, s->tf_fprl, s->tf_fpit);
351 		}
352 #endif
353 	}
354 	db_printf("\n");
355 }
356 
357 void
m88k_db_registers(addr,have_addr,count,modif)358 m88k_db_registers(addr, have_addr, count, modif)
359 	db_expr_t addr;
360 	int have_addr;
361 	db_expr_t count;
362 	char *modif;
363 {
364 	m88k_db_print_frame((db_expr_t)&ddb_regs, TRUE, 0, modif);
365 }
366 
367 /*
368  * m88k_db_trap - field a TRACE or BPT trap
369  * Note that only the tf_regs part of the frame is valid - some ddb routines
370  * invoke this function with a promoted struct reg!
371  */
372 void
m88k_db_trap(type,frame)373 m88k_db_trap(type, frame)
374 	int type;
375 	struct trapframe *frame;
376 {
377 #ifdef MULTIPROCESSOR
378 	struct cpu_info *ci = curcpu();
379 #endif
380 
381 	switch(type) {
382 	case T_KDB_BREAK:
383 	case T_KDB_TRACE:
384 	case T_KDB_ENTRY:
385 		break;
386 	case -1:
387 		break;
388 	default:
389 		kdbprinttrap(type);
390 		if (db_recover != 0) {
391 			db_error("Caught exception in ddb.\n");
392 			/*NOTREACHED*/
393 		}
394 	}
395 
396 #ifdef MULTIPROCESSOR
397 	ci->ci_ddb_state = CI_DDB_ENTERDDB;
398 	__mp_lock(&ddb_mp_lock);
399 	ci->ci_ddb_state = CI_DDB_INDDB;
400 	ddb_mp_nextcpu = (cpuid_t)-1;
401 	m88k_broadcast_ipi(CI_IPI_DDB);		/* pause other processors */
402 #endif
403 
404 	ddb_regs = frame->tf_regs;
405 
406 	db_active++;
407 	cnpollc(1);
408 	db_trap(type, 0);
409 	cnpollc(0);
410 	db_active--;
411 
412 	frame->tf_regs = ddb_regs;
413 
414 #ifdef MULTIPROCESSOR
415 	ci->ci_ddb_state = CI_DDB_RUNNING;
416 	__mp_release_all(&ddb_mp_lock);
417 #endif
418 }
419 
420 extern const char *trap_type[];
421 extern const int trap_types;
422 
423 /*
424  * Print trap reason.
425  */
426 void
kdbprinttrap(int type)427 kdbprinttrap(int type)
428 {
429 	printf("kernel: ");
430 	if (type >= trap_types || type < 0)
431 		printf("type %d", type);
432 	else
433 		printf("%s", trap_type[type]);
434 	printf(" trap\n");
435 }
436 
437 void
db_enter(void)438 db_enter(void)
439 {
440 	asm (ENTRY_ASM); /* entry trap */
441 	/* ends up at ddb_entry_trap below */
442 	return;
443 }
444 
445 /*
446  * When the below routine is entered interrupts should be on
447  * but spl should be high
448  *
449  * The following routine is for breakpoint and watchpoint entry.
450  */
451 
452 /* breakpoint/watchpoint entry */
453 int
ddb_break_trap(type,eframe)454 ddb_break_trap(type, eframe)
455 	int type;
456 	db_regs_t *eframe;
457 {
458 	m88k_db_trap(type, (struct trapframe *)eframe);
459 
460 	if (type == T_KDB_BREAK) {
461 		/*
462 		 * back up an instruction and retry the instruction
463 		 * at the breakpoint address.  mc88110's exip reg
464 		 * already has the address of the exception instruction.
465 		 */
466 		if (CPU_IS88100)
467 			m88100_rewind_insn(eframe);
468 	}
469 
470 	return 0;
471 }
472 
473 /* enter at splhigh */
474 int
ddb_entry_trap(level,eframe)475 ddb_entry_trap(level, eframe)
476 	int level;
477 	db_regs_t *eframe;
478 {
479 	m88k_db_trap(T_KDB_ENTRY, (struct trapframe *)eframe);
480 
481 	return 0;
482 }
483 
484 /*
485  * Read bytes from kernel address space for debugger.
486  */
487 void
db_read_bytes(vaddr_t addr,size_t size,void * datap)488 db_read_bytes(vaddr_t addr, size_t size, void *datap)
489 {
490 	char *data = datap, *src;
491 
492 	src = (char *)addr;
493 
494 	while (size-- > 0) {
495 		*data++ = *src++;
496 	}
497 }
498 
499 /*
500  * Write bytes to kernel address space for debugger.
501  */
502 void
db_write_bytes(vaddr_t addr,size_t size,void * datap)503 db_write_bytes(vaddr_t addr, size_t size, void *datap)
504 {
505 	extern pt_entry_t *pmap_pte(pmap_t, vaddr_t);
506 	char *data = datap, *dst = (char *)addr;
507 	vaddr_t va;
508 	paddr_t pa;
509 	pt_entry_t *pte, opte, npte;
510 	size_t len, olen;
511 	int cpu = cpu_number();
512 
513 	while (size != 0) {
514 		va = trunc_page((vaddr_t)dst);
515 #ifdef M88100
516 		if (CPU_IS88100 && va >= BATC8_VA)
517 			pte = NULL;
518 		else
519 #endif
520 			pte = pmap_pte(pmap_kernel(), va);
521 		if (pte != NULL) {
522 			opte = *pte;
523 			pa = (opte & PG_FRAME) | ((vaddr_t)dst & PAGE_MASK);
524 		}
525 		len = PAGE_SIZE - ((vaddr_t)dst & PAGE_MASK);
526 		if (len > size)
527 			len = size;
528 		size -= olen = len;
529 
530 		if (pte != NULL && (opte & PG_RO)) {
531 			npte = opte & ~PG_RO;
532 			*pte = npte;
533 			cmmu_tlbis(cpu, va, npte);
534 		}
535 		while (len-- != 0)
536 			*dst++ = *data++;
537 		if (pte != NULL && (opte & PG_RO)) {
538 			*pte = opte;
539 			cmmu_tlbis(cpu, va, opte);
540 		}
541 		if (pte != NULL && (opte & (CACHE_INH | CACHE_WT)) == 0) {
542 			cmmu_dcache_wb(cpu, pa, olen);
543 			cmmu_icache_inv(cpu, pa, olen);
544 		}
545 	}
546 }
547 
548 /* display where all the cpus are stopped at */
549 void
m88k_db_where(addr,have_addr,count,modif)550 m88k_db_where(addr, have_addr, count, modif)
551 	db_expr_t addr;
552 	int have_addr;
553 	db_expr_t count;
554 	char *modif;
555 {
556 	const char *name;
557 	db_expr_t offset;
558 	vaddr_t l;
559 
560 	l = PC_REGS(&ddb_regs); /* clear low bits */
561 
562 	db_find_xtrn_sym_and_offset(l, &name, &offset);
563 	if (name && (u_int)offset <= db_maxoff)
564 		db_printf("stopped at 0x%lx  (%s+0x%lx)\n", l, name, offset);
565 	else
566 		db_printf("stopped at 0x%lx\n", l);
567 }
568 
569 /*
570  * Walk back a stack, looking for exception frames.
571  * These frames are recognized by the routine frame_is_sane. Frames
572  * only start with zero, so we only call frame_is_sane if the
573  * current address contains zero.
574  *
575  * If addr is given, it is assumed to an address on the stack to be
576  * searched. Otherwise, r31 of the current cpu is used.
577  */
578 void
m88k_db_frame_search(addr,have_addr,count,modif)579 m88k_db_frame_search(addr, have_addr, count, modif)
580 	db_expr_t addr;
581 	int have_addr;
582 	db_expr_t count;
583 	char *modif;
584 {
585 	if (have_addr)
586 		addr &= ~3; /* round to word */
587 	else
588 		addr = (ddb_regs.r[31]);
589 
590 	/* walk back up stack until 8k boundary, looking for 0 */
591 	while (addr & ((8 * 1024) - 1)) {
592 		if (frame_is_sane((db_regs_t *)addr, 1) != 0)
593 			db_printf("frame found at 0x%lx\n", addr);
594 		addr += 4;
595 	}
596 
597 	db_printf("(Walked back until 0x%lx)\n",addr);
598 }
599 
600 #ifdef MULTIPROCESSOR
601 
602 void
m88k_db_cpu_cmd(db_expr_t addr,int have_addr,db_expr_t count,char * modif)603 m88k_db_cpu_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
604 {
605 	cpuid_t cpu;
606 	struct cpu_info *ci;
607 	char state[15];
608 
609 	/* switch to another processor if requested */
610 	if (have_addr) {
611 		cpu = (cpuid_t)addr;
612 		if (cpu >= 0 && cpu < MAX_CPUS &&
613 		    ISSET(m88k_cpus[cpu].ci_flags, CIF_ALIVE)) {
614 			ddb_mp_nextcpu = cpu;
615 			db_cmd_loop_done = 1;
616 		} else {
617 			db_printf("cpu%ld is not active\n", cpu);
618 		}
619 		return;
620 	}
621 
622 	db_printf(" cpu  flags state          curproc  curpcb   depth    ipi\n");
623 	CPU_INFO_FOREACH(cpu, ci) {
624 		switch (ci->ci_ddb_state) {
625 		case CI_DDB_RUNNING:
626 			strlcpy(state, "running", sizeof state);
627 			break;
628 		case CI_DDB_ENTERDDB:
629 			strlcpy(state, "entering ddb", sizeof state);
630 			break;
631 		case CI_DDB_INDDB:
632 			strlcpy(state, "in ddb", sizeof state);
633 			break;
634 		case CI_DDB_PAUSE:
635 			strlcpy(state, "paused", sizeof state);
636 			break;
637 		default:
638 			snprintf(state, sizeof state, "unknown (%d)",
639 			    ci->ci_ddb_state);
640 			break;
641 		}
642 		db_printf("%ccpu%d   %02x  %-14s %08lx %08lx %3u %08x\n",
643 		    (cpu == cpu_number()) ? '*' : ' ', CPU_INFO_UNIT(ci),
644 		    ci->ci_flags, state, (register_t)ci->ci_curproc,
645 		    (register_t)ci->ci_curpcb, ci->ci_idepth, ci->ci_ipi);
646 	}
647 }
648 
649 #endif	/* MULTIPROCESSOR */
650 
651 /************************/
652 /* COMMAND TABLE / INIT */
653 /************************/
654 
655 const struct db_command db_machine_command_table[] = {
656 #ifdef MULTIPROCESSOR
657 	{ "ddbcpu",	m88k_db_cpu_cmd,	0,	NULL },
658 #endif
659 	{ "frame",	m88k_db_print_frame,	0,	NULL },
660 	{ "regs",	m88k_db_registers,	0,	NULL },
661 	{ "searchframe",m88k_db_frame_search,	0,	NULL },
662 	{ "where",	m88k_db_where,		0,	NULL },
663 #if defined(EXTRA_MACHDEP_COMMANDS)
664 	EXTRA_MACHDEP_COMMANDS
665 #endif
666 	{ NULL,		NULL,			0,	NULL }
667 };
668 
669 void
db_machine_init()670 db_machine_init()
671 {
672 #ifdef MULTIPROCESSOR
673 	__mp_lock_init(&ddb_mp_lock);
674 #endif
675 }
676