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