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
5c7bf3205Sjohnlev * Common Development and Distribution License (the "License").
6c7bf3205Sjohnlev * 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 * The debugger/"PROM" interface layer
307c478bd9Sstevel@tonic-gate *
31*ae115bc7Smrj * It makes more sense on SPARC. In reality, these interfaces deal with three
32*ae115bc7Smrj * things: setting break/watchpoints, stepping, and interfacing with the KDI to
33*ae115bc7Smrj * set up kmdb's IDT handlers.
347c478bd9Sstevel@tonic-gate */
357c478bd9Sstevel@tonic-gate
367c478bd9Sstevel@tonic-gate #include <kmdb/kmdb_dpi_impl.h>
377c478bd9Sstevel@tonic-gate #include <kmdb/kmdb_kdi.h>
387c478bd9Sstevel@tonic-gate #include <kmdb/kmdb_umemglue.h>
397c478bd9Sstevel@tonic-gate #include <kmdb/kaif.h>
40c7bf3205Sjohnlev #include <kmdb/kmdb_io.h>
41*ae115bc7Smrj #include <kmdb/kaif_start.h>
427c478bd9Sstevel@tonic-gate #include <mdb/mdb_err.h>
437c478bd9Sstevel@tonic-gate #include <mdb/mdb_debug.h>
447c478bd9Sstevel@tonic-gate #include <mdb/mdb_isautil.h>
457c478bd9Sstevel@tonic-gate #include <mdb/mdb_io_impl.h>
46*ae115bc7Smrj #include <mdb/mdb_kreg_impl.h>
477c478bd9Sstevel@tonic-gate #include <mdb/mdb.h>
487c478bd9Sstevel@tonic-gate
497c478bd9Sstevel@tonic-gate #include <sys/types.h>
507c478bd9Sstevel@tonic-gate #include <sys/bitmap.h>
51c7bf3205Sjohnlev #include <sys/termios.h>
52*ae115bc7Smrj #include <sys/kdi_impl.h>
537c478bd9Sstevel@tonic-gate
54*ae115bc7Smrj /*
55*ae115bc7Smrj * This is the area containing the saved state when we enter
56*ae115bc7Smrj * via kmdb's IDT entries.
57*ae115bc7Smrj */
58*ae115bc7Smrj kdi_cpusave_t *kaif_cpusave;
597c478bd9Sstevel@tonic-gate int kaif_ncpusave;
60*ae115bc7Smrj kdi_drreg_t kaif_drreg;
617c478bd9Sstevel@tonic-gate
627c478bd9Sstevel@tonic-gate uint32_t kaif_waptmap;
637c478bd9Sstevel@tonic-gate
647c478bd9Sstevel@tonic-gate int kaif_trap_switch;
657c478bd9Sstevel@tonic-gate
667c478bd9Sstevel@tonic-gate void (*kaif_modchg_cb)(struct modctl *, int);
677c478bd9Sstevel@tonic-gate
687c478bd9Sstevel@tonic-gate enum {
697c478bd9Sstevel@tonic-gate M_SYSRET = 0x07, /* after M_ESC */
707c478bd9Sstevel@tonic-gate M_ESC = 0x0f,
717c478bd9Sstevel@tonic-gate M_SYSEXIT = 0x35, /* after M_ESC */
727c478bd9Sstevel@tonic-gate M_REX_LO = 0x40, /* first REX prefix */
737c478bd9Sstevel@tonic-gate M_REX_HI = 0x4f, /* last REX prefix */
747c478bd9Sstevel@tonic-gate M_PUSHF = 0x9c, /* pushfl and pushfq */
757c478bd9Sstevel@tonic-gate M_POPF = 0x9d, /* popfl and popfq */
767c478bd9Sstevel@tonic-gate M_INT3 = 0xcc,
777c478bd9Sstevel@tonic-gate M_INTX = 0xcd,
787c478bd9Sstevel@tonic-gate M_INTO = 0xce,
797c478bd9Sstevel@tonic-gate M_IRET = 0xcf,
807c478bd9Sstevel@tonic-gate M_CLI = 0xfa,
817c478bd9Sstevel@tonic-gate M_STI = 0xfb
827c478bd9Sstevel@tonic-gate };
837c478bd9Sstevel@tonic-gate
847c478bd9Sstevel@tonic-gate #define KAIF_BREAKPOINT_INSTR M_INT3
857c478bd9Sstevel@tonic-gate
867c478bd9Sstevel@tonic-gate #define KAIF_WPPRIV2ID(wp) (int)(uintptr_t)((wp)->wp_priv)
877c478bd9Sstevel@tonic-gate
887c478bd9Sstevel@tonic-gate #ifdef __amd64
897c478bd9Sstevel@tonic-gate #define FLAGS_REG_NAME "rflags"
907c478bd9Sstevel@tonic-gate #else
917c478bd9Sstevel@tonic-gate #define FLAGS_REG_NAME "eflags"
927c478bd9Sstevel@tonic-gate #endif
937c478bd9Sstevel@tonic-gate
947c478bd9Sstevel@tonic-gate /*
957c478bd9Sstevel@tonic-gate * Called during normal debugger operation and during debugger faults.
967c478bd9Sstevel@tonic-gate */
977c478bd9Sstevel@tonic-gate static void
kaif_enter_mon(void)987c478bd9Sstevel@tonic-gate kaif_enter_mon(void)
997c478bd9Sstevel@tonic-gate {
1007c478bd9Sstevel@tonic-gate char c;
1017c478bd9Sstevel@tonic-gate
1027c478bd9Sstevel@tonic-gate for (;;) {
1037c478bd9Sstevel@tonic-gate mdb_iob_printf(mdb.m_out,
1047c478bd9Sstevel@tonic-gate "%s: Do you really want to reboot? (y/n) ",
1057c478bd9Sstevel@tonic-gate mdb.m_pname);
1067c478bd9Sstevel@tonic-gate mdb_iob_flush(mdb.m_out);
107c7bf3205Sjohnlev mdb_iob_clearlines(mdb.m_out);
1087c478bd9Sstevel@tonic-gate
109c7bf3205Sjohnlev c = kmdb_getchar();
1107c478bd9Sstevel@tonic-gate
111c7bf3205Sjohnlev if (c == 'n' || c == 'N' || c == CTRL('c'))
1127c478bd9Sstevel@tonic-gate return;
1137c478bd9Sstevel@tonic-gate else if (c == 'y' || c == 'Y') {
1147c478bd9Sstevel@tonic-gate mdb_iob_printf(mdb.m_out, "Rebooting...\n");
1157c478bd9Sstevel@tonic-gate
1167c478bd9Sstevel@tonic-gate kmdb_dpi_reboot();
1177c478bd9Sstevel@tonic-gate }
1187c478bd9Sstevel@tonic-gate }
1197c478bd9Sstevel@tonic-gate }
1207c478bd9Sstevel@tonic-gate
121acbc304dSjohnlev static kaif_cpusave_t *
kaif_cpuid2save(int cpuid)122acbc304dSjohnlev kaif_cpuid2save(int cpuid)
123acbc304dSjohnlev {
124acbc304dSjohnlev kaif_cpusave_t *save;
125acbc304dSjohnlev
126acbc304dSjohnlev if (cpuid == DPI_MASTER_CPUID)
127acbc304dSjohnlev return (&kaif_cpusave[kaif_master_cpuid]);
128acbc304dSjohnlev
129acbc304dSjohnlev if (cpuid < 0 || cpuid >= kaif_ncpusave) {
130acbc304dSjohnlev (void) set_errno(EINVAL);
131acbc304dSjohnlev return (NULL);
132acbc304dSjohnlev }
133acbc304dSjohnlev
134acbc304dSjohnlev save = &kaif_cpusave[cpuid];
135acbc304dSjohnlev
136acbc304dSjohnlev if (save->krs_cpu_state != KAIF_CPU_STATE_MASTER &&
137acbc304dSjohnlev save->krs_cpu_state != KAIF_CPU_STATE_SLAVE) {
138acbc304dSjohnlev (void) set_errno(EINVAL);
139acbc304dSjohnlev return (NULL);
140acbc304dSjohnlev }
141acbc304dSjohnlev
142acbc304dSjohnlev return (save);
143acbc304dSjohnlev }
144acbc304dSjohnlev
1457c478bd9Sstevel@tonic-gate static int
kaif_get_cpu_state(int cpuid)1467c478bd9Sstevel@tonic-gate kaif_get_cpu_state(int cpuid)
1477c478bd9Sstevel@tonic-gate {
148acbc304dSjohnlev kaif_cpusave_t *save;
1497c478bd9Sstevel@tonic-gate
150acbc304dSjohnlev if ((save = kaif_cpuid2save(cpuid)) == NULL)
151acbc304dSjohnlev return (-1); /* errno is set for us */
1527c478bd9Sstevel@tonic-gate
153acbc304dSjohnlev switch (save->krs_cpu_state) {
1547c478bd9Sstevel@tonic-gate case KAIF_CPU_STATE_MASTER:
1557c478bd9Sstevel@tonic-gate return (DPI_CPU_STATE_MASTER);
1567c478bd9Sstevel@tonic-gate case KAIF_CPU_STATE_SLAVE:
1577c478bd9Sstevel@tonic-gate return (DPI_CPU_STATE_SLAVE);
1587c478bd9Sstevel@tonic-gate default:
1597c478bd9Sstevel@tonic-gate return (set_errno(EINVAL));
1607c478bd9Sstevel@tonic-gate }
1617c478bd9Sstevel@tonic-gate }
1627c478bd9Sstevel@tonic-gate
1637c478bd9Sstevel@tonic-gate static int
kaif_get_master_cpuid(void)1647c478bd9Sstevel@tonic-gate kaif_get_master_cpuid(void)
1657c478bd9Sstevel@tonic-gate {
1667c478bd9Sstevel@tonic-gate return (kaif_master_cpuid);
1677c478bd9Sstevel@tonic-gate }
1687c478bd9Sstevel@tonic-gate
169*ae115bc7Smrj static mdb_tgt_gregset_t *
kaif_kdi_to_gregs(int cpuid)170*ae115bc7Smrj kaif_kdi_to_gregs(int cpuid)
1717c478bd9Sstevel@tonic-gate {
172acbc304dSjohnlev kaif_cpusave_t *save;
1737c478bd9Sstevel@tonic-gate
174acbc304dSjohnlev if ((save = kaif_cpuid2save(cpuid)) == NULL)
175acbc304dSjohnlev return (NULL); /* errno is set for us */
1767c478bd9Sstevel@tonic-gate
177*ae115bc7Smrj /*
178*ae115bc7Smrj * The saved registers are actually identical to an mdb_tgt_gregset,
179*ae115bc7Smrj * so we can directly cast here.
180*ae115bc7Smrj */
181*ae115bc7Smrj return ((mdb_tgt_gregset_t *)save->krs_gregs);
182*ae115bc7Smrj }
183*ae115bc7Smrj
184*ae115bc7Smrj static const mdb_tgt_gregset_t *
kaif_get_gregs(int cpuid)185*ae115bc7Smrj kaif_get_gregs(int cpuid)
186*ae115bc7Smrj {
187*ae115bc7Smrj return (kaif_kdi_to_gregs(cpuid));
1887c478bd9Sstevel@tonic-gate }
1897c478bd9Sstevel@tonic-gate
1907c478bd9Sstevel@tonic-gate typedef struct kaif_reg_synonyms {
1917c478bd9Sstevel@tonic-gate const char *rs_syn;
1927c478bd9Sstevel@tonic-gate const char *rs_name;
1937c478bd9Sstevel@tonic-gate } kaif_reg_synonyms_t;
1947c478bd9Sstevel@tonic-gate
1957c478bd9Sstevel@tonic-gate static kreg_t *
kaif_find_regp(const char * regname)196acbc304dSjohnlev kaif_find_regp(const char *regname)
1977c478bd9Sstevel@tonic-gate {
1987c478bd9Sstevel@tonic-gate static const kaif_reg_synonyms_t synonyms[] = {
1997c478bd9Sstevel@tonic-gate #ifdef __amd64
2007c478bd9Sstevel@tonic-gate { "pc", "rip" },
2017c478bd9Sstevel@tonic-gate { "sp", "rsp" },
2027c478bd9Sstevel@tonic-gate { "fp", "rbp" },
2037c478bd9Sstevel@tonic-gate #else
2047c478bd9Sstevel@tonic-gate { "pc", "eip" },
2057c478bd9Sstevel@tonic-gate { "sp", "esp" },
2067c478bd9Sstevel@tonic-gate { "fp", "ebp" },
2077c478bd9Sstevel@tonic-gate #endif
2087c478bd9Sstevel@tonic-gate { "tt", "trapno" }
2097c478bd9Sstevel@tonic-gate };
210*ae115bc7Smrj mdb_tgt_gregset_t *regs;
2117c478bd9Sstevel@tonic-gate int i;
2127c478bd9Sstevel@tonic-gate
213*ae115bc7Smrj if ((regs = kaif_kdi_to_gregs(DPI_MASTER_CPUID)) == NULL)
214*ae115bc7Smrj return (NULL);
2157c478bd9Sstevel@tonic-gate
2167c478bd9Sstevel@tonic-gate for (i = 0; i < sizeof (synonyms) / sizeof (synonyms[0]); i++) {
2177c478bd9Sstevel@tonic-gate if (strcmp(synonyms[i].rs_syn, regname) == 0)
2187c478bd9Sstevel@tonic-gate regname = synonyms[i].rs_name;
2197c478bd9Sstevel@tonic-gate }
2207c478bd9Sstevel@tonic-gate
2217c478bd9Sstevel@tonic-gate for (i = 0; mdb_isa_kregs[i].rd_name != NULL; i++) {
2227c478bd9Sstevel@tonic-gate const mdb_tgt_regdesc_t *rd = &mdb_isa_kregs[i];
2237c478bd9Sstevel@tonic-gate
2247c478bd9Sstevel@tonic-gate if (strcmp(rd->rd_name, regname) == 0)
225*ae115bc7Smrj return (®s->kregs[rd->rd_num]);
2267c478bd9Sstevel@tonic-gate }
2277c478bd9Sstevel@tonic-gate
2287c478bd9Sstevel@tonic-gate (void) set_errno(ENOENT);
2297c478bd9Sstevel@tonic-gate return (NULL);
2307c478bd9Sstevel@tonic-gate }
2317c478bd9Sstevel@tonic-gate
2327c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2337c478bd9Sstevel@tonic-gate static int
kaif_get_register(const char * regname,kreg_t * valp)234acbc304dSjohnlev kaif_get_register(const char *regname, kreg_t *valp)
2357c478bd9Sstevel@tonic-gate {
2367c478bd9Sstevel@tonic-gate kreg_t *regp;
2377c478bd9Sstevel@tonic-gate
238acbc304dSjohnlev if ((regp = kaif_find_regp(regname)) == NULL)
2397c478bd9Sstevel@tonic-gate return (-1);
2407c478bd9Sstevel@tonic-gate
2417c478bd9Sstevel@tonic-gate *valp = *regp;
2427c478bd9Sstevel@tonic-gate
2437c478bd9Sstevel@tonic-gate return (0);
2447c478bd9Sstevel@tonic-gate }
2457c478bd9Sstevel@tonic-gate
2467c478bd9Sstevel@tonic-gate static int
kaif_set_register(const char * regname,kreg_t val)247acbc304dSjohnlev kaif_set_register(const char *regname, kreg_t val)
2487c478bd9Sstevel@tonic-gate {
2497c478bd9Sstevel@tonic-gate kreg_t *regp;
2507c478bd9Sstevel@tonic-gate
251acbc304dSjohnlev if ((regp = kaif_find_regp(regname)) == NULL)
2527c478bd9Sstevel@tonic-gate return (-1);
2537c478bd9Sstevel@tonic-gate
2547c478bd9Sstevel@tonic-gate *regp = val;
2557c478bd9Sstevel@tonic-gate
2567c478bd9Sstevel@tonic-gate return (0);
2577c478bd9Sstevel@tonic-gate }
2587c478bd9Sstevel@tonic-gate
2597c478bd9Sstevel@tonic-gate static int
kaif_brkpt_arm(uintptr_t addr,mdb_instr_t * instrp)2607c478bd9Sstevel@tonic-gate kaif_brkpt_arm(uintptr_t addr, mdb_instr_t *instrp)
2617c478bd9Sstevel@tonic-gate {
2627c478bd9Sstevel@tonic-gate mdb_instr_t bkpt = KAIF_BREAKPOINT_INSTR;
2637c478bd9Sstevel@tonic-gate
2647c478bd9Sstevel@tonic-gate if (mdb_tgt_vread(mdb.m_target, instrp, sizeof (mdb_instr_t), addr) !=
2657c478bd9Sstevel@tonic-gate sizeof (mdb_instr_t))
2667c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */
2677c478bd9Sstevel@tonic-gate
2687c478bd9Sstevel@tonic-gate if (mdb_tgt_vwrite(mdb.m_target, &bkpt, sizeof (mdb_instr_t), addr) !=
2697c478bd9Sstevel@tonic-gate sizeof (mdb_instr_t))
2707c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */
2717c478bd9Sstevel@tonic-gate
2727c478bd9Sstevel@tonic-gate return (0);
2737c478bd9Sstevel@tonic-gate }
2747c478bd9Sstevel@tonic-gate
2757c478bd9Sstevel@tonic-gate static int
kaif_brkpt_disarm(uintptr_t addr,mdb_instr_t instrp)2767c478bd9Sstevel@tonic-gate kaif_brkpt_disarm(uintptr_t addr, mdb_instr_t instrp)
2777c478bd9Sstevel@tonic-gate {
2787c478bd9Sstevel@tonic-gate if (mdb_tgt_vwrite(mdb.m_target, &instrp, sizeof (mdb_instr_t), addr) !=
2797c478bd9Sstevel@tonic-gate sizeof (mdb_instr_t))
2807c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */
2817c478bd9Sstevel@tonic-gate
2827c478bd9Sstevel@tonic-gate return (0);
2837c478bd9Sstevel@tonic-gate }
2847c478bd9Sstevel@tonic-gate
2857c478bd9Sstevel@tonic-gate /*
2867c478bd9Sstevel@tonic-gate * Intel watchpoints are even more fun than SPARC ones. The Intel architecture
2877c478bd9Sstevel@tonic-gate * manuals refer to watchpoints as breakpoints. For consistency with the
2887c478bd9Sstevel@tonic-gate * terminology used in other portions of kmdb, we will, however, refer to them
2897c478bd9Sstevel@tonic-gate * as watchpoints.
2907c478bd9Sstevel@tonic-gate *
2917c478bd9Sstevel@tonic-gate * Execute, data write, I/O read/write, and data read/write watchpoints are
2927c478bd9Sstevel@tonic-gate * supported by the hardware. Execute watchpoints must be one byte in length,
2937c478bd9Sstevel@tonic-gate * and must be placed on the first byte of the instruction to be watched.
2947c478bd9Sstevel@tonic-gate * Lengths of other watchpoints are more varied.
2957c478bd9Sstevel@tonic-gate *
2967c478bd9Sstevel@tonic-gate * Given that we already have a breakpoint facility, and given the restrictions
2977c478bd9Sstevel@tonic-gate * placed on execute watchpoints, we're going to disallow the creation of
2987c478bd9Sstevel@tonic-gate * execute watchpoints. The others will be fully supported. See the Debugging
2997c478bd9Sstevel@tonic-gate * chapter in both the IA32 and AMD64 System Programming books for more details.
3007c478bd9Sstevel@tonic-gate */
3017c478bd9Sstevel@tonic-gate
3027c478bd9Sstevel@tonic-gate #ifdef __amd64
3037c478bd9Sstevel@tonic-gate #define WAPT_DATA_MAX_SIZE 8
3047c478bd9Sstevel@tonic-gate #define WAPT_DATA_SIZES_MSG "1, 2, 4, or 8"
3057c478bd9Sstevel@tonic-gate #else
3067c478bd9Sstevel@tonic-gate #define WAPT_DATA_MAX_SIZE 4
3077c478bd9Sstevel@tonic-gate #define WAPT_DATA_SIZES_MSG "1, 2, or 4"
3087c478bd9Sstevel@tonic-gate #endif
3097c478bd9Sstevel@tonic-gate
3107c478bd9Sstevel@tonic-gate static int
kaif_wapt_validate(kmdb_wapt_t * wp)3117c478bd9Sstevel@tonic-gate kaif_wapt_validate(kmdb_wapt_t *wp)
3127c478bd9Sstevel@tonic-gate {
3137c478bd9Sstevel@tonic-gate if (wp->wp_type == DPI_WAPT_TYPE_IO) {
3147c478bd9Sstevel@tonic-gate if (wp->wp_wflags != (MDB_TGT_WA_R | MDB_TGT_WA_W)) {
3157c478bd9Sstevel@tonic-gate warn("I/O port watchpoints must be read/write\n");
3167c478bd9Sstevel@tonic-gate return (set_errno(EINVAL));
3177c478bd9Sstevel@tonic-gate }
3187c478bd9Sstevel@tonic-gate
3197c478bd9Sstevel@tonic-gate if (wp->wp_size != 1 && wp->wp_size != 2 && wp->wp_size != 4) {
3207c478bd9Sstevel@tonic-gate warn("I/O watchpoint size must be 1, 2, or 4 bytes\n");
3217c478bd9Sstevel@tonic-gate return (set_errno(EINVAL));
3227c478bd9Sstevel@tonic-gate }
3237c478bd9Sstevel@tonic-gate
3247c478bd9Sstevel@tonic-gate } else if (wp->wp_type == DPI_WAPT_TYPE_PHYS) {
3257c478bd9Sstevel@tonic-gate warn("physical address watchpoints are not supported on this "
3267c478bd9Sstevel@tonic-gate "platform\n");
3277c478bd9Sstevel@tonic-gate return (set_errno(EMDB_TGTHWNOTSUP));
3287c478bd9Sstevel@tonic-gate
3297c478bd9Sstevel@tonic-gate } else {
3307c478bd9Sstevel@tonic-gate if (wp->wp_wflags != (MDB_TGT_WA_R | MDB_TGT_WA_W) &&
3317c478bd9Sstevel@tonic-gate wp->wp_wflags != MDB_TGT_WA_W) {
3327c478bd9Sstevel@tonic-gate warn("watchpoints must be read/write or write-only\n");
3337c478bd9Sstevel@tonic-gate return (set_errno(EINVAL));
3347c478bd9Sstevel@tonic-gate }
3357c478bd9Sstevel@tonic-gate
3367c478bd9Sstevel@tonic-gate if ((wp->wp_size & -(wp->wp_size)) != wp->wp_size ||
3377c478bd9Sstevel@tonic-gate wp->wp_size > WAPT_DATA_MAX_SIZE) {
3387c478bd9Sstevel@tonic-gate warn("data watchpoint size must be " WAPT_DATA_SIZES_MSG
3397c478bd9Sstevel@tonic-gate " bytes\n");
3407c478bd9Sstevel@tonic-gate return (set_errno(EINVAL));
3417c478bd9Sstevel@tonic-gate }
3427c478bd9Sstevel@tonic-gate
3437c478bd9Sstevel@tonic-gate }
3447c478bd9Sstevel@tonic-gate
3457c478bd9Sstevel@tonic-gate if (wp->wp_addr & (wp->wp_size - 1)) {
3467c478bd9Sstevel@tonic-gate warn("%lu-byte watchpoints must be %lu-byte aligned\n",
3477c478bd9Sstevel@tonic-gate (ulong_t)wp->wp_size, (ulong_t)wp->wp_size);
3487c478bd9Sstevel@tonic-gate return (set_errno(EINVAL));
3497c478bd9Sstevel@tonic-gate }
3507c478bd9Sstevel@tonic-gate
3517c478bd9Sstevel@tonic-gate return (0);
3527c478bd9Sstevel@tonic-gate }
3537c478bd9Sstevel@tonic-gate
3547c478bd9Sstevel@tonic-gate static int
kaif_wapt_reserve(kmdb_wapt_t * wp)3557c478bd9Sstevel@tonic-gate kaif_wapt_reserve(kmdb_wapt_t *wp)
3567c478bd9Sstevel@tonic-gate {
3577c478bd9Sstevel@tonic-gate int id;
3587c478bd9Sstevel@tonic-gate
359*ae115bc7Smrj for (id = 0; id <= KDI_MAXWPIDX; id++) {
3607c478bd9Sstevel@tonic-gate if (!BT_TEST(&kaif_waptmap, id)) {
3617c478bd9Sstevel@tonic-gate /* found one */
3627c478bd9Sstevel@tonic-gate BT_SET(&kaif_waptmap, id);
3637c478bd9Sstevel@tonic-gate wp->wp_priv = (void *)(uintptr_t)id;
3647c478bd9Sstevel@tonic-gate return (0);
3657c478bd9Sstevel@tonic-gate }
3667c478bd9Sstevel@tonic-gate }
3677c478bd9Sstevel@tonic-gate
3687c478bd9Sstevel@tonic-gate return (set_errno(EMDB_WPTOOMANY));
3697c478bd9Sstevel@tonic-gate }
3707c478bd9Sstevel@tonic-gate
3717c478bd9Sstevel@tonic-gate static void
kaif_wapt_release(kmdb_wapt_t * wp)3727c478bd9Sstevel@tonic-gate kaif_wapt_release(kmdb_wapt_t *wp)
3737c478bd9Sstevel@tonic-gate {
3747c478bd9Sstevel@tonic-gate int id = KAIF_WPPRIV2ID(wp);
3757c478bd9Sstevel@tonic-gate
3767c478bd9Sstevel@tonic-gate ASSERT(BT_TEST(&kaif_waptmap, id));
3777c478bd9Sstevel@tonic-gate BT_CLEAR(&kaif_waptmap, id);
3787c478bd9Sstevel@tonic-gate }
3797c478bd9Sstevel@tonic-gate
3807c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3817c478bd9Sstevel@tonic-gate static void
kaif_wapt_arm(kmdb_wapt_t * wp)3827c478bd9Sstevel@tonic-gate kaif_wapt_arm(kmdb_wapt_t *wp)
3837c478bd9Sstevel@tonic-gate {
3847c478bd9Sstevel@tonic-gate uint_t rw;
3857c478bd9Sstevel@tonic-gate int hwid = KAIF_WPPRIV2ID(wp);
3867c478bd9Sstevel@tonic-gate
3877c478bd9Sstevel@tonic-gate ASSERT(BT_TEST(&kaif_waptmap, hwid));
3887c478bd9Sstevel@tonic-gate
3897c478bd9Sstevel@tonic-gate if (wp->wp_type == DPI_WAPT_TYPE_IO)
3907c478bd9Sstevel@tonic-gate rw = KREG_DRCTL_WP_IORW;
3917c478bd9Sstevel@tonic-gate else if (wp->wp_wflags & MDB_TGT_WA_R)
3927c478bd9Sstevel@tonic-gate rw = KREG_DRCTL_WP_RW;
3937c478bd9Sstevel@tonic-gate else if (wp->wp_wflags & MDB_TGT_WA_X)
3947c478bd9Sstevel@tonic-gate rw = KREG_DRCTL_WP_EXEC;
3957c478bd9Sstevel@tonic-gate else
3967c478bd9Sstevel@tonic-gate rw = KREG_DRCTL_WP_WONLY;
3977c478bd9Sstevel@tonic-gate
3987c478bd9Sstevel@tonic-gate kaif_drreg.dr_addr[hwid] = wp->wp_addr;
3997c478bd9Sstevel@tonic-gate
4007c478bd9Sstevel@tonic-gate kaif_drreg.dr_ctl &= ~KREG_DRCTL_WP_MASK(hwid);
4017c478bd9Sstevel@tonic-gate kaif_drreg.dr_ctl |= KREG_DRCTL_WP_LENRW(hwid, wp->wp_size - 1, rw);
4027c478bd9Sstevel@tonic-gate kaif_drreg.dr_ctl |= KREG_DRCTL_WPEN(hwid);
403*ae115bc7Smrj kmdb_kdi_update_drreg(&kaif_drreg);
4047c478bd9Sstevel@tonic-gate }
4057c478bd9Sstevel@tonic-gate
4067c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4077c478bd9Sstevel@tonic-gate static void
kaif_wapt_disarm(kmdb_wapt_t * wp)4087c478bd9Sstevel@tonic-gate kaif_wapt_disarm(kmdb_wapt_t *wp)
4097c478bd9Sstevel@tonic-gate {
4107c478bd9Sstevel@tonic-gate int hwid = KAIF_WPPRIV2ID(wp);
4117c478bd9Sstevel@tonic-gate
4127c478bd9Sstevel@tonic-gate ASSERT(BT_TEST(&kaif_waptmap, hwid));
4137c478bd9Sstevel@tonic-gate
4147c478bd9Sstevel@tonic-gate kaif_drreg.dr_addr[hwid] = 0;
4157c478bd9Sstevel@tonic-gate kaif_drreg.dr_ctl &= ~(KREG_DRCTL_WP_MASK(hwid) |
4167c478bd9Sstevel@tonic-gate KREG_DRCTL_WPEN_MASK(hwid));
417*ae115bc7Smrj kmdb_kdi_update_drreg(&kaif_drreg);
4187c478bd9Sstevel@tonic-gate }
4197c478bd9Sstevel@tonic-gate
4207c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4217c478bd9Sstevel@tonic-gate static int
kaif_wapt_match(kmdb_wapt_t * wp)4227c478bd9Sstevel@tonic-gate kaif_wapt_match(kmdb_wapt_t *wp)
4237c478bd9Sstevel@tonic-gate {
4247c478bd9Sstevel@tonic-gate int hwid = KAIF_WPPRIV2ID(wp);
4257c478bd9Sstevel@tonic-gate uint32_t mask = KREG_DRSTAT_WP_MASK(hwid);
4267c478bd9Sstevel@tonic-gate int n = 0;
4277c478bd9Sstevel@tonic-gate int i;
4287c478bd9Sstevel@tonic-gate
4297c478bd9Sstevel@tonic-gate ASSERT(BT_TEST(&kaif_waptmap, hwid));
4307c478bd9Sstevel@tonic-gate
4317c478bd9Sstevel@tonic-gate for (i = 0; i < kaif_ncpusave; i++)
4327c478bd9Sstevel@tonic-gate n += (kaif_cpusave[i].krs_dr.dr_stat & mask) != 0;
4337c478bd9Sstevel@tonic-gate
4347c478bd9Sstevel@tonic-gate return (n);
4357c478bd9Sstevel@tonic-gate }
4367c478bd9Sstevel@tonic-gate
4377c478bd9Sstevel@tonic-gate static int
kaif_step(void)4387c478bd9Sstevel@tonic-gate kaif_step(void)
4397c478bd9Sstevel@tonic-gate {
4407c478bd9Sstevel@tonic-gate kreg_t pc, fl, oldfl, newfl, sp;
4417c478bd9Sstevel@tonic-gate mdb_tgt_addr_t npc;
4427c478bd9Sstevel@tonic-gate mdb_instr_t instr;
4437c478bd9Sstevel@tonic-gate int emulated = 0, rchk = 0;
4447c478bd9Sstevel@tonic-gate size_t pcoff = 0;
4457c478bd9Sstevel@tonic-gate
4467c478bd9Sstevel@tonic-gate (void) kmdb_dpi_get_register("pc", &pc);
4477c478bd9Sstevel@tonic-gate
4487c478bd9Sstevel@tonic-gate if ((npc = mdb_dis_nextins(mdb.m_disasm, mdb.m_target,
4497c478bd9Sstevel@tonic-gate MDB_TGT_AS_VIRT, pc)) == pc) {
4507c478bd9Sstevel@tonic-gate warn("failed to decode instruction at %a for step\n", pc);
4517c478bd9Sstevel@tonic-gate return (set_errno(EINVAL));
4527c478bd9Sstevel@tonic-gate }
4537c478bd9Sstevel@tonic-gate
4547c478bd9Sstevel@tonic-gate /*
4557c478bd9Sstevel@tonic-gate * Stepping behavior depends on the type of instruction. It does not
4567c478bd9Sstevel@tonic-gate * depend on the presence of a REX prefix, as the action we take for a
4577c478bd9Sstevel@tonic-gate * given instruction doesn't currently vary for 32-bit instructions
4587c478bd9Sstevel@tonic-gate * versus their 64-bit counterparts.
4597c478bd9Sstevel@tonic-gate */
4607c478bd9Sstevel@tonic-gate do {
4617c478bd9Sstevel@tonic-gate if (mdb_tgt_vread(mdb.m_target, &instr, sizeof (mdb_instr_t),
4627c478bd9Sstevel@tonic-gate pc + pcoff) != sizeof (mdb_instr_t)) {
4637c478bd9Sstevel@tonic-gate warn("failed to read at %p for step",
4647c478bd9Sstevel@tonic-gate (void *)(pc + pcoff));
4657c478bd9Sstevel@tonic-gate return (-1);
4667c478bd9Sstevel@tonic-gate }
4677c478bd9Sstevel@tonic-gate } while (pcoff++, (instr >= M_REX_LO && instr <= M_REX_HI && !rchk++));
4687c478bd9Sstevel@tonic-gate
4697c478bd9Sstevel@tonic-gate switch (instr) {
4707c478bd9Sstevel@tonic-gate case M_IRET:
4717c478bd9Sstevel@tonic-gate warn("iret cannot be stepped\n");
4727c478bd9Sstevel@tonic-gate return (set_errno(EMDB_TGTNOTSUP));
4737c478bd9Sstevel@tonic-gate
4747c478bd9Sstevel@tonic-gate case M_INT3:
4757c478bd9Sstevel@tonic-gate case M_INTX:
4767c478bd9Sstevel@tonic-gate case M_INTO:
4777c478bd9Sstevel@tonic-gate warn("int cannot be stepped\n");
4787c478bd9Sstevel@tonic-gate return (set_errno(EMDB_TGTNOTSUP));
4797c478bd9Sstevel@tonic-gate
4807c478bd9Sstevel@tonic-gate case M_ESC:
4817c478bd9Sstevel@tonic-gate if (mdb_tgt_vread(mdb.m_target, &instr, sizeof (mdb_instr_t),
4827c478bd9Sstevel@tonic-gate pc + pcoff) != sizeof (mdb_instr_t)) {
4837c478bd9Sstevel@tonic-gate warn("failed to read at %p for step",
4847c478bd9Sstevel@tonic-gate (void *)(pc + pcoff));
4857c478bd9Sstevel@tonic-gate return (-1);
4867c478bd9Sstevel@tonic-gate }
4877c478bd9Sstevel@tonic-gate
4887c478bd9Sstevel@tonic-gate switch (instr) {
4897c478bd9Sstevel@tonic-gate case M_SYSRET:
4907c478bd9Sstevel@tonic-gate warn("sysret cannot be stepped\n");
4917c478bd9Sstevel@tonic-gate return (set_errno(EMDB_TGTNOTSUP));
4927c478bd9Sstevel@tonic-gate case M_SYSEXIT:
4937c478bd9Sstevel@tonic-gate warn("sysexit cannot be stepped\n");
4947c478bd9Sstevel@tonic-gate return (set_errno(EMDB_TGTNOTSUP));
4957c478bd9Sstevel@tonic-gate }
4967c478bd9Sstevel@tonic-gate break;
4977c478bd9Sstevel@tonic-gate
4987c478bd9Sstevel@tonic-gate /*
4997c478bd9Sstevel@tonic-gate * Some instructions need to be emulated. We need to prevent direct
5007c478bd9Sstevel@tonic-gate * manipulations of EFLAGS, so we'll emulate cli, sti. pushfl and
5017c478bd9Sstevel@tonic-gate * popfl also receive special handling, as they manipulate both EFLAGS
5027c478bd9Sstevel@tonic-gate * and %esp.
5037c478bd9Sstevel@tonic-gate */
5047c478bd9Sstevel@tonic-gate case M_CLI:
5057c478bd9Sstevel@tonic-gate (void) kmdb_dpi_get_register(FLAGS_REG_NAME, &fl);
5067c478bd9Sstevel@tonic-gate fl &= ~KREG_EFLAGS_IF_MASK;
5077c478bd9Sstevel@tonic-gate (void) kmdb_dpi_set_register(FLAGS_REG_NAME, fl);
5087c478bd9Sstevel@tonic-gate
5097c478bd9Sstevel@tonic-gate emulated = 1;
5107c478bd9Sstevel@tonic-gate break;
5117c478bd9Sstevel@tonic-gate
5127c478bd9Sstevel@tonic-gate case M_STI:
5137c478bd9Sstevel@tonic-gate (void) kmdb_dpi_get_register(FLAGS_REG_NAME, &fl);
5147c478bd9Sstevel@tonic-gate fl |= (1 << KREG_EFLAGS_IF_SHIFT);
5157c478bd9Sstevel@tonic-gate (void) kmdb_dpi_set_register(FLAGS_REG_NAME, fl);
5167c478bd9Sstevel@tonic-gate
5177c478bd9Sstevel@tonic-gate emulated = 1;
5187c478bd9Sstevel@tonic-gate break;
5197c478bd9Sstevel@tonic-gate
5207c478bd9Sstevel@tonic-gate case M_POPF:
5217c478bd9Sstevel@tonic-gate /*
5227c478bd9Sstevel@tonic-gate * popfl will restore a pushed EFLAGS from the stack, and could
523*ae115bc7Smrj * in so doing cause IF to be turned on, if only for a brief
5247c478bd9Sstevel@tonic-gate * period. To avoid this, we'll secretly replace the stack's
5257c478bd9Sstevel@tonic-gate * EFLAGS with our decaffeinated brand. We'll then manually
5267c478bd9Sstevel@tonic-gate * load our EFLAGS copy with the real verion after the step.
5277c478bd9Sstevel@tonic-gate */
5287c478bd9Sstevel@tonic-gate (void) kmdb_dpi_get_register("sp", &sp);
5297c478bd9Sstevel@tonic-gate (void) kmdb_dpi_get_register(FLAGS_REG_NAME, &fl);
5307c478bd9Sstevel@tonic-gate
5317c478bd9Sstevel@tonic-gate if (mdb_tgt_vread(mdb.m_target, &newfl, sizeof (kreg_t),
5327c478bd9Sstevel@tonic-gate sp) != sizeof (kreg_t)) {
5337c478bd9Sstevel@tonic-gate warn("failed to read " FLAGS_REG_NAME
5347c478bd9Sstevel@tonic-gate " at %p for popfl step\n", (void *)sp);
5357c478bd9Sstevel@tonic-gate return (set_errno(EMDB_TGTNOTSUP)); /* XXX ? */
5367c478bd9Sstevel@tonic-gate }
5377c478bd9Sstevel@tonic-gate
5387c478bd9Sstevel@tonic-gate fl = (fl & ~KREG_EFLAGS_IF_MASK) | KREG_EFLAGS_TF_MASK;
5397c478bd9Sstevel@tonic-gate
5407c478bd9Sstevel@tonic-gate if (mdb_tgt_vwrite(mdb.m_target, &fl, sizeof (kreg_t),
5417c478bd9Sstevel@tonic-gate sp) != sizeof (kreg_t)) {
5427c478bd9Sstevel@tonic-gate warn("failed to update " FLAGS_REG_NAME
5437c478bd9Sstevel@tonic-gate " at %p for popfl step\n", (void *)sp);
5447c478bd9Sstevel@tonic-gate return (set_errno(EMDB_TGTNOTSUP)); /* XXX ? */
5457c478bd9Sstevel@tonic-gate }
5467c478bd9Sstevel@tonic-gate break;
5477c478bd9Sstevel@tonic-gate }
5487c478bd9Sstevel@tonic-gate
5497c478bd9Sstevel@tonic-gate if (emulated) {
5507c478bd9Sstevel@tonic-gate (void) kmdb_dpi_set_register("pc", npc);
5517c478bd9Sstevel@tonic-gate return (0);
5527c478bd9Sstevel@tonic-gate }
5537c478bd9Sstevel@tonic-gate
5547c478bd9Sstevel@tonic-gate /* Do the step with IF off, and TF (step) on */
5557c478bd9Sstevel@tonic-gate (void) kmdb_dpi_get_register(FLAGS_REG_NAME, &oldfl);
5567c478bd9Sstevel@tonic-gate (void) kmdb_dpi_set_register(FLAGS_REG_NAME,
5577c478bd9Sstevel@tonic-gate ((oldfl | (1 << KREG_EFLAGS_TF_SHIFT)) & ~KREG_EFLAGS_IF_MASK));
5587c478bd9Sstevel@tonic-gate
5597c478bd9Sstevel@tonic-gate kmdb_dpi_resume_master(); /* ... there and back again ... */
5607c478bd9Sstevel@tonic-gate
5617c478bd9Sstevel@tonic-gate /* EFLAGS has now changed, and may require tuning */
5627c478bd9Sstevel@tonic-gate
5637c478bd9Sstevel@tonic-gate switch (instr) {
5647c478bd9Sstevel@tonic-gate case M_POPF:
5657c478bd9Sstevel@tonic-gate /*
5667c478bd9Sstevel@tonic-gate * Use the EFLAGS we grabbed before the pop - see the pre-step
5677c478bd9Sstevel@tonic-gate * M_POPFL comment.
5687c478bd9Sstevel@tonic-gate */
5697c478bd9Sstevel@tonic-gate (void) kmdb_dpi_set_register(FLAGS_REG_NAME, newfl);
5707c478bd9Sstevel@tonic-gate return (0);
5717c478bd9Sstevel@tonic-gate
5727c478bd9Sstevel@tonic-gate case M_PUSHF:
5737c478bd9Sstevel@tonic-gate /*
5747c478bd9Sstevel@tonic-gate * We pushed our modified EFLAGS (with IF and TF turned off)
5757c478bd9Sstevel@tonic-gate * onto the stack. Replace the pushed version with our
5767c478bd9Sstevel@tonic-gate * unmodified one.
5777c478bd9Sstevel@tonic-gate */
5787c478bd9Sstevel@tonic-gate (void) kmdb_dpi_get_register("sp", &sp);
5797c478bd9Sstevel@tonic-gate
5807c478bd9Sstevel@tonic-gate if (mdb_tgt_vwrite(mdb.m_target, &oldfl, sizeof (kreg_t),
5817c478bd9Sstevel@tonic-gate sp) != sizeof (kreg_t)) {
5827c478bd9Sstevel@tonic-gate warn("failed to update pushed " FLAGS_REG_NAME
5837c478bd9Sstevel@tonic-gate " at %p after pushfl step\n", (void *)sp);
5847c478bd9Sstevel@tonic-gate return (set_errno(EMDB_TGTNOTSUP)); /* XXX ? */
5857c478bd9Sstevel@tonic-gate }
5867c478bd9Sstevel@tonic-gate
5877c478bd9Sstevel@tonic-gate /* Go back to using the EFLAGS we were using before the step */
5887c478bd9Sstevel@tonic-gate (void) kmdb_dpi_set_register(FLAGS_REG_NAME, oldfl);
5897c478bd9Sstevel@tonic-gate return (0);
5907c478bd9Sstevel@tonic-gate
5917c478bd9Sstevel@tonic-gate default:
5927c478bd9Sstevel@tonic-gate /*
5937c478bd9Sstevel@tonic-gate * The stepped instruction may have altered EFLAGS. We only
5947c478bd9Sstevel@tonic-gate * really care about the value of IF, and we know the stepped
5957c478bd9Sstevel@tonic-gate * instruction didn't alter it, so we can simply copy the
5967c478bd9Sstevel@tonic-gate * pre-step value. We'll also need to turn TF back off.
5977c478bd9Sstevel@tonic-gate */
5987c478bd9Sstevel@tonic-gate (void) kmdb_dpi_get_register(FLAGS_REG_NAME, &fl);
5997c478bd9Sstevel@tonic-gate (void) kmdb_dpi_set_register(FLAGS_REG_NAME,
6007c478bd9Sstevel@tonic-gate ((fl & ~(KREG_EFLAGS_TF_MASK|KREG_EFLAGS_IF_MASK)) |
6017c478bd9Sstevel@tonic-gate (oldfl & KREG_EFLAGS_IF_MASK)));
6027c478bd9Sstevel@tonic-gate return (0);
6037c478bd9Sstevel@tonic-gate }
6047c478bd9Sstevel@tonic-gate }
6057c478bd9Sstevel@tonic-gate
6067c478bd9Sstevel@tonic-gate /*
6077c478bd9Sstevel@tonic-gate * The target has already configured the chip for branch step, leaving us to
6087c478bd9Sstevel@tonic-gate * actually make the machine go. Due to a number of issues involving
6097c478bd9Sstevel@tonic-gate * the potential alteration of system state via instructions like sti, cli,
6107c478bd9Sstevel@tonic-gate * pushfl, and popfl, we're going to treat this like a normal system resume.
6117c478bd9Sstevel@tonic-gate * All CPUs will be released, on the kernel's IDT. Our primary concern is
6127c478bd9Sstevel@tonic-gate * the alteration/storage of our TF'd EFLAGS via pushfl and popfl. There's no
6137c478bd9Sstevel@tonic-gate * real workaround - we don't have opcode breakpoints - so the best we can do is
6147c478bd9Sstevel@tonic-gate * to ensure that the world won't end if someone does bad things to EFLAGS.
6157c478bd9Sstevel@tonic-gate *
6167c478bd9Sstevel@tonic-gate * Two things can happen:
6177c478bd9Sstevel@tonic-gate * 1. EFLAGS.TF may be cleared, either maliciously or via a popfl from saved
6187c478bd9Sstevel@tonic-gate * state. The CPU will continue execution beyond the branch, and will not
6197c478bd9Sstevel@tonic-gate * reenter the debugger unless brought/sent in by other means.
6207c478bd9Sstevel@tonic-gate * 2. Someone may pushlf the TF'd EFLAGS, and may stash a copy of it somewhere.
6217c478bd9Sstevel@tonic-gate * When the saved version is popfl'd back into place, the debugger will be
6227c478bd9Sstevel@tonic-gate * re-entered on a single-step trap.
6237c478bd9Sstevel@tonic-gate */
6247c478bd9Sstevel@tonic-gate static void
kaif_step_branch(void)6257c478bd9Sstevel@tonic-gate kaif_step_branch(void)
6267c478bd9Sstevel@tonic-gate {
6277c478bd9Sstevel@tonic-gate kreg_t fl;
6287c478bd9Sstevel@tonic-gate
6297c478bd9Sstevel@tonic-gate (void) kmdb_dpi_get_register(FLAGS_REG_NAME, &fl);
6307c478bd9Sstevel@tonic-gate (void) kmdb_dpi_set_register(FLAGS_REG_NAME,
6317c478bd9Sstevel@tonic-gate (fl | (1 << KREG_EFLAGS_TF_SHIFT)));
6327c478bd9Sstevel@tonic-gate
6337c478bd9Sstevel@tonic-gate kmdb_dpi_resume_master();
6347c478bd9Sstevel@tonic-gate
6357c478bd9Sstevel@tonic-gate (void) kmdb_dpi_set_register(FLAGS_REG_NAME, fl);
6367c478bd9Sstevel@tonic-gate }
6377c478bd9Sstevel@tonic-gate
6387c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6397c478bd9Sstevel@tonic-gate static uintptr_t
kaif_call(uintptr_t funcva,uint_t argc,const uintptr_t argv[])6407c478bd9Sstevel@tonic-gate kaif_call(uintptr_t funcva, uint_t argc, const uintptr_t argv[])
6417c478bd9Sstevel@tonic-gate {
6427c478bd9Sstevel@tonic-gate return (kaif_invoke(funcva, argc, argv));
6437c478bd9Sstevel@tonic-gate }
6447c478bd9Sstevel@tonic-gate
6457c478bd9Sstevel@tonic-gate static void
dump_crumb(kdi_crumb_t * krmp)646*ae115bc7Smrj dump_crumb(kdi_crumb_t *krmp)
6477c478bd9Sstevel@tonic-gate {
648*ae115bc7Smrj kdi_crumb_t krm;
649acbc304dSjohnlev
650*ae115bc7Smrj if (mdb_vread(&krm, sizeof (kdi_crumb_t), (uintptr_t)krmp) !=
651*ae115bc7Smrj sizeof (kdi_crumb_t)) {
652acbc304dSjohnlev warn("failed to read crumb at %p", krmp);
653acbc304dSjohnlev return;
654acbc304dSjohnlev }
655acbc304dSjohnlev
6567c478bd9Sstevel@tonic-gate mdb_printf("state: ");
657acbc304dSjohnlev switch (krm.krm_cpu_state) {
6587c478bd9Sstevel@tonic-gate case KAIF_CPU_STATE_MASTER:
6597c478bd9Sstevel@tonic-gate mdb_printf("M");
6607c478bd9Sstevel@tonic-gate break;
6617c478bd9Sstevel@tonic-gate case KAIF_CPU_STATE_SLAVE:
6627c478bd9Sstevel@tonic-gate mdb_printf("S");
6637c478bd9Sstevel@tonic-gate break;
6647c478bd9Sstevel@tonic-gate default:
665acbc304dSjohnlev mdb_printf("%d", krm.krm_cpu_state);
6667c478bd9Sstevel@tonic-gate }
6677c478bd9Sstevel@tonic-gate
6687c478bd9Sstevel@tonic-gate mdb_printf(" trapno %3d sp %08x flag %d pc %p %A\n",
669acbc304dSjohnlev krm.krm_trapno, krm.krm_sp, krm.krm_flag, krm.krm_pc, krm.krm_pc);
6707c478bd9Sstevel@tonic-gate }
6717c478bd9Sstevel@tonic-gate
6727c478bd9Sstevel@tonic-gate static void
dump_crumbs(kaif_cpusave_t * save)6737c478bd9Sstevel@tonic-gate dump_crumbs(kaif_cpusave_t *save)
6747c478bd9Sstevel@tonic-gate {
6757c478bd9Sstevel@tonic-gate int i;
6767c478bd9Sstevel@tonic-gate
677*ae115bc7Smrj for (i = KDI_NCRUMBS; i > 0; i--) {
678*ae115bc7Smrj uint_t idx = (save->krs_curcrumbidx + i) % KDI_NCRUMBS;
6797c478bd9Sstevel@tonic-gate dump_crumb(&save->krs_crumbs[idx]);
6807c478bd9Sstevel@tonic-gate }
6817c478bd9Sstevel@tonic-gate }
6827c478bd9Sstevel@tonic-gate
6837c478bd9Sstevel@tonic-gate static void
kaif_dump_crumbs(uintptr_t addr,int cpuid)6847c478bd9Sstevel@tonic-gate kaif_dump_crumbs(uintptr_t addr, int cpuid)
6857c478bd9Sstevel@tonic-gate {
6867c478bd9Sstevel@tonic-gate int i;
6877c478bd9Sstevel@tonic-gate
6887c478bd9Sstevel@tonic-gate if (addr != NULL) {
689acbc304dSjohnlev /* dump_crumb will protect us against bogus addresses */
690*ae115bc7Smrj dump_crumb((kdi_crumb_t *)addr);
6917c478bd9Sstevel@tonic-gate
6927c478bd9Sstevel@tonic-gate } else if (cpuid != -1) {
693acbc304dSjohnlev if (cpuid < 0 || cpuid >= kaif_ncpusave)
6947c478bd9Sstevel@tonic-gate return;
6957c478bd9Sstevel@tonic-gate
6967c478bd9Sstevel@tonic-gate dump_crumbs(&kaif_cpusave[cpuid]);
6977c478bd9Sstevel@tonic-gate
6987c478bd9Sstevel@tonic-gate } else {
6997c478bd9Sstevel@tonic-gate for (i = 0; i < kaif_ncpusave; i++) {
7007c478bd9Sstevel@tonic-gate kaif_cpusave_t *save = &kaif_cpusave[i];
7017c478bd9Sstevel@tonic-gate
7027c478bd9Sstevel@tonic-gate if (save->krs_cpu_state == KAIF_CPU_STATE_NONE)
7037c478bd9Sstevel@tonic-gate continue;
7047c478bd9Sstevel@tonic-gate
7057c478bd9Sstevel@tonic-gate mdb_printf("%sCPU %d crumbs: (curidx %d)\n",
7067c478bd9Sstevel@tonic-gate (i == 0 ? "" : "\n"), i, save->krs_curcrumbidx);
7077c478bd9Sstevel@tonic-gate
7087c478bd9Sstevel@tonic-gate dump_crumbs(save);
7097c478bd9Sstevel@tonic-gate }
7107c478bd9Sstevel@tonic-gate }
7117c478bd9Sstevel@tonic-gate }
7127c478bd9Sstevel@tonic-gate
7137c478bd9Sstevel@tonic-gate static void
kaif_modchg_register(void (* func)(struct modctl *,int))7147c478bd9Sstevel@tonic-gate kaif_modchg_register(void (*func)(struct modctl *, int))
7157c478bd9Sstevel@tonic-gate {
7167c478bd9Sstevel@tonic-gate kaif_modchg_cb = func;
7177c478bd9Sstevel@tonic-gate }
7187c478bd9Sstevel@tonic-gate
7197c478bd9Sstevel@tonic-gate static void
kaif_modchg_cancel(void)7207c478bd9Sstevel@tonic-gate kaif_modchg_cancel(void)
7217c478bd9Sstevel@tonic-gate {
7227c478bd9Sstevel@tonic-gate ASSERT(kaif_modchg_cb != NULL);
7237c478bd9Sstevel@tonic-gate
7247c478bd9Sstevel@tonic-gate kaif_modchg_cb = NULL;
7257c478bd9Sstevel@tonic-gate }
7267c478bd9Sstevel@tonic-gate
727*ae115bc7Smrj static void
kaif_msr_add(const kdi_msr_t * msrs)728*ae115bc7Smrj kaif_msr_add(const kdi_msr_t *msrs)
729*ae115bc7Smrj {
730*ae115bc7Smrj kdi_msr_t *save;
731*ae115bc7Smrj size_t nr_msrs = 0;
732*ae115bc7Smrj size_t i;
733*ae115bc7Smrj
734*ae115bc7Smrj while (msrs[nr_msrs].msr_num != 0)
735*ae115bc7Smrj nr_msrs++;
736*ae115bc7Smrj /* we want to copy the terminating kdi_msr_t too */
737*ae115bc7Smrj nr_msrs++;
738*ae115bc7Smrj
739*ae115bc7Smrj save = mdb_zalloc(sizeof (kdi_msr_t) * nr_msrs * kaif_ncpusave,
740*ae115bc7Smrj UM_SLEEP);
741*ae115bc7Smrj
742*ae115bc7Smrj for (i = 0; i < kaif_ncpusave; i++)
743*ae115bc7Smrj bcopy(msrs, &save[nr_msrs * i], sizeof (kdi_msr_t) * nr_msrs);
744*ae115bc7Smrj
745*ae115bc7Smrj kmdb_kdi_set_debug_msrs(save);
746*ae115bc7Smrj }
747*ae115bc7Smrj
748*ae115bc7Smrj static uint64_t
kaif_msr_get(int cpuid,uint_t num)749*ae115bc7Smrj kaif_msr_get(int cpuid, uint_t num)
750*ae115bc7Smrj {
751*ae115bc7Smrj kdi_cpusave_t *save;
752*ae115bc7Smrj kdi_msr_t *msr;
753*ae115bc7Smrj int i;
754*ae115bc7Smrj
755*ae115bc7Smrj if ((save = kaif_cpuid2save(cpuid)) == NULL)
756*ae115bc7Smrj return (-1); /* errno is set for us */
757*ae115bc7Smrj
758*ae115bc7Smrj msr = save->krs_msr;
759*ae115bc7Smrj
760*ae115bc7Smrj for (i = 0; msr[i].msr_num != 0; i++) {
761*ae115bc7Smrj if (msr[i].msr_num == num && (msr[i].msr_type & KDI_MSR_READ))
762*ae115bc7Smrj return (msr[i].kdi_msr_val);
763*ae115bc7Smrj }
764*ae115bc7Smrj
765*ae115bc7Smrj return (0);
766*ae115bc7Smrj }
767*ae115bc7Smrj
768*ae115bc7Smrj void
kaif_trap_set_debugger(void)769*ae115bc7Smrj kaif_trap_set_debugger(void)
770*ae115bc7Smrj {
771*ae115bc7Smrj kmdb_kdi_idt_switch(NULL);
772*ae115bc7Smrj }
773*ae115bc7Smrj
774*ae115bc7Smrj void
kaif_trap_set_saved(kaif_cpusave_t * cpusave)775*ae115bc7Smrj kaif_trap_set_saved(kaif_cpusave_t *cpusave)
776*ae115bc7Smrj {
777*ae115bc7Smrj kmdb_kdi_idt_switch(cpusave);
778*ae115bc7Smrj }
779*ae115bc7Smrj
780*ae115bc7Smrj static void
kaif_vmready(void)781*ae115bc7Smrj kaif_vmready(void)
782*ae115bc7Smrj {
783*ae115bc7Smrj }
784*ae115bc7Smrj
785*ae115bc7Smrj void
kaif_memavail(caddr_t base,size_t len)786*ae115bc7Smrj kaif_memavail(caddr_t base, size_t len)
787*ae115bc7Smrj {
788*ae115bc7Smrj int ret;
789*ae115bc7Smrj /*
790*ae115bc7Smrj * In the unlikely event that someone is stepping through this routine,
791*ae115bc7Smrj * we need to make sure that the KDI knows about the new range before
792*ae115bc7Smrj * umem gets it. That way the entry code can recognize stacks
793*ae115bc7Smrj * allocated from the new region.
794*ae115bc7Smrj */
795*ae115bc7Smrj kmdb_kdi_memrange_add(base, len);
796*ae115bc7Smrj ret = mdb_umem_add(base, len);
797*ae115bc7Smrj ASSERT(ret == 0);
798*ae115bc7Smrj }
799*ae115bc7Smrj
8007c478bd9Sstevel@tonic-gate void
kaif_mod_loaded(struct modctl * modp)8017c478bd9Sstevel@tonic-gate kaif_mod_loaded(struct modctl *modp)
8027c478bd9Sstevel@tonic-gate {
8037c478bd9Sstevel@tonic-gate if (kaif_modchg_cb != NULL)
8047c478bd9Sstevel@tonic-gate kaif_modchg_cb(modp, 1);
8057c478bd9Sstevel@tonic-gate }
8067c478bd9Sstevel@tonic-gate
8077c478bd9Sstevel@tonic-gate void
kaif_mod_unloading(struct modctl * modp)8087c478bd9Sstevel@tonic-gate kaif_mod_unloading(struct modctl *modp)
8097c478bd9Sstevel@tonic-gate {
8107c478bd9Sstevel@tonic-gate if (kaif_modchg_cb != NULL)
8117c478bd9Sstevel@tonic-gate kaif_modchg_cb(modp, 0);
8127c478bd9Sstevel@tonic-gate }
8137c478bd9Sstevel@tonic-gate
814*ae115bc7Smrj void
kaif_handle_fault(greg_t trapno,greg_t pc,greg_t sp,int cpuid)815*ae115bc7Smrj kaif_handle_fault(greg_t trapno, greg_t pc, greg_t sp, int cpuid)
8167c478bd9Sstevel@tonic-gate {
817*ae115bc7Smrj kmdb_dpi_handle_fault((kreg_t)trapno, (kreg_t)pc,
818*ae115bc7Smrj (kreg_t)sp, cpuid);
819*ae115bc7Smrj }
820*ae115bc7Smrj
821*ae115bc7Smrj static kdi_debugvec_t kaif_dvec = {
822*ae115bc7Smrj NULL, /* dv_kctl_vmready */
823*ae115bc7Smrj NULL, /* dv_kctl_memavail */
824*ae115bc7Smrj NULL, /* dv_kctl_modavail */
825*ae115bc7Smrj NULL, /* dv_kctl_thravail */
826*ae115bc7Smrj kaif_vmready,
827*ae115bc7Smrj kaif_memavail,
828*ae115bc7Smrj kaif_mod_loaded,
829*ae115bc7Smrj kaif_mod_unloading,
830*ae115bc7Smrj kaif_handle_fault
8317c478bd9Sstevel@tonic-gate };
8327c478bd9Sstevel@tonic-gate
8337c478bd9Sstevel@tonic-gate void
kaif_kdi_entry(kdi_cpusave_t * cpusave)834*ae115bc7Smrj kaif_kdi_entry(kdi_cpusave_t *cpusave)
8357c478bd9Sstevel@tonic-gate {
836*ae115bc7Smrj int ret = kaif_main_loop(cpusave);
837*ae115bc7Smrj ASSERT(ret == KAIF_CPU_CMD_RESUME ||
838*ae115bc7Smrj ret == KAIF_CPU_CMD_RESUME_MASTER);
8397c478bd9Sstevel@tonic-gate }
8407c478bd9Sstevel@tonic-gate
841*ae115bc7Smrj /*ARGSUSED*/
8427c478bd9Sstevel@tonic-gate void
kaif_activate(kdi_debugvec_t ** dvecp,uint_t flags)843*ae115bc7Smrj kaif_activate(kdi_debugvec_t **dvecp, uint_t flags)
8447c478bd9Sstevel@tonic-gate {
845*ae115bc7Smrj kmdb_kdi_activate(kaif_kdi_entry, kaif_cpusave, kaif_ncpusave);
846*ae115bc7Smrj *dvecp = &kaif_dvec;
8477c478bd9Sstevel@tonic-gate }
8487c478bd9Sstevel@tonic-gate
8497c478bd9Sstevel@tonic-gate static int
kaif_init(kmdb_auxv_t * kav)8507c478bd9Sstevel@tonic-gate kaif_init(kmdb_auxv_t *kav)
8517c478bd9Sstevel@tonic-gate {
8527c478bd9Sstevel@tonic-gate /* Allocate the per-CPU save areas */
8537c478bd9Sstevel@tonic-gate kaif_cpusave = mdb_zalloc(sizeof (kaif_cpusave_t) * kav->kav_ncpu,
8547c478bd9Sstevel@tonic-gate UM_SLEEP);
8557c478bd9Sstevel@tonic-gate kaif_ncpusave = kav->kav_ncpu;
8567c478bd9Sstevel@tonic-gate
8577c478bd9Sstevel@tonic-gate kaif_modchg_cb = NULL;
8587c478bd9Sstevel@tonic-gate
8597c478bd9Sstevel@tonic-gate kaif_waptmap = 0;
8607c478bd9Sstevel@tonic-gate
8617c478bd9Sstevel@tonic-gate kaif_trap_switch = (kav->kav_flags & KMDB_AUXV_FL_NOTRPSWTCH) == 0;
8627c478bd9Sstevel@tonic-gate
8637c478bd9Sstevel@tonic-gate return (0);
8647c478bd9Sstevel@tonic-gate }
8657c478bd9Sstevel@tonic-gate
8667c478bd9Sstevel@tonic-gate dpi_ops_t kmdb_dpi_ops = {
8677c478bd9Sstevel@tonic-gate kaif_init,
8687c478bd9Sstevel@tonic-gate kaif_activate,
869*ae115bc7Smrj kmdb_kdi_deactivate,
8707c478bd9Sstevel@tonic-gate kaif_enter_mon,
8717c478bd9Sstevel@tonic-gate kaif_modchg_register,
8727c478bd9Sstevel@tonic-gate kaif_modchg_cancel,
8737c478bd9Sstevel@tonic-gate kaif_get_cpu_state,
8747c478bd9Sstevel@tonic-gate kaif_get_master_cpuid,
8757c478bd9Sstevel@tonic-gate kaif_get_gregs,
876acbc304dSjohnlev kaif_get_register,
877acbc304dSjohnlev kaif_set_register,
8787c478bd9Sstevel@tonic-gate kaif_brkpt_arm,
8797c478bd9Sstevel@tonic-gate kaif_brkpt_disarm,
8807c478bd9Sstevel@tonic-gate kaif_wapt_validate,
8817c478bd9Sstevel@tonic-gate kaif_wapt_reserve,
8827c478bd9Sstevel@tonic-gate kaif_wapt_release,
8837c478bd9Sstevel@tonic-gate kaif_wapt_arm,
8847c478bd9Sstevel@tonic-gate kaif_wapt_disarm,
8857c478bd9Sstevel@tonic-gate kaif_wapt_match,
8867c478bd9Sstevel@tonic-gate kaif_step,
8877c478bd9Sstevel@tonic-gate kaif_step_branch,
8887c478bd9Sstevel@tonic-gate kaif_call,
8897c478bd9Sstevel@tonic-gate kaif_dump_crumbs,
8907c478bd9Sstevel@tonic-gate kaif_msr_add,
8917c478bd9Sstevel@tonic-gate kaif_msr_get,
8927c478bd9Sstevel@tonic-gate };
893