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