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
51598Sjohnlev * Common Development and Distribution License (the "License").
61598Sjohnlev * 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 * The debugger/"PROM" interface layer
300Sstevel@tonic-gate *
31*3446Smrj * It makes more sense on SPARC. In reality, these interfaces deal with three
32*3446Smrj * things: setting break/watchpoints, stepping, and interfacing with the KDI to
33*3446Smrj * set up kmdb's IDT handlers.
340Sstevel@tonic-gate */
350Sstevel@tonic-gate
360Sstevel@tonic-gate #include <kmdb/kmdb_dpi_impl.h>
370Sstevel@tonic-gate #include <kmdb/kmdb_kdi.h>
380Sstevel@tonic-gate #include <kmdb/kmdb_umemglue.h>
390Sstevel@tonic-gate #include <kmdb/kaif.h>
401598Sjohnlev #include <kmdb/kmdb_io.h>
41*3446Smrj #include <kmdb/kaif_start.h>
420Sstevel@tonic-gate #include <mdb/mdb_err.h>
430Sstevel@tonic-gate #include <mdb/mdb_debug.h>
440Sstevel@tonic-gate #include <mdb/mdb_isautil.h>
450Sstevel@tonic-gate #include <mdb/mdb_io_impl.h>
46*3446Smrj #include <mdb/mdb_kreg_impl.h>
470Sstevel@tonic-gate #include <mdb/mdb.h>
480Sstevel@tonic-gate
490Sstevel@tonic-gate #include <sys/types.h>
500Sstevel@tonic-gate #include <sys/bitmap.h>
511598Sjohnlev #include <sys/termios.h>
52*3446Smrj #include <sys/kdi_impl.h>
530Sstevel@tonic-gate
54*3446Smrj /*
55*3446Smrj * This is the area containing the saved state when we enter
56*3446Smrj * via kmdb's IDT entries.
57*3446Smrj */
58*3446Smrj kdi_cpusave_t *kaif_cpusave;
590Sstevel@tonic-gate int kaif_ncpusave;
60*3446Smrj kdi_drreg_t kaif_drreg;
610Sstevel@tonic-gate
620Sstevel@tonic-gate uint32_t kaif_waptmap;
630Sstevel@tonic-gate
640Sstevel@tonic-gate int kaif_trap_switch;
650Sstevel@tonic-gate
660Sstevel@tonic-gate void (*kaif_modchg_cb)(struct modctl *, int);
670Sstevel@tonic-gate
680Sstevel@tonic-gate enum {
690Sstevel@tonic-gate M_SYSRET = 0x07, /* after M_ESC */
700Sstevel@tonic-gate M_ESC = 0x0f,
710Sstevel@tonic-gate M_SYSEXIT = 0x35, /* after M_ESC */
720Sstevel@tonic-gate M_REX_LO = 0x40, /* first REX prefix */
730Sstevel@tonic-gate M_REX_HI = 0x4f, /* last REX prefix */
740Sstevel@tonic-gate M_PUSHF = 0x9c, /* pushfl and pushfq */
750Sstevel@tonic-gate M_POPF = 0x9d, /* popfl and popfq */
760Sstevel@tonic-gate M_INT3 = 0xcc,
770Sstevel@tonic-gate M_INTX = 0xcd,
780Sstevel@tonic-gate M_INTO = 0xce,
790Sstevel@tonic-gate M_IRET = 0xcf,
800Sstevel@tonic-gate M_CLI = 0xfa,
810Sstevel@tonic-gate M_STI = 0xfb
820Sstevel@tonic-gate };
830Sstevel@tonic-gate
840Sstevel@tonic-gate #define KAIF_BREAKPOINT_INSTR M_INT3
850Sstevel@tonic-gate
860Sstevel@tonic-gate #define KAIF_WPPRIV2ID(wp) (int)(uintptr_t)((wp)->wp_priv)
870Sstevel@tonic-gate
880Sstevel@tonic-gate #ifdef __amd64
890Sstevel@tonic-gate #define FLAGS_REG_NAME "rflags"
900Sstevel@tonic-gate #else
910Sstevel@tonic-gate #define FLAGS_REG_NAME "eflags"
920Sstevel@tonic-gate #endif
930Sstevel@tonic-gate
940Sstevel@tonic-gate /*
950Sstevel@tonic-gate * Called during normal debugger operation and during debugger faults.
960Sstevel@tonic-gate */
970Sstevel@tonic-gate static void
kaif_enter_mon(void)980Sstevel@tonic-gate kaif_enter_mon(void)
990Sstevel@tonic-gate {
1000Sstevel@tonic-gate char c;
1010Sstevel@tonic-gate
1020Sstevel@tonic-gate for (;;) {
1030Sstevel@tonic-gate mdb_iob_printf(mdb.m_out,
1040Sstevel@tonic-gate "%s: Do you really want to reboot? (y/n) ",
1050Sstevel@tonic-gate mdb.m_pname);
1060Sstevel@tonic-gate mdb_iob_flush(mdb.m_out);
1071598Sjohnlev mdb_iob_clearlines(mdb.m_out);
1080Sstevel@tonic-gate
1091598Sjohnlev c = kmdb_getchar();
1100Sstevel@tonic-gate
1111598Sjohnlev if (c == 'n' || c == 'N' || c == CTRL('c'))
1120Sstevel@tonic-gate return;
1130Sstevel@tonic-gate else if (c == 'y' || c == 'Y') {
1140Sstevel@tonic-gate mdb_iob_printf(mdb.m_out, "Rebooting...\n");
1150Sstevel@tonic-gate
1160Sstevel@tonic-gate kmdb_dpi_reboot();
1170Sstevel@tonic-gate }
1180Sstevel@tonic-gate }
1190Sstevel@tonic-gate }
1200Sstevel@tonic-gate
1211234Sjohnlev static kaif_cpusave_t *
kaif_cpuid2save(int cpuid)1221234Sjohnlev kaif_cpuid2save(int cpuid)
1231234Sjohnlev {
1241234Sjohnlev kaif_cpusave_t *save;
1251234Sjohnlev
1261234Sjohnlev if (cpuid == DPI_MASTER_CPUID)
1271234Sjohnlev return (&kaif_cpusave[kaif_master_cpuid]);
1281234Sjohnlev
1291234Sjohnlev if (cpuid < 0 || cpuid >= kaif_ncpusave) {
1301234Sjohnlev (void) set_errno(EINVAL);
1311234Sjohnlev return (NULL);
1321234Sjohnlev }
1331234Sjohnlev
1341234Sjohnlev save = &kaif_cpusave[cpuid];
1351234Sjohnlev
1361234Sjohnlev if (save->krs_cpu_state != KAIF_CPU_STATE_MASTER &&
1371234Sjohnlev save->krs_cpu_state != KAIF_CPU_STATE_SLAVE) {
1381234Sjohnlev (void) set_errno(EINVAL);
1391234Sjohnlev return (NULL);
1401234Sjohnlev }
1411234Sjohnlev
1421234Sjohnlev return (save);
1431234Sjohnlev }
1441234Sjohnlev
1450Sstevel@tonic-gate static int
kaif_get_cpu_state(int cpuid)1460Sstevel@tonic-gate kaif_get_cpu_state(int cpuid)
1470Sstevel@tonic-gate {
1481234Sjohnlev kaif_cpusave_t *save;
1490Sstevel@tonic-gate
1501234Sjohnlev if ((save = kaif_cpuid2save(cpuid)) == NULL)
1511234Sjohnlev return (-1); /* errno is set for us */
1520Sstevel@tonic-gate
1531234Sjohnlev switch (save->krs_cpu_state) {
1540Sstevel@tonic-gate case KAIF_CPU_STATE_MASTER:
1550Sstevel@tonic-gate return (DPI_CPU_STATE_MASTER);
1560Sstevel@tonic-gate case KAIF_CPU_STATE_SLAVE:
1570Sstevel@tonic-gate return (DPI_CPU_STATE_SLAVE);
1580Sstevel@tonic-gate default:
1590Sstevel@tonic-gate return (set_errno(EINVAL));
1600Sstevel@tonic-gate }
1610Sstevel@tonic-gate }
1620Sstevel@tonic-gate
1630Sstevel@tonic-gate static int
kaif_get_master_cpuid(void)1640Sstevel@tonic-gate kaif_get_master_cpuid(void)
1650Sstevel@tonic-gate {
1660Sstevel@tonic-gate return (kaif_master_cpuid);
1670Sstevel@tonic-gate }
1680Sstevel@tonic-gate
169*3446Smrj static mdb_tgt_gregset_t *
kaif_kdi_to_gregs(int cpuid)170*3446Smrj kaif_kdi_to_gregs(int cpuid)
1710Sstevel@tonic-gate {
1721234Sjohnlev kaif_cpusave_t *save;
1730Sstevel@tonic-gate
1741234Sjohnlev if ((save = kaif_cpuid2save(cpuid)) == NULL)
1751234Sjohnlev return (NULL); /* errno is set for us */
1760Sstevel@tonic-gate
177*3446Smrj /*
178*3446Smrj * The saved registers are actually identical to an mdb_tgt_gregset,
179*3446Smrj * so we can directly cast here.
180*3446Smrj */
181*3446Smrj return ((mdb_tgt_gregset_t *)save->krs_gregs);
182*3446Smrj }
183*3446Smrj
184*3446Smrj static const mdb_tgt_gregset_t *
kaif_get_gregs(int cpuid)185*3446Smrj kaif_get_gregs(int cpuid)
186*3446Smrj {
187*3446Smrj return (kaif_kdi_to_gregs(cpuid));
1880Sstevel@tonic-gate }
1890Sstevel@tonic-gate
1900Sstevel@tonic-gate typedef struct kaif_reg_synonyms {
1910Sstevel@tonic-gate const char *rs_syn;
1920Sstevel@tonic-gate const char *rs_name;
1930Sstevel@tonic-gate } kaif_reg_synonyms_t;
1940Sstevel@tonic-gate
1950Sstevel@tonic-gate static kreg_t *
kaif_find_regp(const char * regname)1961234Sjohnlev kaif_find_regp(const char *regname)
1970Sstevel@tonic-gate {
1980Sstevel@tonic-gate static const kaif_reg_synonyms_t synonyms[] = {
1990Sstevel@tonic-gate #ifdef __amd64
2000Sstevel@tonic-gate { "pc", "rip" },
2010Sstevel@tonic-gate { "sp", "rsp" },
2020Sstevel@tonic-gate { "fp", "rbp" },
2030Sstevel@tonic-gate #else
2040Sstevel@tonic-gate { "pc", "eip" },
2050Sstevel@tonic-gate { "sp", "esp" },
2060Sstevel@tonic-gate { "fp", "ebp" },
2070Sstevel@tonic-gate #endif
2080Sstevel@tonic-gate { "tt", "trapno" }
2090Sstevel@tonic-gate };
210*3446Smrj mdb_tgt_gregset_t *regs;
2110Sstevel@tonic-gate int i;
2120Sstevel@tonic-gate
213*3446Smrj if ((regs = kaif_kdi_to_gregs(DPI_MASTER_CPUID)) == NULL)
214*3446Smrj return (NULL);
2150Sstevel@tonic-gate
2160Sstevel@tonic-gate for (i = 0; i < sizeof (synonyms) / sizeof (synonyms[0]); i++) {
2170Sstevel@tonic-gate if (strcmp(synonyms[i].rs_syn, regname) == 0)
2180Sstevel@tonic-gate regname = synonyms[i].rs_name;
2190Sstevel@tonic-gate }
2200Sstevel@tonic-gate
2210Sstevel@tonic-gate for (i = 0; mdb_isa_kregs[i].rd_name != NULL; i++) {
2220Sstevel@tonic-gate const mdb_tgt_regdesc_t *rd = &mdb_isa_kregs[i];
2230Sstevel@tonic-gate
2240Sstevel@tonic-gate if (strcmp(rd->rd_name, regname) == 0)
225*3446Smrj return (®s->kregs[rd->rd_num]);
2260Sstevel@tonic-gate }
2270Sstevel@tonic-gate
2280Sstevel@tonic-gate (void) set_errno(ENOENT);
2290Sstevel@tonic-gate return (NULL);
2300Sstevel@tonic-gate }
2310Sstevel@tonic-gate
2320Sstevel@tonic-gate /*ARGSUSED*/
2330Sstevel@tonic-gate static int
kaif_get_register(const char * regname,kreg_t * valp)2341234Sjohnlev kaif_get_register(const char *regname, kreg_t *valp)
2350Sstevel@tonic-gate {
2360Sstevel@tonic-gate kreg_t *regp;
2370Sstevel@tonic-gate
2381234Sjohnlev if ((regp = kaif_find_regp(regname)) == NULL)
2390Sstevel@tonic-gate return (-1);
2400Sstevel@tonic-gate
2410Sstevel@tonic-gate *valp = *regp;
2420Sstevel@tonic-gate
2430Sstevel@tonic-gate return (0);
2440Sstevel@tonic-gate }
2450Sstevel@tonic-gate
2460Sstevel@tonic-gate static int
kaif_set_register(const char * regname,kreg_t val)2471234Sjohnlev kaif_set_register(const char *regname, kreg_t val)
2480Sstevel@tonic-gate {
2490Sstevel@tonic-gate kreg_t *regp;
2500Sstevel@tonic-gate
2511234Sjohnlev if ((regp = kaif_find_regp(regname)) == NULL)
2520Sstevel@tonic-gate return (-1);
2530Sstevel@tonic-gate
2540Sstevel@tonic-gate *regp = val;
2550Sstevel@tonic-gate
2560Sstevel@tonic-gate return (0);
2570Sstevel@tonic-gate }
2580Sstevel@tonic-gate
2590Sstevel@tonic-gate static int
kaif_brkpt_arm(uintptr_t addr,mdb_instr_t * instrp)2600Sstevel@tonic-gate kaif_brkpt_arm(uintptr_t addr, mdb_instr_t *instrp)
2610Sstevel@tonic-gate {
2620Sstevel@tonic-gate mdb_instr_t bkpt = KAIF_BREAKPOINT_INSTR;
2630Sstevel@tonic-gate
2640Sstevel@tonic-gate if (mdb_tgt_vread(mdb.m_target, instrp, sizeof (mdb_instr_t), addr) !=
2650Sstevel@tonic-gate sizeof (mdb_instr_t))
2660Sstevel@tonic-gate return (-1); /* errno is set for us */
2670Sstevel@tonic-gate
2680Sstevel@tonic-gate if (mdb_tgt_vwrite(mdb.m_target, &bkpt, sizeof (mdb_instr_t), addr) !=
2690Sstevel@tonic-gate sizeof (mdb_instr_t))
2700Sstevel@tonic-gate return (-1); /* errno is set for us */
2710Sstevel@tonic-gate
2720Sstevel@tonic-gate return (0);
2730Sstevel@tonic-gate }
2740Sstevel@tonic-gate
2750Sstevel@tonic-gate static int
kaif_brkpt_disarm(uintptr_t addr,mdb_instr_t instrp)2760Sstevel@tonic-gate kaif_brkpt_disarm(uintptr_t addr, mdb_instr_t instrp)
2770Sstevel@tonic-gate {
2780Sstevel@tonic-gate if (mdb_tgt_vwrite(mdb.m_target, &instrp, sizeof (mdb_instr_t), addr) !=
2790Sstevel@tonic-gate sizeof (mdb_instr_t))
2800Sstevel@tonic-gate return (-1); /* errno is set for us */
2810Sstevel@tonic-gate
2820Sstevel@tonic-gate return (0);
2830Sstevel@tonic-gate }
2840Sstevel@tonic-gate
2850Sstevel@tonic-gate /*
2860Sstevel@tonic-gate * Intel watchpoints are even more fun than SPARC ones. The Intel architecture
2870Sstevel@tonic-gate * manuals refer to watchpoints as breakpoints. For consistency with the
2880Sstevel@tonic-gate * terminology used in other portions of kmdb, we will, however, refer to them
2890Sstevel@tonic-gate * as watchpoints.
2900Sstevel@tonic-gate *
2910Sstevel@tonic-gate * Execute, data write, I/O read/write, and data read/write watchpoints are
2920Sstevel@tonic-gate * supported by the hardware. Execute watchpoints must be one byte in length,
2930Sstevel@tonic-gate * and must be placed on the first byte of the instruction to be watched.
2940Sstevel@tonic-gate * Lengths of other watchpoints are more varied.
2950Sstevel@tonic-gate *
2960Sstevel@tonic-gate * Given that we already have a breakpoint facility, and given the restrictions
2970Sstevel@tonic-gate * placed on execute watchpoints, we're going to disallow the creation of
2980Sstevel@tonic-gate * execute watchpoints. The others will be fully supported. See the Debugging
2990Sstevel@tonic-gate * chapter in both the IA32 and AMD64 System Programming books for more details.
3000Sstevel@tonic-gate */
3010Sstevel@tonic-gate
3020Sstevel@tonic-gate #ifdef __amd64
3030Sstevel@tonic-gate #define WAPT_DATA_MAX_SIZE 8
3040Sstevel@tonic-gate #define WAPT_DATA_SIZES_MSG "1, 2, 4, or 8"
3050Sstevel@tonic-gate #else
3060Sstevel@tonic-gate #define WAPT_DATA_MAX_SIZE 4
3070Sstevel@tonic-gate #define WAPT_DATA_SIZES_MSG "1, 2, or 4"
3080Sstevel@tonic-gate #endif
3090Sstevel@tonic-gate
3100Sstevel@tonic-gate static int
kaif_wapt_validate(kmdb_wapt_t * wp)3110Sstevel@tonic-gate kaif_wapt_validate(kmdb_wapt_t *wp)
3120Sstevel@tonic-gate {
3130Sstevel@tonic-gate if (wp->wp_type == DPI_WAPT_TYPE_IO) {
3140Sstevel@tonic-gate if (wp->wp_wflags != (MDB_TGT_WA_R | MDB_TGT_WA_W)) {
3150Sstevel@tonic-gate warn("I/O port watchpoints must be read/write\n");
3160Sstevel@tonic-gate return (set_errno(EINVAL));
3170Sstevel@tonic-gate }
3180Sstevel@tonic-gate
3190Sstevel@tonic-gate if (wp->wp_size != 1 && wp->wp_size != 2 && wp->wp_size != 4) {
3200Sstevel@tonic-gate warn("I/O watchpoint size must be 1, 2, or 4 bytes\n");
3210Sstevel@tonic-gate return (set_errno(EINVAL));
3220Sstevel@tonic-gate }
3230Sstevel@tonic-gate
3240Sstevel@tonic-gate } else if (wp->wp_type == DPI_WAPT_TYPE_PHYS) {
3250Sstevel@tonic-gate warn("physical address watchpoints are not supported on this "
3260Sstevel@tonic-gate "platform\n");
3270Sstevel@tonic-gate return (set_errno(EMDB_TGTHWNOTSUP));
3280Sstevel@tonic-gate
3290Sstevel@tonic-gate } else {
3300Sstevel@tonic-gate if (wp->wp_wflags != (MDB_TGT_WA_R | MDB_TGT_WA_W) &&
3310Sstevel@tonic-gate wp->wp_wflags != MDB_TGT_WA_W) {
3320Sstevel@tonic-gate warn("watchpoints must be read/write or write-only\n");
3330Sstevel@tonic-gate return (set_errno(EINVAL));
3340Sstevel@tonic-gate }
3350Sstevel@tonic-gate
3360Sstevel@tonic-gate if ((wp->wp_size & -(wp->wp_size)) != wp->wp_size ||
3370Sstevel@tonic-gate wp->wp_size > WAPT_DATA_MAX_SIZE) {
3380Sstevel@tonic-gate warn("data watchpoint size must be " WAPT_DATA_SIZES_MSG
3390Sstevel@tonic-gate " bytes\n");
3400Sstevel@tonic-gate return (set_errno(EINVAL));
3410Sstevel@tonic-gate }
3420Sstevel@tonic-gate
3430Sstevel@tonic-gate }
3440Sstevel@tonic-gate
3450Sstevel@tonic-gate if (wp->wp_addr & (wp->wp_size - 1)) {
3460Sstevel@tonic-gate warn("%lu-byte watchpoints must be %lu-byte aligned\n",
3470Sstevel@tonic-gate (ulong_t)wp->wp_size, (ulong_t)wp->wp_size);
3480Sstevel@tonic-gate return (set_errno(EINVAL));
3490Sstevel@tonic-gate }
3500Sstevel@tonic-gate
3510Sstevel@tonic-gate return (0);
3520Sstevel@tonic-gate }
3530Sstevel@tonic-gate
3540Sstevel@tonic-gate static int
kaif_wapt_reserve(kmdb_wapt_t * wp)3550Sstevel@tonic-gate kaif_wapt_reserve(kmdb_wapt_t *wp)
3560Sstevel@tonic-gate {
3570Sstevel@tonic-gate int id;
3580Sstevel@tonic-gate
359*3446Smrj for (id = 0; id <= KDI_MAXWPIDX; id++) {
3600Sstevel@tonic-gate if (!BT_TEST(&kaif_waptmap, id)) {
3610Sstevel@tonic-gate /* found one */
3620Sstevel@tonic-gate BT_SET(&kaif_waptmap, id);
3630Sstevel@tonic-gate wp->wp_priv = (void *)(uintptr_t)id;
3640Sstevel@tonic-gate return (0);
3650Sstevel@tonic-gate }
3660Sstevel@tonic-gate }
3670Sstevel@tonic-gate
3680Sstevel@tonic-gate return (set_errno(EMDB_WPTOOMANY));
3690Sstevel@tonic-gate }
3700Sstevel@tonic-gate
3710Sstevel@tonic-gate static void
kaif_wapt_release(kmdb_wapt_t * wp)3720Sstevel@tonic-gate kaif_wapt_release(kmdb_wapt_t *wp)
3730Sstevel@tonic-gate {
3740Sstevel@tonic-gate int id = KAIF_WPPRIV2ID(wp);
3750Sstevel@tonic-gate
3760Sstevel@tonic-gate ASSERT(BT_TEST(&kaif_waptmap, id));
3770Sstevel@tonic-gate BT_CLEAR(&kaif_waptmap, id);
3780Sstevel@tonic-gate }
3790Sstevel@tonic-gate
3800Sstevel@tonic-gate /*ARGSUSED*/
3810Sstevel@tonic-gate static void
kaif_wapt_arm(kmdb_wapt_t * wp)3820Sstevel@tonic-gate kaif_wapt_arm(kmdb_wapt_t *wp)
3830Sstevel@tonic-gate {
3840Sstevel@tonic-gate uint_t rw;
3850Sstevel@tonic-gate int hwid = KAIF_WPPRIV2ID(wp);
3860Sstevel@tonic-gate
3870Sstevel@tonic-gate ASSERT(BT_TEST(&kaif_waptmap, hwid));
3880Sstevel@tonic-gate
3890Sstevel@tonic-gate if (wp->wp_type == DPI_WAPT_TYPE_IO)
3900Sstevel@tonic-gate rw = KREG_DRCTL_WP_IORW;
3910Sstevel@tonic-gate else if (wp->wp_wflags & MDB_TGT_WA_R)
3920Sstevel@tonic-gate rw = KREG_DRCTL_WP_RW;
3930Sstevel@tonic-gate else if (wp->wp_wflags & MDB_TGT_WA_X)
3940Sstevel@tonic-gate rw = KREG_DRCTL_WP_EXEC;
3950Sstevel@tonic-gate else
3960Sstevel@tonic-gate rw = KREG_DRCTL_WP_WONLY;
3970Sstevel@tonic-gate
3980Sstevel@tonic-gate kaif_drreg.dr_addr[hwid] = wp->wp_addr;
3990Sstevel@tonic-gate
4000Sstevel@tonic-gate kaif_drreg.dr_ctl &= ~KREG_DRCTL_WP_MASK(hwid);
4010Sstevel@tonic-gate kaif_drreg.dr_ctl |= KREG_DRCTL_WP_LENRW(hwid, wp->wp_size - 1, rw);
4020Sstevel@tonic-gate kaif_drreg.dr_ctl |= KREG_DRCTL_WPEN(hwid);
403*3446Smrj kmdb_kdi_update_drreg(&kaif_drreg);
4040Sstevel@tonic-gate }
4050Sstevel@tonic-gate
4060Sstevel@tonic-gate /*ARGSUSED*/
4070Sstevel@tonic-gate static void
kaif_wapt_disarm(kmdb_wapt_t * wp)4080Sstevel@tonic-gate kaif_wapt_disarm(kmdb_wapt_t *wp)
4090Sstevel@tonic-gate {
4100Sstevel@tonic-gate int hwid = KAIF_WPPRIV2ID(wp);
4110Sstevel@tonic-gate
4120Sstevel@tonic-gate ASSERT(BT_TEST(&kaif_waptmap, hwid));
4130Sstevel@tonic-gate
4140Sstevel@tonic-gate kaif_drreg.dr_addr[hwid] = 0;
4150Sstevel@tonic-gate kaif_drreg.dr_ctl &= ~(KREG_DRCTL_WP_MASK(hwid) |
4160Sstevel@tonic-gate KREG_DRCTL_WPEN_MASK(hwid));
417*3446Smrj kmdb_kdi_update_drreg(&kaif_drreg);
4180Sstevel@tonic-gate }
4190Sstevel@tonic-gate
4200Sstevel@tonic-gate /*ARGSUSED*/
4210Sstevel@tonic-gate static int
kaif_wapt_match(kmdb_wapt_t * wp)4220Sstevel@tonic-gate kaif_wapt_match(kmdb_wapt_t *wp)
4230Sstevel@tonic-gate {
4240Sstevel@tonic-gate int hwid = KAIF_WPPRIV2ID(wp);
4250Sstevel@tonic-gate uint32_t mask = KREG_DRSTAT_WP_MASK(hwid);
4260Sstevel@tonic-gate int n = 0;
4270Sstevel@tonic-gate int i;
4280Sstevel@tonic-gate
4290Sstevel@tonic-gate ASSERT(BT_TEST(&kaif_waptmap, hwid));
4300Sstevel@tonic-gate
4310Sstevel@tonic-gate for (i = 0; i < kaif_ncpusave; i++)
4320Sstevel@tonic-gate n += (kaif_cpusave[i].krs_dr.dr_stat & mask) != 0;
4330Sstevel@tonic-gate
4340Sstevel@tonic-gate return (n);
4350Sstevel@tonic-gate }
4360Sstevel@tonic-gate
4370Sstevel@tonic-gate static int
kaif_step(void)4380Sstevel@tonic-gate kaif_step(void)
4390Sstevel@tonic-gate {
4400Sstevel@tonic-gate kreg_t pc, fl, oldfl, newfl, sp;
4410Sstevel@tonic-gate mdb_tgt_addr_t npc;
4420Sstevel@tonic-gate mdb_instr_t instr;
4430Sstevel@tonic-gate int emulated = 0, rchk = 0;
4440Sstevel@tonic-gate size_t pcoff = 0;
4450Sstevel@tonic-gate
4460Sstevel@tonic-gate (void) kmdb_dpi_get_register("pc", &pc);
4470Sstevel@tonic-gate
4480Sstevel@tonic-gate if ((npc = mdb_dis_nextins(mdb.m_disasm, mdb.m_target,
4490Sstevel@tonic-gate MDB_TGT_AS_VIRT, pc)) == pc) {
4500Sstevel@tonic-gate warn("failed to decode instruction at %a for step\n", pc);
4510Sstevel@tonic-gate return (set_errno(EINVAL));
4520Sstevel@tonic-gate }
4530Sstevel@tonic-gate
4540Sstevel@tonic-gate /*
4550Sstevel@tonic-gate * Stepping behavior depends on the type of instruction. It does not
4560Sstevel@tonic-gate * depend on the presence of a REX prefix, as the action we take for a
4570Sstevel@tonic-gate * given instruction doesn't currently vary for 32-bit instructions
4580Sstevel@tonic-gate * versus their 64-bit counterparts.
4590Sstevel@tonic-gate */
4600Sstevel@tonic-gate do {
4610Sstevel@tonic-gate if (mdb_tgt_vread(mdb.m_target, &instr, sizeof (mdb_instr_t),
4620Sstevel@tonic-gate pc + pcoff) != sizeof (mdb_instr_t)) {
4630Sstevel@tonic-gate warn("failed to read at %p for step",
4640Sstevel@tonic-gate (void *)(pc + pcoff));
4650Sstevel@tonic-gate return (-1);
4660Sstevel@tonic-gate }
4670Sstevel@tonic-gate } while (pcoff++, (instr >= M_REX_LO && instr <= M_REX_HI && !rchk++));
4680Sstevel@tonic-gate
4690Sstevel@tonic-gate switch (instr) {
4700Sstevel@tonic-gate case M_IRET:
4710Sstevel@tonic-gate warn("iret cannot be stepped\n");
4720Sstevel@tonic-gate return (set_errno(EMDB_TGTNOTSUP));
4730Sstevel@tonic-gate
4740Sstevel@tonic-gate case M_INT3:
4750Sstevel@tonic-gate case M_INTX:
4760Sstevel@tonic-gate case M_INTO:
4770Sstevel@tonic-gate warn("int cannot be stepped\n");
4780Sstevel@tonic-gate return (set_errno(EMDB_TGTNOTSUP));
4790Sstevel@tonic-gate
4800Sstevel@tonic-gate case M_ESC:
4810Sstevel@tonic-gate if (mdb_tgt_vread(mdb.m_target, &instr, sizeof (mdb_instr_t),
4820Sstevel@tonic-gate pc + pcoff) != sizeof (mdb_instr_t)) {
4830Sstevel@tonic-gate warn("failed to read at %p for step",
4840Sstevel@tonic-gate (void *)(pc + pcoff));
4850Sstevel@tonic-gate return (-1);
4860Sstevel@tonic-gate }
4870Sstevel@tonic-gate
4880Sstevel@tonic-gate switch (instr) {
4890Sstevel@tonic-gate case M_SYSRET:
4900Sstevel@tonic-gate warn("sysret cannot be stepped\n");
4910Sstevel@tonic-gate return (set_errno(EMDB_TGTNOTSUP));
4920Sstevel@tonic-gate case M_SYSEXIT:
4930Sstevel@tonic-gate warn("sysexit cannot be stepped\n");
4940Sstevel@tonic-gate return (set_errno(EMDB_TGTNOTSUP));
4950Sstevel@tonic-gate }
4960Sstevel@tonic-gate break;
4970Sstevel@tonic-gate
4980Sstevel@tonic-gate /*
4990Sstevel@tonic-gate * Some instructions need to be emulated. We need to prevent direct
5000Sstevel@tonic-gate * manipulations of EFLAGS, so we'll emulate cli, sti. pushfl and
5010Sstevel@tonic-gate * popfl also receive special handling, as they manipulate both EFLAGS
5020Sstevel@tonic-gate * and %esp.
5030Sstevel@tonic-gate */
5040Sstevel@tonic-gate case M_CLI:
5050Sstevel@tonic-gate (void) kmdb_dpi_get_register(FLAGS_REG_NAME, &fl);
5060Sstevel@tonic-gate fl &= ~KREG_EFLAGS_IF_MASK;
5070Sstevel@tonic-gate (void) kmdb_dpi_set_register(FLAGS_REG_NAME, fl);
5080Sstevel@tonic-gate
5090Sstevel@tonic-gate emulated = 1;
5100Sstevel@tonic-gate break;
5110Sstevel@tonic-gate
5120Sstevel@tonic-gate case M_STI:
5130Sstevel@tonic-gate (void) kmdb_dpi_get_register(FLAGS_REG_NAME, &fl);
5140Sstevel@tonic-gate fl |= (1 << KREG_EFLAGS_IF_SHIFT);
5150Sstevel@tonic-gate (void) kmdb_dpi_set_register(FLAGS_REG_NAME, fl);
5160Sstevel@tonic-gate
5170Sstevel@tonic-gate emulated = 1;
5180Sstevel@tonic-gate break;
5190Sstevel@tonic-gate
5200Sstevel@tonic-gate case M_POPF:
5210Sstevel@tonic-gate /*
5220Sstevel@tonic-gate * popfl will restore a pushed EFLAGS from the stack, and could
523*3446Smrj * in so doing cause IF to be turned on, if only for a brief
5240Sstevel@tonic-gate * period. To avoid this, we'll secretly replace the stack's
5250Sstevel@tonic-gate * EFLAGS with our decaffeinated brand. We'll then manually
5260Sstevel@tonic-gate * load our EFLAGS copy with the real verion after the step.
5270Sstevel@tonic-gate */
5280Sstevel@tonic-gate (void) kmdb_dpi_get_register("sp", &sp);
5290Sstevel@tonic-gate (void) kmdb_dpi_get_register(FLAGS_REG_NAME, &fl);
5300Sstevel@tonic-gate
5310Sstevel@tonic-gate if (mdb_tgt_vread(mdb.m_target, &newfl, sizeof (kreg_t),
5320Sstevel@tonic-gate sp) != sizeof (kreg_t)) {
5330Sstevel@tonic-gate warn("failed to read " FLAGS_REG_NAME
5340Sstevel@tonic-gate " at %p for popfl step\n", (void *)sp);
5350Sstevel@tonic-gate return (set_errno(EMDB_TGTNOTSUP)); /* XXX ? */
5360Sstevel@tonic-gate }
5370Sstevel@tonic-gate
5380Sstevel@tonic-gate fl = (fl & ~KREG_EFLAGS_IF_MASK) | KREG_EFLAGS_TF_MASK;
5390Sstevel@tonic-gate
5400Sstevel@tonic-gate if (mdb_tgt_vwrite(mdb.m_target, &fl, sizeof (kreg_t),
5410Sstevel@tonic-gate sp) != sizeof (kreg_t)) {
5420Sstevel@tonic-gate warn("failed to update " FLAGS_REG_NAME
5430Sstevel@tonic-gate " at %p for popfl step\n", (void *)sp);
5440Sstevel@tonic-gate return (set_errno(EMDB_TGTNOTSUP)); /* XXX ? */
5450Sstevel@tonic-gate }
5460Sstevel@tonic-gate break;
5470Sstevel@tonic-gate }
5480Sstevel@tonic-gate
5490Sstevel@tonic-gate if (emulated) {
5500Sstevel@tonic-gate (void) kmdb_dpi_set_register("pc", npc);
5510Sstevel@tonic-gate return (0);
5520Sstevel@tonic-gate }
5530Sstevel@tonic-gate
5540Sstevel@tonic-gate /* Do the step with IF off, and TF (step) on */
5550Sstevel@tonic-gate (void) kmdb_dpi_get_register(FLAGS_REG_NAME, &oldfl);
5560Sstevel@tonic-gate (void) kmdb_dpi_set_register(FLAGS_REG_NAME,
5570Sstevel@tonic-gate ((oldfl | (1 << KREG_EFLAGS_TF_SHIFT)) & ~KREG_EFLAGS_IF_MASK));
5580Sstevel@tonic-gate
5590Sstevel@tonic-gate kmdb_dpi_resume_master(); /* ... there and back again ... */
5600Sstevel@tonic-gate
5610Sstevel@tonic-gate /* EFLAGS has now changed, and may require tuning */
5620Sstevel@tonic-gate
5630Sstevel@tonic-gate switch (instr) {
5640Sstevel@tonic-gate case M_POPF:
5650Sstevel@tonic-gate /*
5660Sstevel@tonic-gate * Use the EFLAGS we grabbed before the pop - see the pre-step
5670Sstevel@tonic-gate * M_POPFL comment.
5680Sstevel@tonic-gate */
5690Sstevel@tonic-gate (void) kmdb_dpi_set_register(FLAGS_REG_NAME, newfl);
5700Sstevel@tonic-gate return (0);
5710Sstevel@tonic-gate
5720Sstevel@tonic-gate case M_PUSHF:
5730Sstevel@tonic-gate /*
5740Sstevel@tonic-gate * We pushed our modified EFLAGS (with IF and TF turned off)
5750Sstevel@tonic-gate * onto the stack. Replace the pushed version with our
5760Sstevel@tonic-gate * unmodified one.
5770Sstevel@tonic-gate */
5780Sstevel@tonic-gate (void) kmdb_dpi_get_register("sp", &sp);
5790Sstevel@tonic-gate
5800Sstevel@tonic-gate if (mdb_tgt_vwrite(mdb.m_target, &oldfl, sizeof (kreg_t),
5810Sstevel@tonic-gate sp) != sizeof (kreg_t)) {
5820Sstevel@tonic-gate warn("failed to update pushed " FLAGS_REG_NAME
5830Sstevel@tonic-gate " at %p after pushfl step\n", (void *)sp);
5840Sstevel@tonic-gate return (set_errno(EMDB_TGTNOTSUP)); /* XXX ? */
5850Sstevel@tonic-gate }
5860Sstevel@tonic-gate
5870Sstevel@tonic-gate /* Go back to using the EFLAGS we were using before the step */
5880Sstevel@tonic-gate (void) kmdb_dpi_set_register(FLAGS_REG_NAME, oldfl);
5890Sstevel@tonic-gate return (0);
5900Sstevel@tonic-gate
5910Sstevel@tonic-gate default:
5920Sstevel@tonic-gate /*
5930Sstevel@tonic-gate * The stepped instruction may have altered EFLAGS. We only
5940Sstevel@tonic-gate * really care about the value of IF, and we know the stepped
5950Sstevel@tonic-gate * instruction didn't alter it, so we can simply copy the
5960Sstevel@tonic-gate * pre-step value. We'll also need to turn TF back off.
5970Sstevel@tonic-gate */
5980Sstevel@tonic-gate (void) kmdb_dpi_get_register(FLAGS_REG_NAME, &fl);
5990Sstevel@tonic-gate (void) kmdb_dpi_set_register(FLAGS_REG_NAME,
6000Sstevel@tonic-gate ((fl & ~(KREG_EFLAGS_TF_MASK|KREG_EFLAGS_IF_MASK)) |
6010Sstevel@tonic-gate (oldfl & KREG_EFLAGS_IF_MASK)));
6020Sstevel@tonic-gate return (0);
6030Sstevel@tonic-gate }
6040Sstevel@tonic-gate }
6050Sstevel@tonic-gate
6060Sstevel@tonic-gate /*
6070Sstevel@tonic-gate * The target has already configured the chip for branch step, leaving us to
6080Sstevel@tonic-gate * actually make the machine go. Due to a number of issues involving
6090Sstevel@tonic-gate * the potential alteration of system state via instructions like sti, cli,
6100Sstevel@tonic-gate * pushfl, and popfl, we're going to treat this like a normal system resume.
6110Sstevel@tonic-gate * All CPUs will be released, on the kernel's IDT. Our primary concern is
6120Sstevel@tonic-gate * the alteration/storage of our TF'd EFLAGS via pushfl and popfl. There's no
6130Sstevel@tonic-gate * real workaround - we don't have opcode breakpoints - so the best we can do is
6140Sstevel@tonic-gate * to ensure that the world won't end if someone does bad things to EFLAGS.
6150Sstevel@tonic-gate *
6160Sstevel@tonic-gate * Two things can happen:
6170Sstevel@tonic-gate * 1. EFLAGS.TF may be cleared, either maliciously or via a popfl from saved
6180Sstevel@tonic-gate * state. The CPU will continue execution beyond the branch, and will not
6190Sstevel@tonic-gate * reenter the debugger unless brought/sent in by other means.
6200Sstevel@tonic-gate * 2. Someone may pushlf the TF'd EFLAGS, and may stash a copy of it somewhere.
6210Sstevel@tonic-gate * When the saved version is popfl'd back into place, the debugger will be
6220Sstevel@tonic-gate * re-entered on a single-step trap.
6230Sstevel@tonic-gate */
6240Sstevel@tonic-gate static void
kaif_step_branch(void)6250Sstevel@tonic-gate kaif_step_branch(void)
6260Sstevel@tonic-gate {
6270Sstevel@tonic-gate kreg_t fl;
6280Sstevel@tonic-gate
6290Sstevel@tonic-gate (void) kmdb_dpi_get_register(FLAGS_REG_NAME, &fl);
6300Sstevel@tonic-gate (void) kmdb_dpi_set_register(FLAGS_REG_NAME,
6310Sstevel@tonic-gate (fl | (1 << KREG_EFLAGS_TF_SHIFT)));
6320Sstevel@tonic-gate
6330Sstevel@tonic-gate kmdb_dpi_resume_master();
6340Sstevel@tonic-gate
6350Sstevel@tonic-gate (void) kmdb_dpi_set_register(FLAGS_REG_NAME, fl);
6360Sstevel@tonic-gate }
6370Sstevel@tonic-gate
6380Sstevel@tonic-gate /*ARGSUSED*/
6390Sstevel@tonic-gate static uintptr_t
kaif_call(uintptr_t funcva,uint_t argc,const uintptr_t argv[])6400Sstevel@tonic-gate kaif_call(uintptr_t funcva, uint_t argc, const uintptr_t argv[])
6410Sstevel@tonic-gate {
6420Sstevel@tonic-gate return (kaif_invoke(funcva, argc, argv));
6430Sstevel@tonic-gate }
6440Sstevel@tonic-gate
6450Sstevel@tonic-gate static void
dump_crumb(kdi_crumb_t * krmp)646*3446Smrj dump_crumb(kdi_crumb_t *krmp)
6470Sstevel@tonic-gate {
648*3446Smrj kdi_crumb_t krm;
6491234Sjohnlev
650*3446Smrj if (mdb_vread(&krm, sizeof (kdi_crumb_t), (uintptr_t)krmp) !=
651*3446Smrj sizeof (kdi_crumb_t)) {
6521234Sjohnlev warn("failed to read crumb at %p", krmp);
6531234Sjohnlev return;
6541234Sjohnlev }
6551234Sjohnlev
6560Sstevel@tonic-gate mdb_printf("state: ");
6571234Sjohnlev switch (krm.krm_cpu_state) {
6580Sstevel@tonic-gate case KAIF_CPU_STATE_MASTER:
6590Sstevel@tonic-gate mdb_printf("M");
6600Sstevel@tonic-gate break;
6610Sstevel@tonic-gate case KAIF_CPU_STATE_SLAVE:
6620Sstevel@tonic-gate mdb_printf("S");
6630Sstevel@tonic-gate break;
6640Sstevel@tonic-gate default:
6651234Sjohnlev mdb_printf("%d", krm.krm_cpu_state);
6660Sstevel@tonic-gate }
6670Sstevel@tonic-gate
6680Sstevel@tonic-gate mdb_printf(" trapno %3d sp %08x flag %d pc %p %A\n",
6691234Sjohnlev krm.krm_trapno, krm.krm_sp, krm.krm_flag, krm.krm_pc, krm.krm_pc);
6700Sstevel@tonic-gate }
6710Sstevel@tonic-gate
6720Sstevel@tonic-gate static void
dump_crumbs(kaif_cpusave_t * save)6730Sstevel@tonic-gate dump_crumbs(kaif_cpusave_t *save)
6740Sstevel@tonic-gate {
6750Sstevel@tonic-gate int i;
6760Sstevel@tonic-gate
677*3446Smrj for (i = KDI_NCRUMBS; i > 0; i--) {
678*3446Smrj uint_t idx = (save->krs_curcrumbidx + i) % KDI_NCRUMBS;
6790Sstevel@tonic-gate dump_crumb(&save->krs_crumbs[idx]);
6800Sstevel@tonic-gate }
6810Sstevel@tonic-gate }
6820Sstevel@tonic-gate
6830Sstevel@tonic-gate static void
kaif_dump_crumbs(uintptr_t addr,int cpuid)6840Sstevel@tonic-gate kaif_dump_crumbs(uintptr_t addr, int cpuid)
6850Sstevel@tonic-gate {
6860Sstevel@tonic-gate int i;
6870Sstevel@tonic-gate
6880Sstevel@tonic-gate if (addr != NULL) {
6891234Sjohnlev /* dump_crumb will protect us against bogus addresses */
690*3446Smrj dump_crumb((kdi_crumb_t *)addr);
6910Sstevel@tonic-gate
6920Sstevel@tonic-gate } else if (cpuid != -1) {
6931234Sjohnlev if (cpuid < 0 || cpuid >= kaif_ncpusave)
6940Sstevel@tonic-gate return;
6950Sstevel@tonic-gate
6960Sstevel@tonic-gate dump_crumbs(&kaif_cpusave[cpuid]);
6970Sstevel@tonic-gate
6980Sstevel@tonic-gate } else {
6990Sstevel@tonic-gate for (i = 0; i < kaif_ncpusave; i++) {
7000Sstevel@tonic-gate kaif_cpusave_t *save = &kaif_cpusave[i];
7010Sstevel@tonic-gate
7020Sstevel@tonic-gate if (save->krs_cpu_state == KAIF_CPU_STATE_NONE)
7030Sstevel@tonic-gate continue;
7040Sstevel@tonic-gate
7050Sstevel@tonic-gate mdb_printf("%sCPU %d crumbs: (curidx %d)\n",
7060Sstevel@tonic-gate (i == 0 ? "" : "\n"), i, save->krs_curcrumbidx);
7070Sstevel@tonic-gate
7080Sstevel@tonic-gate dump_crumbs(save);
7090Sstevel@tonic-gate }
7100Sstevel@tonic-gate }
7110Sstevel@tonic-gate }
7120Sstevel@tonic-gate
7130Sstevel@tonic-gate static void
kaif_modchg_register(void (* func)(struct modctl *,int))7140Sstevel@tonic-gate kaif_modchg_register(void (*func)(struct modctl *, int))
7150Sstevel@tonic-gate {
7160Sstevel@tonic-gate kaif_modchg_cb = func;
7170Sstevel@tonic-gate }
7180Sstevel@tonic-gate
7190Sstevel@tonic-gate static void
kaif_modchg_cancel(void)7200Sstevel@tonic-gate kaif_modchg_cancel(void)
7210Sstevel@tonic-gate {
7220Sstevel@tonic-gate ASSERT(kaif_modchg_cb != NULL);
7230Sstevel@tonic-gate
7240Sstevel@tonic-gate kaif_modchg_cb = NULL;
7250Sstevel@tonic-gate }
7260Sstevel@tonic-gate
727*3446Smrj static void
kaif_msr_add(const kdi_msr_t * msrs)728*3446Smrj kaif_msr_add(const kdi_msr_t *msrs)
729*3446Smrj {
730*3446Smrj kdi_msr_t *save;
731*3446Smrj size_t nr_msrs = 0;
732*3446Smrj size_t i;
733*3446Smrj
734*3446Smrj while (msrs[nr_msrs].msr_num != 0)
735*3446Smrj nr_msrs++;
736*3446Smrj /* we want to copy the terminating kdi_msr_t too */
737*3446Smrj nr_msrs++;
738*3446Smrj
739*3446Smrj save = mdb_zalloc(sizeof (kdi_msr_t) * nr_msrs * kaif_ncpusave,
740*3446Smrj UM_SLEEP);
741*3446Smrj
742*3446Smrj for (i = 0; i < kaif_ncpusave; i++)
743*3446Smrj bcopy(msrs, &save[nr_msrs * i], sizeof (kdi_msr_t) * nr_msrs);
744*3446Smrj
745*3446Smrj kmdb_kdi_set_debug_msrs(save);
746*3446Smrj }
747*3446Smrj
748*3446Smrj static uint64_t
kaif_msr_get(int cpuid,uint_t num)749*3446Smrj kaif_msr_get(int cpuid, uint_t num)
750*3446Smrj {
751*3446Smrj kdi_cpusave_t *save;
752*3446Smrj kdi_msr_t *msr;
753*3446Smrj int i;
754*3446Smrj
755*3446Smrj if ((save = kaif_cpuid2save(cpuid)) == NULL)
756*3446Smrj return (-1); /* errno is set for us */
757*3446Smrj
758*3446Smrj msr = save->krs_msr;
759*3446Smrj
760*3446Smrj for (i = 0; msr[i].msr_num != 0; i++) {
761*3446Smrj if (msr[i].msr_num == num && (msr[i].msr_type & KDI_MSR_READ))
762*3446Smrj return (msr[i].kdi_msr_val);
763*3446Smrj }
764*3446Smrj
765*3446Smrj return (0);
766*3446Smrj }
767*3446Smrj
768*3446Smrj void
kaif_trap_set_debugger(void)769*3446Smrj kaif_trap_set_debugger(void)
770*3446Smrj {
771*3446Smrj kmdb_kdi_idt_switch(NULL);
772*3446Smrj }
773*3446Smrj
774*3446Smrj void
kaif_trap_set_saved(kaif_cpusave_t * cpusave)775*3446Smrj kaif_trap_set_saved(kaif_cpusave_t *cpusave)
776*3446Smrj {
777*3446Smrj kmdb_kdi_idt_switch(cpusave);
778*3446Smrj }
779*3446Smrj
780*3446Smrj static void
kaif_vmready(void)781*3446Smrj kaif_vmready(void)
782*3446Smrj {
783*3446Smrj }
784*3446Smrj
785*3446Smrj void
kaif_memavail(caddr_t base,size_t len)786*3446Smrj kaif_memavail(caddr_t base, size_t len)
787*3446Smrj {
788*3446Smrj int ret;
789*3446Smrj /*
790*3446Smrj * In the unlikely event that someone is stepping through this routine,
791*3446Smrj * we need to make sure that the KDI knows about the new range before
792*3446Smrj * umem gets it. That way the entry code can recognize stacks
793*3446Smrj * allocated from the new region.
794*3446Smrj */
795*3446Smrj kmdb_kdi_memrange_add(base, len);
796*3446Smrj ret = mdb_umem_add(base, len);
797*3446Smrj ASSERT(ret == 0);
798*3446Smrj }
799*3446Smrj
8000Sstevel@tonic-gate void
kaif_mod_loaded(struct modctl * modp)8010Sstevel@tonic-gate kaif_mod_loaded(struct modctl *modp)
8020Sstevel@tonic-gate {
8030Sstevel@tonic-gate if (kaif_modchg_cb != NULL)
8040Sstevel@tonic-gate kaif_modchg_cb(modp, 1);
8050Sstevel@tonic-gate }
8060Sstevel@tonic-gate
8070Sstevel@tonic-gate void
kaif_mod_unloading(struct modctl * modp)8080Sstevel@tonic-gate kaif_mod_unloading(struct modctl *modp)
8090Sstevel@tonic-gate {
8100Sstevel@tonic-gate if (kaif_modchg_cb != NULL)
8110Sstevel@tonic-gate kaif_modchg_cb(modp, 0);
8120Sstevel@tonic-gate }
8130Sstevel@tonic-gate
814*3446Smrj void
kaif_handle_fault(greg_t trapno,greg_t pc,greg_t sp,int cpuid)815*3446Smrj kaif_handle_fault(greg_t trapno, greg_t pc, greg_t sp, int cpuid)
8160Sstevel@tonic-gate {
817*3446Smrj kmdb_dpi_handle_fault((kreg_t)trapno, (kreg_t)pc,
818*3446Smrj (kreg_t)sp, cpuid);
8190Sstevel@tonic-gate }
8200Sstevel@tonic-gate
821*3446Smrj static kdi_debugvec_t kaif_dvec = {
822*3446Smrj NULL, /* dv_kctl_vmready */
823*3446Smrj NULL, /* dv_kctl_memavail */
824*3446Smrj NULL, /* dv_kctl_modavail */
825*3446Smrj NULL, /* dv_kctl_thravail */
826*3446Smrj kaif_vmready,
827*3446Smrj kaif_memavail,
828*3446Smrj kaif_mod_loaded,
829*3446Smrj kaif_mod_unloading,
830*3446Smrj kaif_handle_fault
831*3446Smrj };
8320Sstevel@tonic-gate
833*3446Smrj void
kaif_kdi_entry(kdi_cpusave_t * cpusave)834*3446Smrj kaif_kdi_entry(kdi_cpusave_t *cpusave)
835*3446Smrj {
836*3446Smrj int ret = kaif_main_loop(cpusave);
837*3446Smrj ASSERT(ret == KAIF_CPU_CMD_RESUME ||
838*3446Smrj ret == KAIF_CPU_CMD_RESUME_MASTER);
8390Sstevel@tonic-gate }
8400Sstevel@tonic-gate
841*3446Smrj /*ARGSUSED*/
842*3446Smrj void
kaif_activate(kdi_debugvec_t ** dvecp,uint_t flags)843*3446Smrj kaif_activate(kdi_debugvec_t **dvecp, uint_t flags)
8440Sstevel@tonic-gate {
845*3446Smrj kmdb_kdi_activate(kaif_kdi_entry, kaif_cpusave, kaif_ncpusave);
846*3446Smrj *dvecp = &kaif_dvec;
8470Sstevel@tonic-gate }
8480Sstevel@tonic-gate
8490Sstevel@tonic-gate static int
kaif_init(kmdb_auxv_t * kav)8500Sstevel@tonic-gate kaif_init(kmdb_auxv_t *kav)
8510Sstevel@tonic-gate {
8520Sstevel@tonic-gate /* Allocate the per-CPU save areas */
8530Sstevel@tonic-gate kaif_cpusave = mdb_zalloc(sizeof (kaif_cpusave_t) * kav->kav_ncpu,
8540Sstevel@tonic-gate UM_SLEEP);
8550Sstevel@tonic-gate kaif_ncpusave = kav->kav_ncpu;
8560Sstevel@tonic-gate
8570Sstevel@tonic-gate kaif_modchg_cb = NULL;
8580Sstevel@tonic-gate
8590Sstevel@tonic-gate kaif_waptmap = 0;
8600Sstevel@tonic-gate
8610Sstevel@tonic-gate kaif_trap_switch = (kav->kav_flags & KMDB_AUXV_FL_NOTRPSWTCH) == 0;
8620Sstevel@tonic-gate
8630Sstevel@tonic-gate return (0);
8640Sstevel@tonic-gate }
8650Sstevel@tonic-gate
8660Sstevel@tonic-gate dpi_ops_t kmdb_dpi_ops = {
8670Sstevel@tonic-gate kaif_init,
8680Sstevel@tonic-gate kaif_activate,
869*3446Smrj kmdb_kdi_deactivate,
8700Sstevel@tonic-gate kaif_enter_mon,
8710Sstevel@tonic-gate kaif_modchg_register,
8720Sstevel@tonic-gate kaif_modchg_cancel,
8730Sstevel@tonic-gate kaif_get_cpu_state,
8740Sstevel@tonic-gate kaif_get_master_cpuid,
8750Sstevel@tonic-gate kaif_get_gregs,
8761234Sjohnlev kaif_get_register,
8771234Sjohnlev kaif_set_register,
8780Sstevel@tonic-gate kaif_brkpt_arm,
8790Sstevel@tonic-gate kaif_brkpt_disarm,
8800Sstevel@tonic-gate kaif_wapt_validate,
8810Sstevel@tonic-gate kaif_wapt_reserve,
8820Sstevel@tonic-gate kaif_wapt_release,
8830Sstevel@tonic-gate kaif_wapt_arm,
8840Sstevel@tonic-gate kaif_wapt_disarm,
8850Sstevel@tonic-gate kaif_wapt_match,
8860Sstevel@tonic-gate kaif_step,
8870Sstevel@tonic-gate kaif_step_branch,
8880Sstevel@tonic-gate kaif_call,
8890Sstevel@tonic-gate kaif_dump_crumbs,
8900Sstevel@tonic-gate kaif_msr_add,
8910Sstevel@tonic-gate kaif_msr_get,
8920Sstevel@tonic-gate };
893