Home | History | Annotate | Line # | Download | only in riscv
      1 /*	$NetBSD: db_interface.c,v 1.7 2026/05/22 06:15:01 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 (at) 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.7 2026/05/22 06:15:01 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_cpuinfo_cmd(db_expr_t, bool, db_expr_t, const char *);
     81 void db_tlbdump_cmd(db_expr_t, bool, db_expr_t, const char *);
     82 void db_kvtophys_cmd(db_expr_t, bool, db_expr_t, const char *);
     83 
     84 paddr_t kvtophys(vaddr_t);
     85 #endif
     86 
     87 
     88 const struct db_command db_machine_command_table[] = {
     89 #ifdef _KERNEL
     90 #ifdef MULTIPROCESSOR
     91 	{ DDB_ADD_CMD("cpu",	db_mach_cpu_cmd,	0,
     92 		"switch to another cpu", "cpu#", NULL) },
     93 #endif
     94 	{ DDB_ADD_CMD("cpuinfo", db_cpuinfo_cmd,	0,
     95 		"Displays the cpuinfo",
     96 		NULL, NULL)
     97 	},
     98 	{ DDB_ADD_CMD("kvtop",	db_kvtophys_cmd,	0,
     99 		"Print the physical address for a given kernel virtual address",
    100 		"address",
    101 		"   address:\tvirtual address to look up") },
    102 	{ DDB_ADD_CMD("reset",	db_mach_reset_cmd,	CS_NOREPEAT,
    103 		"Initiate hardware reset",
    104 		NULL, NULL) },
    105 	{ DDB_ADD_CMD("tlb",	db_tlbdump_cmd,		0,
    106 		"Print out TLB entries. (only works with options DEBUG)",
    107 		NULL, NULL) },
    108 #endif
    109 	{ DDB_END_CMD },
    110 };
    111 
    112 #ifdef _KERNEL
    113 
    114 #ifndef KGDB
    115 int
    116 kdb_trap(int type, db_regs_t *regs)
    117 {
    118 	switch (type) {
    119 	case CAUSE_BREAKPOINT:	/* breakpoint */
    120 		printf("kernel: breakpoint\n");
    121 		break;
    122 	case -1:		/* keyboard interrupt */
    123 		printf("kernel: kdbint trap\n");
    124 		break;
    125 	default:
    126 		printf("kernel: cause %d\n", type);
    127 		if (db_recover != 0) {
    128 			db_error("Faulted in DDB; continuing...\n");
    129 			/*NOTREACHED*/
    130 		}
    131 		break;
    132 	}
    133 
    134 	const int s = splhigh();
    135 	struct cpu_info * const ci = curcpu();
    136 
    137 #if defined(MULTIPROCESSOR)
    138 	bool first_in_ddb = false;
    139 	const u_int cpu_me = cpu_index(ci);
    140 	const u_int old_ddb_cpu = atomic_cas_uint(&ddb_cpu, NOCPU, cpu_me);
    141 	if (old_ddb_cpu == NOCPU) {
    142 		first_in_ddb = true;
    143 		cpu_pause_others();
    144 	} else {
    145 		if (old_ddb_cpu != cpu_me) {
    146 			KASSERT(cpu_is_paused(cpu_me));
    147 			cpu_pause();
    148 			splx(s);
    149 			return 1;
    150 		}
    151 	}
    152 	KASSERT(!cpu_is_paused(cpu_me));
    153 #endif
    154 
    155 	ddb_regs = *regs;
    156 	ci->ci_ddb_regs = &ddb_regs;
    157 	db_active++;
    158 	cnpollc(true);
    159 	db_trap(type, 0 /*code*/);
    160 	cnpollc(false);
    161 	db_active--;
    162 	ci->ci_ddb_regs = NULL;
    163 	*regs = ddb_regs;
    164 
    165 #if defined(MULTIPROCESSOR)
    166 	if (atomic_cas_uint(&ddb_cpu, cpu_me, NOCPU) == cpu_me) {
    167 		cpu_resume_others();
    168 	} else {
    169 		cpu_resume(ddb_cpu);
    170 		if (first_in_ddb)
    171 			cpu_pause();
    172 	}
    173 #endif
    174 
    175 	splx(s);
    176 	return 1;
    177 }
    178 #endif	/* !KGDB */
    179 
    180 
    181 #ifndef KGDB
    182 void
    183 db_tlbdump_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
    184 	       const char *modif)
    185 {
    186 }
    187 
    188 void
    189 db_kvtophys_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
    190 		const char *modif)
    191 {
    192 
    193 	if (!have_addr)
    194 		return;
    195 }
    196 
    197 
    198 static void
    199 show_cpuinfo(struct cpu_info *kci)
    200 {
    201 	struct cpu_info cpuinfobuf;
    202 	cpuid_t cpuid;
    203 	int i;
    204 
    205 	db_read_bytes((db_addr_t)kci, sizeof(cpuinfobuf), (char *)&cpuinfobuf);
    206 
    207 	struct cpu_info *ci = &cpuinfobuf;
    208 	cpuid = ci->ci_cpuid;
    209 	db_printf("cpu_info=%p, cpu_name=%s\n", kci, ci->ci_cpuname);
    210 	db_printf("%p cpu[%lu].ci_cpuid              = %lu\n",
    211 	    &ci->ci_cpuid, cpuid, ci->ci_cpuid);
    212 	db_printf("%p cpu[%lu].ci_curlwp             = %p\n",
    213 	    &ci->ci_curlwp, cpuid, ci->ci_curlwp);
    214 	for (i = 0; i < SOFTINT_COUNT; i++) {
    215 		db_printf("%p cpu[%lu].ci_softlwps[%d]        = %p\n",
    216 		    &ci->ci_softlwps[i], cpuid, i, ci->ci_softlwps[i]);
    217 	}
    218 	db_printf("%p cpu[%lu].ci_want_resched       = %d\n",
    219 	    &ci->ci_want_resched, cpuid, ci->ci_want_resched);
    220 	db_printf("%p cpu[%lu].ci_cpl                = %d\n",
    221 	    &ci->ci_cpl, cpuid, ci->ci_cpl);
    222 	db_printf("%p cpu[%lu].ci_softints           = 0x%08x\n",
    223 	    &ci->ci_softints, cpuid, ci->ci_softints);
    224 	db_printf("%p cpu[%lu].ci_intr_depth         = %u\n",
    225 	    &ci->ci_intr_depth, cpuid, ci->ci_intr_depth);
    226 	db_printf("%p cpu[%lu].ci_lastintr           = %" PRIu64 "\n",
    227 	    &ci->ci_lastintr, cpuid, ci->ci_lastintr);
    228 	db_printf("%p cpu[%lu].ci_lastintr_scheduled = %" PRIu64 "\n",
    229 	    &ci->ci_lastintr_scheduled, cpuid, ci->ci_lastintr_scheduled);
    230 }
    231 
    232 void
    233 db_cpuinfo_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
    234     const char *modif)
    235 {
    236 #ifdef MULTIPROCESSOR
    237 	CPU_INFO_ITERATOR cii;
    238 	struct cpu_info *ci;
    239 	bool showall = false;
    240 
    241 	if (modif != NULL) {
    242 		for (; *modif != '\0'; modif++) {
    243 			switch (*modif) {
    244 			case 'a':
    245 				showall = true;
    246 				break;
    247 			}
    248 		}
    249 	}
    250 
    251 	if (showall) {
    252 		for (CPU_INFO_FOREACH(cii, ci)) {
    253 			show_cpuinfo(ci);
    254 		}
    255 	} else
    256 #endif /* MULTIPROCESSOR */
    257 		show_cpuinfo(curcpu());
    258 }
    259 
    260 
    261 static void
    262 db_mach_reset_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
    263 		const char *modif)
    264 {
    265 }
    266 
    267 #endif	/* !KGDB */
    268 
    269 #ifdef MULTIPROCESSOR
    270 
    271 bool
    272 ddb_running_on_this_cpu_p(void)
    273 {
    274 	return ddb_cpu == cpu_index(curcpu());
    275 }
    276 
    277 bool
    278 ddb_running_on_any_cpu_p(void)
    279 {
    280 	return ddb_cpu != NOCPU;
    281 }
    282 
    283 void
    284 db_resume_others(void)
    285 {
    286 	u_int cpu_me = cpu_index(curcpu());
    287 
    288 	if (atomic_cas_uint(&ddb_cpu, cpu_me, NOCPU) == cpu_me)
    289 		cpu_resume_others();
    290 }
    291 
    292 static void
    293 db_mach_cpu_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif)
    294 {
    295 	CPU_INFO_ITERATOR cii;
    296 	struct cpu_info *ci;
    297 
    298 	if (!have_addr) {
    299 		cpu_debug_dump();
    300 		return;
    301 	}
    302 	for (CPU_INFO_FOREACH(cii, ci)) {
    303 		if (cpu_index(ci) == addr)
    304 			break;
    305 	}
    306 	if (ci == NULL) {
    307 		db_printf("CPU %ld not configured\n", (long)addr);
    308 		return;
    309 	}
    310 	if (ci != curcpu()) {
    311 		if (!cpu_is_paused(cpu_index(ci))) {
    312 			db_printf("CPU %ld not paused\n", (long)addr);
    313 			return;
    314 		}
    315 		(void)atomic_cas_uint(&ddb_cpu, cpu_index(curcpu()), cpu_index(ci));
    316 		db_continue_cmd(0, false, 0, "");
    317 	}
    318 }
    319 #endif	/* MULTIPROCESSOR */
    320 
    321 #endif	/* _KERNEL */
    322