17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5f18fc278Sjohnlev * Common Development and Distribution License (the "License"). 6f18fc278Sjohnlev * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*ae115bc7Smrj * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate /* 297c478bd9Sstevel@tonic-gate * isa-dependent portions of the kmdb target 307c478bd9Sstevel@tonic-gate */ 317c478bd9Sstevel@tonic-gate 327c478bd9Sstevel@tonic-gate #include <kmdb/kvm.h> 337c478bd9Sstevel@tonic-gate #include <kmdb/kvm_cpu.h> 347c478bd9Sstevel@tonic-gate #include <kmdb/kmdb_kdi.h> 357c478bd9Sstevel@tonic-gate #include <kmdb/kmdb_asmutil.h> 367c478bd9Sstevel@tonic-gate #include <mdb/mdb_debug.h> 377c478bd9Sstevel@tonic-gate #include <mdb/mdb_err.h> 387c478bd9Sstevel@tonic-gate #include <mdb/mdb_list.h> 397c478bd9Sstevel@tonic-gate #include <mdb/mdb_target_impl.h> 407c478bd9Sstevel@tonic-gate #include <mdb/mdb_isautil.h> 417c478bd9Sstevel@tonic-gate #include <mdb/mdb_kreg_impl.h> 427c478bd9Sstevel@tonic-gate #include <mdb/mdb.h> 437c478bd9Sstevel@tonic-gate 447c478bd9Sstevel@tonic-gate #include <sys/types.h> 457c478bd9Sstevel@tonic-gate #include <sys/frame.h> 467c478bd9Sstevel@tonic-gate #include <sys/trap.h> 477c478bd9Sstevel@tonic-gate #include <sys/bitmap.h> 487aec1d6eScindi #include <sys/pci_impl.h> 497c478bd9Sstevel@tonic-gate 507c478bd9Sstevel@tonic-gate /* Higher than the highest trap number for which we have a defined specifier */ 517c478bd9Sstevel@tonic-gate #define KMT_MAXTRAPNO 0x20 527c478bd9Sstevel@tonic-gate 537c478bd9Sstevel@tonic-gate #define IOPORTLIMIT 0xffff /* XXX find a new home for this */ 547c478bd9Sstevel@tonic-gate 557c478bd9Sstevel@tonic-gate const char * 567c478bd9Sstevel@tonic-gate kmt_def_dismode(void) 577c478bd9Sstevel@tonic-gate { 587c478bd9Sstevel@tonic-gate #ifdef __amd64 597c478bd9Sstevel@tonic-gate return ("amd64"); 607c478bd9Sstevel@tonic-gate #else 617c478bd9Sstevel@tonic-gate return ("ia32"); 627c478bd9Sstevel@tonic-gate #endif 637c478bd9Sstevel@tonic-gate } 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate int 667c478bd9Sstevel@tonic-gate kmt_step_out_validate(mdb_tgt_t *t, uintptr_t pc) 677c478bd9Sstevel@tonic-gate { 687c478bd9Sstevel@tonic-gate kmt_data_t *kmt = t->t_data; 697c478bd9Sstevel@tonic-gate int i; 707c478bd9Sstevel@tonic-gate 717c478bd9Sstevel@tonic-gate for (i = 0; i < sizeof (kmt->kmt_intrsyms) / sizeof (GElf_Sym); i++) { 727c478bd9Sstevel@tonic-gate GElf_Sym *sym = (GElf_Sym *)&kmt->kmt_intrsyms + i; 737c478bd9Sstevel@tonic-gate 747c478bd9Sstevel@tonic-gate if (pc >= sym->st_value && pc < sym->st_value + sym->st_size) 757c478bd9Sstevel@tonic-gate return (0); 767c478bd9Sstevel@tonic-gate } 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate return (1); 797c478bd9Sstevel@tonic-gate } 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate /* 827c478bd9Sstevel@tonic-gate * Determine the return address for the current frame. 837c478bd9Sstevel@tonic-gate */ 847c478bd9Sstevel@tonic-gate int 857c478bd9Sstevel@tonic-gate kmt_step_out(mdb_tgt_t *t, uintptr_t *p) 867c478bd9Sstevel@tonic-gate { 877c478bd9Sstevel@tonic-gate mdb_instr_t instr; 887c478bd9Sstevel@tonic-gate kreg_t pc, sp, fp; 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate (void) kmdb_dpi_get_register("pc", &pc); 917c478bd9Sstevel@tonic-gate (void) kmdb_dpi_get_register("sp", &sp); 927c478bd9Sstevel@tonic-gate (void) kmdb_dpi_get_register("fp", &fp); 937c478bd9Sstevel@tonic-gate 947c478bd9Sstevel@tonic-gate if (mdb_tgt_vread(t, &instr, sizeof (mdb_instr_t), pc) != 957c478bd9Sstevel@tonic-gate sizeof (mdb_instr_t)) 967c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */ 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate if (!kmt_step_out_validate(t, pc)) 997c478bd9Sstevel@tonic-gate return (set_errno(EMDB_TGTNOTSUP)); 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate return (mdb_isa_step_out(t, p, pc, fp, sp, instr)); 1027c478bd9Sstevel@tonic-gate } 1037c478bd9Sstevel@tonic-gate 1047c478bd9Sstevel@tonic-gate int 1057c478bd9Sstevel@tonic-gate kmt_step_branch(mdb_tgt_t *t) 1067c478bd9Sstevel@tonic-gate { 1077c478bd9Sstevel@tonic-gate kmt_data_t *kmt = t->t_data; 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate return (kmt_cpu_step_branch(t, kmt->kmt_cpu)); 1107c478bd9Sstevel@tonic-gate } 1117c478bd9Sstevel@tonic-gate 1127c478bd9Sstevel@tonic-gate /* 1137c478bd9Sstevel@tonic-gate * Return the address of the next instruction following a call, or return -1 1147c478bd9Sstevel@tonic-gate * and set errno to EAGAIN if the target should just single-step. 1157c478bd9Sstevel@tonic-gate */ 1167c478bd9Sstevel@tonic-gate int 1177c478bd9Sstevel@tonic-gate kmt_next(mdb_tgt_t *t, uintptr_t *p) 1187c478bd9Sstevel@tonic-gate { 1197c478bd9Sstevel@tonic-gate kreg_t pc; 1207c478bd9Sstevel@tonic-gate mdb_instr_t instr; 1217c478bd9Sstevel@tonic-gate 1227c478bd9Sstevel@tonic-gate (void) kmdb_dpi_get_register("pc", &pc); 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate if (mdb_tgt_vread(t, &instr, sizeof (mdb_instr_t), pc) != 1257c478bd9Sstevel@tonic-gate sizeof (mdb_instr_t)) 1267c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */ 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate return (mdb_isa_next(t, p, pc, instr)); 1297c478bd9Sstevel@tonic-gate } 1307c478bd9Sstevel@tonic-gate 1317c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1327c478bd9Sstevel@tonic-gate static int 1337c478bd9Sstevel@tonic-gate kmt_stack_common(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv, 1347c478bd9Sstevel@tonic-gate int cpuid, mdb_tgt_stack_f *func) 1357c478bd9Sstevel@tonic-gate { 1367c478bd9Sstevel@tonic-gate const mdb_tgt_gregset_t *grp = NULL; 1377c478bd9Sstevel@tonic-gate mdb_tgt_gregset_t gregs; 1387c478bd9Sstevel@tonic-gate void *arg = (void *)(uintptr_t)mdb.m_nargs; 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate if (flags & DCMD_ADDRSPEC) { 1417c478bd9Sstevel@tonic-gate bzero(&gregs, sizeof (gregs)); 1427c478bd9Sstevel@tonic-gate gregs.kregs[KREG_FP] = addr; 1437c478bd9Sstevel@tonic-gate grp = &gregs; 1447c478bd9Sstevel@tonic-gate } else 1457c478bd9Sstevel@tonic-gate grp = kmdb_dpi_get_gregs(cpuid); 1467c478bd9Sstevel@tonic-gate 147acbc304dSjohnlev if (grp == NULL) { 148acbc304dSjohnlev warn("failed to retrieve registers for cpu %d", cpuid); 149acbc304dSjohnlev return (DCMD_ERR); 150acbc304dSjohnlev } 151acbc304dSjohnlev 1527c478bd9Sstevel@tonic-gate if (argc != 0) { 1537c478bd9Sstevel@tonic-gate if (argv->a_type == MDB_TYPE_CHAR || argc > 1) 1547c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 1557c478bd9Sstevel@tonic-gate 1567c478bd9Sstevel@tonic-gate if (argv->a_type == MDB_TYPE_STRING) 1577c478bd9Sstevel@tonic-gate arg = (void *)(uintptr_t)mdb_strtoull(argv->a_un.a_str); 1587c478bd9Sstevel@tonic-gate else 1597c478bd9Sstevel@tonic-gate arg = (void *)(uintptr_t)argv->a_un.a_val; 1607c478bd9Sstevel@tonic-gate } 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate (void) mdb_isa_kvm_stack_iter(mdb.m_target, grp, func, arg); 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate return (DCMD_OK); 1657c478bd9Sstevel@tonic-gate } 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate int 1687c478bd9Sstevel@tonic-gate kmt_cpustack(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv, 1697c478bd9Sstevel@tonic-gate int cpuid, int verbose) 1707c478bd9Sstevel@tonic-gate { 1717c478bd9Sstevel@tonic-gate return (kmt_stack_common(addr, flags, argc, argv, cpuid, 1727c478bd9Sstevel@tonic-gate (verbose ? mdb_isa_kvm_framev : mdb_isa_kvm_frame))); 1737c478bd9Sstevel@tonic-gate } 1747c478bd9Sstevel@tonic-gate 1757c478bd9Sstevel@tonic-gate int 1767c478bd9Sstevel@tonic-gate kmt_stack(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1777c478bd9Sstevel@tonic-gate { 1787c478bd9Sstevel@tonic-gate return (kmt_stack_common(addr, flags, argc, argv, DPI_MASTER_CPUID, 1797c478bd9Sstevel@tonic-gate mdb_isa_kvm_frame)); 1807c478bd9Sstevel@tonic-gate } 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate int 1837c478bd9Sstevel@tonic-gate kmt_stackv(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1847c478bd9Sstevel@tonic-gate { 1857c478bd9Sstevel@tonic-gate return (kmt_stack_common(addr, flags, argc, argv, DPI_MASTER_CPUID, 1867c478bd9Sstevel@tonic-gate mdb_isa_kvm_framev)); 1877c478bd9Sstevel@tonic-gate } 1887c478bd9Sstevel@tonic-gate 1897c478bd9Sstevel@tonic-gate int 1907c478bd9Sstevel@tonic-gate kmt_stackr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1917c478bd9Sstevel@tonic-gate { 1927c478bd9Sstevel@tonic-gate return (kmt_stack_common(addr, flags, argc, argv, DPI_MASTER_CPUID, 1937c478bd9Sstevel@tonic-gate mdb_isa_kvm_framev)); 1947c478bd9Sstevel@tonic-gate } 1957c478bd9Sstevel@tonic-gate 1967c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1977c478bd9Sstevel@tonic-gate void 1987c478bd9Sstevel@tonic-gate kmt_printregs(const mdb_tgt_gregset_t *gregs) 1997c478bd9Sstevel@tonic-gate { 2007c478bd9Sstevel@tonic-gate mdb_isa_printregs(gregs); 2017c478bd9Sstevel@tonic-gate } 2027c478bd9Sstevel@tonic-gate 2037c478bd9Sstevel@tonic-gate #define IOCHECK_NOWARN 0 2047c478bd9Sstevel@tonic-gate #define IOCHECK_WARN 1 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate static int 2077c478bd9Sstevel@tonic-gate kmt_io_check(uint64_t nbytes, uintptr_t addr, int dowarn) 2087c478bd9Sstevel@tonic-gate { 2097c478bd9Sstevel@tonic-gate if (addr > IOPORTLIMIT) { 2107c478bd9Sstevel@tonic-gate if (dowarn) 2117c478bd9Sstevel@tonic-gate warn("port address must be 0-%#x\n", IOPORTLIMIT); 2127c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 2137c478bd9Sstevel@tonic-gate } 2147c478bd9Sstevel@tonic-gate 2157c478bd9Sstevel@tonic-gate if (nbytes != 1 && nbytes != 2 && nbytes != 4) { 2167c478bd9Sstevel@tonic-gate if (dowarn) 2177c478bd9Sstevel@tonic-gate warn("port access must be 1, 2, or 4 bytes\n"); 2187c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 2197c478bd9Sstevel@tonic-gate } 2207c478bd9Sstevel@tonic-gate 2217c478bd9Sstevel@tonic-gate if ((addr & (nbytes - 1)) != 0) { 2227c478bd9Sstevel@tonic-gate if (dowarn) { 2237c478bd9Sstevel@tonic-gate warn("address for %llu-byte access must be %llu-byte " 2247c478bd9Sstevel@tonic-gate "aligned\n", (u_longlong_t)nbytes, 2257c478bd9Sstevel@tonic-gate (u_longlong_t)nbytes); 2267c478bd9Sstevel@tonic-gate } 2277c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 2287c478bd9Sstevel@tonic-gate } 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate return (0); 2317c478bd9Sstevel@tonic-gate } 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate /*ARGSUSED1*/ 2347c478bd9Sstevel@tonic-gate int 2357c478bd9Sstevel@tonic-gate kmt_in_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2367c478bd9Sstevel@tonic-gate { 2377c478bd9Sstevel@tonic-gate uint64_t len = 0; 2387c478bd9Sstevel@tonic-gate uint32_t buf; 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate if (mdb_getopts(argc, argv, 2417c478bd9Sstevel@tonic-gate 'L', MDB_OPT_UINT64, &len, 2427c478bd9Sstevel@tonic-gate NULL) != argc) 2437c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate if (len == 0) 2467c478bd9Sstevel@tonic-gate len = mdb.m_dcount; 2477c478bd9Sstevel@tonic-gate 2487c478bd9Sstevel@tonic-gate if (kmt_io_check(len, addr, IOCHECK_WARN) < 0) 2497c478bd9Sstevel@tonic-gate return (DCMD_ERR); 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate if (mdb_tgt_ioread(mdb.m_target, &buf, len, addr) < 0) { 2527c478bd9Sstevel@tonic-gate warn("failed to read from port 0x%llx", (u_longlong_t)addr); 2537c478bd9Sstevel@tonic-gate return (DCMD_ERR); 2547c478bd9Sstevel@tonic-gate } 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate mdb_printf("%x\n", buf); 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate return (DCMD_OK); 2597c478bd9Sstevel@tonic-gate } 2607c478bd9Sstevel@tonic-gate 2617aec1d6eScindi static uint64_t 2627aec1d6eScindi kmt_numarg(const mdb_arg_t *arg) 2637aec1d6eScindi { 2647aec1d6eScindi if (arg->a_type == MDB_TYPE_STRING) 2657aec1d6eScindi return (mdb_strtoull(arg->a_un.a_str)); 2667aec1d6eScindi else 2677aec1d6eScindi return (arg->a_un.a_val); 2687aec1d6eScindi } 2697aec1d6eScindi 2707c478bd9Sstevel@tonic-gate /*ARGSUSED1*/ 2717c478bd9Sstevel@tonic-gate int 2727c478bd9Sstevel@tonic-gate kmt_out_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2737c478bd9Sstevel@tonic-gate { 2747c478bd9Sstevel@tonic-gate uint64_t len = 0; 2757c478bd9Sstevel@tonic-gate uint64_t val; 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate if (mdb_getopts(argc, argv, 2787c478bd9Sstevel@tonic-gate 'L', MDB_OPT_UINT64, &len, 2797c478bd9Sstevel@tonic-gate NULL) != argc - 1) 2807c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 2817c478bd9Sstevel@tonic-gate 2827c478bd9Sstevel@tonic-gate if (len == 0) 2837c478bd9Sstevel@tonic-gate len = mdb.m_dcount; 2847c478bd9Sstevel@tonic-gate 2857c478bd9Sstevel@tonic-gate argv += argc - 1; 2867aec1d6eScindi val = kmt_numarg(argv); 2877c478bd9Sstevel@tonic-gate 2887c478bd9Sstevel@tonic-gate if (kmt_io_check(len, addr, IOCHECK_WARN) < 0) 2897c478bd9Sstevel@tonic-gate return (DCMD_ERR); 2907c478bd9Sstevel@tonic-gate 2917c478bd9Sstevel@tonic-gate if (val > (1ULL << (len * NBBY)) - 1) { 2927c478bd9Sstevel@tonic-gate warn("value is out of range for port size\n"); 2937c478bd9Sstevel@tonic-gate return (DCMD_ERR); 2947c478bd9Sstevel@tonic-gate } 2957c478bd9Sstevel@tonic-gate 2967c478bd9Sstevel@tonic-gate if (mdb_tgt_iowrite(mdb.m_target, &val, len, addr) < 0) { 2977c478bd9Sstevel@tonic-gate warn("failed to write to port %llx", (u_longlong_t)addr); 2987c478bd9Sstevel@tonic-gate return (DCMD_ERR); 2997c478bd9Sstevel@tonic-gate } 3007c478bd9Sstevel@tonic-gate 3017c478bd9Sstevel@tonic-gate return (DCMD_OK); 3027c478bd9Sstevel@tonic-gate } 3037c478bd9Sstevel@tonic-gate 3047c478bd9Sstevel@tonic-gate static int 3057c478bd9Sstevel@tonic-gate kmt_rwmsr(uint32_t addr, uint64_t *valp, void (*rw)(uint32_t, uint64_t *)) 3067c478bd9Sstevel@tonic-gate { 3077c478bd9Sstevel@tonic-gate jmp_buf pcb, *oldpcb = NULL; 3087c478bd9Sstevel@tonic-gate 3097c478bd9Sstevel@tonic-gate if (setjmp(pcb) != 0) { 3107c478bd9Sstevel@tonic-gate kmdb_dpi_restore_fault_hdlr(oldpcb); 3117c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */ 3127c478bd9Sstevel@tonic-gate } 3137c478bd9Sstevel@tonic-gate 3147c478bd9Sstevel@tonic-gate oldpcb = kmdb_dpi_set_fault_hdlr(&pcb); 3157c478bd9Sstevel@tonic-gate rw(addr, valp); 3167c478bd9Sstevel@tonic-gate kmdb_dpi_restore_fault_hdlr(oldpcb); 3177c478bd9Sstevel@tonic-gate 3187c478bd9Sstevel@tonic-gate return (0); 3197c478bd9Sstevel@tonic-gate } 3207c478bd9Sstevel@tonic-gate 3217c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3227c478bd9Sstevel@tonic-gate int 3237c478bd9Sstevel@tonic-gate kmt_rdmsr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 3247c478bd9Sstevel@tonic-gate { 3257c478bd9Sstevel@tonic-gate uint64_t val; 3267c478bd9Sstevel@tonic-gate 3277c478bd9Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC)) 3287c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 3297c478bd9Sstevel@tonic-gate 3307c478bd9Sstevel@tonic-gate if (kmt_rwmsr(addr, &val, rdmsr) < 0) { 3317c478bd9Sstevel@tonic-gate warn("rdmsr failed"); 3327c478bd9Sstevel@tonic-gate return (DCMD_ERR); 3337c478bd9Sstevel@tonic-gate } 3347c478bd9Sstevel@tonic-gate 3357c478bd9Sstevel@tonic-gate mdb_printf("%llx\n", (u_longlong_t)val); 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate return (DCMD_OK); 3387c478bd9Sstevel@tonic-gate } 3397c478bd9Sstevel@tonic-gate 3407c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3417c478bd9Sstevel@tonic-gate int 3427c478bd9Sstevel@tonic-gate kmt_wrmsr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 3437c478bd9Sstevel@tonic-gate { 3447c478bd9Sstevel@tonic-gate uint64_t val; 3457c478bd9Sstevel@tonic-gate 3467c478bd9Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC) || argc != 1) 3477c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 3487c478bd9Sstevel@tonic-gate 3497aec1d6eScindi val = kmt_numarg(argv); 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate if (kmt_rwmsr(addr, &val, wrmsr)) { 3527c478bd9Sstevel@tonic-gate warn("wrmsr failed"); 3537c478bd9Sstevel@tonic-gate return (DCMD_ERR); 3547c478bd9Sstevel@tonic-gate } 3557c478bd9Sstevel@tonic-gate 3567c478bd9Sstevel@tonic-gate return (DCMD_OK); 3577c478bd9Sstevel@tonic-gate } 3587c478bd9Sstevel@tonic-gate 3597c478bd9Sstevel@tonic-gate int 360*ae115bc7Smrj kmt_msr_validate(const kdi_msr_t *msr) 3617c478bd9Sstevel@tonic-gate { 3627c478bd9Sstevel@tonic-gate uint64_t val; 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate for (/* */; msr->msr_num != 0; msr++) { 3657c478bd9Sstevel@tonic-gate if (kmt_rwmsr(msr->msr_num, &val, rdmsr) < 0) 3667c478bd9Sstevel@tonic-gate return (0); 3677c478bd9Sstevel@tonic-gate } 3687c478bd9Sstevel@tonic-gate 3697c478bd9Sstevel@tonic-gate return (1); 3707c478bd9Sstevel@tonic-gate } 3717c478bd9Sstevel@tonic-gate 3727c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3737c478bd9Sstevel@tonic-gate ssize_t 3747c478bd9Sstevel@tonic-gate kmt_write(mdb_tgt_t *t, const void *buf, size_t nbytes, uintptr_t addr) 3757c478bd9Sstevel@tonic-gate { 3767c478bd9Sstevel@tonic-gate if (!(t->t_flags & MDB_TGT_F_ALLOWIO) && 3777c478bd9Sstevel@tonic-gate (nbytes = kmdb_kdi_range_is_nontoxic(addr, nbytes, 1)) == 0) 3787c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOMAP)); 3797c478bd9Sstevel@tonic-gate 380f18fc278Sjohnlev /* 381f18fc278Sjohnlev * No writes to user space are allowed. If we were to allow it, we'd 382f18fc278Sjohnlev * be in the unfortunate situation where kmdb could place a breakpoint 383f18fc278Sjohnlev * on a userspace executable page; this dirty page would end up being 384f18fc278Sjohnlev * flushed back to disk, incurring sadness when it's next executed. 385f18fc278Sjohnlev * Besides, we can't allow trapping in from userspace anyway. 386f18fc278Sjohnlev */ 387f18fc278Sjohnlev if (addr < kmdb_kdi_get_userlimit()) 388f18fc278Sjohnlev return (set_errno(EMDB_TGTNOTSUP)); 389f18fc278Sjohnlev 3907c478bd9Sstevel@tonic-gate return (kmt_rw(t, (void *)buf, nbytes, addr, kmt_writer)); 3917c478bd9Sstevel@tonic-gate } 3927c478bd9Sstevel@tonic-gate 3937c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3947c478bd9Sstevel@tonic-gate static ssize_t 3957c478bd9Sstevel@tonic-gate kmt_iorw(mdb_tgt_t *t, void *buf, size_t nbytes, uint64_t addr, 3967c478bd9Sstevel@tonic-gate void (*iorw)(void *, size_t, uintptr_t)) 3977c478bd9Sstevel@tonic-gate { 3987c478bd9Sstevel@tonic-gate jmp_buf pcb, *oldpcb = NULL; 3997c478bd9Sstevel@tonic-gate 4007c478bd9Sstevel@tonic-gate if (kmt_io_check(nbytes, addr, IOCHECK_NOWARN) < 0) 4017c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */ 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate if (setjmp(pcb) != 0) { 4047c478bd9Sstevel@tonic-gate kmdb_dpi_restore_fault_hdlr(oldpcb); 4057c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */ 4067c478bd9Sstevel@tonic-gate } 4077c478bd9Sstevel@tonic-gate 4087c478bd9Sstevel@tonic-gate oldpcb = kmdb_dpi_set_fault_hdlr(&pcb); 4097c478bd9Sstevel@tonic-gate iorw(buf, nbytes, addr); 4107c478bd9Sstevel@tonic-gate kmdb_dpi_restore_fault_hdlr(oldpcb); 4117c478bd9Sstevel@tonic-gate 4127c478bd9Sstevel@tonic-gate return (nbytes); 4137c478bd9Sstevel@tonic-gate } 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4167c478bd9Sstevel@tonic-gate ssize_t 4177c478bd9Sstevel@tonic-gate kmt_ioread(mdb_tgt_t *t, void *buf, size_t nbytes, uintptr_t addr) 4187c478bd9Sstevel@tonic-gate { 4197c478bd9Sstevel@tonic-gate return (kmt_iorw(t, buf, nbytes, addr, kmt_in)); 4207c478bd9Sstevel@tonic-gate } 4217c478bd9Sstevel@tonic-gate 4227c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4237c478bd9Sstevel@tonic-gate ssize_t 4247c478bd9Sstevel@tonic-gate kmt_iowrite(mdb_tgt_t *t, const void *buf, size_t nbytes, uintptr_t addr) 4257c478bd9Sstevel@tonic-gate { 4267c478bd9Sstevel@tonic-gate return (kmt_iorw(t, (void *)buf, nbytes, addr, kmt_out)); 4277c478bd9Sstevel@tonic-gate } 4287c478bd9Sstevel@tonic-gate 4297aec1d6eScindi static int 4307aec1d6eScindi kmt_pcicfg_common(uintptr_t off, uint32_t *valp, const mdb_arg_t *argv, 4317aec1d6eScindi void (*rw)(void *, size_t, uintptr_t)) 4327aec1d6eScindi { 4337aec1d6eScindi uint32_t bus, dev, func; 4347aec1d6eScindi uint32_t addr; 4357aec1d6eScindi 4367aec1d6eScindi bus = kmt_numarg(&argv[0]); 4377aec1d6eScindi dev = kmt_numarg(&argv[1]); 4387aec1d6eScindi func = kmt_numarg(&argv[2]); 4397aec1d6eScindi 4407aec1d6eScindi if ((bus & 0xffff) != bus) { 4417aec1d6eScindi warn("invalid bus number (must be 0-0xffff)\n"); 4427aec1d6eScindi return (DCMD_ERR); 4437aec1d6eScindi } 4447aec1d6eScindi 4457aec1d6eScindi if ((dev & 0x1f) != dev) { 4467aec1d6eScindi warn("invalid device number (must be 0-0x1f)\n"); 4477aec1d6eScindi return (DCMD_ERR); 4487aec1d6eScindi } 4497aec1d6eScindi 4507aec1d6eScindi if ((func & 0x7) != func) { 4517aec1d6eScindi warn("invalid function number (must be 0-7)\n"); 4527aec1d6eScindi return (DCMD_ERR); 4537aec1d6eScindi } 4547aec1d6eScindi 4557aec1d6eScindi if ((off & 0xfc) != off) { 4567aec1d6eScindi warn("invalid register number (must be 0-0xff, and 4-byte " 4577aec1d6eScindi "aligned\n"); 4587aec1d6eScindi return (DCMD_ERR); 4597aec1d6eScindi } 4607aec1d6eScindi 4617aec1d6eScindi addr = PCI_CADDR1(bus, dev, func, off); 4627aec1d6eScindi 4637aec1d6eScindi if (kmt_iowrite(mdb.m_target, &addr, sizeof (addr), PCI_CONFADD) != 4647aec1d6eScindi sizeof (addr)) { 4657aec1d6eScindi warn("write of PCI_CONFADD failed"); 4667aec1d6eScindi return (DCMD_ERR); 4677aec1d6eScindi } 4687aec1d6eScindi 4697aec1d6eScindi if (kmt_iorw(mdb.m_target, valp, sizeof (*valp), PCI_CONFDATA, rw) != 4707aec1d6eScindi sizeof (*valp)) { 4717aec1d6eScindi warn("access to PCI_CONFDATA failed"); 4727aec1d6eScindi return (DCMD_ERR); 4737aec1d6eScindi } 4747aec1d6eScindi 4757aec1d6eScindi return (DCMD_OK); 4767aec1d6eScindi } 4777aec1d6eScindi 4787aec1d6eScindi /*ARGSUSED*/ 4797aec1d6eScindi int 4807aec1d6eScindi kmt_rdpcicfg(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 4817aec1d6eScindi { 4827aec1d6eScindi uint32_t val; 4837aec1d6eScindi 4847aec1d6eScindi if (argc != 3 || !(flags & DCMD_ADDRSPEC)) 4857aec1d6eScindi return (DCMD_USAGE); 4867aec1d6eScindi 4877aec1d6eScindi if (kmt_pcicfg_common(addr, &val, argv, kmt_in) != DCMD_OK) 4887aec1d6eScindi return (DCMD_ERR); 4897aec1d6eScindi 4907aec1d6eScindi mdb_printf("%llx\n", (u_longlong_t)val); 4917aec1d6eScindi 4927aec1d6eScindi return (DCMD_OK); 4937aec1d6eScindi } 4947aec1d6eScindi 4957aec1d6eScindi /*ARGSUSED*/ 4967aec1d6eScindi int 4977aec1d6eScindi kmt_wrpcicfg(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 4987aec1d6eScindi { 4997aec1d6eScindi uint32_t val; 5007aec1d6eScindi 5017aec1d6eScindi if (argc != 4 || !(flags & DCMD_ADDRSPEC)) 5027aec1d6eScindi return (DCMD_USAGE); 5037aec1d6eScindi 5047aec1d6eScindi val = (uint32_t)kmt_numarg(&argv[3]); 5057aec1d6eScindi 5067aec1d6eScindi if (kmt_pcicfg_common(addr, &val, argv, kmt_out) != DCMD_OK) 5077aec1d6eScindi return (DCMD_ERR); 5087aec1d6eScindi 5097aec1d6eScindi return (DCMD_OK); 5107aec1d6eScindi } 5117aec1d6eScindi 5127c478bd9Sstevel@tonic-gate const char * 5137c478bd9Sstevel@tonic-gate kmt_trapname(int trapnum) 5147c478bd9Sstevel@tonic-gate { 5157c478bd9Sstevel@tonic-gate static char trapname[11]; 5167c478bd9Sstevel@tonic-gate 5177c478bd9Sstevel@tonic-gate switch (trapnum) { 5187c478bd9Sstevel@tonic-gate case T_ZERODIV: 5197c478bd9Sstevel@tonic-gate return ("division by zero (#de) trap"); 5207c478bd9Sstevel@tonic-gate case T_SGLSTP: 5217c478bd9Sstevel@tonic-gate return ("single-step (#db) trap"); 5227c478bd9Sstevel@tonic-gate case T_NMIFLT: 5237c478bd9Sstevel@tonic-gate return ("NMI"); 5247c478bd9Sstevel@tonic-gate case T_BPTFLT: 5257c478bd9Sstevel@tonic-gate return ("breakpoint (#bp) trap"); 5267c478bd9Sstevel@tonic-gate case T_ILLINST: 5277c478bd9Sstevel@tonic-gate return ("illegal instruction (#ud) trap"); 5287c478bd9Sstevel@tonic-gate case T_SEGFLT: 5297c478bd9Sstevel@tonic-gate return ("segment not present (#np) trap"); 5307c478bd9Sstevel@tonic-gate case T_STKFLT: 5317c478bd9Sstevel@tonic-gate return ("stack (#ss) trap"); 5327c478bd9Sstevel@tonic-gate case T_GPFLT: 5337c478bd9Sstevel@tonic-gate return ("general protection (#gp) trap"); 5347c478bd9Sstevel@tonic-gate case T_PGFLT: 5357c478bd9Sstevel@tonic-gate return ("page fault (#pf) trap"); 5367c478bd9Sstevel@tonic-gate case T_ALIGNMENT: 5377c478bd9Sstevel@tonic-gate return ("alignment check (#ac) trap"); 5387c478bd9Sstevel@tonic-gate case T_MCE: 5397c478bd9Sstevel@tonic-gate return ("machine check (#mc) trap"); 5407c478bd9Sstevel@tonic-gate case T_SIMDFPE: 5417c478bd9Sstevel@tonic-gate return ("SSE/SSE2 (#xm) trap"); 5427c478bd9Sstevel@tonic-gate case T_DBGENTR: 5437c478bd9Sstevel@tonic-gate return ("debugger entry trap"); 5447c478bd9Sstevel@tonic-gate default: 5457c478bd9Sstevel@tonic-gate (void) mdb_snprintf(trapname, sizeof (trapname), "trap %#x", 5467c478bd9Sstevel@tonic-gate trapnum); 5477c478bd9Sstevel@tonic-gate return (trapname); 5487c478bd9Sstevel@tonic-gate } 5497c478bd9Sstevel@tonic-gate } 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate void 5527c478bd9Sstevel@tonic-gate kmt_init_isadep(mdb_tgt_t *t) 5537c478bd9Sstevel@tonic-gate { 5547c478bd9Sstevel@tonic-gate kmt_data_t *kmt = t->t_data; 5557c478bd9Sstevel@tonic-gate 5567c478bd9Sstevel@tonic-gate kmt->kmt_rds = mdb_isa_kregs; 5577c478bd9Sstevel@tonic-gate 5587c478bd9Sstevel@tonic-gate kmt->kmt_trapmax = KMT_MAXTRAPNO; 5597c478bd9Sstevel@tonic-gate kmt->kmt_trapmap = mdb_zalloc(BT_SIZEOFMAP(kmt->kmt_trapmax), UM_SLEEP); 5607c478bd9Sstevel@tonic-gate 5617c478bd9Sstevel@tonic-gate /* Traps for which we want to provide an explicit message */ 5627c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_fault(t, T_ZERODIV, MDB_TGT_SPEC_INTERNAL, 5637c478bd9Sstevel@tonic-gate no_se_f, NULL); 5647c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_fault(t, T_ILLINST, MDB_TGT_SPEC_INTERNAL, 5657c478bd9Sstevel@tonic-gate no_se_f, NULL); 5667c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_fault(t, T_SEGFLT, MDB_TGT_SPEC_INTERNAL, 5677c478bd9Sstevel@tonic-gate no_se_f, NULL); 5687c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_fault(t, T_STKFLT, MDB_TGT_SPEC_INTERNAL, 5697c478bd9Sstevel@tonic-gate no_se_f, NULL); 5707c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_fault(t, T_GPFLT, MDB_TGT_SPEC_INTERNAL, 5717c478bd9Sstevel@tonic-gate no_se_f, NULL); 5727c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_fault(t, T_PGFLT, MDB_TGT_SPEC_INTERNAL, 5737c478bd9Sstevel@tonic-gate no_se_f, NULL); 5747c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_fault(t, T_ALIGNMENT, MDB_TGT_SPEC_INTERNAL, 5757c478bd9Sstevel@tonic-gate no_se_f, NULL); 5767c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_fault(t, T_MCE, MDB_TGT_SPEC_INTERNAL, 5777c478bd9Sstevel@tonic-gate no_se_f, NULL); 5787c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_fault(t, T_SIMDFPE, MDB_TGT_SPEC_INTERNAL, 5797c478bd9Sstevel@tonic-gate no_se_f, NULL); 5807c478bd9Sstevel@tonic-gate 5817c478bd9Sstevel@tonic-gate /* 5827c478bd9Sstevel@tonic-gate * Traps which will be handled elsewhere, and which therefore don't 5837c478bd9Sstevel@tonic-gate * need the trap-based message. 5847c478bd9Sstevel@tonic-gate */ 5857c478bd9Sstevel@tonic-gate BT_SET(kmt->kmt_trapmap, T_SGLSTP); 5867c478bd9Sstevel@tonic-gate BT_SET(kmt->kmt_trapmap, T_BPTFLT); 5877c478bd9Sstevel@tonic-gate BT_SET(kmt->kmt_trapmap, T_DBGENTR); 5887c478bd9Sstevel@tonic-gate 5897c478bd9Sstevel@tonic-gate /* Catch-all for traps not explicitly listed here */ 5907c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_fault(t, KMT_TRAP_NOTENUM, MDB_TGT_SPEC_INTERNAL, 5917c478bd9Sstevel@tonic-gate no_se_f, NULL); 5927c478bd9Sstevel@tonic-gate } 5937c478bd9Sstevel@tonic-gate 5947c478bd9Sstevel@tonic-gate void 5957c478bd9Sstevel@tonic-gate kmt_startup_isadep(mdb_tgt_t *t) 5967c478bd9Sstevel@tonic-gate { 5977c478bd9Sstevel@tonic-gate kmt_data_t *kmt = t->t_data; 5987c478bd9Sstevel@tonic-gate 5997c478bd9Sstevel@tonic-gate /* 6007c478bd9Sstevel@tonic-gate * The stack trace and ::step out code need to detect "interrupt" 6017c478bd9Sstevel@tonic-gate * frames. The heuristic they use to detect said frames requires the 6027c478bd9Sstevel@tonic-gate * addresses of routines that can generate them. 6037c478bd9Sstevel@tonic-gate */ 6047c478bd9Sstevel@tonic-gate (void) mdb_tgt_lookup_by_name(t, MDB_TGT_OBJ_EXEC, 6057c478bd9Sstevel@tonic-gate "cmnint", &kmt->kmt_intrsyms._kmt_cmnint, NULL); 6067c478bd9Sstevel@tonic-gate (void) mdb_tgt_lookup_by_name(t, MDB_TGT_OBJ_EXEC, 6077c478bd9Sstevel@tonic-gate "cmntrap", &kmt->kmt_intrsyms._kmt_cmntrap, NULL); 6087c478bd9Sstevel@tonic-gate (void) mdb_tgt_lookup_by_name(t, MDB_TGT_OBJ_EXEC, 6097c478bd9Sstevel@tonic-gate "sys_sysenter", &kmt->kmt_intrsyms._kmt_sysenter, NULL); 6109acbbeafSnn35248 (void) mdb_tgt_lookup_by_name(t, MDB_TGT_OBJ_EXEC, 6119acbbeafSnn35248 "brand_sys_sysenter", &kmt->kmt_intrsyms._kmt_brand_sysenter, NULL); 6127c478bd9Sstevel@tonic-gate #if defined(__amd64) 6137c478bd9Sstevel@tonic-gate (void) mdb_tgt_lookup_by_name(t, MDB_TGT_OBJ_EXEC, 6147c478bd9Sstevel@tonic-gate "sys_syscall", &kmt->kmt_intrsyms._kmt_syscall, NULL); 6159acbbeafSnn35248 (void) mdb_tgt_lookup_by_name(t, MDB_TGT_OBJ_EXEC, 6169acbbeafSnn35248 "brand_sys_syscall", &kmt->kmt_intrsyms._kmt_brand_syscall, NULL); 6177c478bd9Sstevel@tonic-gate #endif 6187c478bd9Sstevel@tonic-gate } 619