1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * 25 * Copyright 2018 Joyent, Inc. 26 * Copyright 2025 Oxide Computer Company 27 */ 28 29 /* 30 * isa-dependent portions of the kmdb target 31 */ 32 33 #include <kmdb/kvm.h> 34 #include <kmdb/kmdb_kdi.h> 35 #include <kmdb/kmdb_asmutil.h> 36 #include <mdb/mdb_debug.h> 37 #include <mdb/mdb_stack.h> 38 #include <mdb/mdb_err.h> 39 #include <mdb/mdb_list.h> 40 #include <mdb/mdb_target_impl.h> 41 #include <mdb/mdb_isautil.h> 42 #include <mdb/mdb_kreg_impl.h> 43 #include <mdb/mdb.h> 44 45 #include <sys/types.h> 46 #include <sys/frame.h> 47 #include <sys/trap.h> 48 #include <sys/bitmap.h> 49 #include <sys/pci_impl.h> 50 51 /* Higher than the highest trap number for which we have a defined specifier */ 52 #define KMT_MAXTRAPNO 0x20 53 54 #define IOPORTLIMIT 0xffff /* XXX find a new home for this */ 55 56 const char * 57 kmt_def_dismode(void) 58 { 59 #ifdef __amd64 60 return ("amd64"); 61 #else 62 return ("ia32"); 63 #endif 64 } 65 66 int 67 kmt_step_out_validate(mdb_tgt_t *t, uintptr_t pc) 68 { 69 kmt_data_t *kmt = t->t_data; 70 int i; 71 72 for (i = 0; i < sizeof (kmt->kmt_intrsyms) / sizeof (GElf_Sym); i++) { 73 GElf_Sym *sym = (GElf_Sym *)&kmt->kmt_intrsyms + i; 74 75 if (pc >= sym->st_value && pc < sym->st_value + sym->st_size) 76 return (0); 77 } 78 79 return (1); 80 } 81 82 /* 83 * Determine the return address for the current frame. 84 */ 85 int 86 kmt_step_out(mdb_tgt_t *t, uintptr_t *p) 87 { 88 mdb_instr_t instr; 89 kreg_t pc, sp, fp; 90 91 (void) kmdb_dpi_get_register("pc", &pc); 92 (void) kmdb_dpi_get_register("sp", &sp); 93 (void) kmdb_dpi_get_register("fp", &fp); 94 95 if (mdb_tgt_vread(t, &instr, sizeof (mdb_instr_t), pc) != 96 sizeof (mdb_instr_t)) 97 return (-1); /* errno is set for us */ 98 99 if (!kmt_step_out_validate(t, pc)) 100 return (set_errno(EMDB_TGTNOTSUP)); 101 102 return (mdb_isa_step_out(t, p, pc, fp, sp, instr)); 103 } 104 105 /* 106 * Return the address of the next instruction following a call, or return -1 107 * and set errno to EAGAIN if the target should just single-step. 108 */ 109 int 110 kmt_next(mdb_tgt_t *t, uintptr_t *p) 111 { 112 kreg_t pc; 113 mdb_instr_t instr; 114 115 (void) kmdb_dpi_get_register("pc", &pc); 116 117 if (mdb_tgt_vread(t, &instr, sizeof (mdb_instr_t), pc) != 118 sizeof (mdb_instr_t)) 119 return (-1); /* errno is set for us */ 120 121 return (mdb_isa_next(t, p, pc, instr)); 122 } 123 124 static int 125 kmt_stack_common(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv, 126 int cpuid, mdb_stack_frame_flags_t sflags, mdb_tgt_stack_f *func) 127 { 128 mdb_tgt_t *t = mdb.m_target; 129 const mdb_tgt_gregset_t *grp = NULL; 130 mdb_tgt_gregset_t gregs; 131 mdb_stack_frame_hdl_t *hdl; 132 uint_t arglim = mdb.m_nargs; 133 int i; 134 135 if (flags & DCMD_ADDRSPEC) { 136 bzero(&gregs, sizeof (gregs)); 137 gregs.kregs[KREG_FP] = addr; 138 grp = &gregs; 139 } else { 140 grp = kmdb_dpi_get_gregs(cpuid); 141 } 142 143 if (grp == NULL) { 144 warn("failed to retrieve registers for cpu %d", cpuid); 145 return (DCMD_ERR); 146 } 147 148 i = mdb_getopts(argc, argv, 149 'n', MDB_OPT_SETBITS, MSF_ADDR, &sflags, 150 's', MDB_OPT_SETBITS, MSF_SIZES, &sflags, 151 't', MDB_OPT_SETBITS, MSF_TYPES, &sflags, 152 'v', MDB_OPT_SETBITS, MSF_VERBOSE, &sflags, 153 NULL); 154 155 argc -= i; 156 argv += i; 157 158 if (argc != 0) { 159 if (argv->a_type == MDB_TYPE_CHAR || argc > 1) 160 return (DCMD_USAGE); 161 162 arglim = mdb_argtoull(argv); 163 } 164 165 if ((hdl = mdb_stack_frame_init(t, arglim, sflags)) == NULL) { 166 mdb_warn("failed to init stack frame\n"); 167 return (DCMD_ERR); 168 } 169 170 (void) mdb_isa_kvm_stack_iter(t, grp, func, (void *)hdl); 171 172 return (DCMD_OK); 173 } 174 175 int 176 kmt_cpustack(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv, 177 int cpuid, uint_t verbose) 178 { 179 return (kmt_stack_common(addr, flags, argc, argv, cpuid, 180 verbose != 0 ? MSF_VERBOSE : 0, mdb_isa_kvm_frame)); 181 } 182 183 int 184 kmt_stack(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 185 { 186 return (kmt_stack_common(addr, flags, argc, argv, DPI_MASTER_CPUID, 187 0, mdb_isa_kvm_frame)); 188 } 189 190 int 191 kmt_stackv(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 192 { 193 return (kmt_stack_common(addr, flags, argc, argv, DPI_MASTER_CPUID, 194 MSF_VERBOSE, mdb_isa_kvm_frame)); 195 } 196 197 int 198 kmt_stackr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 199 { 200 return (kmt_stack_common(addr, flags, argc, argv, DPI_MASTER_CPUID, 201 MSF_VERBOSE, mdb_isa_kvm_frame)); 202 } 203 204 /*ARGSUSED*/ 205 void 206 kmt_printregs(const mdb_tgt_gregset_t *gregs) 207 { 208 mdb_isa_printregs(gregs); 209 } 210 211 #define IOCHECK_NOWARN 0 212 #define IOCHECK_WARN 1 213 214 static int 215 kmt_io_check(uint64_t nbytes, uintptr_t addr, int dowarn) 216 { 217 if (addr > IOPORTLIMIT) { 218 if (dowarn) 219 warn("port address must be 0-%#x\n", IOPORTLIMIT); 220 return (set_errno(EINVAL)); 221 } 222 223 if (nbytes != 1 && nbytes != 2 && nbytes != 4) { 224 if (dowarn) 225 warn("port access must be 1, 2, or 4 bytes\n"); 226 return (set_errno(EINVAL)); 227 } 228 229 if ((addr & (nbytes - 1)) != 0) { 230 if (dowarn) { 231 warn("address for %llu-byte access must be %llu-byte " 232 "aligned\n", (u_longlong_t)nbytes, 233 (u_longlong_t)nbytes); 234 } 235 return (set_errno(EINVAL)); 236 } 237 238 return (0); 239 } 240 241 /*ARGSUSED1*/ 242 int 243 kmt_in_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 244 { 245 uint64_t len = 0; 246 uint32_t buf; 247 248 if (mdb_getopts(argc, argv, 249 'L', MDB_OPT_UINT64, &len, 250 NULL) != argc) 251 return (DCMD_USAGE); 252 253 if (len == 0) 254 len = mdb.m_dcount; 255 256 if (kmt_io_check(len, addr, IOCHECK_WARN) < 0) 257 return (DCMD_ERR); 258 259 if (mdb_tgt_ioread(mdb.m_target, &buf, len, addr) < 0) { 260 warn("failed to read from port 0x%llx", (u_longlong_t)addr); 261 return (DCMD_ERR); 262 } 263 264 mdb_printf("%x\n", buf); 265 266 return (DCMD_OK); 267 } 268 269 /*ARGSUSED1*/ 270 int 271 kmt_out_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 272 { 273 uint64_t len = 0; 274 uint64_t val; 275 276 if (mdb_getopts(argc, argv, 277 'L', MDB_OPT_UINT64, &len, 278 NULL) != argc - 1) 279 return (DCMD_USAGE); 280 281 if (len == 0) 282 len = mdb.m_dcount; 283 284 argv += argc - 1; 285 val = mdb_argtoull(argv); 286 287 if (kmt_io_check(len, addr, IOCHECK_WARN) < 0) 288 return (DCMD_ERR); 289 290 if (val > (1ULL << (len * NBBY)) - 1) { 291 warn("value is out of range for port size\n"); 292 return (DCMD_ERR); 293 } 294 295 if (mdb_tgt_iowrite(mdb.m_target, &val, len, addr) < 0) { 296 warn("failed to write to port %llx", (u_longlong_t)addr); 297 return (DCMD_ERR); 298 } 299 300 return (DCMD_OK); 301 } 302 303 static int 304 kmt_rwmsr(uint32_t addr, uint64_t *valp, void (*rw)(uint32_t, uint64_t *)) 305 { 306 jmp_buf pcb, *oldpcb = NULL; 307 308 if (setjmp(pcb) != 0) { 309 kmdb_dpi_restore_fault_hdlr(oldpcb); 310 return (-1); /* errno is set for us */ 311 } 312 313 oldpcb = kmdb_dpi_set_fault_hdlr(&pcb); 314 rw(addr, valp); 315 kmdb_dpi_restore_fault_hdlr(oldpcb); 316 317 return (0); 318 } 319 320 /*ARGSUSED*/ 321 int 322 kmt_rdmsr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 323 { 324 uint64_t val; 325 326 if (!(flags & DCMD_ADDRSPEC)) 327 return (DCMD_USAGE); 328 329 if (kmt_rwmsr(addr, &val, rdmsr) < 0) { 330 warn("rdmsr failed"); 331 return (DCMD_ERR); 332 } 333 334 mdb_printf("%llx\n", (u_longlong_t)val); 335 336 return (DCMD_OK); 337 } 338 339 /*ARGSUSED*/ 340 int 341 kmt_wrmsr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 342 { 343 uint64_t val; 344 345 if (!(flags & DCMD_ADDRSPEC) || argc != 1) 346 return (DCMD_USAGE); 347 348 val = mdb_argtoull(argv); 349 350 if (kmt_rwmsr(addr, &val, wrmsr)) { 351 warn("wrmsr failed"); 352 return (DCMD_ERR); 353 } 354 355 return (DCMD_OK); 356 } 357 358 /*ARGSUSED*/ 359 ssize_t 360 kmt_write(mdb_tgt_t *t, const void *buf, size_t nbytes, uintptr_t addr) 361 { 362 if (!(t->t_flags & MDB_TGT_F_ALLOWIO) && 363 (nbytes = kmdb_kdi_range_is_nontoxic(addr, nbytes, 1)) == 0) 364 return (set_errno(EMDB_NOMAP)); 365 366 /* 367 * No writes to user space are allowed. If we were to allow it, we'd 368 * be in the unfortunate situation where kmdb could place a breakpoint 369 * on a userspace executable page; this dirty page would end up being 370 * flushed back to disk, incurring sadness when it's next executed. 371 * Besides, we can't allow trapping in from userspace anyway. 372 */ 373 if (addr < kmdb_kdi_get_userlimit()) 374 return (set_errno(EMDB_TGTNOTSUP)); 375 376 return (kmt_rw(t, (void *)buf, nbytes, addr, kmt_writer)); 377 } 378 379 /*ARGSUSED*/ 380 static ssize_t 381 kmt_iorw(mdb_tgt_t *t, void *buf, size_t nbytes, uint64_t addr, 382 void (*iorw)(void *, size_t, uintptr_t)) 383 { 384 jmp_buf pcb, *oldpcb = NULL; 385 386 if (kmt_io_check(nbytes, addr, IOCHECK_NOWARN) < 0) 387 return (-1); /* errno is set for us */ 388 389 if (setjmp(pcb) != 0) { 390 kmdb_dpi_restore_fault_hdlr(oldpcb); 391 return (-1); /* errno is set for us */ 392 } 393 394 oldpcb = kmdb_dpi_set_fault_hdlr(&pcb); 395 iorw(buf, nbytes, addr); 396 kmdb_dpi_restore_fault_hdlr(oldpcb); 397 398 return (nbytes); 399 } 400 401 /*ARGSUSED*/ 402 ssize_t 403 kmt_ioread(mdb_tgt_t *t, void *buf, size_t nbytes, uintptr_t addr) 404 { 405 return (kmt_iorw(t, buf, nbytes, addr, kmt_in)); 406 } 407 408 /*ARGSUSED*/ 409 ssize_t 410 kmt_iowrite(mdb_tgt_t *t, const void *buf, size_t nbytes, uintptr_t addr) 411 { 412 return (kmt_iorw(t, (void *)buf, nbytes, addr, kmt_out)); 413 } 414 415 static int 416 kmt_pcicfg_common(uintptr_t off, uint32_t *valp, const mdb_arg_t *argv, 417 void (*rw)(void *, size_t, uintptr_t)) 418 { 419 uint32_t bus, dev, func; 420 uint32_t addr; 421 422 bus = (uint32_t)mdb_argtoull(&argv[0]); 423 dev = (uint32_t)mdb_argtoull(&argv[1]); 424 func = (uint32_t)mdb_argtoull(&argv[2]); 425 426 if ((bus & 0xffff) != bus) { 427 warn("invalid bus number (must be 0-0xffff)\n"); 428 return (DCMD_ERR); 429 } 430 431 if ((dev & 0x1f) != dev) { 432 warn("invalid device number (must be 0-0x1f)\n"); 433 return (DCMD_ERR); 434 } 435 436 if ((func & 0x7) != func) { 437 warn("invalid function number (must be 0-7)\n"); 438 return (DCMD_ERR); 439 } 440 441 if ((off & 0xfc) != off) { 442 warn("invalid register number (must be 0-0xff, and 4-byte " 443 "aligned\n"); 444 return (DCMD_ERR); 445 } 446 447 addr = PCI_CADDR1(bus, dev, func, off); 448 449 if (kmt_iowrite(mdb.m_target, &addr, sizeof (addr), PCI_CONFADD) != 450 sizeof (addr)) { 451 warn("write of PCI_CONFADD failed"); 452 return (DCMD_ERR); 453 } 454 455 if (kmt_iorw(mdb.m_target, valp, sizeof (*valp), PCI_CONFDATA, rw) != 456 sizeof (*valp)) { 457 warn("access to PCI_CONFDATA failed"); 458 return (DCMD_ERR); 459 } 460 461 return (DCMD_OK); 462 } 463 464 /*ARGSUSED*/ 465 int 466 kmt_rdpcicfg(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 467 { 468 uint32_t val; 469 470 if (argc != 3 || !(flags & DCMD_ADDRSPEC)) 471 return (DCMD_USAGE); 472 473 if (kmt_pcicfg_common(addr, &val, argv, kmt_in) != DCMD_OK) 474 return (DCMD_ERR); 475 476 mdb_printf("%llx\n", (u_longlong_t)val); 477 478 return (DCMD_OK); 479 } 480 481 /*ARGSUSED*/ 482 int 483 kmt_wrpcicfg(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 484 { 485 uint32_t val; 486 487 if (argc != 4 || !(flags & DCMD_ADDRSPEC)) 488 return (DCMD_USAGE); 489 490 val = (uint32_t)mdb_argtoull(&argv[3]); 491 492 if (kmt_pcicfg_common(addr, &val, argv, kmt_out) != DCMD_OK) 493 return (DCMD_ERR); 494 495 return (DCMD_OK); 496 } 497 498 const char * 499 kmt_trapname(int trapnum) 500 { 501 static char trapname[11]; 502 503 switch (trapnum) { 504 case T_ZERODIV: 505 return ("division by zero (#de) trap"); 506 case T_SGLSTP: 507 return ("single-step (#db) trap"); 508 case T_NMIFLT: 509 return ("NMI"); 510 case T_BPTFLT: 511 return ("breakpoint (#bp) trap"); 512 case T_ILLINST: 513 return ("illegal instruction (#ud) trap"); 514 case T_SEGFLT: 515 return ("segment not present (#np) trap"); 516 case T_STKFLT: 517 return ("stack (#ss) trap"); 518 case T_GPFLT: 519 return ("general protection (#gp) trap"); 520 case T_PGFLT: 521 return ("page fault (#pf) trap"); 522 case T_ALIGNMENT: 523 return ("alignment check (#ac) trap"); 524 case T_MCE: 525 return ("machine check (#mc) trap"); 526 case T_SIMDFPE: 527 return ("SSE/SSE2 (#xm) trap"); 528 case T_DBGENTR: 529 return ("debugger entry trap"); 530 default: 531 (void) mdb_snprintf(trapname, sizeof (trapname), "trap %#x", 532 trapnum); 533 return (trapname); 534 } 535 } 536 537 void 538 kmt_init_isadep(mdb_tgt_t *t) 539 { 540 kmt_data_t *kmt = t->t_data; 541 542 kmt->kmt_rds = mdb_isa_kregs; 543 544 kmt->kmt_trapmax = KMT_MAXTRAPNO; 545 kmt->kmt_trapmap = mdb_zalloc(BT_SIZEOFMAP(kmt->kmt_trapmax), UM_SLEEP); 546 547 /* Traps for which we want to provide an explicit message */ 548 (void) mdb_tgt_add_fault(t, T_ZERODIV, MDB_TGT_SPEC_INTERNAL, 549 no_se_f, NULL); 550 (void) mdb_tgt_add_fault(t, T_ILLINST, MDB_TGT_SPEC_INTERNAL, 551 no_se_f, NULL); 552 (void) mdb_tgt_add_fault(t, T_SEGFLT, MDB_TGT_SPEC_INTERNAL, 553 no_se_f, NULL); 554 (void) mdb_tgt_add_fault(t, T_STKFLT, MDB_TGT_SPEC_INTERNAL, 555 no_se_f, NULL); 556 (void) mdb_tgt_add_fault(t, T_GPFLT, MDB_TGT_SPEC_INTERNAL, 557 no_se_f, NULL); 558 (void) mdb_tgt_add_fault(t, T_PGFLT, MDB_TGT_SPEC_INTERNAL, 559 no_se_f, NULL); 560 (void) mdb_tgt_add_fault(t, T_ALIGNMENT, MDB_TGT_SPEC_INTERNAL, 561 no_se_f, NULL); 562 (void) mdb_tgt_add_fault(t, T_MCE, MDB_TGT_SPEC_INTERNAL, 563 no_se_f, NULL); 564 (void) mdb_tgt_add_fault(t, T_SIMDFPE, MDB_TGT_SPEC_INTERNAL, 565 no_se_f, NULL); 566 567 /* 568 * Traps which will be handled elsewhere, and which therefore don't 569 * need the trap-based message. 570 */ 571 BT_SET(kmt->kmt_trapmap, T_SGLSTP); 572 BT_SET(kmt->kmt_trapmap, T_BPTFLT); 573 BT_SET(kmt->kmt_trapmap, T_DBGENTR); 574 575 /* Catch-all for traps not explicitly listed here */ 576 (void) mdb_tgt_add_fault(t, KMT_TRAP_NOTENUM, MDB_TGT_SPEC_INTERNAL, 577 no_se_f, NULL); 578 } 579 580 void 581 kmt_startup_isadep(mdb_tgt_t *t) 582 { 583 kmt_data_t *kmt = t->t_data; 584 585 /* 586 * The stack trace and ::step out code need to detect "interrupt" 587 * frames. The heuristic they use to detect said frames requires the 588 * addresses of routines that can generate them. 589 */ 590 (void) mdb_tgt_lookup_by_name(t, MDB_TGT_OBJ_EXEC, 591 "cmnint", &kmt->kmt_intrsyms._kmt_cmnint, NULL); 592 (void) mdb_tgt_lookup_by_name(t, MDB_TGT_OBJ_EXEC, 593 "cmntrap", &kmt->kmt_intrsyms._kmt_cmntrap, NULL); 594 (void) mdb_tgt_lookup_by_name(t, MDB_TGT_OBJ_EXEC, 595 "sys_sysenter", &kmt->kmt_intrsyms._kmt_sysenter, NULL); 596 (void) mdb_tgt_lookup_by_name(t, MDB_TGT_OBJ_EXEC, 597 "brand_sys_sysenter", &kmt->kmt_intrsyms._kmt_brand_sysenter, NULL); 598 #if defined(__amd64) 599 (void) mdb_tgt_lookup_by_name(t, MDB_TGT_OBJ_EXEC, 600 "sys_syscall", &kmt->kmt_intrsyms._kmt_syscall, NULL); 601 (void) mdb_tgt_lookup_by_name(t, MDB_TGT_OBJ_EXEC, 602 "brand_sys_syscall", &kmt->kmt_intrsyms._kmt_brand_syscall, NULL); 603 #endif 604 } 605