1/*	$OpenBSD: db_interface.c,v 1.15 2022/04/14 19:47:11 naddy Exp $	*/
2/*	$NetBSD: db_interface.c,v 1.37 2006/09/06 00:11:49 uwe Exp $	*/
3
4/*-
5 * Copyright (C) 2002 UCHIYAMA Yasushi.  All rights reserved.
6 * Copyright (c) 2000 Tsubai Masanari.  All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 *    derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include <sys/param.h>
32#include <sys/systm.h>
33#include <sys/proc.h>
34#include <sys/user.h>
35
36#include <uvm/uvm_extern.h>
37
38#include <dev/cons.h>
39
40#include <machine/db_machdep.h>
41#include <ddb/db_run.h>
42#include <ddb/db_sym.h>
43
44#include <sh/ubcreg.h>
45
46db_regs_t ddb_regs;		/* register state */
47
48
49#include <sh/cache.h>
50#include <sh/cache_sh3.h>
51#include <sh/cache_sh4.h>
52#include <sh/mmu.h>
53#include <sh/mmu_sh3.h>
54#include <sh/mmu_sh4.h>
55
56#include <ddb/db_command.h>
57#include <ddb/db_extern.h>
58#include <ddb/db_output.h>
59#include <ddb/db_var.h>
60
61void kdb_printtrap(u_int, int);
62
63void db_tlbdump_cmd(db_expr_t, int, db_expr_t, char *);
64void __db_tlbdump_page_size_sh4(uint32_t);
65void __db_tlbdump_pfn(uint32_t);
66void db_cachedump_cmd(db_expr_t, int, db_expr_t, char *);
67
68void __db_cachedump_sh3(vaddr_t);
69void __db_cachedump_sh4(vaddr_t);
70
71void db_stackcheck_cmd(db_expr_t, int, db_expr_t, char *);
72void db_frame_cmd(db_expr_t, int, db_expr_t, char *);
73void __db_print_symbol(db_expr_t);
74char *__db_procname_by_asid(int);
75
76const struct db_command db_machine_command_table[] = {
77	{ "tlb",	db_tlbdump_cmd,		0,	NULL },
78	{ "cache",	db_cachedump_cmd,	0,	NULL },
79	{ "frame",	db_frame_cmd,		0,	NULL },
80#ifdef KSTACK_DEBUG
81	{ "stack",	db_stackcheck_cmd,	0,	NULL },
82#endif
83	{ NULL }
84};
85
86void
87db_machine_init(void)
88{
89}
90
91void
92kdb_printtrap(u_int type, int code)
93{
94	int i;
95	i = type >> 5;
96
97	db_printf("%s mode trap: ", type & 1 ? "user" : "kernel");
98	if (i >= exp_types)
99		db_printf("type 0x%03x", type & ~1);
100	else
101		db_printf("%s", exp_type[i]);
102
103	db_printf(" code = 0x%x\n", code);
104}
105
106int
107db_ktrap(int type, int code, db_regs_t *regs)
108{
109	extern label_t *db_recover;
110	int s;
111
112	switch (type) {
113	case EXPEVT_TRAPA:	/* trapa instruction */
114	case EXPEVT_BREAK:	/* UBC */
115	case -1:		/* keyboard interrupt */
116		break;
117	default:
118		if (!db_panic && db_recover == NULL)
119			return 0;
120
121		kdb_printtrap(type, code);
122		if (db_recover != NULL) {
123			db_error("Faulted in DDB; continuing...\n");
124			/*NOTREACHED*/
125		}
126	}
127
128	/* XXX Should switch to kdb's own stack here. */
129
130	ddb_regs = *regs;
131
132	s = splhigh();
133	db_active++;
134	cnpollc(1);
135	db_trap(type, code);
136	cnpollc(0);
137	db_active--;
138	splx(s);
139
140	*regs = ddb_regs;
141
142	return 1;
143}
144
145void
146db_enter(void)
147{
148	__asm volatile("trapa %0" :: "i"(_SH_TRA_BREAK));
149}
150
151#define	M_BSR	0xf000
152#define	I_BSR	0xb000
153#define	M_BSRF	0xf0ff
154#define	I_BSRF	0x0003
155#define	M_JSR	0xf0ff
156#define	I_JSR	0x400b
157#define	M_RTS	0xffff
158#define	I_RTS	0x000b
159#define	M_RTE	0xffff
160#define	I_RTE	0x002b
161
162int
163inst_call(int inst)
164{
165#if _BYTE_ORDER == BIG_ENDIAN
166	inst >>= 16;
167#endif
168	return (inst & M_BSR) == I_BSR || (inst & M_BSRF) == I_BSRF ||
169	       (inst & M_JSR) == I_JSR;
170}
171
172int
173inst_return(int inst)
174{
175#if _BYTE_ORDER == BIG_ENDIAN
176	inst >>= 16;
177#endif
178	return (inst & M_RTS) == I_RTS;
179}
180
181int
182inst_trap_return(int inst)
183{
184#if _BYTE_ORDER == BIG_ENDIAN
185	inst >>= 16;
186#endif
187	return (inst & M_RTE) == I_RTE;
188}
189
190void
191db_set_single_step(db_regs_t *regs)
192{
193
194	_reg_write_2(SH_(BBRA), 0);		/* disable break */
195	_reg_write_4(SH_(BARA), 0);		/* break address */
196	_reg_write_1(SH_(BASRA), 0);		/* break ASID */
197	_reg_write_1(SH_(BAMRA), 0x07);		/* break always */
198	_reg_write_2(SH_(BRCR),  0x400);	/* break after each execution */
199
200	regs->tf_ubc = 0x0014;	/* will be written to BBRA */
201}
202
203void
204db_clear_single_step(db_regs_t *regs)
205{
206
207	regs->tf_ubc = 0;
208}
209
210#define	ON(x, c)	((x) & (c) ? '|' : '.')
211
212/*
213 * MMU
214 */
215void
216db_tlbdump_cmd(db_expr_t addr, int have_addr, db_expr_t count,
217    char *modif)
218{
219	static const char *pr[] = { "_r", "_w", "rr", "ww" };
220	static const char title[] =
221	    "   VPN      ASID    PFN  AREA VDCGWtPR  SZ";
222	static const char title2[] =
223	    "          U/K                       U/K";
224	uint32_t r, e;
225	int i;
226#ifdef SH3
227	if (CPU_IS_SH3) {
228		/* MMU configuration. */
229		r = _reg_read_4(SH3_MMUCR);
230		db_printf("%s-mode, %s virtual storage mode\n",
231		    r & SH3_MMUCR_IX
232		    ? "ASID + VPN" : "VPN only",
233		    r & SH3_MMUCR_SV ? "single" : "multiple");
234		i = _reg_read_4(SH3_PTEH) & SH3_PTEH_ASID_MASK;
235		db_printf("ASID=%d (%s)", i, __db_procname_by_asid(i));
236
237		db_printf("---TLB DUMP---\n%s\n%s\n", title, title2);
238		for (i = 0; i < SH3_MMU_WAY; i++) {
239			db_printf(" [way %d]\n", i);
240			for (e = 0; e < SH3_MMU_ENTRY; e++) {
241				uint32_t a;
242				/* address/data array common offset. */
243				a = (e << SH3_MMU_VPN_SHIFT) |
244				    (i << SH3_MMU_WAY_SHIFT);
245
246				r = _reg_read_4(SH3_MMUAA | a);
247				if (r == 0) {
248					db_printf("---------- - --- ----------"
249					    " - ----x --  --\n");
250				} else {
251					vaddr_t va;
252					int asid;
253					asid = r & SH3_MMUAA_D_ASID_MASK;
254					r &= SH3_MMUAA_D_VPN_MASK_1K;
255					va = r | (e << SH3_MMU_VPN_SHIFT);
256					db_printf("0x%08lx %c %3d", va,
257					    (int)va < 0 ? 'K' : 'U', asid);
258
259					r = _reg_read_4(SH3_MMUDA | a);
260					__db_tlbdump_pfn(r);
261
262					db_printf(" %c%c%c%cx %s %2dK\n",
263					    ON(r, SH3_MMUDA_D_V),
264					    ON(r, SH3_MMUDA_D_D),
265					    ON(r, SH3_MMUDA_D_C),
266					    ON(r, SH3_MMUDA_D_SH),
267					    pr[(r & SH3_MMUDA_D_PR_MASK) >>
268						SH3_MMUDA_D_PR_SHIFT],
269					    r & SH3_MMUDA_D_SZ ? 4 : 1);
270				}
271			}
272		}
273	}
274#endif /* SH3 */
275#ifdef SH4
276	if (CPU_IS_SH4) {
277		/* MMU configuration */
278		r = _reg_read_4(SH4_MMUCR);
279		db_printf("%s virtual storage mode, SQ access: (kernel%s)\n",
280		    r & SH3_MMUCR_SV ? "single" : "multiple",
281		    r & SH4_MMUCR_SQMD ? "" : "/user");
282		db_printf("random counter limit=%d\n",
283		    (r & SH4_MMUCR_URB_MASK) >> SH4_MMUCR_URB_SHIFT);
284
285		i = _reg_read_4(SH4_PTEH) & SH4_PTEH_ASID_MASK;
286		db_printf("ASID=%d (%s)", i, __db_procname_by_asid(i));
287
288		/* Dump ITLB */
289		db_printf("---ITLB DUMP ---\n%s TC SA\n%s\n", title, title2);
290		for (i = 0; i < 4; i++) {
291			e = i << SH4_ITLB_E_SHIFT;
292
293			r = _reg_read_4(SH4_ITLB_AA | e);
294			db_printf("0x%08x   %3d",
295			    r & SH4_ITLB_AA_VPN_MASK,
296			    r & SH4_ITLB_AA_ASID_MASK);
297
298			r = _reg_read_4(SH4_ITLB_DA1 | e);
299			__db_tlbdump_pfn(r);
300			db_printf(" %c_%c%c_ %s ",
301			    ON(r, SH4_ITLB_DA1_V),
302			    ON(r, SH4_ITLB_DA1_C),
303			    ON(r, SH4_ITLB_DA1_SH),
304			    pr[(r & SH4_ITLB_DA1_PR) >>
305				SH4_UTLB_DA1_PR_SHIFT]);
306			__db_tlbdump_page_size_sh4(r);
307
308#if 0 /* XXX: causes weird effects on landisk */
309			r = _reg_read_4(SH4_ITLB_DA2 | e);
310			db_printf(" %c  %d\n",
311			    ON(r, SH4_ITLB_DA2_TC),
312			    r & SH4_ITLB_DA2_SA_MASK);
313#else
314			db_printf("\n");
315#endif
316		}
317
318		/* Dump UTLB */
319		db_printf("---UTLB DUMP---\n%s TC SA\n%s\n", title, title2);
320		for (i = 0; i < 64; i++) {
321			e = i << SH4_UTLB_E_SHIFT;
322
323			r = _reg_read_4(SH4_UTLB_AA | e);
324			db_printf("0x%08x   %3d",
325			    r & SH4_UTLB_AA_VPN_MASK,
326			    r & SH4_UTLB_AA_ASID_MASK);
327
328			r = _reg_read_4(SH4_UTLB_DA1 | e);
329			__db_tlbdump_pfn(r);
330			db_printf(" %c%c%c%c%c %s ",
331			    ON(r, SH4_UTLB_DA1_V),
332			    ON(r, SH4_UTLB_DA1_D),
333			    ON(r, SH4_UTLB_DA1_C),
334			    ON(r, SH4_UTLB_DA1_SH),
335			    ON(r, SH4_UTLB_DA1_WT),
336			    pr[(r & SH4_UTLB_DA1_PR_MASK) >>
337				SH4_UTLB_DA1_PR_SHIFT]
338			    );
339			__db_tlbdump_page_size_sh4(r);
340
341#if 0 /* XXX: causes weird effects on landisk */
342			r = _reg_read_4(SH4_UTLB_DA2 | e);
343			db_printf(" %c  %d\n",
344			    ON(r, SH4_UTLB_DA2_TC),
345			    r & SH4_UTLB_DA2_SA_MASK);
346#else
347			db_printf("\n");
348#endif
349		}
350	}
351#endif /* SH4 */
352}
353
354void
355__db_tlbdump_pfn(uint32_t r)
356{
357	uint32_t pa = (r & SH3_MMUDA_D_PPN_MASK);
358
359	db_printf(" 0x%08x %d", pa, (pa >> 26) & 7);
360}
361
362char *
363__db_procname_by_asid(int asid)
364{
365	static char notfound[] = "---";
366	struct process *pr;
367
368	LIST_FOREACH(pr, &allprocess, ps_list) {
369		if (pr->ps_vmspace->vm_map.pmap->pm_asid == asid)
370			return (pr->ps_comm);
371	}
372
373	return (notfound);
374}
375
376#ifdef SH4
377void
378__db_tlbdump_page_size_sh4(uint32_t r)
379{
380	switch (r & SH4_PTEL_SZ_MASK) {
381	case SH4_PTEL_SZ_1K:
382		db_printf(" 1K");
383		break;
384	case SH4_PTEL_SZ_4K:
385		db_printf(" 4K");
386		break;
387	case SH4_PTEL_SZ_64K:
388		db_printf("64K");
389		break;
390	case SH4_PTEL_SZ_1M:
391		db_printf(" 1M");
392		break;
393	}
394}
395#endif /* SH4 */
396
397/*
398 * CACHE
399 */
400void
401db_cachedump_cmd(db_expr_t addr, int have_addr, db_expr_t count,
402    char *modif)
403{
404#ifdef SH3
405	if (CPU_IS_SH3)
406		__db_cachedump_sh3(have_addr ? addr : 0);
407#endif
408#ifdef SH4
409	if (CPU_IS_SH4)
410		__db_cachedump_sh4(have_addr ? addr : 0);
411#endif
412}
413
414#ifdef SH3
415void
416__db_cachedump_sh3(vaddr_t va_start)
417{
418	uint32_t r;
419	vaddr_t va, va_end, cca;
420	int entry, way;
421
422	RUN_P2;
423	/* disable cache */
424	_reg_write_4(SH3_CCR,
425	    _reg_read_4(SH3_CCR) & ~SH3_CCR_CE);
426
427	if (va_start) {
428		va = va_start & ~(sh_cache_line_size - 1);
429		va_end = va + sh_cache_line_size;
430	} else {
431		va = 0;
432		va_end = sh_cache_way_size;
433	}
434
435	db_printf("%d-way, way-size=%dB, way-shift=%d, entry-mask=%08x, "
436	    "line-size=%dB \n", sh_cache_ways, sh_cache_way_size,
437	    sh_cache_way_shift, sh_cache_entry_mask, sh_cache_line_size);
438	db_printf("Entry  Way 0  UV   Way 1  UV   Way 2  UV   Way 3  UV\n");
439	for (; va < va_end; va += sh_cache_line_size) {
440		entry = va & sh_cache_entry_mask;
441		cca = SH3_CCA | entry;
442		db_printf(" %3d ", entry >> CCA_ENTRY_SHIFT);
443		for (way = 0; way < sh_cache_ways; way++) {
444			r = _reg_read_4(cca | (way << sh_cache_way_shift));
445			db_printf("%08x %c%c ", r & CCA_TAGADDR_MASK,
446			    ON(r, CCA_U), ON(r, CCA_V));
447		}
448		db_printf("\n");
449	}
450
451	/* enable cache */
452	_reg_bset_4(SH3_CCR, SH3_CCR_CE);
453	sh_icache_sync_all();
454
455	RUN_P1;
456}
457#endif /* SH3 */
458
459#ifdef SH4
460void
461__db_cachedump_sh4(vaddr_t va)
462{
463	uint32_t r, e;
464	int i, istart, iend;
465
466	RUN_P2; /* must access from P2 */
467
468	/* disable I/D-cache */
469	_reg_write_4(SH4_CCR,
470	    _reg_read_4(SH4_CCR) & ~(SH4_CCR_ICE | SH4_CCR_OCE));
471
472	if (va) {
473		istart = ((va & CCIA_ENTRY_MASK) >> CCIA_ENTRY_SHIFT) & ~3;
474		iend = istart + 4;
475	} else {
476		istart = 0;
477		iend = SH4_ICACHE_SIZE / SH4_CACHE_LINESZ;
478	}
479
480	db_printf("[I-cache]\n");
481	db_printf("  Entry             V           V           V           V\n");
482	for (i = istart; i < iend; i++) {
483		if ((i & 3) == 0)
484			db_printf("\n[%3d-%3d] ", i, i + 3);
485		r = _reg_read_4(SH4_CCIA | (i << CCIA_ENTRY_SHIFT));
486		db_printf("%08x _%c ", r & CCIA_TAGADDR_MASK, ON(r, CCIA_V));
487	}
488
489	db_printf("\n[D-cache]\n");
490	db_printf("  Entry            UV          UV          UV          UV\n");
491	for (i = istart; i < iend; i++) {
492		if ((i & 3) == 0)
493			db_printf("\n[%3d-%3d] ", i, i + 3);
494		e = (i << CCDA_ENTRY_SHIFT);
495		r = _reg_read_4(SH4_CCDA | e);
496		db_printf("%08x %c%c ", r & CCDA_TAGADDR_MASK, ON(r, CCDA_U),
497		    ON(r, CCDA_V));
498
499	}
500	db_printf("\n");
501
502	_reg_write_4(SH4_CCR,
503	    _reg_read_4(SH4_CCR) | SH4_CCR_ICE | SH4_CCR_OCE);
504	sh_icache_sync_all();
505
506	RUN_P1;
507}
508#endif /* SH4 */
509
510#undef ON
511
512void
513db_frame_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
514{
515	struct switchframe *sf = &curpcb->pcb_sf;
516	struct trapframe *tf, *tftop;
517
518	/* Print switch frame */
519	db_printf("[switch frame]\n");
520
521#define	SF(x)	db_printf("sf_" #x "\t\t0x%08x\t", sf->sf_ ## x);	\
522		__db_print_symbol(sf->sf_ ## x)
523
524	SF(sr);
525	SF(r15);
526	SF(r14);
527	SF(r13);
528	SF(r12);
529	SF(r11);
530	SF(r10);
531	SF(r9);
532	SF(r8);
533	SF(pr);
534	db_printf("sf_r6_bank\t0x%08x\n", sf->sf_r6_bank);
535	db_printf("sf_r7_bank\t0x%08x\n", sf->sf_r7_bank);
536
537
538	/* Print trap frame stack */
539	db_printf("[trap frame]\n");
540
541	__asm("stc r6_bank, %0" : "=r"(tf));
542	tftop = (struct trapframe *)((vaddr_t)curpcb + PAGE_SIZE);
543
544	for (; tf != tftop; tf++) {
545		db_printf("-- %p-%p --\n", tf, tf + 1);
546		db_printf("tf_expevt\t0x%08x\n", tf->tf_expevt);
547
548#define	TF(x)	db_printf("tf_" #x "\t\t0x%08x\t", tf->tf_ ## x);	\
549		__db_print_symbol(tf->tf_ ## x)
550
551		TF(ubc);
552		TF(spc);
553		TF(ssr);
554		TF(gbr);
555		TF(macl);
556		TF(mach);
557		TF(pr);
558		TF(r13);
559		TF(r12);
560		TF(r11);
561		TF(r10);
562		TF(r9);
563		TF(r8);
564		TF(r7);
565		TF(r6);
566		TF(r5);
567		TF(r4);
568		TF(r3);
569		TF(r2);
570		TF(r1);
571		TF(r0);
572		TF(r15);
573		TF(r14);
574	}
575#undef	SF
576#undef	TF
577}
578
579void
580__db_print_symbol(db_expr_t value)
581{
582	char *name;
583	db_expr_t offset;
584
585	db_find_sym_and_offset((vaddr_t)value, &name, &offset);
586	if (name != NULL && offset <= db_maxoff && offset != value)
587		db_printsym(value, DB_STGY_ANY, db_printf);
588
589	db_printf("\n");
590}
591
592#ifdef KSTACK_DEBUG
593/*
594 * Stack overflow check
595 */
596void
597db_stackcheck_cmd(db_expr_t addr, int have_addr, db_expr_t count,
598		  char *modif)
599{
600	struct proc *p;
601	struct user *u;
602	struct pcb *pcb;
603	uint32_t *t32;
604	uint8_t *t8;
605	int i, j;
606
607#define	MAX_STACK	(USPACE - PAGE_SIZE)
608#define	MAX_FRAME	(PAGE_SIZE - sizeof(struct user))
609
610	db_printf("stack max: %d byte, frame max %d byte,"
611	    " sizeof(struct trapframe) %d byte\n", MAX_STACK, MAX_FRAME,
612	    sizeof(struct trapframe));
613	db_printf("   PID.LID    "
614		  "stack top    max used    frame top     max used"
615		  "  nest\n");
616
617	LIST_FOREACH(p, &allproc, p_list) {
618		u = p->p_addr;
619		pcb = &u->u_pcb;
620		/* stack */
621		t32 = (uint32_t *)(pcb->pcb_sf.sf_r7_bank - MAX_STACK);
622		for (i = 0; *t32++ == 0xa5a5a5a5; i++)
623			continue;
624		i = MAX_STACK - i * sizeof(int);
625
626		/* frame */
627		t8 = (uint8_t *)((vaddr_t)pcb + PAGE_SIZE - MAX_FRAME);
628		for (j = 0; *t8++ == 0x5a; j++)
629			continue;
630		j = MAX_FRAME - j;
631
632		db_printf("%6d 0x%08x %6d (%3d%%) 0x%08lx %6d (%3d%%) %d %s\n",
633		    p->p_lid,
634		    pcb->pcb_sf.sf_r7_bank, i, i * 100 / MAX_STACK,
635		    (vaddr_t)pcb + PAGE_SIZE, j, j * 100 / MAX_FRAME,
636		    j / sizeof(struct trapframe),
637		    p->p_p->ps_comm);
638	}
639#undef	MAX_STACK
640#undef	MAX_FRAME
641}
642#endif /* KSTACK_DEBUG */
643