1 /* $NetBSD: db_interface.c,v 1.99 2023/02/19 11:19:51 simonb 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.99 2023/02/19 11:19:51 simonb Exp $");
31
32 #ifdef _KERNEL_OPT
33 #include "opt_multiprocessor.h"
34 #include "opt_cputype.h" /* which mips CPUs do we support? */
35 #include "opt_ddb.h"
36 #include "opt_kgdb.h"
37 #endif
38
39 #define __PMAP_PRIVATE
40
41 #include <sys/types.h>
42 #include <sys/systm.h>
43 #include <sys/param.h>
44 #include <sys/proc.h>
45 #include <sys/reboot.h>
46 #include <sys/atomic.h>
47 #include <sys/cpu.h>
48
49 #include <uvm/uvm_extern.h>
50
51 #include <mips/regnum.h>
52 #include <mips/cache.h>
53 #include <mips/pcb.h>
54 #include <mips/pte.h>
55 #include <mips/locore.h>
56 #include <mips/mips_opcode.h>
57 #include <dev/cons.h>
58
59 #include <machine/int_fmtio.h>
60 #include <machine/db_machdep.h>
61 #include <ddb/db_access.h>
62 #include <ddb/db_active.h>
63 #include <ddb/db_user.h>
64 #ifndef KGDB
65 #include <ddb/db_command.h>
66 #include <ddb/db_output.h>
67 #include <ddb/db_sym.h>
68 #include <ddb/db_extern.h>
69 #include <ddb/db_interface.h>
70 #include <ddb/db_lex.h>
71 #include <ddb/db_run.h> /* for db_continue_cmd() proto */
72 #endif
73
74 #define NOCPU ~0
75 volatile u_int ddb_cpu = NOCPU;
76
77 int db_active = 0;
78 #ifdef _KERNEL
79 db_regs_t ddb_regs;
80 #endif
81
82 #if (MIPS32 + MIPS32R2 + MIPS64 + MIPS64R2) > 0
83 static void db_watch_cmd(db_expr_t, bool, db_expr_t, const char *);
84 static void db_unwatch_cmd(db_expr_t, bool, db_expr_t, const char *);
85 #endif /* (MIPS32 + MIPS32R2 + MIPS64 + MIPS64R2) > 0 */
86
87 #ifdef MULTIPROCESSOR
88 static void db_mach_cpu_cmd(db_expr_t, bool, db_expr_t, const char *);
89 #endif
90
91 void db_cp0dump_cmd(db_expr_t, bool, db_expr_t, const char *);
92 void db_cpuinfo_cmd(db_expr_t, bool, db_expr_t, const char *);
93 void db_kvtophys_cmd(db_expr_t, bool, db_expr_t, const char *);
94 void db_tlbdump_cmd(db_expr_t, bool, db_expr_t, const char *);
95
96 #ifdef MIPS64_XLS
97 void db_mfcr_cmd(db_expr_t, bool, db_expr_t, const char *);
98 void db_mtcr_cmd(db_expr_t, bool, db_expr_t, const char *);
99 #endif
100
101 paddr_t kvtophys(vaddr_t);
102
103 #ifdef _KERNEL
104 CTASSERT(sizeof(ddb_regs) == sizeof(struct reg));
105
106 #ifndef KGDB
107 int
kdb_trap(int type,struct reg * regs)108 kdb_trap(int type, struct reg *regs)
109 {
110 int s;
111
112 switch (type) {
113 case T_WATCH: /* watchpoint */
114 case T_BREAK: /* breakpoint */
115 printf("kernel: %s trap\n", trap_names[type & 0x1f]);
116 break;
117 case -1: /* keyboard interrupt */
118 printf("kernel: kdbint trap\n");
119 break;
120 default:
121 printf("kernel: %s trap\n", trap_names[type & 0x1f]);
122 if (db_recover != 0) {
123 db_error("Faulted in DDB; continuing...\n");
124 /*NOTREACHED*/
125 }
126 break;
127 }
128
129 s = splhigh();
130
131 #if defined(MULTIPROCESSOR)
132 bool first_in_ddb = false;
133 const u_int cpu_me = cpu_number();
134 const u_int old_ddb_cpu = atomic_cas_uint(&ddb_cpu, NOCPU, cpu_me);
135 if (old_ddb_cpu == NOCPU) {
136 first_in_ddb = true;
137 cpu_pause_others();
138 } else {
139 if (old_ddb_cpu != cpu_me) {
140 KASSERT(cpu_is_paused(cpu_me));
141 cpu_pause(regs);
142 splx(s);
143 return 1;
144 }
145 }
146 KASSERT(! cpu_is_paused(cpu_me));
147 #endif
148
149 ddb_regs = *regs;
150 db_active++;
151 cnpollc(1);
152 db_trap(type & ~T_USER, 0 /*code*/);
153 cnpollc(0);
154 db_active--;
155 *regs = ddb_regs;
156
157 #if defined(MULTIPROCESSOR)
158 if (atomic_cas_uint(&ddb_cpu, cpu_me, NOCPU) == cpu_me) {
159 cpu_resume_others();
160 } else {
161 cpu_resume(ddb_cpu);
162 if (first_in_ddb)
163 cpu_pause(regs);
164 }
165 #endif
166
167 splx(s);
168 return 1;
169 }
170
171 void
cpu_Debugger(void)172 cpu_Debugger(void)
173 {
174
175 __asm("break");
176 }
177 #endif /* !KGDB */
178
179 /*
180 * Read bytes from kernel address space for debugger.
181 */
182 void
db_read_bytes(vaddr_t addr,size_t size,char * data)183 db_read_bytes(vaddr_t addr, size_t size, char *data)
184 {
185 const char *src = (char *)addr;
186 int err;
187
188 /* If asked to fetch from userspace, do it safely */
189 if (addr < VM_MAXUSER_ADDRESS) {
190 err = copyin(src, data, size);
191 if (err) {
192 #ifdef DDB
193 db_printf("address %p is invalid\n", src);
194 #endif
195 memset(data, 0, size);
196 }
197 return;
198 }
199
200 if (size <= 8 && (size & (size-1)) == 0 && (addr & (size-1)) == 0
201 && ((uintptr_t)data & (size-1)) == 0) {
202 if (size == sizeof(uint8_t))
203 *(uint8_t *)data = *(const uint8_t *)src;
204 else if (size == sizeof(uint16_t))
205 *(uint16_t *)data = *(const uint16_t *)src;
206 else if (size == sizeof(uint32_t))
207 *(uint32_t *)data = *(const uint32_t *)src;
208 else
209 *(uint64_t *)data = *(const uint64_t *)src;
210 return;
211 }
212 while (size--)
213 *data++ = *src++;
214 }
215
216 /*
217 * Write bytes to kernel address space for debugger.
218 */
219 void
db_write_bytes(vaddr_t addr,size_t size,const char * data)220 db_write_bytes(vaddr_t addr, size_t size, const char *data)
221 {
222 char *p = (char *)addr;
223 size_t n = size;
224 int err;
225
226 /* If asked to store to userspace, do it safely */
227 if (addr < VM_MAXUSER_ADDRESS) {
228 err = copyout(data, p, size);
229 if (err) {
230 #ifdef DDB
231 db_printf("address %p is invalid\n", p);
232 #endif
233 }
234 return;
235 }
236
237 if (size <= 8 && (size & (size-1)) == 0 && (addr & (size-1)) == 0
238 && ((uintptr_t)data & (size-1)) == 0) {
239 if (size == sizeof(uint8_t))
240 *(uint8_t *)p = *(const uint8_t *)data;
241 else if (size == sizeof(uint16_t))
242 *(uint16_t *)p = *(const uint16_t *)data;
243 else if (size == sizeof(uint32_t))
244 *(uint32_t *)p = *(const uint32_t *)data;
245 else
246 *(uint64_t *)p = *(const uint64_t *)data;
247 return;
248 }
249 while (n--)
250 *p++ = *data++;
251
252 wbflush();
253 mips_icache_sync_range(addr, size);
254 }
255
256 #ifndef KGDB
257 void
db_tlbdump_cmd(db_expr_t addr,bool have_addr,db_expr_t count,const char * modif)258 db_tlbdump_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
259 const char *modif)
260 {
261 struct tlbmask tlb;
262 bool valid_only = false;
263
264 if (modif[0] == 'v')
265 valid_only = true;
266
267 #ifdef MIPS1
268 if (!MIPS_HAS_R4K_MMU) {
269 int i;
270
271 for (i = 0; i < mips_options.mips_num_tlb_entries; i++) {
272 tlb_read_entry(i, &tlb);
273 if (valid_only && !(tlb.tlb_lo1 & MIPS1_PG_V))
274 continue; /* skip invalid TLBs */
275 db_printf("TLB%c%2d Hi 0x%08x Lo 0x%08x",
276 (tlb.tlb_lo1 & MIPS1_PG_V) ? ' ' : '*',
277 i, tlb.tlb_hi,
278 tlb.tlb_lo1 & MIPS1_PG_FRAME);
279 db_printf(" %c%c%c\n",
280 (tlb.tlb_lo1 & MIPS1_PG_D) ? 'D' : ' ',
281 (tlb.tlb_lo1 & MIPS1_PG_G) ? 'G' : ' ',
282 (tlb.tlb_lo1 & MIPS1_PG_N) ? 'N' : ' ');
283 }
284 }
285 #endif
286 #ifdef MIPS3_PLUS
287 if (MIPS_HAS_R4K_MMU) {
288 int i;
289 const int tlb_count_width =
290 mips_options.mips_num_tlb_entries > 100 ? 3 : 2;
291
292 for (i = 0; i < mips_options.mips_num_tlb_entries; i++) {
293 tlb_read_entry(i, &tlb);
294 if (valid_only &&
295 !((tlb.tlb_lo0 | tlb.tlb_lo1) & MIPS3_PG_V))
296 continue; /* skip invalid TLBs */
297
298 db_printf("TLB%c%*d Hi 0x%08"PRIxVADDR" ",
299 (tlb.tlb_lo0 | tlb.tlb_lo1) & MIPS3_PG_V ? ' ' : '*',
300 tlb_count_width, i, tlb.tlb_hi);
301 db_printf("Lo0=0x%09" PRIx64 " %c%c attr %x ",
302 (uint64_t)mips_tlbpfn_to_paddr(tlb.tlb_lo0),
303 (tlb.tlb_lo0 & MIPS3_PG_D) ? 'D' : ' ',
304 (tlb.tlb_lo0 & MIPS3_PG_G) ? 'G' : ' ',
305 (int)(tlb.tlb_lo0 >> 3) & 7);
306 db_printf("Lo1=0x%09" PRIx64 " %c%c attr %x sz=%x\n",
307 (uint64_t)mips_tlbpfn_to_paddr(tlb.tlb_lo1),
308 (tlb.tlb_lo1 & MIPS3_PG_D) ? 'D' : ' ',
309 (tlb.tlb_lo1 & MIPS3_PG_G) ? 'G' : ' ',
310 (int)(tlb.tlb_lo1 >> 3) & 7,
311 tlb.tlb_mask);
312 }
313 }
314 #endif
315 }
316
317 void
db_kvtophys_cmd(db_expr_t addr,bool have_addr,db_expr_t count,const char * modif)318 db_kvtophys_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
319 const char *modif)
320 {
321
322 if (!have_addr)
323 return;
324 if (VM_MIN_KERNEL_ADDRESS <= addr && addr < VM_MAX_KERNEL_ADDRESS) {
325 /*
326 * Cast the physical address -- some platforms, while
327 * being ILP32, may be using 64-bit paddr_t's.
328 */
329 db_printf("0x%" DDB_EXPR_FMT "x -> 0x%" PRIx64 "\n", addr,
330 (uint64_t) kvtophys(addr));
331 } else
332 db_printf("not a kernel virtual address\n");
333 }
334
335 #define FLDWIDTH 10
336
337 #define SHOW32(reg, name) SHOW32SELECT(reg, 0, name)
338 #define SHOW64(reg, name) SHOW64SELECT(reg, 0, name)
339 #define SHOW32SEL(reg, name) SHOW32SELECT(reg, name)
340 #define SHOW64SEL(reg, name) SHOW64SELECT(reg, name)
341
342 #define SHOW32SELECT(num, sel, name) \
343 do { \
344 uint32_t __val; \
345 \
346 __asm volatile( \
347 ".set push \n\t" \
348 ".set mips32 \n\t" \
349 "mfc0 %0,$%1,%2 \n\t" \
350 ".set pop \n\t" \
351 : "=r"(__val) : "n"(num), "n"(sel)); \
352 db_printf(" %s:%*s %#x\n", name, \
353 FLDWIDTH - (int) strlen(name), "", __val); \
354 } while (0)
355
356 /* XXX not 64-bit ABI safe! */
357 #define SHOW64SELECT(num, sel, name) \
358 do { \
359 uint64_t __val; \
360 \
361 KASSERT (CPUIS64BITS); \
362 __asm volatile( \
363 ".set push \n\t" \
364 ".set mips64 \n\t" \
365 ".set noat \n\t" \
366 "dmfc0 %0,$%1,%2 \n\t" \
367 ".set pop" \
368 : "=r"(__val) : "n"(num), "n"(sel)); \
369 db_printf(" %s:%*s %#"PRIx64"\n", name, \
370 FLDWIDTH - (int) strlen(name), "", __val); \
371 } while (0)
372
373 #define SET32(reg, name, val) \
374 do { \
375 \
376 __asm volatile("mtc0 %0,$" ___STRING(reg) :: "r"(val)); \
377 if (name != NULL) \
378 db_printf(" %s =%*s %#x\n", name, \
379 FLDWIDTH - (int) strlen(name), "", val); \
380 } while (0)
381
382 #define SET64(reg, name) MIPS64_SET64(reg, 0, name)
383
384 #define MIPS64_SET32(num, sel, name, val) \
385 do { \
386 \
387 __asm volatile( \
388 ".set push \n\t" \
389 ".set mips32 \n\t" \
390 "mtc0 %0,$%1,%2 \n\t" \
391 ".set pop \n\t" \
392 :: "r"(val), "n"(num), "n"(sel)); \
393 if (name != NULL) \
394 db_printf(" %s =%*s %#x\n", name, \
395 FLDWIDTH - (int) strlen(name), "", val); \
396 } while (0)
397
398 /* XXX not 64-bit ABI safe! */
399 #define MIPS64_SET64(num, sel, name, val) \
400 do { \
401 \
402 KASSERT (CPUIS64BITS); \
403 __asm volatile( \
404 ".set push \n\t" \
405 ".set mips64 \n\t" \
406 ".set noat \n\t" \
407 "dmtc0 %0,$%1,%2 \n\t" \
408 ".set pop" \
409 :: "r"(val), "n"(num), "n"(sel)); \
410 if (name != NULL) \
411 db_printf(" %s =%*s %#"PRIx64"\n", name, \
412 FLDWIDTH - (int) strlen(name), "", (uint64_t)val); \
413 } while (0)
414
415 void
db_cp0dump_cmd(db_expr_t addr,bool have_addr,db_expr_t count,const char * modif)416 db_cp0dump_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
417 const char *modif)
418 {
419 u_int cp0flags = mips_options.mips_cpu->cpu_cp0flags;
420
421 SHOW32(MIPS_COP_0_TLB_INDEX, "index");
422 SHOW32(MIPS_COP_0_TLB_RANDOM, "random");
423
424 if (!MIPS_HAS_R4K_MMU) {
425 SHOW32(MIPS_COP_0_TLB_LOW, "entrylow");
426 } else {
427 if (CPUIS64BITS) {
428 SHOW64(MIPS_COP_0_TLB_LO0, "entrylo0");
429 SHOW64(MIPS_COP_0_TLB_LO1, "entrylo1");
430 } else {
431 SHOW32(MIPS_COP_0_TLB_LO0, "entrylo0");
432 SHOW32(MIPS_COP_0_TLB_LO1, "entrylo1");
433 }
434 }
435
436 if (CPUIS64BITS) {
437 SHOW64(MIPS_COP_0_TLB_CONTEXT, "context");
438 } else {
439 SHOW32(MIPS_COP_0_TLB_CONTEXT, "context");
440 }
441
442 if (MIPS_HAS_R4K_MMU) {
443 SHOW32(MIPS_COP_0_TLB_PG_MASK, "pagemask");
444 SHOW32(MIPS_COP_0_TLB_WIRED, "wired");
445 }
446
447 if (CPUIS64BITS) {
448 SHOW64(MIPS_COP_0_BAD_VADDR, "badvaddr");
449 } else {
450 SHOW32(MIPS_COP_0_BAD_VADDR, "badvaddr");
451 }
452
453 if (mips_options.mips_cpu_arch >= CPU_ARCH_MIPS3) {
454 SHOW32(MIPS_COP_0_COUNT, "count");
455 }
456
457 if ((cp0flags & MIPS_CP0FL_USE) != 0) {
458 if ((cp0flags & MIPS_CP0FL_EIRR) != 0)
459 SHOW64SEL(MIPS_COP_0_EIRR, "eirr");
460 if ((cp0flags & MIPS_CP0FL_EIMR) != 0)
461 SHOW64SEL(MIPS_COP_0_EIMR, "eimr");
462 }
463
464 if (CPUIS64BITS) {
465 SHOW64(MIPS_COP_0_TLB_HI, "entryhi");
466 } else {
467 SHOW32(MIPS_COP_0_TLB_HI, "entryhi");
468 }
469
470 if (mips_options.mips_cpu_arch >= CPU_ARCH_MIPS3) {
471 SHOW32(MIPS_COP_0_COMPARE, "compare");
472 }
473
474 SHOW32(MIPS_COP_0_STATUS, "status");
475 SHOW32(MIPS_COP_0_CAUSE, "cause");
476
477 if (CPUIS64BITS) {
478 SHOW64(MIPS_COP_0_EXC_PC, "epc");
479 } else {
480 SHOW32(MIPS_COP_0_EXC_PC, "epc");
481 }
482
483 SHOW32(MIPS_COP_0_PRID, "prid");
484
485 if ((cp0flags & MIPS_CP0FL_USE) != 0) {
486 if ((cp0flags & MIPS_CP0FL_EBASE) != 0)
487 SHOW32SEL(MIPS_COP_0_EBASE, "ebase");
488 if ((cp0flags & MIPS_CP0FL_CONFIG) != 0)
489 SHOW32(MIPS_COP_0_CONFIG, "config");
490 if ((cp0flags & MIPS_CP0FL_CONFIG1) != 0)
491 SHOW32SEL(MIPS_COP_0_CONFIG1, "config1");
492 if ((cp0flags & MIPS_CP0FL_CONFIG2) != 0)
493 SHOW32SEL(MIPS_COP_0_CONFIG2, "config2");
494 if ((cp0flags & MIPS_CP0FL_CONFIG3) != 0)
495 SHOW32SEL(MIPS_COP_0_CONFIG3, "config3");
496 if ((cp0flags & MIPS_CP0FL_CONFIG4) != 0)
497 SHOW32SEL(MIPS_COP_0_CONFIG4, "config4");
498 if ((cp0flags & MIPS_CP0FL_CONFIG5) != 0)
499 SHOW32SEL(MIPS_COP_0_CONFIG5, "config5");
500 if ((cp0flags & MIPS_CP0FL_CONFIG6) != 0)
501 SHOW32SEL(MIPS_COP_0_CONFIG6, "config6");
502 if ((cp0flags & MIPS_CP0FL_CONFIG7) != 0)
503 SHOW32SEL(MIPS_COP_0_CONFIG7, "config7");
504 if (CPUISMIPSNNR2)
505 SHOW32(MIPS_COP_0_HWRENA, "hwrena");
506 if (MIPS_HAS_USERLOCAL)
507 SHOW32SEL(MIPS_COP_0_USERLOCAL, "userlocal");
508 } else {
509 SHOW32(MIPS_COP_0_CONFIG, "config");
510 #if (MIPS32 + MIPS32R2 + MIPS64 + MIPS64R2) > 0
511 if (CPUISMIPSNN) {
512 uint32_t val;
513
514 val = mipsNN_cp0_config1_read();
515 db_printf(" config1: %#x\n", val);
516 }
517 #endif
518 }
519
520 if (MIPS_HAS_LLSC) {
521 if (MIPS_HAS_LLADDR) {
522 if (CPUIS64BITS)
523 SHOW64(MIPS_COP_0_LLADDR, "lladdr");
524 else
525 SHOW32(MIPS_COP_0_LLADDR, "lladdr");
526 }
527 }
528
529 #if (MIPS32 + MIPS32R2 + MIPS64 + MIPS64R2) > 0
530 for (int i=0; i < curcpu()->ci_cpuwatch_count; i++) {
531 const intptr_t lo = mipsNN_cp0_watchlo_read(i);
532 const uint32_t hi = mipsNN_cp0_watchhi_read(i);
533 db_printf(" %s%d:%*s %#" PRIxPTR "\t",
534 "watchlo", i, FLDWIDTH - 8, "", lo);
535 db_printf(" %s%d:%*s %#" PRIx32 "\n",
536 "watchhi", i, FLDWIDTH - 8, "", hi);
537 }
538 #endif
539
540 if (CPUIS64BITS) {
541 SHOW64(MIPS_COP_0_TLB_XCONTEXT, "xcontext");
542 }
543
544 if (CPUISMIPSNN) {
545 if (CPUIS64BITS) {
546 SHOW64(MIPS_COP_0_PERFCNT0_CTL, "perfcnt0ctl");
547 SHOW64SEL(MIPS_COP_0_PERFCNT0_CNT, "perfcnt0cnt");
548 } else {
549 SHOW32(MIPS_COP_0_PERFCNT0_CTL, "perfcnt0ctl");
550 SHOW32SEL(MIPS_COP_0_PERFCNT0_CNT, "perfcnt0cnt");
551 }
552 }
553
554 if (((cp0flags & MIPS_CP0FL_USE) == 0) ||
555 ((cp0flags & MIPS_CP0FL_ECC) != 0))
556 SHOW32(MIPS_COP_0_ECC, "ecc");
557
558 if (((cp0flags & MIPS_CP0FL_USE) == 0) ||
559 ((cp0flags & MIPS_CP0FL_CACHE_ERR) != 0))
560 SHOW32(MIPS_COP_0_CACHE_ERR, "cacherr");
561
562 SHOW32(MIPS_COP_0_TAG_LO, "cachelo");
563 SHOW32(MIPS_COP_0_TAG_HI, "cachehi");
564
565 if (CPUIS64BITS) {
566 SHOW64(MIPS_COP_0_ERROR_PC, "errorpc");
567 } else {
568 SHOW32(MIPS_COP_0_ERROR_PC, "errorpc");
569 }
570 }
571
572
573 static void
show_cpuinfo(struct cpu_info * kci)574 show_cpuinfo(struct cpu_info *kci)
575 {
576 struct cpu_info cpuinfobuf;
577 cpuid_t cpuid;
578 int i;
579
580 db_read_bytes((db_addr_t)kci, sizeof(cpuinfobuf), (char *)&cpuinfobuf);
581
582 struct cpu_info *ci = &cpuinfobuf;
583 cpuid = ci->ci_cpuid;
584 db_printf("cpu_info=%p, cpu_name=%s\n", kci, ci->ci_cpuname);
585 db_printf("%p cpu[%lu].ci_cpuid = %lu\n",
586 &ci->ci_cpuid, cpuid, ci->ci_cpuid);
587 db_printf("%p cpu[%lu].ci_curlwp = %p\n",
588 &ci->ci_curlwp, cpuid, ci->ci_curlwp);
589 for (i = 0; i < SOFTINT_COUNT; i++) {
590 db_printf("%p cpu[%lu].ci_softlwps[%d] = %p\n",
591 &ci->ci_softlwps[i], cpuid, i, ci->ci_softlwps[i]);
592 }
593 db_printf("%p cpu[%lu].ci_want_resched = %d\n",
594 &ci->ci_want_resched, cpuid, ci->ci_want_resched);
595 db_printf("%p cpu[%lu].ci_cpl = %d\n",
596 &ci->ci_cpl, cpuid, ci->ci_cpl);
597 db_printf("%p cpu[%lu].ci_softints = 0x%08x\n",
598 &ci->ci_softints, cpuid, ci->ci_softints);
599 db_printf("%p cpu[%lu].ci_idepth = %u\n",
600 &ci->ci_idepth, cpuid, ci->ci_idepth);
601 }
602
603 void
db_cpuinfo_cmd(db_expr_t addr,bool have_addr,db_expr_t count,const char * modif)604 db_cpuinfo_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
605 const char *modif)
606 {
607 #ifdef MULTIPROCESSOR
608 CPU_INFO_ITERATOR cii;
609 struct cpu_info *ci;
610 bool showall = false;
611
612 if (modif != NULL) {
613 for (; *modif != '\0'; modif++) {
614 switch (*modif) {
615 case 'a':
616 showall = true;
617 break;
618 }
619 }
620 }
621
622 if (showall) {
623 for (CPU_INFO_FOREACH(cii, ci)) {
624 show_cpuinfo(ci);
625 }
626 } else
627 #endif /* MULTIPROCESSOR */
628 show_cpuinfo(curcpu());
629 }
630
631
632 #if (MIPS32 + MIPS32R2 + MIPS64 + MIPS64R2) > 0
633 static void
db_watch_cmd(db_expr_t address,bool have_addr,db_expr_t count,const char * modif)634 db_watch_cmd(db_expr_t address, bool have_addr, db_expr_t count,
635 const char *modif)
636 {
637 struct cpu_info * const ci = curcpu();
638 cpu_watchpoint_t *cwp;
639 register_t mask=0;
640 uint32_t asid;
641 uint32_t mode;
642 db_expr_t value;
643 char str[6];
644
645 if (!have_addr) {
646 db_printf("%-3s %-5s %-16s %4s %4s\n",
647 "#", "MODE", "ADDR", "MASK", "ASID");
648 for (u_int i=0; i < ci->ci_cpuwatch_count; i++) {
649 cwp = &ci->ci_cpuwatch_tab[i];
650 mode = cwp->cw_mode;
651 if ((mode & CPUWATCH_RWX) == 0)
652 continue; /* empty/disabled/invalid */
653 str[0] = (mode & CPUWATCH_READ) ? 'r' : '-';
654 str[1] = (mode & CPUWATCH_WRITE) ? 'w' : '-';
655 str[2] = (mode & CPUWATCH_EXEC) ? 'x' : '-';
656 str[3] = (mode & CPUWATCH_MASK) ? 'm' : '-';
657 str[4] = (mode & CPUWATCH_ASID) ? 'a' : 'g';
658 str[5] = '\0';
659 db_printf("%2u: %s %16" PRIxREGISTER
660 " %4" PRIxREGISTER " %4x\n",
661 i, str, cwp->cw_addr, cwp->cw_mask, cwp->cw_asid);
662 }
663 db_flush_lex();
664 return;
665 }
666
667 cwp = cpuwatch_alloc();
668 if (cwp == NULL) {
669 db_printf("no watchpoint available\n");
670 db_flush_lex();
671 return;
672 }
673
674 /*
675 * parse modif to define mode
676 */
677 KASSERT(modif != NULL);
678 mode = 0;
679 for (int i=0; modif[i] != '\0'; i++) {
680 switch(modif[i]) {
681 case 'w':
682 mode |= CPUWATCH_WRITE;
683 break;
684 case 'm':
685 mode |= CPUWATCH_MASK;
686 break;
687 case 'r':
688 mode |= CPUWATCH_READ;
689 break;
690 case 'x':
691 mode |= CPUWATCH_EXEC;
692 break;
693 case 'a':
694 mode |= CPUWATCH_ASID;
695 break;
696 }
697 }
698 if (mode == 0) {
699 db_printf("mode modifier(s) missing\n");
700 db_flush_lex();
701 return;
702 }
703
704 /*
705 * if mask mode is requested get the mask,
706 */
707 if (mode & CPUWATCH_MASK) {
708 if (! db_expression(&value)) {
709 db_printf("mask missing\n");
710 db_flush_lex();
711 return;
712 }
713 mask = (register_t)(value & __BITS(11, 3));
714 }
715
716 /*
717 * if asid mode is requested, get the asid;
718 * otherwise use global mode (and set asid=0)
719 */
720 if (mode & CPUWATCH_ASID) {
721 if (! db_expression(&value)) {
722 db_printf("asid missing\n");
723 db_flush_lex();
724 return;
725 }
726 asid = (uint32_t)(value & __BITS(7,0));
727 } else {
728 asid = 0;
729 }
730
731 if (mode & (CPUWATCH_MASK|CPUWATCH_ASID))
732 db_skip_to_eol();
733 else
734 db_flush_lex();
735
736 /*
737 * store to the (volatile) table entry
738 * other CPUs can see this and load when resuming from pause
739 */
740 cwp->cw_addr = (register_t)address;
741 cwp->cw_mask = (register_t)mask;
742 cwp->cw_asid = asid;
743 cwp->cw_mode = mode;
744
745 /*
746 * program the CPU watchpoint regs
747 */
748 cpuwatch_set(cwp);
749 }
750
751 static void
db_unwatch_cmd(db_expr_t address,bool have_addr,db_expr_t count,const char * modif)752 db_unwatch_cmd(db_expr_t address, bool have_addr, db_expr_t count,
753 const char *modif)
754 {
755 struct cpu_info * const ci = curcpu();
756 const bool unwatch_all = !have_addr;
757 int n;
758
759 n = 0;
760 for (u_int i=0; i < ci->ci_cpuwatch_count; i++) {
761 cpu_watchpoint_t * const cwp = &ci->ci_cpuwatch_tab[i];
762 if (unwatch_all || (cwp->cw_addr == (register_t)address)) {
763 cpuwatch_free(cwp);
764 n++;
765 }
766 }
767 if (n == 0)
768 db_printf("no watch found on address %#" PRIxREGISTER "\n",
769 (register_t)address);
770 }
771 #endif /* (MIPS32 + MIPS32R2 + MIPS64 + MIPS64R2) > 0 */
772
773 #ifdef MIPS64_XLS
774 void
db_mfcr_cmd(db_expr_t addr,bool have_addr,db_expr_t count,const char * modif)775 db_mfcr_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
776 const char *modif)
777 {
778 uint64_t value;
779
780 if ((mips_options.mips_cpu->cpu_flags & CPU_MIPS_HAVE_MxCR) == 0) {
781 db_printf("mfcr not implemented on this CPU\n");
782 return;
783 }
784
785 if (!have_addr) {
786 db_printf("Address missing\n");
787 return;
788 }
789
790 /* value = CR[addr] */
791 __asm volatile( \
792 ".set push \n\t" \
793 ".set arch=xlr \n\t" \
794 ".set noat \n\t" \
795 "mfcr %0,%1 \n\t" \
796 ".set pop \n\t" \
797 : "=r"(value) : "r"(addr));
798
799 db_printf("control reg 0x%" DDB_EXPR_FMT "x = 0x%" PRIx64 "\n",
800 addr, value);
801 }
802
803 void
db_mtcr_cmd(db_expr_t addr,bool have_addr,db_expr_t count,const char * modif)804 db_mtcr_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
805 const char *modif)
806 {
807 db_expr_t value;
808
809 if ((mips_options.mips_cpu->cpu_flags & CPU_MIPS_HAVE_MxCR) == 0) {
810 db_printf("mtcr not implemented on this CPU\n");
811 return;
812 }
813
814 if ((!have_addr) || (! db_expression(&value))) {
815 db_printf("Address missing\n");
816 db_flush_lex();
817 return;
818 }
819 db_skip_to_eol();
820
821 /* CR[addr] = value */
822 __asm volatile( \
823 ".set push \n\t" \
824 ".set arch=xlr \n\t" \
825 ".set noat \n\t" \
826 "mtcr %0,%1 \n\t" \
827 ".set pop \n\t" \
828 :: "r"(value), "r"(addr));
829
830 db_printf("control reg 0x%" DDB_EXPR_FMT "x = 0x%" DDB_EXPR_FMT "x\n",
831 addr, value);
832 }
833 #endif /* MIPS64_XLS */
834
835 #ifdef MIPS64_OCTEON
836 #include <mips/cavium/dev/octeon_ciureg.h>
837
838 #ifdef MULTIPROCESSOR
839 static void
db_mach_nmi_cmd(db_expr_t addr,bool have_addr,db_expr_t count,const char * modif)840 db_mach_nmi_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
841 const char *modif)
842 {
843 CPU_INFO_ITERATOR cii;
844 struct cpu_info *ci;
845
846 if (!have_addr) {
847 db_printf("CPU not specific\n");
848 return;
849 }
850 for (CPU_INFO_FOREACH(cii, ci)) {
851 if (cpu_index(ci) == addr)
852 break;
853 }
854 if (ci == NULL) {
855 db_printf("CPU %ld not configured\n", (long)addr);
856 return;
857 }
858 if (ci == curcpu()) {
859 db_printf("CPU %ld is current cpu; request ignored\n",
860 (long)addr);
861 return;
862 }
863 mips3_sd(MIPS_PHYS_TO_XKPHYS_UNCACHED(CIU_NMI), __BIT(ci->ci_cpuid));
864 }
865 #endif
866 #endif
867
868 static void
db_mach_reset_cmd(db_expr_t addr,bool have_addr,db_expr_t count,const char * modif)869 db_mach_reset_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
870 const char *modif)
871 {
872
873 if (cpu_reset_address == NULL) {
874 db_printf("cpu_reset_address is not set\n");
875 return;
876 }
877
878 cpu_reset_address();
879 }
880
881 const struct db_command db_machine_command_table[] = {
882 #ifdef MULTIPROCESSOR
883 { DDB_ADD_CMD("cpu", db_mach_cpu_cmd, 0,
884 "switch to another cpu", "cpu#", NULL) },
885 #endif
886 { DDB_ADD_CMD("cp0", db_cp0dump_cmd, 0,
887 "Dump CP0 registers.",
888 NULL, NULL) },
889 { DDB_ADD_CMD("cpuinfo", db_cpuinfo_cmd, 0,
890 "Displays the cpuinfo",
891 NULL, NULL)
892 },
893 { DDB_ADD_CMD("kvtop", db_kvtophys_cmd, 0,
894 "Print the physical address for a given kernel virtual address",
895 "address",
896 " address:\tvirtual address to look up") },
897 #ifdef MIPS64_XLS
898 { DDB_ADD_CMD("mfcr", db_mfcr_cmd, CS_NOREPEAT,
899 "Dump processor control register",
900 NULL, NULL) },
901 { DDB_ADD_CMD("mtcr", db_mtcr_cmd, CS_NOREPEAT|CS_MORE,
902 "Set processor control register",
903 NULL, NULL) },
904 #endif
905 #if defined(MIPS64_OCTEON) && defined(MULTIPROCESSOR)
906 { DDB_ADD_CMD("nmi", db_mach_nmi_cmd, CS_NOREPEAT,
907 "Send NMI to processor",
908 "cpu#", NULL) },
909 #endif /* OCTEON + MP */
910 { DDB_ADD_CMD("reset", db_mach_reset_cmd, CS_NOREPEAT,
911 "Initiate hardware reset",
912 NULL, NULL) },
913 { DDB_ADD_CMD("tlb", db_tlbdump_cmd, 0,
914 "Print out TLB entries. (only works with options DEBUG)",
915 NULL, NULL) },
916 #if (MIPS32 + MIPS32R2 + MIPS64 + MIPS64R2) > 0
917 { DDB_ADD_CMD("watch", db_watch_cmd, CS_MORE,
918 "set cp0 watchpoint",
919 "address <mask> <asid> </rwxma>", NULL) },
920 { DDB_ADD_CMD("unwatch",db_unwatch_cmd, 0,
921 "delete cp0 watchpoint",
922 "address", NULL) },
923 #endif /* (MIPS32 + MIPS32R2 + MIPS64 + MIPS64R2) > 0 */
924 { DDB_END_CMD },
925 };
926 #endif /* !KGDB */
927
928 /*
929 * Determine whether the instruction involves a delay slot.
930 */
931 bool
inst_branch(int inst)932 inst_branch(int inst)
933 {
934 InstFmt i;
935 int delslt;
936
937 i.word = inst;
938 delslt = 0;
939 switch (i.JType.op) {
940 case OP_REGIMM:
941 case OP_J:
942 case OP_JAL:
943 #if MIPS64_OCTEON
944 case OP_CVM_BBIT0:
945 case OP_CVM_BBIT032:
946 case OP_CVM_BBIT1:
947 case OP_CVM_BBIT132:
948 #endif
949 case OP_BEQ:
950 case OP_BNE:
951 case OP_BLEZ:
952 case OP_BGTZ:
953 case OP_BEQL:
954 case OP_BNEL:
955 case OP_BLEZL:
956 case OP_BGTZL:
957 delslt = 1;
958 break;
959
960 case OP_COP0:
961 case OP_COP1:
962 switch (i.RType.rs) {
963 case OP_BCx:
964 case OP_BCy:
965 delslt = 1;
966 }
967 break;
968
969 case OP_SPECIAL:
970 if (i.RType.op == OP_JR || i.RType.op == OP_JALR)
971 delslt = 1;
972 break;
973 }
974 return delslt;
975 }
976
977 /*
978 * Determine whether the instruction calls a function.
979 */
980 bool
inst_call(int inst)981 inst_call(int inst)
982 {
983 bool call;
984 InstFmt i;
985
986 i.word = inst;
987 if (i.JType.op == OP_SPECIAL
988 && ((i.RType.func == OP_JR && i.RType.rs != 31) ||
989 i.RType.func == OP_JALR))
990 call = 1;
991 else if (i.JType.op == OP_JAL)
992 call = 1;
993 else
994 call = 0;
995 return call;
996 }
997
998 /*
999 * Determine whether the instruction returns from a function (j ra). The
1000 * compiler can use this construct for other jumps, but usually will not.
1001 * This lets the ddb "next" command to work (also need inst_trap_return()).
1002 */
1003 bool
inst_return(int inst)1004 inst_return(int inst)
1005 {
1006 InstFmt i;
1007
1008 i.word = inst;
1009
1010 return (i.JType.op == OP_SPECIAL && i.RType.func == OP_JR &&
1011 i.RType.rs == 31);
1012 }
1013
1014 /*
1015 * Determine whether the instruction makes a jump.
1016 */
1017 bool
inst_unconditional_flow_transfer(int inst)1018 inst_unconditional_flow_transfer(int inst)
1019 {
1020 InstFmt i;
1021 bool jump;
1022
1023 i.word = inst;
1024 jump = (i.JType.op == OP_J) ||
1025 (i.JType.op == OP_SPECIAL && i.RType.func == OP_JR);
1026 return jump;
1027 }
1028
1029 /*
1030 * Determine whether the instruction is a load/store as appropriate.
1031 */
1032 bool
inst_load(int inst)1033 inst_load(int inst)
1034 {
1035 InstFmt i = { .word = inst, };
1036
1037 /*
1038 * All loads are opcodes 04x or 06x.
1039 */
1040 if ((i.JType.op & 050) != 040)
1041 return false;
1042
1043 /*
1044 * Except these this opcode is not a load.
1045 */
1046 return i.JType.op != OP_PREF;
1047 }
1048
1049 bool
inst_store(int inst)1050 inst_store(int inst)
1051 {
1052 InstFmt i = { .word = inst, };
1053
1054 /*
1055 * All stores are opcodes 05x or 07x.
1056 */
1057 if ((i.JType.op & 050) != 050)
1058 return false;
1059
1060 /*
1061 * Except these two opcodes are not stores.
1062 */
1063 return i.JType.op != OP_RSVD073 && i.JType.op != OP_CACHE;
1064 }
1065
1066 /*
1067 * Return the next pc if the given branch is taken.
1068 * mips_emul_branch() runs analysis for branch delay slot.
1069 */
1070 db_addr_t
branch_taken(int inst,db_addr_t pc,db_regs_t * regs)1071 branch_taken(int inst, db_addr_t pc, db_regs_t *regs)
1072 {
1073 struct pcb * const pcb = lwp_getpcb(curlwp);
1074 const uint32_t fpucsr = PCB_FSR(pcb);
1075 vaddr_t ra;
1076
1077 ra = mips_emul_branch((struct trapframe *)regs, pc, fpucsr, false);
1078 return ra;
1079 }
1080
1081 /*
1082 * Return the next pc of an arbitrary instruction.
1083 */
1084 db_addr_t
next_instr_address(db_addr_t pc,bool bd)1085 next_instr_address(db_addr_t pc, bool bd)
1086 {
1087 uint32_t ins;
1088
1089 if (bd == false)
1090 return (pc + 4);
1091
1092 if (pc < MIPS_KSEG0_START)
1093 ins = mips_ufetch32((void *)pc);
1094 else
1095 ins = *(uint32_t *)pc;
1096
1097 if (inst_branch(ins) || inst_call(ins) || inst_return(ins))
1098 return (pc + 4);
1099
1100 return (pc);
1101 }
1102
1103 #ifdef MULTIPROCESSOR
1104
1105 bool
ddb_running_on_this_cpu_p(void)1106 ddb_running_on_this_cpu_p(void)
1107 {
1108 return ddb_cpu == cpu_number();
1109 }
1110
1111 bool
ddb_running_on_any_cpu_p(void)1112 ddb_running_on_any_cpu_p(void)
1113 {
1114 return ddb_cpu != NOCPU;
1115 }
1116
1117 void
db_resume_others(void)1118 db_resume_others(void)
1119 {
1120 u_int cpu_me = cpu_number();
1121
1122 if (atomic_cas_uint(&ddb_cpu, cpu_me, NOCPU) == cpu_me)
1123 cpu_resume_others();
1124 }
1125
1126 static void
db_mach_cpu_cmd(db_expr_t addr,bool have_addr,db_expr_t count,const char * modif)1127 db_mach_cpu_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif)
1128 {
1129 CPU_INFO_ITERATOR cii;
1130 struct cpu_info *ci;
1131
1132 if (!have_addr) {
1133 cpu_debug_dump();
1134 return;
1135 }
1136 for (CPU_INFO_FOREACH(cii, ci)) {
1137 if (cpu_index(ci) == addr)
1138 break;
1139 }
1140 if (ci == NULL) {
1141 db_printf("CPU %ld not configured\n", (long)addr);
1142 return;
1143 }
1144 if (ci != curcpu()) {
1145 if (!cpu_is_paused(cpu_index(ci))) {
1146 db_printf("CPU %ld not paused\n", (long)addr);
1147 return;
1148 }
1149 (void)atomic_cas_uint(&ddb_cpu, cpu_number(), cpu_index(ci));
1150 db_continue_cmd(0, false, 0, "");
1151 }
1152 }
1153 #endif /* MULTIPROCESSOR */
1154
1155 #endif /* _KERNEL */
1156