10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
51530Sjohnlev * Common Development and Distribution License (the "License").
61530Sjohnlev * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*3446Smrj * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
270Sstevel@tonic-gate
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate * isa-dependent portions of the kmdb target
300Sstevel@tonic-gate */
310Sstevel@tonic-gate
320Sstevel@tonic-gate #include <kmdb/kvm.h>
330Sstevel@tonic-gate #include <kmdb/kvm_cpu.h>
340Sstevel@tonic-gate #include <kmdb/kmdb_kdi.h>
350Sstevel@tonic-gate #include <kmdb/kmdb_asmutil.h>
360Sstevel@tonic-gate #include <mdb/mdb_debug.h>
370Sstevel@tonic-gate #include <mdb/mdb_err.h>
380Sstevel@tonic-gate #include <mdb/mdb_list.h>
390Sstevel@tonic-gate #include <mdb/mdb_target_impl.h>
400Sstevel@tonic-gate #include <mdb/mdb_isautil.h>
410Sstevel@tonic-gate #include <mdb/mdb_kreg_impl.h>
420Sstevel@tonic-gate #include <mdb/mdb.h>
430Sstevel@tonic-gate
440Sstevel@tonic-gate #include <sys/types.h>
450Sstevel@tonic-gate #include <sys/frame.h>
460Sstevel@tonic-gate #include <sys/trap.h>
470Sstevel@tonic-gate #include <sys/bitmap.h>
481414Scindi #include <sys/pci_impl.h>
490Sstevel@tonic-gate
500Sstevel@tonic-gate /* Higher than the highest trap number for which we have a defined specifier */
510Sstevel@tonic-gate #define KMT_MAXTRAPNO 0x20
520Sstevel@tonic-gate
530Sstevel@tonic-gate #define IOPORTLIMIT 0xffff /* XXX find a new home for this */
540Sstevel@tonic-gate
550Sstevel@tonic-gate const char *
kmt_def_dismode(void)560Sstevel@tonic-gate kmt_def_dismode(void)
570Sstevel@tonic-gate {
580Sstevel@tonic-gate #ifdef __amd64
590Sstevel@tonic-gate return ("amd64");
600Sstevel@tonic-gate #else
610Sstevel@tonic-gate return ("ia32");
620Sstevel@tonic-gate #endif
630Sstevel@tonic-gate }
640Sstevel@tonic-gate
650Sstevel@tonic-gate int
kmt_step_out_validate(mdb_tgt_t * t,uintptr_t pc)660Sstevel@tonic-gate kmt_step_out_validate(mdb_tgt_t *t, uintptr_t pc)
670Sstevel@tonic-gate {
680Sstevel@tonic-gate kmt_data_t *kmt = t->t_data;
690Sstevel@tonic-gate int i;
700Sstevel@tonic-gate
710Sstevel@tonic-gate for (i = 0; i < sizeof (kmt->kmt_intrsyms) / sizeof (GElf_Sym); i++) {
720Sstevel@tonic-gate GElf_Sym *sym = (GElf_Sym *)&kmt->kmt_intrsyms + i;
730Sstevel@tonic-gate
740Sstevel@tonic-gate if (pc >= sym->st_value && pc < sym->st_value + sym->st_size)
750Sstevel@tonic-gate return (0);
760Sstevel@tonic-gate }
770Sstevel@tonic-gate
780Sstevel@tonic-gate return (1);
790Sstevel@tonic-gate }
800Sstevel@tonic-gate
810Sstevel@tonic-gate /*
820Sstevel@tonic-gate * Determine the return address for the current frame.
830Sstevel@tonic-gate */
840Sstevel@tonic-gate int
kmt_step_out(mdb_tgt_t * t,uintptr_t * p)850Sstevel@tonic-gate kmt_step_out(mdb_tgt_t *t, uintptr_t *p)
860Sstevel@tonic-gate {
870Sstevel@tonic-gate mdb_instr_t instr;
880Sstevel@tonic-gate kreg_t pc, sp, fp;
890Sstevel@tonic-gate
900Sstevel@tonic-gate (void) kmdb_dpi_get_register("pc", &pc);
910Sstevel@tonic-gate (void) kmdb_dpi_get_register("sp", &sp);
920Sstevel@tonic-gate (void) kmdb_dpi_get_register("fp", &fp);
930Sstevel@tonic-gate
940Sstevel@tonic-gate if (mdb_tgt_vread(t, &instr, sizeof (mdb_instr_t), pc) !=
950Sstevel@tonic-gate sizeof (mdb_instr_t))
960Sstevel@tonic-gate return (-1); /* errno is set for us */
970Sstevel@tonic-gate
980Sstevel@tonic-gate if (!kmt_step_out_validate(t, pc))
990Sstevel@tonic-gate return (set_errno(EMDB_TGTNOTSUP));
1000Sstevel@tonic-gate
1010Sstevel@tonic-gate return (mdb_isa_step_out(t, p, pc, fp, sp, instr));
1020Sstevel@tonic-gate }
1030Sstevel@tonic-gate
1040Sstevel@tonic-gate int
kmt_step_branch(mdb_tgt_t * t)1050Sstevel@tonic-gate kmt_step_branch(mdb_tgt_t *t)
1060Sstevel@tonic-gate {
1070Sstevel@tonic-gate kmt_data_t *kmt = t->t_data;
1080Sstevel@tonic-gate
1090Sstevel@tonic-gate return (kmt_cpu_step_branch(t, kmt->kmt_cpu));
1100Sstevel@tonic-gate }
1110Sstevel@tonic-gate
1120Sstevel@tonic-gate /*
1130Sstevel@tonic-gate * Return the address of the next instruction following a call, or return -1
1140Sstevel@tonic-gate * and set errno to EAGAIN if the target should just single-step.
1150Sstevel@tonic-gate */
1160Sstevel@tonic-gate int
kmt_next(mdb_tgt_t * t,uintptr_t * p)1170Sstevel@tonic-gate kmt_next(mdb_tgt_t *t, uintptr_t *p)
1180Sstevel@tonic-gate {
1190Sstevel@tonic-gate kreg_t pc;
1200Sstevel@tonic-gate mdb_instr_t instr;
1210Sstevel@tonic-gate
1220Sstevel@tonic-gate (void) kmdb_dpi_get_register("pc", &pc);
1230Sstevel@tonic-gate
1240Sstevel@tonic-gate if (mdb_tgt_vread(t, &instr, sizeof (mdb_instr_t), pc) !=
1250Sstevel@tonic-gate sizeof (mdb_instr_t))
1260Sstevel@tonic-gate return (-1); /* errno is set for us */
1270Sstevel@tonic-gate
1280Sstevel@tonic-gate return (mdb_isa_next(t, p, pc, instr));
1290Sstevel@tonic-gate }
1300Sstevel@tonic-gate
1310Sstevel@tonic-gate /*ARGSUSED*/
1320Sstevel@tonic-gate static int
kmt_stack_common(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv,int cpuid,mdb_tgt_stack_f * func)1330Sstevel@tonic-gate kmt_stack_common(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv,
1340Sstevel@tonic-gate int cpuid, mdb_tgt_stack_f *func)
1350Sstevel@tonic-gate {
1360Sstevel@tonic-gate const mdb_tgt_gregset_t *grp = NULL;
1370Sstevel@tonic-gate mdb_tgt_gregset_t gregs;
1380Sstevel@tonic-gate void *arg = (void *)(uintptr_t)mdb.m_nargs;
1390Sstevel@tonic-gate
1400Sstevel@tonic-gate if (flags & DCMD_ADDRSPEC) {
1410Sstevel@tonic-gate bzero(&gregs, sizeof (gregs));
1420Sstevel@tonic-gate gregs.kregs[KREG_FP] = addr;
1430Sstevel@tonic-gate grp = &gregs;
1440Sstevel@tonic-gate } else
1450Sstevel@tonic-gate grp = kmdb_dpi_get_gregs(cpuid);
1460Sstevel@tonic-gate
1471234Sjohnlev if (grp == NULL) {
1481234Sjohnlev warn("failed to retrieve registers for cpu %d", cpuid);
1491234Sjohnlev return (DCMD_ERR);
1501234Sjohnlev }
1511234Sjohnlev
1520Sstevel@tonic-gate if (argc != 0) {
1530Sstevel@tonic-gate if (argv->a_type == MDB_TYPE_CHAR || argc > 1)
1540Sstevel@tonic-gate return (DCMD_USAGE);
1550Sstevel@tonic-gate
1560Sstevel@tonic-gate if (argv->a_type == MDB_TYPE_STRING)
1570Sstevel@tonic-gate arg = (void *)(uintptr_t)mdb_strtoull(argv->a_un.a_str);
1580Sstevel@tonic-gate else
1590Sstevel@tonic-gate arg = (void *)(uintptr_t)argv->a_un.a_val;
1600Sstevel@tonic-gate }
1610Sstevel@tonic-gate
1620Sstevel@tonic-gate (void) mdb_isa_kvm_stack_iter(mdb.m_target, grp, func, arg);
1630Sstevel@tonic-gate
1640Sstevel@tonic-gate return (DCMD_OK);
1650Sstevel@tonic-gate }
1660Sstevel@tonic-gate
1670Sstevel@tonic-gate int
kmt_cpustack(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv,int cpuid,int verbose)1680Sstevel@tonic-gate kmt_cpustack(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv,
1690Sstevel@tonic-gate int cpuid, int verbose)
1700Sstevel@tonic-gate {
1710Sstevel@tonic-gate return (kmt_stack_common(addr, flags, argc, argv, cpuid,
1720Sstevel@tonic-gate (verbose ? mdb_isa_kvm_framev : mdb_isa_kvm_frame)));
1730Sstevel@tonic-gate }
1740Sstevel@tonic-gate
1750Sstevel@tonic-gate int
kmt_stack(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)1760Sstevel@tonic-gate kmt_stack(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1770Sstevel@tonic-gate {
1780Sstevel@tonic-gate return (kmt_stack_common(addr, flags, argc, argv, DPI_MASTER_CPUID,
1790Sstevel@tonic-gate mdb_isa_kvm_frame));
1800Sstevel@tonic-gate }
1810Sstevel@tonic-gate
1820Sstevel@tonic-gate int
kmt_stackv(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)1830Sstevel@tonic-gate kmt_stackv(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1840Sstevel@tonic-gate {
1850Sstevel@tonic-gate return (kmt_stack_common(addr, flags, argc, argv, DPI_MASTER_CPUID,
1860Sstevel@tonic-gate mdb_isa_kvm_framev));
1870Sstevel@tonic-gate }
1880Sstevel@tonic-gate
1890Sstevel@tonic-gate int
kmt_stackr(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)1900Sstevel@tonic-gate kmt_stackr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1910Sstevel@tonic-gate {
1920Sstevel@tonic-gate return (kmt_stack_common(addr, flags, argc, argv, DPI_MASTER_CPUID,
1930Sstevel@tonic-gate mdb_isa_kvm_framev));
1940Sstevel@tonic-gate }
1950Sstevel@tonic-gate
1960Sstevel@tonic-gate /*ARGSUSED*/
1970Sstevel@tonic-gate void
kmt_printregs(const mdb_tgt_gregset_t * gregs)1980Sstevel@tonic-gate kmt_printregs(const mdb_tgt_gregset_t *gregs)
1990Sstevel@tonic-gate {
2000Sstevel@tonic-gate mdb_isa_printregs(gregs);
2010Sstevel@tonic-gate }
2020Sstevel@tonic-gate
2030Sstevel@tonic-gate #define IOCHECK_NOWARN 0
2040Sstevel@tonic-gate #define IOCHECK_WARN 1
2050Sstevel@tonic-gate
2060Sstevel@tonic-gate static int
kmt_io_check(uint64_t nbytes,uintptr_t addr,int dowarn)2070Sstevel@tonic-gate kmt_io_check(uint64_t nbytes, uintptr_t addr, int dowarn)
2080Sstevel@tonic-gate {
2090Sstevel@tonic-gate if (addr > IOPORTLIMIT) {
2100Sstevel@tonic-gate if (dowarn)
2110Sstevel@tonic-gate warn("port address must be 0-%#x\n", IOPORTLIMIT);
2120Sstevel@tonic-gate return (set_errno(EINVAL));
2130Sstevel@tonic-gate }
2140Sstevel@tonic-gate
2150Sstevel@tonic-gate if (nbytes != 1 && nbytes != 2 && nbytes != 4) {
2160Sstevel@tonic-gate if (dowarn)
2170Sstevel@tonic-gate warn("port access must be 1, 2, or 4 bytes\n");
2180Sstevel@tonic-gate return (set_errno(EINVAL));
2190Sstevel@tonic-gate }
2200Sstevel@tonic-gate
2210Sstevel@tonic-gate if ((addr & (nbytes - 1)) != 0) {
2220Sstevel@tonic-gate if (dowarn) {
2230Sstevel@tonic-gate warn("address for %llu-byte access must be %llu-byte "
2240Sstevel@tonic-gate "aligned\n", (u_longlong_t)nbytes,
2250Sstevel@tonic-gate (u_longlong_t)nbytes);
2260Sstevel@tonic-gate }
2270Sstevel@tonic-gate return (set_errno(EINVAL));
2280Sstevel@tonic-gate }
2290Sstevel@tonic-gate
2300Sstevel@tonic-gate return (0);
2310Sstevel@tonic-gate }
2320Sstevel@tonic-gate
2330Sstevel@tonic-gate /*ARGSUSED1*/
2340Sstevel@tonic-gate int
kmt_in_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)2350Sstevel@tonic-gate kmt_in_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2360Sstevel@tonic-gate {
2370Sstevel@tonic-gate uint64_t len = 0;
2380Sstevel@tonic-gate uint32_t buf;
2390Sstevel@tonic-gate
2400Sstevel@tonic-gate if (mdb_getopts(argc, argv,
2410Sstevel@tonic-gate 'L', MDB_OPT_UINT64, &len,
2420Sstevel@tonic-gate NULL) != argc)
2430Sstevel@tonic-gate return (DCMD_USAGE);
2440Sstevel@tonic-gate
2450Sstevel@tonic-gate if (len == 0)
2460Sstevel@tonic-gate len = mdb.m_dcount;
2470Sstevel@tonic-gate
2480Sstevel@tonic-gate if (kmt_io_check(len, addr, IOCHECK_WARN) < 0)
2490Sstevel@tonic-gate return (DCMD_ERR);
2500Sstevel@tonic-gate
2510Sstevel@tonic-gate if (mdb_tgt_ioread(mdb.m_target, &buf, len, addr) < 0) {
2520Sstevel@tonic-gate warn("failed to read from port 0x%llx", (u_longlong_t)addr);
2530Sstevel@tonic-gate return (DCMD_ERR);
2540Sstevel@tonic-gate }
2550Sstevel@tonic-gate
2560Sstevel@tonic-gate mdb_printf("%x\n", buf);
2570Sstevel@tonic-gate
2580Sstevel@tonic-gate return (DCMD_OK);
2590Sstevel@tonic-gate }
2600Sstevel@tonic-gate
2611414Scindi static uint64_t
kmt_numarg(const mdb_arg_t * arg)2621414Scindi kmt_numarg(const mdb_arg_t *arg)
2631414Scindi {
2641414Scindi if (arg->a_type == MDB_TYPE_STRING)
2651414Scindi return (mdb_strtoull(arg->a_un.a_str));
2661414Scindi else
2671414Scindi return (arg->a_un.a_val);
2681414Scindi }
2691414Scindi
2700Sstevel@tonic-gate /*ARGSUSED1*/
2710Sstevel@tonic-gate int
kmt_out_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)2720Sstevel@tonic-gate kmt_out_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2730Sstevel@tonic-gate {
2740Sstevel@tonic-gate uint64_t len = 0;
2750Sstevel@tonic-gate uint64_t val;
2760Sstevel@tonic-gate
2770Sstevel@tonic-gate if (mdb_getopts(argc, argv,
2780Sstevel@tonic-gate 'L', MDB_OPT_UINT64, &len,
2790Sstevel@tonic-gate NULL) != argc - 1)
2800Sstevel@tonic-gate return (DCMD_USAGE);
2810Sstevel@tonic-gate
2820Sstevel@tonic-gate if (len == 0)
2830Sstevel@tonic-gate len = mdb.m_dcount;
2840Sstevel@tonic-gate
2850Sstevel@tonic-gate argv += argc - 1;
2861414Scindi val = kmt_numarg(argv);
2870Sstevel@tonic-gate
2880Sstevel@tonic-gate if (kmt_io_check(len, addr, IOCHECK_WARN) < 0)
2890Sstevel@tonic-gate return (DCMD_ERR);
2900Sstevel@tonic-gate
2910Sstevel@tonic-gate if (val > (1ULL << (len * NBBY)) - 1) {
2920Sstevel@tonic-gate warn("value is out of range for port size\n");
2930Sstevel@tonic-gate return (DCMD_ERR);
2940Sstevel@tonic-gate }
2950Sstevel@tonic-gate
2960Sstevel@tonic-gate if (mdb_tgt_iowrite(mdb.m_target, &val, len, addr) < 0) {
2970Sstevel@tonic-gate warn("failed to write to port %llx", (u_longlong_t)addr);
2980Sstevel@tonic-gate return (DCMD_ERR);
2990Sstevel@tonic-gate }
3000Sstevel@tonic-gate
3010Sstevel@tonic-gate return (DCMD_OK);
3020Sstevel@tonic-gate }
3030Sstevel@tonic-gate
3040Sstevel@tonic-gate static int
kmt_rwmsr(uint32_t addr,uint64_t * valp,void (* rw)(uint32_t,uint64_t *))3050Sstevel@tonic-gate kmt_rwmsr(uint32_t addr, uint64_t *valp, void (*rw)(uint32_t, uint64_t *))
3060Sstevel@tonic-gate {
3070Sstevel@tonic-gate jmp_buf pcb, *oldpcb = NULL;
3080Sstevel@tonic-gate
3090Sstevel@tonic-gate if (setjmp(pcb) != 0) {
3100Sstevel@tonic-gate kmdb_dpi_restore_fault_hdlr(oldpcb);
3110Sstevel@tonic-gate return (-1); /* errno is set for us */
3120Sstevel@tonic-gate }
3130Sstevel@tonic-gate
3140Sstevel@tonic-gate oldpcb = kmdb_dpi_set_fault_hdlr(&pcb);
3150Sstevel@tonic-gate rw(addr, valp);
3160Sstevel@tonic-gate kmdb_dpi_restore_fault_hdlr(oldpcb);
3170Sstevel@tonic-gate
3180Sstevel@tonic-gate return (0);
3190Sstevel@tonic-gate }
3200Sstevel@tonic-gate
3210Sstevel@tonic-gate /*ARGSUSED*/
3220Sstevel@tonic-gate int
kmt_rdmsr(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)3230Sstevel@tonic-gate kmt_rdmsr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
3240Sstevel@tonic-gate {
3250Sstevel@tonic-gate uint64_t val;
3260Sstevel@tonic-gate
3270Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC))
3280Sstevel@tonic-gate return (DCMD_USAGE);
3290Sstevel@tonic-gate
3300Sstevel@tonic-gate if (kmt_rwmsr(addr, &val, rdmsr) < 0) {
3310Sstevel@tonic-gate warn("rdmsr failed");
3320Sstevel@tonic-gate return (DCMD_ERR);
3330Sstevel@tonic-gate }
3340Sstevel@tonic-gate
3350Sstevel@tonic-gate mdb_printf("%llx\n", (u_longlong_t)val);
3360Sstevel@tonic-gate
3370Sstevel@tonic-gate return (DCMD_OK);
3380Sstevel@tonic-gate }
3390Sstevel@tonic-gate
3400Sstevel@tonic-gate /*ARGSUSED*/
3410Sstevel@tonic-gate int
kmt_wrmsr(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)3420Sstevel@tonic-gate kmt_wrmsr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
3430Sstevel@tonic-gate {
3440Sstevel@tonic-gate uint64_t val;
3450Sstevel@tonic-gate
3460Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC) || argc != 1)
3470Sstevel@tonic-gate return (DCMD_USAGE);
3480Sstevel@tonic-gate
3491414Scindi val = kmt_numarg(argv);
3500Sstevel@tonic-gate
3510Sstevel@tonic-gate if (kmt_rwmsr(addr, &val, wrmsr)) {
3520Sstevel@tonic-gate warn("wrmsr failed");
3530Sstevel@tonic-gate return (DCMD_ERR);
3540Sstevel@tonic-gate }
3550Sstevel@tonic-gate
3560Sstevel@tonic-gate return (DCMD_OK);
3570Sstevel@tonic-gate }
3580Sstevel@tonic-gate
3590Sstevel@tonic-gate int
kmt_msr_validate(const kdi_msr_t * msr)360*3446Smrj kmt_msr_validate(const kdi_msr_t *msr)
3610Sstevel@tonic-gate {
3620Sstevel@tonic-gate uint64_t val;
3630Sstevel@tonic-gate
3640Sstevel@tonic-gate for (/* */; msr->msr_num != 0; msr++) {
3650Sstevel@tonic-gate if (kmt_rwmsr(msr->msr_num, &val, rdmsr) < 0)
3660Sstevel@tonic-gate return (0);
3670Sstevel@tonic-gate }
3680Sstevel@tonic-gate
3690Sstevel@tonic-gate return (1);
3700Sstevel@tonic-gate }
3710Sstevel@tonic-gate
3720Sstevel@tonic-gate /*ARGSUSED*/
3730Sstevel@tonic-gate ssize_t
kmt_write(mdb_tgt_t * t,const void * buf,size_t nbytes,uintptr_t addr)3740Sstevel@tonic-gate kmt_write(mdb_tgt_t *t, const void *buf, size_t nbytes, uintptr_t addr)
3750Sstevel@tonic-gate {
3760Sstevel@tonic-gate if (!(t->t_flags & MDB_TGT_F_ALLOWIO) &&
3770Sstevel@tonic-gate (nbytes = kmdb_kdi_range_is_nontoxic(addr, nbytes, 1)) == 0)
3780Sstevel@tonic-gate return (set_errno(EMDB_NOMAP));
3790Sstevel@tonic-gate
3801530Sjohnlev /*
3811530Sjohnlev * No writes to user space are allowed. If we were to allow it, we'd
3821530Sjohnlev * be in the unfortunate situation where kmdb could place a breakpoint
3831530Sjohnlev * on a userspace executable page; this dirty page would end up being
3841530Sjohnlev * flushed back to disk, incurring sadness when it's next executed.
3851530Sjohnlev * Besides, we can't allow trapping in from userspace anyway.
3861530Sjohnlev */
3871530Sjohnlev if (addr < kmdb_kdi_get_userlimit())
3881530Sjohnlev return (set_errno(EMDB_TGTNOTSUP));
3891530Sjohnlev
3900Sstevel@tonic-gate return (kmt_rw(t, (void *)buf, nbytes, addr, kmt_writer));
3910Sstevel@tonic-gate }
3920Sstevel@tonic-gate
3930Sstevel@tonic-gate /*ARGSUSED*/
3940Sstevel@tonic-gate static ssize_t
kmt_iorw(mdb_tgt_t * t,void * buf,size_t nbytes,uint64_t addr,void (* iorw)(void *,size_t,uintptr_t))3950Sstevel@tonic-gate kmt_iorw(mdb_tgt_t *t, void *buf, size_t nbytes, uint64_t addr,
3960Sstevel@tonic-gate void (*iorw)(void *, size_t, uintptr_t))
3970Sstevel@tonic-gate {
3980Sstevel@tonic-gate jmp_buf pcb, *oldpcb = NULL;
3990Sstevel@tonic-gate
4000Sstevel@tonic-gate if (kmt_io_check(nbytes, addr, IOCHECK_NOWARN) < 0)
4010Sstevel@tonic-gate return (-1); /* errno is set for us */
4020Sstevel@tonic-gate
4030Sstevel@tonic-gate if (setjmp(pcb) != 0) {
4040Sstevel@tonic-gate kmdb_dpi_restore_fault_hdlr(oldpcb);
4050Sstevel@tonic-gate return (-1); /* errno is set for us */
4060Sstevel@tonic-gate }
4070Sstevel@tonic-gate
4080Sstevel@tonic-gate oldpcb = kmdb_dpi_set_fault_hdlr(&pcb);
4090Sstevel@tonic-gate iorw(buf, nbytes, addr);
4100Sstevel@tonic-gate kmdb_dpi_restore_fault_hdlr(oldpcb);
4110Sstevel@tonic-gate
4120Sstevel@tonic-gate return (nbytes);
4130Sstevel@tonic-gate }
4140Sstevel@tonic-gate
4150Sstevel@tonic-gate /*ARGSUSED*/
4160Sstevel@tonic-gate ssize_t
kmt_ioread(mdb_tgt_t * t,void * buf,size_t nbytes,uintptr_t addr)4170Sstevel@tonic-gate kmt_ioread(mdb_tgt_t *t, void *buf, size_t nbytes, uintptr_t addr)
4180Sstevel@tonic-gate {
4190Sstevel@tonic-gate return (kmt_iorw(t, buf, nbytes, addr, kmt_in));
4200Sstevel@tonic-gate }
4210Sstevel@tonic-gate
4220Sstevel@tonic-gate /*ARGSUSED*/
4230Sstevel@tonic-gate ssize_t
kmt_iowrite(mdb_tgt_t * t,const void * buf,size_t nbytes,uintptr_t addr)4240Sstevel@tonic-gate kmt_iowrite(mdb_tgt_t *t, const void *buf, size_t nbytes, uintptr_t addr)
4250Sstevel@tonic-gate {
4260Sstevel@tonic-gate return (kmt_iorw(t, (void *)buf, nbytes, addr, kmt_out));
4270Sstevel@tonic-gate }
4280Sstevel@tonic-gate
4291414Scindi static int
kmt_pcicfg_common(uintptr_t off,uint32_t * valp,const mdb_arg_t * argv,void (* rw)(void *,size_t,uintptr_t))4301414Scindi kmt_pcicfg_common(uintptr_t off, uint32_t *valp, const mdb_arg_t *argv,
4311414Scindi void (*rw)(void *, size_t, uintptr_t))
4321414Scindi {
4331414Scindi uint32_t bus, dev, func;
4341414Scindi uint32_t addr;
4351414Scindi
4361414Scindi bus = kmt_numarg(&argv[0]);
4371414Scindi dev = kmt_numarg(&argv[1]);
4381414Scindi func = kmt_numarg(&argv[2]);
4391414Scindi
4401414Scindi if ((bus & 0xffff) != bus) {
4411414Scindi warn("invalid bus number (must be 0-0xffff)\n");
4421414Scindi return (DCMD_ERR);
4431414Scindi }
4441414Scindi
4451414Scindi if ((dev & 0x1f) != dev) {
4461414Scindi warn("invalid device number (must be 0-0x1f)\n");
4471414Scindi return (DCMD_ERR);
4481414Scindi }
4491414Scindi
4501414Scindi if ((func & 0x7) != func) {
4511414Scindi warn("invalid function number (must be 0-7)\n");
4521414Scindi return (DCMD_ERR);
4531414Scindi }
4541414Scindi
4551414Scindi if ((off & 0xfc) != off) {
4561414Scindi warn("invalid register number (must be 0-0xff, and 4-byte "
4571414Scindi "aligned\n");
4581414Scindi return (DCMD_ERR);
4591414Scindi }
4601414Scindi
4611414Scindi addr = PCI_CADDR1(bus, dev, func, off);
4621414Scindi
4631414Scindi if (kmt_iowrite(mdb.m_target, &addr, sizeof (addr), PCI_CONFADD) !=
4641414Scindi sizeof (addr)) {
4651414Scindi warn("write of PCI_CONFADD failed");
4661414Scindi return (DCMD_ERR);
4671414Scindi }
4681414Scindi
4691414Scindi if (kmt_iorw(mdb.m_target, valp, sizeof (*valp), PCI_CONFDATA, rw) !=
4701414Scindi sizeof (*valp)) {
4711414Scindi warn("access to PCI_CONFDATA failed");
4721414Scindi return (DCMD_ERR);
4731414Scindi }
4741414Scindi
4751414Scindi return (DCMD_OK);
4761414Scindi }
4771414Scindi
4781414Scindi /*ARGSUSED*/
4791414Scindi int
kmt_rdpcicfg(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)4801414Scindi kmt_rdpcicfg(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
4811414Scindi {
4821414Scindi uint32_t val;
4831414Scindi
4841414Scindi if (argc != 3 || !(flags & DCMD_ADDRSPEC))
4851414Scindi return (DCMD_USAGE);
4861414Scindi
4871414Scindi if (kmt_pcicfg_common(addr, &val, argv, kmt_in) != DCMD_OK)
4881414Scindi return (DCMD_ERR);
4891414Scindi
4901414Scindi mdb_printf("%llx\n", (u_longlong_t)val);
4911414Scindi
4921414Scindi return (DCMD_OK);
4931414Scindi }
4941414Scindi
4951414Scindi /*ARGSUSED*/
4961414Scindi int
kmt_wrpcicfg(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)4971414Scindi kmt_wrpcicfg(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
4981414Scindi {
4991414Scindi uint32_t val;
5001414Scindi
5011414Scindi if (argc != 4 || !(flags & DCMD_ADDRSPEC))
5021414Scindi return (DCMD_USAGE);
5031414Scindi
5041414Scindi val = (uint32_t)kmt_numarg(&argv[3]);
5051414Scindi
5061414Scindi if (kmt_pcicfg_common(addr, &val, argv, kmt_out) != DCMD_OK)
5071414Scindi return (DCMD_ERR);
5081414Scindi
5091414Scindi return (DCMD_OK);
5101414Scindi }
5111414Scindi
5120Sstevel@tonic-gate const char *
kmt_trapname(int trapnum)5130Sstevel@tonic-gate kmt_trapname(int trapnum)
5140Sstevel@tonic-gate {
5150Sstevel@tonic-gate static char trapname[11];
5160Sstevel@tonic-gate
5170Sstevel@tonic-gate switch (trapnum) {
5180Sstevel@tonic-gate case T_ZERODIV:
5190Sstevel@tonic-gate return ("division by zero (#de) trap");
5200Sstevel@tonic-gate case T_SGLSTP:
5210Sstevel@tonic-gate return ("single-step (#db) trap");
5220Sstevel@tonic-gate case T_NMIFLT:
5230Sstevel@tonic-gate return ("NMI");
5240Sstevel@tonic-gate case T_BPTFLT:
5250Sstevel@tonic-gate return ("breakpoint (#bp) trap");
5260Sstevel@tonic-gate case T_ILLINST:
5270Sstevel@tonic-gate return ("illegal instruction (#ud) trap");
5280Sstevel@tonic-gate case T_SEGFLT:
5290Sstevel@tonic-gate return ("segment not present (#np) trap");
5300Sstevel@tonic-gate case T_STKFLT:
5310Sstevel@tonic-gate return ("stack (#ss) trap");
5320Sstevel@tonic-gate case T_GPFLT:
5330Sstevel@tonic-gate return ("general protection (#gp) trap");
5340Sstevel@tonic-gate case T_PGFLT:
5350Sstevel@tonic-gate return ("page fault (#pf) trap");
5360Sstevel@tonic-gate case T_ALIGNMENT:
5370Sstevel@tonic-gate return ("alignment check (#ac) trap");
5380Sstevel@tonic-gate case T_MCE:
5390Sstevel@tonic-gate return ("machine check (#mc) trap");
5400Sstevel@tonic-gate case T_SIMDFPE:
5410Sstevel@tonic-gate return ("SSE/SSE2 (#xm) trap");
5420Sstevel@tonic-gate case T_DBGENTR:
5430Sstevel@tonic-gate return ("debugger entry trap");
5440Sstevel@tonic-gate default:
5450Sstevel@tonic-gate (void) mdb_snprintf(trapname, sizeof (trapname), "trap %#x",
5460Sstevel@tonic-gate trapnum);
5470Sstevel@tonic-gate return (trapname);
5480Sstevel@tonic-gate }
5490Sstevel@tonic-gate }
5500Sstevel@tonic-gate
5510Sstevel@tonic-gate void
kmt_init_isadep(mdb_tgt_t * t)5520Sstevel@tonic-gate kmt_init_isadep(mdb_tgt_t *t)
5530Sstevel@tonic-gate {
5540Sstevel@tonic-gate kmt_data_t *kmt = t->t_data;
5550Sstevel@tonic-gate
5560Sstevel@tonic-gate kmt->kmt_rds = mdb_isa_kregs;
5570Sstevel@tonic-gate
5580Sstevel@tonic-gate kmt->kmt_trapmax = KMT_MAXTRAPNO;
5590Sstevel@tonic-gate kmt->kmt_trapmap = mdb_zalloc(BT_SIZEOFMAP(kmt->kmt_trapmax), UM_SLEEP);
5600Sstevel@tonic-gate
5610Sstevel@tonic-gate /* Traps for which we want to provide an explicit message */
5620Sstevel@tonic-gate (void) mdb_tgt_add_fault(t, T_ZERODIV, MDB_TGT_SPEC_INTERNAL,
5630Sstevel@tonic-gate no_se_f, NULL);
5640Sstevel@tonic-gate (void) mdb_tgt_add_fault(t, T_ILLINST, MDB_TGT_SPEC_INTERNAL,
5650Sstevel@tonic-gate no_se_f, NULL);
5660Sstevel@tonic-gate (void) mdb_tgt_add_fault(t, T_SEGFLT, MDB_TGT_SPEC_INTERNAL,
5670Sstevel@tonic-gate no_se_f, NULL);
5680Sstevel@tonic-gate (void) mdb_tgt_add_fault(t, T_STKFLT, MDB_TGT_SPEC_INTERNAL,
5690Sstevel@tonic-gate no_se_f, NULL);
5700Sstevel@tonic-gate (void) mdb_tgt_add_fault(t, T_GPFLT, MDB_TGT_SPEC_INTERNAL,
5710Sstevel@tonic-gate no_se_f, NULL);
5720Sstevel@tonic-gate (void) mdb_tgt_add_fault(t, T_PGFLT, MDB_TGT_SPEC_INTERNAL,
5730Sstevel@tonic-gate no_se_f, NULL);
5740Sstevel@tonic-gate (void) mdb_tgt_add_fault(t, T_ALIGNMENT, MDB_TGT_SPEC_INTERNAL,
5750Sstevel@tonic-gate no_se_f, NULL);
5760Sstevel@tonic-gate (void) mdb_tgt_add_fault(t, T_MCE, MDB_TGT_SPEC_INTERNAL,
5770Sstevel@tonic-gate no_se_f, NULL);
5780Sstevel@tonic-gate (void) mdb_tgt_add_fault(t, T_SIMDFPE, MDB_TGT_SPEC_INTERNAL,
5790Sstevel@tonic-gate no_se_f, NULL);
5800Sstevel@tonic-gate
5810Sstevel@tonic-gate /*
5820Sstevel@tonic-gate * Traps which will be handled elsewhere, and which therefore don't
5830Sstevel@tonic-gate * need the trap-based message.
5840Sstevel@tonic-gate */
5850Sstevel@tonic-gate BT_SET(kmt->kmt_trapmap, T_SGLSTP);
5860Sstevel@tonic-gate BT_SET(kmt->kmt_trapmap, T_BPTFLT);
5870Sstevel@tonic-gate BT_SET(kmt->kmt_trapmap, T_DBGENTR);
5880Sstevel@tonic-gate
5890Sstevel@tonic-gate /* Catch-all for traps not explicitly listed here */
5900Sstevel@tonic-gate (void) mdb_tgt_add_fault(t, KMT_TRAP_NOTENUM, MDB_TGT_SPEC_INTERNAL,
5910Sstevel@tonic-gate no_se_f, NULL);
5920Sstevel@tonic-gate }
5930Sstevel@tonic-gate
5940Sstevel@tonic-gate void
kmt_startup_isadep(mdb_tgt_t * t)5950Sstevel@tonic-gate kmt_startup_isadep(mdb_tgt_t *t)
5960Sstevel@tonic-gate {
5970Sstevel@tonic-gate kmt_data_t *kmt = t->t_data;
5980Sstevel@tonic-gate
5990Sstevel@tonic-gate /*
6000Sstevel@tonic-gate * The stack trace and ::step out code need to detect "interrupt"
6010Sstevel@tonic-gate * frames. The heuristic they use to detect said frames requires the
6020Sstevel@tonic-gate * addresses of routines that can generate them.
6030Sstevel@tonic-gate */
6040Sstevel@tonic-gate (void) mdb_tgt_lookup_by_name(t, MDB_TGT_OBJ_EXEC,
6050Sstevel@tonic-gate "cmnint", &kmt->kmt_intrsyms._kmt_cmnint, NULL);
6060Sstevel@tonic-gate (void) mdb_tgt_lookup_by_name(t, MDB_TGT_OBJ_EXEC,
6070Sstevel@tonic-gate "cmntrap", &kmt->kmt_intrsyms._kmt_cmntrap, NULL);
6080Sstevel@tonic-gate (void) mdb_tgt_lookup_by_name(t, MDB_TGT_OBJ_EXEC,
6090Sstevel@tonic-gate "sys_sysenter", &kmt->kmt_intrsyms._kmt_sysenter, NULL);
6102712Snn35248 (void) mdb_tgt_lookup_by_name(t, MDB_TGT_OBJ_EXEC,
6112712Snn35248 "brand_sys_sysenter", &kmt->kmt_intrsyms._kmt_brand_sysenter, NULL);
6120Sstevel@tonic-gate #if defined(__amd64)
6130Sstevel@tonic-gate (void) mdb_tgt_lookup_by_name(t, MDB_TGT_OBJ_EXEC,
6140Sstevel@tonic-gate "sys_syscall", &kmt->kmt_intrsyms._kmt_syscall, NULL);
6152712Snn35248 (void) mdb_tgt_lookup_by_name(t, MDB_TGT_OBJ_EXEC,
6162712Snn35248 "brand_sys_syscall", &kmt->kmt_intrsyms._kmt_brand_syscall, NULL);
6170Sstevel@tonic-gate #endif
6180Sstevel@tonic-gate }
619