1 /* $NetBSD: db_machdep.c,v 1.35 2020/08/14 16:18:36 skrll Exp $ */ 2 3 /* 4 * Copyright (c) 1996 Mark Brinicombe 5 * 6 * Mach Operating System 7 * Copyright (c) 1991,1990 Carnegie Mellon University 8 * All Rights Reserved. 9 * 10 * Permission to use, copy, modify and distribute this software and its 11 * documentation is hereby granted, provided that both the copyright 12 * notice and this permission notice appear in all copies of the 13 * software, derivative works or modified versions, and any portions 14 * thereof, and that both notices appear in supporting documentation. 15 * 16 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 17 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 18 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 19 * 20 * Carnegie Mellon requests users of this software to return to 21 * 22 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 23 * School of Computer Science 24 * Carnegie Mellon University 25 * Pittsburgh PA 15213-3890 26 * 27 * any improvements or extensions that they make and grant Carnegie the 28 * rights to redistribute these changes. 29 */ 30 31 #ifdef _KERNEL_OPT 32 #include "opt_cputypes.h" 33 #include "opt_multiprocessor.h" 34 #endif 35 36 #include <sys/cdefs.h> 37 __KERNEL_RCSID(0, "$NetBSD: db_machdep.c,v 1.35 2020/08/14 16:18:36 skrll Exp $"); 38 39 #include <sys/param.h> 40 41 #include <sys/cpu.h> 42 #include <sys/proc.h> 43 #include <sys/vnode.h> 44 #include <sys/systm.h> 45 46 #include <arm/arm32/db_machdep.h> 47 #include <arm/arm32/machdep.h> 48 #include <arm/cpufunc.h> 49 50 #include <ddb/db_access.h> 51 #include <ddb/db_sym.h> 52 #include <ddb/db_output.h> 53 #include <ddb/db_variables.h> 54 #include <ddb/db_command.h> 55 #include <ddb/db_run.h> 56 57 #ifndef _KERNEL 58 #include <stddef.h> 59 #endif 60 61 #ifdef _KERNEL 62 static long nil; 63 64 void db_md_cpuinfo_cmd(db_expr_t, bool, db_expr_t, const char *); 65 66 int db_access_und_sp(const struct db_variable *, db_expr_t *, int); 67 int db_access_abt_sp(const struct db_variable *, db_expr_t *, int); 68 int db_access_irq_sp(const struct db_variable *, db_expr_t *, int); 69 #endif 70 71 static int 72 ddb_reg_var(const struct db_variable *v, db_expr_t *ep, int op) 73 { 74 register_t * const rp = (register_t *)DDB_REGS; 75 if (op == DB_VAR_SET) { 76 rp[(uintptr_t)v->valuep] = *ep; 77 } else { 78 *ep = rp[(uintptr_t)v->valuep]; 79 } 80 return 0; 81 } 82 83 84 #define XO(f) ((long *)(offsetof(db_regs_t, f) / sizeof(register_t))) 85 const struct db_variable db_regs[] = { 86 { "spsr", XO(tf_spsr), ddb_reg_var, NULL }, 87 { "r0", XO(tf_r0), ddb_reg_var, NULL }, 88 { "r1", XO(tf_r1), ddb_reg_var, NULL }, 89 { "r2", XO(tf_r2), ddb_reg_var, NULL }, 90 { "r3", XO(tf_r3), ddb_reg_var, NULL }, 91 { "r4", XO(tf_r4), ddb_reg_var, NULL }, 92 { "r5", XO(tf_r5), ddb_reg_var, NULL }, 93 { "r6", XO(tf_r6), ddb_reg_var, NULL }, 94 { "r7", XO(tf_r7), ddb_reg_var, NULL }, 95 { "r8", XO(tf_r8), ddb_reg_var, NULL }, 96 { "r9", XO(tf_r9), ddb_reg_var, NULL }, 97 { "r10", XO(tf_r10), ddb_reg_var, NULL }, 98 { "r11", XO(tf_r11), ddb_reg_var, NULL }, 99 { "r12", XO(tf_r12), ddb_reg_var, NULL }, 100 { "usr_sp", XO(tf_usr_sp), ddb_reg_var, NULL }, 101 { "usr_lr", XO(tf_usr_lr), ddb_reg_var, NULL }, 102 { "svc_sp", XO(tf_svc_sp), ddb_reg_var, NULL }, 103 { "svc_lr", XO(tf_svc_lr), ddb_reg_var, NULL }, 104 { "pc", XO(tf_pc), ddb_reg_var, NULL }, 105 #ifdef _KERNEL 106 { "und_sp", &nil, db_access_und_sp, NULL }, 107 { "abt_sp", &nil, db_access_abt_sp, NULL }, 108 { "irq_sp", &nil, db_access_irq_sp, NULL }, 109 #endif 110 }; 111 #undef XO 112 113 const struct db_variable * const db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]); 114 115 const struct db_command db_machine_command_table[] = { 116 #ifdef _KERNEL 117 #if defined(MULTIPROCESSOR) 118 { DDB_ADD_CMD("cpu", db_switch_cpu_cmd, 0, 119 "switch to a different cpu", 120 NULL,NULL) }, 121 #endif /* MULTIPROCESSOR */ 122 { DDB_ADD_CMD("cpuinfo", db_md_cpuinfo_cmd, 0, 123 "Displays the cpuinfo", 124 NULL, NULL) 125 }, 126 { DDB_ADD_CMD("fault", db_show_fault_cmd, 0, 127 "Displays the fault registers", 128 NULL,NULL) }, 129 #endif 130 { DDB_ADD_CMD("frame", db_show_frame_cmd, 0, 131 "Displays the contents of a trapframe", 132 "[address]", 133 " address:\taddress of trapfame to display")}, 134 #ifdef _KERNEL 135 { DDB_ADD_CMD("reset", db_reset_cmd, 0, 136 "Reset the system", 137 NULL,NULL) }, 138 #if defined(CPU_CORTEXA5) || defined(CPU_CORTEXA7) 139 { DDB_ADD_CMD("tlb", db_show_tlb_cmd, 0, 140 "Displays the TLB", 141 NULL,NULL) }, 142 #endif 143 #endif /* _KERNEL */ 144 145 { DDB_ADD_CMD(NULL, NULL, 0,NULL,NULL,NULL) } 146 }; 147 148 void 149 db_show_frame_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) 150 { 151 struct trapframe *frame; 152 153 if (!have_addr) { 154 db_printf("frame address must be specified\n"); 155 return; 156 } 157 158 frame = (struct trapframe *)addr; 159 160 db_printf("frame address = %08x ", (u_int)frame); 161 db_printf("spsr=%08x\n", frame->tf_spsr); 162 db_printf("r0 =%08x r1 =%08x r2 =%08x r3 =%08x\n", 163 frame->tf_r0, frame->tf_r1, frame->tf_r2, frame->tf_r3); 164 db_printf("r4 =%08x r5 =%08x r6 =%08x r7 =%08x\n", 165 frame->tf_r4, frame->tf_r5, frame->tf_r6, frame->tf_r7); 166 db_printf("r8 =%08x r9 =%08x r10=%08x r11=%08x\n", 167 frame->tf_r8, frame->tf_r9, frame->tf_r10, frame->tf_r11); 168 db_printf("r12=%08x r13=%08x r14=%08x r15=%08x\n", 169 frame->tf_r12, frame->tf_usr_sp, frame->tf_usr_lr, frame->tf_pc); 170 db_printf("slr=%08x ssp=%08x\n", frame->tf_svc_lr, frame->tf_svc_sp); 171 } 172 173 #ifdef _KERNEL 174 int 175 db_access_und_sp(const struct db_variable *vp, db_expr_t *valp, int rw) 176 { 177 178 if (rw == DB_VAR_GET) 179 *valp = get_stackptr(PSR_UND32_MODE); 180 return(0); 181 } 182 183 int 184 db_access_abt_sp(const struct db_variable *vp, db_expr_t *valp, int rw) 185 { 186 187 if (rw == DB_VAR_GET) 188 *valp = get_stackptr(PSR_ABT32_MODE); 189 return(0); 190 } 191 192 int 193 db_access_irq_sp(const struct db_variable *vp, db_expr_t *valp, int rw) 194 { 195 196 if (rw == DB_VAR_GET) 197 *valp = get_stackptr(PSR_IRQ32_MODE); 198 return(0); 199 } 200 201 void 202 db_show_fault_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) 203 { 204 db_printf("DFAR=%#x DFSR=%#x IFAR=%#x IFSR=%#x\n", 205 armreg_dfar_read(), armreg_dfsr_read(), 206 armreg_ifar_read(), armreg_ifsr_read()); 207 db_printf("CONTEXTIDR=%#x TTBCR=%#x TTBR=%#x\n", 208 armreg_contextidr_read(), armreg_ttbcr_read(), 209 armreg_ttbr_read()); 210 } 211 212 void 213 db_reset_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) 214 { 215 if (cpu_reset_address == NULL) { 216 db_printf("cpu_reset_address is not set\n"); 217 return; 218 } 219 220 cpu_reset_address(); 221 } 222 223 #if defined(CPU_CORTEXA5) || defined(CPU_CORTEXA7) 224 static void 225 tlb_print_common_header(const char *str) 226 { 227 db_printf("-W/I-- ----VA---- ----PA---- --SIZE-- D AP XN ASD %s\n", str); 228 } 229 230 static void 231 tlb_print_addr(size_t way, size_t va_index, vaddr_t vpn, paddr_t pfn) 232 { 233 db_printf("[%1zu:%02zx] 0x%05lx000 0x%05lx000", way, va_index, vpn, pfn); 234 } 235 236 static void 237 tlb_print_size_domain_prot(const char *sizestr, u_int domain, u_int ap, 238 bool xn_p) 239 { 240 db_printf(" %8s %1x %2d %s", sizestr, domain, ap, (xn_p ? "XN" : "--")); 241 } 242 243 static void 244 tlb_print_asid(bool ng_p, tlb_asid_t asid) 245 { 246 if (ng_p) { 247 db_printf(" %3d", asid); 248 } else { 249 db_printf(" ---"); 250 } 251 } 252 253 struct db_tlbinfo { 254 vaddr_t (*dti_decode_vpn)(size_t, uint32_t, uint32_t); 255 void (*dti_print_header)(void); 256 void (*dti_print_entry)(size_t, size_t, uint32_t, uint32_t); 257 u_int dti_index; 258 }; 259 260 #if defined(CPU_CORTEXA5) 261 static void 262 tlb_print_cortex_a5_header(void) 263 { 264 tlb_print_common_header(" S TEX C B"); 265 } 266 267 static vaddr_t 268 tlb_decode_cortex_a5_vpn(size_t va_index, uint32_t d0, uint32_t d1) 269 { 270 const uint64_t d = ((uint64_t)d1 << 32) | d0; 271 272 const u_int size = __SHIFTOUT(d, ARM_A5_TLBDATA_SIZE); 273 return __SHIFTOUT(d, ARM_A5_TLBDATA_VA) * (ARM_A5_TLBDATAOP_INDEX + 1) 274 + (va_index << (4*size)); 275 } 276 277 static void 278 tlb_print_cortex_a5_entry(size_t way, size_t va_index, uint32_t d0, uint32_t d1) 279 { 280 static const char size_strings[4][8] = { 281 " 4KB ", " 64KB ", " 1MB ", " 16MB ", 282 }; 283 284 const uint64_t d = ((uint64_t)d1 << 32) | d0; 285 286 const paddr_t pfn = __SHIFTOUT(d, ARM_A5_TLBDATA_PA); 287 const vaddr_t vpn = tlb_decode_cortex_a5_vpn(va_index, d0, d1); 288 289 tlb_print_addr(way, va_index, vpn, pfn); 290 291 const u_int size = __SHIFTOUT(d, ARM_A5_TLBDATA_SIZE); 292 const u_int domain = __SHIFTOUT(d, ARM_A5_TLBDATA_DOM); 293 const u_int ap = __SHIFTOUT(d, ARM_A5_TLBDATA_AP); 294 const bool xn_p = (d & ARM_A5_TLBDATA_XN) != 0; 295 296 tlb_print_size_domain_prot(size_strings[size], domain, ap, xn_p); 297 298 const bool ng_p = (d & ARM_A5_TLBDATA_nG) != 0; 299 const tlb_asid_t asid = __SHIFTOUT(d, ARM_A5_TLBDATA_ASID); 300 301 tlb_print_asid(ng_p, asid); 302 303 const u_int tex = __SHIFTOUT(d, ARM_A5_TLBDATA_TEX); 304 const bool c_p = (d & ARM_A5_TLBDATA_C) != 0; 305 const bool b_p = (d & ARM_A5_TLBDATA_B) != 0; 306 const bool s_p = (d & ARM_A5_TLBDATA_S) != 0; 307 308 db_printf(" %c %d %c %c\n", (s_p ? 'S' : '-'), tex, 309 (c_p ? 'C' : '-'), (b_p ? 'B' : '-')); 310 } 311 312 static const struct db_tlbinfo tlb_cortex_a5_info = { 313 .dti_decode_vpn = tlb_decode_cortex_a5_vpn, 314 .dti_print_header = tlb_print_cortex_a5_header, 315 .dti_print_entry = tlb_print_cortex_a5_entry, 316 .dti_index = ARM_A5_TLBDATAOP_INDEX, 317 }; 318 #endif /* CPU_CORTEXA5 */ 319 320 #if defined(CPU_CORTEXA7) 321 static const char tlb_cortex_a7_esizes[8][8] = { 322 " 4KB(S)", " 4KB(L)", "64KB(S)", "64KB(L)", 323 " 1MB(S)", " 2MB(L)", "16MB(S)", " 1GB(L)", 324 }; 325 326 static void 327 tlb_print_cortex_a7_header(void) 328 { 329 tlb_print_common_header("IS --OS- SH"); 330 } 331 332 static inline vaddr_t 333 tlb_decode_cortex_a7_vpn(size_t va_index, uint32_t d0, uint32_t d1) 334 { 335 const u_int size = __SHIFTOUT(d0, ARM_A7_TLBDATA0_SIZE); 336 const u_int shift = (size & 1) 337 ? ((0x12090400 >> (8*size)) & 0x1f) 338 : (2 * size); 339 340 return __SHIFTOUT(d0, ARM_A7_TLBDATA0_VA) * (ARM_A7_TLBDATAOP_INDEX + 1) 341 + (va_index << shift); 342 } 343 344 static void 345 tlb_print_cortex_a7_entry(size_t way, size_t va_index, uint32_t d0, uint32_t d1) 346 { 347 const uint32_t d2 = armreg_tlbdata2_read(); 348 const uint64_t d01 = ((uint64_t)d1 << 32) | d0; 349 const uint64_t d12 = ((uint64_t)d2 << 32) | d1; 350 351 const paddr_t pfn = __SHIFTOUT(d12, ARM_A7_TLBDATA12_PA); 352 const vaddr_t vpn = tlb_decode_cortex_a7_vpn(va_index, d0, d1); 353 354 tlb_print_addr(way, va_index, vpn, pfn); 355 356 const u_int size = __SHIFTOUT(d0, ARM_A7_TLBDATA0_SIZE); 357 const u_int domain = __SHIFTOUT(d2, ARM_A7_TLBDATA2_DOM); 358 const u_int ap = __SHIFTOUT(d1, ARM_A7_TLBDATA1_AP); 359 const bool xn_p = (d2 & ARM_A7_TLBDATA2_XN1) != 0; 360 361 tlb_print_size_domain_prot(tlb_cortex_a7_esizes[size], domain, ap, xn_p); 362 363 const bool ng_p = (d1 & ARM_A7_TLBDATA1_nG) != 0; 364 const tlb_asid_t asid = __SHIFTOUT(d01, ARM_A7_TLBDATA01_ASID); 365 366 tlb_print_asid(ng_p, asid); 367 368 const u_int is = __SHIFTOUT(d2, ARM_A7_TLBDATA2_IS); 369 if (is == ARM_A7_TLBDATA2_IS_DSO) { 370 u_int mt = __SHIFTOUT(d2, ARM_A7_TLBDATA2_SDO_MT); 371 switch (mt) { 372 case ARM_A7_TLBDATA2_SDO_MT_D: 373 db_printf(" DV\n"); 374 return; 375 case ARM_A7_TLBDATA2_SDO_MT_SO: 376 db_printf(" SO\n"); 377 return; 378 default: 379 db_printf(" %02u\n", mt); 380 return; 381 } 382 } 383 const u_int os = __SHIFTOUT(d2, ARM_A7_TLBDATA2_OS); 384 const u_int sh = __SHIFTOUT(d2, ARM_A7_TLBDATA2_SH); 385 static const char is_types[3][3] = { "NC", "WB", "WT" }; 386 static const char os_types[4][6] = { "NC", "WB+WA", "WT", "WB" }; 387 static const char sh_types[4][3] = { "NS", "na", "OS", "IS" }; 388 db_printf(" %2s %5s %2s\n", is_types[is], os_types[os], sh_types[sh]); 389 } 390 391 static const struct db_tlbinfo tlb_cortex_a7_info = { 392 .dti_decode_vpn = tlb_decode_cortex_a7_vpn, 393 .dti_print_header = tlb_print_cortex_a7_header, 394 .dti_print_entry = tlb_print_cortex_a7_entry, 395 .dti_index = ARM_A7_TLBDATAOP_INDEX, 396 }; 397 #endif /* CPU_CORTEXA7 */ 398 399 static inline const struct db_tlbinfo * 400 tlb_lookup_tlbinfo(void) 401 { 402 #if defined(CPU_CORTEXA5) && defined(CPU_CORTEXA7) 403 const bool cortex_a5_p = CPU_ID_CORTEX_A5_P(curcpu()->ci_arm_cpuid); 404 const bool cortex_a7_p = CPU_ID_CORTEX_A7_P(curcpu()->ci_arm_cpuid); 405 #elif defined(CPU_CORTEXA5) 406 const bool cortex_a5_p = true; 407 #else 408 const bool cortex_a7_p = true; 409 #endif 410 #ifdef CPU_CORTEXA5 411 if (cortex_a5_p) { 412 return &tlb_cortex_a5_info; 413 } 414 #endif 415 #ifdef CPU_CORTEXA7 416 if (cortex_a7_p) { 417 return &tlb_cortex_a7_info; 418 } 419 #endif 420 return NULL; 421 } 422 423 void 424 db_show_tlb_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) 425 { 426 const struct db_tlbinfo * const dti = tlb_lookup_tlbinfo(); 427 428 if (have_addr) { 429 const vaddr_t vpn = (vaddr_t)addr >> L2_S_SHIFT; 430 const u_int va_index = vpn & dti->dti_index; 431 for (size_t way = 0; way < 2; way++) { 432 armreg_tlbdataop_write( 433 __SHIFTIN(va_index, dti->dti_index) 434 | __SHIFTIN(way, ARM_TLBDATAOP_WAY)); 435 arm_isb(); 436 const uint32_t d0 = armreg_tlbdata0_read(); 437 const uint32_t d1 = armreg_tlbdata1_read(); 438 if ((d0 & ARM_TLBDATA_VALID) 439 && vpn == (*dti->dti_decode_vpn)(va_index, d0, d1)) { 440 (*dti->dti_print_header)(); 441 (*dti->dti_print_entry)(way, va_index, d0, d1); 442 return; 443 } 444 } 445 db_printf("VA %#"DDB_EXPR_FMT"x not found in TLB\n", addr); 446 return; 447 } 448 449 bool first = true; 450 size_t n = 0; 451 for (size_t va_index = 0; va_index <= dti->dti_index; va_index++) { 452 for (size_t way = 0; way < 2; way++) { 453 armreg_tlbdataop_write( 454 __SHIFTIN(way, ARM_TLBDATAOP_WAY) 455 | __SHIFTIN(va_index, dti->dti_index)); 456 arm_isb(); 457 const uint32_t d0 = armreg_tlbdata0_read(); 458 const uint32_t d1 = armreg_tlbdata1_read(); 459 if (d0 & ARM_TLBDATA_VALID) { 460 if (first) { 461 (*dti->dti_print_header)(); 462 first = false; 463 } 464 (*dti->dti_print_entry)(way, va_index, d0, d1); 465 n++; 466 } 467 } 468 } 469 db_printf("%zu TLB valid entries found\n", n); 470 } 471 #endif /* CPU_CORTEXA5 || CPU_CORTEXA7 */ 472 473 #if defined(MULTIPROCESSOR) 474 void 475 db_switch_cpu_cmd(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) 476 { 477 if (addr >= maxcpus) { 478 db_printf("cpu %"DDB_EXPR_FMT"d out of range", addr); 479 return; 480 } 481 struct cpu_info *new_ci = cpu_lookup(addr); 482 if (new_ci == NULL) { 483 db_printf("cpu %"DDB_EXPR_FMT"d does not exist", addr); 484 return; 485 } 486 if (DDB_REGS->tf_spsr & PSR_T_bit) { 487 DDB_REGS->tf_pc -= 2; /* XXX */ 488 } else { 489 DDB_REGS->tf_pc -= 4; 490 } 491 db_newcpu = new_ci; 492 db_continue_cmd(0, false, 0, ""); 493 } 494 #endif 495 496 static void 497 show_cpuinfo(struct cpu_info *kci) 498 { 499 struct cpu_info cpuinfobuf; 500 cpuid_t cpuid; 501 int i; 502 503 db_read_bytes((db_addr_t)kci, sizeof(cpuinfobuf), (char *)&cpuinfobuf); 504 505 struct cpu_info *ci = &cpuinfobuf; 506 cpuid = ci->ci_cpuid; 507 db_printf("cpu_info=%p, cpu_name=%s\n", kci, ci->ci_cpuname); 508 db_printf("%p cpu[%lu].ci_cpuid = %lu\n", 509 &ci->ci_cpuid, cpuid, ci->ci_cpuid); 510 db_printf("%p cpu[%lu].ci_curlwp = %p\n", 511 &ci->ci_curlwp, cpuid, ci->ci_curlwp); 512 for (i = 0; i < SOFTINT_COUNT; i++) { 513 db_printf("%p cpu[%lu].ci_softlwps[%d] = %p\n", 514 &ci->ci_softlwps[i], cpuid, i, ci->ci_softlwps[i]); 515 } 516 db_printf("%p cpu[%lu].ci_lastintr = %" PRIu64 "\n", 517 &ci->ci_lastintr, cpuid, ci->ci_lastintr); 518 db_printf("%p cpu[%lu].ci_want_resched = %d\n", 519 &ci->ci_want_resched, cpuid, ci->ci_want_resched); 520 db_printf("%p cpu[%lu].ci_cpl = %d\n", 521 &ci->ci_cpl, cpuid, ci->ci_cpl); 522 db_printf("%p cpu[%lu].ci_softints = 0x%08x\n", 523 &ci->ci_softints, cpuid, ci->ci_softints); 524 db_printf("%p cpu[%lu].ci_intr_depth = %u\n", 525 &ci->ci_intr_depth, cpuid, ci->ci_intr_depth); 526 527 } 528 529 void 530 db_md_cpuinfo_cmd(db_expr_t addr, bool have_addr, db_expr_t count, 531 const char *modif) 532 { 533 #ifdef MULTIPROCESSOR 534 CPU_INFO_ITERATOR cii; 535 struct cpu_info *ci; 536 bool showall = false; 537 538 if (modif != NULL) { 539 for (; *modif != '\0'; modif++) { 540 switch (*modif) { 541 case 'a': 542 showall = true; 543 break; 544 } 545 } 546 } 547 548 if (showall) { 549 for (CPU_INFO_FOREACH(cii, ci)) { 550 show_cpuinfo(ci); 551 } 552 } else 553 #endif /* MULTIPROCESSOR */ 554 show_cpuinfo(curcpu()); 555 } 556 557 #endif /* _KERNEL */ 558