xref: /netbsd-src/sys/arch/riscv/riscv/db_interface.c (revision b426528770b1ff548bd444360bac04d668221a78)
1 /*	$NetBSD: db_interface.c,v 1.6 2024/11/25 22:04:14 skrll Exp $	*/
2 
3 /*
4  * Mach Operating System
5  * Copyright (c) 1991,1990 Carnegie Mellon University
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 ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
15  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
16  * 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 Mellon
26  * the rights to redistribute these changes.
27  */
28 
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: db_interface.c,v 1.6 2024/11/25 22:04:14 skrll Exp $");
31 
32 #ifdef _KERNEL_OPT
33 #include "opt_multiprocessor.h"
34 #include "opt_kgdb.h"
35 #endif
36 
37 #define __PMAP_PRIVATE
38 
39 #include <sys/types.h>
40 #include <sys/param.h>
41 
42 #include <sys/atomic.h>
43 #include <sys/cpu.h>
44 #include <sys/proc.h>
45 #include <sys/reboot.h>
46 #include <sys/systm.h>
47 
48 #include <uvm/uvm_extern.h>
49 
50 #include <dev/cons.h>
51 
52 #include <machine/db_machdep.h>
53 
54 #include <ddb/db_access.h>
55 #include <ddb/db_active.h>
56 #include <ddb/db_user.h>
57 #ifndef KGDB
58 #include <ddb/db_command.h>
59 #include <ddb/db_output.h>
60 #include <ddb/db_sym.h>
61 #include <ddb/db_extern.h>
62 #include <ddb/db_interface.h>
63 #include <ddb/db_lex.h>
64 #include <ddb/db_run.h>	/* for db_continue_cmd() proto */
65 #endif
66 
67 #define NOCPU   ~0
68 volatile u_int ddb_cpu = NOCPU;
69 
70 int		db_active = 0;
71 
72 #ifdef _KERNEL
73 db_regs_t	ddb_regs;
74 
75 #ifdef MULTIPROCESSOR
76 static void db_mach_cpu_cmd(db_expr_t, bool, db_expr_t, const char *);
77 #endif
78 static void db_mach_reset_cmd(db_expr_t, bool, db_expr_t, const char *);
79 
80 void db_tlbdump_cmd(db_expr_t, bool, db_expr_t, const char *);
81 void db_kvtophys_cmd(db_expr_t, bool, db_expr_t, const char *);
82 
83 paddr_t kvtophys(vaddr_t);
84 #endif
85 
86 
87 const struct db_command db_machine_command_table[] = {
88 #ifdef _KERNEL
89 #ifdef MULTIPROCESSOR
90 	{ DDB_ADD_CMD("cpu",	db_mach_cpu_cmd,	0,
91 	  "switch to another cpu", "cpu#", NULL) },
92 #endif
93 	{ DDB_ADD_CMD("kvtop",	db_kvtophys_cmd,	0,
94 		"Print the physical address for a given kernel virtual address",
95 		"address",
96 		"   address:\tvirtual address to look up") },
97 	{ DDB_ADD_CMD("reset",	db_mach_reset_cmd,	CS_NOREPEAT,
98 		"Initiate hardware reset",
99 		NULL, NULL) },
100 	{ DDB_ADD_CMD("tlb",	db_tlbdump_cmd,		0,
101 		"Print out TLB entries. (only works with options DEBUG)",
102 		NULL, NULL) },
103 #endif
104 	{ DDB_END_CMD },
105 };
106 
107 #ifdef _KERNEL
108 
109 #ifndef KGDB
110 int
111 kdb_trap(int type, db_regs_t *regs)
112 {
113 	switch (type) {
114 	case CAUSE_BREAKPOINT:	/* breakpoint */
115 		printf("kernel: breakpoint\n");
116 		break;
117 	case -1:		/* keyboard interrupt */
118 		printf("kernel: kdbint trap\n");
119 		break;
120 	default:
121 		printf("kernel: cause %d\n", type);
122 		if (db_recover != 0) {
123 			db_error("Faulted in DDB; continuing...\n");
124 			/*NOTREACHED*/
125 		}
126 		break;
127 	}
128 
129 	const int s = splhigh();
130 	struct cpu_info * const ci = curcpu();
131 
132 #if defined(MULTIPROCESSOR)
133 	bool first_in_ddb = false;
134 	const u_int cpu_me = cpu_index(ci);
135 	const u_int old_ddb_cpu = atomic_cas_uint(&ddb_cpu, NOCPU, cpu_me);
136 	if (old_ddb_cpu == NOCPU) {
137 		first_in_ddb = true;
138 		cpu_pause_others();
139 	} else {
140 		if (old_ddb_cpu != cpu_me) {
141 			KASSERT(cpu_is_paused(cpu_me));
142 			cpu_pause();
143 			splx(s);
144 			return 1;
145 		}
146 	}
147 	KASSERT(!cpu_is_paused(cpu_me));
148 #endif
149 
150 	ddb_regs = *regs;
151 	ci->ci_ddb_regs = &ddb_regs;
152 	db_active++;
153 	cnpollc(true);
154 	db_trap(type, 0 /*code*/);
155 	cnpollc(false);
156 	db_active--;
157 	ci->ci_ddb_regs = NULL;
158 	*regs = ddb_regs;
159 
160 #if defined(MULTIPROCESSOR)
161 	if (atomic_cas_uint(&ddb_cpu, cpu_me, NOCPU) == cpu_me) {
162 		cpu_resume_others();
163 	} else {
164 		cpu_resume(ddb_cpu);
165 		if (first_in_ddb)
166 			cpu_pause();
167 	}
168 #endif
169 
170 	splx(s);
171 	return 1;
172 }
173 #endif	/* !KGDB */
174 
175 
176 #ifndef KGDB
177 void
178 db_tlbdump_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
179 	       const char *modif)
180 {
181 }
182 
183 void
184 db_kvtophys_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
185 		const char *modif)
186 {
187 
188 	if (!have_addr)
189 		return;
190 }
191 
192 
193 static void
194 db_mach_reset_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
195 		const char *modif)
196 {
197 }
198 
199 #endif	/* !KGDB */
200 
201 #ifdef MULTIPROCESSOR
202 
203 bool
204 ddb_running_on_this_cpu_p(void)
205 {
206 	return ddb_cpu == cpu_index(curcpu());
207 }
208 
209 bool
210 ddb_running_on_any_cpu_p(void)
211 {
212 	return ddb_cpu != NOCPU;
213 }
214 
215 void
216 db_resume_others(void)
217 {
218 	u_int cpu_me = cpu_index(curcpu());
219 
220 	if (atomic_cas_uint(&ddb_cpu, cpu_me, NOCPU) == cpu_me)
221 		cpu_resume_others();
222 }
223 
224 static void
225 db_mach_cpu_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif)
226 {
227 	CPU_INFO_ITERATOR cii;
228 	struct cpu_info *ci;
229 
230 	if (!have_addr) {
231 		cpu_debug_dump();
232 		return;
233 	}
234 	for (CPU_INFO_FOREACH(cii, ci)) {
235 		if (cpu_index(ci) == addr)
236 			break;
237 	}
238 	if (ci == NULL) {
239 		db_printf("CPU %ld not configured\n", (long)addr);
240 		return;
241 	}
242 	if (ci != curcpu()) {
243 		if (!cpu_is_paused(cpu_index(ci))) {
244 			db_printf("CPU %ld not paused\n", (long)addr);
245 			return;
246 		}
247 		(void)atomic_cas_uint(&ddb_cpu, cpu_index(curcpu()), cpu_index(ci));
248 		db_continue_cmd(0, false, 0, "");
249 	}
250 }
251 #endif	/* MULTIPROCESSOR */
252 
253 #endif	/* _KERNEL */
254